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();
687 if (properties && argc <= 1) {
688 /* If not argument is specified inspect the manager
690 return show_properties(bus, "/org/freedesktop/login1", &new_line);
693 for (i = 1; i < argc; i++) {
694 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
695 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
696 const char *path = NULL;
698 r = sd_bus_call_method(
700 "org.freedesktop.login1",
701 "/org/freedesktop/login1",
702 "org.freedesktop.login1.Manager",
707 log_error("Failed to get session: %s", bus_error_message(&error, r));
711 r = sd_bus_message_read(reply, "o", &path);
713 return bus_log_parse_error(r);
716 r = show_properties(bus, path, &new_line);
718 r = print_session_status_info(bus, path, &new_line);
727 static int show_user(int argc, char *argv[], void *userdata) {
728 bool properties, new_line = false;
729 sd_bus *bus = userdata;
735 properties = !strstr(argv[0], "status");
737 pager_open_if_enabled();
739 if (properties && argc <= 1) {
740 /* If not argument is specified inspect the manager
742 return show_properties(bus, "/org/freedesktop/login1", &new_line);
745 for (i = 1; i < argc; i++) {
746 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
747 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
748 const char *path = NULL;
751 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
753 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
755 r = sd_bus_call_method(
757 "org.freedesktop.login1",
758 "/org/freedesktop/login1",
759 "org.freedesktop.login1.Manager",
762 "u", (uint32_t) uid);
764 log_error("Failed to get user: %s", bus_error_message(&error, r));
768 r = sd_bus_message_read(reply, "o", &path);
770 return bus_log_parse_error(r);
773 r = show_properties(bus, path, &new_line);
775 r = print_user_status_info(bus, path, &new_line);
784 static int show_seat(int argc, char *argv[], void *userdata) {
785 bool properties, new_line = false;
786 sd_bus *bus = userdata;
792 properties = !strstr(argv[0], "status");
794 pager_open_if_enabled();
796 if (properties && argc <= 1) {
797 /* If not argument is specified inspect the manager
799 return show_properties(bus, "/org/freedesktop/login1", &new_line);
802 for (i = 1; i < argc; i++) {
803 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
804 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
805 const char *path = NULL;
807 r = sd_bus_call_method(
809 "org.freedesktop.login1",
810 "/org/freedesktop/login1",
811 "org.freedesktop.login1.Manager",
816 log_error("Failed to get seat: %s", bus_error_message(&error, r));
820 r = sd_bus_message_read(reply, "o", &path);
822 return bus_log_parse_error(r);
825 r = show_properties(bus, path, &new_line);
827 r = print_seat_status_info(bus, path, &new_line);
836 static int activate(int argc, char *argv[], void *userdata) {
837 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
838 sd_bus *bus = userdata;
844 polkit_agent_open_if_enabled();
846 for (i = 1; i < argc; i++) {
848 r = sd_bus_call_method (
850 "org.freedesktop.login1",
851 "/org/freedesktop/login1",
852 "org.freedesktop.login1.Manager",
853 streq(argv[0], "lock-session") ? "LockSession" :
854 streq(argv[0], "unlock-session") ? "UnlockSession" :
855 streq(argv[0], "terminate-session") ? "TerminateSession" :
860 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
868 static int kill_session(int argc, char *argv[], void *userdata) {
869 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
870 sd_bus *bus = userdata;
876 polkit_agent_open_if_enabled();
879 arg_kill_who = "all";
881 for (i = 1; i < argc; i++) {
883 r = sd_bus_call_method (
885 "org.freedesktop.login1",
886 "/org/freedesktop/login1",
887 "org.freedesktop.login1.Manager",
890 "ssi", argv[i], arg_kill_who, arg_signal);
892 log_error("Could not kill session: %s", bus_error_message(&error, -r));
900 static int enable_linger(int argc, char *argv[], void *userdata) {
901 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
902 sd_bus *bus = userdata;
909 polkit_agent_open_if_enabled();
911 b = streq(argv[0], "enable-linger");
913 for (i = 1; i < argc; i++) {
916 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
918 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
920 r = sd_bus_call_method (
922 "org.freedesktop.login1",
923 "/org/freedesktop/login1",
924 "org.freedesktop.login1.Manager",
927 "ubb", (uint32_t) uid, b, true);
929 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
937 static int terminate_user(int argc, char *argv[], void *userdata) {
938 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
939 sd_bus *bus = userdata;
945 polkit_agent_open_if_enabled();
947 for (i = 1; i < argc; i++) {
950 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
952 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
954 r = sd_bus_call_method (
956 "org.freedesktop.login1",
957 "/org/freedesktop/login1",
958 "org.freedesktop.login1.Manager",
961 "u", (uint32_t) uid);
963 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
971 static int kill_user(int argc, char *argv[], void *userdata) {
972 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
973 sd_bus *bus = userdata;
979 polkit_agent_open_if_enabled();
982 arg_kill_who = "all";
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 "ui", (uint32_t) uid, arg_signal);
1000 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1008 static int attach(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();
1018 for (i = 2; i < argc; i++) {
1020 r = sd_bus_call_method (
1022 "org.freedesktop.login1",
1023 "/org/freedesktop/login1",
1024 "org.freedesktop.login1.Manager",
1027 "ssb", argv[1], argv[i], true);
1030 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1038 static int flush_devices(int argc, char *argv[], void *userdata) {
1039 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1040 sd_bus *bus = userdata;
1046 polkit_agent_open_if_enabled();
1048 r = sd_bus_call_method (
1050 "org.freedesktop.login1",
1051 "/org/freedesktop/login1",
1052 "org.freedesktop.login1.Manager",
1057 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1062 static int lock_sessions(int argc, char *argv[], void *userdata) {
1063 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1064 sd_bus *bus = userdata;
1070 polkit_agent_open_if_enabled();
1072 r = sd_bus_call_method(
1074 "org.freedesktop.login1",
1075 "/org/freedesktop/login1",
1076 "org.freedesktop.login1.Manager",
1077 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1081 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1086 static int terminate_seat(int argc, char *argv[], void *userdata) {
1087 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1088 sd_bus *bus = userdata;
1094 polkit_agent_open_if_enabled();
1096 for (i = 1; i < argc; i++) {
1098 r = sd_bus_call_method(
1100 "org.freedesktop.login1",
1101 "/org/freedesktop/login1",
1102 "org.freedesktop.login1.Manager",
1107 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1115 static int help(int argc, char *argv[], void *userdata) {
1117 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1118 "Send control commands to or query the login manager.\n\n"
1119 " -h --help Show this help\n"
1120 " --version Show package version\n"
1121 " --no-pager Do not pipe output into a pager\n"
1122 " --no-legend Do not show the headers and footers\n"
1123 " --no-ask-password Don't prompt for password\n"
1124 " -H --host=[USER@]HOST Operate on remote host\n"
1125 " -M --machine=CONTAINER Operate on local container\n"
1126 " -p --property=NAME Show only properties by this name\n"
1127 " -a --all Show all properties, including empty ones\n"
1128 " -l --full Do not ellipsize output\n"
1129 " --kill-who=WHO Who to send signal to\n"
1130 " -s --signal=SIGNAL Which signal to send\n"
1131 " -n --lines=INTEGER Number of journal entries to show\n"
1132 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1133 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1134 "Session Commands:\n"
1135 " list-sessions List sessions\n"
1136 " session-status ID... Show session status\n"
1137 " show-session [ID...] Show properties of sessions or the manager\n"
1138 " activate ID Activate a session\n"
1139 " lock-session ID... Screen lock one or more sessions\n"
1140 " unlock-session ID... Screen unlock one or more sessions\n"
1141 " lock-sessions Screen lock all current sessions\n"
1142 " unlock-sessions Screen unlock all current sessions\n"
1143 " terminate-session ID... Terminate one or more sessions\n"
1144 " kill-session ID... Send signal to processes of a session\n\n"
1146 " list-users List users\n"
1147 " user-status USER... Show user status\n"
1148 " show-user [USER...] Show properties of users or the manager\n"
1149 " enable-linger USER... Enable linger state of one or more users\n"
1150 " disable-linger USER... Disable linger state of one or more users\n"
1151 " terminate-user USER... Terminate all sessions of one or more users\n"
1152 " kill-user USER... Send signal to processes of a user\n\n"
1154 " list-seats List seats\n"
1155 " seat-status NAME... Show seat status\n"
1156 " show-seat NAME... Show properties of one or more seats\n"
1157 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1158 " flush-devices Flush all device associations\n"
1159 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1160 , program_invocation_short_name);
1165 static int parse_argv(int argc, char *argv[]) {
1168 ARG_VERSION = 0x100,
1172 ARG_NO_ASK_PASSWORD,
1175 static const struct option options[] = {
1176 { "help", no_argument, NULL, 'h' },
1177 { "version", no_argument, NULL, ARG_VERSION },
1178 { "property", required_argument, NULL, 'p' },
1179 { "all", no_argument, NULL, 'a' },
1180 { "full", no_argument, NULL, 'l' },
1181 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1182 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1183 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1184 { "signal", required_argument, NULL, 's' },
1185 { "host", required_argument, NULL, 'H' },
1186 { "machine", required_argument, NULL, 'M' },
1187 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1188 { "lines", required_argument, NULL, 'n' },
1189 { "output", required_argument, NULL, 'o' },
1198 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1203 help(0, NULL, NULL);
1207 puts(PACKAGE_STRING);
1208 puts(SYSTEMD_FEATURES);
1212 r = strv_extend(&arg_property, optarg);
1216 /* If the user asked for a particular
1217 * property, show it to him, even if it is
1232 if (safe_atou(optarg, &arg_lines) < 0) {
1233 log_error("Failed to parse lines '%s'", optarg);
1239 arg_output = output_mode_from_string(optarg);
1240 if (arg_output < 0) {
1241 log_error("Unknown output '%s'.", optarg);
1247 arg_no_pager = true;
1254 case ARG_NO_ASK_PASSWORD:
1255 arg_ask_password = false;
1259 arg_kill_who = optarg;
1263 arg_signal = signal_from_string_try_harder(optarg);
1264 if (arg_signal < 0) {
1265 log_error("Failed to parse signal string %s.", optarg);
1271 arg_transport = BUS_TRANSPORT_REMOTE;
1276 arg_transport = BUS_TRANSPORT_MACHINE;
1284 assert_not_reached("Unhandled option");
1290 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1292 static const Verb verbs[] = {
1293 { "help", VERB_ANY, VERB_ANY, 0, help },
1294 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1295 { "session-status", 2, VERB_ANY, 0, show_session },
1296 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1297 { "activate", 2, 2, 0, activate },
1298 { "lock-session", 2, VERB_ANY, 0, activate },
1299 { "unlock-session", 2, VERB_ANY, 0, activate },
1300 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1301 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1302 { "terminate-session", 2, VERB_ANY, 0, activate },
1303 { "kill-session", 2, VERB_ANY, 0, kill_session },
1304 { "list-users", VERB_ANY, 1, 0, list_users },
1305 { "user-status", 2, VERB_ANY, 0, show_user },
1306 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1307 { "enable-linger", 2, VERB_ANY, 0, enable_linger },
1308 { "disable-linger", 2, VERB_ANY, 0, enable_linger },
1309 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1310 { "kill-user", 2, VERB_ANY, 0, kill_user },
1311 { "list-seats", VERB_ANY, 1, 0, list_seats },
1312 { "seat-status", 2, VERB_ANY, 0, show_seat },
1313 { "show-seat", VERB_ANY, 1, 0, show_seat },
1314 { "attach", 3, VERB_ANY, 0, attach },
1315 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1316 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1320 return dispatch_verb(argc, argv, verbs, bus);
1323 int main(int argc, char *argv[]) {
1324 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1327 setlocale(LC_ALL, "");
1328 log_parse_environment();
1331 r = parse_argv(argc, argv);
1335 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1337 log_error_errno(r, "Failed to create bus connection: %m");
1341 r = loginctl_main(argc, argv, bus);
1345 polkit_agent_close();
1347 strv_free(arg_property);
1349 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;