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 static OutputFlags get_output_flags(void) {
101 arg_all * OUTPUT_SHOW_ALL |
102 arg_full * OUTPUT_FULL_WIDTH |
103 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
104 on_tty() * OUTPUT_COLOR;
107 static int list_sessions(int argc, char *argv[], void *userdata) {
108 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
109 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
110 const char *id, *user, *seat, *object;
111 sd_bus *bus = userdata;
119 pager_open_if_enabled();
121 r = sd_bus_call_method(
123 "org.freedesktop.login1",
124 "/org/freedesktop/login1",
125 "org.freedesktop.login1.Manager",
130 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
134 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
136 return bus_log_parse_error(r);
139 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
141 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
142 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
146 return bus_log_parse_error(r);
149 printf("\n%u sessions listed.\n", k);
154 static int list_users(int argc, char *argv[], void *userdata) {
155 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
156 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
157 const char *user, *object;
158 sd_bus *bus = userdata;
166 pager_open_if_enabled();
168 r = sd_bus_call_method(
170 "org.freedesktop.login1",
171 "/org/freedesktop/login1",
172 "org.freedesktop.login1.Manager",
177 log_error("Failed to list users: %s", bus_error_message(&error, r));
181 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
183 return bus_log_parse_error(r);
186 printf("%10s %-16s\n", "UID", "USER");
188 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
189 printf("%10u %-16s\n", (unsigned) uid, user);
193 return bus_log_parse_error(r);
196 printf("\n%u users listed.\n", k);
201 static int list_seats(int argc, char *argv[], void *userdata) {
202 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
203 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
204 const char *seat, *object;
205 sd_bus *bus = userdata;
212 pager_open_if_enabled();
214 r = sd_bus_call_method(
216 "org.freedesktop.login1",
217 "/org/freedesktop/login1",
218 "org.freedesktop.login1.Manager",
223 log_error("Failed to list seats: %s", bus_error_message(&error, r));
227 r = sd_bus_message_enter_container(reply, 'a', "(so)");
229 return bus_log_parse_error(r);
232 printf("%-16s\n", "SEAT");
234 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
235 printf("%-16s\n", seat);
239 return bus_log_parse_error(r);
242 printf("\n%u seats listed.\n", k);
247 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
248 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
249 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
250 _cleanup_free_ char *path = NULL;
258 if (arg_transport != BUS_TRANSPORT_LOCAL)
261 path = unit_dbus_path_from_name(unit);
265 r = sd_bus_get_property(
267 "org.freedesktop.systemd1",
271 &error, &reply, "s");
275 r = sd_bus_message_read(reply, "s", &cgroup);
282 if (cg_is_empty_recursive(ELOGIND_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
291 show_cgroup_and_extra(ELOGIND_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
295 typedef struct SessionStatusInfo {
299 struct dual_timestamp timestamp;
316 typedef struct UserStatusInfo {
319 struct dual_timestamp timestamp;
326 typedef struct SeatStatusInfo {
328 char *active_session;
332 static void session_status_info_clear(SessionStatusInfo *info) {
339 free(info->remote_host);
340 free(info->remote_user);
351 static void user_status_info_clear(UserStatusInfo *info) {
355 strv_free(info->sessions);
362 static void seat_status_info_clear(SeatStatusInfo *info) {
365 free(info->active_session);
366 strv_free(info->sessions);
371 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
372 const char *contents;
375 r = sd_bus_message_peek_type(m, NULL, &contents);
379 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
383 if (contents[0] == 's' || contents[0] == 'o') {
385 char **p = (char **) userdata;
387 r = sd_bus_message_read_basic(m, contents[0], &s);
391 r = free_and_strdup(p, s);
395 r = sd_bus_message_read_basic(m, contents[0], userdata);
400 r = sd_bus_message_skip(m, contents+1);
404 r = sd_bus_message_exit_container(m);
411 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
418 r = sd_bus_message_enter_container(m, 'a', "(so)");
422 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
423 r = strv_extend(userdata, name);
430 return sd_bus_message_exit_container(m);
433 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
435 static const struct bus_properties_map map[] = {
436 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
437 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
438 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
439 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
440 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
441 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
442 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
443 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
444 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
445 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
446 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
447 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
448 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
449 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
450 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
451 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
452 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
453 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
454 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
458 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
459 char since2[FORMAT_TIMESTAMP_MAX], *s2;
460 _cleanup_(session_status_info_clear) SessionStatusInfo i = {};
463 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
465 return log_error_errno(r, "Could not get properties: %m");
472 printf("%s - ", strna(i.id));
475 printf("%s (%u)\n", i.name, (unsigned) i.uid);
477 printf("%u\n", (unsigned) i.uid);
479 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
480 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
483 printf("\t Since: %s; %s\n", s2, s1);
485 printf("\t Since: %s\n", s2);
488 _cleanup_free_ char *t = NULL;
490 printf("\t Leader: %u", (unsigned) i.leader);
492 get_process_comm(i.leader, &t);
499 if (!isempty(i.seat)) {
500 printf("\t Seat: %s", i.seat);
503 printf("; vc%u", i.vtnr);
509 printf("\t TTY: %s\n", i.tty);
511 printf("\t Display: %s\n", i.display);
513 if (i.remote_host && i.remote_user)
514 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
515 else if (i.remote_host)
516 printf("\t Remote: %s\n", i.remote_host);
517 else if (i.remote_user)
518 printf("\t Remote: user %s\n", i.remote_user);
520 printf("\t Remote: Yes\n");
523 printf("\t Service: %s", i.service);
526 printf("; type %s", i.type);
529 printf("; class %s", i.class);
533 printf("\t Type: %s", i.type);
536 printf("; class %s", i.class);
540 printf("\t Class: %s\n", i.class);
542 if (!isempty(i.desktop))
543 printf("\t Desktop: %s\n", i.desktop);
546 printf("\t State: %s\n", i.state);
549 printf("\t Unit: %s\n", i.scope);
550 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
552 if (arg_transport == BUS_TRANSPORT_LOCAL) {
554 show_journal_by_unit(
559 i.timestamp.monotonic,
562 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
563 SD_JOURNAL_LOCAL_ONLY,
574 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
576 static const struct bus_properties_map map[] = {
577 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
578 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
579 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
580 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
581 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
582 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
583 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
584 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
588 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
589 char since2[FORMAT_TIMESTAMP_MAX], *s2;
590 _cleanup_(user_status_info_clear) UserStatusInfo i = {};
593 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
595 return log_error_errno(r, "Could not get properties: %m");
603 printf("%s (%u)\n", i.name, (unsigned) i.uid);
605 printf("%u\n", (unsigned) i.uid);
607 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
608 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
611 printf("\t Since: %s; %s\n", s2, s1);
613 printf("\t Since: %s\n", s2);
615 if (!isempty(i.state))
616 printf("\t State: %s\n", i.state);
618 if (!strv_isempty(i.sessions)) {
620 printf("\tSessions:");
622 STRV_FOREACH(l, i.sessions) {
623 if (streq_ptr(*l, i.display))
633 printf("\t Unit: %s\n", i.slice);
634 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
636 show_journal_by_unit(
641 i.timestamp.monotonic,
644 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
645 SD_JOURNAL_LOCAL_ONLY,
655 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
657 static const struct bus_properties_map map[] = {
658 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
659 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
660 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
664 _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
667 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
669 return log_error_errno(r, "Could not get properties: %m");
676 printf("%s\n", strna(i.id));
678 if (!strv_isempty(i.sessions)) {
680 printf("\tSessions:");
682 STRV_FOREACH(l, i.sessions) {
683 if (streq_ptr(*l, i.active_session))
692 if (arg_transport == BUS_TRANSPORT_LOCAL) {
701 printf("\t Devices:\n");
703 show_sysfs(i.id, "\t\t ", c);
709 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
717 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
719 log_error_errno(r, "Could not get properties: %m");
724 static int show_session(int argc, char *argv[], void *userdata) {
725 bool properties, new_line = false;
726 sd_bus *bus = userdata;
732 properties = !strstr(argv[0], "status");
734 pager_open_if_enabled();
737 /* If not argument is specified inspect the manager
740 return show_properties(bus, "/org/freedesktop/login1", &new_line);
742 /* And in the pretty case, show data of the calling session */
743 return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
746 for (i = 1; i < argc; i++) {
747 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
748 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
749 const char *path = NULL;
751 r = sd_bus_call_method(
753 "org.freedesktop.login1",
754 "/org/freedesktop/login1",
755 "org.freedesktop.login1.Manager",
760 log_error("Failed to get session: %s", bus_error_message(&error, r));
764 r = sd_bus_message_read(reply, "o", &path);
766 return bus_log_parse_error(r);
769 r = show_properties(bus, path, &new_line);
771 r = print_session_status_info(bus, path, &new_line);
780 static int show_user(int argc, char *argv[], void *userdata) {
781 bool properties, new_line = false;
782 sd_bus *bus = userdata;
788 properties = !strstr(argv[0], "status");
790 pager_open_if_enabled();
793 /* If not argument is specified inspect the manager
796 return show_properties(bus, "/org/freedesktop/login1", &new_line);
798 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
801 for (i = 1; i < argc; i++) {
802 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
803 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
804 const char *path = NULL;
807 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
809 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
811 r = sd_bus_call_method(
813 "org.freedesktop.login1",
814 "/org/freedesktop/login1",
815 "org.freedesktop.login1.Manager",
818 "u", (uint32_t) uid);
820 log_error("Failed to get user: %s", bus_error_message(&error, r));
824 r = sd_bus_message_read(reply, "o", &path);
826 return bus_log_parse_error(r);
829 r = show_properties(bus, path, &new_line);
831 r = print_user_status_info(bus, path, &new_line);
840 static int show_seat(int argc, char *argv[], void *userdata) {
841 bool properties, new_line = false;
842 sd_bus *bus = userdata;
848 properties = !strstr(argv[0], "status");
850 pager_open_if_enabled();
853 /* If not argument is specified inspect the manager
856 return show_properties(bus, "/org/freedesktop/login1", &new_line);
858 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
861 for (i = 1; i < argc; i++) {
862 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
863 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
864 const char *path = NULL;
866 r = sd_bus_call_method(
868 "org.freedesktop.login1",
869 "/org/freedesktop/login1",
870 "org.freedesktop.login1.Manager",
875 log_error("Failed to get seat: %s", bus_error_message(&error, r));
879 r = sd_bus_message_read(reply, "o", &path);
881 return bus_log_parse_error(r);
884 r = show_properties(bus, path, &new_line);
886 r = print_seat_status_info(bus, path, &new_line);
895 static int activate(int argc, char *argv[], void *userdata) {
896 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
897 sd_bus *bus = userdata;
904 polkit_agent_open_if_enabled();
907 /* No argument? Let's convert this into the empty
908 * session name, which the calls will then resolve to
909 * the caller's session. */
911 short_argv[0] = argv[0];
912 short_argv[1] = (char*) "";
913 short_argv[2] = NULL;
919 for (i = 1; i < argc; i++) {
921 r = sd_bus_call_method(
923 "org.freedesktop.login1",
924 "/org/freedesktop/login1",
925 "org.freedesktop.login1.Manager",
926 streq(argv[0], "lock-session") ? "LockSession" :
927 streq(argv[0], "unlock-session") ? "UnlockSession" :
928 streq(argv[0], "terminate-session") ? "TerminateSession" :
933 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
941 static int kill_session(int argc, char *argv[], void *userdata) {
942 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
943 sd_bus *bus = userdata;
949 polkit_agent_open_if_enabled();
952 arg_kill_who = "all";
954 for (i = 1; i < argc; i++) {
956 r = sd_bus_call_method(
958 "org.freedesktop.login1",
959 "/org/freedesktop/login1",
960 "org.freedesktop.login1.Manager",
963 "ssi", argv[i], arg_kill_who, arg_signal);
965 log_error("Could not kill session: %s", bus_error_message(&error, -r));
973 static int enable_linger(int argc, char *argv[], void *userdata) {
974 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
975 sd_bus *bus = userdata;
983 polkit_agent_open_if_enabled();
985 b = streq(argv[0], "enable-linger");
988 short_argv[0] = argv[0];
989 short_argv[1] = (char*) "";
990 short_argv[2] = NULL;
995 for (i = 1; i < argc; i++) {
998 if (isempty(argv[i]))
1001 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1003 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1006 r = sd_bus_call_method(
1008 "org.freedesktop.login1",
1009 "/org/freedesktop/login1",
1010 "org.freedesktop.login1.Manager",
1013 "ubb", (uint32_t) uid, b, true);
1015 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1023 static int terminate_user(int argc, char *argv[], void *userdata) {
1024 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1025 sd_bus *bus = userdata;
1031 polkit_agent_open_if_enabled();
1033 for (i = 1; i < argc; i++) {
1036 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1038 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1040 r = sd_bus_call_method(
1042 "org.freedesktop.login1",
1043 "/org/freedesktop/login1",
1044 "org.freedesktop.login1.Manager",
1047 "u", (uint32_t) uid);
1049 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1057 static int kill_user(int argc, char *argv[], void *userdata) {
1058 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1059 sd_bus *bus = userdata;
1065 polkit_agent_open_if_enabled();
1068 arg_kill_who = "all";
1070 for (i = 1; i < argc; i++) {
1073 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1075 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1077 r = sd_bus_call_method(
1079 "org.freedesktop.login1",
1080 "/org/freedesktop/login1",
1081 "org.freedesktop.login1.Manager",
1084 "ui", (uint32_t) uid, arg_signal);
1086 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1094 static int attach(int argc, char *argv[], void *userdata) {
1095 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1096 sd_bus *bus = userdata;
1102 polkit_agent_open_if_enabled();
1104 for (i = 2; i < argc; i++) {
1106 r = sd_bus_call_method(
1108 "org.freedesktop.login1",
1109 "/org/freedesktop/login1",
1110 "org.freedesktop.login1.Manager",
1113 "ssb", argv[1], argv[i], true);
1116 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1124 static int flush_devices(int argc, char *argv[], void *userdata) {
1125 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1126 sd_bus *bus = userdata;
1132 polkit_agent_open_if_enabled();
1134 r = sd_bus_call_method(
1136 "org.freedesktop.login1",
1137 "/org/freedesktop/login1",
1138 "org.freedesktop.login1.Manager",
1143 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1148 static int lock_sessions(int argc, char *argv[], void *userdata) {
1149 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1150 sd_bus *bus = userdata;
1156 polkit_agent_open_if_enabled();
1158 r = sd_bus_call_method(
1160 "org.freedesktop.login1",
1161 "/org/freedesktop/login1",
1162 "org.freedesktop.login1.Manager",
1163 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1167 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1172 static int terminate_seat(int argc, char *argv[], void *userdata) {
1173 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1174 sd_bus *bus = userdata;
1180 polkit_agent_open_if_enabled();
1182 for (i = 1; i < argc; i++) {
1184 r = sd_bus_call_method(
1186 "org.freedesktop.login1",
1187 "/org/freedesktop/login1",
1188 "org.freedesktop.login1.Manager",
1193 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1201 /* Ask elogind, which might grant access to unprivileged users
1202 * through PolicyKit */
1203 static int reboot_with_logind(sd_bus *bus, enum action a) {
1204 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1207 static const char *table[_ACTION_MAX] = {
1208 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
1209 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
1210 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
1216 polkit_agent_open_if_enabled();
1220 case ACTION_POWEROFF:
1221 method = "PowerOff";
1228 case ACTION_SUSPEND:
1232 case ACTION_HIBERNATE:
1233 method = "Hibernate";
1236 case ACTION_HYBRID_SLEEP:
1237 method = "HybridSleep";
1240 case ACTION_CANCEL_SHUTDOWN:
1241 method = "CancelScheduledShutdown";
1249 r = sd_bus_call_method(
1251 "org.freedesktop.login1",
1252 "/org/freedesktop/login1",
1253 "org.freedesktop.login1.Manager",
1262 log_warning_errno(r, "Failed to set wall message, ignoring: %s",
1263 bus_error_message(&error, r));
1264 sd_bus_error_free(&error);
1269 r = sd_bus_call_method(
1271 "org.freedesktop.login1",
1272 "/org/freedesktop/login1",
1273 "org.freedesktop.login1.Manager",
1277 "b", arg_ask_password);
1279 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
1284 static const struct {
1285 HandleAction action;
1287 } action_table[_ACTION_MAX] = {
1288 [ACTION_POWEROFF] = { HANDLE_POWEROFF, "poweroff", },
1289 [ACTION_REBOOT] = { HANDLE_REBOOT, "reboot", },
1290 [ACTION_SUSPEND] = { HANDLE_SUSPEND, "suspend", },
1291 [ACTION_HIBERNATE] = { HANDLE_HIBERNATE, "hibernate", },
1292 [ACTION_HYBRID_SLEEP] = { HANDLE_HYBRID_SLEEP, "hybrid-sleep" },
1295 static enum action verb_to_action(const char *verb) {
1298 for (i = _ACTION_INVALID; i < _ACTION_MAX; i++)
1299 if (streq_ptr(action_table[i].verb, verb))
1302 return _ACTION_INVALID;
1305 static int check_inhibitors(sd_bus *bus, enum action a) {
1306 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1307 _cleanup_strv_free_ char **sessions = NULL;
1308 const char *what, *who, *why, *mode;
1317 if (arg_ignore_inhibitors)
1326 r = sd_bus_call_method(
1328 "org.freedesktop.login1",
1329 "/org/freedesktop/login1",
1330 "org.freedesktop.login1.Manager",
1336 /* If logind is not around, then there are no inhibitors... */
1339 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
1341 return bus_log_parse_error(r);
1343 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
1344 _cleanup_free_ char *comm = NULL, *user = NULL;
1345 _cleanup_strv_free_ char **sv = NULL;
1347 if (!streq(mode, "block"))
1350 sv = strv_split(what, ":");
1354 if ((pid_t) pid < 0)
1355 return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
1357 if (!strv_contains(sv,
1358 a == ACTION_POWEROFF ||
1359 a == ACTION_REBOOT ? "shutdown" : "sleep"))
1362 get_process_comm(pid, &comm);
1363 user = uid_to_name(uid);
1365 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
1366 who, (pid_t) pid, strna(comm), strna(user), why);
1371 return bus_log_parse_error(r);
1373 r = sd_bus_message_exit_container(reply);
1375 return bus_log_parse_error(r);
1377 /* Check for current sessions */
1378 sd_get_sessions(&sessions);
1379 STRV_FOREACH(s, sessions) {
1380 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1382 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1385 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1388 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1391 sd_session_get_tty(*s, &tty);
1392 sd_session_get_seat(*s, &seat);
1393 sd_session_get_service(*s, &service);
1394 user = uid_to_name(uid);
1396 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1403 log_error("Please retry operation after closing inhibitors and logging out other users.\n"
1404 "Alternatively, ignore inhibitors and users with 'loginctl %s -i'.",
1405 action_table[a].verb);
1410 static int start_special(int argc, char *argv[], void *userdata) {
1411 sd_bus *bus = userdata;
1417 a = verb_to_action(argv[0]);
1419 r = check_inhibitors(bus, a);
1423 /* Now power off actions in chroot environments */
1424 if ((a == ACTION_POWEROFF ||
1425 a == ACTION_REBOOT) &&
1426 (running_in_chroot() > 0) ) {
1427 log_info("Running in chroot, ignoring request.");
1431 /* Switch to cancel shutdown, if a shutdown action was requested,
1432 and the option to cancel it was set: */
1433 if ((a == ACTION_POWEROFF ||
1434 a == ACTION_REBOOT) &&
1435 (arg_action == ACTION_CANCEL_SHUTDOWN))
1436 return reboot_with_logind(bus, arg_action);
1438 /* Otherwise perform requested action */
1439 if (a == ACTION_POWEROFF ||
1440 a == ACTION_REBOOT ||
1441 a == ACTION_SUSPEND ||
1442 a == ACTION_HIBERNATE ||
1443 a == ACTION_HYBRID_SLEEP)
1444 return reboot_with_logind(bus, a);
1449 static int help(int argc, char *argv[], void *userdata) {
1451 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1452 "Send control commands to or query the login manager.\n\n"
1453 " -h --help Show this help\n"
1454 " --version Show package version\n"
1455 " --no-pager Do not pipe output into a pager\n"
1456 " --no-legend Do not show the headers and footers\n"
1457 " --no-ask-password Don't prompt for password\n"
1458 " -H --host=[USER@]HOST Operate on remote host\n"
1459 " -M --machine=CONTAINER Operate on local container\n"
1460 " -p --property=NAME Show only properties by this name\n"
1461 " -a --all Show all properties, including empty ones\n"
1462 " -l --full Do not ellipsize output\n"
1463 " --kill-who=WHO Who to send signal to\n"
1464 " -s --signal=SIGNAL Which signal to send\n"
1466 " -n --lines=INTEGER Number of journal entries to show\n"
1467 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1468 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1470 " -c Cancel a pending shutdown\n"
1471 " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n"
1472 "Session Commands:\n"
1473 " list-sessions List sessions\n"
1474 " session-status [ID...] Show session status\n"
1475 " show-session [ID...] Show properties of sessions or the manager\n"
1476 " activate [ID] Activate a session\n"
1477 " lock-session [ID...] Screen lock one or more sessions\n"
1478 " unlock-session [ID...] Screen unlock one or more sessions\n"
1479 " lock-sessions Screen lock all current sessions\n"
1480 " unlock-sessions Screen unlock all current sessions\n"
1481 " terminate-session ID... Terminate one or more sessions\n"
1482 " kill-session ID... Send signal to processes of a session\n\n"
1484 " list-users List users\n"
1485 " user-status [USER...] Show user status\n"
1486 " show-user [USER...] Show properties of users or the manager\n"
1487 " enable-linger [USER...] Enable linger state of one or more users\n"
1488 " disable-linger [USER...] Disable linger state of one or more users\n"
1489 " terminate-user USER... Terminate all sessions of one or more users\n"
1490 " kill-user USER... Send signal to processes of a user\n\n"
1492 " list-seats List seats\n"
1493 " seat-status [NAME...] Show seat status\n"
1494 " show-seat [NAME...] Show properties of seats or the manager\n"
1495 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1496 " flush-devices Flush all device associations\n"
1497 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1498 "System Commands:\n"
1499 " poweroff Turn off the machine\n"
1500 " reboot Reboot the machine\n"
1501 " suspend Suspend the machine to memory\n"
1502 " hibernate Suspend the machine to disk\n"
1503 " hybrid-sleep Suspend the machine to memory and disk\n"
1504 , program_invocation_short_name);
1509 static int parse_argv(int argc, char *argv[]) {
1512 ARG_VERSION = 0x100,
1516 ARG_NO_ASK_PASSWORD,
1519 static const struct option options[] = {
1520 { "help", no_argument, NULL, 'h' },
1521 { "version", no_argument, NULL, ARG_VERSION },
1522 { "property", required_argument, NULL, 'p' },
1523 { "all", no_argument, NULL, 'a' },
1524 { "full", no_argument, NULL, 'l' },
1525 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1526 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1527 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1528 { "signal", required_argument, NULL, 's' },
1529 { "host", required_argument, NULL, 'H' },
1530 { "machine", required_argument, NULL, 'M' },
1531 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1533 { "lines", required_argument, NULL, 'n' },
1534 { "output", required_argument, NULL, 'o' },
1536 { "ignore-inhibitors", no_argument, NULL, 'i' },
1545 while ((c = getopt_long(argc, argv, "hp:als:H:M:ci", options, NULL)) >= 0)
1550 help(0, NULL, NULL);
1554 puts(PACKAGE_STRING);
1555 puts(SYSTEMD_FEATURES);
1559 r = strv_extend(&arg_property, optarg);
1563 /* If the user asked for a particular
1564 * property, show it to him, even if it is
1579 if (safe_atou(optarg, &arg_lines) < 0) {
1580 log_error("Failed to parse lines '%s'", optarg);
1586 arg_output = output_mode_from_string(optarg);
1587 if (arg_output < 0) {
1588 log_error("Unknown output '%s'.", optarg);
1594 arg_no_pager = true;
1601 case ARG_NO_ASK_PASSWORD:
1602 arg_ask_password = false;
1606 arg_kill_who = optarg;
1610 arg_signal = signal_from_string_try_harder(optarg);
1611 if (arg_signal < 0) {
1612 log_error("Failed to parse signal string %s.", optarg);
1618 arg_transport = BUS_TRANSPORT_REMOTE;
1623 arg_transport = BUS_TRANSPORT_MACHINE;
1628 arg_action = ACTION_CANCEL_SHUTDOWN;
1632 arg_ignore_inhibitors = true;
1639 assert_not_reached("Unhandled option");
1645 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1647 static const Verb verbs[] = {
1648 { "help", VERB_ANY, VERB_ANY, 0, help },
1649 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1650 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1651 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1652 { "activate", VERB_ANY, 2, 0, activate },
1653 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1654 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1655 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1656 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1657 { "terminate-session", 2, VERB_ANY, 0, activate },
1658 { "kill-session", 2, VERB_ANY, 0, kill_session },
1659 { "list-users", VERB_ANY, 1, 0, list_users },
1660 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1661 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1662 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1663 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1664 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1665 { "kill-user", 2, VERB_ANY, 0, kill_user },
1666 { "list-seats", VERB_ANY, 1, 0, list_seats },
1667 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1668 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1669 { "attach", 3, VERB_ANY, 0, attach },
1670 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1671 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1672 { "poweroff", VERB_ANY, 1, 0, start_special },
1673 { "reboot", VERB_ANY, 1, 0, start_special },
1674 { "suspend", VERB_ANY, 1, 0, start_special },
1675 { "hibernate", VERB_ANY, 1, 0, start_special },
1676 { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
1677 { "cancel-shutdown", VERB_ANY, 1, 0, start_special },
1681 return dispatch_verb(argc, argv, verbs, bus);
1684 int main(int argc, char *argv[]) {
1685 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
1688 setlocale(LC_ALL, "");
1689 log_parse_environment();
1692 r = parse_argv(argc, argv);
1696 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1698 log_error_errno(r, "Failed to create bus connection: %m");
1702 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1704 r = loginctl_main(argc, argv, bus);
1708 polkit_agent_close();
1710 strv_free(arg_property);
1712 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;