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;
277 typedef struct UserStatusInfo {
287 typedef struct SeatStatusInfo {
289 const char *active_session;
293 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
294 const char *contents;
297 r = sd_bus_message_peek_type(m, NULL, &contents);
301 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
305 if (contents[0] == 's' || contents[0] == 'o') {
307 char **p = (char **) userdata;
309 r = sd_bus_message_read_basic(m, contents[0], &s);
319 r = sd_bus_message_read_basic(m, contents[0], userdata);
324 r = sd_bus_message_skip(m, contents+1);
328 r = sd_bus_message_exit_container(m);
335 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
342 r = sd_bus_message_enter_container(m, 'a', "(so)");
346 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
347 r = strv_extend(userdata, name);
354 return sd_bus_message_exit_container(m);
357 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
359 static const struct bus_properties_map map[] = {
360 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
361 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
362 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
363 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
364 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
365 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
366 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
367 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
368 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
369 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
370 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
371 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
372 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
373 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
374 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
375 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp) },
376 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
377 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
381 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
382 char since2[FORMAT_TIMESTAMP_MAX], *s2;
383 SessionStatusInfo i = {};
386 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
388 log_error("Could not get properties: %s", strerror(-r));
397 printf("%s - ", strna(i.id));
400 printf("%s (%u)\n", i.name, (unsigned) i.uid);
402 printf("%u\n", (unsigned) i.uid);
404 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
405 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
408 printf("\t Since: %s; %s\n", s2, s1);
410 printf("\t Since: %s\n", s2);
413 _cleanup_free_ char *t = NULL;
415 printf("\t Leader: %u", (unsigned) i.leader);
417 get_process_comm(i.leader, &t);
424 if (!isempty(i.seat)) {
425 printf("\t Seat: %s", i.seat);
428 printf("; vc%i", i.vtnr);
434 printf("\t TTY: %s\n", i.tty);
436 printf("\t Display: %s\n", i.display);
438 if (i.remote_host && i.remote_user)
439 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
440 else if (i.remote_host)
441 printf("\t Remote: %s\n", i.remote_host);
442 else if (i.remote_user)
443 printf("\t Remote: user %s\n", i.remote_user);
445 printf("\t Remote: Yes\n");
448 printf("\t Service: %s", i.service);
451 printf("; type %s", i.type);
454 printf("; class %s", i.class);
458 printf("\t Type: %s", i.type);
461 printf("; class %s", i.class);
465 printf("\t Class: %s\n", i.class);
467 if (!isempty(i.desktop))
468 printf("\t Desktop: %s\n", i.desktop);
471 printf("\t State: %s\n", i.state);
474 printf("\t Unit: %s\n", i.scope);
475 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
481 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
483 static const struct bus_properties_map map[] = {
484 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
485 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
486 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
487 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
488 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp) },
489 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
490 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
494 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
495 char since2[FORMAT_TIMESTAMP_MAX], *s2;
496 UserStatusInfo i = {};
499 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
501 log_error("Could not get properties: %s", strerror(-r));
511 printf("%s (%u)\n", i.name, (unsigned) i.uid);
513 printf("%u\n", (unsigned) i.uid);
515 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
516 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
519 printf("\t Since: %s; %s\n", s2, s1);
521 printf("\t Since: %s\n", s2);
523 if (!isempty(i.state))
524 printf("\t State: %s\n", i.state);
526 if (!strv_isempty(i.sessions)) {
528 printf("\tSessions:");
530 STRV_FOREACH(l, i.sessions) {
531 if (streq_ptr(*l, i.display))
541 printf("\t Unit: %s\n", i.slice);
542 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
546 strv_free(i.sessions);
551 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
553 static const struct bus_properties_map map[] = {
554 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
555 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
556 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
560 SeatStatusInfo i = {};
563 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
565 log_error("Could not get properties: %s", strerror(-r));
574 printf("%s\n", strna(i.id));
576 if (!strv_isempty(i.sessions)) {
578 printf("\tSessions:");
580 STRV_FOREACH(l, i.sessions) {
581 if (streq_ptr(*l, i.active_session))
590 if (arg_transport == BUS_TRANSPORT_LOCAL) {
599 printf("\t Devices:\n");
601 show_sysfs(i.id, "\t\t ", c);
605 strv_free(i.sessions);
610 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
618 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
620 log_error("Could not get properties: %s", strerror(-r));
625 static int show_session(sd_bus *bus, char **args, unsigned n) {
626 bool properties, new_line = false;
633 properties = !strstr(args[0], "status");
635 pager_open_if_enabled();
637 if (properties && n <= 1) {
638 /* If not argument is specified inspect the manager
640 return show_properties(bus, "/org/freedesktop/login1", &new_line);
643 for (i = 1; i < n; i++) {
644 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
645 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
646 const char *path = NULL;
648 r = sd_bus_call_method(
650 "org.freedesktop.login1",
651 "/org/freedesktop/login1",
652 "org.freedesktop.login1.Manager",
657 log_error("Failed to get session: %s", bus_error_message(&error, r));
661 r = sd_bus_message_read(reply, "o", &path);
663 return bus_log_parse_error(r);
666 r = show_properties(bus, path, &new_line);
668 r = print_session_status_info(bus, path, &new_line);
677 static int show_user(sd_bus *bus, char **args, unsigned n) {
678 bool properties, new_line = false;
685 properties = !strstr(args[0], "status");
687 pager_open_if_enabled();
689 if (properties && n <= 1) {
690 /* If not argument is specified inspect the manager
692 return show_properties(bus, "/org/freedesktop/login1", &new_line);
695 for (i = 1; i < n; i++) {
696 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
697 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
698 const char *path = NULL;
701 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
703 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
707 r = sd_bus_call_method(
709 "org.freedesktop.login1",
710 "/org/freedesktop/login1",
711 "org.freedesktop.login1.Manager",
714 "u", (uint32_t) uid);
716 log_error("Failed to get user: %s", bus_error_message(&error, r));
720 r = sd_bus_message_read(reply, "o", &path);
722 return bus_log_parse_error(r);
725 r = show_properties(bus, path, &new_line);
727 r = print_user_status_info(bus, path, &new_line);
736 static int show_seat(sd_bus *bus, char **args, unsigned n) {
737 bool properties, new_line = false;
744 properties = !strstr(args[0], "status");
746 pager_open_if_enabled();
748 if (properties && n <= 1) {
749 /* If not argument is specified inspect the manager
751 return show_properties(bus, "/org/freedesktop/login1", &new_line);
754 for (i = 1; i < n; i++) {
755 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
756 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
757 const char *path = NULL;
759 r = sd_bus_call_method(
761 "org.freedesktop.login1",
762 "/org/freedesktop/login1",
763 "org.freedesktop.login1.Manager",
768 log_error("Failed to get seat: %s", bus_error_message(&error, r));
772 r = sd_bus_message_read(reply, "o", &path);
774 return bus_log_parse_error(r);
777 r = show_properties(bus, path, &new_line);
779 r = print_seat_status_info(bus, path, &new_line);
788 static int activate(sd_bus *bus, char **args, unsigned n) {
789 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
795 for (i = 1; i < n; i++) {
797 r = sd_bus_call_method (
799 "org.freedesktop.login1",
800 "/org/freedesktop/login1",
801 "org.freedesktop.login1.Manager",
802 streq(args[0], "lock-session") ? "LockSession" :
803 streq(args[0], "unlock-session") ? "UnlockSession" :
804 streq(args[0], "terminate-session") ? "TerminateSession" :
809 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
817 static int kill_session(sd_bus *bus, char **args, unsigned n) {
818 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
825 arg_kill_who = "all";
827 for (i = 1; i < n; i++) {
829 r = sd_bus_call_method (
831 "org.freedesktop.login1",
832 "/org/freedesktop/login1",
833 "org.freedesktop.login1.Manager",
836 "ssi", args[i], arg_kill_who, arg_signal);
838 log_error("Could not kill session: %s", bus_error_message(&error, -r));
846 static int enable_linger(sd_bus *bus, char **args, unsigned n) {
847 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
854 polkit_agent_open_if_enabled();
856 b = streq(args[0], "enable-linger");
858 for (i = 1; i < n; i++) {
861 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
863 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
867 r = sd_bus_call_method (
869 "org.freedesktop.login1",
870 "/org/freedesktop/login1",
871 "org.freedesktop.login1.Manager",
874 "ubb", (uint32_t) uid, b, true);
876 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
884 static int terminate_user(sd_bus *bus, char **args, unsigned n) {
885 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
891 for (i = 1; i < n; i++) {
894 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
896 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
900 r = sd_bus_call_method (
902 "org.freedesktop.login1",
903 "/org/freedesktop/login1",
904 "org.freedesktop.login1.Manager",
907 "u", (uint32_t) uid);
909 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
917 static int kill_user(sd_bus *bus, char **args, unsigned n) {
918 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
925 arg_kill_who = "all";
927 for (i = 1; i < n; i++) {
930 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
932 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
936 r = sd_bus_call_method (
938 "org.freedesktop.login1",
939 "/org/freedesktop/login1",
940 "org.freedesktop.login1.Manager",
943 "ui", (uint32_t) uid, arg_signal);
945 log_error("Could not kill user: %s", bus_error_message(&error, -r));
953 static int attach(sd_bus *bus, char **args, unsigned n) {
954 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
960 polkit_agent_open_if_enabled();
962 for (i = 2; i < n; i++) {
964 r = sd_bus_call_method (
966 "org.freedesktop.login1",
967 "/org/freedesktop/login1",
968 "org.freedesktop.login1.Manager",
971 "ssb", args[1], args[i], true);
974 log_error("Could not attach device: %s", bus_error_message(&error, -r));
982 static int flush_devices(sd_bus *bus, char **args, unsigned n) {
983 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
988 polkit_agent_open_if_enabled();
990 r = sd_bus_call_method (
992 "org.freedesktop.login1",
993 "/org/freedesktop/login1",
994 "org.freedesktop.login1.Manager",
999 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1004 static int lock_sessions(sd_bus *bus, char **args, unsigned n) {
1005 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1010 r = sd_bus_call_method (
1012 "org.freedesktop.login1",
1013 "/org/freedesktop/login1",
1014 "org.freedesktop.login1.Manager",
1015 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1019 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1024 static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
1025 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1031 for (i = 1; i < n; i++) {
1033 r = sd_bus_call_method (
1035 "org.freedesktop.login1",
1036 "/org/freedesktop/login1",
1037 "org.freedesktop.login1.Manager",
1042 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1050 static int help(void) {
1052 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1053 "Send control commands to or query the login manager.\n\n"
1054 " -h --help Show this help\n"
1055 " --version Show package version\n"
1056 " --no-pager Do not pipe output into a pager\n"
1057 " --no-legend Do not show the headers and footers\n"
1058 " --no-ask-password Don't prompt for password\n"
1059 " -H --host=[USER@]HOST Operate on remote host\n"
1060 " -M --machine=CONTAINER Operate on local container\n"
1061 " -p --property=NAME Show only properties by this name\n"
1062 " -a --all Show all properties, including empty ones\n"
1063 " -l --full Do not ellipsize output\n"
1064 " --kill-who=WHO Who to send signal to\n"
1065 " -s --signal=SIGNAL Which signal to send\n\n"
1067 " list-sessions List sessions\n"
1068 " session-status ID... Show session status\n"
1069 " show-session [ID...] Show properties of sessions or the manager\n"
1070 " activate ID Activate a session\n"
1071 " lock-session ID... Screen lock one or more sessions\n"
1072 " unlock-session ID... Screen unlock one or more sessions\n"
1073 " lock-sessions Screen lock all current sessions\n"
1074 " unlock-sessions Screen unlock all current sessions\n"
1075 " terminate-session ID... Terminate one or more sessions\n"
1076 " kill-session ID... Send signal to processes of a session\n"
1077 " list-users List users\n"
1078 " user-status USER... Show user status\n"
1079 " show-user [USER...] Show properties of users or the manager\n"
1080 " enable-linger USER... Enable linger state of one or more users\n"
1081 " disable-linger USER... Disable linger state of one or more users\n"
1082 " terminate-user USER... Terminate all sessions of one or more users\n"
1083 " kill-user USER... Send signal to processes of a user\n"
1084 " list-seats List seats\n"
1085 " seat-status NAME... Show seat status\n"
1086 " show-seat NAME... Show properties of one or more seats\n"
1087 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1088 " flush-devices Flush all device associations\n"
1089 " terminate-seat NAME... Terminate all sessions on one or more seats\n",
1090 program_invocation_short_name);
1095 static int parse_argv(int argc, char *argv[]) {
1098 ARG_VERSION = 0x100,
1102 ARG_NO_ASK_PASSWORD,
1105 static const struct option options[] = {
1106 { "help", no_argument, NULL, 'h' },
1107 { "version", no_argument, NULL, ARG_VERSION },
1108 { "property", required_argument, NULL, 'p' },
1109 { "all", no_argument, NULL, 'a' },
1110 { "full", no_argument, NULL, 'l' },
1111 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1112 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1113 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1114 { "signal", required_argument, NULL, 's' },
1115 { "host", required_argument, NULL, 'H' },
1116 { "machine", required_argument, NULL, 'M' },
1117 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1126 while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) {
1134 puts(PACKAGE_STRING);
1135 puts(SYSTEMD_FEATURES);
1139 r = strv_extend(&arg_property, optarg);
1143 /* If the user asked for a particular
1144 * property, show it to him, even if it is
1159 arg_no_pager = true;
1166 case ARG_NO_ASK_PASSWORD:
1167 arg_ask_password = false;
1171 arg_kill_who = optarg;
1175 arg_signal = signal_from_string_try_harder(optarg);
1176 if (arg_signal < 0) {
1177 log_error("Failed to parse signal string %s.", optarg);
1183 arg_transport = BUS_TRANSPORT_REMOTE;
1188 arg_transport = BUS_TRANSPORT_CONTAINER;
1196 assert_not_reached("Unhandled option");
1203 static int loginctl_main(sd_bus *bus, int argc, char *argv[]) {
1205 static const struct {
1213 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1215 { "list-sessions", LESS, 1, list_sessions },
1216 { "session-status", MORE, 2, show_session },
1217 { "show-session", MORE, 1, show_session },
1218 { "activate", EQUAL, 2, activate },
1219 { "lock-session", MORE, 2, activate },
1220 { "unlock-session", MORE, 2, activate },
1221 { "lock-sessions", EQUAL, 1, lock_sessions },
1222 { "unlock-sessions", EQUAL, 1, lock_sessions },
1223 { "terminate-session", MORE, 2, activate },
1224 { "kill-session", MORE, 2, kill_session },
1225 { "list-users", EQUAL, 1, list_users },
1226 { "user-status", MORE, 2, show_user },
1227 { "show-user", MORE, 1, show_user },
1228 { "enable-linger", MORE, 2, enable_linger },
1229 { "disable-linger", MORE, 2, enable_linger },
1230 { "terminate-user", MORE, 2, terminate_user },
1231 { "kill-user", MORE, 2, kill_user },
1232 { "list-seats", EQUAL, 1, list_seats },
1233 { "seat-status", MORE, 2, show_seat },
1234 { "show-seat", MORE, 1, show_seat },
1235 { "attach", MORE, 3, attach },
1236 { "flush-devices", EQUAL, 1, flush_devices },
1237 { "terminate-seat", MORE, 2, terminate_seat },
1246 left = argc - optind;
1249 /* Special rule: no arguments means "list-sessions" */
1252 if (streq(argv[optind], "help")) {
1257 for (i = 0; i < ELEMENTSOF(verbs); i++)
1258 if (streq(argv[optind], verbs[i].verb))
1261 if (i >= ELEMENTSOF(verbs)) {
1262 log_error("Unknown operation %s", argv[optind]);
1267 switch (verbs[i].argc_cmp) {
1270 if (left != verbs[i].argc) {
1271 log_error("Invalid number of arguments.");
1278 if (left < verbs[i].argc) {
1279 log_error("Too few arguments.");
1286 if (left > verbs[i].argc) {
1287 log_error("Too many arguments.");
1294 assert_not_reached("Unknown comparison operator.");
1297 return verbs[i].dispatch(bus, argv + optind, left);
1300 int main(int argc, char *argv[]) {
1301 _cleanup_bus_unref_ sd_bus *bus = NULL;
1304 setlocale(LC_ALL, "");
1305 log_parse_environment();
1308 r = parse_argv(argc, argv);
1312 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1314 log_error("Failed to create bus connection: %s", strerror(-r));
1318 r = loginctl_main(bus, argc, argv);
1323 strv_free(arg_property);
1325 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;