1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <dbus/dbus.h>
34 #include "dbus-common.h"
37 #include "cgroup-show.h"
38 #include "sysfs-show.h"
39 #include "spawn-polkit-agent.h"
41 static char **arg_property = NULL;
42 static bool arg_all = false;
43 static bool arg_full = false;
44 static bool arg_no_pager = false;
45 static const char *arg_kill_who = NULL;
46 static int arg_signal = SIGTERM;
47 static enum transport {
51 } arg_transport = TRANSPORT_NORMAL;
52 static bool arg_ask_password = true;
53 static const char *arg_host = NULL;
55 static void pager_open_if_enabled(void) {
57 /* Cache result before we open the pager */
64 static void polkit_agent_open_if_enabled(void) {
66 /* Open the polkit agent as a child process if necessary */
68 if (!arg_ask_password)
74 static int list_sessions(DBusConnection *bus, char **args, unsigned n) {
75 DBusMessage *reply = NULL;
77 DBusMessageIter iter, sub, sub2;
80 pager_open_if_enabled();
82 r = bus_method_call_with_reply (
84 "org.freedesktop.login1",
85 "/org/freedesktop/login1",
86 "org.freedesktop.login1.Manager",
94 if (!dbus_message_iter_init(reply, &iter) ||
95 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
96 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
97 log_error("Failed to parse reply.");
102 dbus_message_iter_recurse(&iter, &sub);
105 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
107 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
108 const char *id, *user, *seat, *object;
111 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
112 log_error("Failed to parse reply.");
117 dbus_message_iter_recurse(&sub, &sub2);
119 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
120 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
121 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
122 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
123 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
124 log_error("Failed to parse reply.");
129 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
133 dbus_message_iter_next(&sub);
137 printf("\n%u sessions listed.\n", k);
143 dbus_message_unref(reply);
148 static int list_users(DBusConnection *bus, char **args, unsigned n) {
149 DBusMessage *reply = NULL;
151 DBusMessageIter iter, sub, sub2;
154 pager_open_if_enabled();
156 r = bus_method_call_with_reply (
158 "org.freedesktop.login1",
159 "/org/freedesktop/login1",
160 "org.freedesktop.login1.Manager",
168 if (!dbus_message_iter_init(reply, &iter) ||
169 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
170 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
171 log_error("Failed to parse reply.");
176 dbus_message_iter_recurse(&iter, &sub);
179 printf("%10s %-16s\n", "UID", "USER");
181 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
182 const char *user, *object;
185 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
186 log_error("Failed to parse reply.");
191 dbus_message_iter_recurse(&sub, &sub2);
193 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
194 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
195 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
196 log_error("Failed to parse reply.");
201 printf("%10u %-16s\n", (unsigned) uid, user);
205 dbus_message_iter_next(&sub);
209 printf("\n%u users listed.\n", k);
215 dbus_message_unref(reply);
220 static int list_seats(DBusConnection *bus, char **args, unsigned n) {
221 DBusMessage *reply = NULL;
223 DBusMessageIter iter, sub, sub2;
226 pager_open_if_enabled();
228 r = bus_method_call_with_reply (
230 "org.freedesktop.login1",
231 "/org/freedesktop/login1",
232 "org.freedesktop.login1.Manager",
240 if (!dbus_message_iter_init(reply, &iter) ||
241 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
242 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
243 log_error("Failed to parse reply.");
248 dbus_message_iter_recurse(&iter, &sub);
251 printf("%-16s\n", "SEAT");
253 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
254 const char *seat, *object;
256 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
257 log_error("Failed to parse reply.");
262 dbus_message_iter_recurse(&sub, &sub2);
264 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
265 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
266 log_error("Failed to parse reply.");
271 printf("%-16s\n", seat);
275 dbus_message_iter_next(&sub);
279 printf("\n%u seats listed.\n", k);
285 dbus_message_unref(reply);
290 typedef struct SessionStatusInfo {
295 const char *default_control_group;
301 const char *remote_host;
302 const char *remote_user;
310 typedef struct UserStatusInfo {
314 const char *default_control_group;
320 typedef struct SeatStatusInfo {
322 const char *active_session;
326 static void print_session_status_info(SessionStatusInfo *i) {
327 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
328 char since2[FORMAT_TIMESTAMP_MAX], *s2;
331 printf("%s - ", strna(i->id));
334 printf("%s (%u)\n", i->name, (unsigned) i->uid);
336 printf("%u\n", (unsigned) i->uid);
338 s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp);
339 s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
342 printf("\t Since: %s; %s\n", s2, s1);
344 printf("\t Since: %s\n", s2);
349 printf("\t Leader: %u", (unsigned) i->leader);
351 get_process_comm(i->leader, &t);
361 printf("\t Seat: %s", i->seat);
364 printf("; vc%i", i->vtnr);
370 printf("\t TTY: %s\n", i->tty);
372 printf("\t Display: %s\n", i->display);
374 if (i->remote_host && i->remote_user)
375 printf("\t Remote: %s@%s\n", i->remote_user, i->remote_host);
376 else if (i->remote_host)
377 printf("\t Remote: %s\n", i->remote_host);
378 else if (i->remote_user)
379 printf("\t Remote: user %s\n", i->remote_user);
381 printf("\t Remote: Yes\n");
384 printf("\t Service: %s", i->service);
387 printf("; type %s", i->type);
390 printf("; class %s", i->class);
393 } else if (i->type) {
394 printf("\t Type: %s\n", i->type);
397 printf("; class %s", i->class);
399 printf("\t Class: %s\n", i->class);
402 printf("\t State: %s\n", i->state);
404 if (i->default_control_group) {
407 arg_all * OUTPUT_SHOW_ALL |
408 arg_full * OUTPUT_FULL_WIDTH;
410 printf("\t CGroup: %s\n", i->default_control_group);
412 if (arg_transport != TRANSPORT_SSH) {
419 show_cgroup_and_extra_by_spec(i->default_control_group,
420 "\t\t ", c, false, &i->leader,
421 i->leader > 0 ? 1 : 0,
427 static void print_user_status_info(UserStatusInfo *i) {
428 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
429 char since2[FORMAT_TIMESTAMP_MAX], *s2;
433 printf("%s (%u)\n", i->name, (unsigned) i->uid);
435 printf("%u\n", (unsigned) i->uid);
437 s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp);
438 s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
441 printf("\t Since: %s; %s\n", s2, s1);
443 printf("\t Since: %s\n", s2);
445 if (!isempty(i->state))
446 printf("\t State: %s\n", i->state);
448 if (!strv_isempty(i->sessions)) {
450 printf("\tSessions:");
452 STRV_FOREACH(l, i->sessions) {
453 if (streq_ptr(*l, i->display))
462 if (i->default_control_group) {
465 arg_all * OUTPUT_SHOW_ALL |
466 arg_full * OUTPUT_FULL_WIDTH;
468 printf("\t CGroup: %s\n", i->default_control_group);
470 if (arg_transport != TRANSPORT_SSH) {
477 show_cgroup_by_path(i->default_control_group, "\t\t ",
478 c, false, output_flags);
483 static void print_seat_status_info(SeatStatusInfo *i) {
486 printf("%s\n", strna(i->id));
488 if (!strv_isempty(i->sessions)) {
490 printf("\tSessions:");
492 STRV_FOREACH(l, i->sessions) {
493 if (streq_ptr(*l, i->active_session))
502 if (arg_transport != TRANSPORT_SSH) {
511 printf("\t Devices:\n");
513 show_sysfs(i->id, "\t\t ", c);
517 static int status_property_session(const char *name, DBusMessageIter *iter, SessionStatusInfo *i) {
522 switch (dbus_message_iter_get_arg_type(iter)) {
524 case DBUS_TYPE_STRING: {
527 dbus_message_iter_get_basic(iter, &s);
530 if (streq(name, "Id"))
532 else if (streq(name, "Name"))
534 else if (streq(name, "DefaultControlGroup"))
535 i->default_control_group = s;
536 else if (streq(name, "TTY"))
538 else if (streq(name, "Display"))
540 else if (streq(name, "RemoteHost"))
542 else if (streq(name, "RemoteUser"))
544 else if (streq(name, "Service"))
546 else if (streq(name, "Type"))
548 else if (streq(name, "Class"))
550 else if (streq(name, "State"))
556 case DBUS_TYPE_UINT32: {
559 dbus_message_iter_get_basic(iter, &u);
561 if (streq(name, "VTNr"))
563 else if (streq(name, "Leader"))
564 i->leader = (pid_t) u;
569 case DBUS_TYPE_BOOLEAN: {
572 dbus_message_iter_get_basic(iter, &b);
574 if (streq(name, "Remote"))
580 case DBUS_TYPE_UINT64: {
583 dbus_message_iter_get_basic(iter, &u);
585 if (streq(name, "Timestamp"))
586 i->timestamp = (usec_t) u;
591 case DBUS_TYPE_STRUCT: {
594 dbus_message_iter_recurse(iter, &sub);
596 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "User")) {
599 dbus_message_iter_get_basic(&sub, &u);
602 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Seat")) {
605 dbus_message_iter_get_basic(&sub, &s);
618 static int status_property_user(const char *name, DBusMessageIter *iter, UserStatusInfo *i) {
623 switch (dbus_message_iter_get_arg_type(iter)) {
625 case DBUS_TYPE_STRING: {
628 dbus_message_iter_get_basic(iter, &s);
631 if (streq(name, "Name"))
633 else if (streq(name, "DefaultControlGroup"))
634 i->default_control_group = s;
635 else if (streq(name, "State"))
641 case DBUS_TYPE_UINT32: {
644 dbus_message_iter_get_basic(iter, &u);
646 if (streq(name, "UID"))
652 case DBUS_TYPE_UINT64: {
655 dbus_message_iter_get_basic(iter, &u);
657 if (streq(name, "Timestamp"))
658 i->timestamp = (usec_t) u;
663 case DBUS_TYPE_STRUCT: {
666 dbus_message_iter_recurse(iter, &sub);
668 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Display")) {
671 dbus_message_iter_get_basic(&sub, &s);
680 case DBUS_TYPE_ARRAY: {
682 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
683 DBusMessageIter sub, sub2;
685 dbus_message_iter_recurse(iter, &sub);
686 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
690 dbus_message_iter_recurse(&sub, &sub2);
692 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
693 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
696 l = strv_append(i->sessions, id);
700 strv_free(i->sessions);
704 dbus_message_iter_next(&sub);
715 static int status_property_seat(const char *name, DBusMessageIter *iter, SeatStatusInfo *i) {
720 switch (dbus_message_iter_get_arg_type(iter)) {
722 case DBUS_TYPE_STRING: {
725 dbus_message_iter_get_basic(iter, &s);
728 if (streq(name, "Id"))
734 case DBUS_TYPE_STRUCT: {
737 dbus_message_iter_recurse(iter, &sub);
739 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "ActiveSession")) {
742 dbus_message_iter_get_basic(&sub, &s);
745 i->active_session = s;
751 case DBUS_TYPE_ARRAY: {
753 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
754 DBusMessageIter sub, sub2;
756 dbus_message_iter_recurse(iter, &sub);
757 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
761 dbus_message_iter_recurse(&sub, &sub2);
763 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
764 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
767 l = strv_append(i->sessions, id);
771 strv_free(i->sessions);
775 dbus_message_iter_next(&sub);
786 static int print_property(const char *name, DBusMessageIter *iter) {
790 if (arg_property && !strv_find(arg_property, name))
793 switch (dbus_message_iter_get_arg_type(iter)) {
795 case DBUS_TYPE_STRUCT: {
798 dbus_message_iter_recurse(iter, &sub);
800 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING &&
801 (streq(name, "Display") || streq(name, "ActiveSession"))) {
804 dbus_message_iter_get_basic(&sub, &s);
806 if (arg_all || !isempty(s))
807 printf("%s=%s\n", name, s);
813 case DBUS_TYPE_ARRAY:
815 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
816 DBusMessageIter sub, sub2;
819 dbus_message_iter_recurse(iter, &sub);
820 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
824 dbus_message_iter_recurse(&sub, &sub2);
826 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
827 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
831 printf("%s=%s", name, id);
836 dbus_message_iter_next(&sub);
839 if (!found && arg_all)
840 printf("%s=\n", name);
850 if (generic_print_property(name, iter, arg_all) > 0)
854 printf("%s=[unprintable]\n", name);
859 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
860 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
861 const char *interface = "";
863 DBusMessageIter iter, sub, sub2, sub3;
864 SessionStatusInfo session_info;
865 UserStatusInfo user_info;
866 SeatStatusInfo seat_info;
875 r = bus_method_call_with_reply(
877 "org.freedesktop.login1",
879 "org.freedesktop.DBus.Properties",
883 DBUS_TYPE_STRING, &interface,
888 if (!dbus_message_iter_init(reply, &iter) ||
889 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
890 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
891 log_error("Failed to parse reply.");
896 dbus_message_iter_recurse(&iter, &sub);
903 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
906 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
907 log_error("Failed to parse reply.");
912 dbus_message_iter_recurse(&sub, &sub2);
914 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
915 log_error("Failed to parse reply.");
920 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
921 log_error("Failed to parse reply.");
926 dbus_message_iter_recurse(&sub2, &sub3);
929 r = print_property(name, &sub3);
930 else if (strstr(verb, "session"))
931 r = status_property_session(name, &sub3, &session_info);
932 else if (strstr(verb, "user"))
933 r = status_property_user(name, &sub3, &user_info);
935 r = status_property_seat(name, &sub3, &seat_info);
938 log_error("Failed to parse reply.");
942 dbus_message_iter_next(&sub);
945 if (!show_properties) {
946 if (strstr(verb, "session"))
947 print_session_status_info(&session_info);
948 else if (strstr(verb, "user"))
949 print_user_status_info(&user_info);
951 print_seat_status_info(&seat_info);
957 strv_free(seat_info.sessions);
958 strv_free(user_info.sessions);
963 static int show(DBusConnection *bus, char **args, unsigned n) {
964 DBusMessage *reply = NULL;
968 bool show_properties, new_line = false;
973 dbus_error_init(&error);
975 show_properties = !strstr(args[0], "status");
977 pager_open_if_enabled();
979 if (show_properties && n <= 1) {
980 /* If not argument is specified inspect the manager
983 ret = show_one(args[0], bus, "/org/freedesktop/login1", show_properties, &new_line);
987 for (i = 1; i < n; i++) {
988 const char *path = NULL;
990 if (strstr(args[0], "session")) {
992 ret = bus_method_call_with_reply (
994 "org.freedesktop.login1",
995 "/org/freedesktop/login1",
996 "org.freedesktop.login1.Manager",
1000 DBUS_TYPE_STRING, &args[i],
1003 } else if (strstr(args[0], "user")) {
1007 ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
1009 log_error("User %s unknown.", args[i]);
1014 ret = bus_method_call_with_reply (
1016 "org.freedesktop.login1",
1017 "/org/freedesktop/login1",
1018 "org.freedesktop.login1.Manager",
1022 DBUS_TYPE_UINT32, &u,
1026 ret = bus_method_call_with_reply (
1028 "org.freedesktop.login1",
1029 "/org/freedesktop/login1",
1030 "org.freedesktop.login1.Manager",
1034 DBUS_TYPE_STRING, &args[i],
1040 if (!dbus_message_get_args(reply, &error,
1041 DBUS_TYPE_OBJECT_PATH, &path,
1042 DBUS_TYPE_INVALID)) {
1043 log_error("Failed to parse reply: %s", bus_error_message(&error));
1048 r = show_one(args[0], bus, path, show_properties, &new_line);
1052 dbus_message_unref(reply);
1058 dbus_message_unref(reply);
1060 dbus_error_free(&error);
1065 static int activate(DBusConnection *bus, char **args, unsigned n) {
1071 for (i = 1; i < n; i++) {
1073 ret = bus_method_call_with_reply (
1075 "org.freedesktop.login1",
1076 "/org/freedesktop/login1",
1077 "org.freedesktop.login1.Manager",
1078 streq(args[0], "lock-session") ? "LockSession" :
1079 streq(args[0], "unlock-session") ? "UnlockSession" :
1080 streq(args[0], "terminate-session") ? "TerminateSession" :
1084 DBUS_TYPE_STRING, &args[i],
1094 static int kill_session(DBusConnection *bus, char **args, unsigned n) {
1101 arg_kill_who = "all";
1103 for (i = 1; i < n; i++) {
1104 ret = bus_method_call_with_reply (
1106 "org.freedesktop.login1",
1107 "/org/freedesktop/login1",
1108 "org.freedesktop.login1.Manager",
1112 DBUS_TYPE_STRING, &args[i],
1113 DBUS_TYPE_STRING, &arg_kill_who,
1114 DBUS_TYPE_INT32, &arg_signal,
1124 static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
1127 dbus_bool_t b, interactive = true;
1131 polkit_agent_open_if_enabled();
1133 b = streq(args[0], "enable-linger");
1135 for (i = 1; i < n; i++) {
1139 ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
1141 log_error("Failed to resolve user %s: %s", args[i], strerror(-ret));
1146 ret = bus_method_call_with_reply (
1148 "org.freedesktop.login1",
1149 "/org/freedesktop/login1",
1150 "org.freedesktop.login1.Manager",
1154 DBUS_TYPE_UINT32, &u,
1155 DBUS_TYPE_BOOLEAN, &b,
1156 DBUS_TYPE_BOOLEAN, &interactive,
1166 static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
1172 for (i = 1; i < n; i++) {
1176 ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
1178 log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
1183 ret = bus_method_call_with_reply (
1185 "org.freedesktop.login1",
1186 "/org/freedesktop/login1",
1187 "org.freedesktop.login1.Manager",
1191 DBUS_TYPE_UINT32, &u,
1201 static int kill_user(DBusConnection *bus, char **args, unsigned n) {
1208 arg_kill_who = "all";
1210 for (i = 1; i < n; i++) {
1214 ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
1216 log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
1221 ret = bus_method_call_with_reply (
1223 "org.freedesktop.login1",
1224 "/org/freedesktop/login1",
1225 "org.freedesktop.login1.Manager",
1229 DBUS_TYPE_UINT32, &u,
1230 DBUS_TYPE_INT32, &arg_signal,
1240 static int attach(DBusConnection *bus, char **args, unsigned n) {
1243 dbus_bool_t interactive = true;
1247 polkit_agent_open_if_enabled();
1249 for (i = 2; i < n; i++) {
1250 ret = bus_method_call_with_reply (
1252 "org.freedesktop.login1",
1253 "/org/freedesktop/login1",
1254 "org.freedesktop.login1.Manager",
1258 DBUS_TYPE_STRING, &args[1],
1259 DBUS_TYPE_STRING, &args[i],
1260 DBUS_TYPE_BOOLEAN, &interactive,
1270 static int flush_devices(DBusConnection *bus, char **args, unsigned n) {
1271 dbus_bool_t interactive = true;
1275 polkit_agent_open_if_enabled();
1277 return bus_method_call_with_reply (
1279 "org.freedesktop.login1",
1280 "/org/freedesktop/login1",
1281 "org.freedesktop.login1.Manager",
1285 DBUS_TYPE_BOOLEAN, &interactive,
1289 static int lock_sessions(DBusConnection *bus, char **args, unsigned n) {
1292 polkit_agent_open_if_enabled();
1294 return bus_method_call_with_reply (
1296 "org.freedesktop.login1",
1297 "/org/freedesktop/login1",
1298 "org.freedesktop.login1.Manager",
1299 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1305 static int terminate_seat(DBusConnection *bus, char **args, unsigned n) {
1311 for (i = 1; i < n; i++) {
1312 ret = bus_method_call_with_reply (
1314 "org.freedesktop.login1",
1315 "/org/freedesktop/login1",
1316 "org.freedesktop.login1.Manager",
1320 DBUS_TYPE_STRING, &args[i],
1330 static int help(void) {
1332 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1333 "Send control commands to or query the login manager.\n\n"
1334 " -h --help Show this help\n"
1335 " --version Show package version\n"
1336 " -p --property=NAME Show only properties by this name\n"
1337 " -a --all Show all properties, including empty ones\n"
1338 " --kill-who=WHO Who to send signal to\n"
1339 " --full Do not ellipsize output\n"
1340 " -s --signal=SIGNAL Which signal to send\n"
1341 " --no-ask-password Don't prompt for password\n"
1342 " -H --host=[USER@]HOST Show information for remote host\n"
1343 " -P --privileged Acquire privileges before execution\n"
1344 " --no-pager Do not pipe output into a pager\n\n"
1346 " list-sessions List sessions\n"
1347 " session-status [ID...] Show session status\n"
1348 " show-session [ID...] Show properties of one or more sessions\n"
1349 " activate [ID] Activate a session\n"
1350 " lock-session [ID...] Screen lock one or more sessions\n"
1351 " unlock-session [ID...] Screen unlock one or more sessions\n"
1352 " lock-sessions Screen lock all current sessions\n"
1353 " unlock-sessions Screen unlock all current sessions\n"
1354 " terminate-session [ID...] Terminate one or more sessions\n"
1355 " kill-session [ID...] Send signal to processes of a session\n"
1356 " list-users List users\n"
1357 " user-status [USER...] Show user status\n"
1358 " show-user [USER...] Show properties of one or more users\n"
1359 " enable-linger [USER...] Enable linger state of one or more users\n"
1360 " disable-linger [USER...] Disable linger state of one or more users\n"
1361 " terminate-user [USER...] Terminate all sessions of one or more users\n"
1362 " kill-user [USER...] Send signal to processes of a user\n"
1363 " list-seats List seats\n"
1364 " seat-status [NAME...] Show seat status\n"
1365 " show-seat [NAME...] Show properties of one or more seats\n"
1366 " attach [NAME] [DEVICE...] Attach one or more devices to a seat\n"
1367 " flush-devices Flush all device associations\n"
1368 " terminate-seat [NAME...] Terminate all sessions on one or more seats\n",
1369 program_invocation_short_name);
1374 static int parse_argv(int argc, char *argv[]) {
1377 ARG_VERSION = 0x100,
1380 ARG_NO_ASK_PASSWORD,
1384 static const struct option options[] = {
1385 { "help", no_argument, NULL, 'h' },
1386 { "version", no_argument, NULL, ARG_VERSION },
1387 { "property", required_argument, NULL, 'p' },
1388 { "all", no_argument, NULL, 'a' },
1389 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1390 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1391 { "signal", required_argument, NULL, 's' },
1392 { "host", required_argument, NULL, 'H' },
1393 { "privileged", no_argument, NULL, 'P' },
1394 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1395 { "full", no_argument, NULL, ARG_FULL },
1396 { NULL, 0, NULL, 0 }
1404 while ((c = getopt_long(argc, argv, "hp:as:H:P", options, NULL)) >= 0) {
1413 puts(PACKAGE_STRING);
1414 puts(SYSTEMD_FEATURES);
1420 l = strv_append(arg_property, optarg);
1424 strv_free(arg_property);
1427 /* If the user asked for a particular
1428 * property, show it to him, even if it is
1439 arg_no_pager = true;
1442 case ARG_NO_ASK_PASSWORD:
1443 arg_ask_password = false;
1447 arg_kill_who = optarg;
1451 arg_signal = signal_from_string_try_harder(optarg);
1452 if (arg_signal < 0) {
1453 log_error("Failed to parse signal string %s.", optarg);
1459 arg_transport = TRANSPORT_POLKIT;
1463 arg_transport = TRANSPORT_SSH;
1475 log_error("Unknown option code %c", c);
1483 static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
1485 static const struct {
1493 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
1495 { "list-sessions", LESS, 1, list_sessions },
1496 { "session-status", MORE, 2, show },
1497 { "show-session", MORE, 1, show },
1498 { "activate", EQUAL, 2, activate },
1499 { "lock-session", MORE, 2, activate },
1500 { "unlock-session", MORE, 2, activate },
1501 { "lock-sessions", EQUAL, 1, lock_sessions },
1502 { "unlock-sessions", EQUAL, 1, lock_sessions },
1503 { "terminate-session", MORE, 2, activate },
1504 { "kill-session", MORE, 2, kill_session },
1505 { "list-users", EQUAL, 1, list_users },
1506 { "user-status", MORE, 2, show },
1507 { "show-user", MORE, 1, show },
1508 { "enable-linger", MORE, 2, enable_linger },
1509 { "disable-linger", MORE, 2, enable_linger },
1510 { "terminate-user", MORE, 2, terminate_user },
1511 { "kill-user", MORE, 2, kill_user },
1512 { "list-seats", EQUAL, 1, list_seats },
1513 { "seat-status", MORE, 2, show },
1514 { "show-seat", MORE, 1, show },
1515 { "attach", MORE, 3, attach },
1516 { "flush-devices", EQUAL, 1, flush_devices },
1517 { "terminate-seat", MORE, 2, terminate_seat },
1527 left = argc - optind;
1530 /* Special rule: no arguments means "list-sessions" */
1533 if (streq(argv[optind], "help")) {
1538 for (i = 0; i < ELEMENTSOF(verbs); i++)
1539 if (streq(argv[optind], verbs[i].verb))
1542 if (i >= ELEMENTSOF(verbs)) {
1543 log_error("Unknown operation %s", argv[optind]);
1548 switch (verbs[i].argc_cmp) {
1551 if (left != verbs[i].argc) {
1552 log_error("Invalid number of arguments.");
1559 if (left < verbs[i].argc) {
1560 log_error("Too few arguments.");
1567 if (left > verbs[i].argc) {
1568 log_error("Too many arguments.");
1575 assert_not_reached("Unknown comparison operator.");
1579 log_error("Failed to get D-Bus connection: %s", error->message);
1583 return verbs[i].dispatch(bus, argv + optind, left);
1586 int main(int argc, char*argv[]) {
1587 int r, retval = EXIT_FAILURE;
1588 DBusConnection *bus = NULL;
1591 dbus_error_init(&error);
1593 setlocale(LC_ALL, "");
1594 log_parse_environment();
1597 r = parse_argv(argc, argv);
1601 retval = EXIT_SUCCESS;
1605 if (arg_transport == TRANSPORT_NORMAL)
1606 bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
1607 else if (arg_transport == TRANSPORT_POLKIT)
1608 bus_connect_system_polkit(&bus, &error);
1609 else if (arg_transport == TRANSPORT_SSH)
1610 bus_connect_system_ssh(NULL, arg_host, &bus, &error);
1612 assert_not_reached("Uh, invalid transport...");
1614 r = loginctl_main(bus, argc, argv, &error);
1615 retval = r < 0 ? EXIT_FAILURE : r;
1619 dbus_connection_flush(bus);
1620 dbus_connection_close(bus);
1621 dbus_connection_unref(bus);
1624 dbus_error_free(&error);
1627 strv_free(arg_property);