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 static char **arg_property
= NULL
;
53 static bool arg_all
= false;
54 static bool arg_value
= false;
55 static bool arg_full
= false;
56 static bool arg_no_pager
= false;
57 static bool arg_legend
= true;
58 static const char *arg_kill_who
= NULL
;
59 static int arg_signal
= SIGTERM
;
60 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
61 static char *arg_host
= NULL
;
62 static bool arg_ask_password
= true;
63 static unsigned arg_lines
= 10;
64 static OutputMode arg_output
= OUTPUT_SHORT
;
66 static OutputFlags
get_output_flags(void) {
69 arg_all
* OUTPUT_SHOW_ALL
|
70 (arg_full
|| !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH
|
71 colors_enabled() * OUTPUT_COLOR
;
74 static int get_session_path(sd_bus
*bus
, const char *session_id
, sd_bus_error
*error
, char **path
) {
75 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
79 r
= sd_bus_call_method(
81 "org.freedesktop.login1",
82 "/org/freedesktop/login1",
83 "org.freedesktop.login1.Manager",
90 r
= sd_bus_message_read(reply
, "o", &ans
);
102 static int list_sessions(int argc
, char *argv
[], void *userdata
) {
103 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
104 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
105 const char *id
, *user
, *seat
, *object
;
106 sd_bus
*bus
= userdata
;
114 pager_open(arg_no_pager
, false);
116 r
= sd_bus_call_method(
118 "org.freedesktop.login1",
119 "/org/freedesktop/login1",
120 "org.freedesktop.login1.Manager",
125 log_error("Failed to list sessions: %s", bus_error_message(&error
, r
));
129 r
= sd_bus_message_enter_container(reply
, 'a', "(susso)");
131 return bus_log_parse_error(r
);
134 printf("%10s %10s %-16s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT", "TTY");
136 while ((r
= sd_bus_message_read(reply
, "(susso)", &id
, &uid
, &user
, &seat
, &object
)) > 0) {
137 _cleanup_(sd_bus_error_free
) sd_bus_error error2
= SD_BUS_ERROR_NULL
;
138 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply2
= NULL
;
139 _cleanup_free_
char *path
= NULL
;
140 const char *tty
= NULL
;
142 r
= get_session_path(bus
, id
, &error2
, &path
);
144 log_warning("Failed to get session path: %s", bus_error_message(&error
, r
));
146 r
= sd_bus_get_property(
148 "org.freedesktop.login1",
150 "org.freedesktop.login1.Session",
156 log_warning("Failed to get TTY for session %s: %s",
157 id
, bus_error_message(&error2
, r
));
159 r
= sd_bus_message_read(reply2
, "s", &tty
);
161 return bus_log_parse_error(r
);
165 printf("%10s %10"PRIu32
" %-16s %-16s %-16s\n", id
, uid
, user
, seat
, strna(tty
));
169 return bus_log_parse_error(r
);
172 printf("\n%u sessions listed.\n", k
);
177 static int list_users(int argc
, char *argv
[], void *userdata
) {
178 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
179 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
180 const char *user
, *object
;
181 sd_bus
*bus
= userdata
;
189 pager_open(arg_no_pager
, false);
191 r
= sd_bus_call_method(
193 "org.freedesktop.login1",
194 "/org/freedesktop/login1",
195 "org.freedesktop.login1.Manager",
200 log_error("Failed to list users: %s", bus_error_message(&error
, r
));
204 r
= sd_bus_message_enter_container(reply
, 'a', "(uso)");
206 return bus_log_parse_error(r
);
209 printf("%10s %-16s\n", "UID", "USER");
211 while ((r
= sd_bus_message_read(reply
, "(uso)", &uid
, &user
, &object
)) > 0) {
212 printf("%10"PRIu32
" %-16s\n", uid
, user
);
216 return bus_log_parse_error(r
);
219 printf("\n%u users listed.\n", k
);
224 static int list_seats(int argc
, char *argv
[], void *userdata
) {
225 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
226 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
227 const char *seat
, *object
;
228 sd_bus
*bus
= userdata
;
234 pager_open(arg_no_pager
, false);
236 r
= sd_bus_call_method(
238 "org.freedesktop.login1",
239 "/org/freedesktop/login1",
240 "org.freedesktop.login1.Manager",
245 log_error("Failed to list seats: %s", bus_error_message(&error
, r
));
249 r
= sd_bus_message_enter_container(reply
, 'a', "(so)");
251 return bus_log_parse_error(r
);
254 printf("%-16s\n", "SEAT");
256 while ((r
= sd_bus_message_read(reply
, "(so)", &seat
, &object
)) > 0) {
257 printf("%-16s\n", seat
);
261 return bus_log_parse_error(r
);
264 printf("\n%u seats listed.\n", k
);
269 static int show_unit_cgroup(sd_bus
*bus
, const char *interface
, const char *unit
, pid_t leader
) {
270 _cleanup_free_
char *cgroup
= NULL
;
271 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
278 r
= show_cgroup_get_unit_path_and_warn(bus
, unit
, &cgroup
);
291 r
= unit_show_processes(bus
, unit
, cgroup
, "\t\t ", c
, get_output_flags(), &error
);
294 if (arg_transport
== BUS_TRANSPORT_REMOTE
)
297 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
299 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER
, cgroup
) != 0 && leader
<= 0)
302 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, "\t\t ", c
, &leader
, leader
> 0, get_output_flags());
304 return log_error_errno(r
, "Failed to dump process list: %s", bus_error_message(&error
, r
));
309 typedef struct SessionStatusInfo
{
313 struct dual_timestamp timestamp
;
330 typedef struct UserStatusInfo
{
334 struct dual_timestamp timestamp
;
341 typedef struct SeatStatusInfo
{
343 char *active_session
;
347 static void session_status_info_clear(SessionStatusInfo
*info
) {
354 free(info
->remote_host
);
355 free(info
->remote_user
);
366 static void user_status_info_clear(UserStatusInfo
*info
) {
370 strv_free(info
->sessions
);
377 static void seat_status_info_clear(SeatStatusInfo
*info
) {
380 free(info
->active_session
);
381 strv_free(info
->sessions
);
386 static int prop_map_first_of_struct(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
387 const char *contents
;
390 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
394 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_STRUCT
, contents
);
398 if (IN_SET(contents
[0], 's', 'o')) {
400 char **p
= (char **) userdata
;
402 r
= sd_bus_message_read_basic(m
, contents
[0], &s
);
406 r
= free_and_strdup(p
, s
);
410 r
= sd_bus_message_read_basic(m
, contents
[0], userdata
);
415 r
= sd_bus_message_skip(m
, contents
+1);
419 r
= sd_bus_message_exit_container(m
);
426 static int prop_map_sessions_strv(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
433 r
= sd_bus_message_enter_container(m
, 'a', "(so)");
437 while ((r
= sd_bus_message_read(m
, "(so)", &name
, NULL
)) > 0) {
438 r
= strv_extend(userdata
, name
);
445 return sd_bus_message_exit_container(m
);
448 static int print_session_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
450 static const struct bus_properties_map map
[] = {
451 { "Id", "s", NULL
, offsetof(SessionStatusInfo
, id
) },
452 { "Name", "s", NULL
, offsetof(SessionStatusInfo
, name
) },
453 { "TTY", "s", NULL
, offsetof(SessionStatusInfo
, tty
) },
454 { "Display", "s", NULL
, offsetof(SessionStatusInfo
, display
) },
455 { "RemoteHost", "s", NULL
, offsetof(SessionStatusInfo
, remote_host
) },
456 { "RemoteUser", "s", NULL
, offsetof(SessionStatusInfo
, remote_user
) },
457 { "Service", "s", NULL
, offsetof(SessionStatusInfo
, service
) },
458 { "Desktop", "s", NULL
, offsetof(SessionStatusInfo
, desktop
) },
459 { "Type", "s", NULL
, offsetof(SessionStatusInfo
, type
) },
460 { "Class", "s", NULL
, offsetof(SessionStatusInfo
, class) },
461 { "Scope", "s", NULL
, offsetof(SessionStatusInfo
, scope
) },
462 { "State", "s", NULL
, offsetof(SessionStatusInfo
, state
) },
463 { "VTNr", "u", NULL
, offsetof(SessionStatusInfo
, vtnr
) },
464 { "Leader", "u", NULL
, offsetof(SessionStatusInfo
, leader
) },
465 { "Remote", "b", NULL
, offsetof(SessionStatusInfo
, remote
) },
466 { "Timestamp", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.realtime
) },
467 { "TimestampMonotonic", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.monotonic
) },
468 { "User", "(uo)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, uid
) },
469 { "Seat", "(so)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, seat
) },
473 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
474 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
475 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
476 _cleanup_(session_status_info_clear
) SessionStatusInfo i
= {};
479 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &error
, &i
);
481 return log_error_errno(r
, "Could not get properties: %s", bus_error_message(&error
, r
));
488 printf("%s - ", strna(i
.id
));
491 printf("%s (%"PRIu32
")\n", i
.name
, i
.uid
);
493 printf("%"PRIu32
"\n", i
.uid
);
495 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
496 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
499 printf("\t Since: %s; %s\n", s2
, s1
);
501 printf("\t Since: %s\n", s2
);
504 _cleanup_free_
char *t
= NULL
;
506 printf("\t Leader: %"PRIu32
, i
.leader
);
508 get_process_comm(i
.leader
, &t
);
515 if (!isempty(i
.seat
)) {
516 printf("\t Seat: %s", i
.seat
);
519 printf("; vc%u", i
.vtnr
);
525 printf("\t TTY: %s\n", i
.tty
);
527 printf("\t Display: %s\n", i
.display
);
529 if (i
.remote_host
&& i
.remote_user
)
530 printf("\t Remote: %s@%s\n", i
.remote_user
, i
.remote_host
);
531 else if (i
.remote_host
)
532 printf("\t Remote: %s\n", i
.remote_host
);
533 else if (i
.remote_user
)
534 printf("\t Remote: user %s\n", i
.remote_user
);
536 printf("\t Remote: Yes\n");
539 printf("\t Service: %s", i
.service
);
542 printf("; type %s", i
.type
);
545 printf("; class %s", i
.class);
549 printf("\t Type: %s", i
.type
);
552 printf("; class %s", i
.class);
556 printf("\t Class: %s\n", i
.class);
558 if (!isempty(i
.desktop
))
559 printf("\t Desktop: %s\n", i
.desktop
);
562 printf("\t State: %s\n", i
.state
);
565 printf("\t Unit: %s\n", i
.scope
);
566 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Scope", i
.scope
, i
.leader
);
568 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
570 show_journal_by_unit(
575 i
.timestamp
.monotonic
,
578 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
579 SD_JOURNAL_LOCAL_ONLY
,
588 static int print_user_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
590 static const struct bus_properties_map map
[] = {
591 { "Name", "s", NULL
, offsetof(UserStatusInfo
, name
) },
592 { "Linger", "b", NULL
, offsetof(UserStatusInfo
, linger
) },
593 { "Slice", "s", NULL
, offsetof(UserStatusInfo
, slice
) },
594 { "State", "s", NULL
, offsetof(UserStatusInfo
, state
) },
595 { "UID", "u", NULL
, offsetof(UserStatusInfo
, uid
) },
596 { "Timestamp", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.realtime
) },
597 { "TimestampMonotonic", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.monotonic
) },
598 { "Display", "(so)", prop_map_first_of_struct
, offsetof(UserStatusInfo
, display
) },
599 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(UserStatusInfo
, sessions
) },
603 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
604 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
605 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
606 _cleanup_(user_status_info_clear
) UserStatusInfo i
= {};
609 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &error
, &i
);
611 return log_error_errno(r
, "Could not get properties: %s", bus_error_message(&error
, r
));
619 printf("%s (%"PRIu32
")\n", i
.name
, i
.uid
);
621 printf("%"PRIu32
"\n", i
.uid
);
623 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
624 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
627 printf("\t Since: %s; %s\n", s2
, s1
);
629 printf("\t Since: %s\n", s2
);
631 if (!isempty(i
.state
))
632 printf("\t State: %s\n", i
.state
);
634 if (!strv_isempty(i
.sessions
)) {
636 printf("\tSessions:");
638 STRV_FOREACH(l
, i
.sessions
)
640 streq_ptr(*l
, i
.display
) ? "*" : "",
646 printf("\t Linger: %s\n", yes_no(i
.linger
));
649 printf("\t Unit: %s\n", i
.slice
);
650 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Slice", i
.slice
, 0);
652 show_journal_by_unit(
657 i
.timestamp
.monotonic
,
660 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
661 SD_JOURNAL_LOCAL_ONLY
,
669 static int print_seat_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
671 static const struct bus_properties_map map
[] = {
672 { "Id", "s", NULL
, offsetof(SeatStatusInfo
, id
) },
673 { "ActiveSession", "(so)", prop_map_first_of_struct
, offsetof(SeatStatusInfo
, active_session
) },
674 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(SeatStatusInfo
, sessions
) },
678 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
679 _cleanup_(seat_status_info_clear
) SeatStatusInfo i
= {};
682 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &error
, &i
);
684 return log_error_errno(r
, "Could not get properties: %s", bus_error_message(&error
, r
));
691 printf("%s\n", strna(i
.id
));
693 if (!strv_isempty(i
.sessions
)) {
695 printf("\tSessions:");
697 STRV_FOREACH(l
, i
.sessions
) {
698 if (streq_ptr(*l
, i
.active_session
))
707 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
716 printf("\t Devices:\n");
718 show_sysfs(i
.id
, "\t\t ", c
, get_output_flags());
724 #define property(name, fmt, ...) \
727 printf(fmt "\n", __VA_ARGS__); \
729 printf("%s=" fmt "\n", name, __VA_ARGS__); \
732 static int print_property(const char *name
, sd_bus_message
*m
, const char *contents
) {
739 if (arg_property
&& !strv_find(arg_property
, name
))
740 /* skip what we didn't read */
741 return sd_bus_message_skip(m
, contents
);
743 switch (contents
[0]) {
745 case SD_BUS_TYPE_STRUCT_BEGIN
:
747 if (contents
[1] == SD_BUS_TYPE_STRING
&& STR_IN_SET(name
, "Display", "Seat", "ActiveSession")) {
750 r
= sd_bus_message_read(m
, "(so)", &s
, NULL
);
752 return bus_log_parse_error(r
);
754 if (arg_all
|| !isempty(s
))
755 property(name
, "%s", s
);
759 } else if (contents
[1] == SD_BUS_TYPE_UINT32
&& streq(name
, "User")) {
762 r
= sd_bus_message_read(m
, "(uo)", &uid
, NULL
);
764 return bus_log_parse_error(r
);
766 if (!uid_is_valid(uid
)) {
767 log_error("Invalid user ID: " UID_FMT
, uid
);
771 property(name
, UID_FMT
, uid
);
777 case SD_BUS_TYPE_ARRAY
:
779 if (contents
[1] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "Sessions")) {
783 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(so)");
785 return bus_log_parse_error(r
);
790 while ((r
= sd_bus_message_read(m
, "(so)", &s
, NULL
)) > 0) {
791 printf("%s%s", space
? " " : "", s
);
795 if (space
|| !arg_value
)
799 return bus_log_parse_error(r
);
801 r
= sd_bus_message_exit_container(m
);
803 return bus_log_parse_error(r
);
811 r
= bus_print_property(name
, m
, arg_value
, arg_all
);
813 return bus_log_parse_error(r
);
816 r
= sd_bus_message_skip(m
, contents
);
818 return bus_log_parse_error(r
);
821 printf("%s=[unprintable]\n", name
);
827 static int show_properties(sd_bus
*bus
, const char *path
, bool *new_line
) {
828 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
829 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
836 r
= sd_bus_call_method(
838 "org.freedesktop.login1",
840 "org.freedesktop.DBus.Properties",
846 return log_error_errno(r
, "Failed to get properties: %s", bus_error_message(&error
, r
));
848 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
850 return bus_log_parse_error(r
);
857 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
858 const char *name
, *contents
;
860 r
= sd_bus_message_read(reply
, "s", &name
);
862 return bus_log_parse_error(r
);
864 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
866 return bus_log_parse_error(r
);
868 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
870 return bus_log_parse_error(r
);
872 r
= print_property(name
, reply
, contents
);
876 r
= sd_bus_message_exit_container(reply
);
878 return bus_log_parse_error(r
);
880 r
= sd_bus_message_exit_container(reply
);
882 return bus_log_parse_error(r
);
885 return bus_log_parse_error(r
);
887 r
= sd_bus_message_exit_container(reply
);
889 return bus_log_parse_error(r
);
894 static int show_session(int argc
, char *argv
[], void *userdata
) {
895 bool properties
, new_line
= false;
896 sd_bus
*bus
= userdata
;
898 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
899 _cleanup_free_
char *path
= NULL
;
904 properties
= !strstr(argv
[0], "status");
906 pager_open(arg_no_pager
, false);
909 const char *session
, *p
= "/org/freedesktop/login1/session/self";
912 /* If no argument is specified inspect the manager itself */
913 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
915 /* And in the pretty case, show data of the calling session */
916 session
= getenv("XDG_SESSION_ID");
918 r
= get_session_path(bus
, session
, &error
, &path
);
920 log_error("Failed to get session path: %s", bus_error_message(&error
, r
));
926 return print_session_status_info(bus
, p
, &new_line
);
929 for (i
= 1; i
< argc
; i
++) {
930 r
= get_session_path(bus
, argv
[i
], &error
, &path
);
932 log_error("Failed to get session path: %s", bus_error_message(&error
, r
));
937 r
= show_properties(bus
, path
, &new_line
);
939 r
= print_session_status_info(bus
, path
, &new_line
);
948 static int show_user(int argc
, char *argv
[], void *userdata
) {
949 bool properties
, new_line
= false;
950 sd_bus
*bus
= userdata
;
956 properties
= !strstr(argv
[0], "status");
958 pager_open(arg_no_pager
, false);
961 /* If not argument is specified inspect the manager
964 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
966 return print_user_status_info(bus
, "/org/freedesktop/login1/user/self", &new_line
);
969 for (i
= 1; i
< argc
; i
++) {
970 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
971 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
972 const char *path
= NULL
;
975 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
977 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
979 r
= sd_bus_call_method(
981 "org.freedesktop.login1",
982 "/org/freedesktop/login1",
983 "org.freedesktop.login1.Manager",
986 "u", (uint32_t) uid
);
988 log_error("Failed to get user: %s", bus_error_message(&error
, r
));
992 r
= sd_bus_message_read(reply
, "o", &path
);
994 return bus_log_parse_error(r
);
997 r
= show_properties(bus
, path
, &new_line
);
999 r
= print_user_status_info(bus
, path
, &new_line
);
1008 static int show_seat(int argc
, char *argv
[], void *userdata
) {
1009 bool properties
, new_line
= false;
1010 sd_bus
*bus
= userdata
;
1016 properties
= !strstr(argv
[0], "status");
1018 pager_open(arg_no_pager
, false);
1021 /* If not argument is specified inspect the manager
1024 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
1026 return print_seat_status_info(bus
, "/org/freedesktop/login1/seat/self", &new_line
);
1029 for (i
= 1; i
< argc
; i
++) {
1030 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1031 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
* reply
= NULL
;
1032 const char *path
= NULL
;
1034 r
= sd_bus_call_method(
1036 "org.freedesktop.login1",
1037 "/org/freedesktop/login1",
1038 "org.freedesktop.login1.Manager",
1043 log_error("Failed to get seat: %s", bus_error_message(&error
, r
));
1047 r
= sd_bus_message_read(reply
, "o", &path
);
1049 return bus_log_parse_error(r
);
1052 r
= show_properties(bus
, path
, &new_line
);
1054 r
= print_seat_status_info(bus
, path
, &new_line
);
1063 static int activate(int argc
, char *argv
[], void *userdata
) {
1064 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1065 sd_bus
*bus
= userdata
;
1066 char *short_argv
[3];
1072 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1075 /* No argument? Let's either use $XDG_SESSION_ID (if specified), or an empty
1076 * session name, in which case logind will try to guess our session. */
1078 short_argv
[0] = argv
[0];
1079 short_argv
[1] = getenv("XDG_SESSION_ID") ?: (char*) "";
1080 short_argv
[2] = NULL
;
1086 for (i
= 1; i
< argc
; i
++) {
1088 r
= sd_bus_call_method(
1090 "org.freedesktop.login1",
1091 "/org/freedesktop/login1",
1092 "org.freedesktop.login1.Manager",
1093 streq(argv
[0], "lock-session") ? "LockSession" :
1094 streq(argv
[0], "unlock-session") ? "UnlockSession" :
1095 streq(argv
[0], "terminate-session") ? "TerminateSession" :
1100 log_error("Failed to issue method call: %s", bus_error_message(&error
, -r
));
1108 static int kill_session(int argc
, char *argv
[], void *userdata
) {
1109 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1110 sd_bus
*bus
= userdata
;
1116 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1119 arg_kill_who
= "all";
1121 for (i
= 1; i
< argc
; i
++) {
1123 r
= sd_bus_call_method(
1125 "org.freedesktop.login1",
1126 "/org/freedesktop/login1",
1127 "org.freedesktop.login1.Manager",
1130 "ssi", argv
[i
], arg_kill_who
, arg_signal
);
1132 log_error("Could not kill session: %s", bus_error_message(&error
, -r
));
1140 static int enable_linger(int argc
, char *argv
[], void *userdata
) {
1141 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1142 sd_bus
*bus
= userdata
;
1143 char* short_argv
[3];
1150 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1152 b
= streq(argv
[0], "enable-linger");
1155 /* No argument? Let's use an empty user name,
1156 * then logind will use our user. */
1158 short_argv
[0] = argv
[0];
1159 short_argv
[1] = (char*) "";
1160 short_argv
[2] = NULL
;
1165 for (i
= 1; i
< argc
; i
++) {
1168 if (isempty(argv
[i
]))
1171 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1173 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1176 r
= sd_bus_call_method(
1178 "org.freedesktop.login1",
1179 "/org/freedesktop/login1",
1180 "org.freedesktop.login1.Manager",
1183 "ubb", (uint32_t) uid
, b
, true);
1185 log_error("Could not enable linger: %s", bus_error_message(&error
, -r
));
1193 static int terminate_user(int argc
, char *argv
[], void *userdata
) {
1194 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1195 sd_bus
*bus
= userdata
;
1201 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1203 for (i
= 1; i
< argc
; i
++) {
1206 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1208 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1210 r
= sd_bus_call_method(
1212 "org.freedesktop.login1",
1213 "/org/freedesktop/login1",
1214 "org.freedesktop.login1.Manager",
1217 "u", (uint32_t) uid
);
1219 log_error("Could not terminate user: %s", bus_error_message(&error
, -r
));
1227 static int kill_user(int argc
, char *argv
[], void *userdata
) {
1228 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1229 sd_bus
*bus
= userdata
;
1235 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1238 arg_kill_who
= "all";
1240 for (i
= 1; i
< argc
; i
++) {
1243 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1245 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1247 r
= sd_bus_call_method(
1249 "org.freedesktop.login1",
1250 "/org/freedesktop/login1",
1251 "org.freedesktop.login1.Manager",
1254 "ui", (uint32_t) uid
, arg_signal
);
1256 log_error("Could not kill user: %s", bus_error_message(&error
, -r
));
1264 static int attach(int argc
, char *argv
[], void *userdata
) {
1265 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1266 sd_bus
*bus
= userdata
;
1272 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1274 for (i
= 2; i
< argc
; i
++) {
1276 r
= sd_bus_call_method(
1278 "org.freedesktop.login1",
1279 "/org/freedesktop/login1",
1280 "org.freedesktop.login1.Manager",
1283 "ssb", argv
[1], argv
[i
], true);
1286 log_error("Could not attach device: %s", bus_error_message(&error
, -r
));
1294 static int flush_devices(int argc
, char *argv
[], void *userdata
) {
1295 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1296 sd_bus
*bus
= userdata
;
1302 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1304 r
= sd_bus_call_method(
1306 "org.freedesktop.login1",
1307 "/org/freedesktop/login1",
1308 "org.freedesktop.login1.Manager",
1313 log_error("Could not flush devices: %s", bus_error_message(&error
, -r
));
1318 static int lock_sessions(int argc
, char *argv
[], void *userdata
) {
1319 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1320 sd_bus
*bus
= userdata
;
1326 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1328 r
= sd_bus_call_method(
1330 "org.freedesktop.login1",
1331 "/org/freedesktop/login1",
1332 "org.freedesktop.login1.Manager",
1333 streq(argv
[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1337 log_error("Could not lock sessions: %s", bus_error_message(&error
, -r
));
1342 static int terminate_seat(int argc
, char *argv
[], void *userdata
) {
1343 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1344 sd_bus
*bus
= userdata
;
1350 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1352 for (i
= 1; i
< argc
; i
++) {
1354 r
= sd_bus_call_method(
1356 "org.freedesktop.login1",
1357 "/org/freedesktop/login1",
1358 "org.freedesktop.login1.Manager",
1363 log_error("Could not terminate seat: %s", bus_error_message(&error
, -r
));
1371 static int help(int argc
, char *argv
[], void *userdata
) {
1373 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1374 "Send control commands to or query the login manager.\n\n"
1375 " -h --help Show this help\n"
1376 " --version Show package version\n"
1377 " --no-pager Do not pipe output into a pager\n"
1378 " --no-legend Do not show the headers and footers\n"
1379 " --no-ask-password Don't prompt for password\n"
1380 " -H --host=[USER@]HOST Operate on remote host\n"
1381 " -M --machine=CONTAINER Operate on local container\n"
1382 " -p --property=NAME Show only properties by this name\n"
1383 " -a --all Show all properties, including empty ones\n"
1384 " --value When showing properties, only print the value\n"
1385 " -l --full Do not ellipsize output\n"
1386 " --kill-who=WHO Who to send signal to\n"
1387 " -s --signal=SIGNAL Which signal to send\n"
1388 " -n --lines=INTEGER Number of journal entries to show\n"
1389 " -o --output=STRING Change journal output mode (short, short-precise,\n"
1390 " short-iso, short-iso-precise, short-full,\n"
1391 " short-monotonic, short-unix, verbose, export,\n"
1392 " json, json-pretty, json-sse, cat)\n"
1393 "Session Commands:\n"
1394 " list-sessions List sessions\n"
1395 " session-status [ID...] Show session status\n"
1396 " show-session [ID...] Show properties of sessions or the manager\n"
1397 " activate [ID] Activate a session\n"
1398 " lock-session [ID...] Screen lock one or more sessions\n"
1399 " unlock-session [ID...] Screen unlock one or more sessions\n"
1400 " lock-sessions Screen lock all current sessions\n"
1401 " unlock-sessions Screen unlock all current sessions\n"
1402 " terminate-session ID... Terminate one or more sessions\n"
1403 " kill-session ID... Send signal to processes of a session\n\n"
1405 " list-users List users\n"
1406 " user-status [USER...] Show user status\n"
1407 " show-user [USER...] Show properties of users or the manager\n"
1408 " enable-linger [USER...] Enable linger state of one or more users\n"
1409 " disable-linger [USER...] Disable linger state of one or more users\n"
1410 " terminate-user USER... Terminate all sessions of one or more users\n"
1411 " kill-user USER... Send signal to processes of a user\n\n"
1413 " list-seats List seats\n"
1414 " seat-status [NAME...] Show seat status\n"
1415 " show-seat [NAME...] Show properties of seats or the manager\n"
1416 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1417 " flush-devices Flush all device associations\n"
1418 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1419 , program_invocation_short_name
);
1424 static int parse_argv(int argc
, char *argv
[]) {
1427 ARG_VERSION
= 0x100,
1432 ARG_NO_ASK_PASSWORD
,
1435 static const struct option options
[] = {
1436 { "help", no_argument
, NULL
, 'h' },
1437 { "version", no_argument
, NULL
, ARG_VERSION
},
1438 { "property", required_argument
, NULL
, 'p' },
1439 { "all", no_argument
, NULL
, 'a' },
1440 { "value", no_argument
, NULL
, ARG_VALUE
},
1441 { "full", no_argument
, NULL
, 'l' },
1442 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1443 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1444 { "kill-who", required_argument
, NULL
, ARG_KILL_WHO
},
1445 { "signal", required_argument
, NULL
, 's' },
1446 { "host", required_argument
, NULL
, 'H' },
1447 { "machine", required_argument
, NULL
, 'M' },
1448 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
1449 { "lines", required_argument
, NULL
, 'n' },
1450 { "output", required_argument
, NULL
, 'o' },
1459 while ((c
= getopt_long(argc
, argv
, "hp:als:H:M:n:o:", options
, NULL
)) >= 0)
1464 help(0, NULL
, NULL
);
1471 r
= strv_extend(&arg_property
, optarg
);
1475 /* If the user asked for a particular
1476 * property, show it to him, even if it is
1495 if (safe_atou(optarg
, &arg_lines
) < 0) {
1496 log_error("Failed to parse lines '%s'", optarg
);
1502 arg_output
= output_mode_from_string(optarg
);
1503 if (arg_output
< 0) {
1504 log_error("Unknown output '%s'.", optarg
);
1510 arg_no_pager
= true;
1517 case ARG_NO_ASK_PASSWORD
:
1518 arg_ask_password
= false;
1522 arg_kill_who
= optarg
;
1526 arg_signal
= signal_from_string_try_harder(optarg
);
1527 if (arg_signal
< 0) {
1528 log_error("Failed to parse signal string %s.", optarg
);
1534 arg_transport
= BUS_TRANSPORT_REMOTE
;
1539 arg_transport
= BUS_TRANSPORT_MACHINE
;
1547 assert_not_reached("Unhandled option");
1553 static int loginctl_main(int argc
, char *argv
[], sd_bus
*bus
) {
1555 static const Verb verbs
[] = {
1556 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1557 { "list-sessions", VERB_ANY
, 1, VERB_DEFAULT
, list_sessions
},
1558 { "session-status", VERB_ANY
, VERB_ANY
, 0, show_session
},
1559 { "show-session", VERB_ANY
, VERB_ANY
, 0, show_session
},
1560 { "activate", VERB_ANY
, 2, 0, activate
},
1561 { "lock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1562 { "unlock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1563 { "lock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1564 { "unlock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1565 { "terminate-session", 2, VERB_ANY
, 0, activate
},
1566 { "kill-session", 2, VERB_ANY
, 0, kill_session
},
1567 { "list-users", VERB_ANY
, 1, 0, list_users
},
1568 { "user-status", VERB_ANY
, VERB_ANY
, 0, show_user
},
1569 { "show-user", VERB_ANY
, VERB_ANY
, 0, show_user
},
1570 { "enable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1571 { "disable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1572 { "terminate-user", 2, VERB_ANY
, 0, terminate_user
},
1573 { "kill-user", 2, VERB_ANY
, 0, kill_user
},
1574 { "list-seats", VERB_ANY
, 1, 0, list_seats
},
1575 { "seat-status", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1576 { "show-seat", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1577 { "attach", 3, VERB_ANY
, 0, attach
},
1578 { "flush-devices", VERB_ANY
, 1, 0, flush_devices
},
1579 { "terminate-seat", 2, VERB_ANY
, 0, terminate_seat
},
1583 return dispatch_verb(argc
, argv
, verbs
, bus
);
1586 int main(int argc
, char *argv
[]) {
1587 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1590 setlocale(LC_ALL
, "");
1591 log_parse_environment();
1595 r
= parse_argv(argc
, argv
);
1599 r
= bus_connect_transport(arg_transport
, arg_host
, false, &bus
);
1601 log_error_errno(r
, "Failed to create bus connection: %m");
1605 sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
1607 r
= loginctl_main(argc
, argv
, bus
);
1611 polkit_agent_close();
1613 strv_free(arg_property
);
1615 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;