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"
49 static char **arg_property = NULL;
50 static bool arg_all = false;
51 static bool arg_full = false;
52 static bool arg_no_pager = false;
53 static bool arg_legend = true;
54 static const char *arg_kill_who = NULL;
55 static int arg_signal = SIGTERM;
56 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
57 static char *arg_host = NULL;
58 static bool arg_ask_password = true;
60 static unsigned arg_lines = 10;
61 static OutputMode arg_output = OUTPUT_SHORT;
64 static void pager_open_if_enabled(void) {
72 static void polkit_agent_open_if_enabled(void) {
74 /* Open the polkit agent as a child process if necessary */
76 if (!arg_ask_password)
79 if (arg_transport != BUS_TRANSPORT_LOCAL)
85 static OutputFlags get_output_flags(void) {
88 arg_all * OUTPUT_SHOW_ALL |
89 arg_full * OUTPUT_FULL_WIDTH |
90 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
91 on_tty() * OUTPUT_COLOR;
94 static int list_sessions(int argc, char *argv[], void *userdata) {
95 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
96 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
97 const char *id, *user, *seat, *object;
98 sd_bus *bus = userdata;
106 pager_open_if_enabled();
108 r = sd_bus_call_method(
110 "org.freedesktop.login1",
111 "/org/freedesktop/login1",
112 "org.freedesktop.login1.Manager",
117 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
121 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
123 return bus_log_parse_error(r);
126 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
128 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
129 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
133 return bus_log_parse_error(r);
136 printf("\n%u sessions listed.\n", k);
141 static int list_users(int argc, char *argv[], void *userdata) {
142 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
143 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
144 const char *user, *object;
145 sd_bus *bus = userdata;
153 pager_open_if_enabled();
155 r = sd_bus_call_method(
157 "org.freedesktop.login1",
158 "/org/freedesktop/login1",
159 "org.freedesktop.login1.Manager",
164 log_error("Failed to list users: %s", bus_error_message(&error, r));
168 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
170 return bus_log_parse_error(r);
173 printf("%10s %-16s\n", "UID", "USER");
175 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
176 printf("%10u %-16s\n", (unsigned) uid, user);
180 return bus_log_parse_error(r);
183 printf("\n%u users listed.\n", k);
188 static int list_seats(int argc, char *argv[], void *userdata) {
189 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
190 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
191 const char *seat, *object;
192 sd_bus *bus = userdata;
199 pager_open_if_enabled();
201 r = sd_bus_call_method(
203 "org.freedesktop.login1",
204 "/org/freedesktop/login1",
205 "org.freedesktop.login1.Manager",
210 log_error("Failed to list seats: %s", bus_error_message(&error, r));
214 r = sd_bus_message_enter_container(reply, 'a', "(so)");
216 return bus_log_parse_error(r);
219 printf("%-16s\n", "SEAT");
221 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
222 printf("%-16s\n", seat);
226 return bus_log_parse_error(r);
229 printf("\n%u seats listed.\n", k);
234 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
235 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
236 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
237 _cleanup_free_ char *path = NULL;
245 if (arg_transport != BUS_TRANSPORT_LOCAL)
248 path = unit_dbus_path_from_name(unit);
252 r = sd_bus_get_property(
254 "org.freedesktop.systemd1",
258 &error, &reply, "s");
262 r = sd_bus_message_read(reply, "s", &cgroup);
269 if (cg_is_empty_recursive(ELOGIND_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
278 show_cgroup_and_extra(ELOGIND_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
282 typedef struct SessionStatusInfo {
286 struct dual_timestamp timestamp;
303 typedef struct UserStatusInfo {
306 struct dual_timestamp timestamp;
313 typedef struct SeatStatusInfo {
315 char *active_session;
319 static void session_status_info_clear(SessionStatusInfo *info) {
326 free(info->remote_host);
327 free(info->remote_user);
338 static void user_status_info_clear(UserStatusInfo *info) {
342 strv_free(info->sessions);
349 static void seat_status_info_clear(SeatStatusInfo *info) {
352 free(info->active_session);
353 strv_free(info->sessions);
358 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
359 const char *contents;
362 r = sd_bus_message_peek_type(m, NULL, &contents);
366 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
370 if (contents[0] == 's' || contents[0] == 'o') {
372 char **p = (char **) userdata;
374 r = sd_bus_message_read_basic(m, contents[0], &s);
378 r = free_and_strdup(p, s);
382 r = sd_bus_message_read_basic(m, contents[0], userdata);
387 r = sd_bus_message_skip(m, contents+1);
391 r = sd_bus_message_exit_container(m);
398 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
405 r = sd_bus_message_enter_container(m, 'a', "(so)");
409 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
410 r = strv_extend(userdata, name);
417 return sd_bus_message_exit_container(m);
420 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
422 static const struct bus_properties_map map[] = {
423 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
424 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
425 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
426 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
427 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
428 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
429 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
430 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
431 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
432 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
433 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
434 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
435 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
436 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
437 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
438 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
439 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
440 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
441 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
445 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
446 char since2[FORMAT_TIMESTAMP_MAX], *s2;
447 _cleanup_(session_status_info_clear) SessionStatusInfo i = {};
450 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
452 return log_error_errno(r, "Could not get properties: %m");
459 printf("%s - ", strna(i.id));
462 printf("%s (%u)\n", i.name, (unsigned) i.uid);
464 printf("%u\n", (unsigned) i.uid);
466 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
467 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
470 printf("\t Since: %s; %s\n", s2, s1);
472 printf("\t Since: %s\n", s2);
475 _cleanup_free_ char *t = NULL;
477 printf("\t Leader: %u", (unsigned) i.leader);
479 get_process_comm(i.leader, &t);
486 if (!isempty(i.seat)) {
487 printf("\t Seat: %s", i.seat);
490 printf("; vc%u", i.vtnr);
496 printf("\t TTY: %s\n", i.tty);
498 printf("\t Display: %s\n", i.display);
500 if (i.remote_host && i.remote_user)
501 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
502 else if (i.remote_host)
503 printf("\t Remote: %s\n", i.remote_host);
504 else if (i.remote_user)
505 printf("\t Remote: user %s\n", i.remote_user);
507 printf("\t Remote: Yes\n");
510 printf("\t Service: %s", i.service);
513 printf("; type %s", i.type);
516 printf("; class %s", i.class);
520 printf("\t Type: %s", i.type);
523 printf("; class %s", i.class);
527 printf("\t Class: %s\n", i.class);
529 if (!isempty(i.desktop))
530 printf("\t Desktop: %s\n", i.desktop);
533 printf("\t State: %s\n", i.state);
536 printf("\t Unit: %s\n", i.scope);
537 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
539 if (arg_transport == BUS_TRANSPORT_LOCAL) {
541 show_journal_by_unit(
546 i.timestamp.monotonic,
549 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
550 SD_JOURNAL_LOCAL_ONLY,
561 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
563 static const struct bus_properties_map map[] = {
564 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
565 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
566 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
567 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
568 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
569 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
570 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
571 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
575 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
576 char since2[FORMAT_TIMESTAMP_MAX], *s2;
577 _cleanup_(user_status_info_clear) UserStatusInfo i = {};
580 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
582 return log_error_errno(r, "Could not get properties: %m");
590 printf("%s (%u)\n", i.name, (unsigned) i.uid);
592 printf("%u\n", (unsigned) i.uid);
594 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
595 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
598 printf("\t Since: %s; %s\n", s2, s1);
600 printf("\t Since: %s\n", s2);
602 if (!isempty(i.state))
603 printf("\t State: %s\n", i.state);
605 if (!strv_isempty(i.sessions)) {
607 printf("\tSessions:");
609 STRV_FOREACH(l, i.sessions) {
610 if (streq_ptr(*l, i.display))
620 printf("\t Unit: %s\n", i.slice);
621 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
623 show_journal_by_unit(
628 i.timestamp.monotonic,
631 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
632 SD_JOURNAL_LOCAL_ONLY,
642 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
644 static const struct bus_properties_map map[] = {
645 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
646 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
647 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
651 _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
654 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
656 return log_error_errno(r, "Could not get properties: %m");
663 printf("%s\n", strna(i.id));
665 if (!strv_isempty(i.sessions)) {
667 printf("\tSessions:");
669 STRV_FOREACH(l, i.sessions) {
670 if (streq_ptr(*l, i.active_session))
679 if (arg_transport == BUS_TRANSPORT_LOCAL) {
688 printf("\t Devices:\n");
690 show_sysfs(i.id, "\t\t ", c);
696 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
704 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
706 log_error_errno(r, "Could not get properties: %m");
711 static int show_session(int argc, char *argv[], void *userdata) {
712 bool properties, new_line = false;
713 sd_bus *bus = userdata;
719 properties = !strstr(argv[0], "status");
721 pager_open_if_enabled();
724 /* If not argument is specified inspect the manager
727 return show_properties(bus, "/org/freedesktop/login1", &new_line);
729 /* And in the pretty case, show data of the calling session */
730 return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
733 for (i = 1; i < argc; i++) {
734 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
735 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
736 const char *path = NULL;
738 r = sd_bus_call_method(
740 "org.freedesktop.login1",
741 "/org/freedesktop/login1",
742 "org.freedesktop.login1.Manager",
747 log_error("Failed to get session: %s", bus_error_message(&error, r));
751 r = sd_bus_message_read(reply, "o", &path);
753 return bus_log_parse_error(r);
756 r = show_properties(bus, path, &new_line);
758 r = print_session_status_info(bus, path, &new_line);
767 static int show_user(int argc, char *argv[], void *userdata) {
768 bool properties, new_line = false;
769 sd_bus *bus = userdata;
775 properties = !strstr(argv[0], "status");
777 pager_open_if_enabled();
780 /* If not argument is specified inspect the manager
783 return show_properties(bus, "/org/freedesktop/login1", &new_line);
785 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
788 for (i = 1; i < argc; i++) {
789 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
790 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
791 const char *path = NULL;
794 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
796 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
798 r = sd_bus_call_method(
800 "org.freedesktop.login1",
801 "/org/freedesktop/login1",
802 "org.freedesktop.login1.Manager",
805 "u", (uint32_t) uid);
807 log_error("Failed to get user: %s", bus_error_message(&error, r));
811 r = sd_bus_message_read(reply, "o", &path);
813 return bus_log_parse_error(r);
816 r = show_properties(bus, path, &new_line);
818 r = print_user_status_info(bus, path, &new_line);
827 static int show_seat(int argc, char *argv[], void *userdata) {
828 bool properties, new_line = false;
829 sd_bus *bus = userdata;
835 properties = !strstr(argv[0], "status");
837 pager_open_if_enabled();
840 /* If not argument is specified inspect the manager
843 return show_properties(bus, "/org/freedesktop/login1", &new_line);
845 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
848 for (i = 1; i < argc; i++) {
849 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
850 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
851 const char *path = NULL;
853 r = sd_bus_call_method(
855 "org.freedesktop.login1",
856 "/org/freedesktop/login1",
857 "org.freedesktop.login1.Manager",
862 log_error("Failed to get seat: %s", bus_error_message(&error, r));
866 r = sd_bus_message_read(reply, "o", &path);
868 return bus_log_parse_error(r);
871 r = show_properties(bus, path, &new_line);
873 r = print_seat_status_info(bus, path, &new_line);
882 static int activate(int argc, char *argv[], void *userdata) {
883 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
884 sd_bus *bus = userdata;
891 polkit_agent_open_if_enabled();
894 /* No argument? Let's convert this into the empty
895 * session name, which the calls will then resolve to
896 * the caller's session. */
898 short_argv[0] = argv[0];
899 short_argv[1] = (char*) "";
900 short_argv[2] = NULL;
906 for (i = 1; i < argc; i++) {
908 r = sd_bus_call_method(
910 "org.freedesktop.login1",
911 "/org/freedesktop/login1",
912 "org.freedesktop.login1.Manager",
913 streq(argv[0], "lock-session") ? "LockSession" :
914 streq(argv[0], "unlock-session") ? "UnlockSession" :
915 streq(argv[0], "terminate-session") ? "TerminateSession" :
920 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
928 static int kill_session(int argc, char *argv[], void *userdata) {
929 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
930 sd_bus *bus = userdata;
936 polkit_agent_open_if_enabled();
939 arg_kill_who = "all";
941 for (i = 1; i < argc; i++) {
943 r = sd_bus_call_method(
945 "org.freedesktop.login1",
946 "/org/freedesktop/login1",
947 "org.freedesktop.login1.Manager",
950 "ssi", argv[i], arg_kill_who, arg_signal);
952 log_error("Could not kill session: %s", bus_error_message(&error, -r));
960 static int enable_linger(int argc, char *argv[], void *userdata) {
961 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
962 sd_bus *bus = userdata;
970 polkit_agent_open_if_enabled();
972 b = streq(argv[0], "enable-linger");
975 short_argv[0] = argv[0];
976 short_argv[1] = (char*) "";
977 short_argv[2] = NULL;
982 for (i = 1; i < argc; i++) {
985 if (isempty(argv[i]))
988 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
990 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
993 r = sd_bus_call_method(
995 "org.freedesktop.login1",
996 "/org/freedesktop/login1",
997 "org.freedesktop.login1.Manager",
1000 "ubb", (uint32_t) uid, b, true);
1002 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1010 static int terminate_user(int argc, char *argv[], void *userdata) {
1011 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1012 sd_bus *bus = userdata;
1018 polkit_agent_open_if_enabled();
1020 for (i = 1; i < argc; i++) {
1023 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1025 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1027 r = sd_bus_call_method(
1029 "org.freedesktop.login1",
1030 "/org/freedesktop/login1",
1031 "org.freedesktop.login1.Manager",
1034 "u", (uint32_t) uid);
1036 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1044 static int kill_user(int argc, char *argv[], void *userdata) {
1045 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1046 sd_bus *bus = userdata;
1052 polkit_agent_open_if_enabled();
1055 arg_kill_who = "all";
1057 for (i = 1; i < argc; i++) {
1060 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1062 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1064 r = sd_bus_call_method(
1066 "org.freedesktop.login1",
1067 "/org/freedesktop/login1",
1068 "org.freedesktop.login1.Manager",
1071 "ui", (uint32_t) uid, arg_signal);
1073 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1081 static int attach(int argc, char *argv[], void *userdata) {
1082 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1083 sd_bus *bus = userdata;
1089 polkit_agent_open_if_enabled();
1091 for (i = 2; i < argc; i++) {
1093 r = sd_bus_call_method(
1095 "org.freedesktop.login1",
1096 "/org/freedesktop/login1",
1097 "org.freedesktop.login1.Manager",
1100 "ssb", argv[1], argv[i], true);
1103 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1111 static int flush_devices(int argc, char *argv[], void *userdata) {
1112 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1113 sd_bus *bus = userdata;
1119 polkit_agent_open_if_enabled();
1121 r = sd_bus_call_method(
1123 "org.freedesktop.login1",
1124 "/org/freedesktop/login1",
1125 "org.freedesktop.login1.Manager",
1130 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1135 static int lock_sessions(int argc, char *argv[], void *userdata) {
1136 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1137 sd_bus *bus = userdata;
1143 polkit_agent_open_if_enabled();
1145 r = sd_bus_call_method(
1147 "org.freedesktop.login1",
1148 "/org/freedesktop/login1",
1149 "org.freedesktop.login1.Manager",
1150 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1154 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1159 static int terminate_seat(int argc, char *argv[], void *userdata) {
1160 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1161 sd_bus *bus = userdata;
1167 polkit_agent_open_if_enabled();
1169 for (i = 1; i < argc; i++) {
1171 r = sd_bus_call_method(
1173 "org.freedesktop.login1",
1174 "/org/freedesktop/login1",
1175 "org.freedesktop.login1.Manager",
1180 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1188 static int check_inhibitors(sd_bus *bus, const char *verb, const char *inhibit_what) {
1189 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1190 _cleanup_strv_free_ char **sessions = NULL;
1191 const char *what, *who, *why, *mode;
1205 r = sd_bus_call_method(
1207 "org.freedesktop.login1",
1208 "/org/freedesktop/login1",
1209 "org.freedesktop.login1.Manager",
1215 /* If logind is not around, then there are no inhibitors... */
1218 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
1220 return bus_log_parse_error(r);
1222 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
1223 _cleanup_free_ char *comm = NULL, *user = NULL;
1224 _cleanup_strv_free_ char **sv = NULL;
1226 if (!streq(mode, "block"))
1229 sv = strv_split(what, ":");
1233 if (!strv_contains(sv, inhibit_what))
1236 get_process_comm(pid, &comm);
1237 user = uid_to_name(uid);
1239 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
1240 who, pid, strna(comm), strna(user), why);
1245 return bus_log_parse_error(r);
1247 r = sd_bus_message_exit_container(reply);
1249 return bus_log_parse_error(r);
1251 /* Check for current sessions */
1252 sd_get_sessions(&sessions);
1253 STRV_FOREACH(s, sessions) {
1254 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1256 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1259 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1262 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1265 sd_session_get_tty(*s, &tty);
1266 sd_session_get_seat(*s, &seat);
1267 sd_session_get_service(*s, &service);
1268 user = uid_to_name(uid);
1270 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1277 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'loginctl %s -i'.", verb);
1282 static int poweroff(int argc, char *argv[], void *userdata) {
1283 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1284 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1285 sd_bus *bus = userdata;
1290 r = check_inhibitors(bus, "poweroff", "shutdown");
1294 polkit_agent_open_if_enabled();
1296 r = sd_bus_call_method(
1298 "org.freedesktop.login1",
1299 "/org/freedesktop/login1",
1300 "org.freedesktop.login1.Manager",
1304 "b", arg_ask_password);
1306 log_error("Failed to power off: %s", bus_error_message(&error, r));
1311 static int reboot(int argc, char *argv[], void *userdata) {
1312 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1313 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1314 sd_bus *bus = userdata;
1319 r = check_inhibitors(bus, "reboot", "shutdown");
1323 polkit_agent_open_if_enabled();
1325 r = sd_bus_call_method(
1327 "org.freedesktop.login1",
1328 "/org/freedesktop/login1",
1329 "org.freedesktop.login1.Manager",
1333 "b", arg_ask_password);
1335 log_error("Failed to reboot: %s", bus_error_message(&error, r));
1340 static int suspend(int argc, char *argv[], void *userdata) {
1341 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1342 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1343 sd_bus *bus = userdata;
1348 r = check_inhibitors(bus, "suspend", "sleep");
1352 polkit_agent_open_if_enabled();
1354 r = sd_bus_call_method(
1356 "org.freedesktop.login1",
1357 "/org/freedesktop/login1",
1358 "org.freedesktop.login1.Manager",
1362 "b", arg_ask_password);
1364 log_error("Failed to suspend: %s", bus_error_message(&error, r));
1369 static int hibernate(int argc, char *argv[], void *userdata) {
1370 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1371 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1372 sd_bus *bus = userdata;
1377 r = check_inhibitors(bus, "hibernate", "sleep");
1381 polkit_agent_open_if_enabled();
1383 r = sd_bus_call_method(
1385 "org.freedesktop.login1",
1386 "/org/freedesktop/login1",
1387 "org.freedesktop.login1.Manager",
1391 "b", arg_ask_password);
1393 log_error("Failed to hibernate: %s", bus_error_message(&error, r));
1398 static int hybrid_sleep(int argc, char *argv[], void *userdata) {
1399 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1400 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1401 sd_bus *bus = userdata;
1406 r = check_inhibitors(bus, "hybrid-sleep", "sleep");
1410 polkit_agent_open_if_enabled();
1412 r = sd_bus_call_method(
1414 "org.freedesktop.login1",
1415 "/org/freedesktop/login1",
1416 "org.freedesktop.login1.Manager",
1420 "b", arg_ask_password);
1422 log_error("Failed to hybrid sleep: %s", bus_error_message(&error, r));
1427 static int help(int argc, char *argv[], void *userdata) {
1429 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1430 "Send control commands to or query the login manager.\n\n"
1431 " -h --help Show this help\n"
1432 " --version Show package version\n"
1433 " --no-pager Do not pipe output into a pager\n"
1434 " --no-legend Do not show the headers and footers\n"
1435 " --no-ask-password Don't prompt for password\n"
1436 " -H --host=[USER@]HOST Operate on remote host\n"
1437 " -M --machine=CONTAINER Operate on local container\n"
1438 " -p --property=NAME Show only properties by this name\n"
1439 " -a --all Show all properties, including empty ones\n"
1440 " -l --full Do not ellipsize output\n"
1441 " --kill-who=WHO Who to send signal to\n"
1442 " -s --signal=SIGNAL Which signal to send\n"
1444 " -n --lines=INTEGER Number of journal entries to show\n"
1445 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1446 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1448 "Session Commands:\n"
1449 " list-sessions List sessions\n"
1450 " session-status [ID...] Show session status\n"
1451 " show-session [ID...] Show properties of sessions or the manager\n"
1452 " activate [ID] Activate a session\n"
1453 " lock-session [ID...] Screen lock one or more sessions\n"
1454 " unlock-session [ID...] Screen unlock one or more sessions\n"
1455 " lock-sessions Screen lock all current sessions\n"
1456 " unlock-sessions Screen unlock all current sessions\n"
1457 " terminate-session ID... Terminate one or more sessions\n"
1458 " kill-session ID... Send signal to processes of a session\n\n"
1460 " list-users List users\n"
1461 " user-status [USER...] Show user status\n"
1462 " show-user [USER...] Show properties of users or the manager\n"
1463 " enable-linger [USER...] Enable linger state of one or more users\n"
1464 " disable-linger [USER...] Disable linger state of one or more users\n"
1465 " terminate-user USER... Terminate all sessions of one or more users\n"
1466 " kill-user USER... Send signal to processes of a user\n\n"
1468 " list-seats List seats\n"
1469 " seat-status [NAME...] Show seat status\n"
1470 " show-seat [NAME...] Show properties of seats or the manager\n"
1471 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1472 " flush-devices Flush all device associations\n"
1473 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1474 "System Commands:\n"
1475 " poweroff Turn off the machine\n"
1476 " reboot Reboot the machine\n"
1477 " suspend Suspend the machine to memory\n"
1478 " hibernate Suspend the machine to disk\n"
1479 " hybrid-sleep Suspend the machine to memory and disk\n"
1480 , program_invocation_short_name);
1485 static int parse_argv(int argc, char *argv[]) {
1488 ARG_VERSION = 0x100,
1492 ARG_NO_ASK_PASSWORD,
1495 static const struct option options[] = {
1496 { "help", no_argument, NULL, 'h' },
1497 { "version", no_argument, NULL, ARG_VERSION },
1498 { "property", required_argument, NULL, 'p' },
1499 { "all", no_argument, NULL, 'a' },
1500 { "full", no_argument, NULL, 'l' },
1501 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1502 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1503 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1504 { "signal", required_argument, NULL, 's' },
1505 { "host", required_argument, NULL, 'H' },
1506 { "machine", required_argument, NULL, 'M' },
1507 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1509 { "lines", required_argument, NULL, 'n' },
1510 { "output", required_argument, NULL, 'o' },
1520 while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
1525 help(0, NULL, NULL);
1529 puts(PACKAGE_STRING);
1530 puts(SYSTEMD_FEATURES);
1534 r = strv_extend(&arg_property, optarg);
1538 /* If the user asked for a particular
1539 * property, show it to him, even if it is
1554 if (safe_atou(optarg, &arg_lines) < 0) {
1555 log_error("Failed to parse lines '%s'", optarg);
1561 arg_output = output_mode_from_string(optarg);
1562 if (arg_output < 0) {
1563 log_error("Unknown output '%s'.", optarg);
1569 arg_no_pager = true;
1576 case ARG_NO_ASK_PASSWORD:
1577 arg_ask_password = false;
1581 arg_kill_who = optarg;
1585 arg_signal = signal_from_string_try_harder(optarg);
1586 if (arg_signal < 0) {
1587 log_error("Failed to parse signal string %s.", optarg);
1593 arg_transport = BUS_TRANSPORT_REMOTE;
1598 arg_transport = BUS_TRANSPORT_MACHINE;
1606 assert_not_reached("Unhandled option");
1612 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1614 static const Verb verbs[] = {
1615 { "help", VERB_ANY, VERB_ANY, 0, help },
1616 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1617 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1618 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1619 { "activate", VERB_ANY, 2, 0, activate },
1620 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1621 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1622 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1623 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1624 { "terminate-session", 2, VERB_ANY, 0, activate },
1625 { "kill-session", 2, VERB_ANY, 0, kill_session },
1626 { "list-users", VERB_ANY, 1, 0, list_users },
1627 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1628 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1629 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1630 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1631 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1632 { "kill-user", 2, VERB_ANY, 0, kill_user },
1633 { "list-seats", VERB_ANY, 1, 0, list_seats },
1634 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1635 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1636 { "attach", 3, VERB_ANY, 0, attach },
1637 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1638 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1639 { "poweroff", VERB_ANY, 1, 0, poweroff },
1640 { "reboot", VERB_ANY, 1, 0, reboot },
1641 { "suspend", VERB_ANY, 1, 0, suspend },
1642 { "hibernate", VERB_ANY, 1, 0, hibernate },
1643 { "hybrid-sleep", VERB_ANY, 1, 0, hybrid_sleep },
1647 return dispatch_verb(argc, argv, verbs, bus);
1650 int main(int argc, char *argv[]) {
1651 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
1654 setlocale(LC_ALL, "");
1655 log_parse_environment();
1658 r = parse_argv(argc, argv);
1662 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1664 log_error_errno(r, "Failed to create bus connection: %m");
1668 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1670 r = loginctl_main(argc, argv, bus);
1674 polkit_agent_close();
1676 strv_free(arg_property);
1678 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;