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/>.
31 #include "bus-error.h"
38 #include "unit-name.h"
39 #include "sysfs-show.h"
40 //#include "logs-show.h"
41 //#include "cgroup-show.h"
42 #include "cgroup-util.h"
43 #include "spawn-polkit-agent.h"
45 #include "process-util.h"
46 #include "terminal-util.h"
47 #include "signal-util.h"
48 #include "logind-action.h"
50 static char **arg_property = NULL;
51 static bool arg_all = false;
52 static bool arg_full = false;
53 static bool arg_no_pager = false;
54 static bool arg_legend = true;
55 static const char *arg_kill_who = NULL;
56 static int arg_signal = SIGTERM;
57 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
58 static char *arg_host = NULL;
59 static bool arg_ask_password = true;
60 static bool arg_ignore_inhibitors = false;
62 static unsigned arg_lines = 10;
63 static OutputMode arg_output = OUTPUT_SHORT;
72 ACTION_CANCEL_SHUTDOWN,
77 static void pager_open_if_enabled(void) {
85 static void polkit_agent_open_if_enabled(void) {
87 /* Open the polkit agent as a child process if necessary */
89 if (!arg_ask_password)
92 if (arg_transport != BUS_TRANSPORT_LOCAL)
98 /// UNNEEDED by elogind
100 static OutputFlags get_output_flags(void) {
103 arg_all * OUTPUT_SHOW_ALL |
104 arg_full * OUTPUT_FULL_WIDTH |
105 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
106 on_tty() * OUTPUT_COLOR;
110 static int list_sessions(int argc, char *argv[], void *userdata) {
111 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
112 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
113 const char *id, *user, *seat, *object;
114 sd_bus *bus = userdata;
122 pager_open_if_enabled();
124 r = sd_bus_call_method(
126 "org.freedesktop.login1",
127 "/org/freedesktop/login1",
128 "org.freedesktop.login1.Manager",
133 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
137 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
139 return bus_log_parse_error(r);
142 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
144 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
145 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
149 return bus_log_parse_error(r);
152 printf("\n%u sessions listed.\n", k);
157 static int list_users(int argc, char *argv[], void *userdata) {
158 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
159 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
160 const char *user, *object;
161 sd_bus *bus = userdata;
169 pager_open_if_enabled();
171 r = sd_bus_call_method(
173 "org.freedesktop.login1",
174 "/org/freedesktop/login1",
175 "org.freedesktop.login1.Manager",
180 log_error("Failed to list users: %s", bus_error_message(&error, r));
184 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
186 return bus_log_parse_error(r);
189 printf("%10s %-16s\n", "UID", "USER");
191 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
192 printf("%10u %-16s\n", (unsigned) uid, user);
196 return bus_log_parse_error(r);
199 printf("\n%u users listed.\n", k);
204 static int list_seats(int argc, char *argv[], void *userdata) {
205 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
206 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
207 const char *seat, *object;
208 sd_bus *bus = userdata;
215 pager_open_if_enabled();
217 r = sd_bus_call_method(
219 "org.freedesktop.login1",
220 "/org/freedesktop/login1",
221 "org.freedesktop.login1.Manager",
226 log_error("Failed to list seats: %s", bus_error_message(&error, r));
230 r = sd_bus_message_enter_container(reply, 'a', "(so)");
232 return bus_log_parse_error(r);
235 printf("%-16s\n", "SEAT");
237 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
238 printf("%-16s\n", seat);
242 return bus_log_parse_error(r);
245 printf("\n%u seats listed.\n", k);
250 /// UNNEEDED by elogind
252 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
253 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
254 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
255 _cleanup_free_ char *path = NULL;
263 if (arg_transport != BUS_TRANSPORT_LOCAL)
266 path = unit_dbus_path_from_name(unit);
270 r = sd_bus_get_property(
272 "org.freedesktop.systemd1",
276 &error, &reply, "s");
280 r = sd_bus_message_read(reply, "s", &cgroup);
287 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
296 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
301 typedef struct SessionStatusInfo {
305 struct dual_timestamp timestamp;
322 typedef struct UserStatusInfo {
325 struct dual_timestamp timestamp;
332 typedef struct SeatStatusInfo {
334 char *active_session;
338 static void session_status_info_clear(SessionStatusInfo *info) {
345 free(info->remote_host);
346 free(info->remote_user);
357 static void user_status_info_clear(UserStatusInfo *info) {
361 strv_free(info->sessions);
368 static void seat_status_info_clear(SeatStatusInfo *info) {
371 free(info->active_session);
372 strv_free(info->sessions);
377 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
378 const char *contents;
381 r = sd_bus_message_peek_type(m, NULL, &contents);
385 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
389 if (contents[0] == 's' || contents[0] == 'o') {
391 char **p = (char **) userdata;
393 r = sd_bus_message_read_basic(m, contents[0], &s);
397 r = free_and_strdup(p, s);
401 r = sd_bus_message_read_basic(m, contents[0], userdata);
406 r = sd_bus_message_skip(m, contents+1);
410 r = sd_bus_message_exit_container(m);
417 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
424 r = sd_bus_message_enter_container(m, 'a', "(so)");
428 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
429 r = strv_extend(userdata, name);
436 return sd_bus_message_exit_container(m);
439 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
441 static const struct bus_properties_map map[] = {
442 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
443 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
444 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
445 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
446 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
447 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
448 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
449 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
450 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
451 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
452 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
453 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
454 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
455 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
456 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
457 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
458 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
459 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
460 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
464 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
465 char since2[FORMAT_TIMESTAMP_MAX], *s2;
466 _cleanup_(session_status_info_clear) SessionStatusInfo i = {};
469 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
471 return log_error_errno(r, "Could not get properties: %m");
478 printf("%s - ", strna(i.id));
481 printf("%s (%u)\n", i.name, (unsigned) i.uid);
483 printf("%u\n", (unsigned) i.uid);
485 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
486 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
489 printf("\t Since: %s; %s\n", s2, s1);
491 printf("\t Since: %s\n", s2);
494 _cleanup_free_ char *t = NULL;
496 printf("\t Leader: %u", (unsigned) i.leader);
498 get_process_comm(i.leader, &t);
505 if (!isempty(i.seat)) {
506 printf("\t Seat: %s", i.seat);
509 printf("; vc%u", i.vtnr);
515 printf("\t TTY: %s\n", i.tty);
517 printf("\t Display: %s\n", i.display);
519 if (i.remote_host && i.remote_user)
520 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
521 else if (i.remote_host)
522 printf("\t Remote: %s\n", i.remote_host);
523 else if (i.remote_user)
524 printf("\t Remote: user %s\n", i.remote_user);
526 printf("\t Remote: Yes\n");
529 printf("\t Service: %s", i.service);
532 printf("; type %s", i.type);
535 printf("; class %s", i.class);
539 printf("\t Type: %s", i.type);
542 printf("; class %s", i.class);
546 printf("\t Class: %s\n", i.class);
548 if (!isempty(i.desktop))
549 printf("\t Desktop: %s\n", i.desktop);
552 printf("\t State: %s\n", i.state);
555 printf("\t Unit: %s\n", i.scope);
557 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
558 if (arg_transport == BUS_TRANSPORT_LOCAL) {
560 show_journal_by_unit(
565 i.timestamp.monotonic,
568 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
569 SD_JOURNAL_LOCAL_ONLY,
580 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
582 static const struct bus_properties_map map[] = {
583 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
584 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
585 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
586 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
587 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
588 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
589 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
590 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
594 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
595 char since2[FORMAT_TIMESTAMP_MAX], *s2;
596 _cleanup_(user_status_info_clear) UserStatusInfo i = {};
599 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
601 return log_error_errno(r, "Could not get properties: %m");
609 printf("%s (%u)\n", i.name, (unsigned) i.uid);
611 printf("%u\n", (unsigned) i.uid);
613 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
614 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
617 printf("\t Since: %s; %s\n", s2, s1);
619 printf("\t Since: %s\n", s2);
621 if (!isempty(i.state))
622 printf("\t State: %s\n", i.state);
624 if (!strv_isempty(i.sessions)) {
626 printf("\tSessions:");
628 STRV_FOREACH(l, i.sessions) {
629 if (streq_ptr(*l, i.display))
639 printf("\t Unit: %s\n", i.slice);
641 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
642 show_journal_by_unit(
647 i.timestamp.monotonic,
650 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
651 SD_JOURNAL_LOCAL_ONLY,
661 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
663 static const struct bus_properties_map map[] = {
664 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
665 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
666 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
670 _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
673 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
675 return log_error_errno(r, "Could not get properties: %m");
682 printf("%s\n", strna(i.id));
684 if (!strv_isempty(i.sessions)) {
686 printf("\tSessions:");
688 STRV_FOREACH(l, i.sessions) {
689 if (streq_ptr(*l, i.active_session))
698 if (arg_transport == BUS_TRANSPORT_LOCAL) {
707 printf("\t Devices:\n");
709 show_sysfs(i.id, "\t\t ", c);
715 static int print_property(const char *name, sd_bus_message *m, const char *contents) {
722 if (arg_property && !strv_find(arg_property, name))
723 /* skip what we didn't read */
724 return sd_bus_message_skip(m, contents);
726 switch (contents[0]) {
728 case SD_BUS_TYPE_STRUCT_BEGIN:
730 if (contents[1] == SD_BUS_TYPE_STRING && STR_IN_SET(name, "Display", "Seat", "ActiveSession")) {
733 r = sd_bus_message_read(m, "(so)", &s, NULL);
735 return bus_log_parse_error(r);
737 if (arg_all || !isempty(s))
738 printf("%s=%s\n", name, s);
742 } else if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "User")) {
745 r = sd_bus_message_read(m, "(uo)", &uid, NULL);
747 return bus_log_parse_error(r);
749 if (!uid_is_valid(uid)) {
750 log_error("Invalid user ID: " UID_FMT, uid);
754 printf("%s=" UID_FMT "\n", name, uid);
761 case SD_BUS_TYPE_ARRAY:
763 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Sessions")) {
767 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(so)");
769 return bus_log_parse_error(r);
773 while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
774 printf("%s%s", space ? " " : "", s);
781 return bus_log_parse_error(r);
783 r = sd_bus_message_exit_container(m);
785 return bus_log_parse_error(r);
793 r = bus_print_property(name, m, arg_all);
795 return bus_log_parse_error(r);
798 r = sd_bus_message_skip(m, contents);
800 return bus_log_parse_error(r);
803 printf("%s=[unprintable]\n", name);
809 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
810 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
811 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
818 r = sd_bus_call_method(
820 "org.freedesktop.login1",
822 "org.freedesktop.DBus.Properties",
828 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
830 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
832 return bus_log_parse_error(r);
839 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
840 const char *name, *contents;
842 r = sd_bus_message_read(reply, "s", &name);
844 return bus_log_parse_error(r);
846 r = sd_bus_message_peek_type(reply, NULL, &contents);
848 return bus_log_parse_error(r);
850 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
852 return bus_log_parse_error(r);
854 r = print_property(name, reply, contents);
858 r = sd_bus_message_exit_container(reply);
860 return bus_log_parse_error(r);
862 r = sd_bus_message_exit_container(reply);
864 return bus_log_parse_error(r);
867 return bus_log_parse_error(r);
869 r = sd_bus_message_exit_container(reply);
871 return bus_log_parse_error(r);
876 static int show_session(int argc, char *argv[], void *userdata) {
877 bool properties, new_line = false;
878 sd_bus *bus = userdata;
884 properties = !strstr(argv[0], "status");
886 pager_open_if_enabled();
889 /* If not argument is specified inspect the manager
892 return show_properties(bus, "/org/freedesktop/login1", &new_line);
894 /* And in the pretty case, show data of the calling session */
895 return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
898 for (i = 1; i < argc; i++) {
899 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
900 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
901 const char *path = NULL;
903 r = sd_bus_call_method(
905 "org.freedesktop.login1",
906 "/org/freedesktop/login1",
907 "org.freedesktop.login1.Manager",
912 log_error("Failed to get session: %s", bus_error_message(&error, r));
916 r = sd_bus_message_read(reply, "o", &path);
918 return bus_log_parse_error(r);
921 r = show_properties(bus, path, &new_line);
923 r = print_session_status_info(bus, path, &new_line);
932 static int show_user(int argc, char *argv[], void *userdata) {
933 bool properties, new_line = false;
934 sd_bus *bus = userdata;
940 properties = !strstr(argv[0], "status");
942 pager_open_if_enabled();
945 /* If not argument is specified inspect the manager
948 return show_properties(bus, "/org/freedesktop/login1", &new_line);
950 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
953 for (i = 1; i < argc; i++) {
954 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
955 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
956 const char *path = NULL;
959 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
961 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
963 r = sd_bus_call_method(
965 "org.freedesktop.login1",
966 "/org/freedesktop/login1",
967 "org.freedesktop.login1.Manager",
970 "u", (uint32_t) uid);
972 log_error("Failed to get user: %s", bus_error_message(&error, r));
976 r = sd_bus_message_read(reply, "o", &path);
978 return bus_log_parse_error(r);
981 r = show_properties(bus, path, &new_line);
983 r = print_user_status_info(bus, path, &new_line);
992 static int show_seat(int argc, char *argv[], void *userdata) {
993 bool properties, new_line = false;
994 sd_bus *bus = userdata;
1000 properties = !strstr(argv[0], "status");
1002 pager_open_if_enabled();
1005 /* If not argument is specified inspect the manager
1008 return show_properties(bus, "/org/freedesktop/login1", &new_line);
1010 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
1013 for (i = 1; i < argc; i++) {
1014 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1015 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
1016 const char *path = NULL;
1018 r = sd_bus_call_method(
1020 "org.freedesktop.login1",
1021 "/org/freedesktop/login1",
1022 "org.freedesktop.login1.Manager",
1027 log_error("Failed to get seat: %s", bus_error_message(&error, r));
1031 r = sd_bus_message_read(reply, "o", &path);
1033 return bus_log_parse_error(r);
1036 r = show_properties(bus, path, &new_line);
1038 r = print_seat_status_info(bus, path, &new_line);
1047 static int activate(int argc, char *argv[], void *userdata) {
1048 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1049 sd_bus *bus = userdata;
1050 char *short_argv[3];
1056 polkit_agent_open_if_enabled();
1059 /* No argument? Let's convert this into the empty
1060 * session name, which the calls will then resolve to
1061 * the caller's session. */
1063 short_argv[0] = argv[0];
1064 short_argv[1] = (char*) "";
1065 short_argv[2] = NULL;
1071 for (i = 1; i < argc; i++) {
1073 r = sd_bus_call_method(
1075 "org.freedesktop.login1",
1076 "/org/freedesktop/login1",
1077 "org.freedesktop.login1.Manager",
1078 streq(argv[0], "lock-session") ? "LockSession" :
1079 streq(argv[0], "unlock-session") ? "UnlockSession" :
1080 streq(argv[0], "terminate-session") ? "TerminateSession" :
1085 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
1093 static int kill_session(int argc, char *argv[], void *userdata) {
1094 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1095 sd_bus *bus = userdata;
1101 polkit_agent_open_if_enabled();
1104 arg_kill_who = "all";
1106 for (i = 1; i < argc; i++) {
1108 r = sd_bus_call_method(
1110 "org.freedesktop.login1",
1111 "/org/freedesktop/login1",
1112 "org.freedesktop.login1.Manager",
1115 "ssi", argv[i], arg_kill_who, arg_signal);
1117 log_error("Could not kill session: %s", bus_error_message(&error, -r));
1125 static int enable_linger(int argc, char *argv[], void *userdata) {
1126 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1127 sd_bus *bus = userdata;
1128 char* short_argv[3];
1135 polkit_agent_open_if_enabled();
1137 b = streq(argv[0], "enable-linger");
1140 short_argv[0] = argv[0];
1141 short_argv[1] = (char*) "";
1142 short_argv[2] = NULL;
1147 for (i = 1; i < argc; i++) {
1150 if (isempty(argv[i]))
1153 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1155 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1158 r = sd_bus_call_method(
1160 "org.freedesktop.login1",
1161 "/org/freedesktop/login1",
1162 "org.freedesktop.login1.Manager",
1165 "ubb", (uint32_t) uid, b, true);
1167 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1175 static int terminate_user(int argc, char *argv[], void *userdata) {
1176 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1177 sd_bus *bus = userdata;
1183 polkit_agent_open_if_enabled();
1185 for (i = 1; i < argc; i++) {
1188 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1190 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1192 r = sd_bus_call_method(
1194 "org.freedesktop.login1",
1195 "/org/freedesktop/login1",
1196 "org.freedesktop.login1.Manager",
1199 "u", (uint32_t) uid);
1201 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1209 static int kill_user(int argc, char *argv[], void *userdata) {
1210 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1211 sd_bus *bus = userdata;
1217 polkit_agent_open_if_enabled();
1220 arg_kill_who = "all";
1222 for (i = 1; i < argc; i++) {
1225 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1227 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1229 r = sd_bus_call_method(
1231 "org.freedesktop.login1",
1232 "/org/freedesktop/login1",
1233 "org.freedesktop.login1.Manager",
1236 "ui", (uint32_t) uid, arg_signal);
1238 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1246 static int attach(int argc, char *argv[], void *userdata) {
1247 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1248 sd_bus *bus = userdata;
1254 polkit_agent_open_if_enabled();
1256 for (i = 2; i < argc; i++) {
1258 r = sd_bus_call_method(
1260 "org.freedesktop.login1",
1261 "/org/freedesktop/login1",
1262 "org.freedesktop.login1.Manager",
1265 "ssb", argv[1], argv[i], true);
1268 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1276 static int flush_devices(int argc, char *argv[], void *userdata) {
1277 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1278 sd_bus *bus = userdata;
1284 polkit_agent_open_if_enabled();
1286 r = sd_bus_call_method(
1288 "org.freedesktop.login1",
1289 "/org/freedesktop/login1",
1290 "org.freedesktop.login1.Manager",
1295 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1300 static int lock_sessions(int argc, char *argv[], void *userdata) {
1301 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1302 sd_bus *bus = userdata;
1308 polkit_agent_open_if_enabled();
1310 r = sd_bus_call_method(
1312 "org.freedesktop.login1",
1313 "/org/freedesktop/login1",
1314 "org.freedesktop.login1.Manager",
1315 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1319 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1324 static int terminate_seat(int argc, char *argv[], void *userdata) {
1325 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1326 sd_bus *bus = userdata;
1332 polkit_agent_open_if_enabled();
1334 for (i = 1; i < argc; i++) {
1336 r = sd_bus_call_method(
1338 "org.freedesktop.login1",
1339 "/org/freedesktop/login1",
1340 "org.freedesktop.login1.Manager",
1345 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1353 /* Ask elogind, which might grant access to unprivileged users
1354 * through PolicyKit */
1355 static int reboot_with_logind(sd_bus *bus, enum action a) {
1356 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1359 static const char *table[_ACTION_MAX] = {
1360 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
1361 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
1362 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
1368 polkit_agent_open_if_enabled();
1372 case ACTION_POWEROFF:
1373 method = "PowerOff";
1380 case ACTION_SUSPEND:
1384 case ACTION_HIBERNATE:
1385 method = "Hibernate";
1388 case ACTION_HYBRID_SLEEP:
1389 method = "HybridSleep";
1392 case ACTION_CANCEL_SHUTDOWN:
1393 method = "CancelScheduledShutdown";
1401 r = sd_bus_call_method(
1403 "org.freedesktop.login1",
1404 "/org/freedesktop/login1",
1405 "org.freedesktop.login1.Manager",
1414 log_warning_errno(r, "Failed to set wall message, ignoring: %s",
1415 bus_error_message(&error, r));
1416 sd_bus_error_free(&error);
1421 r = sd_bus_call_method(
1423 "org.freedesktop.login1",
1424 "/org/freedesktop/login1",
1425 "org.freedesktop.login1.Manager",
1429 "b", arg_ask_password);
1431 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
1436 static const struct {
1437 HandleAction action;
1439 } action_table[_ACTION_MAX] = {
1440 [ACTION_POWEROFF] = { HANDLE_POWEROFF, "poweroff", },
1441 [ACTION_REBOOT] = { HANDLE_REBOOT, "reboot", },
1442 [ACTION_SUSPEND] = { HANDLE_SUSPEND, "suspend", },
1443 [ACTION_HIBERNATE] = { HANDLE_HIBERNATE, "hibernate", },
1444 [ACTION_HYBRID_SLEEP] = { HANDLE_HYBRID_SLEEP, "hybrid-sleep" },
1447 static enum action verb_to_action(const char *verb) {
1450 for (i = _ACTION_INVALID; i < _ACTION_MAX; i++)
1451 if (streq_ptr(action_table[i].verb, verb))
1454 return _ACTION_INVALID;
1457 static int check_inhibitors(sd_bus *bus, enum action a) {
1458 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1459 _cleanup_strv_free_ char **sessions = NULL;
1460 const char *what, *who, *why, *mode;
1469 if (arg_ignore_inhibitors)
1478 r = sd_bus_call_method(
1480 "org.freedesktop.login1",
1481 "/org/freedesktop/login1",
1482 "org.freedesktop.login1.Manager",
1488 /* If logind is not around, then there are no inhibitors... */
1491 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
1493 return bus_log_parse_error(r);
1495 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
1496 _cleanup_free_ char *comm = NULL, *user = NULL;
1497 _cleanup_strv_free_ char **sv = NULL;
1499 if (!streq(mode, "block"))
1502 sv = strv_split(what, ":");
1506 if ((pid_t) pid < 0)
1507 return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
1509 if (!strv_contains(sv,
1510 a == ACTION_POWEROFF ||
1511 a == ACTION_REBOOT ? "shutdown" : "sleep"))
1514 get_process_comm(pid, &comm);
1515 user = uid_to_name(uid);
1517 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
1518 who, (pid_t) pid, strna(comm), strna(user), why);
1523 return bus_log_parse_error(r);
1525 r = sd_bus_message_exit_container(reply);
1527 return bus_log_parse_error(r);
1529 /* Check for current sessions */
1530 sd_get_sessions(&sessions);
1531 STRV_FOREACH(s, sessions) {
1532 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1534 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1537 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1540 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1543 sd_session_get_tty(*s, &tty);
1544 sd_session_get_seat(*s, &seat);
1545 sd_session_get_service(*s, &service);
1546 user = uid_to_name(uid);
1548 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1555 log_error("Please retry operation after closing inhibitors and logging out other users.\n"
1556 "Alternatively, ignore inhibitors and users with 'loginctl %s -i'.",
1557 action_table[a].verb);
1562 static int start_special(int argc, char *argv[], void *userdata) {
1563 sd_bus *bus = userdata;
1569 a = verb_to_action(argv[0]);
1571 r = check_inhibitors(bus, a);
1575 /* Now power off actions in chroot environments */
1576 if ((a == ACTION_POWEROFF ||
1577 a == ACTION_REBOOT) &&
1578 (running_in_chroot() > 0) ) {
1579 log_info("Running in chroot, ignoring request.");
1583 /* Switch to cancel shutdown, if a shutdown action was requested,
1584 and the option to cancel it was set: */
1585 if ((a == ACTION_POWEROFF ||
1586 a == ACTION_REBOOT) &&
1587 (arg_action == ACTION_CANCEL_SHUTDOWN))
1588 return reboot_with_logind(bus, arg_action);
1590 /* Otherwise perform requested action */
1591 if (a == ACTION_POWEROFF ||
1592 a == ACTION_REBOOT ||
1593 a == ACTION_SUSPEND ||
1594 a == ACTION_HIBERNATE ||
1595 a == ACTION_HYBRID_SLEEP)
1596 return reboot_with_logind(bus, a);
1601 static int help(int argc, char *argv[], void *userdata) {
1603 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1604 "Send control commands to or query the login manager.\n\n"
1605 " -h --help Show this help\n"
1606 " --version Show package version\n"
1607 " --no-pager Do not pipe output into a pager\n"
1608 " --no-legend Do not show the headers and footers\n"
1609 " --no-ask-password Don't prompt for password\n"
1610 " -H --host=[USER@]HOST Operate on remote host\n"
1611 " -M --machine=CONTAINER Operate on local container\n"
1612 " -p --property=NAME Show only properties by this name\n"
1613 " -a --all Show all properties, including empty ones\n"
1614 " -l --full Do not ellipsize output\n"
1615 " --kill-who=WHO Who to send signal to\n"
1616 " -s --signal=SIGNAL Which signal to send\n"
1618 " -n --lines=INTEGER Number of journal entries to show\n"
1619 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1620 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1622 " -c Cancel a pending shutdown\n"
1623 " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n"
1624 "Session Commands:\n"
1625 " list-sessions List sessions\n"
1626 " session-status [ID...] Show session status\n"
1627 " show-session [ID...] Show properties of sessions or the manager\n"
1628 " activate [ID] Activate a session\n"
1629 " lock-session [ID...] Screen lock one or more sessions\n"
1630 " unlock-session [ID...] Screen unlock one or more sessions\n"
1631 " lock-sessions Screen lock all current sessions\n"
1632 " unlock-sessions Screen unlock all current sessions\n"
1633 " terminate-session ID... Terminate one or more sessions\n"
1634 " kill-session ID... Send signal to processes of a session\n\n"
1636 " list-users List users\n"
1637 " user-status [USER...] Show user status\n"
1638 " show-user [USER...] Show properties of users or the manager\n"
1639 " enable-linger [USER...] Enable linger state of one or more users\n"
1640 " disable-linger [USER...] Disable linger state of one or more users\n"
1641 " terminate-user USER... Terminate all sessions of one or more users\n"
1642 " kill-user USER... Send signal to processes of a user\n\n"
1644 " list-seats List seats\n"
1645 " seat-status [NAME...] Show seat status\n"
1646 " show-seat [NAME...] Show properties of seats or the manager\n"
1647 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1648 " flush-devices Flush all device associations\n"
1649 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1650 "System Commands:\n"
1651 " poweroff Turn off the machine\n"
1652 " reboot Reboot the machine\n"
1653 " suspend Suspend the machine to memory\n"
1654 " hibernate Suspend the machine to disk\n"
1655 " hybrid-sleep Suspend the machine to memory and disk\n"
1656 , program_invocation_short_name);
1661 static int parse_argv(int argc, char *argv[]) {
1664 ARG_VERSION = 0x100,
1668 ARG_NO_ASK_PASSWORD,
1671 static const struct option options[] = {
1672 { "help", no_argument, NULL, 'h' },
1673 { "version", no_argument, NULL, ARG_VERSION },
1674 { "property", required_argument, NULL, 'p' },
1675 { "all", no_argument, NULL, 'a' },
1676 { "full", no_argument, NULL, 'l' },
1677 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1678 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1679 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1680 { "signal", required_argument, NULL, 's' },
1681 { "host", required_argument, NULL, 'H' },
1682 { "machine", required_argument, NULL, 'M' },
1683 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1685 { "lines", required_argument, NULL, 'n' },
1686 { "output", required_argument, NULL, 'o' },
1688 { "ignore-inhibitors", no_argument, NULL, 'i' },
1697 while ((c = getopt_long(argc, argv, "hp:als:H:M:ci", options, NULL)) >= 0)
1702 help(0, NULL, NULL);
1709 r = strv_extend(&arg_property, optarg);
1713 /* If the user asked for a particular
1714 * property, show it to him, even if it is
1729 if (safe_atou(optarg, &arg_lines) < 0) {
1730 log_error("Failed to parse lines '%s'", optarg);
1736 arg_output = output_mode_from_string(optarg);
1737 if (arg_output < 0) {
1738 log_error("Unknown output '%s'.", optarg);
1744 arg_no_pager = true;
1751 case ARG_NO_ASK_PASSWORD:
1752 arg_ask_password = false;
1756 arg_kill_who = optarg;
1760 arg_signal = signal_from_string_try_harder(optarg);
1761 if (arg_signal < 0) {
1762 log_error("Failed to parse signal string %s.", optarg);
1768 arg_transport = BUS_TRANSPORT_REMOTE;
1773 arg_transport = BUS_TRANSPORT_MACHINE;
1778 arg_action = ACTION_CANCEL_SHUTDOWN;
1782 arg_ignore_inhibitors = true;
1789 assert_not_reached("Unhandled option");
1795 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1797 static const Verb verbs[] = {
1798 { "help", VERB_ANY, VERB_ANY, 0, help },
1799 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1800 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1801 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1802 { "activate", VERB_ANY, 2, 0, activate },
1803 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1804 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1805 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1806 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1807 { "terminate-session", 2, VERB_ANY, 0, activate },
1808 { "kill-session", 2, VERB_ANY, 0, kill_session },
1809 { "list-users", VERB_ANY, 1, 0, list_users },
1810 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1811 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1812 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1813 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1814 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1815 { "kill-user", 2, VERB_ANY, 0, kill_user },
1816 { "list-seats", VERB_ANY, 1, 0, list_seats },
1817 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1818 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1819 { "attach", 3, VERB_ANY, 0, attach },
1820 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1821 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1822 { "poweroff", VERB_ANY, 1, 0, start_special },
1823 { "reboot", VERB_ANY, 1, 0, start_special },
1824 { "suspend", VERB_ANY, 1, 0, start_special },
1825 { "hibernate", VERB_ANY, 1, 0, start_special },
1826 { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
1827 { "cancel-shutdown", VERB_ANY, 1, 0, start_special },
1831 return dispatch_verb(argc, argv, verbs, bus);
1834 int main(int argc, char *argv[]) {
1835 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
1838 setlocale(LC_ALL, "");
1839 elogind_set_program_name(argv[0]);
1840 log_parse_environment();
1843 r = parse_argv(argc, argv);
1847 r = bus_connect_transport(arg_transport, arg_host, false, &bus);
1849 log_error_errno(r, "Failed to create bus connection: %m");
1853 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1855 r = loginctl_main(argc, argv, bus);
1859 polkit_agent_close();
1861 strv_free(arg_property);
1863 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;