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) {
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);
381 printf("%s - ", strna(i.id));
384 printf("%s (%u)\n", i.name, (unsigned) i.uid);
386 printf("%u\n", (unsigned) i.uid);
388 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
389 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
392 printf("\t Since: %s; %s\n", s2, s1);
394 printf("\t Since: %s\n", s2);
397 _cleanup_free_ char *t = NULL;
399 printf("\t Leader: %u", (unsigned) i.leader);
401 get_process_comm(i.leader, &t);
409 printf("\t Seat: %s", i.seat);
412 printf("; vc%i", i.vtnr);
418 printf("\t TTY: %s\n", i.tty);
420 printf("\t Display: %s\n", i.display);
422 if (i.remote_host && i.remote_user)
423 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
424 else if (i.remote_host)
425 printf("\t Remote: %s\n", i.remote_host);
426 else if (i.remote_user)
427 printf("\t Remote: user %s\n", i.remote_user);
429 printf("\t Remote: Yes\n");
432 printf("\t Service: %s", i.service);
435 printf("; type %s", i.type);
438 printf("; class %s", i.class);
442 printf("\t Type: %s\n", i.type);
445 printf("; class %s", i.class);
447 printf("\t Class: %s\n", i.class);
450 printf("\t State: %s\n", i.state);
453 printf("\t Unit: %s\n", i.scope);
454 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
460 static int print_user_status_info(sd_bus *bus, const char *path) {
462 static const struct bus_properties_map map[] = {
463 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
464 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
465 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
466 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
467 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp) },
468 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
469 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
473 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
474 char since2[FORMAT_TIMESTAMP_MAX], *s2;
475 UserStatusInfo i = {};
478 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
483 printf("%s (%u)\n", i.name, (unsigned) i.uid);
485 printf("%u\n", (unsigned) i.uid);
487 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
488 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
491 printf("\t Since: %s; %s\n", s2, s1);
493 printf("\t Since: %s\n", s2);
495 if (!isempty(i.state))
496 printf("\t State: %s\n", i.state);
498 if (!strv_isempty(i.sessions)) {
500 printf("\tSessions:");
502 STRV_FOREACH(l, i.sessions) {
503 if (streq_ptr(*l, i.display))
513 printf("\t Unit: %s\n", i.slice);
514 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
518 strv_free(i.sessions);
523 static int print_seat_status_info(sd_bus *bus, const char *path) {
525 static const struct bus_properties_map map[] = {
526 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
527 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
528 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
532 SeatStatusInfo i = {};
535 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
539 printf("%s\n", strna(i.id));
541 if (!strv_isempty(i.sessions)) {
543 printf("\tSessions:");
545 STRV_FOREACH(l, i.sessions) {
546 if (streq_ptr(*l, i.active_session))
555 if (arg_transport == BUS_TRANSPORT_LOCAL) {
564 printf("\t Devices:\n");
566 show_sysfs(i.id, "\t\t ", c);
570 strv_free(i.sessions);
575 static int show_session(sd_bus *bus, char **args, unsigned n) {
576 bool show_properties;
583 show_properties = !strstr(args[0], "status");
585 pager_open_if_enabled();
587 if (show_properties && n <= 1) {
588 /* If not argument is specified inspect the manager
590 r = bus_print_all_properties(bus, "org.freedesktop.login1", "/org/freedesktop/login1", NULL, arg_all);
592 log_error("Failed to query login manager.");
597 for (i = 1; i < n; i++) {
598 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
599 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
600 const char *path = NULL;
605 r = sd_bus_call_method(
607 "org.freedesktop.login1",
608 "/org/freedesktop/login1",
609 "org.freedesktop.login1.Manager",
614 log_error("Failed to get session: %s", bus_error_message(&error, r));
618 r = sd_bus_message_read(reply, "o", &path);
620 return bus_log_parse_error(r);
623 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, NULL, arg_all);
625 r = print_session_status_info(bus, path);
627 log_error("Failed to query session: %s", strerror(-r));
635 static int show_user(sd_bus *bus, char **args, unsigned n) {
636 bool show_properties;
643 show_properties = !strstr(args[0], "status");
645 pager_open_if_enabled();
647 if (show_properties && n <= 1) {
648 /* If not argument is specified inspect the manager
650 r = bus_print_all_properties(bus, "org.freedesktop.login1", "/org/freedesktop/login1", NULL, arg_all);
652 log_error("Failed to query login manager.");
657 for (i = 1; i < n; i++) {
658 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
659 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
660 const char *path = NULL;
666 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
668 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
672 r = sd_bus_call_method(
674 "org.freedesktop.login1",
675 "/org/freedesktop/login1",
676 "org.freedesktop.login1.Manager",
679 "u", (uint32_t) uid);
681 log_error("Failed to get user: %s", bus_error_message(&error, r));
685 r = sd_bus_message_read(reply, "o", &path);
687 return bus_log_parse_error(r);
690 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, NULL, arg_all);
692 r = print_user_status_info(bus, path);
694 log_error("Failed to query user: %s", strerror(-r));
702 static int show_seat(sd_bus *bus, char **args, unsigned n) {
703 bool show_properties;
710 show_properties = !strstr(args[0], "status");
712 pager_open_if_enabled();
714 if (show_properties && n <= 1) {
715 /* If not argument is specified inspect the manager
717 r = bus_print_all_properties(bus, "org.freedesktop.login1", "/org/freedesktop/login1", NULL, arg_all);
719 log_error("Failed to query login manager.");
724 for (i = 1; i < n; i++) {
725 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
726 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
727 const char *path = NULL;
732 r = sd_bus_call_method(
734 "org.freedesktop.login1",
735 "/org/freedesktop/login1",
736 "org.freedesktop.login1.Manager",
741 log_error("Failed to get seat: %s", bus_error_message(&error, r));
745 r = sd_bus_message_read(reply, "o", &path);
747 return bus_log_parse_error(r);
750 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, NULL, arg_all);
752 r = print_seat_status_info(bus, path);
754 log_error("Failed to query seat: %s", strerror(-r));
762 static int activate(sd_bus *bus, char **args, unsigned n) {
763 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
769 for (i = 1; i < n; i++) {
771 r = sd_bus_call_method (
773 "org.freedesktop.login1",
774 "/org/freedesktop/login1",
775 "org.freedesktop.login1.Manager",
776 streq(args[0], "lock-session") ? "LockSession" :
777 streq(args[0], "unlock-session") ? "UnlockSession" :
778 streq(args[0], "terminate-session") ? "TerminateSession" :
783 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
791 static int kill_session(sd_bus *bus, char **args, unsigned n) {
792 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
799 arg_kill_who = "all";
801 for (i = 1; i < n; i++) {
803 r = sd_bus_call_method (
805 "org.freedesktop.login1",
806 "/org/freedesktop/login1",
807 "org.freedesktop.login1.Manager",
810 "ssi", args[i], arg_kill_who, arg_signal);
812 log_error("Could not kill session: %s", bus_error_message(&error, -r));
820 static int enable_linger(sd_bus *bus, char **args, unsigned n) {
821 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
828 polkit_agent_open_if_enabled();
830 b = streq(args[0], "enable-linger");
832 for (i = 1; i < n; i++) {
835 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
837 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
841 r = sd_bus_call_method (
843 "org.freedesktop.login1",
844 "/org/freedesktop/login1",
845 "org.freedesktop.login1.Manager",
848 "ubb", (uint32_t) uid, b, true);
850 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
858 static int terminate_user(sd_bus *bus, char **args, unsigned n) {
859 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
865 for (i = 1; i < n; i++) {
868 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
870 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
874 r = sd_bus_call_method (
876 "org.freedesktop.login1",
877 "/org/freedesktop/login1",
878 "org.freedesktop.login1.Manager",
881 "u", (uint32_t) uid);
883 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
891 static int kill_user(sd_bus *bus, char **args, unsigned n) {
892 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
899 arg_kill_who = "all";
901 for (i = 1; i < n; i++) {
904 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
906 log_error("Failed to look up user %s: %s", args[i], strerror(-r));
910 r = sd_bus_call_method (
912 "org.freedesktop.login1",
913 "/org/freedesktop/login1",
914 "org.freedesktop.login1.Manager",
917 "ui", (uint32_t) uid, arg_signal);
919 log_error("Could not kill user: %s", bus_error_message(&error, -r));
927 static int attach(sd_bus *bus, char **args, unsigned n) {
928 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
934 polkit_agent_open_if_enabled();
936 for (i = 2; i < n; i++) {
938 r = sd_bus_call_method (
940 "org.freedesktop.login1",
941 "/org/freedesktop/login1",
942 "org.freedesktop.login1.Manager",
945 "ssb", args[1], args[i], true);
948 log_error("Could not attach device: %s", bus_error_message(&error, -r));
956 static int flush_devices(sd_bus *bus, char **args, unsigned n) {
957 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
962 polkit_agent_open_if_enabled();
964 r = sd_bus_call_method (
966 "org.freedesktop.login1",
967 "/org/freedesktop/login1",
968 "org.freedesktop.login1.Manager",
973 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
978 static int lock_sessions(sd_bus *bus, char **args, unsigned n) {
979 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
984 r = sd_bus_call_method (
986 "org.freedesktop.login1",
987 "/org/freedesktop/login1",
988 "org.freedesktop.login1.Manager",
989 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
993 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
998 static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
999 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1005 for (i = 1; i < n; i++) {
1007 r = sd_bus_call_method (
1009 "org.freedesktop.login1",
1010 "/org/freedesktop/login1",
1011 "org.freedesktop.login1.Manager",
1016 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1024 static int help(void) {
1026 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1027 "Send control commands to or query the login manager.\n\n"
1028 " -h --help Show this help\n"
1029 " --version Show package version\n"
1030 " --no-pager Do not pipe output into a pager\n"
1031 " --no-ask-password Don't prompt for password\n"
1032 " -H --host=[USER@]HOST Operate on remote host\n"
1033 " -M --machine=CONTAINER Operate on local container\n"
1034 " -p --property=NAME Show only properties by this name\n"
1035 " -a --all Show all properties, including empty ones\n"
1036 " -l --full Do not ellipsize output\n"
1037 " --kill-who=WHO Who to send signal to\n"
1038 " -s --signal=SIGNAL Which signal to send\n\n"
1040 " list-sessions List sessions\n"
1041 " session-status [ID...] Show session status\n"
1042 " show-session [ID...] Show properties of one or more sessions\n"
1043 " activate [ID] Activate a session\n"
1044 " lock-session [ID...] Screen lock one or more sessions\n"
1045 " unlock-session [ID...] Screen unlock one or more sessions\n"
1046 " lock-sessions Screen lock all current sessions\n"
1047 " unlock-sessions Screen unlock all current sessions\n"
1048 " terminate-session [ID...] Terminate one or more sessions\n"
1049 " kill-session [ID...] Send signal to processes of a session\n"
1050 " list-users List users\n"
1051 " user-status [USER...] Show user status\n"
1052 " show-user [USER...] Show properties of one or more users\n"
1053 " enable-linger [USER...] Enable linger state of one or more users\n"
1054 " disable-linger [USER...] Disable linger state of one or more users\n"
1055 " terminate-user [USER...] Terminate all sessions of one or more users\n"
1056 " kill-user [USER...] Send signal to processes of a user\n"
1057 " list-seats List seats\n"
1058 " seat-status [NAME...] Show seat status\n"
1059 " show-seat [NAME...] Show properties of one or more seats\n"
1060 " attach [NAME] [DEVICE...] Attach one or more devices to a seat\n"
1061 " flush-devices Flush all device associations\n"
1062 " terminate-seat [NAME...] Terminate all sessions on one or more seats\n",
1063 program_invocation_short_name);
1068 static int parse_argv(int argc, char *argv[]) {
1071 ARG_VERSION = 0x100,
1074 ARG_NO_ASK_PASSWORD,
1077 static const struct option options[] = {
1078 { "help", no_argument, NULL, 'h' },
1079 { "version", no_argument, NULL, ARG_VERSION },
1080 { "property", required_argument, NULL, 'p' },
1081 { "all", no_argument, NULL, 'a' },
1082 { "full", no_argument, NULL, 'l' },
1083 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1084 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1085 { "signal", required_argument, NULL, 's' },
1086 { "host", required_argument, NULL, 'H' },
1087 { "machine", required_argument, NULL, 'M' },
1088 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1097 while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0) {
1105 puts(PACKAGE_STRING);
1106 puts(SYSTEMD_FEATURES);
1112 l = strv_append(arg_property, optarg);
1116 strv_free(arg_property);
1119 /* If the user asked for a particular
1120 * property, show it to him, even if it is
1135 arg_no_pager = true;
1138 case ARG_NO_ASK_PASSWORD:
1139 arg_ask_password = false;
1143 arg_kill_who = optarg;
1147 arg_signal = signal_from_string_try_harder(optarg);
1148 if (arg_signal < 0) {
1149 log_error("Failed to parse signal string %s.", optarg);
1155 arg_transport = BUS_TRANSPORT_REMOTE;
1160 arg_transport = BUS_TRANSPORT_CONTAINER;
1168 assert_not_reached("Unhandled option");
1175 static int loginctl_main(sd_bus *bus, int argc, char *argv[]) {
1177 static const struct {
1185 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1187 { "list-sessions", LESS, 1, list_sessions },
1188 { "session-status", MORE, 2, show_session },
1189 { "show-session", MORE, 1, show_session },
1190 { "activate", EQUAL, 2, activate },
1191 { "lock-session", MORE, 2, activate },
1192 { "unlock-session", MORE, 2, activate },
1193 { "lock-sessions", EQUAL, 1, lock_sessions },
1194 { "unlock-sessions", EQUAL, 1, lock_sessions },
1195 { "terminate-session", MORE, 2, activate },
1196 { "kill-session", MORE, 2, kill_session },
1197 { "list-users", EQUAL, 1, list_users },
1198 { "user-status", MORE, 2, show_user },
1199 { "show-user", MORE, 1, show_user },
1200 { "enable-linger", MORE, 2, enable_linger },
1201 { "disable-linger", MORE, 2, enable_linger },
1202 { "terminate-user", MORE, 2, terminate_user },
1203 { "kill-user", MORE, 2, kill_user },
1204 { "list-seats", EQUAL, 1, list_seats },
1205 { "seat-status", MORE, 2, show_seat },
1206 { "show-seat", MORE, 1, show_seat },
1207 { "attach", MORE, 3, attach },
1208 { "flush-devices", EQUAL, 1, flush_devices },
1209 { "terminate-seat", MORE, 2, terminate_seat },
1218 left = argc - optind;
1221 /* Special rule: no arguments means "list-sessions" */
1224 if (streq(argv[optind], "help")) {
1229 for (i = 0; i < ELEMENTSOF(verbs); i++)
1230 if (streq(argv[optind], verbs[i].verb))
1233 if (i >= ELEMENTSOF(verbs)) {
1234 log_error("Unknown operation %s", argv[optind]);
1239 switch (verbs[i].argc_cmp) {
1242 if (left != verbs[i].argc) {
1243 log_error("Invalid number of arguments.");
1250 if (left < verbs[i].argc) {
1251 log_error("Too few arguments.");
1258 if (left > verbs[i].argc) {
1259 log_error("Too many arguments.");
1266 assert_not_reached("Unknown comparison operator.");
1269 return verbs[i].dispatch(bus, argv + optind, left);
1272 int main(int argc, char *argv[]) {
1273 _cleanup_bus_unref_ sd_bus *bus = NULL;
1276 setlocale(LC_ALL, "");
1277 log_parse_environment();
1280 r = parse_argv(argc, argv);
1284 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1286 log_error("Failed to create bus connection: %s", strerror(-r));
1290 r = loginctl_main(bus, argc, argv);
1295 strv_free(arg_property);
1297 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;