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) {
812 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, print_property, arg_property, arg_value, arg_all, NULL);
814 return bus_log_parse_error(r);
819 static int show_session(int argc, char *argv[], void *userdata) {
820 bool properties, new_line = false;
821 sd_bus *bus = userdata;
823 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
824 _cleanup_free_ char *path = NULL;
829 properties = !strstr(argv[0], "status");
831 (void) pager_open(arg_no_pager, false);
834 const char *session, *p = "/org/freedesktop/login1/session/self";
837 /* If no argument is specified inspect the manager itself */
838 return show_properties(bus, "/org/freedesktop/login1", &new_line);
840 /* And in the pretty case, show data of the calling session */
841 session = getenv("XDG_SESSION_ID");
843 r = get_session_path(bus, session, &error, &path);
845 log_error("Failed to get session path: %s", bus_error_message(&error, r));
851 return print_session_status_info(bus, p, &new_line);
854 for (i = 1; i < argc; i++) {
855 r = get_session_path(bus, argv[i], &error, &path);
857 log_error("Failed to get session path: %s", bus_error_message(&error, r));
862 r = show_properties(bus, path, &new_line);
864 r = print_session_status_info(bus, path, &new_line);
873 static int show_user(int argc, char *argv[], void *userdata) {
874 bool properties, new_line = false;
875 sd_bus *bus = userdata;
881 properties = !strstr(argv[0], "status");
883 (void) pager_open(arg_no_pager, false);
886 /* If not argument is specified inspect the manager
889 return show_properties(bus, "/org/freedesktop/login1", &new_line);
891 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
894 for (i = 1; i < argc; i++) {
895 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
896 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
897 const char *path = NULL;
900 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
902 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
904 r = sd_bus_call_method(
906 "org.freedesktop.login1",
907 "/org/freedesktop/login1",
908 "org.freedesktop.login1.Manager",
911 "u", (uint32_t) uid);
913 log_error("Failed to get user: %s", bus_error_message(&error, r));
917 r = sd_bus_message_read(reply, "o", &path);
919 return bus_log_parse_error(r);
922 r = show_properties(bus, path, &new_line);
924 r = print_user_status_info(bus, path, &new_line);
933 static int show_seat(int argc, char *argv[], void *userdata) {
934 bool properties, new_line = false;
935 sd_bus *bus = userdata;
941 properties = !strstr(argv[0], "status");
943 (void) pager_open(arg_no_pager, false);
946 /* If not argument is specified inspect the manager
949 return show_properties(bus, "/org/freedesktop/login1", &new_line);
951 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
954 for (i = 1; i < argc; i++) {
955 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
956 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
957 const char *path = NULL;
959 r = sd_bus_call_method(
961 "org.freedesktop.login1",
962 "/org/freedesktop/login1",
963 "org.freedesktop.login1.Manager",
968 log_error("Failed to get seat: %s", bus_error_message(&error, r));
972 r = sd_bus_message_read(reply, "o", &path);
974 return bus_log_parse_error(r);
977 r = show_properties(bus, path, &new_line);
979 r = print_seat_status_info(bus, path, &new_line);
988 static int activate(int argc, char *argv[], void *userdata) {
989 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
990 sd_bus *bus = userdata;
997 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1000 /* No argument? Let's either use $XDG_SESSION_ID (if specified), or an empty
1001 * session name, in which case logind will try to guess our session. */
1003 short_argv[0] = argv[0];
1004 short_argv[1] = getenv("XDG_SESSION_ID") ?: (char*) "";
1005 short_argv[2] = NULL;
1011 for (i = 1; i < argc; i++) {
1013 r = sd_bus_call_method(
1015 "org.freedesktop.login1",
1016 "/org/freedesktop/login1",
1017 "org.freedesktop.login1.Manager",
1018 streq(argv[0], "lock-session") ? "LockSession" :
1019 streq(argv[0], "unlock-session") ? "UnlockSession" :
1020 streq(argv[0], "terminate-session") ? "TerminateSession" :
1025 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
1033 static int kill_session(int argc, char *argv[], void *userdata) {
1034 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1035 sd_bus *bus = userdata;
1041 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1044 arg_kill_who = "all";
1046 for (i = 1; i < argc; i++) {
1048 r = sd_bus_call_method(
1050 "org.freedesktop.login1",
1051 "/org/freedesktop/login1",
1052 "org.freedesktop.login1.Manager",
1055 "ssi", argv[i], arg_kill_who, arg_signal);
1057 log_error("Could not kill session: %s", bus_error_message(&error, -r));
1065 static int enable_linger(int argc, char *argv[], void *userdata) {
1066 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1067 sd_bus *bus = userdata;
1068 char* short_argv[3];
1075 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1077 b = streq(argv[0], "enable-linger");
1080 /* No argument? Let's use an empty user name,
1081 * then logind will use our user. */
1083 short_argv[0] = argv[0];
1084 short_argv[1] = (char*) "";
1085 short_argv[2] = NULL;
1090 for (i = 1; i < argc; i++) {
1093 if (isempty(argv[i]))
1096 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1098 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1101 r = sd_bus_call_method(
1103 "org.freedesktop.login1",
1104 "/org/freedesktop/login1",
1105 "org.freedesktop.login1.Manager",
1108 "ubb", (uint32_t) uid, b, true);
1110 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1118 static int terminate_user(int argc, char *argv[], void *userdata) {
1119 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1120 sd_bus *bus = userdata;
1126 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1128 for (i = 1; i < argc; i++) {
1131 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1133 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1135 r = sd_bus_call_method(
1137 "org.freedesktop.login1",
1138 "/org/freedesktop/login1",
1139 "org.freedesktop.login1.Manager",
1142 "u", (uint32_t) uid);
1144 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1152 static int kill_user(int argc, char *argv[], void *userdata) {
1153 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1154 sd_bus *bus = userdata;
1160 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1163 arg_kill_who = "all";
1165 for (i = 1; i < argc; i++) {
1168 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1170 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1172 r = sd_bus_call_method(
1174 "org.freedesktop.login1",
1175 "/org/freedesktop/login1",
1176 "org.freedesktop.login1.Manager",
1179 "ui", (uint32_t) uid, arg_signal);
1181 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1189 static int attach(int argc, char *argv[], void *userdata) {
1190 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1191 sd_bus *bus = userdata;
1197 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1199 for (i = 2; i < argc; i++) {
1201 r = sd_bus_call_method(
1203 "org.freedesktop.login1",
1204 "/org/freedesktop/login1",
1205 "org.freedesktop.login1.Manager",
1208 "ssb", argv[1], argv[i], true);
1211 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1219 static int flush_devices(int argc, char *argv[], void *userdata) {
1220 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1221 sd_bus *bus = userdata;
1227 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1229 r = sd_bus_call_method(
1231 "org.freedesktop.login1",
1232 "/org/freedesktop/login1",
1233 "org.freedesktop.login1.Manager",
1238 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1243 static int lock_sessions(int argc, char *argv[], void *userdata) {
1244 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1245 sd_bus *bus = userdata;
1251 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1253 r = sd_bus_call_method(
1255 "org.freedesktop.login1",
1256 "/org/freedesktop/login1",
1257 "org.freedesktop.login1.Manager",
1258 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1262 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1267 static int terminate_seat(int argc, char *argv[], void *userdata) {
1268 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1269 sd_bus *bus = userdata;
1275 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1277 for (i = 1; i < argc; i++) {
1279 r = sd_bus_call_method(
1281 "org.freedesktop.login1",
1282 "/org/freedesktop/login1",
1283 "org.freedesktop.login1.Manager",
1288 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1296 static int help(int argc, char *argv[], void *userdata) {
1298 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1299 "Send control commands to or query the login manager.\n\n"
1300 " -h --help Show this help\n"
1301 " --version Show package version\n"
1302 " --no-pager Do not pipe output into a pager\n"
1303 #if 1 /// elogind supports --no-wall and --dry-run
1304 " --no-wall Do not print any wall message\n"
1305 " --dry-run Only print what would be done\n"
1306 " -q --quiet Suppress output\n"
1308 " --no-legend Do not show the headers and footers\n"
1309 " --no-ask-password Don't prompt for password\n"
1310 " -H --host=[USER@]HOST Operate on remote host\n"
1311 " -M --machine=CONTAINER Operate on local container\n"
1312 " -p --property=NAME Show only properties by this name\n"
1313 " -a --all Show all properties, including empty ones\n"
1314 " --value When showing properties, only print the value\n"
1315 " -l --full Do not ellipsize output\n"
1316 " --kill-who=WHO Who to send signal to\n"
1317 " -s --signal=SIGNAL Which signal to send\n"
1318 #if 0 /// UNNEEDED by elogind
1319 " -n --lines=INTEGER Number of journal entries to show\n"
1320 " -o --output=STRING Change journal output mode (short, short-precise,\n"
1321 " short-iso, short-iso-precise, short-full,\n"
1322 " short-monotonic, short-unix, verbose, export,\n"
1323 " json, json-pretty, json-sse, cat)\n"
1325 /// elogind can cancel shutdowns and allows to ignore inhibitors
1326 " -c Cancel a pending shutdown or reboot\n"
1327 " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n\n"
1329 "Session Commands:\n"
1330 #if 0 /// elogind has "list" as a shorthand for "list-sessions"
1331 " list-sessions List sessions\n"
1333 " list[-sessions] List sessions (default command)\n"
1335 " session-status [ID...] Show session status\n"
1336 " show-session [ID...] Show properties of sessions or the manager\n"
1337 " activate [ID] Activate a session\n"
1338 " lock-session [ID...] Screen lock one or more sessions\n"
1339 " unlock-session [ID...] Screen unlock one or more sessions\n"
1340 " lock-sessions Screen lock all current sessions\n"
1341 " unlock-sessions Screen unlock all current sessions\n"
1342 " terminate-session ID... Terminate one or more sessions\n"
1343 " kill-session ID... Send signal to processes of a session\n\n"
1345 " list-users List users\n"
1346 " user-status [USER...] Show user status\n"
1347 " show-user [USER...] Show properties of users or the manager\n"
1348 " enable-linger [USER...] Enable linger state of one or more users\n"
1349 " disable-linger [USER...] Disable linger state of one or more users\n"
1350 " terminate-user USER... Terminate all sessions of one or more users\n"
1351 " kill-user USER... Send signal to processes of a user\n\n"
1353 " list-seats List seats\n"
1354 " seat-status [NAME...] Show seat status\n"
1355 " show-seat [NAME...] Show properties of seats or the manager\n"
1356 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1357 " flush-devices Flush all device associations\n"
1358 #if 0 /// elogind adds some system commands to loginctl
1359 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1361 " terminate-seat NAME... Terminate all sessions on one or more seats\n\n"
1362 "System Commands:\n"
1363 " poweroff [TIME] [WALL...] Turn off the machine\n"
1364 " reboot [TIME] [WALL...] Reboot the machine\n"
1365 " suspend Suspend the machine to memory\n"
1366 " hibernate Suspend the machine to disk\n"
1367 " hybrid-sleep Suspend the machine to memory and disk\n"
1369 , program_invocation_short_name);
1374 static int parse_argv(int argc, char *argv[]) {
1377 ARG_VERSION = 0x100,
1380 #if 1 /// elogind supports --no-wall and --dry-run
1386 ARG_NO_ASK_PASSWORD,
1389 static const struct option options[] = {
1390 { "help", no_argument, NULL, 'h' },
1391 { "version", no_argument, NULL, ARG_VERSION },
1392 { "property", required_argument, NULL, 'p' },
1393 { "all", no_argument, NULL, 'a' },
1394 { "value", no_argument, NULL, ARG_VALUE },
1395 { "full", no_argument, NULL, 'l' },
1396 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1397 #if 1 /// elogind supports --no-wall, --dry-run and --quiet
1398 { "no-wall", no_argument, NULL, ARG_NO_WALL },
1399 { "dry-run", no_argument, NULL, ARG_DRY_RUN },
1400 { "quiet", no_argument, NULL, 'q' },
1402 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1403 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1404 { "signal", required_argument, NULL, 's' },
1405 { "host", required_argument, NULL, 'H' },
1406 { "machine", required_argument, NULL, 'M' },
1407 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1408 #if 0 /// UNNEEDED by elogind
1409 { "lines", required_argument, NULL, 'n' },
1410 { "output", required_argument, NULL, 'o' },
1412 /// elogind allows to ignore inhibitors for system commands.
1413 { "ignore-inhibitors", no_argument, NULL, 'i' },
1423 #if 0 /// elogind adds some system commands to loginctl
1424 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1426 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:ci", options, NULL)) >= 0)
1432 help(0, NULL, NULL);
1439 r = strv_extend(&arg_property, optarg);
1443 /* If the user asked for a particular
1444 * property, show it to him, even if it is
1462 #if 0 /// UNNEEDED by elogind
1464 if (safe_atou(optarg, &arg_lines) < 0) {
1465 log_error("Failed to parse lines '%s'", optarg);
1471 arg_output = output_mode_from_string(optarg);
1472 if (arg_output < 0) {
1473 log_error("Unknown output '%s'.", optarg);
1480 arg_no_pager = true;
1482 #if 1 /// elogind supports --no-wall, -dry-run and --quiet
1501 case ARG_NO_ASK_PASSWORD:
1502 arg_ask_password = false;
1506 arg_kill_who = optarg;
1510 arg_signal = signal_from_string_try_harder(optarg);
1511 if (arg_signal < 0) {
1512 log_error("Failed to parse signal string %s.", optarg);
1518 arg_transport = BUS_TRANSPORT_REMOTE;
1523 arg_transport = BUS_TRANSPORT_MACHINE;
1526 #if 1 /// elogind can cancel shutdowns and allows to ignore inhibitors
1528 arg_action = ACTION_CANCEL_SHUTDOWN;
1532 arg_ignore_inhibitors = true;
1539 assert_not_reached("Unhandled option");
1545 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1547 static const Verb verbs[] = {
1548 { "help", VERB_ANY, VERB_ANY, 0, help },
1549 #if 0 /// elogind has "list" as a shorthand for "list-sessions"
1550 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1552 { "list", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1553 { "list-sessions", VERB_ANY, 1, 0, list_sessions },
1555 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1556 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1557 { "activate", VERB_ANY, 2, 0, activate },
1558 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1559 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1560 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1561 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1562 { "terminate-session", 2, VERB_ANY, 0, activate },
1563 { "kill-session", 2, VERB_ANY, 0, kill_session },
1564 { "list-users", VERB_ANY, 1, 0, list_users },
1565 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1566 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1567 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1568 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1569 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1570 { "kill-user", 2, VERB_ANY, 0, kill_user },
1571 { "list-seats", VERB_ANY, 1, 0, list_seats },
1572 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1573 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1574 { "attach", 3, VERB_ANY, 0, attach },
1575 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1576 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1577 #if 1 /// elogind adds some system commands to loginctl
1578 { "poweroff", VERB_ANY, VERB_ANY, 0, start_special },
1579 { "reboot", VERB_ANY, VERB_ANY, 0, start_special },
1580 { "suspend", VERB_ANY, 1, 0, start_special },
1581 { "hibernate", VERB_ANY, 1, 0, start_special },
1582 { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
1583 { "cancel-shutdown", VERB_ANY, 1, 0, start_special },
1588 #if 1 /// elogind can do shutdown and allows its cancellation
1589 if ((argc == optind) && (ACTION_CANCEL_SHUTDOWN == arg_action))
1590 return elogind_cancel_shutdown(bus);
1592 return dispatch_verb(argc, argv, verbs, bus);
1595 int main(int argc, char *argv[]) {
1599 setlocale(LC_ALL, "");
1600 elogind_set_program_name(argv[0]);
1601 log_parse_environment();
1605 r = parse_argv(argc, argv);
1609 r = bus_connect_transport(arg_transport, arg_host, false, &bus);
1611 log_error_errno(r, "Failed to create bus connection: %m");
1615 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1617 r = loginctl_main(argc, argv, bus);
1620 /* make sure we terminate the bus connection first, and then close the
1621 * pager, see issue #3543 for the details. */
1622 sd_bus_flush_close_unref(bus);
1624 #if 0 /// elogind does that in elogind_cleanup()
1625 polkit_agent_close();
1628 strv_free(arg_property);
1630 #if 1 /// elogind has some own cleanups to do
1633 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;