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"
45 #include "user-util.h"
49 static char **arg_property
= NULL
;
50 static bool arg_all
= false;
51 static bool arg_full
= false;
52 static bool arg_no_pager
= false;
53 static bool arg_legend
= true;
54 static const char *arg_kill_who
= NULL
;
55 static int arg_signal
= SIGTERM
;
56 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
57 static char *arg_host
= NULL
;
58 static bool arg_ask_password
= true;
59 static unsigned arg_lines
= 10;
60 static OutputMode arg_output
= OUTPUT_SHORT
;
62 static void pager_open_if_enabled(void) {
70 static void polkit_agent_open_if_enabled(void) {
72 /* Open the polkit agent as a child process if necessary */
74 if (!arg_ask_password
)
77 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
83 static OutputFlags
get_output_flags(void) {
86 arg_all
* OUTPUT_SHOW_ALL
|
87 arg_full
* OUTPUT_FULL_WIDTH
|
88 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH
|
89 on_tty() * OUTPUT_COLOR
;
92 static int list_sessions(int argc
, char *argv
[], void *userdata
) {
93 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
94 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
95 const char *id
, *user
, *seat
, *object
;
96 sd_bus
*bus
= userdata
;
104 pager_open_if_enabled();
106 r
= sd_bus_call_method(
108 "org.freedesktop.login1",
109 "/org/freedesktop/login1",
110 "org.freedesktop.login1.Manager",
115 log_error("Failed to list sessions: %s", bus_error_message(&error
, r
));
119 r
= sd_bus_message_enter_container(reply
, 'a', "(susso)");
121 return bus_log_parse_error(r
);
124 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
126 while ((r
= sd_bus_message_read(reply
, "(susso)", &id
, &uid
, &user
, &seat
, &object
)) > 0) {
127 printf("%10s %10u %-16s %-16s\n", id
, (unsigned) uid
, user
, seat
);
131 return bus_log_parse_error(r
);
134 printf("\n%u sessions listed.\n", k
);
139 static int list_users(int argc
, char *argv
[], void *userdata
) {
140 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
141 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
142 const char *user
, *object
;
143 sd_bus
*bus
= userdata
;
151 pager_open_if_enabled();
153 r
= sd_bus_call_method(
155 "org.freedesktop.login1",
156 "/org/freedesktop/login1",
157 "org.freedesktop.login1.Manager",
162 log_error("Failed to list users: %s", bus_error_message(&error
, r
));
166 r
= sd_bus_message_enter_container(reply
, 'a', "(uso)");
168 return bus_log_parse_error(r
);
171 printf("%10s %-16s\n", "UID", "USER");
173 while ((r
= sd_bus_message_read(reply
, "(uso)", &uid
, &user
, &object
)) > 0) {
174 printf("%10u %-16s\n", (unsigned) uid
, user
);
178 return bus_log_parse_error(r
);
181 printf("\n%u users listed.\n", k
);
186 static int list_seats(int argc
, char *argv
[], void *userdata
) {
187 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
188 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
189 const char *seat
, *object
;
190 sd_bus
*bus
= userdata
;
197 pager_open_if_enabled();
199 r
= sd_bus_call_method(
201 "org.freedesktop.login1",
202 "/org/freedesktop/login1",
203 "org.freedesktop.login1.Manager",
208 log_error("Failed to list seats: %s", bus_error_message(&error
, r
));
212 r
= sd_bus_message_enter_container(reply
, 'a', "(so)");
214 return bus_log_parse_error(r
);
217 printf("%-16s\n", "SEAT");
219 while ((r
= sd_bus_message_read(reply
, "(so)", &seat
, &object
)) > 0) {
220 printf("%-16s\n", seat
);
224 return bus_log_parse_error(r
);
227 printf("\n%u seats listed.\n", k
);
232 static int show_unit_cgroup(sd_bus
*bus
, const char *interface
, const char *unit
, pid_t leader
) {
233 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
234 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
235 _cleanup_free_
char *path
= NULL
;
243 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
246 path
= unit_dbus_path_from_name(unit
);
250 r
= sd_bus_get_property(
252 "org.freedesktop.systemd1",
256 &error
, &reply
, "s");
260 r
= sd_bus_message_read(reply
, "s", &cgroup
);
267 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER
, cgroup
) != 0 && leader
<= 0)
276 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, "\t\t ", c
, false, &leader
, leader
> 0, get_output_flags());
280 typedef struct SessionStatusInfo
{
284 struct dual_timestamp timestamp
;
301 typedef struct UserStatusInfo
{
304 struct dual_timestamp timestamp
;
311 typedef struct SeatStatusInfo
{
313 char *active_session
;
317 static void session_status_info_clear(SessionStatusInfo
*info
) {
324 free(info
->remote_host
);
325 free(info
->remote_user
);
336 static void user_status_info_clear(UserStatusInfo
*info
) {
340 strv_free(info
->sessions
);
347 static void seat_status_info_clear(SeatStatusInfo
*info
) {
350 free(info
->active_session
);
351 strv_free(info
->sessions
);
356 static int prop_map_first_of_struct(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
357 const char *contents
;
360 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
364 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_STRUCT
, contents
);
368 if (contents
[0] == 's' || contents
[0] == 'o') {
370 char **p
= (char **) userdata
;
372 r
= sd_bus_message_read_basic(m
, contents
[0], &s
);
376 r
= free_and_strdup(p
, s
);
380 r
= sd_bus_message_read_basic(m
, contents
[0], userdata
);
385 r
= sd_bus_message_skip(m
, contents
+1);
389 r
= sd_bus_message_exit_container(m
);
396 static int prop_map_sessions_strv(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
403 r
= sd_bus_message_enter_container(m
, 'a', "(so)");
407 while ((r
= sd_bus_message_read(m
, "(so)", &name
, NULL
)) > 0) {
408 r
= strv_extend(userdata
, name
);
415 return sd_bus_message_exit_container(m
);
418 static int print_session_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
420 static const struct bus_properties_map map
[] = {
421 { "Id", "s", NULL
, offsetof(SessionStatusInfo
, id
) },
422 { "Name", "s", NULL
, offsetof(SessionStatusInfo
, name
) },
423 { "TTY", "s", NULL
, offsetof(SessionStatusInfo
, tty
) },
424 { "Display", "s", NULL
, offsetof(SessionStatusInfo
, display
) },
425 { "RemoteHost", "s", NULL
, offsetof(SessionStatusInfo
, remote_host
) },
426 { "RemoteUser", "s", NULL
, offsetof(SessionStatusInfo
, remote_user
) },
427 { "Service", "s", NULL
, offsetof(SessionStatusInfo
, service
) },
428 { "Desktop", "s", NULL
, offsetof(SessionStatusInfo
, desktop
) },
429 { "Type", "s", NULL
, offsetof(SessionStatusInfo
, type
) },
430 { "Class", "s", NULL
, offsetof(SessionStatusInfo
, class) },
431 { "Scope", "s", NULL
, offsetof(SessionStatusInfo
, scope
) },
432 { "State", "s", NULL
, offsetof(SessionStatusInfo
, state
) },
433 { "VTNr", "u", NULL
, offsetof(SessionStatusInfo
, vtnr
) },
434 { "Leader", "u", NULL
, offsetof(SessionStatusInfo
, leader
) },
435 { "Remote", "b", NULL
, offsetof(SessionStatusInfo
, remote
) },
436 { "Timestamp", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.realtime
) },
437 { "TimestampMonotonic", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.monotonic
) },
438 { "User", "(uo)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, uid
) },
439 { "Seat", "(so)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, seat
) },
443 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
444 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
445 _cleanup_(session_status_info_clear
) SessionStatusInfo i
= {};
448 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
450 return log_error_errno(r
, "Could not get properties: %m");
457 printf("%s - ", strna(i
.id
));
460 printf("%s (%u)\n", i
.name
, (unsigned) i
.uid
);
462 printf("%u\n", (unsigned) i
.uid
);
464 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
465 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
468 printf("\t Since: %s; %s\n", s2
, s1
);
470 printf("\t Since: %s\n", s2
);
473 _cleanup_free_
char *t
= NULL
;
475 printf("\t Leader: %u", (unsigned) i
.leader
);
477 get_process_comm(i
.leader
, &t
);
484 if (!isempty(i
.seat
)) {
485 printf("\t Seat: %s", i
.seat
);
488 printf("; vc%u", i
.vtnr
);
494 printf("\t TTY: %s\n", i
.tty
);
496 printf("\t Display: %s\n", i
.display
);
498 if (i
.remote_host
&& i
.remote_user
)
499 printf("\t Remote: %s@%s\n", i
.remote_user
, i
.remote_host
);
500 else if (i
.remote_host
)
501 printf("\t Remote: %s\n", i
.remote_host
);
502 else if (i
.remote_user
)
503 printf("\t Remote: user %s\n", i
.remote_user
);
505 printf("\t Remote: Yes\n");
508 printf("\t Service: %s", i
.service
);
511 printf("; type %s", i
.type
);
514 printf("; class %s", i
.class);
518 printf("\t Type: %s", i
.type
);
521 printf("; class %s", i
.class);
525 printf("\t Class: %s\n", i
.class);
527 if (!isempty(i
.desktop
))
528 printf("\t Desktop: %s\n", i
.desktop
);
531 printf("\t State: %s\n", i
.state
);
534 printf("\t Unit: %s\n", i
.scope
);
535 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Scope", i
.scope
, i
.leader
);
537 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
539 show_journal_by_unit(
544 i
.timestamp
.monotonic
,
547 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
548 SD_JOURNAL_LOCAL_ONLY
,
557 static int print_user_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
559 static const struct bus_properties_map map
[] = {
560 { "Name", "s", NULL
, offsetof(UserStatusInfo
, name
) },
561 { "Slice", "s", NULL
, offsetof(UserStatusInfo
, slice
) },
562 { "State", "s", NULL
, offsetof(UserStatusInfo
, state
) },
563 { "UID", "u", NULL
, offsetof(UserStatusInfo
, uid
) },
564 { "Timestamp", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.realtime
) },
565 { "TimestampMonotonic", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.monotonic
) },
566 { "Display", "(so)", prop_map_first_of_struct
, offsetof(UserStatusInfo
, display
) },
567 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(UserStatusInfo
, sessions
) },
571 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
572 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
573 _cleanup_(user_status_info_clear
) UserStatusInfo i
= {};
576 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
578 return log_error_errno(r
, "Could not get properties: %m");
586 printf("%s (%u)\n", i
.name
, (unsigned) i
.uid
);
588 printf("%u\n", (unsigned) i
.uid
);
590 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
591 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
594 printf("\t Since: %s; %s\n", s2
, s1
);
596 printf("\t Since: %s\n", s2
);
598 if (!isempty(i
.state
))
599 printf("\t State: %s\n", i
.state
);
601 if (!strv_isempty(i
.sessions
)) {
603 printf("\tSessions:");
605 STRV_FOREACH(l
, i
.sessions
) {
606 if (streq_ptr(*l
, i
.display
))
616 printf("\t Unit: %s\n", i
.slice
);
617 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Slice", i
.slice
, 0);
619 show_journal_by_unit(
624 i
.timestamp
.monotonic
,
627 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
628 SD_JOURNAL_LOCAL_ONLY
,
636 static int print_seat_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
638 static const struct bus_properties_map map
[] = {
639 { "Id", "s", NULL
, offsetof(SeatStatusInfo
, id
) },
640 { "ActiveSession", "(so)", prop_map_first_of_struct
, offsetof(SeatStatusInfo
, active_session
) },
641 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(SeatStatusInfo
, sessions
) },
645 _cleanup_(seat_status_info_clear
) SeatStatusInfo i
= {};
648 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
650 return log_error_errno(r
, "Could not get properties: %m");
657 printf("%s\n", strna(i
.id
));
659 if (!strv_isempty(i
.sessions
)) {
661 printf("\tSessions:");
663 STRV_FOREACH(l
, i
.sessions
) {
664 if (streq_ptr(*l
, i
.active_session
))
673 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
682 printf("\t Devices:\n");
684 show_sysfs(i
.id
, "\t\t ", c
);
690 static int print_property(const char *name
, sd_bus_message
*m
, const char *contents
) {
697 if (arg_property
&& !strv_find(arg_property
, name
))
698 /* skip what we didn't read */
699 return sd_bus_message_skip(m
, contents
);
701 switch (contents
[0]) {
703 case SD_BUS_TYPE_STRUCT_BEGIN
:
705 if (contents
[1] == SD_BUS_TYPE_STRING
&& STR_IN_SET(name
, "Display", "Seat", "ActiveSession")) {
708 r
= sd_bus_message_read(m
, "(so)", &s
, NULL
);
710 return bus_log_parse_error(r
);
712 if (arg_all
|| !isempty(s
))
713 printf("%s=%s\n", name
, s
);
717 } else if (contents
[1] == SD_BUS_TYPE_UINT32
&& streq(name
, "User")) {
720 r
= sd_bus_message_read(m
, "(uo)", &uid
, NULL
);
722 return bus_log_parse_error(r
);
724 if (!uid_is_valid(uid
)) {
725 log_error("Invalid user ID: " UID_FMT
, uid
);
729 printf("%s=" UID_FMT
"\n", name
, uid
);
736 case SD_BUS_TYPE_ARRAY
:
738 if (contents
[1] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "Sessions")) {
742 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(so)");
744 return bus_log_parse_error(r
);
748 while ((r
= sd_bus_message_read(m
, "(so)", &s
, NULL
)) > 0) {
749 printf("%s%s", space
? " " : "", s
);
756 return bus_log_parse_error(r
);
758 r
= sd_bus_message_exit_container(m
);
760 return bus_log_parse_error(r
);
768 r
= bus_print_property(name
, m
, arg_all
);
770 return bus_log_parse_error(r
);
773 r
= sd_bus_message_skip(m
, contents
);
775 return bus_log_parse_error(r
);
778 printf("%s=[unprintable]\n", name
);
784 static int show_properties(sd_bus
*bus
, const char *path
, bool *new_line
) {
785 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
786 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
793 r
= sd_bus_call_method(
795 "org.freedesktop.login1",
797 "org.freedesktop.DBus.Properties",
803 return log_error_errno(r
, "Failed to get properties: %s", bus_error_message(&error
, r
));
805 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
807 return bus_log_parse_error(r
);
814 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
815 const char *name
, *contents
;
817 r
= sd_bus_message_read(reply
, "s", &name
);
819 return bus_log_parse_error(r
);
821 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
823 return bus_log_parse_error(r
);
825 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
827 return bus_log_parse_error(r
);
829 r
= print_property(name
, reply
, contents
);
833 r
= sd_bus_message_exit_container(reply
);
835 return bus_log_parse_error(r
);
837 r
= sd_bus_message_exit_container(reply
);
839 return bus_log_parse_error(r
);
842 return bus_log_parse_error(r
);
844 r
= sd_bus_message_exit_container(reply
);
846 return bus_log_parse_error(r
);
851 static int show_session(int argc
, char *argv
[], void *userdata
) {
852 bool properties
, new_line
= false;
853 sd_bus
*bus
= userdata
;
859 properties
= !strstr(argv
[0], "status");
861 pager_open_if_enabled();
864 /* If not argument is specified inspect the manager
867 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
869 /* And in the pretty case, show data of the calling session */
870 return print_session_status_info(bus
, "/org/freedesktop/login1/session/self", &new_line
);
873 for (i
= 1; i
< argc
; i
++) {
874 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
875 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
876 const char *path
= NULL
;
878 r
= sd_bus_call_method(
880 "org.freedesktop.login1",
881 "/org/freedesktop/login1",
882 "org.freedesktop.login1.Manager",
887 log_error("Failed to get session: %s", bus_error_message(&error
, r
));
891 r
= sd_bus_message_read(reply
, "o", &path
);
893 return bus_log_parse_error(r
);
896 r
= show_properties(bus
, path
, &new_line
);
898 r
= print_session_status_info(bus
, path
, &new_line
);
907 static int show_user(int argc
, char *argv
[], void *userdata
) {
908 bool properties
, new_line
= false;
909 sd_bus
*bus
= userdata
;
915 properties
= !strstr(argv
[0], "status");
917 pager_open_if_enabled();
920 /* If not argument is specified inspect the manager
923 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
925 return print_user_status_info(bus
, "/org/freedesktop/login1/user/self", &new_line
);
928 for (i
= 1; i
< argc
; i
++) {
929 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
930 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
931 const char *path
= NULL
;
934 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
936 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
938 r
= sd_bus_call_method(
940 "org.freedesktop.login1",
941 "/org/freedesktop/login1",
942 "org.freedesktop.login1.Manager",
945 "u", (uint32_t) uid
);
947 log_error("Failed to get user: %s", bus_error_message(&error
, r
));
951 r
= sd_bus_message_read(reply
, "o", &path
);
953 return bus_log_parse_error(r
);
956 r
= show_properties(bus
, path
, &new_line
);
958 r
= print_user_status_info(bus
, path
, &new_line
);
967 static int show_seat(int argc
, char *argv
[], void *userdata
) {
968 bool properties
, new_line
= false;
969 sd_bus
*bus
= userdata
;
975 properties
= !strstr(argv
[0], "status");
977 pager_open_if_enabled();
980 /* If not argument is specified inspect the manager
983 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
985 return print_seat_status_info(bus
, "/org/freedesktop/login1/seat/self", &new_line
);
988 for (i
= 1; i
< argc
; i
++) {
989 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
990 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
991 const char *path
= NULL
;
993 r
= sd_bus_call_method(
995 "org.freedesktop.login1",
996 "/org/freedesktop/login1",
997 "org.freedesktop.login1.Manager",
1002 log_error("Failed to get seat: %s", bus_error_message(&error
, r
));
1006 r
= sd_bus_message_read(reply
, "o", &path
);
1008 return bus_log_parse_error(r
);
1011 r
= show_properties(bus
, path
, &new_line
);
1013 r
= print_seat_status_info(bus
, path
, &new_line
);
1022 static int activate(int argc
, char *argv
[], void *userdata
) {
1023 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1024 sd_bus
*bus
= userdata
;
1025 char *short_argv
[3];
1031 polkit_agent_open_if_enabled();
1034 /* No argument? Let's convert this into the empty
1035 * session name, which the calls will then resolve to
1036 * the caller's session. */
1038 short_argv
[0] = argv
[0];
1039 short_argv
[1] = (char*) "";
1040 short_argv
[2] = NULL
;
1046 for (i
= 1; i
< argc
; i
++) {
1048 r
= sd_bus_call_method(
1050 "org.freedesktop.login1",
1051 "/org/freedesktop/login1",
1052 "org.freedesktop.login1.Manager",
1053 streq(argv
[0], "lock-session") ? "LockSession" :
1054 streq(argv
[0], "unlock-session") ? "UnlockSession" :
1055 streq(argv
[0], "terminate-session") ? "TerminateSession" :
1060 log_error("Failed to issue method call: %s", bus_error_message(&error
, -r
));
1068 static int kill_session(int argc
, char *argv
[], void *userdata
) {
1069 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1070 sd_bus
*bus
= userdata
;
1076 polkit_agent_open_if_enabled();
1079 arg_kill_who
= "all";
1081 for (i
= 1; i
< argc
; i
++) {
1083 r
= sd_bus_call_method(
1085 "org.freedesktop.login1",
1086 "/org/freedesktop/login1",
1087 "org.freedesktop.login1.Manager",
1090 "ssi", argv
[i
], arg_kill_who
, arg_signal
);
1092 log_error("Could not kill session: %s", bus_error_message(&error
, -r
));
1100 static int enable_linger(int argc
, char *argv
[], void *userdata
) {
1101 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1102 sd_bus
*bus
= userdata
;
1103 char* short_argv
[3];
1110 polkit_agent_open_if_enabled();
1112 b
= streq(argv
[0], "enable-linger");
1115 short_argv
[0] = argv
[0];
1116 short_argv
[1] = (char*) "";
1117 short_argv
[2] = NULL
;
1122 for (i
= 1; i
< argc
; i
++) {
1125 if (isempty(argv
[i
]))
1128 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1130 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1133 r
= sd_bus_call_method(
1135 "org.freedesktop.login1",
1136 "/org/freedesktop/login1",
1137 "org.freedesktop.login1.Manager",
1140 "ubb", (uint32_t) uid
, b
, true);
1142 log_error("Could not enable linger: %s", bus_error_message(&error
, -r
));
1150 static int terminate_user(int argc
, char *argv
[], void *userdata
) {
1151 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1152 sd_bus
*bus
= userdata
;
1158 polkit_agent_open_if_enabled();
1160 for (i
= 1; i
< argc
; i
++) {
1163 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1165 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1167 r
= sd_bus_call_method(
1169 "org.freedesktop.login1",
1170 "/org/freedesktop/login1",
1171 "org.freedesktop.login1.Manager",
1174 "u", (uint32_t) uid
);
1176 log_error("Could not terminate user: %s", bus_error_message(&error
, -r
));
1184 static int kill_user(int argc
, char *argv
[], void *userdata
) {
1185 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1186 sd_bus
*bus
= userdata
;
1192 polkit_agent_open_if_enabled();
1195 arg_kill_who
= "all";
1197 for (i
= 1; i
< argc
; i
++) {
1200 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1202 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1204 r
= sd_bus_call_method(
1206 "org.freedesktop.login1",
1207 "/org/freedesktop/login1",
1208 "org.freedesktop.login1.Manager",
1211 "ui", (uint32_t) uid
, arg_signal
);
1213 log_error("Could not kill user: %s", bus_error_message(&error
, -r
));
1221 static int attach(int argc
, char *argv
[], void *userdata
) {
1222 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1223 sd_bus
*bus
= userdata
;
1229 polkit_agent_open_if_enabled();
1231 for (i
= 2; i
< argc
; i
++) {
1233 r
= sd_bus_call_method(
1235 "org.freedesktop.login1",
1236 "/org/freedesktop/login1",
1237 "org.freedesktop.login1.Manager",
1240 "ssb", argv
[1], argv
[i
], true);
1243 log_error("Could not attach device: %s", bus_error_message(&error
, -r
));
1251 static int flush_devices(int argc
, char *argv
[], void *userdata
) {
1252 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1253 sd_bus
*bus
= userdata
;
1259 polkit_agent_open_if_enabled();
1261 r
= sd_bus_call_method(
1263 "org.freedesktop.login1",
1264 "/org/freedesktop/login1",
1265 "org.freedesktop.login1.Manager",
1270 log_error("Could not flush devices: %s", bus_error_message(&error
, -r
));
1275 static int lock_sessions(int argc
, char *argv
[], void *userdata
) {
1276 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1277 sd_bus
*bus
= userdata
;
1283 polkit_agent_open_if_enabled();
1285 r
= sd_bus_call_method(
1287 "org.freedesktop.login1",
1288 "/org/freedesktop/login1",
1289 "org.freedesktop.login1.Manager",
1290 streq(argv
[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1294 log_error("Could not lock sessions: %s", bus_error_message(&error
, -r
));
1299 static int terminate_seat(int argc
, char *argv
[], void *userdata
) {
1300 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1301 sd_bus
*bus
= userdata
;
1307 polkit_agent_open_if_enabled();
1309 for (i
= 1; i
< argc
; i
++) {
1311 r
= sd_bus_call_method(
1313 "org.freedesktop.login1",
1314 "/org/freedesktop/login1",
1315 "org.freedesktop.login1.Manager",
1320 log_error("Could not terminate seat: %s", bus_error_message(&error
, -r
));
1328 static int help(int argc
, char *argv
[], void *userdata
) {
1330 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1331 "Send control commands to or query the login manager.\n\n"
1332 " -h --help Show this help\n"
1333 " --version Show package version\n"
1334 " --no-pager Do not pipe output into a pager\n"
1335 " --no-legend Do not show the headers and footers\n"
1336 " --no-ask-password Don't prompt for password\n"
1337 " -H --host=[USER@]HOST Operate on remote host\n"
1338 " -M --machine=CONTAINER Operate on local container\n"
1339 " -p --property=NAME Show only properties by this name\n"
1340 " -a --all Show all properties, including empty ones\n"
1341 " -l --full Do not ellipsize output\n"
1342 " --kill-who=WHO Who to send signal to\n"
1343 " -s --signal=SIGNAL Which signal to send\n"
1344 " -n --lines=INTEGER Number of journal entries to show\n"
1345 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1346 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1347 "Session Commands:\n"
1348 " list-sessions List sessions\n"
1349 " session-status [ID...] Show session status\n"
1350 " show-session [ID...] Show properties of sessions or the manager\n"
1351 " activate [ID] Activate a session\n"
1352 " lock-session [ID...] Screen lock one or more sessions\n"
1353 " unlock-session [ID...] Screen unlock one or more sessions\n"
1354 " lock-sessions Screen lock all current sessions\n"
1355 " unlock-sessions Screen unlock all current sessions\n"
1356 " terminate-session ID... Terminate one or more sessions\n"
1357 " kill-session ID... Send signal to processes of a session\n\n"
1359 " list-users List users\n"
1360 " user-status [USER...] Show user status\n"
1361 " show-user [USER...] Show properties of users or the manager\n"
1362 " enable-linger [USER...] Enable linger state of one or more users\n"
1363 " disable-linger [USER...] Disable linger state of one or more users\n"
1364 " terminate-user USER... Terminate all sessions of one or more users\n"
1365 " kill-user USER... Send signal to processes of a user\n\n"
1367 " list-seats List seats\n"
1368 " seat-status [NAME...] Show seat status\n"
1369 " show-seat [NAME...] Show properties of seats or the manager\n"
1370 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1371 " flush-devices Flush all device associations\n"
1372 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1373 , program_invocation_short_name
);
1378 static int parse_argv(int argc
, char *argv
[]) {
1381 ARG_VERSION
= 0x100,
1385 ARG_NO_ASK_PASSWORD
,
1388 static const struct option options
[] = {
1389 { "help", no_argument
, NULL
, 'h' },
1390 { "version", no_argument
, NULL
, ARG_VERSION
},
1391 { "property", required_argument
, NULL
, 'p' },
1392 { "all", no_argument
, NULL
, 'a' },
1393 { "full", no_argument
, NULL
, 'l' },
1394 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1395 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1396 { "kill-who", required_argument
, NULL
, ARG_KILL_WHO
},
1397 { "signal", required_argument
, NULL
, 's' },
1398 { "host", required_argument
, NULL
, 'H' },
1399 { "machine", required_argument
, NULL
, 'M' },
1400 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
1401 { "lines", required_argument
, NULL
, 'n' },
1402 { "output", required_argument
, NULL
, 'o' },
1411 while ((c
= getopt_long(argc
, argv
, "hp:als:H:M:n:o:", options
, NULL
)) >= 0)
1416 help(0, NULL
, NULL
);
1423 r
= strv_extend(&arg_property
, optarg
);
1427 /* If the user asked for a particular
1428 * property, show it to him, even if it is
1443 if (safe_atou(optarg
, &arg_lines
) < 0) {
1444 log_error("Failed to parse lines '%s'", optarg
);
1450 arg_output
= output_mode_from_string(optarg
);
1451 if (arg_output
< 0) {
1452 log_error("Unknown output '%s'.", optarg
);
1458 arg_no_pager
= true;
1465 case ARG_NO_ASK_PASSWORD
:
1466 arg_ask_password
= false;
1470 arg_kill_who
= optarg
;
1474 arg_signal
= signal_from_string_try_harder(optarg
);
1475 if (arg_signal
< 0) {
1476 log_error("Failed to parse signal string %s.", optarg
);
1482 arg_transport
= BUS_TRANSPORT_REMOTE
;
1487 arg_transport
= BUS_TRANSPORT_MACHINE
;
1495 assert_not_reached("Unhandled option");
1501 static int loginctl_main(int argc
, char *argv
[], sd_bus
*bus
) {
1503 static const Verb verbs
[] = {
1504 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1505 { "list-sessions", VERB_ANY
, 1, VERB_DEFAULT
, list_sessions
},
1506 { "session-status", VERB_ANY
, VERB_ANY
, 0, show_session
},
1507 { "show-session", VERB_ANY
, VERB_ANY
, 0, show_session
},
1508 { "activate", VERB_ANY
, 2, 0, activate
},
1509 { "lock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1510 { "unlock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1511 { "lock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1512 { "unlock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1513 { "terminate-session", 2, VERB_ANY
, 0, activate
},
1514 { "kill-session", 2, VERB_ANY
, 0, kill_session
},
1515 { "list-users", VERB_ANY
, 1, 0, list_users
},
1516 { "user-status", VERB_ANY
, VERB_ANY
, 0, show_user
},
1517 { "show-user", VERB_ANY
, VERB_ANY
, 0, show_user
},
1518 { "enable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1519 { "disable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1520 { "terminate-user", 2, VERB_ANY
, 0, terminate_user
},
1521 { "kill-user", 2, VERB_ANY
, 0, kill_user
},
1522 { "list-seats", VERB_ANY
, 1, 0, list_seats
},
1523 { "seat-status", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1524 { "show-seat", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1525 { "attach", 3, VERB_ANY
, 0, attach
},
1526 { "flush-devices", VERB_ANY
, 1, 0, flush_devices
},
1527 { "terminate-seat", 2, VERB_ANY
, 0, terminate_seat
},
1531 return dispatch_verb(argc
, argv
, verbs
, bus
);
1534 int main(int argc
, char *argv
[]) {
1535 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1538 setlocale(LC_ALL
, "");
1539 log_parse_environment();
1542 r
= parse_argv(argc
, argv
);
1546 r
= bus_connect_transport(arg_transport
, arg_host
, false, &bus
);
1548 log_error_errno(r
, "Failed to create bus connection: %m");
1552 sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
1554 r
= loginctl_main(argc
, argv
, bus
);
1558 polkit_agent_close();
1560 strv_free(arg_property
);
1562 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;