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"
32 #include "cgroup-show.h"
33 #include "cgroup-util.h"
35 #include "logs-show.h"
38 #include "process-util.h"
39 #include "signal-util.h"
40 #include "spawn-polkit-agent.h"
42 #include "sysfs-show.h"
43 #include "terminal-util.h"
44 #include "unit-name.h"
48 static char **arg_property
= NULL
;
49 static bool arg_all
= false;
50 static bool arg_full
= false;
51 static bool arg_no_pager
= false;
52 static bool arg_legend
= true;
53 static const char *arg_kill_who
= NULL
;
54 static int arg_signal
= SIGTERM
;
55 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
56 static char *arg_host
= NULL
;
57 static bool arg_ask_password
= true;
58 static unsigned arg_lines
= 10;
59 static OutputMode arg_output
= OUTPUT_SHORT
;
61 static void pager_open_if_enabled(void) {
69 static void polkit_agent_open_if_enabled(void) {
71 /* Open the polkit agent as a child process if necessary */
73 if (!arg_ask_password
)
76 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
82 static OutputFlags
get_output_flags(void) {
85 arg_all
* OUTPUT_SHOW_ALL
|
86 arg_full
* OUTPUT_FULL_WIDTH
|
87 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH
|
88 on_tty() * OUTPUT_COLOR
;
91 static int list_sessions(int argc
, char *argv
[], void *userdata
) {
92 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
93 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
94 const char *id
, *user
, *seat
, *object
;
95 sd_bus
*bus
= userdata
;
103 pager_open_if_enabled();
105 r
= sd_bus_call_method(
107 "org.freedesktop.login1",
108 "/org/freedesktop/login1",
109 "org.freedesktop.login1.Manager",
114 log_error("Failed to list sessions: %s", bus_error_message(&error
, r
));
118 r
= sd_bus_message_enter_container(reply
, 'a', "(susso)");
120 return bus_log_parse_error(r
);
123 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
125 while ((r
= sd_bus_message_read(reply
, "(susso)", &id
, &uid
, &user
, &seat
, &object
)) > 0) {
126 printf("%10s %10u %-16s %-16s\n", id
, (unsigned) uid
, user
, seat
);
130 return bus_log_parse_error(r
);
133 printf("\n%u sessions listed.\n", k
);
138 static int list_users(int argc
, char *argv
[], void *userdata
) {
139 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
140 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
141 const char *user
, *object
;
142 sd_bus
*bus
= userdata
;
150 pager_open_if_enabled();
152 r
= sd_bus_call_method(
154 "org.freedesktop.login1",
155 "/org/freedesktop/login1",
156 "org.freedesktop.login1.Manager",
161 log_error("Failed to list users: %s", bus_error_message(&error
, r
));
165 r
= sd_bus_message_enter_container(reply
, 'a', "(uso)");
167 return bus_log_parse_error(r
);
170 printf("%10s %-16s\n", "UID", "USER");
172 while ((r
= sd_bus_message_read(reply
, "(uso)", &uid
, &user
, &object
)) > 0) {
173 printf("%10u %-16s\n", (unsigned) uid
, user
);
177 return bus_log_parse_error(r
);
180 printf("\n%u users listed.\n", k
);
185 static int list_seats(int argc
, char *argv
[], void *userdata
) {
186 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
187 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
188 const char *seat
, *object
;
189 sd_bus
*bus
= userdata
;
196 pager_open_if_enabled();
198 r
= sd_bus_call_method(
200 "org.freedesktop.login1",
201 "/org/freedesktop/login1",
202 "org.freedesktop.login1.Manager",
207 log_error("Failed to list seats: %s", bus_error_message(&error
, r
));
211 r
= sd_bus_message_enter_container(reply
, 'a', "(so)");
213 return bus_log_parse_error(r
);
216 printf("%-16s\n", "SEAT");
218 while ((r
= sd_bus_message_read(reply
, "(so)", &seat
, &object
)) > 0) {
219 printf("%-16s\n", seat
);
223 return bus_log_parse_error(r
);
226 printf("\n%u seats listed.\n", k
);
231 static int show_unit_cgroup(sd_bus
*bus
, const char *interface
, const char *unit
, pid_t leader
) {
232 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
233 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
234 _cleanup_free_
char *path
= NULL
;
242 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
245 path
= unit_dbus_path_from_name(unit
);
249 r
= sd_bus_get_property(
251 "org.freedesktop.systemd1",
255 &error
, &reply
, "s");
259 r
= sd_bus_message_read(reply
, "s", &cgroup
);
266 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER
, cgroup
) != 0 && leader
<= 0)
275 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, "\t\t ", c
, false, &leader
, leader
> 0, get_output_flags());
279 typedef struct SessionStatusInfo
{
283 struct dual_timestamp timestamp
;
300 typedef struct UserStatusInfo
{
303 struct dual_timestamp timestamp
;
310 typedef struct SeatStatusInfo
{
312 char *active_session
;
316 static void session_status_info_clear(SessionStatusInfo
*info
) {
323 free(info
->remote_host
);
324 free(info
->remote_user
);
335 static void user_status_info_clear(UserStatusInfo
*info
) {
339 strv_free(info
->sessions
);
346 static void seat_status_info_clear(SeatStatusInfo
*info
) {
349 free(info
->active_session
);
350 strv_free(info
->sessions
);
355 static int prop_map_first_of_struct(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
356 const char *contents
;
359 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
363 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_STRUCT
, contents
);
367 if (contents
[0] == 's' || contents
[0] == 'o') {
369 char **p
= (char **) userdata
;
371 r
= sd_bus_message_read_basic(m
, contents
[0], &s
);
375 r
= free_and_strdup(p
, s
);
379 r
= sd_bus_message_read_basic(m
, contents
[0], userdata
);
384 r
= sd_bus_message_skip(m
, contents
+1);
388 r
= sd_bus_message_exit_container(m
);
395 static int prop_map_sessions_strv(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
402 r
= sd_bus_message_enter_container(m
, 'a', "(so)");
406 while ((r
= sd_bus_message_read(m
, "(so)", &name
, NULL
)) > 0) {
407 r
= strv_extend(userdata
, name
);
414 return sd_bus_message_exit_container(m
);
417 static int print_session_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
419 static const struct bus_properties_map map
[] = {
420 { "Id", "s", NULL
, offsetof(SessionStatusInfo
, id
) },
421 { "Name", "s", NULL
, offsetof(SessionStatusInfo
, name
) },
422 { "TTY", "s", NULL
, offsetof(SessionStatusInfo
, tty
) },
423 { "Display", "s", NULL
, offsetof(SessionStatusInfo
, display
) },
424 { "RemoteHost", "s", NULL
, offsetof(SessionStatusInfo
, remote_host
) },
425 { "RemoteUser", "s", NULL
, offsetof(SessionStatusInfo
, remote_user
) },
426 { "Service", "s", NULL
, offsetof(SessionStatusInfo
, service
) },
427 { "Desktop", "s", NULL
, offsetof(SessionStatusInfo
, desktop
) },
428 { "Type", "s", NULL
, offsetof(SessionStatusInfo
, type
) },
429 { "Class", "s", NULL
, offsetof(SessionStatusInfo
, class) },
430 { "Scope", "s", NULL
, offsetof(SessionStatusInfo
, scope
) },
431 { "State", "s", NULL
, offsetof(SessionStatusInfo
, state
) },
432 { "VTNr", "u", NULL
, offsetof(SessionStatusInfo
, vtnr
) },
433 { "Leader", "u", NULL
, offsetof(SessionStatusInfo
, leader
) },
434 { "Remote", "b", NULL
, offsetof(SessionStatusInfo
, remote
) },
435 { "Timestamp", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.realtime
) },
436 { "TimestampMonotonic", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.monotonic
) },
437 { "User", "(uo)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, uid
) },
438 { "Seat", "(so)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, seat
) },
442 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
443 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
444 _cleanup_(session_status_info_clear
) SessionStatusInfo i
= {};
447 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
449 return log_error_errno(r
, "Could not get properties: %m");
456 printf("%s - ", strna(i
.id
));
459 printf("%s (%u)\n", i
.name
, (unsigned) i
.uid
);
461 printf("%u\n", (unsigned) i
.uid
);
463 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
464 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
467 printf("\t Since: %s; %s\n", s2
, s1
);
469 printf("\t Since: %s\n", s2
);
472 _cleanup_free_
char *t
= NULL
;
474 printf("\t Leader: %u", (unsigned) i
.leader
);
476 get_process_comm(i
.leader
, &t
);
483 if (!isempty(i
.seat
)) {
484 printf("\t Seat: %s", i
.seat
);
487 printf("; vc%u", i
.vtnr
);
493 printf("\t TTY: %s\n", i
.tty
);
495 printf("\t Display: %s\n", i
.display
);
497 if (i
.remote_host
&& i
.remote_user
)
498 printf("\t Remote: %s@%s\n", i
.remote_user
, i
.remote_host
);
499 else if (i
.remote_host
)
500 printf("\t Remote: %s\n", i
.remote_host
);
501 else if (i
.remote_user
)
502 printf("\t Remote: user %s\n", i
.remote_user
);
504 printf("\t Remote: Yes\n");
507 printf("\t Service: %s", i
.service
);
510 printf("; type %s", i
.type
);
513 printf("; class %s", i
.class);
517 printf("\t Type: %s", i
.type
);
520 printf("; class %s", i
.class);
524 printf("\t Class: %s\n", i
.class);
526 if (!isempty(i
.desktop
))
527 printf("\t Desktop: %s\n", i
.desktop
);
530 printf("\t State: %s\n", i
.state
);
533 printf("\t Unit: %s\n", i
.scope
);
534 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Scope", i
.scope
, i
.leader
);
536 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
538 show_journal_by_unit(
543 i
.timestamp
.monotonic
,
546 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
547 SD_JOURNAL_LOCAL_ONLY
,
556 static int print_user_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
558 static const struct bus_properties_map map
[] = {
559 { "Name", "s", NULL
, offsetof(UserStatusInfo
, name
) },
560 { "Slice", "s", NULL
, offsetof(UserStatusInfo
, slice
) },
561 { "State", "s", NULL
, offsetof(UserStatusInfo
, state
) },
562 { "UID", "u", NULL
, offsetof(UserStatusInfo
, uid
) },
563 { "Timestamp", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.realtime
) },
564 { "TimestampMonotonic", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.monotonic
) },
565 { "Display", "(so)", prop_map_first_of_struct
, offsetof(UserStatusInfo
, display
) },
566 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(UserStatusInfo
, sessions
) },
570 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
571 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
572 _cleanup_(user_status_info_clear
) UserStatusInfo i
= {};
575 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
577 return log_error_errno(r
, "Could not get properties: %m");
585 printf("%s (%u)\n", i
.name
, (unsigned) i
.uid
);
587 printf("%u\n", (unsigned) i
.uid
);
589 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
590 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
593 printf("\t Since: %s; %s\n", s2
, s1
);
595 printf("\t Since: %s\n", s2
);
597 if (!isempty(i
.state
))
598 printf("\t State: %s\n", i
.state
);
600 if (!strv_isempty(i
.sessions
)) {
602 printf("\tSessions:");
604 STRV_FOREACH(l
, i
.sessions
) {
605 if (streq_ptr(*l
, i
.display
))
615 printf("\t Unit: %s\n", i
.slice
);
616 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Slice", i
.slice
, 0);
618 show_journal_by_unit(
623 i
.timestamp
.monotonic
,
626 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
627 SD_JOURNAL_LOCAL_ONLY
,
635 static int print_seat_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
637 static const struct bus_properties_map map
[] = {
638 { "Id", "s", NULL
, offsetof(SeatStatusInfo
, id
) },
639 { "ActiveSession", "(so)", prop_map_first_of_struct
, offsetof(SeatStatusInfo
, active_session
) },
640 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(SeatStatusInfo
, sessions
) },
644 _cleanup_(seat_status_info_clear
) SeatStatusInfo i
= {};
647 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
649 return log_error_errno(r
, "Could not get properties: %m");
656 printf("%s\n", strna(i
.id
));
658 if (!strv_isempty(i
.sessions
)) {
660 printf("\tSessions:");
662 STRV_FOREACH(l
, i
.sessions
) {
663 if (streq_ptr(*l
, i
.active_session
))
672 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
681 printf("\t Devices:\n");
683 show_sysfs(i
.id
, "\t\t ", c
);
689 static int print_property(const char *name
, sd_bus_message
*m
, const char *contents
) {
696 if (arg_property
&& !strv_find(arg_property
, name
))
697 /* skip what we didn't read */
698 return sd_bus_message_skip(m
, contents
);
700 switch (contents
[0]) {
702 case SD_BUS_TYPE_STRUCT_BEGIN
:
704 if (contents
[1] == SD_BUS_TYPE_STRING
&& STR_IN_SET(name
, "Display", "Seat", "ActiveSession")) {
707 r
= sd_bus_message_read(m
, "(so)", &s
, NULL
);
709 return bus_log_parse_error(r
);
711 if (arg_all
|| !isempty(s
))
712 printf("%s=%s\n", name
, s
);
716 } else if (contents
[1] == SD_BUS_TYPE_UINT32
&& streq(name
, "User")) {
719 r
= sd_bus_message_read(m
, "(uo)", &uid
, NULL
);
721 return bus_log_parse_error(r
);
723 if (!uid_is_valid(uid
)) {
724 log_error("Invalid user ID: " UID_FMT
, uid
);
728 printf("%s=" UID_FMT
"\n", name
, uid
);
735 case SD_BUS_TYPE_ARRAY
:
737 if (contents
[1] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "Sessions")) {
741 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(so)");
743 return bus_log_parse_error(r
);
747 while ((r
= sd_bus_message_read(m
, "(so)", &s
, NULL
)) > 0) {
748 printf("%s%s", space
? " " : "", s
);
755 return bus_log_parse_error(r
);
757 r
= sd_bus_message_exit_container(m
);
759 return bus_log_parse_error(r
);
767 r
= bus_print_property(name
, m
, arg_all
);
769 return bus_log_parse_error(r
);
772 r
= sd_bus_message_skip(m
, contents
);
774 return bus_log_parse_error(r
);
777 printf("%s=[unprintable]\n", name
);
783 static int show_properties(sd_bus
*bus
, const char *path
, bool *new_line
) {
784 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
785 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
792 r
= sd_bus_call_method(
794 "org.freedesktop.login1",
796 "org.freedesktop.DBus.Properties",
802 return log_error_errno(r
, "Failed to get properties: %s", bus_error_message(&error
, r
));
804 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
806 return bus_log_parse_error(r
);
813 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
814 const char *name
, *contents
;
816 r
= sd_bus_message_read(reply
, "s", &name
);
818 return bus_log_parse_error(r
);
820 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
822 return bus_log_parse_error(r
);
824 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
826 return bus_log_parse_error(r
);
828 r
= print_property(name
, reply
, contents
);
832 r
= sd_bus_message_exit_container(reply
);
834 return bus_log_parse_error(r
);
836 r
= sd_bus_message_exit_container(reply
);
838 return bus_log_parse_error(r
);
841 return bus_log_parse_error(r
);
843 r
= sd_bus_message_exit_container(reply
);
845 return bus_log_parse_error(r
);
850 static int show_session(int argc
, char *argv
[], void *userdata
) {
851 bool properties
, new_line
= false;
852 sd_bus
*bus
= userdata
;
858 properties
= !strstr(argv
[0], "status");
860 pager_open_if_enabled();
863 /* If not argument is specified inspect the manager
866 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
868 /* And in the pretty case, show data of the calling session */
869 return print_session_status_info(bus
, "/org/freedesktop/login1/session/self", &new_line
);
872 for (i
= 1; i
< argc
; i
++) {
873 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
874 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
875 const char *path
= NULL
;
877 r
= sd_bus_call_method(
879 "org.freedesktop.login1",
880 "/org/freedesktop/login1",
881 "org.freedesktop.login1.Manager",
886 log_error("Failed to get session: %s", bus_error_message(&error
, r
));
890 r
= sd_bus_message_read(reply
, "o", &path
);
892 return bus_log_parse_error(r
);
895 r
= show_properties(bus
, path
, &new_line
);
897 r
= print_session_status_info(bus
, path
, &new_line
);
906 static int show_user(int argc
, char *argv
[], void *userdata
) {
907 bool properties
, new_line
= false;
908 sd_bus
*bus
= userdata
;
914 properties
= !strstr(argv
[0], "status");
916 pager_open_if_enabled();
919 /* If not argument is specified inspect the manager
922 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
924 return print_user_status_info(bus
, "/org/freedesktop/login1/user/self", &new_line
);
927 for (i
= 1; i
< argc
; i
++) {
928 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
929 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
930 const char *path
= NULL
;
933 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
935 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
937 r
= sd_bus_call_method(
939 "org.freedesktop.login1",
940 "/org/freedesktop/login1",
941 "org.freedesktop.login1.Manager",
944 "u", (uint32_t) uid
);
946 log_error("Failed to get user: %s", bus_error_message(&error
, r
));
950 r
= sd_bus_message_read(reply
, "o", &path
);
952 return bus_log_parse_error(r
);
955 r
= show_properties(bus
, path
, &new_line
);
957 r
= print_user_status_info(bus
, path
, &new_line
);
966 static int show_seat(int argc
, char *argv
[], void *userdata
) {
967 bool properties
, new_line
= false;
968 sd_bus
*bus
= userdata
;
974 properties
= !strstr(argv
[0], "status");
976 pager_open_if_enabled();
979 /* If not argument is specified inspect the manager
982 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
984 return print_seat_status_info(bus
, "/org/freedesktop/login1/seat/self", &new_line
);
987 for (i
= 1; i
< argc
; i
++) {
988 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
989 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
990 const char *path
= NULL
;
992 r
= sd_bus_call_method(
994 "org.freedesktop.login1",
995 "/org/freedesktop/login1",
996 "org.freedesktop.login1.Manager",
1001 log_error("Failed to get seat: %s", bus_error_message(&error
, r
));
1005 r
= sd_bus_message_read(reply
, "o", &path
);
1007 return bus_log_parse_error(r
);
1010 r
= show_properties(bus
, path
, &new_line
);
1012 r
= print_seat_status_info(bus
, path
, &new_line
);
1021 static int activate(int argc
, char *argv
[], void *userdata
) {
1022 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1023 sd_bus
*bus
= userdata
;
1024 char *short_argv
[3];
1030 polkit_agent_open_if_enabled();
1033 /* No argument? Let's convert this into the empty
1034 * session name, which the calls will then resolve to
1035 * the caller's session. */
1037 short_argv
[0] = argv
[0];
1038 short_argv
[1] = (char*) "";
1039 short_argv
[2] = NULL
;
1045 for (i
= 1; i
< argc
; i
++) {
1047 r
= sd_bus_call_method(
1049 "org.freedesktop.login1",
1050 "/org/freedesktop/login1",
1051 "org.freedesktop.login1.Manager",
1052 streq(argv
[0], "lock-session") ? "LockSession" :
1053 streq(argv
[0], "unlock-session") ? "UnlockSession" :
1054 streq(argv
[0], "terminate-session") ? "TerminateSession" :
1059 log_error("Failed to issue method call: %s", bus_error_message(&error
, -r
));
1067 static int kill_session(int argc
, char *argv
[], void *userdata
) {
1068 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1069 sd_bus
*bus
= userdata
;
1075 polkit_agent_open_if_enabled();
1078 arg_kill_who
= "all";
1080 for (i
= 1; i
< argc
; i
++) {
1082 r
= sd_bus_call_method(
1084 "org.freedesktop.login1",
1085 "/org/freedesktop/login1",
1086 "org.freedesktop.login1.Manager",
1089 "ssi", argv
[i
], arg_kill_who
, arg_signal
);
1091 log_error("Could not kill session: %s", bus_error_message(&error
, -r
));
1099 static int enable_linger(int argc
, char *argv
[], void *userdata
) {
1100 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1101 sd_bus
*bus
= userdata
;
1102 char* short_argv
[3];
1109 polkit_agent_open_if_enabled();
1111 b
= streq(argv
[0], "enable-linger");
1114 short_argv
[0] = argv
[0];
1115 short_argv
[1] = (char*) "";
1116 short_argv
[2] = NULL
;
1121 for (i
= 1; i
< argc
; i
++) {
1124 if (isempty(argv
[i
]))
1127 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1129 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1132 r
= sd_bus_call_method(
1134 "org.freedesktop.login1",
1135 "/org/freedesktop/login1",
1136 "org.freedesktop.login1.Manager",
1139 "ubb", (uint32_t) uid
, b
, true);
1141 log_error("Could not enable linger: %s", bus_error_message(&error
, -r
));
1149 static int terminate_user(int argc
, char *argv
[], void *userdata
) {
1150 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1151 sd_bus
*bus
= userdata
;
1157 polkit_agent_open_if_enabled();
1159 for (i
= 1; i
< argc
; i
++) {
1162 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1164 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1166 r
= sd_bus_call_method(
1168 "org.freedesktop.login1",
1169 "/org/freedesktop/login1",
1170 "org.freedesktop.login1.Manager",
1173 "u", (uint32_t) uid
);
1175 log_error("Could not terminate user: %s", bus_error_message(&error
, -r
));
1183 static int kill_user(int argc
, char *argv
[], void *userdata
) {
1184 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1185 sd_bus
*bus
= userdata
;
1191 polkit_agent_open_if_enabled();
1194 arg_kill_who
= "all";
1196 for (i
= 1; i
< argc
; i
++) {
1199 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1201 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1203 r
= sd_bus_call_method(
1205 "org.freedesktop.login1",
1206 "/org/freedesktop/login1",
1207 "org.freedesktop.login1.Manager",
1210 "ui", (uint32_t) uid
, arg_signal
);
1212 log_error("Could not kill user: %s", bus_error_message(&error
, -r
));
1220 static int attach(int argc
, char *argv
[], void *userdata
) {
1221 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1222 sd_bus
*bus
= userdata
;
1228 polkit_agent_open_if_enabled();
1230 for (i
= 2; i
< argc
; i
++) {
1232 r
= sd_bus_call_method(
1234 "org.freedesktop.login1",
1235 "/org/freedesktop/login1",
1236 "org.freedesktop.login1.Manager",
1239 "ssb", argv
[1], argv
[i
], true);
1242 log_error("Could not attach device: %s", bus_error_message(&error
, -r
));
1250 static int flush_devices(int argc
, char *argv
[], void *userdata
) {
1251 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1252 sd_bus
*bus
= userdata
;
1258 polkit_agent_open_if_enabled();
1260 r
= sd_bus_call_method(
1262 "org.freedesktop.login1",
1263 "/org/freedesktop/login1",
1264 "org.freedesktop.login1.Manager",
1269 log_error("Could not flush devices: %s", bus_error_message(&error
, -r
));
1274 static int lock_sessions(int argc
, char *argv
[], void *userdata
) {
1275 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1276 sd_bus
*bus
= userdata
;
1282 polkit_agent_open_if_enabled();
1284 r
= sd_bus_call_method(
1286 "org.freedesktop.login1",
1287 "/org/freedesktop/login1",
1288 "org.freedesktop.login1.Manager",
1289 streq(argv
[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1293 log_error("Could not lock sessions: %s", bus_error_message(&error
, -r
));
1298 static int terminate_seat(int argc
, char *argv
[], void *userdata
) {
1299 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1300 sd_bus
*bus
= userdata
;
1306 polkit_agent_open_if_enabled();
1308 for (i
= 1; i
< argc
; i
++) {
1310 r
= sd_bus_call_method(
1312 "org.freedesktop.login1",
1313 "/org/freedesktop/login1",
1314 "org.freedesktop.login1.Manager",
1319 log_error("Could not terminate seat: %s", bus_error_message(&error
, -r
));
1327 static int help(int argc
, char *argv
[], void *userdata
) {
1329 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1330 "Send control commands to or query the login manager.\n\n"
1331 " -h --help Show this help\n"
1332 " --version Show package version\n"
1333 " --no-pager Do not pipe output into a pager\n"
1334 " --no-legend Do not show the headers and footers\n"
1335 " --no-ask-password Don't prompt for password\n"
1336 " -H --host=[USER@]HOST Operate on remote host\n"
1337 " -M --machine=CONTAINER Operate on local container\n"
1338 " -p --property=NAME Show only properties by this name\n"
1339 " -a --all Show all properties, including empty ones\n"
1340 " -l --full Do not ellipsize output\n"
1341 " --kill-who=WHO Who to send signal to\n"
1342 " -s --signal=SIGNAL Which signal to send\n"
1343 " -n --lines=INTEGER Number of journal entries to show\n"
1344 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1345 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1346 "Session Commands:\n"
1347 " list-sessions List sessions\n"
1348 " session-status [ID...] Show session status\n"
1349 " show-session [ID...] Show properties of sessions or the manager\n"
1350 " activate [ID] Activate a session\n"
1351 " lock-session [ID...] Screen lock one or more sessions\n"
1352 " unlock-session [ID...] Screen unlock one or more sessions\n"
1353 " lock-sessions Screen lock all current sessions\n"
1354 " unlock-sessions Screen unlock all current sessions\n"
1355 " terminate-session ID... Terminate one or more sessions\n"
1356 " kill-session ID... Send signal to processes of a session\n\n"
1358 " list-users List users\n"
1359 " user-status [USER...] Show user status\n"
1360 " show-user [USER...] Show properties of users or the manager\n"
1361 " enable-linger [USER...] Enable linger state of one or more users\n"
1362 " disable-linger [USER...] Disable linger state of one or more users\n"
1363 " terminate-user USER... Terminate all sessions of one or more users\n"
1364 " kill-user USER... Send signal to processes of a user\n\n"
1366 " list-seats List seats\n"
1367 " seat-status [NAME...] Show seat status\n"
1368 " show-seat [NAME...] Show properties of seats or the manager\n"
1369 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1370 " flush-devices Flush all device associations\n"
1371 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1372 , program_invocation_short_name
);
1377 static int parse_argv(int argc
, char *argv
[]) {
1380 ARG_VERSION
= 0x100,
1384 ARG_NO_ASK_PASSWORD
,
1387 static const struct option options
[] = {
1388 { "help", no_argument
, NULL
, 'h' },
1389 { "version", no_argument
, NULL
, ARG_VERSION
},
1390 { "property", required_argument
, NULL
, 'p' },
1391 { "all", no_argument
, NULL
, 'a' },
1392 { "full", no_argument
, NULL
, 'l' },
1393 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1394 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1395 { "kill-who", required_argument
, NULL
, ARG_KILL_WHO
},
1396 { "signal", required_argument
, NULL
, 's' },
1397 { "host", required_argument
, NULL
, 'H' },
1398 { "machine", required_argument
, NULL
, 'M' },
1399 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
1400 { "lines", required_argument
, NULL
, 'n' },
1401 { "output", required_argument
, NULL
, 'o' },
1410 while ((c
= getopt_long(argc
, argv
, "hp:als:H:M:n:o:", options
, NULL
)) >= 0)
1415 help(0, NULL
, NULL
);
1422 r
= strv_extend(&arg_property
, optarg
);
1426 /* If the user asked for a particular
1427 * property, show it to him, even if it is
1442 if (safe_atou(optarg
, &arg_lines
) < 0) {
1443 log_error("Failed to parse lines '%s'", optarg
);
1449 arg_output
= output_mode_from_string(optarg
);
1450 if (arg_output
< 0) {
1451 log_error("Unknown output '%s'.", optarg
);
1457 arg_no_pager
= true;
1464 case ARG_NO_ASK_PASSWORD
:
1465 arg_ask_password
= false;
1469 arg_kill_who
= optarg
;
1473 arg_signal
= signal_from_string_try_harder(optarg
);
1474 if (arg_signal
< 0) {
1475 log_error("Failed to parse signal string %s.", optarg
);
1481 arg_transport
= BUS_TRANSPORT_REMOTE
;
1486 arg_transport
= BUS_TRANSPORT_MACHINE
;
1494 assert_not_reached("Unhandled option");
1500 static int loginctl_main(int argc
, char *argv
[], sd_bus
*bus
) {
1502 static const Verb verbs
[] = {
1503 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1504 { "list-sessions", VERB_ANY
, 1, VERB_DEFAULT
, list_sessions
},
1505 { "session-status", VERB_ANY
, VERB_ANY
, 0, show_session
},
1506 { "show-session", VERB_ANY
, VERB_ANY
, 0, show_session
},
1507 { "activate", VERB_ANY
, 2, 0, activate
},
1508 { "lock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1509 { "unlock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1510 { "lock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1511 { "unlock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1512 { "terminate-session", 2, VERB_ANY
, 0, activate
},
1513 { "kill-session", 2, VERB_ANY
, 0, kill_session
},
1514 { "list-users", VERB_ANY
, 1, 0, list_users
},
1515 { "user-status", VERB_ANY
, VERB_ANY
, 0, show_user
},
1516 { "show-user", VERB_ANY
, VERB_ANY
, 0, show_user
},
1517 { "enable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1518 { "disable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1519 { "terminate-user", 2, VERB_ANY
, 0, terminate_user
},
1520 { "kill-user", 2, VERB_ANY
, 0, kill_user
},
1521 { "list-seats", VERB_ANY
, 1, 0, list_seats
},
1522 { "seat-status", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1523 { "show-seat", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1524 { "attach", 3, VERB_ANY
, 0, attach
},
1525 { "flush-devices", VERB_ANY
, 1, 0, flush_devices
},
1526 { "terminate-seat", 2, VERB_ANY
, 0, terminate_seat
},
1530 return dispatch_verb(argc
, argv
, verbs
, bus
);
1533 int main(int argc
, char *argv
[]) {
1534 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1537 setlocale(LC_ALL
, "");
1538 log_parse_environment();
1541 r
= parse_argv(argc
, argv
);
1545 r
= bus_connect_transport(arg_transport
, arg_host
, false, &bus
);
1547 log_error_errno(r
, "Failed to create bus connection: %m");
1551 sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
1553 r
= loginctl_main(argc
, argv
, bus
);
1557 polkit_agent_close();
1559 strv_free(arg_property
);
1561 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;