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 return log_error_errno(r, "Could not get properties: %m");
395 printf("%s - ", strna(i.id));
398 printf("%s (%u)\n", i.name, (unsigned) i.uid);
400 printf("%u\n", (unsigned) i.uid);
402 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
403 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
406 printf("\t Since: %s; %s\n", s2, s1);
408 printf("\t Since: %s\n", s2);
411 _cleanup_free_ char *t = NULL;
413 printf("\t Leader: %u", (unsigned) i.leader);
415 get_process_comm(i.leader, &t);
422 if (!isempty(i.seat)) {
423 printf("\t Seat: %s", i.seat);
426 printf("; vc%u", i.vtnr);
432 printf("\t TTY: %s\n", i.tty);
434 printf("\t Display: %s\n", i.display);
436 if (i.remote_host && i.remote_user)
437 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
438 else if (i.remote_host)
439 printf("\t Remote: %s\n", i.remote_host);
440 else if (i.remote_user)
441 printf("\t Remote: user %s\n", i.remote_user);
443 printf("\t Remote: Yes\n");
446 printf("\t Service: %s", i.service);
449 printf("; type %s", i.type);
452 printf("; class %s", i.class);
456 printf("\t Type: %s", i.type);
459 printf("; class %s", i.class);
463 printf("\t Class: %s\n", i.class);
465 if (!isempty(i.desktop))
466 printf("\t Desktop: %s\n", i.desktop);
469 printf("\t State: %s\n", i.state);
472 printf("\t Unit: %s\n", i.scope);
473 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
479 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
481 static const struct bus_properties_map map[] = {
482 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
483 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
484 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
485 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
486 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp) },
487 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
488 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
492 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
493 char since2[FORMAT_TIMESTAMP_MAX], *s2;
494 UserStatusInfo i = {};
497 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
499 log_error_errno(r, "Could not get properties: %m");
509 printf("%s (%u)\n", i.name, (unsigned) i.uid);
511 printf("%u\n", (unsigned) i.uid);
513 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp);
514 s2 = format_timestamp(since2, sizeof(since2), i.timestamp);
517 printf("\t Since: %s; %s\n", s2, s1);
519 printf("\t Since: %s\n", s2);
521 if (!isempty(i.state))
522 printf("\t State: %s\n", i.state);
524 if (!strv_isempty(i.sessions)) {
526 printf("\tSessions:");
528 STRV_FOREACH(l, i.sessions) {
529 if (streq_ptr(*l, i.display))
539 printf("\t Unit: %s\n", i.slice);
540 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
544 strv_free(i.sessions);
549 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
551 static const struct bus_properties_map map[] = {
552 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
553 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
554 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
558 SeatStatusInfo i = {};
561 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
563 log_error_errno(r, "Could not get properties: %m");
572 printf("%s\n", strna(i.id));
574 if (!strv_isempty(i.sessions)) {
576 printf("\tSessions:");
578 STRV_FOREACH(l, i.sessions) {
579 if (streq_ptr(*l, i.active_session))
588 if (arg_transport == BUS_TRANSPORT_LOCAL) {
597 printf("\t Devices:\n");
599 show_sysfs(i.id, "\t\t ", c);
603 strv_free(i.sessions);
608 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
616 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
618 log_error_errno(r, "Could not get properties: %m");
623 static int show_session(sd_bus *bus, char **args, unsigned n) {
624 bool properties, new_line = false;
631 properties = !strstr(args[0], "status");
633 pager_open_if_enabled();
635 if (properties && n <= 1) {
636 /* If not argument is specified inspect the manager
638 return show_properties(bus, "/org/freedesktop/login1", &new_line);
641 for (i = 1; i < n; i++) {
642 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
643 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
644 const char *path = NULL;
646 r = sd_bus_call_method(
648 "org.freedesktop.login1",
649 "/org/freedesktop/login1",
650 "org.freedesktop.login1.Manager",
655 log_error("Failed to get session: %s", bus_error_message(&error, r));
659 r = sd_bus_message_read(reply, "o", &path);
661 return bus_log_parse_error(r);
664 r = show_properties(bus, path, &new_line);
666 r = print_session_status_info(bus, path, &new_line);
675 static int show_user(sd_bus *bus, char **args, unsigned n) {
676 bool properties, new_line = false;
683 properties = !strstr(args[0], "status");
685 pager_open_if_enabled();
687 if (properties && n <= 1) {
688 /* If not argument is specified inspect the manager
690 return show_properties(bus, "/org/freedesktop/login1", &new_line);
693 for (i = 1; i < n; i++) {
694 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
695 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
696 const char *path = NULL;
699 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
701 return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
703 r = sd_bus_call_method(
705 "org.freedesktop.login1",
706 "/org/freedesktop/login1",
707 "org.freedesktop.login1.Manager",
710 "u", (uint32_t) uid);
712 log_error("Failed to get user: %s", bus_error_message(&error, r));
716 r = sd_bus_message_read(reply, "o", &path);
718 return bus_log_parse_error(r);
721 r = show_properties(bus, path, &new_line);
723 r = print_user_status_info(bus, path, &new_line);
732 static int show_seat(sd_bus *bus, char **args, unsigned n) {
733 bool properties, new_line = false;
740 properties = !strstr(args[0], "status");
742 pager_open_if_enabled();
744 if (properties && n <= 1) {
745 /* If not argument is specified inspect the manager
747 return show_properties(bus, "/org/freedesktop/login1", &new_line);
750 for (i = 1; i < n; i++) {
751 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
752 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
753 const char *path = NULL;
755 r = sd_bus_call_method(
757 "org.freedesktop.login1",
758 "/org/freedesktop/login1",
759 "org.freedesktop.login1.Manager",
764 log_error("Failed to get seat: %s", bus_error_message(&error, r));
768 r = sd_bus_message_read(reply, "o", &path);
770 return bus_log_parse_error(r);
773 r = show_properties(bus, path, &new_line);
775 r = print_seat_status_info(bus, path, &new_line);
784 static int activate(sd_bus *bus, char **args, unsigned n) {
785 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
791 for (i = 1; i < n; i++) {
793 r = sd_bus_call_method (
795 "org.freedesktop.login1",
796 "/org/freedesktop/login1",
797 "org.freedesktop.login1.Manager",
798 streq(args[0], "lock-session") ? "LockSession" :
799 streq(args[0], "unlock-session") ? "UnlockSession" :
800 streq(args[0], "terminate-session") ? "TerminateSession" :
805 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
813 static int kill_session(sd_bus *bus, char **args, unsigned n) {
814 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
821 arg_kill_who = "all";
823 for (i = 1; i < n; i++) {
825 r = sd_bus_call_method (
827 "org.freedesktop.login1",
828 "/org/freedesktop/login1",
829 "org.freedesktop.login1.Manager",
832 "ssi", args[i], arg_kill_who, arg_signal);
834 log_error("Could not kill session: %s", bus_error_message(&error, -r));
842 static int enable_linger(sd_bus *bus, char **args, unsigned n) {
843 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
850 polkit_agent_open_if_enabled();
852 b = streq(args[0], "enable-linger");
854 for (i = 1; i < n; i++) {
857 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
859 return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
861 r = sd_bus_call_method (
863 "org.freedesktop.login1",
864 "/org/freedesktop/login1",
865 "org.freedesktop.login1.Manager",
868 "ubb", (uint32_t) uid, b, true);
870 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
878 static int terminate_user(sd_bus *bus, char **args, unsigned n) {
879 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
885 for (i = 1; i < n; i++) {
888 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
890 return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
892 r = sd_bus_call_method (
894 "org.freedesktop.login1",
895 "/org/freedesktop/login1",
896 "org.freedesktop.login1.Manager",
899 "u", (uint32_t) uid);
901 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
909 static int kill_user(sd_bus *bus, char **args, unsigned n) {
910 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
917 arg_kill_who = "all";
919 for (i = 1; i < n; i++) {
922 r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
924 return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
926 r = sd_bus_call_method (
928 "org.freedesktop.login1",
929 "/org/freedesktop/login1",
930 "org.freedesktop.login1.Manager",
933 "ui", (uint32_t) uid, arg_signal);
935 log_error("Could not kill user: %s", bus_error_message(&error, -r));
943 static int attach(sd_bus *bus, char **args, unsigned n) {
944 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
950 polkit_agent_open_if_enabled();
952 for (i = 2; i < n; i++) {
954 r = sd_bus_call_method (
956 "org.freedesktop.login1",
957 "/org/freedesktop/login1",
958 "org.freedesktop.login1.Manager",
961 "ssb", args[1], args[i], true);
964 log_error("Could not attach device: %s", bus_error_message(&error, -r));
972 static int flush_devices(sd_bus *bus, char **args, unsigned n) {
973 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
978 polkit_agent_open_if_enabled();
980 r = sd_bus_call_method (
982 "org.freedesktop.login1",
983 "/org/freedesktop/login1",
984 "org.freedesktop.login1.Manager",
989 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
994 static int lock_sessions(sd_bus *bus, char **args, unsigned n) {
995 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1000 r = sd_bus_call_method (
1002 "org.freedesktop.login1",
1003 "/org/freedesktop/login1",
1004 "org.freedesktop.login1.Manager",
1005 streq(args[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1009 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1014 static int terminate_seat(sd_bus *bus, char **args, unsigned n) {
1015 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1021 for (i = 1; i < n; i++) {
1023 r = sd_bus_call_method (
1025 "org.freedesktop.login1",
1026 "/org/freedesktop/login1",
1027 "org.freedesktop.login1.Manager",
1032 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1040 static void help(void) {
1041 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1042 "Send control commands to or query the login manager.\n\n"
1043 " -h --help Show this help\n"
1044 " --version Show package version\n"
1045 " --no-pager Do not pipe output into a pager\n"
1046 " --no-legend Do not show the headers and footers\n"
1047 " --no-ask-password Don't prompt for password\n"
1048 " -H --host=[USER@]HOST Operate on remote host\n"
1049 " -M --machine=CONTAINER Operate on local container\n"
1050 " -p --property=NAME Show only properties by this name\n"
1051 " -a --all Show all properties, including empty ones\n"
1052 " -l --full Do not ellipsize output\n"
1053 " --kill-who=WHO Who to send signal to\n"
1054 " -s --signal=SIGNAL Which signal to send\n\n"
1055 "Session Commands:\n"
1056 " list-sessions List sessions\n"
1057 " session-status ID... Show session status\n"
1058 " show-session [ID...] Show properties of sessions or the manager\n"
1059 " activate ID Activate a session\n"
1060 " lock-session ID... Screen lock one or more sessions\n"
1061 " unlock-session ID... Screen unlock one or more sessions\n"
1062 " lock-sessions Screen lock all current sessions\n"
1063 " unlock-sessions Screen unlock all current sessions\n"
1064 " terminate-session ID... Terminate one or more sessions\n"
1065 " kill-session ID... Send signal to processes of a session\n\n"
1067 " list-users List users\n"
1068 " user-status USER... Show user status\n"
1069 " show-user [USER...] Show properties of users or the manager\n"
1070 " enable-linger USER... Enable linger state of one or more users\n"
1071 " disable-linger USER... Disable linger state of one or more users\n"
1072 " terminate-user USER... Terminate all sessions of one or more users\n"
1073 " kill-user USER... Send signal to processes of a user\n\n"
1075 " list-seats List seats\n"
1076 " seat-status NAME... Show seat status\n"
1077 " show-seat NAME... Show properties of one or more seats\n"
1078 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1079 " flush-devices Flush all device associations\n"
1080 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1081 , program_invocation_short_name);
1084 static int parse_argv(int argc, char *argv[]) {
1087 ARG_VERSION = 0x100,
1091 ARG_NO_ASK_PASSWORD,
1094 static const struct option options[] = {
1095 { "help", no_argument, NULL, 'h' },
1096 { "version", no_argument, NULL, ARG_VERSION },
1097 { "property", required_argument, NULL, 'p' },
1098 { "all", no_argument, NULL, 'a' },
1099 { "full", no_argument, NULL, 'l' },
1100 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1101 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1102 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1103 { "signal", required_argument, NULL, 's' },
1104 { "host", required_argument, NULL, 'H' },
1105 { "machine", required_argument, NULL, 'M' },
1106 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1115 while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
1124 puts(PACKAGE_STRING);
1125 puts(SYSTEMD_FEATURES);
1129 r = strv_extend(&arg_property, optarg);
1133 /* If the user asked for a particular
1134 * property, show it to him, even if it is
1149 arg_no_pager = true;
1156 case ARG_NO_ASK_PASSWORD:
1157 arg_ask_password = false;
1161 arg_kill_who = optarg;
1165 arg_signal = signal_from_string_try_harder(optarg);
1166 if (arg_signal < 0) {
1167 log_error("Failed to parse signal string %s.", optarg);
1173 arg_transport = BUS_TRANSPORT_REMOTE;
1178 arg_transport = BUS_TRANSPORT_MACHINE;
1186 assert_not_reached("Unhandled option");
1192 static int loginctl_main(sd_bus *bus, int argc, char *argv[]) {
1194 static const struct {
1202 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1204 { "list-sessions", LESS, 1, list_sessions },
1205 { "session-status", MORE, 2, show_session },
1206 { "show-session", MORE, 1, show_session },
1207 { "activate", EQUAL, 2, activate },
1208 { "lock-session", MORE, 2, activate },
1209 { "unlock-session", MORE, 2, activate },
1210 { "lock-sessions", EQUAL, 1, lock_sessions },
1211 { "unlock-sessions", EQUAL, 1, lock_sessions },
1212 { "terminate-session", MORE, 2, activate },
1213 { "kill-session", MORE, 2, kill_session },
1214 { "list-users", EQUAL, 1, list_users },
1215 { "user-status", MORE, 2, show_user },
1216 { "show-user", MORE, 1, show_user },
1217 { "enable-linger", MORE, 2, enable_linger },
1218 { "disable-linger", MORE, 2, enable_linger },
1219 { "terminate-user", MORE, 2, terminate_user },
1220 { "kill-user", MORE, 2, kill_user },
1221 { "list-seats", EQUAL, 1, list_seats },
1222 { "seat-status", MORE, 2, show_seat },
1223 { "show-seat", MORE, 1, show_seat },
1224 { "attach", MORE, 3, attach },
1225 { "flush-devices", EQUAL, 1, flush_devices },
1226 { "terminate-seat", MORE, 2, terminate_seat },
1235 left = argc - optind;
1238 /* Special rule: no arguments means "list-sessions" */
1241 if (streq(argv[optind], "help")) {
1246 for (i = 0; i < ELEMENTSOF(verbs); i++)
1247 if (streq(argv[optind], verbs[i].verb))
1250 if (i >= ELEMENTSOF(verbs)) {
1251 log_error("Unknown operation %s", argv[optind]);
1256 switch (verbs[i].argc_cmp) {
1259 if (left != verbs[i].argc) {
1260 log_error("Invalid number of arguments.");
1267 if (left < verbs[i].argc) {
1268 log_error("Too few arguments.");
1275 if (left > verbs[i].argc) {
1276 log_error("Too many arguments.");
1283 assert_not_reached("Unknown comparison operator.");
1286 return verbs[i].dispatch(bus, argv + optind, left);
1289 int main(int argc, char *argv[]) {
1290 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1293 setlocale(LC_ALL, "");
1294 log_parse_environment();
1297 r = parse_argv(argc, argv);
1301 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1303 log_error_errno(r, "Failed to create bus connection: %m");
1307 r = loginctl_main(bus, argc, argv);
1312 strv_free(arg_property);
1314 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;