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_no_wall;
75 extern usec_t arg_when;
76 extern bool arg_ignore_inhibitors;
77 extern elogind_action arg_action;
80 static OutputFlags get_output_flags(void) {
83 arg_all * OUTPUT_SHOW_ALL |
84 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
85 colors_enabled() * OUTPUT_COLOR;
88 static int get_session_path(sd_bus *bus, const char *session_id, sd_bus_error *error, char **path) {
89 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
93 r = sd_bus_call_method(
95 "org.freedesktop.login1",
96 "/org/freedesktop/login1",
97 "org.freedesktop.login1.Manager",
104 r = sd_bus_message_read(reply, "o", &ans);
116 static int list_sessions(int argc, char *argv[], void *userdata) {
117 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
118 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
119 const char *id, *user, *seat, *object;
120 sd_bus *bus = userdata;
128 pager_open(arg_no_pager, false);
130 r = sd_bus_call_method(
132 "org.freedesktop.login1",
133 "/org/freedesktop/login1",
134 "org.freedesktop.login1.Manager",
139 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
143 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
145 return bus_log_parse_error(r);
148 printf("%10s %10s %-16s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT", "TTY");
150 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
151 _cleanup_(sd_bus_error_free) sd_bus_error error2 = SD_BUS_ERROR_NULL;
152 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply2 = NULL;
153 _cleanup_free_ char *path = NULL;
154 const char *tty = NULL;
156 r = get_session_path(bus, id, &error2, &path);
158 log_warning("Failed to get session path: %s", bus_error_message(&error, r));
160 r = sd_bus_get_property(
162 "org.freedesktop.login1",
164 "org.freedesktop.login1.Session",
170 log_warning("Failed to get TTY for session %s: %s",
171 id, bus_error_message(&error2, r));
173 r = sd_bus_message_read(reply2, "s", &tty);
175 return bus_log_parse_error(r);
179 printf("%10s %10"PRIu32" %-16s %-16s %-16s\n", id, uid, user, seat, strna(tty));
183 return bus_log_parse_error(r);
186 printf("\n%u sessions listed.\n", k);
191 static int list_users(int argc, char *argv[], void *userdata) {
192 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
193 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
194 const char *user, *object;
195 sd_bus *bus = userdata;
203 pager_open(arg_no_pager, false);
205 r = sd_bus_call_method(
207 "org.freedesktop.login1",
208 "/org/freedesktop/login1",
209 "org.freedesktop.login1.Manager",
214 log_error("Failed to list users: %s", bus_error_message(&error, r));
218 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
220 return bus_log_parse_error(r);
223 printf("%10s %-16s\n", "UID", "USER");
225 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
226 printf("%10"PRIu32" %-16s\n", uid, user);
230 return bus_log_parse_error(r);
233 printf("\n%u users listed.\n", k);
238 static int list_seats(int argc, char *argv[], void *userdata) {
239 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
240 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
241 const char *seat, *object;
242 sd_bus *bus = userdata;
248 pager_open(arg_no_pager, false);
250 r = sd_bus_call_method(
252 "org.freedesktop.login1",
253 "/org/freedesktop/login1",
254 "org.freedesktop.login1.Manager",
259 log_error("Failed to list seats: %s", bus_error_message(&error, r));
263 r = sd_bus_message_enter_container(reply, 'a', "(so)");
265 return bus_log_parse_error(r);
268 printf("%-16s\n", "SEAT");
270 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
271 printf("%-16s\n", seat);
275 return bus_log_parse_error(r);
278 printf("\n%u seats listed.\n", k);
283 #if 0 /// UNNEEDED by elogind
284 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
285 _cleanup_free_ char *cgroup = NULL;
286 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
293 r = show_cgroup_get_unit_path_and_warn(bus, unit, &cgroup);
306 r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error);
309 if (arg_transport == BUS_TRANSPORT_REMOTE)
312 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
314 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
317 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags());
319 return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
325 typedef struct SessionStatusInfo {
329 struct dual_timestamp timestamp;
346 typedef struct UserStatusInfo {
350 struct dual_timestamp timestamp;
357 typedef struct SeatStatusInfo {
359 char *active_session;
363 static void session_status_info_clear(SessionStatusInfo *info) {
370 free(info->remote_host);
371 free(info->remote_user);
382 static void user_status_info_clear(UserStatusInfo *info) {
386 strv_free(info->sessions);
393 static void seat_status_info_clear(SeatStatusInfo *info) {
396 free(info->active_session);
397 strv_free(info->sessions);
402 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
403 const char *contents;
406 r = sd_bus_message_peek_type(m, NULL, &contents);
410 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
414 if (IN_SET(contents[0], 's', 'o')) {
416 char **p = (char **) userdata;
418 r = sd_bus_message_read_basic(m, contents[0], &s);
422 r = free_and_strdup(p, s);
426 r = sd_bus_message_read_basic(m, contents[0], userdata);
431 r = sd_bus_message_skip(m, contents+1);
435 r = sd_bus_message_exit_container(m);
442 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
449 r = sd_bus_message_enter_container(m, 'a', "(so)");
453 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
454 r = strv_extend(userdata, name);
461 return sd_bus_message_exit_container(m);
464 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
466 static const struct bus_properties_map map[] = {
467 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
468 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
469 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
470 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
471 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
472 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
473 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
474 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
475 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
476 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
477 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
478 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
479 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
480 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
481 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
482 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
483 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
484 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
485 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
489 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
490 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
491 char since2[FORMAT_TIMESTAMP_MAX], *s2;
492 _cleanup_(session_status_info_clear) SessionStatusInfo i = {};
495 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i);
497 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
504 printf("%s - ", strna(i.id));
507 printf("%s (%"PRIu32")\n", i.name, i.uid);
509 printf("%"PRIu32"\n", i.uid);
511 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
512 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
515 printf("\t Since: %s; %s\n", s2, s1);
517 printf("\t Since: %s\n", s2);
520 _cleanup_free_ char *t = NULL;
522 printf("\t Leader: %"PRIu32, i.leader);
524 get_process_comm(i.leader, &t);
531 if (!isempty(i.seat)) {
532 printf("\t Seat: %s", i.seat);
535 printf("; vc%u", i.vtnr);
541 printf("\t TTY: %s\n", i.tty);
543 printf("\t Display: %s\n", i.display);
545 if (i.remote_host && i.remote_user)
546 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
547 else if (i.remote_host)
548 printf("\t Remote: %s\n", i.remote_host);
549 else if (i.remote_user)
550 printf("\t Remote: user %s\n", i.remote_user);
552 printf("\t Remote: Yes\n");
555 printf("\t Service: %s", i.service);
558 printf("; type %s", i.type);
561 printf("; class %s", i.class);
565 printf("\t Type: %s", i.type);
568 printf("; class %s", i.class);
572 printf("\t Class: %s\n", i.class);
574 if (!isempty(i.desktop))
575 printf("\t Desktop: %s\n", i.desktop);
578 printf("\t State: %s\n", i.state);
581 printf("\t Unit: %s\n", i.scope);
582 #if 0 /// UNNEEDED by elogind
583 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
585 if (arg_transport == BUS_TRANSPORT_LOCAL) {
587 show_journal_by_unit(
592 i.timestamp.monotonic,
595 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
596 SD_JOURNAL_LOCAL_ONLY,
606 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
608 static const struct bus_properties_map map[] = {
609 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
610 { "Linger", "b", NULL, offsetof(UserStatusInfo, linger) },
611 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
612 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
613 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
614 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
615 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
616 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
617 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
621 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
622 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
623 char since2[FORMAT_TIMESTAMP_MAX], *s2;
624 _cleanup_(user_status_info_clear) UserStatusInfo i = {};
627 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i);
629 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
637 printf("%s (%"PRIu32")\n", i.name, i.uid);
639 printf("%"PRIu32"\n", i.uid);
641 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
642 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
645 printf("\t Since: %s; %s\n", s2, s1);
647 printf("\t Since: %s\n", s2);
649 if (!isempty(i.state))
650 printf("\t State: %s\n", i.state);
652 if (!strv_isempty(i.sessions)) {
654 printf("\tSessions:");
656 STRV_FOREACH(l, i.sessions)
658 streq_ptr(*l, i.display) ? "*" : "",
664 printf("\t Linger: %s\n", yes_no(i.linger));
667 printf("\t Unit: %s\n", i.slice);
668 #if 0 /// UNNEEDED by elogind
669 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
671 show_journal_by_unit(
676 i.timestamp.monotonic,
679 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
680 SD_JOURNAL_LOCAL_ONLY,
689 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
691 static const struct bus_properties_map map[] = {
692 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
693 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
694 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
698 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
699 _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
702 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i);
704 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
711 printf("%s\n", strna(i.id));
713 if (!strv_isempty(i.sessions)) {
715 printf("\tSessions:");
717 STRV_FOREACH(l, i.sessions) {
718 if (streq_ptr(*l, i.active_session))
727 if (arg_transport == BUS_TRANSPORT_LOCAL) {
736 printf("\t Devices:\n");
738 show_sysfs(i.id, "\t\t ", c, get_output_flags());
744 #define property(name, fmt, ...) \
747 printf(fmt "\n", __VA_ARGS__); \
749 printf("%s=" fmt "\n", name, __VA_ARGS__); \
752 static int print_property(const char *name, sd_bus_message *m, const char *contents) {
759 if (arg_property && !strv_find(arg_property, name))
760 /* skip what we didn't read */
761 return sd_bus_message_skip(m, contents);
763 switch (contents[0]) {
765 case SD_BUS_TYPE_STRUCT_BEGIN:
767 if (contents[1] == SD_BUS_TYPE_STRING && STR_IN_SET(name, "Display", "Seat", "ActiveSession")) {
770 r = sd_bus_message_read(m, "(so)", &s, NULL);
772 return bus_log_parse_error(r);
774 if (arg_all || !isempty(s))
775 property(name, "%s", s);
779 } else if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "User")) {
782 r = sd_bus_message_read(m, "(uo)", &uid, NULL);
784 return bus_log_parse_error(r);
786 if (!uid_is_valid(uid)) {
787 log_error("Invalid user ID: " UID_FMT, uid);
791 property(name, UID_FMT, uid);
797 case SD_BUS_TYPE_ARRAY:
799 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Sessions")) {
803 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(so)");
805 return bus_log_parse_error(r);
810 while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
811 printf("%s%s", space ? " " : "", s);
815 if (space || !arg_value)
819 return bus_log_parse_error(r);
821 r = sd_bus_message_exit_container(m);
823 return bus_log_parse_error(r);
831 r = bus_print_property(name, m, arg_value, arg_all);
833 return bus_log_parse_error(r);
836 r = sd_bus_message_skip(m, contents);
838 return bus_log_parse_error(r);
841 printf("%s=[unprintable]\n", name);
847 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
848 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
849 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
856 r = sd_bus_call_method(
858 "org.freedesktop.login1",
860 "org.freedesktop.DBus.Properties",
866 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
868 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
870 return bus_log_parse_error(r);
877 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
878 const char *name, *contents;
880 r = sd_bus_message_read(reply, "s", &name);
882 return bus_log_parse_error(r);
884 r = sd_bus_message_peek_type(reply, NULL, &contents);
886 return bus_log_parse_error(r);
888 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
890 return bus_log_parse_error(r);
892 r = print_property(name, reply, contents);
896 r = sd_bus_message_exit_container(reply);
898 return bus_log_parse_error(r);
900 r = sd_bus_message_exit_container(reply);
902 return bus_log_parse_error(r);
905 return bus_log_parse_error(r);
907 r = sd_bus_message_exit_container(reply);
909 return bus_log_parse_error(r);
914 static int show_session(int argc, char *argv[], void *userdata) {
915 bool properties, new_line = false;
916 sd_bus *bus = userdata;
918 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
919 _cleanup_free_ char *path = NULL;
924 properties = !strstr(argv[0], "status");
926 pager_open(arg_no_pager, false);
929 const char *session, *p = "/org/freedesktop/login1/session/self";
932 /* If no argument is specified inspect the manager itself */
933 return show_properties(bus, "/org/freedesktop/login1", &new_line);
935 /* And in the pretty case, show data of the calling session */
936 session = getenv("XDG_SESSION_ID");
938 r = get_session_path(bus, session, &error, &path);
940 log_error("Failed to get session path: %s", bus_error_message(&error, r));
946 return print_session_status_info(bus, p, &new_line);
949 for (i = 1; i < argc; i++) {
950 r = get_session_path(bus, argv[i], &error, &path);
952 log_error("Failed to get session path: %s", bus_error_message(&error, r));
957 r = show_properties(bus, path, &new_line);
959 r = print_session_status_info(bus, path, &new_line);
968 static int show_user(int argc, char *argv[], void *userdata) {
969 bool properties, new_line = false;
970 sd_bus *bus = userdata;
976 properties = !strstr(argv[0], "status");
978 pager_open(arg_no_pager, false);
981 /* If not argument is specified inspect the manager
984 return show_properties(bus, "/org/freedesktop/login1", &new_line);
986 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
989 for (i = 1; i < argc; i++) {
990 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
991 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
992 const char *path = NULL;
995 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
997 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
999 r = sd_bus_call_method(
1001 "org.freedesktop.login1",
1002 "/org/freedesktop/login1",
1003 "org.freedesktop.login1.Manager",
1006 "u", (uint32_t) uid);
1008 log_error("Failed to get user: %s", bus_error_message(&error, r));
1012 r = sd_bus_message_read(reply, "o", &path);
1014 return bus_log_parse_error(r);
1017 r = show_properties(bus, path, &new_line);
1019 r = print_user_status_info(bus, path, &new_line);
1028 static int show_seat(int argc, char *argv[], void *userdata) {
1029 bool properties, new_line = false;
1030 sd_bus *bus = userdata;
1036 properties = !strstr(argv[0], "status");
1038 pager_open(arg_no_pager, false);
1041 /* If not argument is specified inspect the manager
1044 return show_properties(bus, "/org/freedesktop/login1", &new_line);
1046 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
1049 for (i = 1; i < argc; i++) {
1050 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1051 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
1052 const char *path = NULL;
1054 r = sd_bus_call_method(
1056 "org.freedesktop.login1",
1057 "/org/freedesktop/login1",
1058 "org.freedesktop.login1.Manager",
1063 log_error("Failed to get seat: %s", bus_error_message(&error, r));
1067 r = sd_bus_message_read(reply, "o", &path);
1069 return bus_log_parse_error(r);
1072 r = show_properties(bus, path, &new_line);
1074 r = print_seat_status_info(bus, path, &new_line);
1083 static int activate(int argc, char *argv[], void *userdata) {
1084 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1085 sd_bus *bus = userdata;
1086 char *short_argv[3];
1092 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1095 /* No argument? Let's either use $XDG_SESSION_ID (if specified), or an empty
1096 * session name, in which case logind will try to guess our session. */
1098 short_argv[0] = argv[0];
1099 short_argv[1] = getenv("XDG_SESSION_ID") ?: (char*) "";
1100 short_argv[2] = NULL;
1106 for (i = 1; i < argc; i++) {
1108 r = sd_bus_call_method(
1110 "org.freedesktop.login1",
1111 "/org/freedesktop/login1",
1112 "org.freedesktop.login1.Manager",
1113 streq(argv[0], "lock-session") ? "LockSession" :
1114 streq(argv[0], "unlock-session") ? "UnlockSession" :
1115 streq(argv[0], "terminate-session") ? "TerminateSession" :
1120 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
1128 static int kill_session(int argc, char *argv[], void *userdata) {
1129 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1130 sd_bus *bus = userdata;
1136 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1139 arg_kill_who = "all";
1141 for (i = 1; i < argc; i++) {
1143 r = sd_bus_call_method(
1145 "org.freedesktop.login1",
1146 "/org/freedesktop/login1",
1147 "org.freedesktop.login1.Manager",
1150 "ssi", argv[i], arg_kill_who, arg_signal);
1152 log_error("Could not kill session: %s", bus_error_message(&error, -r));
1160 static int enable_linger(int argc, char *argv[], void *userdata) {
1161 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1162 sd_bus *bus = userdata;
1163 char* short_argv[3];
1170 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1172 b = streq(argv[0], "enable-linger");
1175 /* No argument? Let's use an empty user name,
1176 * then logind will use our user. */
1178 short_argv[0] = argv[0];
1179 short_argv[1] = (char*) "";
1180 short_argv[2] = NULL;
1185 for (i = 1; i < argc; i++) {
1188 if (isempty(argv[i]))
1191 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1193 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1196 r = sd_bus_call_method(
1198 "org.freedesktop.login1",
1199 "/org/freedesktop/login1",
1200 "org.freedesktop.login1.Manager",
1203 "ubb", (uint32_t) uid, b, true);
1205 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1213 static int terminate_user(int argc, char *argv[], void *userdata) {
1214 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1215 sd_bus *bus = userdata;
1221 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1223 for (i = 1; i < argc; i++) {
1226 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1228 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1230 r = sd_bus_call_method(
1232 "org.freedesktop.login1",
1233 "/org/freedesktop/login1",
1234 "org.freedesktop.login1.Manager",
1237 "u", (uint32_t) uid);
1239 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1247 static int kill_user(int argc, char *argv[], void *userdata) {
1248 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1249 sd_bus *bus = userdata;
1255 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1258 arg_kill_who = "all";
1260 for (i = 1; i < argc; i++) {
1263 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1265 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1267 r = sd_bus_call_method(
1269 "org.freedesktop.login1",
1270 "/org/freedesktop/login1",
1271 "org.freedesktop.login1.Manager",
1274 "ui", (uint32_t) uid, arg_signal);
1276 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1284 static int attach(int argc, char *argv[], void *userdata) {
1285 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1286 sd_bus *bus = userdata;
1292 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1294 for (i = 2; i < argc; i++) {
1296 r = sd_bus_call_method(
1298 "org.freedesktop.login1",
1299 "/org/freedesktop/login1",
1300 "org.freedesktop.login1.Manager",
1303 "ssb", argv[1], argv[i], true);
1306 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1314 static int flush_devices(int argc, char *argv[], void *userdata) {
1315 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1316 sd_bus *bus = userdata;
1322 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1324 r = sd_bus_call_method(
1326 "org.freedesktop.login1",
1327 "/org/freedesktop/login1",
1328 "org.freedesktop.login1.Manager",
1333 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1338 static int lock_sessions(int argc, char *argv[], void *userdata) {
1339 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1340 sd_bus *bus = userdata;
1346 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1348 r = sd_bus_call_method(
1350 "org.freedesktop.login1",
1351 "/org/freedesktop/login1",
1352 "org.freedesktop.login1.Manager",
1353 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1357 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1362 static int terminate_seat(int argc, char *argv[], void *userdata) {
1363 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1364 sd_bus *bus = userdata;
1370 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1372 for (i = 1; i < argc; i++) {
1374 r = sd_bus_call_method(
1376 "org.freedesktop.login1",
1377 "/org/freedesktop/login1",
1378 "org.freedesktop.login1.Manager",
1383 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1391 static int help(int argc, char *argv[], void *userdata) {
1393 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1394 "Send control commands to or query the login manager.\n\n"
1395 " -h --help Show this help\n"
1396 " --version Show package version\n"
1397 " --no-pager Do not pipe output into a pager\n"
1398 #if 1 /// elogind supports --no-wall
1399 " --no-wall Do not print any wall message\n"
1401 " --no-legend Do not show the headers and footers\n"
1402 " --no-ask-password Don't prompt for password\n"
1403 " -H --host=[USER@]HOST Operate on remote host\n"
1404 " -M --machine=CONTAINER Operate on local container\n"
1405 " -p --property=NAME Show only properties by this name\n"
1406 " -a --all Show all properties, including empty ones\n"
1407 " --value When showing properties, only print the value\n"
1408 " -l --full Do not ellipsize output\n"
1409 " --kill-who=WHO Who to send signal to\n"
1410 " -s --signal=SIGNAL Which signal to send\n"
1411 #if 0 /// UNNEEDED by elogind
1412 " -n --lines=INTEGER Number of journal entries to show\n"
1413 " -o --output=STRING Change journal output mode (short, short-precise,\n"
1414 " short-iso, short-iso-precise, short-full,\n"
1415 " short-monotonic, short-unix, verbose, export,\n"
1416 " json, json-pretty, json-sse, cat)\n"
1418 /// elogind can cancel shutdowns and allows to ignore inhibitors
1419 " -c Cancel a pending shutdown or reboot\n"
1420 " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n\n"
1422 "Session Commands:\n"
1423 #if 0 /// elogind has "list" as a shorthand for "list-sessions"
1424 " list-sessions List sessions\n"
1426 " list[-sessions] List sessions (default command)\n"
1428 " session-status [ID...] Show session status\n"
1429 " show-session [ID...] Show properties of sessions or the manager\n"
1430 " activate [ID] Activate a session\n"
1431 " lock-session [ID...] Screen lock one or more sessions\n"
1432 " unlock-session [ID...] Screen unlock one or more sessions\n"
1433 " lock-sessions Screen lock all current sessions\n"
1434 " unlock-sessions Screen unlock all current sessions\n"
1435 " terminate-session ID... Terminate one or more sessions\n"
1436 " kill-session ID... Send signal to processes of a session\n\n"
1438 " list-users List users\n"
1439 " user-status [USER...] Show user status\n"
1440 " show-user [USER...] Show properties of users or the manager\n"
1441 " enable-linger [USER...] Enable linger state of one or more users\n"
1442 " disable-linger [USER...] Disable linger state of one or more users\n"
1443 " terminate-user USER... Terminate all sessions of one or more users\n"
1444 " kill-user USER... Send signal to processes of a user\n\n"
1446 " list-seats List seats\n"
1447 " seat-status [NAME...] Show seat status\n"
1448 " show-seat [NAME...] Show properties of seats or the manager\n"
1449 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1450 " flush-devices Flush all device associations\n"
1451 #if 0 /// elogind adds some system commands to loginctl
1452 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1454 " terminate-seat NAME... Terminate all sessions on one or more seats\n\n"
1455 "System Commands:\n"
1456 " poweroff [TIME] [WALL...] Turn off the machine\n"
1457 " reboot [TIME] [WALL...] Reboot the machine\n"
1458 " suspend Suspend the machine to memory\n"
1459 " hibernate Suspend the machine to disk\n"
1460 " hybrid-sleep Suspend the machine to memory and disk\n"
1462 , program_invocation_short_name);
1467 static int parse_argv(int argc, char *argv[]) {
1470 ARG_VERSION = 0x100,
1473 #if 1 /// elogind supports --no-wall
1478 ARG_NO_ASK_PASSWORD,
1481 static const struct option options[] = {
1482 { "help", no_argument, NULL, 'h' },
1483 { "version", no_argument, NULL, ARG_VERSION },
1484 { "property", required_argument, NULL, 'p' },
1485 { "all", no_argument, NULL, 'a' },
1486 { "value", no_argument, NULL, ARG_VALUE },
1487 { "full", no_argument, NULL, 'l' },
1488 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1489 #if 1 /// elogind supports --no-wall
1490 { "no-wall", no_argument, NULL, ARG_NO_WALL },
1492 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1493 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1494 { "signal", required_argument, NULL, 's' },
1495 { "host", required_argument, NULL, 'H' },
1496 { "machine", required_argument, NULL, 'M' },
1497 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1498 #if 0 /// UNNEEDED by elogind
1499 { "lines", required_argument, NULL, 'n' },
1500 { "output", required_argument, NULL, 'o' },
1502 /// elogind allows to ignore inhibitors for system commands.
1503 { "ignore-inhibitors", no_argument, NULL, 'i' },
1513 #if 0 /// elogind adds some system commands to loginctl
1514 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1516 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:ci", options, NULL)) >= 0)
1522 help(0, NULL, NULL);
1529 r = strv_extend(&arg_property, optarg);
1533 /* If the user asked for a particular
1534 * property, show it to him, even if it is
1552 #if 0 /// UNNEEDED by elogind
1554 if (safe_atou(optarg, &arg_lines) < 0) {
1555 log_error("Failed to parse lines '%s'", optarg);
1561 arg_output = output_mode_from_string(optarg);
1562 if (arg_output < 0) {
1563 log_error("Unknown output '%s'.", optarg);
1570 arg_no_pager = true;
1572 #if 1 /// elogind supports --no-wall
1582 case ARG_NO_ASK_PASSWORD:
1583 arg_ask_password = false;
1587 arg_kill_who = optarg;
1591 arg_signal = signal_from_string_try_harder(optarg);
1592 if (arg_signal < 0) {
1593 log_error("Failed to parse signal string %s.", optarg);
1599 arg_transport = BUS_TRANSPORT_REMOTE;
1604 arg_transport = BUS_TRANSPORT_MACHINE;
1607 #if 1 /// elogind can cancel shutdowns and allows to ignore inhibitors
1609 arg_action = ACTION_CANCEL_SHUTDOWN;
1613 arg_ignore_inhibitors = true;
1620 assert_not_reached("Unhandled option");
1626 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1628 static const Verb verbs[] = {
1629 { "help", VERB_ANY, VERB_ANY, 0, help },
1630 #if 0 /// elogind has "list" as a shorthand for "list-sessions"
1631 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1633 { "list", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1634 { "list-sessions", VERB_ANY, 1, 0, list_sessions },
1636 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1637 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1638 { "activate", VERB_ANY, 2, 0, activate },
1639 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1640 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1641 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1642 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1643 { "terminate-session", 2, VERB_ANY, 0, activate },
1644 { "kill-session", 2, VERB_ANY, 0, kill_session },
1645 { "list-users", VERB_ANY, 1, 0, list_users },
1646 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1647 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1648 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1649 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1650 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1651 { "kill-user", 2, VERB_ANY, 0, kill_user },
1652 { "list-seats", VERB_ANY, 1, 0, list_seats },
1653 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1654 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1655 { "attach", 3, VERB_ANY, 0, attach },
1656 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1657 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1658 #if 1 /// elogind adds some system commands to loginctl
1659 { "poweroff", VERB_ANY, VERB_ANY, 0, start_special },
1660 { "reboot", VERB_ANY, VERB_ANY, 0, start_special },
1661 { "suspend", VERB_ANY, 1, 0, start_special },
1662 { "hibernate", VERB_ANY, 1, 0, start_special },
1663 { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
1664 { "cancel-shutdown", VERB_ANY, 1, 0, start_special },
1669 #if 1 /// elogind can do shutdown and allows its cancellation
1670 if ((argc == optind) && (ACTION_CANCEL_SHUTDOWN == arg_action))
1671 return elogind_cancel_shutdown(bus);
1673 return dispatch_verb(argc, argv, verbs, bus);
1676 int main(int argc, char *argv[]) {
1677 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1680 setlocale(LC_ALL, "");
1681 elogind_set_program_name(argv[0]);
1682 log_parse_environment();
1686 r = parse_argv(argc, argv);
1690 r = bus_connect_transport(arg_transport, arg_host, false, &bus);
1692 log_error_errno(r, "Failed to create bus connection: %m");
1696 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1698 r = loginctl_main(argc, argv, bus);
1702 #if 0 /// elogind does that in elogind_cleanup()
1703 polkit_agent_close();
1706 strv_free(arg_property);
1708 #if 1 /// elogind has some own cleanups to do
1711 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;