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 static char **arg_property = NULL;
46 static bool arg_all = false;
47 static bool arg_full = false;
48 static bool arg_no_pager = false;
49 static bool arg_legend = true;
50 static const char *arg_kill_who = NULL;
51 static int arg_signal = SIGTERM;
52 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
53 static char *arg_host = NULL;
54 static bool arg_ask_password = true;
55 static unsigned arg_lines = 10;
56 static OutputMode arg_output = OUTPUT_SHORT;
58 static void pager_open_if_enabled(void) {
66 static void polkit_agent_open_if_enabled(void) {
68 /* Open the polkit agent as a child process if necessary */
70 if (!arg_ask_password)
73 if (arg_transport != BUS_TRANSPORT_LOCAL)
79 static OutputFlags get_output_flags(void) {
82 arg_all * OUTPUT_SHOW_ALL |
83 arg_full * OUTPUT_FULL_WIDTH |
84 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
85 on_tty() * OUTPUT_COLOR;
88 static int list_sessions(sd_bus *bus, char **args, unsigned n) {
89 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
90 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
91 const char *id, *user, *seat, *object;
96 pager_open_if_enabled();
98 r = sd_bus_call_method(
100 "org.freedesktop.login1",
101 "/org/freedesktop/login1",
102 "org.freedesktop.login1.Manager",
107 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
111 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
113 return bus_log_parse_error(r);
116 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
118 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
119 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
123 return bus_log_parse_error(r);
126 printf("\n%u sessions listed.\n", k);
131 static int list_users(sd_bus *bus, char **args, unsigned n) {
132 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
133 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
134 const char *user, *object;
139 pager_open_if_enabled();
141 r = sd_bus_call_method(
143 "org.freedesktop.login1",
144 "/org/freedesktop/login1",
145 "org.freedesktop.login1.Manager",
150 log_error("Failed to list users: %s", bus_error_message(&error, r));
154 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
156 return bus_log_parse_error(r);
159 printf("%10s %-16s\n", "UID", "USER");
161 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
162 printf("%10u %-16s\n", (unsigned) uid, user);
166 return bus_log_parse_error(r);
169 printf("\n%u users listed.\n", k);
174 static int list_seats(sd_bus *bus, char **args, unsigned n) {
175 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
176 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
177 const char *seat, *object;
181 pager_open_if_enabled();
183 r = sd_bus_call_method(
185 "org.freedesktop.login1",
186 "/org/freedesktop/login1",
187 "org.freedesktop.login1.Manager",
192 log_error("Failed to list seats: %s", bus_error_message(&error, r));
196 r = sd_bus_message_enter_container(reply, 'a', "(so)");
198 return bus_log_parse_error(r);
201 printf("%-16s\n", "SEAT");
203 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
204 printf("%-16s\n", seat);
208 return bus_log_parse_error(r);
211 printf("\n%u seats listed.\n", k);
216 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
217 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
218 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
219 _cleanup_free_ char *path = NULL;
227 if (arg_transport != BUS_TRANSPORT_LOCAL)
230 path = unit_dbus_path_from_name(unit);
234 r = sd_bus_get_property(
236 "org.freedesktop.systemd1",
240 &error, &reply, "s");
244 r = sd_bus_message_read(reply, "s", &cgroup);
251 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
260 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
264 typedef struct SessionStatusInfo {
268 struct dual_timestamp timestamp;
274 const char *remote_host;
275 const char *remote_user;
285 typedef struct UserStatusInfo {
288 struct dual_timestamp timestamp;
295 typedef struct SeatStatusInfo {
297 const char *active_session;
301 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
302 const char *contents;
305 r = sd_bus_message_peek_type(m, NULL, &contents);
309 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
313 if (contents[0] == 's' || contents[0] == 'o') {
315 char **p = (char **) userdata;
317 r = sd_bus_message_read_basic(m, contents[0], &s);
327 r = sd_bus_message_read_basic(m, contents[0], userdata);
332 r = sd_bus_message_skip(m, contents+1);
336 r = sd_bus_message_exit_container(m);
343 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
350 r = sd_bus_message_enter_container(m, 'a', "(so)");
354 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
355 r = strv_extend(userdata, name);
362 return sd_bus_message_exit_container(m);
365 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
367 static const struct bus_properties_map map[] = {
368 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
369 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
370 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
371 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
372 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
373 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
374 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
375 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
376 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
377 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
378 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
379 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
380 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
381 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
382 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
383 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
384 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
385 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
386 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
390 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
391 char since2[FORMAT_TIMESTAMP_MAX], *s2;
392 SessionStatusInfo i = {};
395 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
397 return log_error_errno(r, "Could not get properties: %m");
404 printf("%s - ", strna(i.id));
407 printf("%s (%u)\n", i.name, (unsigned) i.uid);
409 printf("%u\n", (unsigned) i.uid);
411 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
412 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
415 printf("\t Since: %s; %s\n", s2, s1);
417 printf("\t Since: %s\n", s2);
420 _cleanup_free_ char *t = NULL;
422 printf("\t Leader: %u", (unsigned) i.leader);
424 get_process_comm(i.leader, &t);
431 if (!isempty(i.seat)) {
432 printf("\t Seat: %s", i.seat);
435 printf("; vc%u", i.vtnr);
441 printf("\t TTY: %s\n", i.tty);
443 printf("\t Display: %s\n", i.display);
445 if (i.remote_host && i.remote_user)
446 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
447 else if (i.remote_host)
448 printf("\t Remote: %s\n", i.remote_host);
449 else if (i.remote_user)
450 printf("\t Remote: user %s\n", i.remote_user);
452 printf("\t Remote: Yes\n");
455 printf("\t Service: %s", i.service);
458 printf("; type %s", i.type);
461 printf("; class %s", i.class);
465 printf("\t Type: %s", i.type);
468 printf("; class %s", i.class);
472 printf("\t Class: %s\n", i.class);
474 if (!isempty(i.desktop))
475 printf("\t Desktop: %s\n", i.desktop);
478 printf("\t State: %s\n", i.state);
481 printf("\t Unit: %s\n", i.scope);
482 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
484 if (arg_transport == BUS_TRANSPORT_LOCAL) {
486 show_journal_by_unit(
491 i.timestamp.monotonic,
494 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
495 SD_JOURNAL_LOCAL_ONLY,
504 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
506 static const struct bus_properties_map map[] = {
507 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
508 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
509 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
510 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
511 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
512 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
513 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
514 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
518 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
519 char since2[FORMAT_TIMESTAMP_MAX], *s2;
520 UserStatusInfo i = {};
523 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
525 log_error_errno(r, "Could not get properties: %m");
535 printf("%s (%u)\n", i.name, (unsigned) i.uid);
537 printf("%u\n", (unsigned) i.uid);
539 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
540 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
543 printf("\t Since: %s; %s\n", s2, s1);
545 printf("\t Since: %s\n", s2);
547 if (!isempty(i.state))
548 printf("\t State: %s\n", i.state);
550 if (!strv_isempty(i.sessions)) {
552 printf("\tSessions:");
554 STRV_FOREACH(l, i.sessions) {
555 if (streq_ptr(*l, i.display))
565 printf("\t Unit: %s\n", i.slice);
566 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
568 show_journal_by_unit(
573 i.timestamp.monotonic,
576 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
577 SD_JOURNAL_LOCAL_ONLY,
583 strv_free(i.sessions);
588 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
590 static const struct bus_properties_map map[] = {
591 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
592 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
593 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
597 SeatStatusInfo i = {};
600 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
602 log_error_errno(r, "Could not get properties: %m");
611 printf("%s\n", strna(i.id));
613 if (!strv_isempty(i.sessions)) {
615 printf("\tSessions:");
617 STRV_FOREACH(l, i.sessions) {
618 if (streq_ptr(*l, i.active_session))
627 if (arg_transport == BUS_TRANSPORT_LOCAL) {
636 printf("\t Devices:\n");
638 show_sysfs(i.id, "\t\t ", c);
642 strv_free(i.sessions);
647 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
655 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
657 log_error_errno(r, "Could not get properties: %m");
662 static int show_session(sd_bus *bus, char **args, unsigned n) {
663 bool properties, new_line = false;
670 properties = !strstr(args[0], "status");
672 pager_open_if_enabled();
674 if (properties && n <= 1) {
675 /* If not argument is specified inspect the manager
677 return show_properties(bus, "/org/freedesktop/login1", &new_line);
680 for (i = 1; i < n; i++) {
681 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
682 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
683 const char *path = NULL;
685 r = sd_bus_call_method(
687 "org.freedesktop.login1",
688 "/org/freedesktop/login1",
689 "org.freedesktop.login1.Manager",
694 log_error("Failed to get session: %s", bus_error_message(&error, r));
698 r = sd_bus_message_read(reply, "o", &path);
700 return bus_log_parse_error(r);
703 r = show_properties(bus, path, &new_line);
705 r = print_session_status_info(bus, path, &new_line);
714 static int show_user(sd_bus *bus, char **args, unsigned n) {
715 bool properties, new_line = false;
722 properties = !strstr(args[0], "status");
724 pager_open_if_enabled();
726 if (properties && n <= 1) {
727 /* If not argument is specified inspect the manager
729 return show_properties(bus, "/org/freedesktop/login1", &new_line);
732 for (i = 1; i < n; i++) {
733 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
734 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
735 const char *path = NULL;
738 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
740 return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
742 r = sd_bus_call_method(
744 "org.freedesktop.login1",
745 "/org/freedesktop/login1",
746 "org.freedesktop.login1.Manager",
749 "u", (uint32_t) uid);
751 log_error("Failed to get user: %s", bus_error_message(&error, r));
755 r = sd_bus_message_read(reply, "o", &path);
757 return bus_log_parse_error(r);
760 r = show_properties(bus, path, &new_line);
762 r = print_user_status_info(bus, path, &new_line);
771 static int show_seat(sd_bus *bus, char **args, unsigned n) {
772 bool properties, new_line = false;
779 properties = !strstr(args[0], "status");
781 pager_open_if_enabled();
783 if (properties && n <= 1) {
784 /* If not argument is specified inspect the manager
786 return show_properties(bus, "/org/freedesktop/login1", &new_line);
789 for (i = 1; i < n; i++) {
790 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
791 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
792 const char *path = NULL;
794 r = sd_bus_call_method(
796 "org.freedesktop.login1",
797 "/org/freedesktop/login1",
798 "org.freedesktop.login1.Manager",
803 log_error("Failed to get seat: %s", bus_error_message(&error, r));
807 r = sd_bus_message_read(reply, "o", &path);
809 return bus_log_parse_error(r);
812 r = show_properties(bus, path, &new_line);
814 r = print_seat_status_info(bus, path, &new_line);
823 static int activate(sd_bus *bus, char **args, unsigned n) {
824 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
830 polkit_agent_open_if_enabled();
832 for (i = 1; i < n; i++) {
834 r = sd_bus_call_method (
836 "org.freedesktop.login1",
837 "/org/freedesktop/login1",
838 "org.freedesktop.login1.Manager",
839 streq(args[0], "lock-session") ? "LockSession" :
840 streq(args[0], "unlock-session") ? "UnlockSession" :
841 streq(args[0], "terminate-session") ? "TerminateSession" :
846 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
854 static int kill_session(sd_bus *bus, char **args, unsigned n) {
855 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
861 polkit_agent_open_if_enabled();
864 arg_kill_who = "all";
866 for (i = 1; i < n; i++) {
868 r = sd_bus_call_method (
870 "org.freedesktop.login1",
871 "/org/freedesktop/login1",
872 "org.freedesktop.login1.Manager",
875 "ssi", args[i], arg_kill_who, arg_signal);
877 log_error("Could not kill session: %s", bus_error_message(&error, -r));
885 static int enable_linger(sd_bus *bus, char **args, unsigned n) {
886 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
893 polkit_agent_open_if_enabled();
895 b = streq(args[0], "enable-linger");
897 for (i = 1; i < n; i++) {
900 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
902 return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
904 r = sd_bus_call_method (
906 "org.freedesktop.login1",
907 "/org/freedesktop/login1",
908 "org.freedesktop.login1.Manager",
911 "ubb", (uint32_t) uid, b, true);
913 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
921 static int terminate_user(sd_bus *bus, char **args, unsigned n) {
922 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
928 polkit_agent_open_if_enabled();
930 for (i = 1; i < n; i++) {
933 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
935 return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
937 r = sd_bus_call_method (
939 "org.freedesktop.login1",
940 "/org/freedesktop/login1",
941 "org.freedesktop.login1.Manager",
944 "u", (uint32_t) uid);
946 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
954 static int kill_user(sd_bus *bus, char **args, unsigned n) {
955 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
961 polkit_agent_open_if_enabled();
964 arg_kill_who = "all";
966 for (i = 1; i < n; i++) {
969 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
971 return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
973 r = sd_bus_call_method (
975 "org.freedesktop.login1",
976 "/org/freedesktop/login1",
977 "org.freedesktop.login1.Manager",
980 "ui", (uint32_t) uid, arg_signal);
982 log_error("Could not kill user: %s", bus_error_message(&error, -r));
990 static int attach(sd_bus *bus, char **args, unsigned n) {
991 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
997 polkit_agent_open_if_enabled();
999 for (i = 2; i < n; i++) {
1001 r = sd_bus_call_method (
1003 "org.freedesktop.login1",
1004 "/org/freedesktop/login1",
1005 "org.freedesktop.login1.Manager",
1008 "ssb", args[1], args[i], true);
1011 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1019 static int flush_devices(sd_bus *bus, char **args, unsigned n) {
1020 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1025 polkit_agent_open_if_enabled();
1027 r = sd_bus_call_method (
1029 "org.freedesktop.login1",
1030 "/org/freedesktop/login1",
1031 "org.freedesktop.login1.Manager",
1036 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1041 static int lock_sessions(sd_bus *bus, char **args, unsigned n) {
1042 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1047 polkit_agent_open_if_enabled();
1049 r = sd_bus_call_method (
1051 "org.freedesktop.login1",
1052 "/org/freedesktop/login1",
1053 "org.freedesktop.login1.Manager",
1054 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1058 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1063 static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
1064 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1070 polkit_agent_open_if_enabled();
1072 for (i = 1; i < n; i++) {
1074 r = sd_bus_call_method (
1076 "org.freedesktop.login1",
1077 "/org/freedesktop/login1",
1078 "org.freedesktop.login1.Manager",
1083 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1091 static void help(void) {
1093 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1094 "Send control commands to or query the login manager.\n\n"
1095 " -h --help Show this help\n"
1096 " --version Show package version\n"
1097 " --no-pager Do not pipe output into a pager\n"
1098 " --no-legend Do not show the headers and footers\n"
1099 " --no-ask-password Don't prompt for password\n"
1100 " -H --host=[USER@]HOST Operate on remote host\n"
1101 " -M --machine=CONTAINER Operate on local container\n"
1102 " -p --property=NAME Show only properties by this name\n"
1103 " -a --all Show all properties, including empty ones\n"
1104 " -l --full Do not ellipsize output\n"
1105 " --kill-who=WHO Who to send signal to\n"
1106 " -s --signal=SIGNAL Which signal to send\n"
1107 " -n --lines=INTEGER Number of journal entries to show\n"
1108 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1109 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1110 "Session Commands:\n"
1111 " list-sessions List sessions\n"
1112 " session-status ID... Show session status\n"
1113 " show-session [ID...] Show properties of sessions or the manager\n"
1114 " activate ID Activate a session\n"
1115 " lock-session ID... Screen lock one or more sessions\n"
1116 " unlock-session ID... Screen unlock one or more sessions\n"
1117 " lock-sessions Screen lock all current sessions\n"
1118 " unlock-sessions Screen unlock all current sessions\n"
1119 " terminate-session ID... Terminate one or more sessions\n"
1120 " kill-session ID... Send signal to processes of a session\n\n"
1122 " list-users List users\n"
1123 " user-status USER... Show user status\n"
1124 " show-user [USER...] Show properties of users or the manager\n"
1125 " enable-linger USER... Enable linger state of one or more users\n"
1126 " disable-linger USER... Disable linger state of one or more users\n"
1127 " terminate-user USER... Terminate all sessions of one or more users\n"
1128 " kill-user USER... Send signal to processes of a user\n\n"
1130 " list-seats List seats\n"
1131 " seat-status NAME... Show seat status\n"
1132 " show-seat NAME... Show properties of one or more seats\n"
1133 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1134 " flush-devices Flush all device associations\n"
1135 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1136 , program_invocation_short_name);
1139 static int parse_argv(int argc, char *argv[]) {
1142 ARG_VERSION = 0x100,
1146 ARG_NO_ASK_PASSWORD,
1149 static const struct option options[] = {
1150 { "help", no_argument, NULL, 'h' },
1151 { "version", no_argument, NULL, ARG_VERSION },
1152 { "property", required_argument, NULL, 'p' },
1153 { "all", no_argument, NULL, 'a' },
1154 { "full", no_argument, NULL, 'l' },
1155 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1156 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1157 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1158 { "signal", required_argument, NULL, 's' },
1159 { "host", required_argument, NULL, 'H' },
1160 { "machine", required_argument, NULL, 'M' },
1161 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1162 { "lines", required_argument, NULL, 'n' },
1163 { "output", required_argument, NULL, 'o' },
1172 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1181 puts(PACKAGE_STRING);
1182 puts(SYSTEMD_FEATURES);
1186 r = strv_extend(&arg_property, optarg);
1190 /* If the user asked for a particular
1191 * property, show it to him, even if it is
1206 if (safe_atou(optarg, &arg_lines) < 0) {
1207 log_error("Failed to parse lines '%s'", optarg);
1213 arg_output = output_mode_from_string(optarg);
1214 if (arg_output < 0) {
1215 log_error("Unknown output '%s'.", optarg);
1221 arg_no_pager = true;
1228 case ARG_NO_ASK_PASSWORD:
1229 arg_ask_password = false;
1233 arg_kill_who = optarg;
1237 arg_signal = signal_from_string_try_harder(optarg);
1238 if (arg_signal < 0) {
1239 log_error("Failed to parse signal string %s.", optarg);
1245 arg_transport = BUS_TRANSPORT_REMOTE;
1250 arg_transport = BUS_TRANSPORT_MACHINE;
1258 assert_not_reached("Unhandled option");
1264 static int loginctl_main(sd_bus *bus, int argc, char *argv[]) {
1266 static const struct {
1274 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1276 { "list-sessions", LESS, 1, list_sessions },
1277 { "session-status", MORE, 2, show_session },
1278 { "show-session", MORE, 1, show_session },
1279 { "activate", EQUAL, 2, activate },
1280 { "lock-session", MORE, 2, activate },
1281 { "unlock-session", MORE, 2, activate },
1282 { "lock-sessions", EQUAL, 1, lock_sessions },
1283 { "unlock-sessions", EQUAL, 1, lock_sessions },
1284 { "terminate-session", MORE, 2, activate },
1285 { "kill-session", MORE, 2, kill_session },
1286 { "list-users", EQUAL, 1, list_users },
1287 { "user-status", MORE, 2, show_user },
1288 { "show-user", MORE, 1, show_user },
1289 { "enable-linger", MORE, 2, enable_linger },
1290 { "disable-linger", MORE, 2, enable_linger },
1291 { "terminate-user", MORE, 2, terminate_user },
1292 { "kill-user", MORE, 2, kill_user },
1293 { "list-seats", EQUAL, 1, list_seats },
1294 { "seat-status", MORE, 2, show_seat },
1295 { "show-seat", MORE, 1, show_seat },
1296 { "attach", MORE, 3, attach },
1297 { "flush-devices", EQUAL, 1, flush_devices },
1298 { "terminate-seat", MORE, 2, terminate_seat },
1307 left = argc - optind;
1310 /* Special rule: no arguments means "list-sessions" */
1313 if (streq(argv[optind], "help")) {
1318 for (i = 0; i < ELEMENTSOF(verbs); i++)
1319 if (streq(argv[optind], verbs[i].verb))
1322 if (i >= ELEMENTSOF(verbs)) {
1323 log_error("Unknown operation %s", argv[optind]);
1328 switch (verbs[i].argc_cmp) {
1331 if (left != verbs[i].argc) {
1332 log_error("Invalid number of arguments.");
1339 if (left < verbs[i].argc) {
1340 log_error("Too few arguments.");
1347 if (left > verbs[i].argc) {
1348 log_error("Too many arguments.");
1355 assert_not_reached("Unknown comparison operator.");
1358 return verbs[i].dispatch(bus, argv + optind, left);
1361 int main(int argc, char *argv[]) {
1362 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1365 setlocale(LC_ALL, "");
1366 log_parse_environment();
1369 r = parse_argv(argc, argv);
1373 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1375 log_error_errno(r, "Failed to create bus connection: %m");
1379 r = loginctl_main(bus, argc, argv);
1384 strv_free(arg_property);
1386 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;