1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include "alloc-util.h"
30 #include "bus-error.h"
31 //#include "bus-unit-util.h"
33 //#include "cgroup-show.h"
34 #include "cgroup-util.h"
36 //#include "logs-show.h"
39 #include "parse-util.h"
40 #include "process-util.h"
42 #include "signal-util.h"
43 #include "spawn-polkit-agent.h"
45 #include "sysfs-show.h"
46 #include "terminal-util.h"
47 #include "unit-name.h"
48 #include "user-util.h"
52 /// Additional includes needed by elogind
53 #include "eloginctl.h"
55 static char **arg_property = NULL;
56 static bool arg_all = false;
57 static bool arg_value = false;
58 static bool arg_full = false;
59 static bool arg_no_pager = false;
60 static bool arg_legend = true;
61 static const char *arg_kill_who = NULL;
62 static int arg_signal = SIGTERM;
63 #if 0 /// UNNEEDED by elogind
64 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
65 static char *arg_host = NULL;
66 static bool arg_ask_password = true;
67 static unsigned arg_lines = 10;
68 static OutputMode arg_output = OUTPUT_SHORT;
70 /// Instead we need this:
71 extern BusTransport arg_transport;
72 static char *arg_host = NULL;
73 extern bool arg_ask_password;
74 extern bool arg_dry_run;
75 extern bool arg_quiet;
76 extern bool arg_no_wall;
77 extern usec_t arg_when;
78 extern bool arg_ignore_inhibitors;
79 extern elogind_action arg_action;
82 static OutputFlags get_output_flags(void) {
85 arg_all * OUTPUT_SHOW_ALL |
86 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
87 colors_enabled() * OUTPUT_COLOR;
90 static int get_session_path(sd_bus *bus, const char *session_id, sd_bus_error *error, char **path) {
91 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
95 r = sd_bus_call_method(
97 "org.freedesktop.login1",
98 "/org/freedesktop/login1",
99 "org.freedesktop.login1.Manager",
106 r = sd_bus_message_read(reply, "o", &ans);
118 static int list_sessions(int argc, char *argv[], void *userdata) {
119 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
120 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
121 const char *id, *user, *seat, *object;
122 sd_bus *bus = userdata;
130 (void) pager_open(arg_no_pager, false);
132 r = sd_bus_call_method(
134 "org.freedesktop.login1",
135 "/org/freedesktop/login1",
136 "org.freedesktop.login1.Manager",
141 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
145 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
147 return bus_log_parse_error(r);
150 printf("%10s %10s %-16s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT", "TTY");
152 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
153 _cleanup_(sd_bus_error_free) sd_bus_error error2 = SD_BUS_ERROR_NULL;
154 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply2 = NULL;
155 _cleanup_free_ char *path = NULL;
156 const char *tty = NULL;
158 r = get_session_path(bus, id, &error2, &path);
160 log_warning("Failed to get session path: %s", bus_error_message(&error, r));
162 r = sd_bus_get_property(
164 "org.freedesktop.login1",
166 "org.freedesktop.login1.Session",
172 log_warning("Failed to get TTY for session %s: %s",
173 id, bus_error_message(&error2, r));
175 r = sd_bus_message_read(reply2, "s", &tty);
177 return bus_log_parse_error(r);
181 printf("%10s %10"PRIu32" %-16s %-16s %-16s\n", id, uid, user, seat, strna(tty));
185 return bus_log_parse_error(r);
188 printf("\n%u sessions listed.\n", k);
193 static int list_users(int argc, char *argv[], void *userdata) {
194 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
195 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
196 const char *user, *object;
197 sd_bus *bus = userdata;
205 (void) pager_open(arg_no_pager, false);
207 r = sd_bus_call_method(
209 "org.freedesktop.login1",
210 "/org/freedesktop/login1",
211 "org.freedesktop.login1.Manager",
216 log_error("Failed to list users: %s", bus_error_message(&error, r));
220 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
222 return bus_log_parse_error(r);
225 printf("%10s %-16s\n", "UID", "USER");
227 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
228 printf("%10"PRIu32" %-16s\n", uid, user);
232 return bus_log_parse_error(r);
235 printf("\n%u users listed.\n", k);
240 static int list_seats(int argc, char *argv[], void *userdata) {
241 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
242 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
243 const char *seat, *object;
244 sd_bus *bus = userdata;
250 (void) pager_open(arg_no_pager, false);
252 r = sd_bus_call_method(
254 "org.freedesktop.login1",
255 "/org/freedesktop/login1",
256 "org.freedesktop.login1.Manager",
261 log_error("Failed to list seats: %s", bus_error_message(&error, r));
265 r = sd_bus_message_enter_container(reply, 'a', "(so)");
267 return bus_log_parse_error(r);
270 printf("%-16s\n", "SEAT");
272 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
273 printf("%-16s\n", seat);
277 return bus_log_parse_error(r);
280 printf("\n%u seats listed.\n", k);
285 #if 0 /// UNNEEDED by elogind
286 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
287 _cleanup_free_ char *cgroup = NULL;
288 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
295 r = show_cgroup_get_unit_path_and_warn(bus, unit, &cgroup);
308 r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error);
311 if (arg_transport == BUS_TRANSPORT_REMOTE)
314 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
316 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
319 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags());
321 return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
327 typedef struct SessionStatusInfo {
331 struct dual_timestamp timestamp;
337 const char *remote_host;
338 const char *remote_user;
348 typedef struct UserStatusInfo {
352 struct dual_timestamp timestamp;
359 typedef struct SeatStatusInfo {
361 const char *active_session;
365 static void user_status_info_clear(UserStatusInfo *info) {
367 strv_free(info->sessions);
372 static void seat_status_info_clear(SeatStatusInfo *info) {
374 strv_free(info->sessions);
379 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
380 const char *contents;
383 r = sd_bus_message_peek_type(m, NULL, &contents);
387 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
391 r = sd_bus_message_read_basic(m, contents[0], userdata);
395 r = sd_bus_message_skip(m, contents+1);
399 r = sd_bus_message_exit_container(m);
406 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
413 r = sd_bus_message_enter_container(m, 'a', "(so)");
417 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
418 r = strv_extend(userdata, name);
425 return sd_bus_message_exit_container(m);
428 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
430 static const struct bus_properties_map map[] = {
431 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
432 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
433 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
434 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
435 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
436 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
437 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
438 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
439 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
440 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
441 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
442 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
443 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
444 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
445 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
446 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
447 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
448 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
449 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
453 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
454 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
455 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
456 char since2[FORMAT_TIMESTAMP_MAX], *s2;
457 SessionStatusInfo i = {};
460 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, BUS_MAP_BOOLEAN_AS_BOOL, &error, &m, &i);
462 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
469 printf("%s - ", strna(i.id));
472 printf("%s (%"PRIu32")\n", i.name, i.uid);
474 printf("%"PRIu32"\n", i.uid);
476 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
477 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
480 printf("\t Since: %s; %s\n", s2, s1);
482 printf("\t Since: %s\n", s2);
485 _cleanup_free_ char *t = NULL;
487 printf("\t Leader: %"PRIu32, i.leader);
489 get_process_comm(i.leader, &t);
496 if (!isempty(i.seat)) {
497 printf("\t Seat: %s", i.seat);
500 printf("; vc%u", i.vtnr);
506 printf("\t TTY: %s\n", i.tty);
508 printf("\t Display: %s\n", i.display);
510 if (i.remote_host && i.remote_user)
511 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
512 else if (i.remote_host)
513 printf("\t Remote: %s\n", i.remote_host);
514 else if (i.remote_user)
515 printf("\t Remote: user %s\n", i.remote_user);
517 printf("\t Remote: Yes\n");
520 printf("\t Service: %s", i.service);
523 printf("; type %s", i.type);
526 printf("; class %s", i.class);
530 printf("\t Type: %s", i.type);
533 printf("; class %s", i.class);
537 printf("\t Class: %s\n", i.class);
539 if (!isempty(i.desktop))
540 printf("\t Desktop: %s\n", i.desktop);
543 printf("\t State: %s\n", i.state);
546 printf("\t Unit: %s\n", i.scope);
547 #if 0 /// UNNEEDED by elogind
548 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
550 if (arg_transport == BUS_TRANSPORT_LOCAL) {
552 show_journal_by_unit(
557 i.timestamp.monotonic,
560 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
561 SD_JOURNAL_LOCAL_ONLY,
571 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
573 static const struct bus_properties_map map[] = {
574 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
575 { "Linger", "b", NULL, offsetof(UserStatusInfo, linger) },
576 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
577 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
578 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
579 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
580 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
581 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
582 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
586 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
587 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
588 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
589 char since2[FORMAT_TIMESTAMP_MAX], *s2;
590 _cleanup_(user_status_info_clear) UserStatusInfo i = {};
593 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, BUS_MAP_BOOLEAN_AS_BOOL, &error, &m, &i);
595 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
603 printf("%s (%"PRIu32")\n", i.name, i.uid);
605 printf("%"PRIu32"\n", i.uid);
607 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
608 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
611 printf("\t Since: %s; %s\n", s2, s1);
613 printf("\t Since: %s\n", s2);
615 if (!isempty(i.state))
616 printf("\t State: %s\n", i.state);
618 if (!strv_isempty(i.sessions)) {
620 printf("\tSessions:");
622 STRV_FOREACH(l, i.sessions)
624 streq_ptr(*l, i.display) ? "*" : "",
630 printf("\t Linger: %s\n", yes_no(i.linger));
633 printf("\t Unit: %s\n", i.slice);
634 #if 0 /// UNNEEDED by elogind
635 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
637 show_journal_by_unit(
642 i.timestamp.monotonic,
645 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
646 SD_JOURNAL_LOCAL_ONLY,
655 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
657 static const struct bus_properties_map map[] = {
658 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
659 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
660 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
664 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
665 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
666 _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
669 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, 0, &error, &m, &i);
671 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
678 printf("%s\n", strna(i.id));
680 if (!strv_isempty(i.sessions)) {
682 printf("\tSessions:");
684 STRV_FOREACH(l, i.sessions) {
685 if (streq_ptr(*l, i.active_session))
694 if (arg_transport == BUS_TRANSPORT_LOCAL) {
703 printf("\t Devices:\n");
705 show_sysfs(i.id, "\t\t ", c, get_output_flags());
711 #define property(name, fmt, ...) \
714 printf(fmt "\n", __VA_ARGS__); \
716 printf("%s=" fmt "\n", name, __VA_ARGS__); \
719 static int print_property(const char *name, sd_bus_message *m, bool value, bool all) {
721 const char *contents;
727 r = sd_bus_message_peek_type(m, &type, &contents);
733 case SD_BUS_TYPE_STRUCT:
735 if (contents[0] == SD_BUS_TYPE_STRING && STR_IN_SET(name, "Display", "Seat", "ActiveSession")) {
738 r = sd_bus_message_read(m, "(so)", &s, NULL);
740 return bus_log_parse_error(r);
742 if (all || !isempty(s))
743 property(name, "%s", s);
747 } else if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "User")) {
750 r = sd_bus_message_read(m, "(uo)", &uid, NULL);
752 return bus_log_parse_error(r);
754 if (!uid_is_valid(uid)) {
755 log_error("Invalid user ID: " UID_FMT, uid);
759 property(name, UID_FMT, uid);
764 case SD_BUS_TYPE_ARRAY:
766 if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Sessions")) {
770 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(so)");
772 return bus_log_parse_error(r);
777 while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
778 printf("%s%s", space ? " " : "", s);
786 return bus_log_parse_error(r);
788 r = sd_bus_message_exit_container(m);
790 return bus_log_parse_error(r);
800 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
801 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
802 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
814 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, print_property, arg_property, arg_value, arg_all, NULL);
816 return bus_log_parse_error(r);
821 static int show_session(int argc, char *argv[], void *userdata) {
822 bool properties, new_line = false;
823 sd_bus *bus = userdata;
825 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
826 _cleanup_free_ char *path = NULL;
831 properties = !strstr(argv[0], "status");
833 (void) pager_open(arg_no_pager, false);
836 const char *session, *p = "/org/freedesktop/login1/session/self";
839 /* If no argument is specified inspect the manager itself */
840 return show_properties(bus, "/org/freedesktop/login1", &new_line);
842 /* And in the pretty case, show data of the calling session */
843 session = getenv("XDG_SESSION_ID");
845 r = get_session_path(bus, session, &error, &path);
847 log_error("Failed to get session path: %s", bus_error_message(&error, r));
853 return print_session_status_info(bus, p, &new_line);
856 for (i = 1; i < argc; i++) {
857 r = get_session_path(bus, argv[i], &error, &path);
859 log_error("Failed to get session path: %s", bus_error_message(&error, r));
864 r = show_properties(bus, path, &new_line);
866 r = print_session_status_info(bus, path, &new_line);
875 static int show_user(int argc, char *argv[], void *userdata) {
876 bool properties, new_line = false;
877 sd_bus *bus = userdata;
883 properties = !strstr(argv[0], "status");
885 (void) pager_open(arg_no_pager, false);
888 /* If not argument is specified inspect the manager
891 return show_properties(bus, "/org/freedesktop/login1", &new_line);
893 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
896 for (i = 1; i < argc; i++) {
897 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
898 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
899 const char *path = NULL;
902 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
904 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
906 r = sd_bus_call_method(
908 "org.freedesktop.login1",
909 "/org/freedesktop/login1",
910 "org.freedesktop.login1.Manager",
913 "u", (uint32_t) uid);
915 log_error("Failed to get user: %s", bus_error_message(&error, r));
919 r = sd_bus_message_read(reply, "o", &path);
921 return bus_log_parse_error(r);
924 r = show_properties(bus, path, &new_line);
926 r = print_user_status_info(bus, path, &new_line);
935 static int show_seat(int argc, char *argv[], void *userdata) {
936 bool properties, new_line = false;
937 sd_bus *bus = userdata;
943 properties = !strstr(argv[0], "status");
945 (void) pager_open(arg_no_pager, false);
948 /* If not argument is specified inspect the manager
951 return show_properties(bus, "/org/freedesktop/login1", &new_line);
953 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
956 for (i = 1; i < argc; i++) {
957 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
958 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
959 const char *path = NULL;
961 r = sd_bus_call_method(
963 "org.freedesktop.login1",
964 "/org/freedesktop/login1",
965 "org.freedesktop.login1.Manager",
970 log_error("Failed to get seat: %s", bus_error_message(&error, r));
974 r = sd_bus_message_read(reply, "o", &path);
976 return bus_log_parse_error(r);
979 r = show_properties(bus, path, &new_line);
981 r = print_seat_status_info(bus, path, &new_line);
990 static int activate(int argc, char *argv[], void *userdata) {
991 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
992 sd_bus *bus = userdata;
999 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1002 /* No argument? Let's either use $XDG_SESSION_ID (if specified), or an empty
1003 * session name, in which case logind will try to guess our session. */
1005 short_argv[0] = argv[0];
1006 short_argv[1] = getenv("XDG_SESSION_ID") ?: (char*) "";
1007 short_argv[2] = NULL;
1013 for (i = 1; i < argc; i++) {
1015 r = sd_bus_call_method(
1017 "org.freedesktop.login1",
1018 "/org/freedesktop/login1",
1019 "org.freedesktop.login1.Manager",
1020 streq(argv[0], "lock-session") ? "LockSession" :
1021 streq(argv[0], "unlock-session") ? "UnlockSession" :
1022 streq(argv[0], "terminate-session") ? "TerminateSession" :
1027 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
1035 static int kill_session(int argc, char *argv[], void *userdata) {
1036 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1037 sd_bus *bus = userdata;
1043 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1046 arg_kill_who = "all";
1048 for (i = 1; i < argc; i++) {
1050 r = sd_bus_call_method(
1052 "org.freedesktop.login1",
1053 "/org/freedesktop/login1",
1054 "org.freedesktop.login1.Manager",
1057 "ssi", argv[i], arg_kill_who, arg_signal);
1059 log_error("Could not kill session: %s", bus_error_message(&error, -r));
1067 static int enable_linger(int argc, char *argv[], void *userdata) {
1068 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1069 sd_bus *bus = userdata;
1070 char* short_argv[3];
1077 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1079 b = streq(argv[0], "enable-linger");
1082 /* No argument? Let's use an empty user name,
1083 * then logind will use our user. */
1085 short_argv[0] = argv[0];
1086 short_argv[1] = (char*) "";
1087 short_argv[2] = NULL;
1092 for (i = 1; i < argc; i++) {
1095 if (isempty(argv[i]))
1098 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1100 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1103 r = sd_bus_call_method(
1105 "org.freedesktop.login1",
1106 "/org/freedesktop/login1",
1107 "org.freedesktop.login1.Manager",
1110 "ubb", (uint32_t) uid, b, true);
1112 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1120 static int terminate_user(int argc, char *argv[], void *userdata) {
1121 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1122 sd_bus *bus = userdata;
1128 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1130 for (i = 1; i < argc; i++) {
1133 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1135 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1137 r = sd_bus_call_method(
1139 "org.freedesktop.login1",
1140 "/org/freedesktop/login1",
1141 "org.freedesktop.login1.Manager",
1144 "u", (uint32_t) uid);
1146 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1154 static int kill_user(int argc, char *argv[], void *userdata) {
1155 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1156 sd_bus *bus = userdata;
1162 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1165 arg_kill_who = "all";
1167 for (i = 1; i < argc; i++) {
1170 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1172 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1174 r = sd_bus_call_method(
1176 "org.freedesktop.login1",
1177 "/org/freedesktop/login1",
1178 "org.freedesktop.login1.Manager",
1181 "ui", (uint32_t) uid, arg_signal);
1183 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1191 static int attach(int argc, char *argv[], void *userdata) {
1192 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1193 sd_bus *bus = userdata;
1199 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1201 for (i = 2; i < argc; i++) {
1203 r = sd_bus_call_method(
1205 "org.freedesktop.login1",
1206 "/org/freedesktop/login1",
1207 "org.freedesktop.login1.Manager",
1210 "ssb", argv[1], argv[i], true);
1213 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1221 static int flush_devices(int argc, char *argv[], void *userdata) {
1222 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1223 sd_bus *bus = userdata;
1229 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1231 r = sd_bus_call_method(
1233 "org.freedesktop.login1",
1234 "/org/freedesktop/login1",
1235 "org.freedesktop.login1.Manager",
1240 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1245 static int lock_sessions(int argc, char *argv[], void *userdata) {
1246 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1247 sd_bus *bus = userdata;
1253 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1255 r = sd_bus_call_method(
1257 "org.freedesktop.login1",
1258 "/org/freedesktop/login1",
1259 "org.freedesktop.login1.Manager",
1260 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1264 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1269 static int terminate_seat(int argc, char *argv[], void *userdata) {
1270 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1271 sd_bus *bus = userdata;
1277 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1279 for (i = 1; i < argc; i++) {
1281 r = sd_bus_call_method(
1283 "org.freedesktop.login1",
1284 "/org/freedesktop/login1",
1285 "org.freedesktop.login1.Manager",
1290 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1298 static int help(int argc, char *argv[], void *userdata) {
1300 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1301 "Send control commands to or query the login manager.\n\n"
1302 " -h --help Show this help\n"
1303 " --version Show package version\n"
1304 " --no-pager Do not pipe output into a pager\n"
1305 #if 1 /// elogind supports --no-wall and --dry-run
1306 " --no-wall Do not print any wall message\n"
1307 " --dry-run Only print what would be done\n"
1308 " -q --quiet Suppress output\n"
1310 " --no-legend Do not show the headers and footers\n"
1311 " --no-ask-password Don't prompt for password\n"
1312 " -H --host=[USER@]HOST Operate on remote host\n"
1313 " -M --machine=CONTAINER Operate on local container\n"
1314 " -p --property=NAME Show only properties by this name\n"
1315 " -a --all Show all properties, including empty ones\n"
1316 " --value When showing properties, only print the value\n"
1317 " -l --full Do not ellipsize output\n"
1318 " --kill-who=WHO Who to send signal to\n"
1319 " -s --signal=SIGNAL Which signal to send\n"
1320 #if 0 /// UNNEEDED by elogind
1321 " -n --lines=INTEGER Number of journal entries to show\n"
1322 " -o --output=STRING Change journal output mode (short, short-precise,\n"
1323 " short-iso, short-iso-precise, short-full,\n"
1324 " short-monotonic, short-unix, verbose, export,\n"
1325 " json, json-pretty, json-sse, cat)\n"
1327 /// elogind can cancel shutdowns and allows to ignore inhibitors
1328 " -c Cancel a pending shutdown or reboot\n"
1329 " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n\n"
1331 "Session Commands:\n"
1332 #if 0 /// elogind has "list" as a shorthand for "list-sessions"
1333 " list-sessions List sessions\n"
1335 " list[-sessions] List sessions (default command)\n"
1337 " session-status [ID...] Show session status\n"
1338 " show-session [ID...] Show properties of sessions or the manager\n"
1339 " activate [ID] Activate a session\n"
1340 " lock-session [ID...] Screen lock one or more sessions\n"
1341 " unlock-session [ID...] Screen unlock one or more sessions\n"
1342 " lock-sessions Screen lock all current sessions\n"
1343 " unlock-sessions Screen unlock all current sessions\n"
1344 " terminate-session ID... Terminate one or more sessions\n"
1345 " kill-session ID... Send signal to processes of a session\n\n"
1347 " list-users List users\n"
1348 " user-status [USER...] Show user status\n"
1349 " show-user [USER...] Show properties of users or the manager\n"
1350 " enable-linger [USER...] Enable linger state of one or more users\n"
1351 " disable-linger [USER...] Disable linger state of one or more users\n"
1352 " terminate-user USER... Terminate all sessions of one or more users\n"
1353 " kill-user USER... Send signal to processes of a user\n\n"
1355 " list-seats List seats\n"
1356 " seat-status [NAME...] Show seat status\n"
1357 " show-seat [NAME...] Show properties of seats or the manager\n"
1358 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1359 " flush-devices Flush all device associations\n"
1360 #if 0 /// elogind adds some system commands to loginctl
1361 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1363 " terminate-seat NAME... Terminate all sessions on one or more seats\n\n"
1364 "System Commands:\n"
1365 " poweroff [TIME] [WALL...] Turn off the machine\n"
1366 " reboot [TIME] [WALL...] Reboot the machine\n"
1367 " suspend Suspend the machine to memory\n"
1368 " hibernate Suspend the machine to disk\n"
1369 " hybrid-sleep Suspend the machine to memory and disk\n"
1371 , program_invocation_short_name);
1376 static int parse_argv(int argc, char *argv[]) {
1379 ARG_VERSION = 0x100,
1382 #if 1 /// elogind supports --no-wall and --dry-run
1388 ARG_NO_ASK_PASSWORD,
1391 static const struct option options[] = {
1392 { "help", no_argument, NULL, 'h' },
1393 { "version", no_argument, NULL, ARG_VERSION },
1394 { "property", required_argument, NULL, 'p' },
1395 { "all", no_argument, NULL, 'a' },
1396 { "value", no_argument, NULL, ARG_VALUE },
1397 { "full", no_argument, NULL, 'l' },
1398 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1399 #if 1 /// elogind supports --no-wall, --dry-run and --quiet
1400 { "no-wall", no_argument, NULL, ARG_NO_WALL },
1401 { "dry-run", no_argument, NULL, ARG_DRY_RUN },
1402 { "quiet", no_argument, NULL, 'q' },
1404 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1405 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1406 { "signal", required_argument, NULL, 's' },
1407 { "host", required_argument, NULL, 'H' },
1408 { "machine", required_argument, NULL, 'M' },
1409 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1410 #if 0 /// UNNEEDED by elogind
1411 { "lines", required_argument, NULL, 'n' },
1412 { "output", required_argument, NULL, 'o' },
1414 /// elogind allows to ignore inhibitors for system commands.
1415 { "ignore-inhibitors", no_argument, NULL, 'i' },
1425 #if 0 /// elogind adds some system commands to loginctl
1426 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1428 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:ci", options, NULL)) >= 0)
1434 help(0, NULL, NULL);
1441 r = strv_extend(&arg_property, optarg);
1445 /* If the user asked for a particular
1446 * property, show it to him, even if it is
1464 #if 0 /// UNNEEDED by elogind
1466 if (safe_atou(optarg, &arg_lines) < 0) {
1467 log_error("Failed to parse lines '%s'", optarg);
1473 arg_output = output_mode_from_string(optarg);
1474 if (arg_output < 0) {
1475 log_error("Unknown output '%s'.", optarg);
1482 arg_no_pager = true;
1484 #if 1 /// elogind supports --no-wall, -dry-run and --quiet
1503 case ARG_NO_ASK_PASSWORD:
1504 arg_ask_password = false;
1508 arg_kill_who = optarg;
1512 arg_signal = signal_from_string_try_harder(optarg);
1513 if (arg_signal < 0) {
1514 log_error("Failed to parse signal string %s.", optarg);
1520 arg_transport = BUS_TRANSPORT_REMOTE;
1525 arg_transport = BUS_TRANSPORT_MACHINE;
1528 #if 1 /// elogind can cancel shutdowns and allows to ignore inhibitors
1530 arg_action = ACTION_CANCEL_SHUTDOWN;
1534 arg_ignore_inhibitors = true;
1541 assert_not_reached("Unhandled option");
1547 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1549 static const Verb verbs[] = {
1550 { "help", VERB_ANY, VERB_ANY, 0, help },
1551 #if 0 /// elogind has "list" as a shorthand for "list-sessions"
1552 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1554 { "list", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1555 { "list-sessions", VERB_ANY, 1, 0, list_sessions },
1557 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1558 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1559 { "activate", VERB_ANY, 2, 0, activate },
1560 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1561 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1562 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1563 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1564 { "terminate-session", 2, VERB_ANY, 0, activate },
1565 { "kill-session", 2, VERB_ANY, 0, kill_session },
1566 { "list-users", VERB_ANY, 1, 0, list_users },
1567 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1568 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1569 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1570 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1571 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1572 { "kill-user", 2, VERB_ANY, 0, kill_user },
1573 { "list-seats", VERB_ANY, 1, 0, list_seats },
1574 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1575 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1576 { "attach", 3, VERB_ANY, 0, attach },
1577 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1578 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1579 #if 1 /// elogind adds some system commands to loginctl
1580 { "poweroff", VERB_ANY, VERB_ANY, 0, start_special },
1581 { "reboot", VERB_ANY, VERB_ANY, 0, start_special },
1582 { "suspend", VERB_ANY, 1, 0, start_special },
1583 { "hibernate", VERB_ANY, 1, 0, start_special },
1584 { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
1585 { "cancel-shutdown", VERB_ANY, 1, 0, start_special },
1590 #if 1 /// elogind can do shutdown and allows its cancellation
1591 if ((argc == optind) && (ACTION_CANCEL_SHUTDOWN == arg_action))
1592 return elogind_cancel_shutdown(bus);
1594 return dispatch_verb(argc, argv, verbs, bus);
1597 int main(int argc, char *argv[]) {
1601 setlocale(LC_ALL, "");
1602 elogind_set_program_name(argv[0]);
1603 log_parse_environment();
1607 r = parse_argv(argc, argv);
1611 r = bus_connect_transport(arg_transport, arg_host, false, &bus);
1613 log_error_errno(r, "Failed to create bus connection: %m");
1617 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1619 r = loginctl_main(argc, argv, bus);
1622 /* make sure we terminate the bus connection first, and then close the
1623 * pager, see issue #3543 for the details. */
1624 sd_bus_flush_close_unref(bus);
1626 #if 0 /// elogind does that in elogind_cleanup()
1627 polkit_agent_close();
1630 strv_free(arg_property);
1632 #if 1 /// elogind has some own cleanups to do
1635 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;