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"
46 static char **arg_property = NULL;
47 static bool arg_all = false;
48 static bool arg_full = false;
49 static bool arg_no_pager = false;
50 static bool arg_legend = true;
51 static const char *arg_kill_who = NULL;
52 static int arg_signal = SIGTERM;
53 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
54 static char *arg_host = NULL;
55 static bool arg_ask_password = true;
56 static unsigned arg_lines = 10;
57 static OutputMode arg_output = OUTPUT_SHORT;
59 static void pager_open_if_enabled(void) {
67 static void polkit_agent_open_if_enabled(void) {
69 /* Open the polkit agent as a child process if necessary */
71 if (!arg_ask_password)
74 if (arg_transport != BUS_TRANSPORT_LOCAL)
80 static OutputFlags get_output_flags(void) {
83 arg_all * OUTPUT_SHOW_ALL |
84 arg_full * OUTPUT_FULL_WIDTH |
85 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
86 on_tty() * OUTPUT_COLOR;
89 static int list_sessions(int argc, char *argv[], void *userdata) {
90 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
91 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
92 const char *id, *user, *seat, *object;
93 sd_bus *bus = userdata;
101 pager_open_if_enabled();
103 r = sd_bus_call_method(
105 "org.freedesktop.login1",
106 "/org/freedesktop/login1",
107 "org.freedesktop.login1.Manager",
112 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
116 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
118 return bus_log_parse_error(r);
121 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
123 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
124 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
128 return bus_log_parse_error(r);
131 printf("\n%u sessions listed.\n", k);
136 static int list_users(int argc, char *argv[], void *userdata) {
137 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
138 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
139 const char *user, *object;
140 sd_bus *bus = userdata;
148 pager_open_if_enabled();
150 r = sd_bus_call_method(
152 "org.freedesktop.login1",
153 "/org/freedesktop/login1",
154 "org.freedesktop.login1.Manager",
159 log_error("Failed to list users: %s", bus_error_message(&error, r));
163 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
165 return bus_log_parse_error(r);
168 printf("%10s %-16s\n", "UID", "USER");
170 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
171 printf("%10u %-16s\n", (unsigned) uid, user);
175 return bus_log_parse_error(r);
178 printf("\n%u users listed.\n", k);
183 static int list_seats(int argc, char *argv[], void *userdata) {
184 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
185 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
186 const char *seat, *object;
187 sd_bus *bus = userdata;
194 pager_open_if_enabled();
196 r = sd_bus_call_method(
198 "org.freedesktop.login1",
199 "/org/freedesktop/login1",
200 "org.freedesktop.login1.Manager",
205 log_error("Failed to list seats: %s", bus_error_message(&error, r));
209 r = sd_bus_message_enter_container(reply, 'a', "(so)");
211 return bus_log_parse_error(r);
214 printf("%-16s\n", "SEAT");
216 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
217 printf("%-16s\n", seat);
221 return bus_log_parse_error(r);
224 printf("\n%u seats listed.\n", k);
229 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
230 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
231 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
232 _cleanup_free_ char *path = NULL;
240 if (arg_transport != BUS_TRANSPORT_LOCAL)
243 path = unit_dbus_path_from_name(unit);
247 r = sd_bus_get_property(
249 "org.freedesktop.systemd1",
253 &error, &reply, "s");
257 r = sd_bus_message_read(reply, "s", &cgroup);
264 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
273 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
277 typedef struct SessionStatusInfo {
281 struct dual_timestamp timestamp;
287 const char *remote_host;
288 const char *remote_user;
298 typedef struct UserStatusInfo {
301 struct dual_timestamp timestamp;
308 typedef struct SeatStatusInfo {
310 const char *active_session;
314 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
315 const char *contents;
318 r = sd_bus_message_peek_type(m, NULL, &contents);
322 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
326 if (contents[0] == 's' || contents[0] == 'o') {
328 char **p = (char **) userdata;
330 r = sd_bus_message_read_basic(m, contents[0], &s);
340 r = sd_bus_message_read_basic(m, contents[0], userdata);
345 r = sd_bus_message_skip(m, contents+1);
349 r = sd_bus_message_exit_container(m);
356 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
363 r = sd_bus_message_enter_container(m, 'a', "(so)");
367 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
368 r = strv_extend(userdata, name);
375 return sd_bus_message_exit_container(m);
378 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
380 static const struct bus_properties_map map[] = {
381 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
382 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
383 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
384 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
385 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
386 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
387 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
388 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
389 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
390 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
391 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
392 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
393 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
394 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
395 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
396 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
397 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
398 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
399 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
403 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
404 char since2[FORMAT_TIMESTAMP_MAX], *s2;
405 SessionStatusInfo i = {};
408 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
410 return log_error_errno(r, "Could not get properties: %m");
417 printf("%s - ", strna(i.id));
420 printf("%s (%u)\n", i.name, (unsigned) i.uid);
422 printf("%u\n", (unsigned) i.uid);
424 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
425 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
428 printf("\t Since: %s; %s\n", s2, s1);
430 printf("\t Since: %s\n", s2);
433 _cleanup_free_ char *t = NULL;
435 printf("\t Leader: %u", (unsigned) i.leader);
437 get_process_comm(i.leader, &t);
444 if (!isempty(i.seat)) {
445 printf("\t Seat: %s", i.seat);
448 printf("; vc%u", i.vtnr);
454 printf("\t TTY: %s\n", i.tty);
456 printf("\t Display: %s\n", i.display);
458 if (i.remote_host && i.remote_user)
459 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
460 else if (i.remote_host)
461 printf("\t Remote: %s\n", i.remote_host);
462 else if (i.remote_user)
463 printf("\t Remote: user %s\n", i.remote_user);
465 printf("\t Remote: Yes\n");
468 printf("\t Service: %s", i.service);
471 printf("; type %s", i.type);
474 printf("; class %s", i.class);
478 printf("\t Type: %s", i.type);
481 printf("; class %s", i.class);
485 printf("\t Class: %s\n", i.class);
487 if (!isempty(i.desktop))
488 printf("\t Desktop: %s\n", i.desktop);
491 printf("\t State: %s\n", i.state);
494 printf("\t Unit: %s\n", i.scope);
495 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
497 if (arg_transport == BUS_TRANSPORT_LOCAL) {
499 show_journal_by_unit(
504 i.timestamp.monotonic,
507 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
508 SD_JOURNAL_LOCAL_ONLY,
517 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
519 static const struct bus_properties_map map[] = {
520 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
521 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
522 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
523 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
524 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
525 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
526 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
527 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
531 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
532 char since2[FORMAT_TIMESTAMP_MAX], *s2;
533 UserStatusInfo i = {};
536 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
538 log_error_errno(r, "Could not get properties: %m");
548 printf("%s (%u)\n", i.name, (unsigned) i.uid);
550 printf("%u\n", (unsigned) i.uid);
552 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
553 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
556 printf("\t Since: %s; %s\n", s2, s1);
558 printf("\t Since: %s\n", s2);
560 if (!isempty(i.state))
561 printf("\t State: %s\n", i.state);
563 if (!strv_isempty(i.sessions)) {
565 printf("\tSessions:");
567 STRV_FOREACH(l, i.sessions) {
568 if (streq_ptr(*l, i.display))
578 printf("\t Unit: %s\n", i.slice);
579 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
581 show_journal_by_unit(
586 i.timestamp.monotonic,
589 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
590 SD_JOURNAL_LOCAL_ONLY,
596 strv_free(i.sessions);
601 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
603 static const struct bus_properties_map map[] = {
604 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
605 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
606 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
610 SeatStatusInfo i = {};
613 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
615 log_error_errno(r, "Could not get properties: %m");
624 printf("%s\n", strna(i.id));
626 if (!strv_isempty(i.sessions)) {
628 printf("\tSessions:");
630 STRV_FOREACH(l, i.sessions) {
631 if (streq_ptr(*l, i.active_session))
640 if (arg_transport == BUS_TRANSPORT_LOCAL) {
649 printf("\t Devices:\n");
651 show_sysfs(i.id, "\t\t ", c);
655 strv_free(i.sessions);
660 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
668 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
670 log_error_errno(r, "Could not get properties: %m");
675 static int show_session(int argc, char *argv[], void *userdata) {
676 bool properties, new_line = false;
677 sd_bus *bus = userdata;
683 properties = !strstr(argv[0], "status");
685 pager_open_if_enabled();
688 /* If not argument is specified inspect the manager
691 return show_properties(bus, "/org/freedesktop/login1", &new_line);
693 /* And in the pretty case, show data of the calling session */
694 return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
697 for (i = 1; i < argc; i++) {
698 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
699 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
700 const char *path = NULL;
702 r = sd_bus_call_method(
704 "org.freedesktop.login1",
705 "/org/freedesktop/login1",
706 "org.freedesktop.login1.Manager",
711 log_error("Failed to get session: %s", bus_error_message(&error, r));
715 r = sd_bus_message_read(reply, "o", &path);
717 return bus_log_parse_error(r);
720 r = show_properties(bus, path, &new_line);
722 r = print_session_status_info(bus, path, &new_line);
731 static int show_user(int argc, char *argv[], void *userdata) {
732 bool properties, new_line = false;
733 sd_bus *bus = userdata;
739 properties = !strstr(argv[0], "status");
741 pager_open_if_enabled();
744 /* If not argument is specified inspect the manager
747 return show_properties(bus, "/org/freedesktop/login1", &new_line);
749 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
752 for (i = 1; i < argc; i++) {
753 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
754 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
755 const char *path = NULL;
758 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
760 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
762 r = sd_bus_call_method(
764 "org.freedesktop.login1",
765 "/org/freedesktop/login1",
766 "org.freedesktop.login1.Manager",
769 "u", (uint32_t) uid);
771 log_error("Failed to get user: %s", bus_error_message(&error, r));
775 r = sd_bus_message_read(reply, "o", &path);
777 return bus_log_parse_error(r);
780 r = show_properties(bus, path, &new_line);
782 r = print_user_status_info(bus, path, &new_line);
791 static int show_seat(int argc, char *argv[], void *userdata) {
792 bool properties, new_line = false;
793 sd_bus *bus = userdata;
799 properties = !strstr(argv[0], "status");
801 pager_open_if_enabled();
804 /* If not argument is specified inspect the manager
807 return show_properties(bus, "/org/freedesktop/login1", &new_line);
809 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
812 for (i = 1; i < argc; i++) {
813 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
814 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
815 const char *path = NULL;
817 r = sd_bus_call_method(
819 "org.freedesktop.login1",
820 "/org/freedesktop/login1",
821 "org.freedesktop.login1.Manager",
826 log_error("Failed to get seat: %s", bus_error_message(&error, r));
830 r = sd_bus_message_read(reply, "o", &path);
832 return bus_log_parse_error(r);
835 r = show_properties(bus, path, &new_line);
837 r = print_seat_status_info(bus, path, &new_line);
846 static int activate(int argc, char *argv[], void *userdata) {
847 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
848 sd_bus *bus = userdata;
855 polkit_agent_open_if_enabled();
858 /* No argument? Let's convert this into the empty
859 * session name, which the calls will then resolve to
860 * the caller's session. */
862 short_argv[0] = argv[0];
863 short_argv[1] = (char*) "";
864 short_argv[2] = NULL;
870 for (i = 1; i < argc; i++) {
872 r = sd_bus_call_method (
874 "org.freedesktop.login1",
875 "/org/freedesktop/login1",
876 "org.freedesktop.login1.Manager",
877 streq(argv[0], "lock-session") ? "LockSession" :
878 streq(argv[0], "unlock-session") ? "UnlockSession" :
879 streq(argv[0], "terminate-session") ? "TerminateSession" :
884 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
892 static int kill_session(int argc, char *argv[], void *userdata) {
893 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
894 sd_bus *bus = userdata;
900 polkit_agent_open_if_enabled();
903 arg_kill_who = "all";
905 for (i = 1; i < argc; i++) {
907 r = sd_bus_call_method (
909 "org.freedesktop.login1",
910 "/org/freedesktop/login1",
911 "org.freedesktop.login1.Manager",
914 "ssi", argv[i], arg_kill_who, arg_signal);
916 log_error("Could not kill session: %s", bus_error_message(&error, -r));
924 static int enable_linger(int argc, char *argv[], void *userdata) {
925 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
926 sd_bus *bus = userdata;
934 polkit_agent_open_if_enabled();
936 b = streq(argv[0], "enable-linger");
939 short_argv[0] = argv[0];
940 short_argv[1] = (char*) "";
941 short_argv[2] = NULL;
946 for (i = 1; i < argc; i++) {
949 if (isempty(argv[i]))
952 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
954 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
957 r = sd_bus_call_method (
959 "org.freedesktop.login1",
960 "/org/freedesktop/login1",
961 "org.freedesktop.login1.Manager",
964 "ubb", (uint32_t) uid, b, true);
966 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
974 static int terminate_user(int argc, char *argv[], void *userdata) {
975 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
976 sd_bus *bus = userdata;
982 polkit_agent_open_if_enabled();
984 for (i = 1; i < argc; i++) {
987 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
989 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
991 r = sd_bus_call_method (
993 "org.freedesktop.login1",
994 "/org/freedesktop/login1",
995 "org.freedesktop.login1.Manager",
998 "u", (uint32_t) uid);
1000 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1008 static int kill_user(int argc, char *argv[], void *userdata) {
1009 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1010 sd_bus *bus = userdata;
1016 polkit_agent_open_if_enabled();
1019 arg_kill_who = "all";
1021 for (i = 1; i < argc; i++) {
1024 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1026 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1028 r = sd_bus_call_method (
1030 "org.freedesktop.login1",
1031 "/org/freedesktop/login1",
1032 "org.freedesktop.login1.Manager",
1035 "ui", (uint32_t) uid, arg_signal);
1037 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1045 static int attach(int argc, char *argv[], void *userdata) {
1046 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1047 sd_bus *bus = userdata;
1053 polkit_agent_open_if_enabled();
1055 for (i = 2; i < argc; i++) {
1057 r = sd_bus_call_method (
1059 "org.freedesktop.login1",
1060 "/org/freedesktop/login1",
1061 "org.freedesktop.login1.Manager",
1064 "ssb", argv[1], argv[i], true);
1067 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1075 static int flush_devices(int argc, char *argv[], void *userdata) {
1076 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1077 sd_bus *bus = userdata;
1083 polkit_agent_open_if_enabled();
1085 r = sd_bus_call_method (
1087 "org.freedesktop.login1",
1088 "/org/freedesktop/login1",
1089 "org.freedesktop.login1.Manager",
1094 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1099 static int lock_sessions(int argc, char *argv[], void *userdata) {
1100 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1101 sd_bus *bus = userdata;
1107 polkit_agent_open_if_enabled();
1109 r = sd_bus_call_method(
1111 "org.freedesktop.login1",
1112 "/org/freedesktop/login1",
1113 "org.freedesktop.login1.Manager",
1114 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1118 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1123 static int terminate_seat(int argc, char *argv[], void *userdata) {
1124 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1125 sd_bus *bus = userdata;
1131 polkit_agent_open_if_enabled();
1133 for (i = 1; i < argc; i++) {
1135 r = sd_bus_call_method(
1137 "org.freedesktop.login1",
1138 "/org/freedesktop/login1",
1139 "org.freedesktop.login1.Manager",
1144 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1152 static int help(int argc, char *argv[], void *userdata) {
1154 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1155 "Send control commands to or query the login manager.\n\n"
1156 " -h --help Show this help\n"
1157 " --version Show package version\n"
1158 " --no-pager Do not pipe output into a pager\n"
1159 " --no-legend Do not show the headers and footers\n"
1160 " --no-ask-password Don't prompt for password\n"
1161 " -H --host=[USER@]HOST Operate on remote host\n"
1162 " -M --machine=CONTAINER Operate on local container\n"
1163 " -p --property=NAME Show only properties by this name\n"
1164 " -a --all Show all properties, including empty ones\n"
1165 " -l --full Do not ellipsize output\n"
1166 " --kill-who=WHO Who to send signal to\n"
1167 " -s --signal=SIGNAL Which signal to send\n"
1168 " -n --lines=INTEGER Number of journal entries to show\n"
1169 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1170 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1171 "Session Commands:\n"
1172 " list-sessions List sessions\n"
1173 " session-status [ID...] Show session status\n"
1174 " show-session [ID...] Show properties of sessions or the manager\n"
1175 " activate [ID] Activate a session\n"
1176 " lock-session [ID...] Screen lock one or more sessions\n"
1177 " unlock-session [ID...] Screen unlock one or more sessions\n"
1178 " lock-sessions Screen lock all current sessions\n"
1179 " unlock-sessions Screen unlock all current sessions\n"
1180 " terminate-session ID... Terminate one or more sessions\n"
1181 " kill-session ID... Send signal to processes of a session\n\n"
1183 " list-users List users\n"
1184 " user-status [USER...] Show user status\n"
1185 " show-user [USER...] Show properties of users or the manager\n"
1186 " enable-linger [USER...] Enable linger state of one or more users\n"
1187 " disable-linger [USER...] Disable linger state of one or more users\n"
1188 " terminate-user USER... Terminate all sessions of one or more users\n"
1189 " kill-user USER... Send signal to processes of a user\n\n"
1191 " list-seats List seats\n"
1192 " seat-status [NAME...] Show seat status\n"
1193 " show-seat [NAME...] Show properties of seats or the manager\n"
1194 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1195 " flush-devices Flush all device associations\n"
1196 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1197 , program_invocation_short_name);
1202 static int parse_argv(int argc, char *argv[]) {
1205 ARG_VERSION = 0x100,
1209 ARG_NO_ASK_PASSWORD,
1212 static const struct option options[] = {
1213 { "help", no_argument, NULL, 'h' },
1214 { "version", no_argument, NULL, ARG_VERSION },
1215 { "property", required_argument, NULL, 'p' },
1216 { "all", no_argument, NULL, 'a' },
1217 { "full", no_argument, NULL, 'l' },
1218 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1219 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1220 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1221 { "signal", required_argument, NULL, 's' },
1222 { "host", required_argument, NULL, 'H' },
1223 { "machine", required_argument, NULL, 'M' },
1224 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1225 { "lines", required_argument, NULL, 'n' },
1226 { "output", required_argument, NULL, 'o' },
1235 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1240 help(0, NULL, NULL);
1244 puts(PACKAGE_STRING);
1245 puts(SYSTEMD_FEATURES);
1249 r = strv_extend(&arg_property, optarg);
1253 /* If the user asked for a particular
1254 * property, show it to him, even if it is
1269 if (safe_atou(optarg, &arg_lines) < 0) {
1270 log_error("Failed to parse lines '%s'", optarg);
1276 arg_output = output_mode_from_string(optarg);
1277 if (arg_output < 0) {
1278 log_error("Unknown output '%s'.", optarg);
1284 arg_no_pager = true;
1291 case ARG_NO_ASK_PASSWORD:
1292 arg_ask_password = false;
1296 arg_kill_who = optarg;
1300 arg_signal = signal_from_string_try_harder(optarg);
1301 if (arg_signal < 0) {
1302 log_error("Failed to parse signal string %s.", optarg);
1308 arg_transport = BUS_TRANSPORT_REMOTE;
1313 arg_transport = BUS_TRANSPORT_MACHINE;
1321 assert_not_reached("Unhandled option");
1327 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1329 static const Verb verbs[] = {
1330 { "help", VERB_ANY, VERB_ANY, 0, help },
1331 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1332 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1333 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1334 { "activate", VERB_ANY, 2, 0, activate },
1335 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1336 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1337 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1338 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1339 { "terminate-session", 2, VERB_ANY, 0, activate },
1340 { "kill-session", 2, VERB_ANY, 0, kill_session },
1341 { "list-users", VERB_ANY, 1, 0, list_users },
1342 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1343 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1344 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1345 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1346 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1347 { "kill-user", 2, VERB_ANY, 0, kill_user },
1348 { "list-seats", VERB_ANY, 1, 0, list_seats },
1349 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1350 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1351 { "attach", 3, VERB_ANY, 0, attach },
1352 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1353 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1357 return dispatch_verb(argc, argv, verbs, bus);
1360 int main(int argc, char *argv[]) {
1361 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1364 setlocale(LC_ALL, "");
1365 log_parse_environment();
1368 r = parse_argv(argc, argv);
1372 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1374 log_error_errno(r, "Failed to create bus connection: %m");
1378 r = loginctl_main(argc, argv, bus);
1382 polkit_agent_close();
1384 strv_free(arg_property);
1386 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;