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 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 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 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;
348 typedef struct UserStatusInfo {
352 struct dual_timestamp timestamp;
359 typedef struct SeatStatusInfo {
361 char *active_session;
365 static void session_status_info_clear(SessionStatusInfo *info) {
372 free(info->remote_host);
373 free(info->remote_user);
384 static void user_status_info_clear(UserStatusInfo *info) {
388 strv_free(info->sessions);
395 static void seat_status_info_clear(SeatStatusInfo *info) {
398 free(info->active_session);
399 strv_free(info->sessions);
404 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
405 const char *contents;
408 r = sd_bus_message_peek_type(m, NULL, &contents);
412 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
416 if (IN_SET(contents[0], 's', 'o')) {
418 char **p = (char **) userdata;
420 r = sd_bus_message_read_basic(m, contents[0], &s);
424 r = free_and_strdup(p, s);
428 r = sd_bus_message_read_basic(m, contents[0], userdata);
433 r = sd_bus_message_skip(m, contents+1);
437 r = sd_bus_message_exit_container(m);
444 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
451 r = sd_bus_message_enter_container(m, 'a', "(so)");
455 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
456 r = strv_extend(userdata, name);
463 return sd_bus_message_exit_container(m);
466 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
468 static const struct bus_properties_map map[] = {
469 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
470 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
471 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
472 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
473 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
474 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
475 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
476 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
477 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
478 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
479 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
480 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
481 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
482 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
483 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
484 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
485 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
486 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
487 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
491 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
492 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
493 char since2[FORMAT_TIMESTAMP_MAX], *s2;
494 _cleanup_(session_status_info_clear) SessionStatusInfo i = {};
497 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i);
499 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
506 printf("%s - ", strna(i.id));
509 printf("%s (%"PRIu32")\n", i.name, i.uid);
511 printf("%"PRIu32"\n", i.uid);
513 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
514 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
517 printf("\t Since: %s; %s\n", s2, s1);
519 printf("\t Since: %s\n", s2);
522 _cleanup_free_ char *t = NULL;
524 printf("\t Leader: %"PRIu32, i.leader);
526 get_process_comm(i.leader, &t);
533 if (!isempty(i.seat)) {
534 printf("\t Seat: %s", i.seat);
537 printf("; vc%u", i.vtnr);
543 printf("\t TTY: %s\n", i.tty);
545 printf("\t Display: %s\n", i.display);
547 if (i.remote_host && i.remote_user)
548 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
549 else if (i.remote_host)
550 printf("\t Remote: %s\n", i.remote_host);
551 else if (i.remote_user)
552 printf("\t Remote: user %s\n", i.remote_user);
554 printf("\t Remote: Yes\n");
557 printf("\t Service: %s", i.service);
560 printf("; type %s", i.type);
563 printf("; class %s", i.class);
567 printf("\t Type: %s", i.type);
570 printf("; class %s", i.class);
574 printf("\t Class: %s\n", i.class);
576 if (!isempty(i.desktop))
577 printf("\t Desktop: %s\n", i.desktop);
580 printf("\t State: %s\n", i.state);
583 printf("\t Unit: %s\n", i.scope);
584 #if 0 /// UNNEEDED by elogind
585 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
587 if (arg_transport == BUS_TRANSPORT_LOCAL) {
589 show_journal_by_unit(
594 i.timestamp.monotonic,
597 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
598 SD_JOURNAL_LOCAL_ONLY,
608 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
610 static const struct bus_properties_map map[] = {
611 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
612 { "Linger", "b", NULL, offsetof(UserStatusInfo, linger) },
613 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
614 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
615 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
616 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
617 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
618 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
619 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
623 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
624 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
625 char since2[FORMAT_TIMESTAMP_MAX], *s2;
626 _cleanup_(user_status_info_clear) UserStatusInfo i = {};
629 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i);
631 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
639 printf("%s (%"PRIu32")\n", i.name, i.uid);
641 printf("%"PRIu32"\n", i.uid);
643 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
644 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
647 printf("\t Since: %s; %s\n", s2, s1);
649 printf("\t Since: %s\n", s2);
651 if (!isempty(i.state))
652 printf("\t State: %s\n", i.state);
654 if (!strv_isempty(i.sessions)) {
656 printf("\tSessions:");
658 STRV_FOREACH(l, i.sessions)
660 streq_ptr(*l, i.display) ? "*" : "",
666 printf("\t Linger: %s\n", yes_no(i.linger));
669 printf("\t Unit: %s\n", i.slice);
670 #if 0 /// UNNEEDED by elogind
671 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
673 show_journal_by_unit(
678 i.timestamp.monotonic,
681 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
682 SD_JOURNAL_LOCAL_ONLY,
691 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
693 static const struct bus_properties_map map[] = {
694 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
695 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
696 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
700 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
701 _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
704 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i);
706 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
713 printf("%s\n", strna(i.id));
715 if (!strv_isempty(i.sessions)) {
717 printf("\tSessions:");
719 STRV_FOREACH(l, i.sessions) {
720 if (streq_ptr(*l, i.active_session))
729 if (arg_transport == BUS_TRANSPORT_LOCAL) {
738 printf("\t Devices:\n");
740 show_sysfs(i.id, "\t\t ", c, get_output_flags());
746 #define property(name, fmt, ...) \
749 printf(fmt "\n", __VA_ARGS__); \
751 printf("%s=" fmt "\n", name, __VA_ARGS__); \
754 static int print_property(const char *name, sd_bus_message *m, const char *contents) {
761 if (arg_property && !strv_find(arg_property, name))
762 /* skip what we didn't read */
763 return sd_bus_message_skip(m, contents);
765 switch (contents[0]) {
767 case SD_BUS_TYPE_STRUCT_BEGIN:
769 if (contents[1] == SD_BUS_TYPE_STRING && STR_IN_SET(name, "Display", "Seat", "ActiveSession")) {
772 r = sd_bus_message_read(m, "(so)", &s, NULL);
774 return bus_log_parse_error(r);
776 if (arg_all || !isempty(s))
777 property(name, "%s", s);
781 } else if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "User")) {
784 r = sd_bus_message_read(m, "(uo)", &uid, NULL);
786 return bus_log_parse_error(r);
788 if (!uid_is_valid(uid)) {
789 log_error("Invalid user ID: " UID_FMT, uid);
793 property(name, UID_FMT, uid);
799 case SD_BUS_TYPE_ARRAY:
801 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Sessions")) {
805 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(so)");
807 return bus_log_parse_error(r);
812 while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
813 printf("%s%s", space ? " " : "", s);
817 if (space || !arg_value)
821 return bus_log_parse_error(r);
823 r = sd_bus_message_exit_container(m);
825 return bus_log_parse_error(r);
833 r = bus_print_property(name, m, arg_value, arg_all);
835 return bus_log_parse_error(r);
838 r = sd_bus_message_skip(m, contents);
840 return bus_log_parse_error(r);
843 printf("%s=[unprintable]\n", name);
849 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
850 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
851 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
858 r = sd_bus_call_method(
860 "org.freedesktop.login1",
862 "org.freedesktop.DBus.Properties",
868 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
870 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
872 return bus_log_parse_error(r);
879 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
880 const char *name, *contents;
882 r = sd_bus_message_read(reply, "s", &name);
884 return bus_log_parse_error(r);
886 r = sd_bus_message_peek_type(reply, NULL, &contents);
888 return bus_log_parse_error(r);
890 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
892 return bus_log_parse_error(r);
894 r = print_property(name, reply, contents);
898 r = sd_bus_message_exit_container(reply);
900 return bus_log_parse_error(r);
902 r = sd_bus_message_exit_container(reply);
904 return bus_log_parse_error(r);
907 return bus_log_parse_error(r);
909 r = sd_bus_message_exit_container(reply);
911 return bus_log_parse_error(r);
916 static int show_session(int argc, char *argv[], void *userdata) {
917 bool properties, new_line = false;
918 sd_bus *bus = userdata;
920 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
921 _cleanup_free_ char *path = NULL;
926 properties = !strstr(argv[0], "status");
928 pager_open(arg_no_pager, false);
931 const char *session, *p = "/org/freedesktop/login1/session/self";
934 /* If no argument is specified inspect the manager itself */
935 return show_properties(bus, "/org/freedesktop/login1", &new_line);
937 /* And in the pretty case, show data of the calling session */
938 session = getenv("XDG_SESSION_ID");
940 r = get_session_path(bus, session, &error, &path);
942 log_error("Failed to get session path: %s", bus_error_message(&error, r));
948 return print_session_status_info(bus, p, &new_line);
951 for (i = 1; i < argc; i++) {
952 r = get_session_path(bus, argv[i], &error, &path);
954 log_error("Failed to get session path: %s", bus_error_message(&error, r));
959 r = show_properties(bus, path, &new_line);
961 r = print_session_status_info(bus, path, &new_line);
970 static int show_user(int argc, char *argv[], void *userdata) {
971 bool properties, new_line = false;
972 sd_bus *bus = userdata;
978 properties = !strstr(argv[0], "status");
980 pager_open(arg_no_pager, false);
983 /* If not argument is specified inspect the manager
986 return show_properties(bus, "/org/freedesktop/login1", &new_line);
988 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
991 for (i = 1; i < argc; i++) {
992 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
993 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
994 const char *path = NULL;
997 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
999 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1001 r = sd_bus_call_method(
1003 "org.freedesktop.login1",
1004 "/org/freedesktop/login1",
1005 "org.freedesktop.login1.Manager",
1008 "u", (uint32_t) uid);
1010 log_error("Failed to get user: %s", bus_error_message(&error, r));
1014 r = sd_bus_message_read(reply, "o", &path);
1016 return bus_log_parse_error(r);
1019 r = show_properties(bus, path, &new_line);
1021 r = print_user_status_info(bus, path, &new_line);
1030 static int show_seat(int argc, char *argv[], void *userdata) {
1031 bool properties, new_line = false;
1032 sd_bus *bus = userdata;
1038 properties = !strstr(argv[0], "status");
1040 pager_open(arg_no_pager, false);
1043 /* If not argument is specified inspect the manager
1046 return show_properties(bus, "/org/freedesktop/login1", &new_line);
1048 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
1051 for (i = 1; i < argc; i++) {
1052 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1053 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
1054 const char *path = NULL;
1056 r = sd_bus_call_method(
1058 "org.freedesktop.login1",
1059 "/org/freedesktop/login1",
1060 "org.freedesktop.login1.Manager",
1065 log_error("Failed to get seat: %s", bus_error_message(&error, r));
1069 r = sd_bus_message_read(reply, "o", &path);
1071 return bus_log_parse_error(r);
1074 r = show_properties(bus, path, &new_line);
1076 r = print_seat_status_info(bus, path, &new_line);
1085 static int activate(int argc, char *argv[], void *userdata) {
1086 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1087 sd_bus *bus = userdata;
1088 char *short_argv[3];
1094 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1097 /* No argument? Let's either use $XDG_SESSION_ID (if specified), or an empty
1098 * session name, in which case logind will try to guess our session. */
1100 short_argv[0] = argv[0];
1101 short_argv[1] = getenv("XDG_SESSION_ID") ?: (char*) "";
1102 short_argv[2] = NULL;
1108 for (i = 1; i < argc; i++) {
1110 r = sd_bus_call_method(
1112 "org.freedesktop.login1",
1113 "/org/freedesktop/login1",
1114 "org.freedesktop.login1.Manager",
1115 streq(argv[0], "lock-session") ? "LockSession" :
1116 streq(argv[0], "unlock-session") ? "UnlockSession" :
1117 streq(argv[0], "terminate-session") ? "TerminateSession" :
1122 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
1130 static int kill_session(int argc, char *argv[], void *userdata) {
1131 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1132 sd_bus *bus = userdata;
1138 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1141 arg_kill_who = "all";
1143 for (i = 1; i < argc; i++) {
1145 r = sd_bus_call_method(
1147 "org.freedesktop.login1",
1148 "/org/freedesktop/login1",
1149 "org.freedesktop.login1.Manager",
1152 "ssi", argv[i], arg_kill_who, arg_signal);
1154 log_error("Could not kill session: %s", bus_error_message(&error, -r));
1162 static int enable_linger(int argc, char *argv[], void *userdata) {
1163 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1164 sd_bus *bus = userdata;
1165 char* short_argv[3];
1172 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1174 b = streq(argv[0], "enable-linger");
1177 /* No argument? Let's use an empty user name,
1178 * then logind will use our user. */
1180 short_argv[0] = argv[0];
1181 short_argv[1] = (char*) "";
1182 short_argv[2] = NULL;
1187 for (i = 1; i < argc; i++) {
1190 if (isempty(argv[i]))
1193 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1195 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1198 r = sd_bus_call_method(
1200 "org.freedesktop.login1",
1201 "/org/freedesktop/login1",
1202 "org.freedesktop.login1.Manager",
1205 "ubb", (uint32_t) uid, b, true);
1207 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1215 static int terminate_user(int argc, char *argv[], void *userdata) {
1216 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1217 sd_bus *bus = userdata;
1223 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1225 for (i = 1; i < argc; i++) {
1228 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1230 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1232 r = sd_bus_call_method(
1234 "org.freedesktop.login1",
1235 "/org/freedesktop/login1",
1236 "org.freedesktop.login1.Manager",
1239 "u", (uint32_t) uid);
1241 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1249 static int kill_user(int argc, char *argv[], void *userdata) {
1250 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1251 sd_bus *bus = userdata;
1257 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1260 arg_kill_who = "all";
1262 for (i = 1; i < argc; i++) {
1265 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1267 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1269 r = sd_bus_call_method(
1271 "org.freedesktop.login1",
1272 "/org/freedesktop/login1",
1273 "org.freedesktop.login1.Manager",
1276 "ui", (uint32_t) uid, arg_signal);
1278 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1286 static int attach(int argc, char *argv[], void *userdata) {
1287 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1288 sd_bus *bus = userdata;
1294 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1296 for (i = 2; i < argc; i++) {
1298 r = sd_bus_call_method(
1300 "org.freedesktop.login1",
1301 "/org/freedesktop/login1",
1302 "org.freedesktop.login1.Manager",
1305 "ssb", argv[1], argv[i], true);
1308 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1316 static int flush_devices(int argc, char *argv[], void *userdata) {
1317 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1318 sd_bus *bus = userdata;
1324 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1326 r = sd_bus_call_method(
1328 "org.freedesktop.login1",
1329 "/org/freedesktop/login1",
1330 "org.freedesktop.login1.Manager",
1335 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1340 static int lock_sessions(int argc, char *argv[], void *userdata) {
1341 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1342 sd_bus *bus = userdata;
1348 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1350 r = sd_bus_call_method(
1352 "org.freedesktop.login1",
1353 "/org/freedesktop/login1",
1354 "org.freedesktop.login1.Manager",
1355 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1359 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1364 static int terminate_seat(int argc, char *argv[], void *userdata) {
1365 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1366 sd_bus *bus = userdata;
1372 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1374 for (i = 1; i < argc; i++) {
1376 r = sd_bus_call_method(
1378 "org.freedesktop.login1",
1379 "/org/freedesktop/login1",
1380 "org.freedesktop.login1.Manager",
1385 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1393 static int help(int argc, char *argv[], void *userdata) {
1395 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1396 "Send control commands to or query the login manager.\n\n"
1397 " -h --help Show this help\n"
1398 " --version Show package version\n"
1399 " --no-pager Do not pipe output into a pager\n"
1400 #if 1 /// elogind supports --no-wall and --dry-run
1401 " --no-wall Do not print any wall message\n"
1402 " --dry-run Only print what would be done\n"
1403 " -q --quiet Suppress output\n"
1405 " --no-legend Do not show the headers and footers\n"
1406 " --no-ask-password Don't prompt for password\n"
1407 " -H --host=[USER@]HOST Operate on remote host\n"
1408 " -M --machine=CONTAINER Operate on local container\n"
1409 " -p --property=NAME Show only properties by this name\n"
1410 " -a --all Show all properties, including empty ones\n"
1411 " --value When showing properties, only print the value\n"
1412 " -l --full Do not ellipsize output\n"
1413 " --kill-who=WHO Who to send signal to\n"
1414 " -s --signal=SIGNAL Which signal to send\n"
1415 #if 0 /// UNNEEDED by elogind
1416 " -n --lines=INTEGER Number of journal entries to show\n"
1417 " -o --output=STRING Change journal output mode (short, short-precise,\n"
1418 " short-iso, short-iso-precise, short-full,\n"
1419 " short-monotonic, short-unix, verbose, export,\n"
1420 " json, json-pretty, json-sse, cat)\n"
1422 /// elogind can cancel shutdowns and allows to ignore inhibitors
1423 " -c Cancel a pending shutdown or reboot\n"
1424 " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n\n"
1426 "Session Commands:\n"
1427 #if 0 /// elogind has "list" as a shorthand for "list-sessions"
1428 " list-sessions List sessions\n"
1430 " list[-sessions] List sessions (default command)\n"
1432 " session-status [ID...] Show session status\n"
1433 " show-session [ID...] Show properties of sessions or the manager\n"
1434 " activate [ID] Activate a session\n"
1435 " lock-session [ID...] Screen lock one or more sessions\n"
1436 " unlock-session [ID...] Screen unlock one or more sessions\n"
1437 " lock-sessions Screen lock all current sessions\n"
1438 " unlock-sessions Screen unlock all current sessions\n"
1439 " terminate-session ID... Terminate one or more sessions\n"
1440 " kill-session ID... Send signal to processes of a session\n\n"
1442 " list-users List users\n"
1443 " user-status [USER...] Show user status\n"
1444 " show-user [USER...] Show properties of users or the manager\n"
1445 " enable-linger [USER...] Enable linger state of one or more users\n"
1446 " disable-linger [USER...] Disable linger state of one or more users\n"
1447 " terminate-user USER... Terminate all sessions of one or more users\n"
1448 " kill-user USER... Send signal to processes of a user\n\n"
1450 " list-seats List seats\n"
1451 " seat-status [NAME...] Show seat status\n"
1452 " show-seat [NAME...] Show properties of seats or the manager\n"
1453 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1454 " flush-devices Flush all device associations\n"
1455 #if 0 /// elogind adds some system commands to loginctl
1456 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1458 " terminate-seat NAME... Terminate all sessions on one or more seats\n\n"
1459 "System Commands:\n"
1460 " poweroff [TIME] [WALL...] Turn off the machine\n"
1461 " reboot [TIME] [WALL...] Reboot the machine\n"
1462 " suspend Suspend the machine to memory\n"
1463 " hibernate Suspend the machine to disk\n"
1464 " hybrid-sleep Suspend the machine to memory and disk\n"
1466 , program_invocation_short_name);
1471 static int parse_argv(int argc, char *argv[]) {
1474 ARG_VERSION = 0x100,
1477 #if 1 /// elogind supports --no-wall and --dry-run
1483 ARG_NO_ASK_PASSWORD,
1486 static const struct option options[] = {
1487 { "help", no_argument, NULL, 'h' },
1488 { "version", no_argument, NULL, ARG_VERSION },
1489 { "property", required_argument, NULL, 'p' },
1490 { "all", no_argument, NULL, 'a' },
1491 { "value", no_argument, NULL, ARG_VALUE },
1492 { "full", no_argument, NULL, 'l' },
1493 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1494 #if 1 /// elogind supports --no-wall, --dry-run and --quiet
1495 { "no-wall", no_argument, NULL, ARG_NO_WALL },
1496 { "dry-run", no_argument, NULL, ARG_DRY_RUN },
1497 { "quiet", no_argument, NULL, 'q' },
1499 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1500 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1501 { "signal", required_argument, NULL, 's' },
1502 { "host", required_argument, NULL, 'H' },
1503 { "machine", required_argument, NULL, 'M' },
1504 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1505 #if 0 /// UNNEEDED by elogind
1506 { "lines", required_argument, NULL, 'n' },
1507 { "output", required_argument, NULL, 'o' },
1509 /// elogind allows to ignore inhibitors for system commands.
1510 { "ignore-inhibitors", no_argument, NULL, 'i' },
1520 #if 0 /// elogind adds some system commands to loginctl
1521 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1523 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:ci", options, NULL)) >= 0)
1529 help(0, NULL, NULL);
1536 r = strv_extend(&arg_property, optarg);
1540 /* If the user asked for a particular
1541 * property, show it to him, even if it is
1559 #if 0 /// UNNEEDED by elogind
1561 if (safe_atou(optarg, &arg_lines) < 0) {
1562 log_error("Failed to parse lines '%s'", optarg);
1568 arg_output = output_mode_from_string(optarg);
1569 if (arg_output < 0) {
1570 log_error("Unknown output '%s'.", optarg);
1577 arg_no_pager = true;
1579 #if 1 /// elogind supports --no-wall, -dry-run and --quiet
1598 case ARG_NO_ASK_PASSWORD:
1599 arg_ask_password = false;
1603 arg_kill_who = optarg;
1607 arg_signal = signal_from_string_try_harder(optarg);
1608 if (arg_signal < 0) {
1609 log_error("Failed to parse signal string %s.", optarg);
1615 arg_transport = BUS_TRANSPORT_REMOTE;
1620 arg_transport = BUS_TRANSPORT_MACHINE;
1623 #if 1 /// elogind can cancel shutdowns and allows to ignore inhibitors
1625 arg_action = ACTION_CANCEL_SHUTDOWN;
1629 arg_ignore_inhibitors = true;
1636 assert_not_reached("Unhandled option");
1642 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1644 static const Verb verbs[] = {
1645 { "help", VERB_ANY, VERB_ANY, 0, help },
1646 #if 0 /// elogind has "list" as a shorthand for "list-sessions"
1647 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1649 { "list", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1650 { "list-sessions", VERB_ANY, 1, 0, list_sessions },
1652 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1653 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1654 { "activate", VERB_ANY, 2, 0, activate },
1655 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1656 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1657 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1658 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1659 { "terminate-session", 2, VERB_ANY, 0, activate },
1660 { "kill-session", 2, VERB_ANY, 0, kill_session },
1661 { "list-users", VERB_ANY, 1, 0, list_users },
1662 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1663 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1664 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1665 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1666 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1667 { "kill-user", 2, VERB_ANY, 0, kill_user },
1668 { "list-seats", VERB_ANY, 1, 0, list_seats },
1669 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1670 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1671 { "attach", 3, VERB_ANY, 0, attach },
1672 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1673 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1674 #if 1 /// elogind adds some system commands to loginctl
1675 { "poweroff", VERB_ANY, VERB_ANY, 0, start_special },
1676 { "reboot", VERB_ANY, VERB_ANY, 0, start_special },
1677 { "suspend", VERB_ANY, 1, 0, start_special },
1678 { "hibernate", VERB_ANY, 1, 0, start_special },
1679 { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
1680 { "cancel-shutdown", VERB_ANY, 1, 0, start_special },
1685 #if 1 /// elogind can do shutdown and allows its cancellation
1686 if ((argc == optind) && (ACTION_CANCEL_SHUTDOWN == arg_action))
1687 return elogind_cancel_shutdown(bus);
1689 return dispatch_verb(argc, argv, verbs, bus);
1692 int main(int argc, char *argv[]) {
1696 setlocale(LC_ALL, "");
1697 elogind_set_program_name(argv[0]);
1698 log_parse_environment();
1702 r = parse_argv(argc, argv);
1706 r = bus_connect_transport(arg_transport, arg_host, false, &bus);
1708 log_error_errno(r, "Failed to create bus connection: %m");
1712 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1714 r = loginctl_main(argc, argv, bus);
1717 /* make sure we terminate the bus connection first, and then close the
1718 * pager, see issue #3543 for the details. */
1719 sd_bus_flush_close_unref(bus);
1721 #if 0 /// elogind does that in elogind_cleanup()
1722 polkit_agent_close();
1725 strv_free(arg_property);
1727 #if 1 /// elogind has some own cleanups to do
1730 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;