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 const char *arg_kill_who = NULL;
49 static int arg_signal = SIGTERM;
50 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
51 static bool arg_ask_password = true;
52 static char *arg_host = NULL;
54 static void pager_open_if_enabled(void) {
62 static void polkit_agent_open_if_enabled(void) {
64 /* Open the polkit agent as a child process if necessary */
66 if (!arg_ask_password)
69 if (arg_transport != BUS_TRANSPORT_LOCAL)
75 static int list_sessions(sd_bus *bus, char **args, unsigned n) {
76 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
77 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
78 const char *id, *user, *seat, *object;
83 pager_open_if_enabled();
85 r = sd_bus_call_method(
87 "org.freedesktop.login1",
88 "/org/freedesktop/login1",
89 "org.freedesktop.login1.Manager",
94 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
98 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
100 return bus_log_parse_error(r);
102 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
104 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
105 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
109 return bus_log_parse_error(r);
111 printf("\n%u sessions listed.\n", k);
116 static int list_users(sd_bus *bus, char **args, unsigned n) {
117 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
118 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
119 const char *user, *object;
124 pager_open_if_enabled();
126 r = sd_bus_call_method(
128 "org.freedesktop.login1",
129 "/org/freedesktop/login1",
130 "org.freedesktop.login1.Manager",
135 log_error("Failed to list users: %s", bus_error_message(&error, r));
139 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
141 return bus_log_parse_error(r);
143 printf("%10s %-16s\n", "UID", "USER");
145 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
146 printf("%10u %-16s\n", (unsigned) uid, user);
150 return bus_log_parse_error(r);
152 printf("\n%u users listed.\n", k);
157 static int list_seats(sd_bus *bus, char **args, unsigned n) {
158 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
159 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
160 const char *seat, *object;
164 pager_open_if_enabled();
166 r = sd_bus_call_method(
168 "org.freedesktop.login1",
169 "/org/freedesktop/login1",
170 "org.freedesktop.login1.Manager",
175 log_error("Failed to list seats: %s", bus_error_message(&error, r));
179 r = sd_bus_message_enter_container(reply, 'a', "(so)");
181 return bus_log_parse_error(r);
183 printf("%-16s\n", "SEAT");
185 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
186 printf("%-16s\n", seat);
190 return bus_log_parse_error(r);
192 printf("\n%u seats listed.\n", k);
197 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
198 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
199 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
200 _cleanup_free_ char *path = NULL;
208 if (arg_transport != BUS_TRANSPORT_LOCAL)
211 path = unit_dbus_path_from_name(unit);
215 r = sd_bus_get_property(
217 "org.freedesktop.systemd1",
221 &error, &reply, "s");
225 r = sd_bus_message_read(reply, "s", &cgroup);
232 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
236 arg_all * OUTPUT_SHOW_ALL |
237 arg_full * OUTPUT_FULL_WIDTH;
245 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, output_flags);
249 typedef struct SessionStatusInfo {
259 const char *remote_host;
260 const char *remote_user;
269 typedef struct UserStatusInfo {
279 typedef struct SeatStatusInfo {
281 const char *active_session;
285 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
286 const char *contents;
289 r = sd_bus_message_peek_type(m, NULL, &contents);
293 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
297 if (contents[0] == 's' || contents[0] == 'o') {
299 char **p = (char **) userdata;
301 r = sd_bus_message_read_basic(m, contents[0], &s);
311 r = sd_bus_message_read_basic(m, contents[0], userdata);
316 r = sd_bus_message_skip(m, contents+1);
320 r = sd_bus_message_exit_container(m);
327 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
334 r = sd_bus_message_enter_container(m, 'a', "(so)");
338 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
339 r = strv_extend(userdata, name);
346 return sd_bus_message_exit_container(m);
349 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
351 static const struct bus_properties_map map[] = {
352 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
353 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
354 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
355 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
356 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
357 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
358 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
359 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
360 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
361 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
362 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
363 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
364 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
365 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
366 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp) },
367 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
368 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, id) },
372 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
373 char since2[FORMAT_TIMESTAMP_MAX], *s2;
374 SessionStatusInfo i = {};
377 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
379 log_error("Could not get properties: %s", strerror(-r));
388 printf("%s - ", strna(i.id));
391 printf("%s (%u)\n", i.name, (unsigned) i.uid);
393 printf("%u\n", (unsigned) i.uid);
395 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
396 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
399 printf("\t Since: %s; %s\n", s2, s1);
401 printf("\t Since: %s\n", s2);
404 _cleanup_free_ char *t = NULL;
406 printf("\t Leader: %u", (unsigned) i.leader);
408 get_process_comm(i.leader, &t);
416 printf("\t Seat: %s", i.seat);
419 printf("; vc%i", i.vtnr);
425 printf("\t TTY: %s\n", i.tty);
427 printf("\t Display: %s\n", i.display);
429 if (i.remote_host && i.remote_user)
430 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
431 else if (i.remote_host)
432 printf("\t Remote: %s\n", i.remote_host);
433 else if (i.remote_user)
434 printf("\t Remote: user %s\n", i.remote_user);
436 printf("\t Remote: Yes\n");
439 printf("\t Service: %s", i.service);
442 printf("; type %s", i.type);
445 printf("; class %s", i.class);
449 printf("\t Type: %s\n", i.type);
452 printf("; class %s", i.class);
454 printf("\t Class: %s\n", i.class);
457 printf("\t State: %s\n", i.state);
460 printf("\t Unit: %s\n", i.scope);
461 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
467 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
469 static const struct bus_properties_map map[] = {
470 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
471 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
472 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
473 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
474 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp) },
475 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
476 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
480 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
481 char since2[FORMAT_TIMESTAMP_MAX], *s2;
482 UserStatusInfo i = {};
485 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
487 log_error("Could not get properties: %s", strerror(-r));
497 printf("%s (%u)\n", i.name, (unsigned) i.uid);
499 printf("%u\n", (unsigned) i.uid);
501 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
502 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
505 printf("\t Since: %s; %s\n", s2, s1);
507 printf("\t Since: %s\n", s2);
509 if (!isempty(i.state))
510 printf("\t State: %s\n", i.state);
512 if (!strv_isempty(i.sessions)) {
514 printf("\tSessions:");
516 STRV_FOREACH(l, i.sessions) {
517 if (streq_ptr(*l, i.display))
527 printf("\t Unit: %s\n", i.slice);
528 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
532 strv_free(i.sessions);
537 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
539 static const struct bus_properties_map map[] = {
540 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
541 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
542 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
546 SeatStatusInfo i = {};
549 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
551 log_error("Could not get properties: %s", strerror(-r));
560 printf("%s\n", strna(i.id));
562 if (!strv_isempty(i.sessions)) {
564 printf("\tSessions:");
566 STRV_FOREACH(l, i.sessions) {
567 if (streq_ptr(*l, i.active_session))
576 if (arg_transport == BUS_TRANSPORT_LOCAL) {
585 printf("\t Devices:\n");
587 show_sysfs(i.id, "\t\t ", c);
591 strv_free(i.sessions);
596 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
604 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
606 log_error("Could not get properties: %s", strerror(-r));
611 static int show_session(sd_bus *bus, char **args, unsigned n) {
612 bool properties, new_line = false;
619 properties = !strstr(args[0], "status");
621 pager_open_if_enabled();
623 if (properties && n <= 1) {
624 /* If not argument is specified inspect the manager
626 return show_properties(bus, "/org/freedesktop/login1", &new_line);
629 for (i = 1; i < n; i++) {
630 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
631 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
632 const char *path = NULL;
634 r = sd_bus_call_method(
636 "org.freedesktop.login1",
637 "/org/freedesktop/login1",
638 "org.freedesktop.login1.Manager",
643 log_error("Failed to get session: %s", bus_error_message(&error, r));
647 r = sd_bus_message_read(reply, "o", &path);
649 return bus_log_parse_error(r);
652 r = show_properties(bus, path, &new_line);
654 r = print_session_status_info(bus, path, &new_line);
663 static int show_user(sd_bus *bus, char **args, unsigned n) {
664 bool properties, new_line = false;
671 properties = !strstr(args[0], "status");
673 pager_open_if_enabled();
675 if (properties && n <= 1) {
676 /* If not argument is specified inspect the manager
678 return show_properties(bus, "/org/freedesktop/login1", &new_line);
681 for (i = 1; i < n; i++) {
682 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
683 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
684 const char *path = NULL;
687 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
689 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
693 r = sd_bus_call_method(
695 "org.freedesktop.login1",
696 "/org/freedesktop/login1",
697 "org.freedesktop.login1.Manager",
700 "u", (uint32_t) uid);
702 log_error("Failed to get user: %s", bus_error_message(&error, r));
706 r = sd_bus_message_read(reply, "o", &path);
708 return bus_log_parse_error(r);
711 r = show_properties(bus, path, &new_line);
713 r = print_user_status_info(bus, path, &new_line);
722 static int show_seat(sd_bus *bus, char **args, unsigned n) {
723 bool properties, new_line = false;
730 properties = !strstr(args[0], "status");
732 pager_open_if_enabled();
734 if (properties && n <= 1) {
735 /* If not argument is specified inspect the manager
737 return show_properties(bus, "/org/freedesktop/login1", &new_line);
740 for (i = 1; i < n; i++) {
741 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
742 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
743 const char *path = NULL;
745 r = sd_bus_call_method(
747 "org.freedesktop.login1",
748 "/org/freedesktop/login1",
749 "org.freedesktop.login1.Manager",
754 log_error("Failed to get seat: %s", bus_error_message(&error, r));
758 r = sd_bus_message_read(reply, "o", &path);
760 return bus_log_parse_error(r);
763 r = show_properties(bus, path, &new_line);
765 r = print_seat_status_info(bus, path, &new_line);
774 static int activate(sd_bus *bus, char **args, unsigned n) {
775 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
781 for (i = 1; i < n; i++) {
783 r = sd_bus_call_method (
785 "org.freedesktop.login1",
786 "/org/freedesktop/login1",
787 "org.freedesktop.login1.Manager",
788 streq(args[0], "lock-session") ? "LockSession" :
789 streq(args[0], "unlock-session") ? "UnlockSession" :
790 streq(args[0], "terminate-session") ? "TerminateSession" :
795 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
803 static int kill_session(sd_bus *bus, char **args, unsigned n) {
804 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
811 arg_kill_who = "all";
813 for (i = 1; i < n; i++) {
815 r = sd_bus_call_method (
817 "org.freedesktop.login1",
818 "/org/freedesktop/login1",
819 "org.freedesktop.login1.Manager",
822 "ssi", args[i], arg_kill_who, arg_signal);
824 log_error("Could not kill session: %s", bus_error_message(&error, -r));
832 static int enable_linger(sd_bus *bus, char **args, unsigned n) {
833 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
840 polkit_agent_open_if_enabled();
842 b = streq(args[0], "enable-linger");
844 for (i = 1; i < n; i++) {
847 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
849 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
853 r = sd_bus_call_method (
855 "org.freedesktop.login1",
856 "/org/freedesktop/login1",
857 "org.freedesktop.login1.Manager",
860 "ubb", (uint32_t) uid, b, true);
862 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
870 static int terminate_user(sd_bus *bus, char **args, unsigned n) {
871 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
877 for (i = 1; i < n; i++) {
880 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
882 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
886 r = sd_bus_call_method (
888 "org.freedesktop.login1",
889 "/org/freedesktop/login1",
890 "org.freedesktop.login1.Manager",
893 "u", (uint32_t) uid);
895 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
903 static int kill_user(sd_bus *bus, char **args, unsigned n) {
904 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
911 arg_kill_who = "all";
913 for (i = 1; i < n; i++) {
916 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
918 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
922 r = sd_bus_call_method (
924 "org.freedesktop.login1",
925 "/org/freedesktop/login1",
926 "org.freedesktop.login1.Manager",
929 "ui", (uint32_t) uid, arg_signal);
931 log_error("Could not kill user: %s", bus_error_message(&error, -r));
939 static int attach(sd_bus *bus, char **args, unsigned n) {
940 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
946 polkit_agent_open_if_enabled();
948 for (i = 2; i < n; i++) {
950 r = sd_bus_call_method (
952 "org.freedesktop.login1",
953 "/org/freedesktop/login1",
954 "org.freedesktop.login1.Manager",
957 "ssb", args[1], args[i], true);
960 log_error("Could not attach device: %s", bus_error_message(&error, -r));
968 static int flush_devices(sd_bus *bus, char **args, unsigned n) {
969 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
974 polkit_agent_open_if_enabled();
976 r = sd_bus_call_method (
978 "org.freedesktop.login1",
979 "/org/freedesktop/login1",
980 "org.freedesktop.login1.Manager",
985 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
990 static int lock_sessions(sd_bus *bus, char **args, unsigned n) {
991 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
996 r = sd_bus_call_method (
998 "org.freedesktop.login1",
999 "/org/freedesktop/login1",
1000 "org.freedesktop.login1.Manager",
1001 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1005 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1010 static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
1011 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1017 for (i = 1; i < n; i++) {
1019 r = sd_bus_call_method (
1021 "org.freedesktop.login1",
1022 "/org/freedesktop/login1",
1023 "org.freedesktop.login1.Manager",
1028 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1036 static int help(void) {
1038 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1039 "Send control commands to or query the login manager.\n\n"
1040 " -h --help Show this help\n"
1041 " --version Show package version\n"
1042 " --no-pager Do not pipe output into a pager\n"
1043 " --no-ask-password Don't prompt for password\n"
1044 " -H --host=[USER@]HOST Operate on remote host\n"
1045 " -M --machine=CONTAINER Operate on local container\n"
1046 " -p --property=NAME Show only properties by this name\n"
1047 " -a --all Show all properties, including empty ones\n"
1048 " -l --full Do not ellipsize output\n"
1049 " --kill-who=WHO Who to send signal to\n"
1050 " -s --signal=SIGNAL Which signal to send\n\n"
1052 " list-sessions List sessions\n"
1053 " session-status ID... Show session status\n"
1054 " show-session [ID...] Show properties of sessions or the manager\n"
1055 " activate ID Activate a session\n"
1056 " lock-session ID... Screen lock one or more sessions\n"
1057 " unlock-session ID... Screen unlock one or more sessions\n"
1058 " lock-sessions Screen lock all current sessions\n"
1059 " unlock-sessions Screen unlock all current sessions\n"
1060 " terminate-session ID... Terminate one or more sessions\n"
1061 " kill-session ID... Send signal to processes of a session\n"
1062 " list-users List users\n"
1063 " user-status USER... Show user status\n"
1064 " show-user [USER...] Show properties of users or the manager\n"
1065 " enable-linger USER... Enable linger state of one or more users\n"
1066 " disable-linger USER... Disable linger state of one or more users\n"
1067 " terminate-user USER... Terminate all sessions of one or more users\n"
1068 " kill-user USER... Send signal to processes of a user\n"
1069 " list-seats List seats\n"
1070 " seat-status NAME... Show seat status\n"
1071 " show-seat NAME... Show properties of one or more seats\n"
1072 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1073 " flush-devices Flush all device associations\n"
1074 " terminate-seat NAME... Terminate all sessions on one or more seats\n",
1075 program_invocation_short_name);
1080 static int parse_argv(int argc, char *argv[]) {
1083 ARG_VERSION = 0x100,
1086 ARG_NO_ASK_PASSWORD,
1089 static const struct option options[] = {
1090 { "help", no_argument, NULL, 'h' },
1091 { "version", no_argument, NULL, ARG_VERSION },
1092 { "property", required_argument, NULL, 'p' },
1093 { "all", no_argument, NULL, 'a' },
1094 { "full", no_argument, NULL, 'l' },
1095 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1096 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1097 { "signal", required_argument, NULL, 's' },
1098 { "host", required_argument, NULL, 'H' },
1099 { "machine", required_argument, NULL, 'M' },
1100 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1109 while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) {
1117 puts(PACKAGE_STRING);
1118 puts(SYSTEMD_FEATURES);
1122 r = strv_extend(&arg_property, optarg);
1126 /* If the user asked for a particular
1127 * property, show it to him, even if it is
1142 arg_no_pager = true;
1145 case ARG_NO_ASK_PASSWORD:
1146 arg_ask_password = false;
1150 arg_kill_who = optarg;
1154 arg_signal = signal_from_string_try_harder(optarg);
1155 if (arg_signal < 0) {
1156 log_error("Failed to parse signal string %s.", optarg);
1162 arg_transport = BUS_TRANSPORT_REMOTE;
1167 arg_transport = BUS_TRANSPORT_CONTAINER;
1175 assert_not_reached("Unhandled option");
1182 static int loginctl_main(sd_bus *bus, int argc, char *argv[]) {
1184 static const struct {
1192 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1194 { "list-sessions", LESS, 1, list_sessions },
1195 { "session-status", MORE, 2, show_session },
1196 { "show-session", MORE, 1, show_session },
1197 { "activate", EQUAL, 2, activate },
1198 { "lock-session", MORE, 2, activate },
1199 { "unlock-session", MORE, 2, activate },
1200 { "lock-sessions", EQUAL, 1, lock_sessions },
1201 { "unlock-sessions", EQUAL, 1, lock_sessions },
1202 { "terminate-session", MORE, 2, activate },
1203 { "kill-session", MORE, 2, kill_session },
1204 { "list-users", EQUAL, 1, list_users },
1205 { "user-status", MORE, 2, show_user },
1206 { "show-user", MORE, 1, show_user },
1207 { "enable-linger", MORE, 2, enable_linger },
1208 { "disable-linger", MORE, 2, enable_linger },
1209 { "terminate-user", MORE, 2, terminate_user },
1210 { "kill-user", MORE, 2, kill_user },
1211 { "list-seats", EQUAL, 1, list_seats },
1212 { "seat-status", MORE, 2, show_seat },
1213 { "show-seat", MORE, 1, show_seat },
1214 { "attach", MORE, 3, attach },
1215 { "flush-devices", EQUAL, 1, flush_devices },
1216 { "terminate-seat", MORE, 2, terminate_seat },
1225 left = argc - optind;
1228 /* Special rule: no arguments means "list-sessions" */
1231 if (streq(argv[optind], "help")) {
1236 for (i = 0; i < ELEMENTSOF(verbs); i++)
1237 if (streq(argv[optind], verbs[i].verb))
1240 if (i >= ELEMENTSOF(verbs)) {
1241 log_error("Unknown operation %s", argv[optind]);
1246 switch (verbs[i].argc_cmp) {
1249 if (left != verbs[i].argc) {
1250 log_error("Invalid number of arguments.");
1257 if (left < verbs[i].argc) {
1258 log_error("Too few arguments.");
1265 if (left > verbs[i].argc) {
1266 log_error("Too many arguments.");
1273 assert_not_reached("Unknown comparison operator.");
1276 return verbs[i].dispatch(bus, argv + optind, left);
1279 int main(int argc, char *argv[]) {
1280 _cleanup_bus_unref_ sd_bus *bus = NULL;
1283 setlocale(LC_ALL, "");
1284 log_parse_environment();
1287 r = parse_argv(argc, argv);
1291 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1293 log_error("Failed to create bus connection: %s", strerror(-r));
1297 r = loginctl_main(bus, argc, argv);
1302 strv_free(arg_property);
1304 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;