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/>.
30 #include "alloc-util.h"
31 #include "bus-error.h"
33 //#include "cgroup-show.h"
34 #include "cgroup-util.h"
36 //#include "logs-show.h"
39 #include "parse-util.h"
40 #include "process-util.h"
41 #include "signal-util.h"
42 #include "spawn-polkit-agent.h"
44 #include "sysfs-show.h"
45 #include "terminal-util.h"
46 #include "unit-name.h"
47 #include "user-util.h"
51 /// Additional includes for elogind
52 #include "logind-action.h"
53 #include "musl_missing.h"
57 static char **arg_property = NULL;
58 static bool arg_all = false;
59 static bool arg_full = false;
60 static bool arg_no_pager = false;
61 static bool arg_legend = true;
62 static const char *arg_kill_who = NULL;
63 static int arg_signal = SIGTERM;
64 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
65 static char *arg_host = NULL;
66 static bool arg_ask_password = true;
67 static bool arg_ignore_inhibitors = false;
69 static unsigned arg_lines = 10;
70 static OutputMode arg_output = OUTPUT_SHORT;
79 ACTION_CANCEL_SHUTDOWN,
84 static void pager_open_if_enabled(void) {
92 static void polkit_agent_open_if_enabled(void) {
94 /* Open the polkit agent as a child process if necessary */
96 if (!arg_ask_password)
99 if (arg_transport != BUS_TRANSPORT_LOCAL)
105 /// UNNEEDED by elogind
107 static OutputFlags get_output_flags(void) {
110 arg_all * OUTPUT_SHOW_ALL |
111 arg_full * OUTPUT_FULL_WIDTH |
112 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
113 on_tty() * OUTPUT_COLOR;
117 static int list_sessions(int argc, char *argv[], void *userdata) {
118 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
119 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
120 const char *id, *user, *seat, *object;
121 sd_bus *bus = userdata;
129 pager_open_if_enabled();
131 r = sd_bus_call_method(
133 "org.freedesktop.login1",
134 "/org/freedesktop/login1",
135 "org.freedesktop.login1.Manager",
140 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
144 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
146 return bus_log_parse_error(r);
149 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
151 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
152 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
156 return bus_log_parse_error(r);
159 printf("\n%u sessions listed.\n", k);
164 static int list_users(int argc, char *argv[], void *userdata) {
165 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
166 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
167 const char *user, *object;
168 sd_bus *bus = userdata;
176 pager_open_if_enabled();
178 r = sd_bus_call_method(
180 "org.freedesktop.login1",
181 "/org/freedesktop/login1",
182 "org.freedesktop.login1.Manager",
187 log_error("Failed to list users: %s", bus_error_message(&error, r));
191 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
193 return bus_log_parse_error(r);
196 printf("%10s %-16s\n", "UID", "USER");
198 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
199 printf("%10u %-16s\n", (unsigned) uid, user);
203 return bus_log_parse_error(r);
206 printf("\n%u users listed.\n", k);
211 static int list_seats(int argc, char *argv[], void *userdata) {
212 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
213 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
214 const char *seat, *object;
215 sd_bus *bus = userdata;
222 pager_open_if_enabled();
224 r = sd_bus_call_method(
226 "org.freedesktop.login1",
227 "/org/freedesktop/login1",
228 "org.freedesktop.login1.Manager",
233 log_error("Failed to list seats: %s", bus_error_message(&error, r));
237 r = sd_bus_message_enter_container(reply, 'a', "(so)");
239 return bus_log_parse_error(r);
242 printf("%-16s\n", "SEAT");
244 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
245 printf("%-16s\n", seat);
249 return bus_log_parse_error(r);
252 printf("\n%u seats listed.\n", k);
257 /// UNNEEDED by elogind
259 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
260 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
261 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
262 _cleanup_free_ char *path = NULL;
270 if (arg_transport != BUS_TRANSPORT_LOCAL)
273 path = unit_dbus_path_from_name(unit);
277 r = sd_bus_get_property(
279 "org.freedesktop.systemd1",
283 &error, &reply, "s");
287 r = sd_bus_message_read(reply, "s", &cgroup);
294 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
303 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
308 typedef struct SessionStatusInfo {
312 struct dual_timestamp timestamp;
329 typedef struct UserStatusInfo {
332 struct dual_timestamp timestamp;
339 typedef struct SeatStatusInfo {
341 char *active_session;
345 static void session_status_info_clear(SessionStatusInfo *info) {
352 free(info->remote_host);
353 free(info->remote_user);
364 static void user_status_info_clear(UserStatusInfo *info) {
368 strv_free(info->sessions);
375 static void seat_status_info_clear(SeatStatusInfo *info) {
378 free(info->active_session);
379 strv_free(info->sessions);
384 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
385 const char *contents;
388 r = sd_bus_message_peek_type(m, NULL, &contents);
392 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
396 if (contents[0] == 's' || contents[0] == 'o') {
398 char **p = (char **) userdata;
400 r = sd_bus_message_read_basic(m, contents[0], &s);
404 r = free_and_strdup(p, s);
408 r = sd_bus_message_read_basic(m, contents[0], userdata);
413 r = sd_bus_message_skip(m, contents+1);
417 r = sd_bus_message_exit_container(m);
424 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
431 r = sd_bus_message_enter_container(m, 'a', "(so)");
435 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
436 r = strv_extend(userdata, name);
443 return sd_bus_message_exit_container(m);
446 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
448 static const struct bus_properties_map map[] = {
449 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
450 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
451 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
452 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
453 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
454 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
455 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
456 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
457 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
458 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
459 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
460 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
461 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
462 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
463 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
464 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
465 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
466 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
467 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
471 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
472 char since2[FORMAT_TIMESTAMP_MAX], *s2;
473 _cleanup_(session_status_info_clear) SessionStatusInfo i = {};
476 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
478 return log_error_errno(r, "Could not get properties: %m");
485 printf("%s - ", strna(i.id));
488 printf("%s (%u)\n", i.name, (unsigned) i.uid);
490 printf("%u\n", (unsigned) i.uid);
492 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
493 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
496 printf("\t Since: %s; %s\n", s2, s1);
498 printf("\t Since: %s\n", s2);
501 _cleanup_free_ char *t = NULL;
503 printf("\t Leader: %u", (unsigned) i.leader);
505 get_process_comm(i.leader, &t);
512 if (!isempty(i.seat)) {
513 printf("\t Seat: %s", i.seat);
516 printf("; vc%u", i.vtnr);
522 printf("\t TTY: %s\n", i.tty);
524 printf("\t Display: %s\n", i.display);
526 if (i.remote_host && i.remote_user)
527 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
528 else if (i.remote_host)
529 printf("\t Remote: %s\n", i.remote_host);
530 else if (i.remote_user)
531 printf("\t Remote: user %s\n", i.remote_user);
533 printf("\t Remote: Yes\n");
536 printf("\t Service: %s", i.service);
539 printf("; type %s", i.type);
542 printf("; class %s", i.class);
546 printf("\t Type: %s", i.type);
549 printf("; class %s", i.class);
553 printf("\t Class: %s\n", i.class);
555 if (!isempty(i.desktop))
556 printf("\t Desktop: %s\n", i.desktop);
559 printf("\t State: %s\n", i.state);
562 printf("\t Unit: %s\n", i.scope);
564 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
565 if (arg_transport == BUS_TRANSPORT_LOCAL) {
567 show_journal_by_unit(
572 i.timestamp.monotonic,
575 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
576 SD_JOURNAL_LOCAL_ONLY,
587 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
589 static const struct bus_properties_map map[] = {
590 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
591 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
592 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
593 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
594 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
595 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
596 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
597 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
601 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
602 char since2[FORMAT_TIMESTAMP_MAX], *s2;
603 _cleanup_(user_status_info_clear) UserStatusInfo i = {};
606 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
608 return log_error_errno(r, "Could not get properties: %m");
616 printf("%s (%u)\n", i.name, (unsigned) i.uid);
618 printf("%u\n", (unsigned) i.uid);
620 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
621 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
624 printf("\t Since: %s; %s\n", s2, s1);
626 printf("\t Since: %s\n", s2);
628 if (!isempty(i.state))
629 printf("\t State: %s\n", i.state);
631 if (!strv_isempty(i.sessions)) {
633 printf("\tSessions:");
635 STRV_FOREACH(l, i.sessions) {
636 if (streq_ptr(*l, i.display))
646 printf("\t Unit: %s\n", i.slice);
648 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
649 show_journal_by_unit(
654 i.timestamp.monotonic,
657 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
658 SD_JOURNAL_LOCAL_ONLY,
668 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
670 static const struct bus_properties_map map[] = {
671 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
672 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
673 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
677 _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
680 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
682 return log_error_errno(r, "Could not get properties: %m");
689 printf("%s\n", strna(i.id));
691 if (!strv_isempty(i.sessions)) {
693 printf("\tSessions:");
695 STRV_FOREACH(l, i.sessions) {
696 if (streq_ptr(*l, i.active_session))
705 if (arg_transport == BUS_TRANSPORT_LOCAL) {
714 printf("\t Devices:\n");
716 show_sysfs(i.id, "\t\t ", c);
722 static int print_property(const char *name, sd_bus_message *m, const char *contents) {
729 if (arg_property && !strv_find(arg_property, name))
730 /* skip what we didn't read */
731 return sd_bus_message_skip(m, contents);
733 switch (contents[0]) {
735 case SD_BUS_TYPE_STRUCT_BEGIN:
737 if (contents[1] == SD_BUS_TYPE_STRING && STR_IN_SET(name, "Display", "Seat", "ActiveSession")) {
740 r = sd_bus_message_read(m, "(so)", &s, NULL);
742 return bus_log_parse_error(r);
744 if (arg_all || !isempty(s))
745 printf("%s=%s\n", name, s);
749 } else if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "User")) {
752 r = sd_bus_message_read(m, "(uo)", &uid, NULL);
754 return bus_log_parse_error(r);
756 if (!uid_is_valid(uid)) {
757 log_error("Invalid user ID: " UID_FMT, uid);
761 printf("%s=" UID_FMT "\n", name, uid);
768 case SD_BUS_TYPE_ARRAY:
770 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Sessions")) {
774 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(so)");
776 return bus_log_parse_error(r);
780 while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
781 printf("%s%s", space ? " " : "", s);
788 return bus_log_parse_error(r);
790 r = sd_bus_message_exit_container(m);
792 return bus_log_parse_error(r);
800 r = bus_print_property(name, m, arg_all);
802 return bus_log_parse_error(r);
805 r = sd_bus_message_skip(m, contents);
807 return bus_log_parse_error(r);
810 printf("%s=[unprintable]\n", name);
816 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
817 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
818 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
825 r = sd_bus_call_method(
827 "org.freedesktop.login1",
829 "org.freedesktop.DBus.Properties",
835 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
837 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
839 return bus_log_parse_error(r);
846 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
847 const char *name, *contents;
849 r = sd_bus_message_read(reply, "s", &name);
851 return bus_log_parse_error(r);
853 r = sd_bus_message_peek_type(reply, NULL, &contents);
855 return bus_log_parse_error(r);
857 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
859 return bus_log_parse_error(r);
861 r = print_property(name, reply, contents);
865 r = sd_bus_message_exit_container(reply);
867 return bus_log_parse_error(r);
869 r = sd_bus_message_exit_container(reply);
871 return bus_log_parse_error(r);
874 return bus_log_parse_error(r);
876 r = sd_bus_message_exit_container(reply);
878 return bus_log_parse_error(r);
883 static int show_session(int argc, char *argv[], void *userdata) {
884 bool properties, new_line = false;
885 sd_bus *bus = userdata;
891 properties = !strstr(argv[0], "status");
893 pager_open_if_enabled();
896 /* If not argument is specified inspect the manager
899 return show_properties(bus, "/org/freedesktop/login1", &new_line);
901 /* And in the pretty case, show data of the calling session */
902 return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
905 for (i = 1; i < argc; i++) {
906 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
907 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
908 const char *path = NULL;
910 r = sd_bus_call_method(
912 "org.freedesktop.login1",
913 "/org/freedesktop/login1",
914 "org.freedesktop.login1.Manager",
919 log_error("Failed to get session: %s", bus_error_message(&error, r));
923 r = sd_bus_message_read(reply, "o", &path);
925 return bus_log_parse_error(r);
928 r = show_properties(bus, path, &new_line);
930 r = print_session_status_info(bus, path, &new_line);
939 static int show_user(int argc, char *argv[], void *userdata) {
940 bool properties, new_line = false;
941 sd_bus *bus = userdata;
947 properties = !strstr(argv[0], "status");
949 pager_open_if_enabled();
952 /* If not argument is specified inspect the manager
955 return show_properties(bus, "/org/freedesktop/login1", &new_line);
957 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
960 for (i = 1; i < argc; i++) {
961 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
962 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
963 const char *path = NULL;
966 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
968 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
970 r = sd_bus_call_method(
972 "org.freedesktop.login1",
973 "/org/freedesktop/login1",
974 "org.freedesktop.login1.Manager",
977 "u", (uint32_t) uid);
979 log_error("Failed to get user: %s", bus_error_message(&error, r));
983 r = sd_bus_message_read(reply, "o", &path);
985 return bus_log_parse_error(r);
988 r = show_properties(bus, path, &new_line);
990 r = print_user_status_info(bus, path, &new_line);
999 static int show_seat(int argc, char *argv[], void *userdata) {
1000 bool properties, new_line = false;
1001 sd_bus *bus = userdata;
1007 properties = !strstr(argv[0], "status");
1009 pager_open_if_enabled();
1012 /* If not argument is specified inspect the manager
1015 return show_properties(bus, "/org/freedesktop/login1", &new_line);
1017 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
1020 for (i = 1; i < argc; i++) {
1021 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1022 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
1023 const char *path = NULL;
1025 r = sd_bus_call_method(
1027 "org.freedesktop.login1",
1028 "/org/freedesktop/login1",
1029 "org.freedesktop.login1.Manager",
1034 log_error("Failed to get seat: %s", bus_error_message(&error, r));
1038 r = sd_bus_message_read(reply, "o", &path);
1040 return bus_log_parse_error(r);
1043 r = show_properties(bus, path, &new_line);
1045 r = print_seat_status_info(bus, path, &new_line);
1054 static int activate(int argc, char *argv[], void *userdata) {
1055 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1056 sd_bus *bus = userdata;
1057 char *short_argv[3];
1063 polkit_agent_open_if_enabled();
1066 /* No argument? Let's convert this into the empty
1067 * session name, which the calls will then resolve to
1068 * the caller's session. */
1070 short_argv[0] = argv[0];
1071 short_argv[1] = (char*) "";
1072 short_argv[2] = NULL;
1078 for (i = 1; i < argc; i++) {
1080 r = sd_bus_call_method(
1082 "org.freedesktop.login1",
1083 "/org/freedesktop/login1",
1084 "org.freedesktop.login1.Manager",
1085 streq(argv[0], "lock-session") ? "LockSession" :
1086 streq(argv[0], "unlock-session") ? "UnlockSession" :
1087 streq(argv[0], "terminate-session") ? "TerminateSession" :
1092 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
1100 static int kill_session(int argc, char *argv[], void *userdata) {
1101 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1102 sd_bus *bus = userdata;
1108 polkit_agent_open_if_enabled();
1111 arg_kill_who = "all";
1113 for (i = 1; i < argc; i++) {
1115 r = sd_bus_call_method(
1117 "org.freedesktop.login1",
1118 "/org/freedesktop/login1",
1119 "org.freedesktop.login1.Manager",
1122 "ssi", argv[i], arg_kill_who, arg_signal);
1124 log_error("Could not kill session: %s", bus_error_message(&error, -r));
1132 static int enable_linger(int argc, char *argv[], void *userdata) {
1133 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1134 sd_bus *bus = userdata;
1135 char* short_argv[3];
1142 polkit_agent_open_if_enabled();
1144 b = streq(argv[0], "enable-linger");
1147 short_argv[0] = argv[0];
1148 short_argv[1] = (char*) "";
1149 short_argv[2] = NULL;
1154 for (i = 1; i < argc; i++) {
1157 if (isempty(argv[i]))
1160 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1162 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1165 r = sd_bus_call_method(
1167 "org.freedesktop.login1",
1168 "/org/freedesktop/login1",
1169 "org.freedesktop.login1.Manager",
1172 "ubb", (uint32_t) uid, b, true);
1174 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1182 static int terminate_user(int argc, char *argv[], void *userdata) {
1183 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1184 sd_bus *bus = userdata;
1190 polkit_agent_open_if_enabled();
1192 for (i = 1; i < argc; i++) {
1195 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1197 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1199 r = sd_bus_call_method(
1201 "org.freedesktop.login1",
1202 "/org/freedesktop/login1",
1203 "org.freedesktop.login1.Manager",
1206 "u", (uint32_t) uid);
1208 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1216 static int kill_user(int argc, char *argv[], void *userdata) {
1217 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1218 sd_bus *bus = userdata;
1224 polkit_agent_open_if_enabled();
1227 arg_kill_who = "all";
1229 for (i = 1; i < argc; i++) {
1232 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1234 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1236 r = sd_bus_call_method(
1238 "org.freedesktop.login1",
1239 "/org/freedesktop/login1",
1240 "org.freedesktop.login1.Manager",
1243 "ui", (uint32_t) uid, arg_signal);
1245 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1253 static int attach(int argc, char *argv[], void *userdata) {
1254 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1255 sd_bus *bus = userdata;
1261 polkit_agent_open_if_enabled();
1263 for (i = 2; i < argc; i++) {
1265 r = sd_bus_call_method(
1267 "org.freedesktop.login1",
1268 "/org/freedesktop/login1",
1269 "org.freedesktop.login1.Manager",
1272 "ssb", argv[1], argv[i], true);
1275 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1283 static int flush_devices(int argc, char *argv[], void *userdata) {
1284 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1285 sd_bus *bus = userdata;
1291 polkit_agent_open_if_enabled();
1293 r = sd_bus_call_method(
1295 "org.freedesktop.login1",
1296 "/org/freedesktop/login1",
1297 "org.freedesktop.login1.Manager",
1302 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1307 static int lock_sessions(int argc, char *argv[], void *userdata) {
1308 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1309 sd_bus *bus = userdata;
1315 polkit_agent_open_if_enabled();
1317 r = sd_bus_call_method(
1319 "org.freedesktop.login1",
1320 "/org/freedesktop/login1",
1321 "org.freedesktop.login1.Manager",
1322 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1326 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1331 static int terminate_seat(int argc, char *argv[], void *userdata) {
1332 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1333 sd_bus *bus = userdata;
1339 polkit_agent_open_if_enabled();
1341 for (i = 1; i < argc; i++) {
1343 r = sd_bus_call_method(
1345 "org.freedesktop.login1",
1346 "/org/freedesktop/login1",
1347 "org.freedesktop.login1.Manager",
1352 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1360 /* Ask elogind, which might grant access to unprivileged users
1361 * through PolicyKit */
1362 static int reboot_with_logind(sd_bus *bus, enum action a) {
1363 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1366 static const char *table[_ACTION_MAX] = {
1367 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
1368 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
1369 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
1375 polkit_agent_open_if_enabled();
1379 case ACTION_POWEROFF:
1380 method = "PowerOff";
1387 case ACTION_SUSPEND:
1391 case ACTION_HIBERNATE:
1392 method = "Hibernate";
1395 case ACTION_HYBRID_SLEEP:
1396 method = "HybridSleep";
1399 case ACTION_CANCEL_SHUTDOWN:
1400 method = "CancelScheduledShutdown";
1408 r = sd_bus_call_method(
1410 "org.freedesktop.login1",
1411 "/org/freedesktop/login1",
1412 "org.freedesktop.login1.Manager",
1421 log_warning_errno(r, "Failed to set wall message, ignoring: %s",
1422 bus_error_message(&error, r));
1423 sd_bus_error_free(&error);
1428 r = sd_bus_call_method(
1430 "org.freedesktop.login1",
1431 "/org/freedesktop/login1",
1432 "org.freedesktop.login1.Manager",
1436 "b", arg_ask_password);
1438 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
1443 static const struct {
1444 HandleAction action;
1446 } action_table[_ACTION_MAX] = {
1447 [ACTION_POWEROFF] = { HANDLE_POWEROFF, "poweroff", },
1448 [ACTION_REBOOT] = { HANDLE_REBOOT, "reboot", },
1449 [ACTION_SUSPEND] = { HANDLE_SUSPEND, "suspend", },
1450 [ACTION_HIBERNATE] = { HANDLE_HIBERNATE, "hibernate", },
1451 [ACTION_HYBRID_SLEEP] = { HANDLE_HYBRID_SLEEP, "hybrid-sleep" },
1454 static enum action verb_to_action(const char *verb) {
1457 for (i = _ACTION_INVALID; i < _ACTION_MAX; i++)
1458 if (streq_ptr(action_table[i].verb, verb))
1461 return _ACTION_INVALID;
1464 static int check_inhibitors(sd_bus *bus, enum action a) {
1465 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1466 _cleanup_strv_free_ char **sessions = NULL;
1467 const char *what, *who, *why, *mode;
1476 if (arg_ignore_inhibitors)
1485 r = sd_bus_call_method(
1487 "org.freedesktop.login1",
1488 "/org/freedesktop/login1",
1489 "org.freedesktop.login1.Manager",
1495 /* If logind is not around, then there are no inhibitors... */
1498 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
1500 return bus_log_parse_error(r);
1502 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
1503 _cleanup_free_ char *comm = NULL, *user = NULL;
1504 _cleanup_strv_free_ char **sv = NULL;
1506 if (!streq(mode, "block"))
1509 sv = strv_split(what, ":");
1513 if ((pid_t) pid < 0)
1514 return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
1516 if (!strv_contains(sv,
1517 a == ACTION_POWEROFF ||
1518 a == ACTION_REBOOT ? "shutdown" : "sleep"))
1521 get_process_comm(pid, &comm);
1522 user = uid_to_name(uid);
1524 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
1525 who, (pid_t) pid, strna(comm), strna(user), why);
1530 return bus_log_parse_error(r);
1532 r = sd_bus_message_exit_container(reply);
1534 return bus_log_parse_error(r);
1536 /* Check for current sessions */
1537 sd_get_sessions(&sessions);
1538 STRV_FOREACH(s, sessions) {
1539 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1541 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1544 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1547 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1550 sd_session_get_tty(*s, &tty);
1551 sd_session_get_seat(*s, &seat);
1552 sd_session_get_service(*s, &service);
1553 user = uid_to_name(uid);
1555 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1562 log_error("Please retry operation after closing inhibitors and logging out other users.\n"
1563 "Alternatively, ignore inhibitors and users with 'loginctl %s -i'.",
1564 action_table[a].verb);
1569 static int start_special(int argc, char *argv[], void *userdata) {
1570 sd_bus *bus = userdata;
1576 a = verb_to_action(argv[0]);
1578 r = check_inhibitors(bus, a);
1582 /* Now power off actions in chroot environments */
1583 if ((a == ACTION_POWEROFF ||
1584 a == ACTION_REBOOT) &&
1585 (running_in_chroot() > 0) ) {
1586 log_info("Running in chroot, ignoring request.");
1590 /* Switch to cancel shutdown, if a shutdown action was requested,
1591 and the option to cancel it was set: */
1592 if ((a == ACTION_POWEROFF ||
1593 a == ACTION_REBOOT) &&
1594 (arg_action == ACTION_CANCEL_SHUTDOWN))
1595 return reboot_with_logind(bus, arg_action);
1597 /* Otherwise perform requested action */
1598 if (a == ACTION_POWEROFF ||
1599 a == ACTION_REBOOT ||
1600 a == ACTION_SUSPEND ||
1601 a == ACTION_HIBERNATE ||
1602 a == ACTION_HYBRID_SLEEP)
1603 return reboot_with_logind(bus, a);
1608 static int help(int argc, char *argv[], void *userdata) {
1610 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1611 "Send control commands to or query the login manager.\n\n"
1612 " -h --help Show this help\n"
1613 " --version Show package version\n"
1614 " --no-pager Do not pipe output into a pager\n"
1615 " --no-legend Do not show the headers and footers\n"
1616 " --no-ask-password Don't prompt for password\n"
1617 " -H --host=[USER@]HOST Operate on remote host\n"
1618 " -M --machine=CONTAINER Operate on local container\n"
1619 " -p --property=NAME Show only properties by this name\n"
1620 " -a --all Show all properties, including empty ones\n"
1621 " -l --full Do not ellipsize output\n"
1622 " --kill-who=WHO Who to send signal to\n"
1623 " -s --signal=SIGNAL Which signal to send\n"
1625 " -n --lines=INTEGER Number of journal entries to show\n"
1626 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1627 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1629 " -c Cancel a pending shutdown\n"
1630 " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n"
1631 "Session Commands:\n"
1632 " list-sessions List sessions\n"
1633 " session-status [ID...] Show session status\n"
1634 " show-session [ID...] Show properties of sessions or the manager\n"
1635 " activate [ID] Activate a session\n"
1636 " lock-session [ID...] Screen lock one or more sessions\n"
1637 " unlock-session [ID...] Screen unlock one or more sessions\n"
1638 " lock-sessions Screen lock all current sessions\n"
1639 " unlock-sessions Screen unlock all current sessions\n"
1640 " terminate-session ID... Terminate one or more sessions\n"
1641 " kill-session ID... Send signal to processes of a session\n\n"
1643 " list-users List users\n"
1644 " user-status [USER...] Show user status\n"
1645 " show-user [USER...] Show properties of users or the manager\n"
1646 " enable-linger [USER...] Enable linger state of one or more users\n"
1647 " disable-linger [USER...] Disable linger state of one or more users\n"
1648 " terminate-user USER... Terminate all sessions of one or more users\n"
1649 " kill-user USER... Send signal to processes of a user\n\n"
1651 " list-seats List seats\n"
1652 " seat-status [NAME...] Show seat status\n"
1653 " show-seat [NAME...] Show properties of seats or the manager\n"
1654 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1655 " flush-devices Flush all device associations\n"
1656 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1657 "System Commands:\n"
1658 " poweroff Turn off the machine\n"
1659 " reboot Reboot the machine\n"
1660 " suspend Suspend the machine to memory\n"
1661 " hibernate Suspend the machine to disk\n"
1662 " hybrid-sleep Suspend the machine to memory and disk\n"
1663 , program_invocation_short_name);
1668 static int parse_argv(int argc, char *argv[]) {
1671 ARG_VERSION = 0x100,
1675 ARG_NO_ASK_PASSWORD,
1678 static const struct option options[] = {
1679 { "help", no_argument, NULL, 'h' },
1680 { "version", no_argument, NULL, ARG_VERSION },
1681 { "property", required_argument, NULL, 'p' },
1682 { "all", no_argument, NULL, 'a' },
1683 { "full", no_argument, NULL, 'l' },
1684 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1685 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1686 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1687 { "signal", required_argument, NULL, 's' },
1688 { "host", required_argument, NULL, 'H' },
1689 { "machine", required_argument, NULL, 'M' },
1690 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1692 { "lines", required_argument, NULL, 'n' },
1693 { "output", required_argument, NULL, 'o' },
1695 { "ignore-inhibitors", no_argument, NULL, 'i' },
1704 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:ci", options, NULL)) >= 0)
1709 help(0, NULL, NULL);
1716 r = strv_extend(&arg_property, optarg);
1720 /* If the user asked for a particular
1721 * property, show it to him, even if it is
1736 if (safe_atou(optarg, &arg_lines) < 0) {
1737 log_error("Failed to parse lines '%s'", optarg);
1743 arg_output = output_mode_from_string(optarg);
1744 if (arg_output < 0) {
1745 log_error("Unknown output '%s'.", optarg);
1751 arg_no_pager = true;
1758 case ARG_NO_ASK_PASSWORD:
1759 arg_ask_password = false;
1763 arg_kill_who = optarg;
1767 arg_signal = signal_from_string_try_harder(optarg);
1768 if (arg_signal < 0) {
1769 log_error("Failed to parse signal string %s.", optarg);
1775 arg_transport = BUS_TRANSPORT_REMOTE;
1780 arg_transport = BUS_TRANSPORT_MACHINE;
1785 arg_action = ACTION_CANCEL_SHUTDOWN;
1789 arg_ignore_inhibitors = true;
1796 assert_not_reached("Unhandled option");
1802 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1804 static const Verb verbs[] = {
1805 { "help", VERB_ANY, VERB_ANY, 0, help },
1806 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1807 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1808 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1809 { "activate", VERB_ANY, 2, 0, activate },
1810 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1811 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1812 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1813 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1814 { "terminate-session", 2, VERB_ANY, 0, activate },
1815 { "kill-session", 2, VERB_ANY, 0, kill_session },
1816 { "list-users", VERB_ANY, 1, 0, list_users },
1817 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1818 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1819 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1820 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1821 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1822 { "kill-user", 2, VERB_ANY, 0, kill_user },
1823 { "list-seats", VERB_ANY, 1, 0, list_seats },
1824 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1825 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1826 { "attach", 3, VERB_ANY, 0, attach },
1827 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1828 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1829 { "poweroff", VERB_ANY, 1, 0, start_special },
1830 { "reboot", VERB_ANY, 1, 0, start_special },
1831 { "suspend", VERB_ANY, 1, 0, start_special },
1832 { "hibernate", VERB_ANY, 1, 0, start_special },
1833 { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
1834 { "cancel-shutdown", VERB_ANY, 1, 0, start_special },
1838 return dispatch_verb(argc, argv, verbs, bus);
1841 int main(int argc, char *argv[]) {
1842 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
1845 setlocale(LC_ALL, "");
1846 elogind_set_program_name(argv[0]);
1847 log_parse_environment();
1850 r = parse_argv(argc, argv);
1854 r = bus_connect_transport(arg_transport, arg_host, false, &bus);
1856 log_error_errno(r, "Failed to create bus connection: %m");
1860 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1862 r = loginctl_main(argc, argv, bus);
1866 polkit_agent_close();
1868 strv_free(arg_property);
1870 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;