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 "cgroup-show.h"
41 #include "cgroup-util.h"
42 #include "spawn-polkit-agent.h"
44 static char **arg_property = NULL;
45 static bool arg_all = false;
46 static bool arg_full = false;
47 static bool arg_no_pager = false;
48 static bool arg_legend = true;
49 static const char *arg_kill_who = NULL;
50 static int arg_signal = SIGTERM;
51 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
52 static bool arg_ask_password = true;
53 static char *arg_host = NULL;
55 static void pager_open_if_enabled(void) {
63 static void polkit_agent_open_if_enabled(void) {
65 /* Open the polkit agent as a child process if necessary */
67 if (!arg_ask_password)
70 if (arg_transport != BUS_TRANSPORT_LOCAL)
76 static int list_sessions(sd_bus *bus, char **args, unsigned n) {
77 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
78 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
79 const char *id, *user, *seat, *object;
84 pager_open_if_enabled();
86 r = sd_bus_call_method(
88 "org.freedesktop.login1",
89 "/org/freedesktop/login1",
90 "org.freedesktop.login1.Manager",
95 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
99 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
101 return bus_log_parse_error(r);
104 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
106 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
107 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
111 return bus_log_parse_error(r);
114 printf("\n%u sessions listed.\n", k);
119 static int list_users(sd_bus *bus, char **args, unsigned n) {
120 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
121 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
122 const char *user, *object;
127 pager_open_if_enabled();
129 r = sd_bus_call_method(
131 "org.freedesktop.login1",
132 "/org/freedesktop/login1",
133 "org.freedesktop.login1.Manager",
138 log_error("Failed to list users: %s", bus_error_message(&error, r));
142 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
144 return bus_log_parse_error(r);
147 printf("%10s %-16s\n", "UID", "USER");
149 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
150 printf("%10u %-16s\n", (unsigned) uid, user);
154 return bus_log_parse_error(r);
157 printf("\n%u users listed.\n", k);
162 static int list_seats(sd_bus *bus, char **args, unsigned n) {
163 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
164 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
165 const char *seat, *object;
169 pager_open_if_enabled();
171 r = sd_bus_call_method(
173 "org.freedesktop.login1",
174 "/org/freedesktop/login1",
175 "org.freedesktop.login1.Manager",
180 log_error("Failed to list seats: %s", bus_error_message(&error, r));
184 r = sd_bus_message_enter_container(reply, 'a', "(so)");
186 return bus_log_parse_error(r);
189 printf("%-16s\n", "SEAT");
191 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
192 printf("%-16s\n", seat);
196 return bus_log_parse_error(r);
199 printf("\n%u seats listed.\n", k);
204 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
205 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
206 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
207 _cleanup_free_ char *path = NULL;
215 if (arg_transport != BUS_TRANSPORT_LOCAL)
218 path = unit_dbus_path_from_name(unit);
222 r = sd_bus_get_property(
224 "org.freedesktop.systemd1",
228 &error, &reply, "s");
232 r = sd_bus_message_read(reply, "s", &cgroup);
239 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
243 arg_all * OUTPUT_SHOW_ALL |
244 arg_full * OUTPUT_FULL_WIDTH;
252 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, output_flags);
256 typedef struct SessionStatusInfo {
266 const char *remote_host;
267 const char *remote_user;
276 typedef struct UserStatusInfo {
286 typedef struct SeatStatusInfo {
288 const char *active_session;
292 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
293 const char *contents;
296 r = sd_bus_message_peek_type(m, NULL, &contents);
300 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
304 if (contents[0] == 's' || contents[0] == 'o') {
306 char **p = (char **) userdata;
308 r = sd_bus_message_read_basic(m, contents[0], &s);
318 r = sd_bus_message_read_basic(m, contents[0], userdata);
323 r = sd_bus_message_skip(m, contents+1);
327 r = sd_bus_message_exit_container(m);
334 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
341 r = sd_bus_message_enter_container(m, 'a', "(so)");
345 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
346 r = strv_extend(userdata, name);
353 return sd_bus_message_exit_container(m);
356 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
358 static const struct bus_properties_map map[] = {
359 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
360 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
361 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
362 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
363 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
364 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
365 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
366 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
367 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
368 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
369 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
370 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
371 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
372 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
373 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp) },
374 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
375 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
379 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
380 char since2[FORMAT_TIMESTAMP_MAX], *s2;
381 SessionStatusInfo i = {};
384 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
386 log_error("Could not get properties: %s", strerror(-r));
395 printf("%s - ", strna(i.id));
398 printf("%s (%u)\n", i.name, (unsigned) i.uid);
400 printf("%u\n", (unsigned) i.uid);
402 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
403 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
406 printf("\t Since: %s; %s\n", s2, s1);
408 printf("\t Since: %s\n", s2);
411 _cleanup_free_ char *t = NULL;
413 printf("\t Leader: %u", (unsigned) i.leader);
415 get_process_comm(i.leader, &t);
422 if (!isempty(i.seat)) {
423 printf("\t Seat: %s", i.seat);
426 printf("; vc%i", i.vtnr);
432 printf("\t TTY: %s\n", i.tty);
434 printf("\t Display: %s\n", i.display);
436 if (i.remote_host && i.remote_user)
437 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
438 else if (i.remote_host)
439 printf("\t Remote: %s\n", i.remote_host);
440 else if (i.remote_user)
441 printf("\t Remote: user %s\n", i.remote_user);
443 printf("\t Remote: Yes\n");
446 printf("\t Service: %s", i.service);
449 printf("; type %s", i.type);
452 printf("; class %s", i.class);
456 printf("\t Type: %s", i.type);
459 printf("; class %s", i.class);
463 printf("\t Class: %s\n", i.class);
466 printf("\t State: %s\n", i.state);
469 printf("\t Unit: %s\n", i.scope);
470 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
476 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
478 static const struct bus_properties_map map[] = {
479 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
480 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
481 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
482 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
483 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp) },
484 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
485 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
489 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
490 char since2[FORMAT_TIMESTAMP_MAX], *s2;
491 UserStatusInfo i = {};
494 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
496 log_error("Could not get properties: %s", strerror(-r));
506 printf("%s (%u)\n", i.name, (unsigned) i.uid);
508 printf("%u\n", (unsigned) i.uid);
510 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
511 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
514 printf("\t Since: %s; %s\n", s2, s1);
516 printf("\t Since: %s\n", s2);
518 if (!isempty(i.state))
519 printf("\t State: %s\n", i.state);
521 if (!strv_isempty(i.sessions)) {
523 printf("\tSessions:");
525 STRV_FOREACH(l, i.sessions) {
526 if (streq_ptr(*l, i.display))
536 printf("\t Unit: %s\n", i.slice);
537 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
541 strv_free(i.sessions);
546 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
548 static const struct bus_properties_map map[] = {
549 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
550 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
551 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
555 SeatStatusInfo i = {};
558 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
560 log_error("Could not get properties: %s", strerror(-r));
569 printf("%s\n", strna(i.id));
571 if (!strv_isempty(i.sessions)) {
573 printf("\tSessions:");
575 STRV_FOREACH(l, i.sessions) {
576 if (streq_ptr(*l, i.active_session))
585 if (arg_transport == BUS_TRANSPORT_LOCAL) {
594 printf("\t Devices:\n");
596 show_sysfs(i.id, "\t\t ", c);
600 strv_free(i.sessions);
605 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
613 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
615 log_error("Could not get properties: %s", strerror(-r));
620 static int show_session(sd_bus *bus, char **args, unsigned n) {
621 bool properties, new_line = false;
628 properties = !strstr(args[0], "status");
630 pager_open_if_enabled();
632 if (properties && n <= 1) {
633 /* If not argument is specified inspect the manager
635 return show_properties(bus, "/org/freedesktop/login1", &new_line);
638 for (i = 1; i < n; i++) {
639 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
640 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
641 const char *path = NULL;
643 r = sd_bus_call_method(
645 "org.freedesktop.login1",
646 "/org/freedesktop/login1",
647 "org.freedesktop.login1.Manager",
652 log_error("Failed to get session: %s", bus_error_message(&error, r));
656 r = sd_bus_message_read(reply, "o", &path);
658 return bus_log_parse_error(r);
661 r = show_properties(bus, path, &new_line);
663 r = print_session_status_info(bus, path, &new_line);
672 static int show_user(sd_bus *bus, char **args, unsigned n) {
673 bool properties, new_line = false;
680 properties = !strstr(args[0], "status");
682 pager_open_if_enabled();
684 if (properties && n <= 1) {
685 /* If not argument is specified inspect the manager
687 return show_properties(bus, "/org/freedesktop/login1", &new_line);
690 for (i = 1; i < n; i++) {
691 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
692 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
693 const char *path = NULL;
696 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
698 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
702 r = sd_bus_call_method(
704 "org.freedesktop.login1",
705 "/org/freedesktop/login1",
706 "org.freedesktop.login1.Manager",
709 "u", (uint32_t) uid);
711 log_error("Failed to get user: %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_user_status_info(bus, path, &new_line);
731 static int show_seat(sd_bus *bus, char **args, unsigned n) {
732 bool properties, new_line = false;
739 properties = !strstr(args[0], "status");
741 pager_open_if_enabled();
743 if (properties && n <= 1) {
744 /* If not argument is specified inspect the manager
746 return show_properties(bus, "/org/freedesktop/login1", &new_line);
749 for (i = 1; i < n; i++) {
750 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
751 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
752 const char *path = NULL;
754 r = sd_bus_call_method(
756 "org.freedesktop.login1",
757 "/org/freedesktop/login1",
758 "org.freedesktop.login1.Manager",
763 log_error("Failed to get seat: %s", bus_error_message(&error, r));
767 r = sd_bus_message_read(reply, "o", &path);
769 return bus_log_parse_error(r);
772 r = show_properties(bus, path, &new_line);
774 r = print_seat_status_info(bus, path, &new_line);
783 static int activate(sd_bus *bus, char **args, unsigned n) {
784 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
790 for (i = 1; i < n; i++) {
792 r = sd_bus_call_method (
794 "org.freedesktop.login1",
795 "/org/freedesktop/login1",
796 "org.freedesktop.login1.Manager",
797 streq(args[0], "lock-session") ? "LockSession" :
798 streq(args[0], "unlock-session") ? "UnlockSession" :
799 streq(args[0], "terminate-session") ? "TerminateSession" :
804 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
812 static int kill_session(sd_bus *bus, char **args, unsigned n) {
813 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
820 arg_kill_who = "all";
822 for (i = 1; i < n; i++) {
824 r = sd_bus_call_method (
826 "org.freedesktop.login1",
827 "/org/freedesktop/login1",
828 "org.freedesktop.login1.Manager",
831 "ssi", args[i], arg_kill_who, arg_signal);
833 log_error("Could not kill session: %s", bus_error_message(&error, -r));
841 static int enable_linger(sd_bus *bus, char **args, unsigned n) {
842 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
849 polkit_agent_open_if_enabled();
851 b = streq(args[0], "enable-linger");
853 for (i = 1; i < n; i++) {
856 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
858 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
862 r = sd_bus_call_method (
864 "org.freedesktop.login1",
865 "/org/freedesktop/login1",
866 "org.freedesktop.login1.Manager",
869 "ubb", (uint32_t) uid, b, true);
871 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
879 static int terminate_user(sd_bus *bus, char **args, unsigned n) {
880 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
886 for (i = 1; i < n; i++) {
889 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
891 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
895 r = sd_bus_call_method (
897 "org.freedesktop.login1",
898 "/org/freedesktop/login1",
899 "org.freedesktop.login1.Manager",
902 "u", (uint32_t) uid);
904 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
912 static int kill_user(sd_bus *bus, char **args, unsigned n) {
913 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
920 arg_kill_who = "all";
922 for (i = 1; i < n; i++) {
925 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
927 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
931 r = sd_bus_call_method (
933 "org.freedesktop.login1",
934 "/org/freedesktop/login1",
935 "org.freedesktop.login1.Manager",
938 "ui", (uint32_t) uid, arg_signal);
940 log_error("Could not kill user: %s", bus_error_message(&error, -r));
948 static int attach(sd_bus *bus, char **args, unsigned n) {
949 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
955 polkit_agent_open_if_enabled();
957 for (i = 2; i < n; i++) {
959 r = sd_bus_call_method (
961 "org.freedesktop.login1",
962 "/org/freedesktop/login1",
963 "org.freedesktop.login1.Manager",
966 "ssb", args[1], args[i], true);
969 log_error("Could not attach device: %s", bus_error_message(&error, -r));
977 static int flush_devices(sd_bus *bus, char **args, unsigned n) {
978 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
983 polkit_agent_open_if_enabled();
985 r = sd_bus_call_method (
987 "org.freedesktop.login1",
988 "/org/freedesktop/login1",
989 "org.freedesktop.login1.Manager",
994 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
999 static int lock_sessions(sd_bus *bus, char **args, unsigned n) {
1000 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1005 r = sd_bus_call_method (
1007 "org.freedesktop.login1",
1008 "/org/freedesktop/login1",
1009 "org.freedesktop.login1.Manager",
1010 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1014 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1019 static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
1020 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1026 for (i = 1; i < n; i++) {
1028 r = sd_bus_call_method (
1030 "org.freedesktop.login1",
1031 "/org/freedesktop/login1",
1032 "org.freedesktop.login1.Manager",
1037 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1045 static int help(void) {
1047 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1048 "Send control commands to or query the login manager.\n\n"
1049 " -h --help Show this help\n"
1050 " --version Show package version\n"
1051 " --no-pager Do not pipe output into a pager\n"
1052 " --no-legend Do not show the headers and footers\n"
1053 " --no-ask-password Don't prompt for password\n"
1054 " -H --host=[USER@]HOST Operate on remote host\n"
1055 " -M --machine=CONTAINER Operate on local container\n"
1056 " -p --property=NAME Show only properties by this name\n"
1057 " -a --all Show all properties, including empty ones\n"
1058 " -l --full Do not ellipsize output\n"
1059 " --kill-who=WHO Who to send signal to\n"
1060 " -s --signal=SIGNAL Which signal to send\n\n"
1062 " list-sessions List sessions\n"
1063 " session-status ID... Show session status\n"
1064 " show-session [ID...] Show properties of sessions or the manager\n"
1065 " activate ID Activate a session\n"
1066 " lock-session ID... Screen lock one or more sessions\n"
1067 " unlock-session ID... Screen unlock one or more sessions\n"
1068 " lock-sessions Screen lock all current sessions\n"
1069 " unlock-sessions Screen unlock all current sessions\n"
1070 " terminate-session ID... Terminate one or more sessions\n"
1071 " kill-session ID... Send signal to processes of a session\n"
1072 " list-users List users\n"
1073 " user-status USER... Show user status\n"
1074 " show-user [USER...] Show properties of users or the manager\n"
1075 " enable-linger USER... Enable linger state of one or more users\n"
1076 " disable-linger USER... Disable linger state of one or more users\n"
1077 " terminate-user USER... Terminate all sessions of one or more users\n"
1078 " kill-user USER... Send signal to processes of a user\n"
1079 " list-seats List seats\n"
1080 " seat-status NAME... Show seat status\n"
1081 " show-seat NAME... Show properties of one or more seats\n"
1082 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1083 " flush-devices Flush all device associations\n"
1084 " terminate-seat NAME... Terminate all sessions on one or more seats\n",
1085 program_invocation_short_name);
1090 static int parse_argv(int argc, char *argv[]) {
1093 ARG_VERSION = 0x100,
1097 ARG_NO_ASK_PASSWORD,
1100 static const struct option options[] = {
1101 { "help", no_argument, NULL, 'h' },
1102 { "version", no_argument, NULL, ARG_VERSION },
1103 { "property", required_argument, NULL, 'p' },
1104 { "all", no_argument, NULL, 'a' },
1105 { "full", no_argument, NULL, 'l' },
1106 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1107 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1108 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1109 { "signal", required_argument, NULL, 's' },
1110 { "host", required_argument, NULL, 'H' },
1111 { "machine", required_argument, NULL, 'M' },
1112 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1121 while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) {
1129 puts(PACKAGE_STRING);
1130 puts(SYSTEMD_FEATURES);
1134 r = strv_extend(&arg_property, optarg);
1138 /* If the user asked for a particular
1139 * property, show it to him, even if it is
1154 arg_no_pager = true;
1161 case ARG_NO_ASK_PASSWORD:
1162 arg_ask_password = false;
1166 arg_kill_who = optarg;
1170 arg_signal = signal_from_string_try_harder(optarg);
1171 if (arg_signal < 0) {
1172 log_error("Failed to parse signal string %s.", optarg);
1178 arg_transport = BUS_TRANSPORT_REMOTE;
1183 arg_transport = BUS_TRANSPORT_CONTAINER;
1191 assert_not_reached("Unhandled option");
1198 static int loginctl_main(sd_bus *bus, int argc, char *argv[]) {
1200 static const struct {
1208 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1210 { "list-sessions", LESS, 1, list_sessions },
1211 { "session-status", MORE, 2, show_session },
1212 { "show-session", MORE, 1, show_session },
1213 { "activate", EQUAL, 2, activate },
1214 { "lock-session", MORE, 2, activate },
1215 { "unlock-session", MORE, 2, activate },
1216 { "lock-sessions", EQUAL, 1, lock_sessions },
1217 { "unlock-sessions", EQUAL, 1, lock_sessions },
1218 { "terminate-session", MORE, 2, activate },
1219 { "kill-session", MORE, 2, kill_session },
1220 { "list-users", EQUAL, 1, list_users },
1221 { "user-status", MORE, 2, show_user },
1222 { "show-user", MORE, 1, show_user },
1223 { "enable-linger", MORE, 2, enable_linger },
1224 { "disable-linger", MORE, 2, enable_linger },
1225 { "terminate-user", MORE, 2, terminate_user },
1226 { "kill-user", MORE, 2, kill_user },
1227 { "list-seats", EQUAL, 1, list_seats },
1228 { "seat-status", MORE, 2, show_seat },
1229 { "show-seat", MORE, 1, show_seat },
1230 { "attach", MORE, 3, attach },
1231 { "flush-devices", EQUAL, 1, flush_devices },
1232 { "terminate-seat", MORE, 2, terminate_seat },
1241 left = argc - optind;
1244 /* Special rule: no arguments means "list-sessions" */
1247 if (streq(argv[optind], "help")) {
1252 for (i = 0; i < ELEMENTSOF(verbs); i++)
1253 if (streq(argv[optind], verbs[i].verb))
1256 if (i >= ELEMENTSOF(verbs)) {
1257 log_error("Unknown operation %s", argv[optind]);
1262 switch (verbs[i].argc_cmp) {
1265 if (left != verbs[i].argc) {
1266 log_error("Invalid number of arguments.");
1273 if (left < verbs[i].argc) {
1274 log_error("Too few arguments.");
1281 if (left > verbs[i].argc) {
1282 log_error("Too many arguments.");
1289 assert_not_reached("Unknown comparison operator.");
1292 return verbs[i].dispatch(bus, argv + optind, left);
1295 int main(int argc, char *argv[]) {
1296 _cleanup_bus_unref_ sd_bus *bus = NULL;
1299 setlocale(LC_ALL, "");
1300 log_parse_environment();
1303 r = parse_argv(argc, argv);
1307 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1309 log_error("Failed to create bus connection: %s", strerror(-r));
1313 r = loginctl_main(bus, argc, argv);
1318 strv_free(arg_property);
1320 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;