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 log_parse_error(int r) {
76 log_error("Failed to parse message: %s", strerror(-r));
80 static int list_sessions(sd_bus *bus, char **args, unsigned n) {
81 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
82 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
83 const char *id, *user, *seat, *object;
88 pager_open_if_enabled();
90 r = sd_bus_call_method(
92 "org.freedesktop.login1",
93 "/org/freedesktop/login1",
94 "org.freedesktop.login1.Manager",
99 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
103 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
105 return log_parse_error(r);
107 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
109 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
110 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
114 return log_parse_error(r);
116 printf("\n%u sessions listed.\n", k);
121 static int list_users(sd_bus *bus, char **args, unsigned n) {
122 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
123 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
124 const char *user, *object;
129 pager_open_if_enabled();
131 r = sd_bus_call_method(
133 "org.freedesktop.login1",
134 "/org/freedesktop/login1",
135 "org.freedesktop.login1.Manager",
140 log_error("Failed to list users: %s", bus_error_message(&error, r));
144 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
146 return log_parse_error(r);
148 printf("%10s %-16s\n", "UID", "USER");
150 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
151 printf("%10u %-16s\n", (unsigned) uid, user);
155 return 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 log_parse_error(r);
188 printf("%-16s\n", "SEAT");
190 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
191 printf("%-16s\n", seat);
195 return log_parse_error(r);
197 printf("\n%u seats listed.\n", k);
202 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
203 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
204 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
205 _cleanup_free_ char *path = NULL;
213 if (arg_transport != BUS_TRANSPORT_LOCAL)
216 path = unit_dbus_path_from_name(unit);
220 r = sd_bus_get_property(
222 "org.freedesktop.systemd1",
226 &error, &reply, "s");
230 r = sd_bus_message_read(reply, "s", &cgroup);
237 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
241 arg_all * OUTPUT_SHOW_ALL |
242 arg_full * OUTPUT_FULL_WIDTH;
250 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, output_flags);
254 typedef struct SessionStatusInfo {
264 const char *remote_host;
265 const char *remote_user;
274 typedef struct UserStatusInfo {
284 typedef struct SeatStatusInfo {
286 const char *active_session;
290 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
291 const char *contents;
294 r = sd_bus_message_peek_type(m, NULL, &contents);
298 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
302 if (contents[0] == 's' || contents[0] == 'o') {
304 char **p = (char **) userdata;
306 r = sd_bus_message_read_basic(m, contents[0], &s);
316 r = sd_bus_message_read_basic(m, contents[0], userdata);
321 r = sd_bus_message_skip(m, contents+1);
325 r = sd_bus_message_exit_container(m);
332 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
339 r = sd_bus_message_enter_container(m, 'a', "(so)");
343 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
344 r = strv_extend(userdata, name);
351 return sd_bus_message_exit_container(m);
354 static int print_session_status_info(sd_bus *bus, const char *path) {
356 static const struct bus_properties_map map[] = {
357 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
358 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
359 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
360 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
361 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
362 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
363 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
364 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
365 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
366 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
367 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
368 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
369 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
370 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
371 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp) },
372 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
373 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, id) },
377 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
378 char since2[FORMAT_TIMESTAMP_MAX], *s2;
379 SessionStatusInfo i = {};
382 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
386 printf("%s - ", strna(i.id));
389 printf("%s (%u)\n", i.name, (unsigned) i.uid);
391 printf("%u\n", (unsigned) i.uid);
393 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
394 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
397 printf("\t Since: %s; %s\n", s2, s1);
399 printf("\t Since: %s\n", s2);
402 _cleanup_free_ char *t = NULL;
404 printf("\t Leader: %u", (unsigned) i.leader);
406 get_process_comm(i.leader, &t);
414 printf("\t Seat: %s", i.seat);
417 printf("; vc%i", i.vtnr);
423 printf("\t TTY: %s\n", i.tty);
425 printf("\t Display: %s\n", i.display);
427 if (i.remote_host && i.remote_user)
428 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
429 else if (i.remote_host)
430 printf("\t Remote: %s\n", i.remote_host);
431 else if (i.remote_user)
432 printf("\t Remote: user %s\n", i.remote_user);
434 printf("\t Remote: Yes\n");
437 printf("\t Service: %s", i.service);
440 printf("; type %s", i.type);
443 printf("; class %s", i.class);
447 printf("\t Type: %s\n", i.type);
450 printf("; class %s", i.class);
452 printf("\t Class: %s\n", i.class);
455 printf("\t State: %s\n", i.state);
458 printf("\t Unit: %s\n", i.scope);
459 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
465 static int print_user_status_info(sd_bus *bus, const char *path) {
467 static const struct bus_properties_map map[] = {
468 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
469 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
470 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
471 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
472 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp) },
473 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
474 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
478 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
479 char since2[FORMAT_TIMESTAMP_MAX], *s2;
480 UserStatusInfo i = {};
483 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
488 printf("%s (%u)\n", i.name, (unsigned) i.uid);
490 printf("%u\n", (unsigned) i.uid);
492 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
493 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
496 printf("\t Since: %s; %s\n", s2, s1);
498 printf("\t Since: %s\n", s2);
500 if (!isempty(i.state))
501 printf("\t State: %s\n", i.state);
503 if (!strv_isempty(i.sessions)) {
505 printf("\tSessions:");
507 STRV_FOREACH(l, i.sessions) {
508 if (streq_ptr(*l, i.display))
518 printf("\t Unit: %s\n", i.slice);
519 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
523 strv_free(i.sessions);
528 static int print_seat_status_info(sd_bus *bus, const char *path) {
530 static const struct bus_properties_map map[] = {
531 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
532 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
533 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
537 SeatStatusInfo i = {};
540 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
544 printf("%s\n", strna(i.id));
546 if (!strv_isempty(i.sessions)) {
548 printf("\tSessions:");
550 STRV_FOREACH(l, i.sessions) {
551 if (streq_ptr(*l, i.active_session))
560 if (arg_transport == BUS_TRANSPORT_LOCAL) {
569 printf("\t Devices:\n");
571 show_sysfs(i.id, "\t\t ", c);
575 strv_free(i.sessions);
580 static int show_session(sd_bus *bus, char **args, unsigned n) {
581 bool show_properties;
588 show_properties = !strstr(args[0], "status");
590 pager_open_if_enabled();
592 if (show_properties && n <= 1) {
593 /* If not argument is specified inspect the manager
595 r = bus_print_all_properties(bus, "org.freedesktop.login1", "/org/freedesktop/login1", NULL, arg_all);
597 log_error("Failed to query login manager.");
602 for (i = 1; i < n; i++) {
603 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
604 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
605 const char *path = NULL;
610 r = sd_bus_call_method(
612 "org.freedesktop.login1",
613 "/org/freedesktop/login1",
614 "org.freedesktop.login1.Manager",
619 log_error("Failed to get session: %s", bus_error_message(&error, r));
623 r = sd_bus_message_read(reply, "o", &path);
625 return log_parse_error(r);
628 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, NULL, arg_all);
630 r = print_session_status_info(bus, path);
632 log_error("Failed to query session: %s", strerror(-r));
640 static int show_user(sd_bus *bus, char **args, unsigned n) {
641 bool show_properties;
648 show_properties = !strstr(args[0], "status");
650 pager_open_if_enabled();
652 if (show_properties && n <= 1) {
653 /* If not argument is specified inspect the manager
655 r = bus_print_all_properties(bus, "org.freedesktop.login1", "/org/freedesktop/login1", NULL, arg_all);
657 log_error("Failed to query login manager.");
662 for (i = 1; i < n; i++) {
663 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
664 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
665 const char *path = NULL;
671 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
673 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
677 r = sd_bus_call_method(
679 "org.freedesktop.login1",
680 "/org/freedesktop/login1",
681 "org.freedesktop.login1.Manager",
684 "u", (uint32_t) uid);
686 log_error("Failed to get user: %s", bus_error_message(&error, r));
690 r = sd_bus_message_read(reply, "o", &path);
692 return log_parse_error(r);
695 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, NULL, arg_all);
697 r = print_user_status_info(bus, path);
699 log_error("Failed to query user: %s", strerror(-r));
707 static int show_seat(sd_bus *bus, char **args, unsigned n) {
708 bool show_properties;
715 show_properties = !strstr(args[0], "status");
717 pager_open_if_enabled();
719 if (show_properties && n <= 1) {
720 /* If not argument is specified inspect the manager
722 r = bus_print_all_properties(bus, "org.freedesktop.login1", "/org/freedesktop/login1", NULL, arg_all);
724 log_error("Failed to query login manager.");
729 for (i = 1; i < n; i++) {
730 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
731 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
732 const char *path = NULL;
737 r = sd_bus_call_method(
739 "org.freedesktop.login1",
740 "/org/freedesktop/login1",
741 "org.freedesktop.login1.Manager",
746 log_error("Failed to get seat: %s", bus_error_message(&error, r));
750 r = sd_bus_message_read(reply, "o", &path);
752 return log_parse_error(r);
755 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, NULL, arg_all);
757 r = print_seat_status_info(bus, path);
759 log_error("Failed to query seat: %s", strerror(-r));
767 static int activate(sd_bus *bus, char **args, unsigned n) {
768 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
774 for (i = 1; i < n; i++) {
776 r = sd_bus_call_method (
778 "org.freedesktop.login1",
779 "/org/freedesktop/login1",
780 "org.freedesktop.login1.Manager",
781 streq(args[0], "lock-session") ? "LockSession" :
782 streq(args[0], "unlock-session") ? "UnlockSession" :
783 streq(args[0], "terminate-session") ? "TerminateSession" :
788 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
796 static int kill_session(sd_bus *bus, char **args, unsigned n) {
797 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
804 arg_kill_who = "all";
806 for (i = 1; i < n; i++) {
808 r = sd_bus_call_method (
810 "org.freedesktop.login1",
811 "/org/freedesktop/login1",
812 "org.freedesktop.login1.Manager",
815 "ssi", args[i], arg_kill_who, arg_signal);
817 log_error("Could not kill session: %s", bus_error_message(&error, -r));
825 static int enable_linger(sd_bus *bus, char **args, unsigned n) {
826 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
833 polkit_agent_open_if_enabled();
835 b = streq(args[0], "enable-linger");
837 for (i = 1; i < n; i++) {
840 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
842 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
846 r = sd_bus_call_method (
848 "org.freedesktop.login1",
849 "/org/freedesktop/login1",
850 "org.freedesktop.login1.Manager",
853 "ubb", (uint32_t) uid, b, true);
855 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
863 static int terminate_user(sd_bus *bus, char **args, unsigned n) {
864 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
870 for (i = 1; i < n; i++) {
873 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
875 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
879 r = sd_bus_call_method (
881 "org.freedesktop.login1",
882 "/org/freedesktop/login1",
883 "org.freedesktop.login1.Manager",
886 "u", (uint32_t) uid);
888 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
896 static int kill_user(sd_bus *bus, char **args, unsigned n) {
897 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
904 arg_kill_who = "all";
906 for (i = 1; i < n; i++) {
909 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
911 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
915 r = sd_bus_call_method (
917 "org.freedesktop.login1",
918 "/org/freedesktop/login1",
919 "org.freedesktop.login1.Manager",
922 "ui", (uint32_t) uid, arg_signal);
924 log_error("Could not kill user: %s", bus_error_message(&error, -r));
932 static int attach(sd_bus *bus, char **args, unsigned n) {
933 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
939 polkit_agent_open_if_enabled();
941 for (i = 2; i < n; i++) {
943 r = sd_bus_call_method (
945 "org.freedesktop.login1",
946 "/org/freedesktop/login1",
947 "org.freedesktop.login1.Manager",
950 "ssb", args[1], args[i], true);
953 log_error("Could not attach device: %s", bus_error_message(&error, -r));
961 static int flush_devices(sd_bus *bus, char **args, unsigned n) {
962 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
967 polkit_agent_open_if_enabled();
969 r = sd_bus_call_method (
971 "org.freedesktop.login1",
972 "/org/freedesktop/login1",
973 "org.freedesktop.login1.Manager",
978 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
983 static int lock_sessions(sd_bus *bus, char **args, unsigned n) {
984 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
989 r = sd_bus_call_method (
991 "org.freedesktop.login1",
992 "/org/freedesktop/login1",
993 "org.freedesktop.login1.Manager",
994 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
998 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1003 static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
1004 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1010 for (i = 1; i < n; i++) {
1012 r = sd_bus_call_method (
1014 "org.freedesktop.login1",
1015 "/org/freedesktop/login1",
1016 "org.freedesktop.login1.Manager",
1021 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1029 static int help(void) {
1031 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1032 "Send control commands to or query the login manager.\n\n"
1033 " -h --help Show this help\n"
1034 " --version Show package version\n"
1035 " --no-pager Do not pipe output into a pager\n"
1036 " --no-ask-password Don't prompt for password\n"
1037 " -H --host=[USER@]HOST Operate on remote host\n"
1038 " -M --machine=CONTAINER Operate on local container\n"
1039 " -p --property=NAME Show only properties by this name\n"
1040 " -a --all Show all properties, including empty ones\n"
1041 " -l --full Do not ellipsize output\n"
1042 " --kill-who=WHO Who to send signal to\n"
1043 " -s --signal=SIGNAL Which signal to send\n\n"
1045 " list-sessions List sessions\n"
1046 " session-status [ID...] Show session status\n"
1047 " show-session [ID...] Show properties of one or more sessions\n"
1048 " activate [ID] Activate a session\n"
1049 " lock-session [ID...] Screen lock one or more sessions\n"
1050 " unlock-session [ID...] Screen unlock one or more sessions\n"
1051 " lock-sessions Screen lock all current sessions\n"
1052 " unlock-sessions Screen unlock all current sessions\n"
1053 " terminate-session [ID...] Terminate one or more sessions\n"
1054 " kill-session [ID...] Send signal to processes of a session\n"
1055 " list-users List users\n"
1056 " user-status [USER...] Show user status\n"
1057 " show-user [USER...] Show properties of one or more users\n"
1058 " enable-linger [USER...] Enable linger state of one or more users\n"
1059 " disable-linger [USER...] Disable linger state of one or more users\n"
1060 " terminate-user [USER...] Terminate all sessions of one or more users\n"
1061 " kill-user [USER...] Send signal to processes of a user\n"
1062 " list-seats List seats\n"
1063 " seat-status [NAME...] Show seat status\n"
1064 " show-seat [NAME...] Show properties of one or more seats\n"
1065 " attach [NAME] [DEVICE...] Attach one or more devices to a seat\n"
1066 " flush-devices Flush all device associations\n"
1067 " terminate-seat [NAME...] Terminate all sessions on one or more seats\n",
1068 program_invocation_short_name);
1073 static int parse_argv(int argc, char *argv[]) {
1076 ARG_VERSION = 0x100,
1079 ARG_NO_ASK_PASSWORD,
1082 static const struct option options[] = {
1083 { "help", no_argument, NULL, 'h' },
1084 { "version", no_argument, NULL, ARG_VERSION },
1085 { "property", required_argument, NULL, 'p' },
1086 { "all", no_argument, NULL, 'a' },
1087 { "full", no_argument, NULL, 'l' },
1088 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1089 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1090 { "signal", required_argument, NULL, 's' },
1091 { "host", required_argument, NULL, 'H' },
1092 { "machine", required_argument, NULL, 'M' },
1093 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1102 while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) {
1110 puts(PACKAGE_STRING);
1111 puts(SYSTEMD_FEATURES);
1117 l = strv_append(arg_property, optarg);
1121 strv_free(arg_property);
1124 /* If the user asked for a particular
1125 * property, show it to him, even if it is
1140 arg_no_pager = true;
1143 case ARG_NO_ASK_PASSWORD:
1144 arg_ask_password = false;
1148 arg_kill_who = optarg;
1152 arg_signal = signal_from_string_try_harder(optarg);
1153 if (arg_signal < 0) {
1154 log_error("Failed to parse signal string %s.", optarg);
1160 arg_transport = BUS_TRANSPORT_REMOTE;
1165 arg_transport = BUS_TRANSPORT_CONTAINER;
1173 assert_not_reached("Unhandled option");
1180 static int loginctl_main(sd_bus *bus, int argc, char *argv[]) {
1182 static const struct {
1190 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1192 { "list-sessions", LESS, 1, list_sessions },
1193 { "session-status", MORE, 2, show_session },
1194 { "show-session", MORE, 1, show_session },
1195 { "activate", EQUAL, 2, activate },
1196 { "lock-session", MORE, 2, activate },
1197 { "unlock-session", MORE, 2, activate },
1198 { "lock-sessions", EQUAL, 1, lock_sessions },
1199 { "unlock-sessions", EQUAL, 1, lock_sessions },
1200 { "terminate-session", MORE, 2, activate },
1201 { "kill-session", MORE, 2, kill_session },
1202 { "list-users", EQUAL, 1, list_users },
1203 { "user-status", MORE, 2, show_user },
1204 { "show-user", MORE, 1, show_user },
1205 { "enable-linger", MORE, 2, enable_linger },
1206 { "disable-linger", MORE, 2, enable_linger },
1207 { "terminate-user", MORE, 2, terminate_user },
1208 { "kill-user", MORE, 2, kill_user },
1209 { "list-seats", EQUAL, 1, list_seats },
1210 { "seat-status", MORE, 2, show_seat },
1211 { "show-seat", MORE, 1, show_seat },
1212 { "attach", MORE, 3, attach },
1213 { "flush-devices", EQUAL, 1, flush_devices },
1214 { "terminate-seat", MORE, 2, terminate_seat },
1223 left = argc - optind;
1226 /* Special rule: no arguments means "list-sessions" */
1229 if (streq(argv[optind], "help")) {
1234 for (i = 0; i < ELEMENTSOF(verbs); i++)
1235 if (streq(argv[optind], verbs[i].verb))
1238 if (i >= ELEMENTSOF(verbs)) {
1239 log_error("Unknown operation %s", argv[optind]);
1244 switch (verbs[i].argc_cmp) {
1247 if (left != verbs[i].argc) {
1248 log_error("Invalid number of arguments.");
1255 if (left < verbs[i].argc) {
1256 log_error("Too few arguments.");
1263 if (left > verbs[i].argc) {
1264 log_error("Too many arguments.");
1271 assert_not_reached("Unknown comparison operator.");
1274 return verbs[i].dispatch(bus, argv + optind, left);
1277 int main(int argc, char *argv[]) {
1278 _cleanup_bus_unref_ sd_bus *bus = NULL;
1281 setlocale(LC_ALL, "");
1282 log_parse_environment();
1285 r = parse_argv(argc, argv);
1289 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1291 log_error("Failed to create bus connection: %s", strerror(-r));
1295 r = loginctl_main(bus, argc, argv);
1300 strv_free(arg_property);
1302 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;