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, id) },
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);
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\n", i.type);
459 printf("; class %s", i.class);
461 printf("\t Class: %s\n", i.class);
464 printf("\t State: %s\n", i.state);
467 printf("\t Unit: %s\n", i.scope);
468 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
474 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
476 static const struct bus_properties_map map[] = {
477 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
478 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
479 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
480 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
481 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp) },
482 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
483 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
487 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
488 char since2[FORMAT_TIMESTAMP_MAX], *s2;
489 UserStatusInfo i = {};
492 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
494 log_error("Could not get properties: %s", strerror(-r));
504 printf("%s (%u)\n", i.name, (unsigned) i.uid);
506 printf("%u\n", (unsigned) i.uid);
508 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
509 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
512 printf("\t Since: %s; %s\n", s2, s1);
514 printf("\t Since: %s\n", s2);
516 if (!isempty(i.state))
517 printf("\t State: %s\n", i.state);
519 if (!strv_isempty(i.sessions)) {
521 printf("\tSessions:");
523 STRV_FOREACH(l, i.sessions) {
524 if (streq_ptr(*l, i.display))
534 printf("\t Unit: %s\n", i.slice);
535 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
539 strv_free(i.sessions);
544 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
546 static const struct bus_properties_map map[] = {
547 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
548 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
549 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
553 SeatStatusInfo i = {};
556 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
558 log_error("Could not get properties: %s", strerror(-r));
567 printf("%s\n", strna(i.id));
569 if (!strv_isempty(i.sessions)) {
571 printf("\tSessions:");
573 STRV_FOREACH(l, i.sessions) {
574 if (streq_ptr(*l, i.active_session))
583 if (arg_transport == BUS_TRANSPORT_LOCAL) {
592 printf("\t Devices:\n");
594 show_sysfs(i.id, "\t\t ", c);
598 strv_free(i.sessions);
603 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
611 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
613 log_error("Could not get properties: %s", strerror(-r));
618 static int show_session(sd_bus *bus, char **args, unsigned n) {
619 bool properties, new_line = false;
626 properties = !strstr(args[0], "status");
628 pager_open_if_enabled();
630 if (properties && n <= 1) {
631 /* If not argument is specified inspect the manager
633 return show_properties(bus, "/org/freedesktop/login1", &new_line);
636 for (i = 1; i < n; i++) {
637 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
638 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
639 const char *path = NULL;
641 r = sd_bus_call_method(
643 "org.freedesktop.login1",
644 "/org/freedesktop/login1",
645 "org.freedesktop.login1.Manager",
650 log_error("Failed to get session: %s", bus_error_message(&error, r));
654 r = sd_bus_message_read(reply, "o", &path);
656 return bus_log_parse_error(r);
659 r = show_properties(bus, path, &new_line);
661 r = print_session_status_info(bus, path, &new_line);
670 static int show_user(sd_bus *bus, char **args, unsigned n) {
671 bool properties, new_line = false;
678 properties = !strstr(args[0], "status");
680 pager_open_if_enabled();
682 if (properties && n <= 1) {
683 /* If not argument is specified inspect the manager
685 return show_properties(bus, "/org/freedesktop/login1", &new_line);
688 for (i = 1; i < n; i++) {
689 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
690 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
691 const char *path = NULL;
694 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
696 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
700 r = sd_bus_call_method(
702 "org.freedesktop.login1",
703 "/org/freedesktop/login1",
704 "org.freedesktop.login1.Manager",
707 "u", (uint32_t) uid);
709 log_error("Failed to get user: %s", bus_error_message(&error, r));
713 r = sd_bus_message_read(reply, "o", &path);
715 return bus_log_parse_error(r);
718 r = show_properties(bus, path, &new_line);
720 r = print_user_status_info(bus, path, &new_line);
729 static int show_seat(sd_bus *bus, char **args, unsigned n) {
730 bool properties, new_line = false;
737 properties = !strstr(args[0], "status");
739 pager_open_if_enabled();
741 if (properties && n <= 1) {
742 /* If not argument is specified inspect the manager
744 return show_properties(bus, "/org/freedesktop/login1", &new_line);
747 for (i = 1; i < n; i++) {
748 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
749 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
750 const char *path = NULL;
752 r = sd_bus_call_method(
754 "org.freedesktop.login1",
755 "/org/freedesktop/login1",
756 "org.freedesktop.login1.Manager",
761 log_error("Failed to get seat: %s", bus_error_message(&error, r));
765 r = sd_bus_message_read(reply, "o", &path);
767 return bus_log_parse_error(r);
770 r = show_properties(bus, path, &new_line);
772 r = print_seat_status_info(bus, path, &new_line);
781 static int activate(sd_bus *bus, char **args, unsigned n) {
782 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
788 for (i = 1; i < n; i++) {
790 r = sd_bus_call_method (
792 "org.freedesktop.login1",
793 "/org/freedesktop/login1",
794 "org.freedesktop.login1.Manager",
795 streq(args[0], "lock-session") ? "LockSession" :
796 streq(args[0], "unlock-session") ? "UnlockSession" :
797 streq(args[0], "terminate-session") ? "TerminateSession" :
802 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
810 static int kill_session(sd_bus *bus, char **args, unsigned n) {
811 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
818 arg_kill_who = "all";
820 for (i = 1; i < n; i++) {
822 r = sd_bus_call_method (
824 "org.freedesktop.login1",
825 "/org/freedesktop/login1",
826 "org.freedesktop.login1.Manager",
829 "ssi", args[i], arg_kill_who, arg_signal);
831 log_error("Could not kill session: %s", bus_error_message(&error, -r));
839 static int enable_linger(sd_bus *bus, char **args, unsigned n) {
840 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
847 polkit_agent_open_if_enabled();
849 b = streq(args[0], "enable-linger");
851 for (i = 1; i < n; i++) {
854 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
856 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
860 r = sd_bus_call_method (
862 "org.freedesktop.login1",
863 "/org/freedesktop/login1",
864 "org.freedesktop.login1.Manager",
867 "ubb", (uint32_t) uid, b, true);
869 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
877 static int terminate_user(sd_bus *bus, char **args, unsigned n) {
878 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
884 for (i = 1; i < n; i++) {
887 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
889 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
893 r = sd_bus_call_method (
895 "org.freedesktop.login1",
896 "/org/freedesktop/login1",
897 "org.freedesktop.login1.Manager",
900 "u", (uint32_t) uid);
902 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
910 static int kill_user(sd_bus *bus, char **args, unsigned n) {
911 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
918 arg_kill_who = "all";
920 for (i = 1; i < n; i++) {
923 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
925 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
929 r = sd_bus_call_method (
931 "org.freedesktop.login1",
932 "/org/freedesktop/login1",
933 "org.freedesktop.login1.Manager",
936 "ui", (uint32_t) uid, arg_signal);
938 log_error("Could not kill user: %s", bus_error_message(&error, -r));
946 static int attach(sd_bus *bus, char **args, unsigned n) {
947 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
953 polkit_agent_open_if_enabled();
955 for (i = 2; i < n; i++) {
957 r = sd_bus_call_method (
959 "org.freedesktop.login1",
960 "/org/freedesktop/login1",
961 "org.freedesktop.login1.Manager",
964 "ssb", args[1], args[i], true);
967 log_error("Could not attach device: %s", bus_error_message(&error, -r));
975 static int flush_devices(sd_bus *bus, char **args, unsigned n) {
976 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
981 polkit_agent_open_if_enabled();
983 r = sd_bus_call_method (
985 "org.freedesktop.login1",
986 "/org/freedesktop/login1",
987 "org.freedesktop.login1.Manager",
992 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
997 static int lock_sessions(sd_bus *bus, char **args, unsigned n) {
998 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1003 r = sd_bus_call_method (
1005 "org.freedesktop.login1",
1006 "/org/freedesktop/login1",
1007 "org.freedesktop.login1.Manager",
1008 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1012 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1017 static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
1018 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1024 for (i = 1; i < n; i++) {
1026 r = sd_bus_call_method (
1028 "org.freedesktop.login1",
1029 "/org/freedesktop/login1",
1030 "org.freedesktop.login1.Manager",
1035 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1043 static int help(void) {
1045 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1046 "Send control commands to or query the login manager.\n\n"
1047 " -h --help Show this help\n"
1048 " --version Show package version\n"
1049 " --no-pager Do not pipe output into a pager\n"
1050 " --no-legend Do not show the headers and footers\n"
1051 " --no-ask-password Don't prompt for password\n"
1052 " -H --host=[USER@]HOST Operate on remote host\n"
1053 " -M --machine=CONTAINER Operate on local container\n"
1054 " -p --property=NAME Show only properties by this name\n"
1055 " -a --all Show all properties, including empty ones\n"
1056 " -l --full Do not ellipsize output\n"
1057 " --kill-who=WHO Who to send signal to\n"
1058 " -s --signal=SIGNAL Which signal to send\n\n"
1060 " list-sessions List sessions\n"
1061 " session-status ID... Show session status\n"
1062 " show-session [ID...] Show properties of sessions or the manager\n"
1063 " activate ID Activate a session\n"
1064 " lock-session ID... Screen lock one or more sessions\n"
1065 " unlock-session ID... Screen unlock one or more sessions\n"
1066 " lock-sessions Screen lock all current sessions\n"
1067 " unlock-sessions Screen unlock all current sessions\n"
1068 " terminate-session ID... Terminate one or more sessions\n"
1069 " kill-session ID... Send signal to processes of a session\n"
1070 " list-users List users\n"
1071 " user-status USER... Show user status\n"
1072 " show-user [USER...] Show properties of users or the manager\n"
1073 " enable-linger USER... Enable linger state of one or more users\n"
1074 " disable-linger USER... Disable linger state of one or more users\n"
1075 " terminate-user USER... Terminate all sessions of one or more users\n"
1076 " kill-user USER... Send signal to processes of a user\n"
1077 " list-seats List seats\n"
1078 " seat-status NAME... Show seat status\n"
1079 " show-seat NAME... Show properties of one or more seats\n"
1080 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1081 " flush-devices Flush all device associations\n"
1082 " terminate-seat NAME... Terminate all sessions on one or more seats\n",
1083 program_invocation_short_name);
1088 static int parse_argv(int argc, char *argv[]) {
1091 ARG_VERSION = 0x100,
1095 ARG_NO_ASK_PASSWORD,
1098 static const struct option options[] = {
1099 { "help", no_argument, NULL, 'h' },
1100 { "version", no_argument, NULL, ARG_VERSION },
1101 { "property", required_argument, NULL, 'p' },
1102 { "all", no_argument, NULL, 'a' },
1103 { "full", no_argument, NULL, 'l' },
1104 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1105 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1106 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1107 { "signal", required_argument, NULL, 's' },
1108 { "host", required_argument, NULL, 'H' },
1109 { "machine", required_argument, NULL, 'M' },
1110 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1119 while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) {
1127 puts(PACKAGE_STRING);
1128 puts(SYSTEMD_FEATURES);
1132 r = strv_extend(&arg_property, optarg);
1136 /* If the user asked for a particular
1137 * property, show it to him, even if it is
1152 arg_no_pager = true;
1159 case ARG_NO_ASK_PASSWORD:
1160 arg_ask_password = false;
1164 arg_kill_who = optarg;
1168 arg_signal = signal_from_string_try_harder(optarg);
1169 if (arg_signal < 0) {
1170 log_error("Failed to parse signal string %s.", optarg);
1176 arg_transport = BUS_TRANSPORT_REMOTE;
1181 arg_transport = BUS_TRANSPORT_CONTAINER;
1189 assert_not_reached("Unhandled option");
1196 static int loginctl_main(sd_bus *bus, int argc, char *argv[]) {
1198 static const struct {
1206 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1208 { "list-sessions", LESS, 1, list_sessions },
1209 { "session-status", MORE, 2, show_session },
1210 { "show-session", MORE, 1, show_session },
1211 { "activate", EQUAL, 2, activate },
1212 { "lock-session", MORE, 2, activate },
1213 { "unlock-session", MORE, 2, activate },
1214 { "lock-sessions", EQUAL, 1, lock_sessions },
1215 { "unlock-sessions", EQUAL, 1, lock_sessions },
1216 { "terminate-session", MORE, 2, activate },
1217 { "kill-session", MORE, 2, kill_session },
1218 { "list-users", EQUAL, 1, list_users },
1219 { "user-status", MORE, 2, show_user },
1220 { "show-user", MORE, 1, show_user },
1221 { "enable-linger", MORE, 2, enable_linger },
1222 { "disable-linger", MORE, 2, enable_linger },
1223 { "terminate-user", MORE, 2, terminate_user },
1224 { "kill-user", MORE, 2, kill_user },
1225 { "list-seats", EQUAL, 1, list_seats },
1226 { "seat-status", MORE, 2, show_seat },
1227 { "show-seat", MORE, 1, show_seat },
1228 { "attach", MORE, 3, attach },
1229 { "flush-devices", EQUAL, 1, flush_devices },
1230 { "terminate-seat", MORE, 2, terminate_seat },
1239 left = argc - optind;
1242 /* Special rule: no arguments means "list-sessions" */
1245 if (streq(argv[optind], "help")) {
1250 for (i = 0; i < ELEMENTSOF(verbs); i++)
1251 if (streq(argv[optind], verbs[i].verb))
1254 if (i >= ELEMENTSOF(verbs)) {
1255 log_error("Unknown operation %s", argv[optind]);
1260 switch (verbs[i].argc_cmp) {
1263 if (left != verbs[i].argc) {
1264 log_error("Invalid number of arguments.");
1271 if (left < verbs[i].argc) {
1272 log_error("Too few arguments.");
1279 if (left > verbs[i].argc) {
1280 log_error("Too many arguments.");
1287 assert_not_reached("Unknown comparison operator.");
1290 return verbs[i].dispatch(bus, argv + optind, left);
1293 int main(int argc, char *argv[]) {
1294 _cleanup_bus_unref_ sd_bus *bus = NULL;
1297 setlocale(LC_ALL, "");
1298 log_parse_environment();
1301 r = parse_argv(argc, argv);
1305 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1307 log_error("Failed to create bus connection: %s", strerror(-r));
1311 r = loginctl_main(bus, argc, argv);
1316 strv_free(arg_property);
1318 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;