1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "bus-error.h"
37 #include "unit-name.h"
38 #include "sysfs-show.h"
39 #include "logs-show.h"
40 #include "cgroup-show.h"
41 #include "cgroup-util.h"
42 #include "spawn-polkit-agent.h"
45 static char **arg_property = NULL;
46 static bool arg_all = false;
47 static bool arg_full = false;
48 static bool arg_no_pager = false;
49 static bool arg_legend = true;
50 static const char *arg_kill_who = NULL;
51 static int arg_signal = SIGTERM;
52 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
53 static char *arg_host = NULL;
54 static bool arg_ask_password = true;
55 static unsigned arg_lines = 10;
56 static OutputMode arg_output = OUTPUT_SHORT;
58 static void pager_open_if_enabled(void) {
66 static void polkit_agent_open_if_enabled(void) {
68 /* Open the polkit agent as a child process if necessary */
70 if (!arg_ask_password)
73 if (arg_transport != BUS_TRANSPORT_LOCAL)
79 static OutputFlags get_output_flags(void) {
82 arg_all * OUTPUT_SHOW_ALL |
83 arg_full * OUTPUT_FULL_WIDTH |
84 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
85 on_tty() * OUTPUT_COLOR;
88 static int list_sessions(int argc, char *argv[], void *userdata) {
89 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
90 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
91 const char *id, *user, *seat, *object;
92 sd_bus *bus = userdata;
100 pager_open_if_enabled();
102 r = sd_bus_call_method(
104 "org.freedesktop.login1",
105 "/org/freedesktop/login1",
106 "org.freedesktop.login1.Manager",
111 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
115 r = sd_bus_message_enter_container(reply, 'a', "(susso)");
117 return bus_log_parse_error(r);
120 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
122 while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
123 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
127 return bus_log_parse_error(r);
130 printf("\n%u sessions listed.\n", k);
135 static int list_users(int argc, char *argv[], void *userdata) {
136 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
137 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
138 const char *user, *object;
139 sd_bus *bus = userdata;
147 pager_open_if_enabled();
149 r = sd_bus_call_method(
151 "org.freedesktop.login1",
152 "/org/freedesktop/login1",
153 "org.freedesktop.login1.Manager",
158 log_error("Failed to list users: %s", bus_error_message(&error, r));
162 r = sd_bus_message_enter_container(reply, 'a', "(uso)");
164 return bus_log_parse_error(r);
167 printf("%10s %-16s\n", "UID", "USER");
169 while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
170 printf("%10u %-16s\n", (unsigned) uid, user);
174 return bus_log_parse_error(r);
177 printf("\n%u users listed.\n", k);
182 static int list_seats(int argc, char *argv[], void *userdata) {
183 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
184 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
185 const char *seat, *object;
186 sd_bus *bus = userdata;
193 pager_open_if_enabled();
195 r = sd_bus_call_method(
197 "org.freedesktop.login1",
198 "/org/freedesktop/login1",
199 "org.freedesktop.login1.Manager",
204 log_error("Failed to list seats: %s", bus_error_message(&error, r));
208 r = sd_bus_message_enter_container(reply, 'a', "(so)");
210 return bus_log_parse_error(r);
213 printf("%-16s\n", "SEAT");
215 while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
216 printf("%-16s\n", seat);
220 return bus_log_parse_error(r);
223 printf("\n%u seats listed.\n", k);
228 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
229 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
230 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
231 _cleanup_free_ char *path = NULL;
239 if (arg_transport != BUS_TRANSPORT_LOCAL)
242 path = unit_dbus_path_from_name(unit);
246 r = sd_bus_get_property(
248 "org.freedesktop.systemd1",
252 &error, &reply, "s");
256 r = sd_bus_message_read(reply, "s", &cgroup);
263 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
272 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
276 typedef struct SessionStatusInfo {
280 struct dual_timestamp timestamp;
286 const char *remote_host;
287 const char *remote_user;
297 typedef struct UserStatusInfo {
300 struct dual_timestamp timestamp;
307 typedef struct SeatStatusInfo {
309 const char *active_session;
313 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
314 const char *contents;
317 r = sd_bus_message_peek_type(m, NULL, &contents);
321 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
325 if (contents[0] == 's' || contents[0] == 'o') {
327 char **p = (char **) userdata;
329 r = sd_bus_message_read_basic(m, contents[0], &s);
339 r = sd_bus_message_read_basic(m, contents[0], userdata);
344 r = sd_bus_message_skip(m, contents+1);
348 r = sd_bus_message_exit_container(m);
355 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
362 r = sd_bus_message_enter_container(m, 'a', "(so)");
366 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
367 r = strv_extend(userdata, name);
374 return sd_bus_message_exit_container(m);
377 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
379 static const struct bus_properties_map map[] = {
380 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
381 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
382 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
383 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
384 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
385 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
386 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
387 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
388 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
389 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
390 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
391 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
392 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
393 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
394 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
395 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
396 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
397 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
398 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
402 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
403 char since2[FORMAT_TIMESTAMP_MAX], *s2;
404 SessionStatusInfo i = {};
407 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
409 return log_error_errno(r, "Could not get properties: %m");
416 printf("%s - ", strna(i.id));
419 printf("%s (%u)\n", i.name, (unsigned) i.uid);
421 printf("%u\n", (unsigned) i.uid);
423 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
424 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
427 printf("\t Since: %s; %s\n", s2, s1);
429 printf("\t Since: %s\n", s2);
432 _cleanup_free_ char *t = NULL;
434 printf("\t Leader: %u", (unsigned) i.leader);
436 get_process_comm(i.leader, &t);
443 if (!isempty(i.seat)) {
444 printf("\t Seat: %s", i.seat);
447 printf("; vc%u", i.vtnr);
453 printf("\t TTY: %s\n", i.tty);
455 printf("\t Display: %s\n", i.display);
457 if (i.remote_host && i.remote_user)
458 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
459 else if (i.remote_host)
460 printf("\t Remote: %s\n", i.remote_host);
461 else if (i.remote_user)
462 printf("\t Remote: user %s\n", i.remote_user);
464 printf("\t Remote: Yes\n");
467 printf("\t Service: %s", i.service);
470 printf("; type %s", i.type);
473 printf("; class %s", i.class);
477 printf("\t Type: %s", i.type);
480 printf("; class %s", i.class);
484 printf("\t Class: %s\n", i.class);
486 if (!isempty(i.desktop))
487 printf("\t Desktop: %s\n", i.desktop);
490 printf("\t State: %s\n", i.state);
493 printf("\t Unit: %s\n", i.scope);
494 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
496 if (arg_transport == BUS_TRANSPORT_LOCAL) {
498 show_journal_by_unit(
503 i.timestamp.monotonic,
506 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
507 SD_JOURNAL_LOCAL_ONLY,
516 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
518 static const struct bus_properties_map map[] = {
519 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
520 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
521 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
522 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
523 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
524 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
525 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
526 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
530 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
531 char since2[FORMAT_TIMESTAMP_MAX], *s2;
532 UserStatusInfo i = {};
535 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
537 log_error_errno(r, "Could not get properties: %m");
547 printf("%s (%u)\n", i.name, (unsigned) i.uid);
549 printf("%u\n", (unsigned) i.uid);
551 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
552 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
555 printf("\t Since: %s; %s\n", s2, s1);
557 printf("\t Since: %s\n", s2);
559 if (!isempty(i.state))
560 printf("\t State: %s\n", i.state);
562 if (!strv_isempty(i.sessions)) {
564 printf("\tSessions:");
566 STRV_FOREACH(l, i.sessions) {
567 if (streq_ptr(*l, i.display))
577 printf("\t Unit: %s\n", i.slice);
578 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
580 show_journal_by_unit(
585 i.timestamp.monotonic,
588 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
589 SD_JOURNAL_LOCAL_ONLY,
595 strv_free(i.sessions);
600 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
602 static const struct bus_properties_map map[] = {
603 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
604 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
605 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
609 SeatStatusInfo i = {};
612 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
614 log_error_errno(r, "Could not get properties: %m");
623 printf("%s\n", strna(i.id));
625 if (!strv_isempty(i.sessions)) {
627 printf("\tSessions:");
629 STRV_FOREACH(l, i.sessions) {
630 if (streq_ptr(*l, i.active_session))
639 if (arg_transport == BUS_TRANSPORT_LOCAL) {
648 printf("\t Devices:\n");
650 show_sysfs(i.id, "\t\t ", c);
654 strv_free(i.sessions);
659 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
667 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
669 log_error_errno(r, "Could not get properties: %m");
674 static int show_session(int argc, char *argv[], void *userdata) {
675 bool properties, new_line = false;
676 sd_bus *bus = userdata;
682 properties = !strstr(argv[0], "status");
684 pager_open_if_enabled();
687 /* If not argument is specified inspect the manager
690 return show_properties(bus, "/org/freedesktop/login1", &new_line);
692 /* And in the pretty case, show data of the calling session */
693 return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
696 for (i = 1; i < argc; i++) {
697 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
698 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
699 const char *path = NULL;
701 r = sd_bus_call_method(
703 "org.freedesktop.login1",
704 "/org/freedesktop/login1",
705 "org.freedesktop.login1.Manager",
710 log_error("Failed to get session: %s", bus_error_message(&error, r));
714 r = sd_bus_message_read(reply, "o", &path);
716 return bus_log_parse_error(r);
719 r = show_properties(bus, path, &new_line);
721 r = print_session_status_info(bus, path, &new_line);
730 static int show_user(int argc, char *argv[], void *userdata) {
731 bool properties, new_line = false;
732 sd_bus *bus = userdata;
738 properties = !strstr(argv[0], "status");
740 pager_open_if_enabled();
743 /* If not argument is specified inspect the manager
746 return show_properties(bus, "/org/freedesktop/login1", &new_line);
748 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
751 for (i = 1; i < argc; i++) {
752 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
753 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
754 const char *path = NULL;
757 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
759 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
761 r = sd_bus_call_method(
763 "org.freedesktop.login1",
764 "/org/freedesktop/login1",
765 "org.freedesktop.login1.Manager",
768 "u", (uint32_t) uid);
770 log_error("Failed to get user: %s", bus_error_message(&error, r));
774 r = sd_bus_message_read(reply, "o", &path);
776 return bus_log_parse_error(r);
779 r = show_properties(bus, path, &new_line);
781 r = print_user_status_info(bus, path, &new_line);
790 static int show_seat(int argc, char *argv[], void *userdata) {
791 bool properties, new_line = false;
792 sd_bus *bus = userdata;
798 properties = !strstr(argv[0], "status");
800 pager_open_if_enabled();
803 /* If not argument is specified inspect the manager
806 return show_properties(bus, "/org/freedesktop/login1", &new_line);
808 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
811 for (i = 1; i < argc; i++) {
812 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
813 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
814 const char *path = NULL;
816 r = sd_bus_call_method(
818 "org.freedesktop.login1",
819 "/org/freedesktop/login1",
820 "org.freedesktop.login1.Manager",
825 log_error("Failed to get seat: %s", bus_error_message(&error, r));
829 r = sd_bus_message_read(reply, "o", &path);
831 return bus_log_parse_error(r);
834 r = show_properties(bus, path, &new_line);
836 r = print_seat_status_info(bus, path, &new_line);
845 static int activate(int argc, char *argv[], void *userdata) {
846 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
847 sd_bus *bus = userdata;
854 polkit_agent_open_if_enabled();
857 /* No argument? Let's convert this into the empty
858 * session name, which the calls will then resolve to
859 * the caller's session. */
861 short_argv[0] = argv[0];
862 short_argv[1] = (char*) "";
863 short_argv[2] = NULL;
869 for (i = 1; i < argc; i++) {
871 r = sd_bus_call_method(
873 "org.freedesktop.login1",
874 "/org/freedesktop/login1",
875 "org.freedesktop.login1.Manager",
876 streq(argv[0], "lock-session") ? "LockSession" :
877 streq(argv[0], "unlock-session") ? "UnlockSession" :
878 streq(argv[0], "terminate-session") ? "TerminateSession" :
883 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
891 static int kill_session(int argc, char *argv[], void *userdata) {
892 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
893 sd_bus *bus = userdata;
899 polkit_agent_open_if_enabled();
902 arg_kill_who = "all";
904 for (i = 1; i < argc; i++) {
906 r = sd_bus_call_method(
908 "org.freedesktop.login1",
909 "/org/freedesktop/login1",
910 "org.freedesktop.login1.Manager",
913 "ssi", argv[i], arg_kill_who, arg_signal);
915 log_error("Could not kill session: %s", bus_error_message(&error, -r));
923 static int enable_linger(int argc, char *argv[], void *userdata) {
924 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
925 sd_bus *bus = userdata;
933 polkit_agent_open_if_enabled();
935 b = streq(argv[0], "enable-linger");
938 short_argv[0] = argv[0];
939 short_argv[1] = (char*) "";
940 short_argv[2] = NULL;
945 for (i = 1; i < argc; i++) {
948 if (isempty(argv[i]))
951 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
953 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
956 r = sd_bus_call_method(
958 "org.freedesktop.login1",
959 "/org/freedesktop/login1",
960 "org.freedesktop.login1.Manager",
963 "ubb", (uint32_t) uid, b, true);
965 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
973 static int terminate_user(int argc, char *argv[], void *userdata) {
974 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
975 sd_bus *bus = userdata;
981 polkit_agent_open_if_enabled();
983 for (i = 1; i < argc; i++) {
986 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
988 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
990 r = sd_bus_call_method(
992 "org.freedesktop.login1",
993 "/org/freedesktop/login1",
994 "org.freedesktop.login1.Manager",
997 "u", (uint32_t) uid);
999 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1007 static int kill_user(int argc, char *argv[], void *userdata) {
1008 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1009 sd_bus *bus = userdata;
1015 polkit_agent_open_if_enabled();
1018 arg_kill_who = "all";
1020 for (i = 1; i < argc; i++) {
1023 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1025 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1027 r = sd_bus_call_method(
1029 "org.freedesktop.login1",
1030 "/org/freedesktop/login1",
1031 "org.freedesktop.login1.Manager",
1034 "ui", (uint32_t) uid, arg_signal);
1036 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1044 static int attach(int argc, char *argv[], void *userdata) {
1045 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1046 sd_bus *bus = userdata;
1052 polkit_agent_open_if_enabled();
1054 for (i = 2; i < argc; i++) {
1056 r = sd_bus_call_method(
1058 "org.freedesktop.login1",
1059 "/org/freedesktop/login1",
1060 "org.freedesktop.login1.Manager",
1063 "ssb", argv[1], argv[i], true);
1066 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1074 static int flush_devices(int argc, char *argv[], void *userdata) {
1075 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1076 sd_bus *bus = userdata;
1082 polkit_agent_open_if_enabled();
1084 r = sd_bus_call_method(
1086 "org.freedesktop.login1",
1087 "/org/freedesktop/login1",
1088 "org.freedesktop.login1.Manager",
1093 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1098 static int lock_sessions(int argc, char *argv[], void *userdata) {
1099 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1100 sd_bus *bus = userdata;
1106 polkit_agent_open_if_enabled();
1108 r = sd_bus_call_method(
1110 "org.freedesktop.login1",
1111 "/org/freedesktop/login1",
1112 "org.freedesktop.login1.Manager",
1113 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1117 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1122 static int terminate_seat(int argc, char *argv[], void *userdata) {
1123 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1124 sd_bus *bus = userdata;
1130 polkit_agent_open_if_enabled();
1132 for (i = 1; i < argc; i++) {
1134 r = sd_bus_call_method(
1136 "org.freedesktop.login1",
1137 "/org/freedesktop/login1",
1138 "org.freedesktop.login1.Manager",
1143 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1151 static int help(int argc, char *argv[], void *userdata) {
1153 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1154 "Send control commands to or query the login manager.\n\n"
1155 " -h --help Show this help\n"
1156 " --version Show package version\n"
1157 " --no-pager Do not pipe output into a pager\n"
1158 " --no-legend Do not show the headers and footers\n"
1159 " --no-ask-password Don't prompt for password\n"
1160 " -H --host=[USER@]HOST Operate on remote host\n"
1161 " -M --machine=CONTAINER Operate on local container\n"
1162 " -p --property=NAME Show only properties by this name\n"
1163 " -a --all Show all properties, including empty ones\n"
1164 " -l --full Do not ellipsize output\n"
1165 " --kill-who=WHO Who to send signal to\n"
1166 " -s --signal=SIGNAL Which signal to send\n"
1167 " -n --lines=INTEGER Number of journal entries to show\n"
1168 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1169 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1170 "Session Commands:\n"
1171 " list-sessions List sessions\n"
1172 " session-status [ID...] Show session status\n"
1173 " show-session [ID...] Show properties of sessions or the manager\n"
1174 " activate [ID] Activate a session\n"
1175 " lock-session [ID...] Screen lock one or more sessions\n"
1176 " unlock-session [ID...] Screen unlock one or more sessions\n"
1177 " lock-sessions Screen lock all current sessions\n"
1178 " unlock-sessions Screen unlock all current sessions\n"
1179 " terminate-session ID... Terminate one or more sessions\n"
1180 " kill-session ID... Send signal to processes of a session\n\n"
1182 " list-users List users\n"
1183 " user-status [USER...] Show user status\n"
1184 " show-user [USER...] Show properties of users or the manager\n"
1185 " enable-linger [USER...] Enable linger state of one or more users\n"
1186 " disable-linger [USER...] Disable linger state of one or more users\n"
1187 " terminate-user USER... Terminate all sessions of one or more users\n"
1188 " kill-user USER... Send signal to processes of a user\n\n"
1190 " list-seats List seats\n"
1191 " seat-status [NAME...] Show seat status\n"
1192 " show-seat [NAME...] Show properties of seats or the manager\n"
1193 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1194 " flush-devices Flush all device associations\n"
1195 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1196 , program_invocation_short_name);
1201 static int parse_argv(int argc, char *argv[]) {
1204 ARG_VERSION = 0x100,
1208 ARG_NO_ASK_PASSWORD,
1211 static const struct option options[] = {
1212 { "help", no_argument, NULL, 'h' },
1213 { "version", no_argument, NULL, ARG_VERSION },
1214 { "property", required_argument, NULL, 'p' },
1215 { "all", no_argument, NULL, 'a' },
1216 { "full", no_argument, NULL, 'l' },
1217 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1218 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1219 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1220 { "signal", required_argument, NULL, 's' },
1221 { "host", required_argument, NULL, 'H' },
1222 { "machine", required_argument, NULL, 'M' },
1223 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1224 { "lines", required_argument, NULL, 'n' },
1225 { "output", required_argument, NULL, 'o' },
1234 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1239 help(0, NULL, NULL);
1243 puts(PACKAGE_STRING);
1244 puts(SYSTEMD_FEATURES);
1248 r = strv_extend(&arg_property, optarg);
1252 /* If the user asked for a particular
1253 * property, show it to him, even if it is
1268 if (safe_atou(optarg, &arg_lines) < 0) {
1269 log_error("Failed to parse lines '%s'", optarg);
1275 arg_output = output_mode_from_string(optarg);
1276 if (arg_output < 0) {
1277 log_error("Unknown output '%s'.", optarg);
1283 arg_no_pager = true;
1290 case ARG_NO_ASK_PASSWORD:
1291 arg_ask_password = false;
1295 arg_kill_who = optarg;
1299 arg_signal = signal_from_string_try_harder(optarg);
1300 if (arg_signal < 0) {
1301 log_error("Failed to parse signal string %s.", optarg);
1307 arg_transport = BUS_TRANSPORT_REMOTE;
1312 arg_transport = BUS_TRANSPORT_MACHINE;
1320 assert_not_reached("Unhandled option");
1326 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1328 static const Verb verbs[] = {
1329 { "help", VERB_ANY, VERB_ANY, 0, help },
1330 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1331 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1332 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1333 { "activate", VERB_ANY, 2, 0, activate },
1334 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1335 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1336 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1337 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1338 { "terminate-session", 2, VERB_ANY, 0, activate },
1339 { "kill-session", 2, VERB_ANY, 0, kill_session },
1340 { "list-users", VERB_ANY, 1, 0, list_users },
1341 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1342 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1343 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1344 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1345 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1346 { "kill-user", 2, VERB_ANY, 0, kill_user },
1347 { "list-seats", VERB_ANY, 1, 0, list_seats },
1348 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1349 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1350 { "attach", 3, VERB_ANY, 0, attach },
1351 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1352 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1356 return dispatch_verb(argc, argv, verbs, bus);
1359 int main(int argc, char *argv[]) {
1360 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1363 setlocale(LC_ALL, "");
1364 log_parse_environment();
1367 r = parse_argv(argc, argv);
1371 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1373 log_error_errno(r, "Failed to create bus connection: %m");
1377 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1379 r = loginctl_main(argc, argv, bus);
1383 polkit_agent_close();
1385 strv_free(arg_property);
1387 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;