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) {
56 /* Cache result before we open the pager */
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)
73 static int log_parse_error(int r) {
74 log_error("Failed to parse message: %s", strerror(-r));
78 static int list_sessions(sd_bus *bus, char **args, unsigned n) {
79 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
80 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
81 const char *id, *user, *seat, *object;
86 pager_open_if_enabled();
88 r = sd_bus_call_method(
90 "org.freedesktop.login1",
91 "/org/freedesktop/login1",
92 "org.freedesktop.login1.Manager",
97 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
101 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
103 return log_parse_error(r);
105 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
107 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
108 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
112 return 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 log_parse_error(r);
146 printf("%10s %-16s\n", "UID", "USER");
148 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
149 printf("%10u %-16s\n", (unsigned) uid, user);
153 return log_parse_error(r);
155 printf("\n%u users listed.\n", k);
160 static int list_seats(sd_bus *bus, char **args, unsigned n) {
161 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
162 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
163 const char *seat, *object;
167 pager_open_if_enabled();
169 r = sd_bus_call_method(
171 "org.freedesktop.login1",
172 "/org/freedesktop/login1",
173 "org.freedesktop.login1.Manager",
178 log_error("Failed to list seats: %s", bus_error_message(&error, r));
182 r = sd_bus_message_enter_container(reply, 'a', "(so)");
184 return log_parse_error(r);
186 printf("%-16s\n", "SEAT");
188 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
189 printf("%-16s\n", seat);
193 return log_parse_error(r);
195 printf("\n%u seats listed.\n", k);
200 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
201 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
202 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
203 _cleanup_free_ char *path = NULL;
211 if (arg_transport != BUS_TRANSPORT_LOCAL)
214 path = unit_dbus_path_from_name(unit);
218 r = sd_bus_get_property(
220 "org.freedesktop.systemd1",
224 &error, &reply, "s");
228 r = sd_bus_message_read(reply, "s", &cgroup);
235 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
239 arg_all * OUTPUT_SHOW_ALL |
240 arg_full * OUTPUT_FULL_WIDTH;
248 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, output_flags);
252 typedef struct SessionStatusInfo {
262 const char *remote_host;
263 const char *remote_user;
272 typedef struct UserStatusInfo {
282 typedef struct SeatStatusInfo {
284 const char *active_session;
288 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
289 const char *contents;
292 r = sd_bus_message_peek_type(m, NULL, &contents);
296 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
300 if (contents[0] == 's' || contents[0] == 'o') {
302 char **p = (char **) userdata;
304 r = sd_bus_message_read_basic(m, contents[0], &s);
314 r = sd_bus_message_read_basic(m, contents[0], userdata);
319 r = sd_bus_message_skip(m, contents+1);
323 r = sd_bus_message_exit_container(m);
330 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
337 r = sd_bus_message_enter_container(m, 'a', "(so)");
341 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
342 r = strv_extend(userdata, name);
349 return sd_bus_message_exit_container(m);
352 static int print_session_status_info(sd_bus *bus, const char *path) {
354 static const struct bus_properties_map map[] = {
355 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
356 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
357 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
358 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
359 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
360 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
361 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
362 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
363 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
364 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
365 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
366 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
367 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
368 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
369 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp) },
370 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
371 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, id) },
375 SessionStatusInfo i = {};
376 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
377 char since2[FORMAT_TIMESTAMP_MAX], *s2;
380 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
384 printf("%s - ", strna(i.id));
387 printf("%s (%u)\n", i.name, (unsigned) i.uid);
389 printf("%u\n", (unsigned) i.uid);
391 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
392 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
395 printf("\t Since: %s; %s\n", s2, s1);
397 printf("\t Since: %s\n", s2);
400 _cleanup_free_ char *t = NULL;
402 printf("\t Leader: %u", (unsigned) i.leader);
404 get_process_comm(i.leader, &t);
412 printf("\t Seat: %s", i.seat);
415 printf("; vc%i", i.vtnr);
421 printf("\t TTY: %s\n", i.tty);
423 printf("\t Display: %s\n", i.display);
425 if (i.remote_host && i.remote_user)
426 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
427 else if (i.remote_host)
428 printf("\t Remote: %s\n", i.remote_host);
429 else if (i.remote_user)
430 printf("\t Remote: user %s\n", i.remote_user);
432 printf("\t Remote: Yes\n");
435 printf("\t Service: %s", i.service);
438 printf("; type %s", i.type);
441 printf("; class %s", i.class);
445 printf("\t Type: %s\n", i.type);
448 printf("; class %s", i.class);
450 printf("\t Class: %s\n", i.class);
453 printf("\t State: %s\n", i.state);
456 printf("\t Unit: %s\n", i.scope);
457 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
463 static int print_user_status_info(sd_bus *bus, const char *path) {
465 static const struct bus_properties_map map[] = {
466 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
467 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
468 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
469 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
470 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp) },
471 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
472 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
476 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
477 char since2[FORMAT_TIMESTAMP_MAX], *s2;
478 UserStatusInfo i = {};
481 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
486 printf("%s (%u)\n", i.name, (unsigned) i.uid);
488 printf("%u\n", (unsigned) i.uid);
490 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
491 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
494 printf("\t Since: %s; %s\n", s2, s1);
496 printf("\t Since: %s\n", s2);
498 if (!isempty(i.state))
499 printf("\t State: %s\n", i.state);
501 if (!strv_isempty(i.sessions)) {
503 printf("\tSessions:");
505 STRV_FOREACH(l, i.sessions) {
506 if (streq_ptr(*l, i.display))
516 printf("\t Unit: %s\n", i.slice);
517 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
521 strv_free(i.sessions);
526 static int print_seat_status_info(sd_bus *bus, const char *path) {
528 static const struct bus_properties_map map[] = {
529 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
530 { "ActiveSession", "(so)", &prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
531 { "Sessions", "a(so)", &prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
535 SeatStatusInfo i = {};
538 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
542 printf("%s\n", strna(i.id));
544 if (!strv_isempty(i.sessions)) {
546 printf("\tSessions:");
548 STRV_FOREACH(l, i.sessions) {
549 if (streq_ptr(*l, i.active_session))
558 if (arg_transport == BUS_TRANSPORT_LOCAL) {
567 printf("\t Devices:\n");
569 show_sysfs(i.id, "\t\t ", c);
573 strv_free(i.sessions);
578 static int show_session(sd_bus *bus, char **args, unsigned n) {
579 bool show_properties;
586 show_properties = !strstr(args[0], "status");
588 pager_open_if_enabled();
590 if (show_properties && n <= 1) {
591 /* If not argument is specified inspect the manager
593 r = bus_print_all_properties(bus, "org.freedesktop.login1", "/org/freedesktop/login1", NULL, arg_all);
595 log_error("Failed to query login manager.");
600 for (i = 1; i < n; i++) {
601 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
602 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
603 const char *path = NULL;
608 r = sd_bus_call_method(
610 "org.freedesktop.login1",
611 "/org/freedesktop/login1",
612 "org.freedesktop.login1.Manager",
617 log_error("Failed to get session: %s", bus_error_message(&error, r));
621 r = sd_bus_message_read(reply, "o", &path);
623 return log_parse_error(r);
626 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, NULL, arg_all);
628 r = print_session_status_info(bus, path);
630 log_error("Failed to query session: %s", strerror(-r));
638 static int show_user(sd_bus *bus, char **args, unsigned n) {
639 bool show_properties;
646 show_properties = !strstr(args[0], "status");
648 pager_open_if_enabled();
650 if (show_properties && n <= 1) {
651 /* If not argument is specified inspect the manager
653 r = bus_print_all_properties(bus, "org.freedesktop.login1", "/org/freedesktop/login1", NULL, arg_all);
655 log_error("Failed to query login manager.");
660 for (i = 1; i < n; i++) {
661 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
662 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
663 const char *path = NULL;
669 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
671 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
675 r = sd_bus_call_method(
677 "org.freedesktop.login1",
678 "/org/freedesktop/login1",
679 "org.freedesktop.login1.Manager",
682 "u", (uint32_t) uid);
684 log_error("Failed to get user: %s", bus_error_message(&error, r));
688 r = sd_bus_message_read(reply, "o", &path);
690 return log_parse_error(r);
693 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, NULL, arg_all);
695 r = print_user_status_info(bus, path);
697 log_error("Failed to query user: %s", strerror(-r));
705 static int show_seat(sd_bus *bus, char **args, unsigned n) {
706 bool show_properties;
713 show_properties = !strstr(args[0], "status");
715 pager_open_if_enabled();
717 if (show_properties && n <= 1) {
718 /* If not argument is specified inspect the manager
720 r = bus_print_all_properties(bus, "org.freedesktop.login1", "/org/freedesktop/login1", NULL, arg_all);
722 log_error("Failed to query login manager.");
727 for (i = 1; i < n; i++) {
728 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
729 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
730 const char *path = NULL;
735 r = sd_bus_call_method(
737 "org.freedesktop.login1",
738 "/org/freedesktop/login1",
739 "org.freedesktop.login1.Manager",
744 log_error("Failed to get seat: %s", bus_error_message(&error, r));
748 r = sd_bus_message_read(reply, "o", &path);
750 return log_parse_error(r);
753 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, NULL, arg_all);
755 r = print_seat_status_info(bus, path);
757 log_error("Failed to query seat: %s", strerror(-r));
765 static int activate(sd_bus *bus, char **args, unsigned n) {
766 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
772 for (i = 1; i < n; i++) {
774 r = sd_bus_call_method (
776 "org.freedesktop.login1",
777 "/org/freedesktop/login1",
778 "org.freedesktop.login1.Manager",
779 streq(args[0], "lock-session") ? "LockSession" :
780 streq(args[0], "unlock-session") ? "UnlockSession" :
781 streq(args[0], "terminate-session") ? "TerminateSession" :
786 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
794 static int kill_session(sd_bus *bus, char **args, unsigned n) {
795 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
802 arg_kill_who = "all";
804 for (i = 1; i < n; i++) {
806 r = sd_bus_call_method (
808 "org.freedesktop.login1",
809 "/org/freedesktop/login1",
810 "org.freedesktop.login1.Manager",
813 "ssi", args[i], arg_kill_who, arg_signal);
815 log_error("Could not kill session: %s", bus_error_message(&error, -r));
823 static int enable_linger(sd_bus *bus, char **args, unsigned n) {
824 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
831 polkit_agent_open_if_enabled();
833 b = streq(args[0], "enable-linger");
835 for (i = 1; i < n; i++) {
838 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
840 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
844 r = sd_bus_call_method (
846 "org.freedesktop.login1",
847 "/org/freedesktop/login1",
848 "org.freedesktop.login1.Manager",
851 "ubb", (uint32_t) uid, b, true);
853 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
861 static int terminate_user(sd_bus *bus, char **args, unsigned n) {
862 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
868 for (i = 1; i < n; i++) {
871 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
873 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
877 r = sd_bus_call_method (
879 "org.freedesktop.login1",
880 "/org/freedesktop/login1",
881 "org.freedesktop.login1.Manager",
884 "u", (uint32_t) uid);
886 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
894 static int kill_user(sd_bus *bus, char **args, unsigned n) {
895 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
902 arg_kill_who = "all";
904 for (i = 1; i < n; i++) {
907 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
909 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
913 r = sd_bus_call_method (
915 "org.freedesktop.login1",
916 "/org/freedesktop/login1",
917 "org.freedesktop.login1.Manager",
920 "ui", (uint32_t) uid, arg_signal);
922 log_error("Could not kill user: %s", bus_error_message(&error, -r));
930 static int attach(sd_bus *bus, char **args, unsigned n) {
931 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
937 polkit_agent_open_if_enabled();
939 for (i = 2; i < n; i++) {
941 r = sd_bus_call_method (
943 "org.freedesktop.login1",
944 "/org/freedesktop/login1",
945 "org.freedesktop.login1.Manager",
948 "ssb", args[1], args[i], true);
951 log_error("Could not attach device: %s", bus_error_message(&error, -r));
959 static int flush_devices(sd_bus *bus, char **args, unsigned n) {
960 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
965 polkit_agent_open_if_enabled();
967 r = sd_bus_call_method (
969 "org.freedesktop.login1",
970 "/org/freedesktop/login1",
971 "org.freedesktop.login1.Manager",
976 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
981 static int lock_sessions(sd_bus *bus, char **args, unsigned n) {
982 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
987 r = sd_bus_call_method (
989 "org.freedesktop.login1",
990 "/org/freedesktop/login1",
991 "org.freedesktop.login1.Manager",
992 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
996 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1001 static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
1002 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1008 for (i = 1; i < n; i++) {
1010 r = sd_bus_call_method (
1012 "org.freedesktop.login1",
1013 "/org/freedesktop/login1",
1014 "org.freedesktop.login1.Manager",
1019 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1027 static int help(void) {
1029 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1030 "Send control commands to or query the login manager.\n\n"
1031 " -h --help Show this help\n"
1032 " --version Show package version\n"
1033 " --no-pager Do not pipe output into a pager\n"
1034 " --no-ask-password Don't prompt for password\n"
1035 " -H --host=[USER@]HOST Operate on remote host\n"
1036 " -M --machine=CONTAINER Operate on local container\n"
1037 " -p --property=NAME Show only properties by this name\n"
1038 " -a --all Show all properties, including empty ones\n"
1039 " -l --full Do not ellipsize output\n"
1040 " --kill-who=WHO Who to send signal to\n"
1041 " -s --signal=SIGNAL Which signal to send\n\n"
1043 " list-sessions List sessions\n"
1044 " session-status [ID...] Show session status\n"
1045 " show-session [ID...] Show properties of one or more sessions\n"
1046 " activate [ID] Activate a session\n"
1047 " lock-session [ID...] Screen lock one or more sessions\n"
1048 " unlock-session [ID...] Screen unlock one or more sessions\n"
1049 " lock-sessions Screen lock all current sessions\n"
1050 " unlock-sessions Screen unlock all current sessions\n"
1051 " terminate-session [ID...] Terminate one or more sessions\n"
1052 " kill-session [ID...] Send signal to processes of a session\n"
1053 " list-users List users\n"
1054 " user-status [USER...] Show user status\n"
1055 " show-user [USER...] Show properties of one or more users\n"
1056 " enable-linger [USER...] Enable linger state of one or more users\n"
1057 " disable-linger [USER...] Disable linger state of one or more users\n"
1058 " terminate-user [USER...] Terminate all sessions of one or more users\n"
1059 " kill-user [USER...] Send signal to processes of a user\n"
1060 " list-seats List seats\n"
1061 " seat-status [NAME...] Show seat status\n"
1062 " show-seat [NAME...] Show properties of one or more seats\n"
1063 " attach [NAME] [DEVICE...] Attach one or more devices to a seat\n"
1064 " flush-devices Flush all device associations\n"
1065 " terminate-seat [NAME...] Terminate all sessions on one or more seats\n",
1066 program_invocation_short_name);
1071 static int parse_argv(int argc, char *argv[]) {
1074 ARG_VERSION = 0x100,
1077 ARG_NO_ASK_PASSWORD,
1080 static const struct option options[] = {
1081 { "help", no_argument, NULL, 'h' },
1082 { "version", no_argument, NULL, ARG_VERSION },
1083 { "property", required_argument, NULL, 'p' },
1084 { "all", no_argument, NULL, 'a' },
1085 { "full", no_argument, NULL, 'l' },
1086 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1087 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1088 { "signal", required_argument, NULL, 's' },
1089 { "host", required_argument, NULL, 'H' },
1090 { "machine", required_argument, NULL, 'M' },
1091 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1100 while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) {
1108 puts(PACKAGE_STRING);
1109 puts(SYSTEMD_FEATURES);
1115 l = strv_append(arg_property, optarg);
1119 strv_free(arg_property);
1122 /* If the user asked for a particular
1123 * property, show it to him, even if it is
1138 arg_no_pager = true;
1141 case ARG_NO_ASK_PASSWORD:
1142 arg_ask_password = false;
1146 arg_kill_who = optarg;
1150 arg_signal = signal_from_string_try_harder(optarg);
1151 if (arg_signal < 0) {
1152 log_error("Failed to parse signal string %s.", optarg);
1158 arg_transport = BUS_TRANSPORT_REMOTE;
1163 arg_transport = BUS_TRANSPORT_CONTAINER;
1171 assert_not_reached("Unhandled option");
1178 static int loginctl_main(sd_bus *bus, int argc, char *argv[]) {
1180 static const struct {
1188 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1190 { "list-sessions", LESS, 1, list_sessions },
1191 { "session-status", MORE, 2, show_session },
1192 { "show-session", MORE, 1, show_session },
1193 { "activate", EQUAL, 2, activate },
1194 { "lock-session", MORE, 2, activate },
1195 { "unlock-session", MORE, 2, activate },
1196 { "lock-sessions", EQUAL, 1, lock_sessions },
1197 { "unlock-sessions", EQUAL, 1, lock_sessions },
1198 { "terminate-session", MORE, 2, activate },
1199 { "kill-session", MORE, 2, kill_session },
1200 { "list-users", EQUAL, 1, list_users },
1201 { "user-status", MORE, 2, show_user },
1202 { "show-user", MORE, 1, show_user },
1203 { "enable-linger", MORE, 2, enable_linger },
1204 { "disable-linger", MORE, 2, enable_linger },
1205 { "terminate-user", MORE, 2, terminate_user },
1206 { "kill-user", MORE, 2, kill_user },
1207 { "list-seats", EQUAL, 1, list_seats },
1208 { "seat-status", MORE, 2, show_seat },
1209 { "show-seat", MORE, 1, show_seat },
1210 { "attach", MORE, 3, attach },
1211 { "flush-devices", EQUAL, 1, flush_devices },
1212 { "terminate-seat", MORE, 2, terminate_seat },
1221 left = argc - optind;
1224 /* Special rule: no arguments means "list-sessions" */
1227 if (streq(argv[optind], "help")) {
1232 for (i = 0; i < ELEMENTSOF(verbs); i++)
1233 if (streq(argv[optind], verbs[i].verb))
1236 if (i >= ELEMENTSOF(verbs)) {
1237 log_error("Unknown operation %s", argv[optind]);
1242 switch (verbs[i].argc_cmp) {
1245 if (left != verbs[i].argc) {
1246 log_error("Invalid number of arguments.");
1253 if (left < verbs[i].argc) {
1254 log_error("Too few arguments.");
1261 if (left > verbs[i].argc) {
1262 log_error("Too many arguments.");
1269 assert_not_reached("Unknown comparison operator.");
1272 return verbs[i].dispatch(bus, argv + optind, left);
1275 int main(int argc, char *argv[]) {
1276 _cleanup_bus_unref_ sd_bus *bus = NULL;
1279 setlocale(LC_ALL, "");
1280 log_parse_environment();
1283 r = parse_argv(argc, argv);
1287 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1289 log_error("Failed to create bus connection: %s", strerror(-r));
1293 r = loginctl_main(bus, argc, argv);
1298 strv_free(arg_property);
1300 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;