1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "bus-error.h"
37 #include "unit-name.h"
38 #include "sysfs-show.h"
39 #include "logs-show.h"
40 #include "cgroup-show.h"
41 #include "cgroup-util.h"
42 #include "spawn-polkit-agent.h"
44 #include "process-util.h"
45 #include "terminal-util.h"
46 #include "signal-util.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
, false) != 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 show_properties(sd_bus
*bus
, const char *path
, bool *new_line
) {
697 r
= bus_print_all_properties(bus
, "org.freedesktop.login1", path
, arg_property
, arg_all
);
699 log_error_errno(r
, "Could not get properties: %m");
704 static int show_session(int argc
, char *argv
[], void *userdata
) {
705 bool properties
, new_line
= false;
706 sd_bus
*bus
= userdata
;
712 properties
= !strstr(argv
[0], "status");
714 pager_open_if_enabled();
717 /* If not argument is specified inspect the manager
720 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
722 /* And in the pretty case, show data of the calling session */
723 return print_session_status_info(bus
, "/org/freedesktop/login1/session/self", &new_line
);
726 for (i
= 1; i
< argc
; i
++) {
727 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
728 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
729 const char *path
= NULL
;
731 r
= sd_bus_call_method(
733 "org.freedesktop.login1",
734 "/org/freedesktop/login1",
735 "org.freedesktop.login1.Manager",
740 log_error("Failed to get session: %s", bus_error_message(&error
, r
));
744 r
= sd_bus_message_read(reply
, "o", &path
);
746 return bus_log_parse_error(r
);
749 r
= show_properties(bus
, path
, &new_line
);
751 r
= print_session_status_info(bus
, path
, &new_line
);
760 static int show_user(int argc
, char *argv
[], void *userdata
) {
761 bool properties
, new_line
= false;
762 sd_bus
*bus
= userdata
;
768 properties
= !strstr(argv
[0], "status");
770 pager_open_if_enabled();
773 /* If not argument is specified inspect the manager
776 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
778 return print_user_status_info(bus
, "/org/freedesktop/login1/user/self", &new_line
);
781 for (i
= 1; i
< argc
; i
++) {
782 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
783 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
784 const char *path
= NULL
;
787 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
789 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
791 r
= sd_bus_call_method(
793 "org.freedesktop.login1",
794 "/org/freedesktop/login1",
795 "org.freedesktop.login1.Manager",
798 "u", (uint32_t) uid
);
800 log_error("Failed to get user: %s", bus_error_message(&error
, r
));
804 r
= sd_bus_message_read(reply
, "o", &path
);
806 return bus_log_parse_error(r
);
809 r
= show_properties(bus
, path
, &new_line
);
811 r
= print_user_status_info(bus
, path
, &new_line
);
820 static int show_seat(int argc
, char *argv
[], void *userdata
) {
821 bool properties
, new_line
= false;
822 sd_bus
*bus
= userdata
;
828 properties
= !strstr(argv
[0], "status");
830 pager_open_if_enabled();
833 /* If not argument is specified inspect the manager
836 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
838 return print_seat_status_info(bus
, "/org/freedesktop/login1/seat/self", &new_line
);
841 for (i
= 1; i
< argc
; i
++) {
842 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
843 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
844 const char *path
= NULL
;
846 r
= sd_bus_call_method(
848 "org.freedesktop.login1",
849 "/org/freedesktop/login1",
850 "org.freedesktop.login1.Manager",
855 log_error("Failed to get seat: %s", bus_error_message(&error
, r
));
859 r
= sd_bus_message_read(reply
, "o", &path
);
861 return bus_log_parse_error(r
);
864 r
= show_properties(bus
, path
, &new_line
);
866 r
= print_seat_status_info(bus
, path
, &new_line
);
875 static int activate(int argc
, char *argv
[], void *userdata
) {
876 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
877 sd_bus
*bus
= userdata
;
884 polkit_agent_open_if_enabled();
887 /* No argument? Let's convert this into the empty
888 * session name, which the calls will then resolve to
889 * the caller's session. */
891 short_argv
[0] = argv
[0];
892 short_argv
[1] = (char*) "";
893 short_argv
[2] = NULL
;
899 for (i
= 1; i
< argc
; i
++) {
901 r
= sd_bus_call_method(
903 "org.freedesktop.login1",
904 "/org/freedesktop/login1",
905 "org.freedesktop.login1.Manager",
906 streq(argv
[0], "lock-session") ? "LockSession" :
907 streq(argv
[0], "unlock-session") ? "UnlockSession" :
908 streq(argv
[0], "terminate-session") ? "TerminateSession" :
913 log_error("Failed to issue method call: %s", bus_error_message(&error
, -r
));
921 static int kill_session(int argc
, char *argv
[], void *userdata
) {
922 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
923 sd_bus
*bus
= userdata
;
929 polkit_agent_open_if_enabled();
932 arg_kill_who
= "all";
934 for (i
= 1; i
< argc
; i
++) {
936 r
= sd_bus_call_method(
938 "org.freedesktop.login1",
939 "/org/freedesktop/login1",
940 "org.freedesktop.login1.Manager",
943 "ssi", argv
[i
], arg_kill_who
, arg_signal
);
945 log_error("Could not kill session: %s", bus_error_message(&error
, -r
));
953 static int enable_linger(int argc
, char *argv
[], void *userdata
) {
954 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
955 sd_bus
*bus
= userdata
;
963 polkit_agent_open_if_enabled();
965 b
= streq(argv
[0], "enable-linger");
968 short_argv
[0] = argv
[0];
969 short_argv
[1] = (char*) "";
970 short_argv
[2] = NULL
;
975 for (i
= 1; i
< argc
; i
++) {
978 if (isempty(argv
[i
]))
981 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
983 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
986 r
= sd_bus_call_method(
988 "org.freedesktop.login1",
989 "/org/freedesktop/login1",
990 "org.freedesktop.login1.Manager",
993 "ubb", (uint32_t) uid
, b
, true);
995 log_error("Could not enable linger: %s", bus_error_message(&error
, -r
));
1003 static int terminate_user(int argc
, char *argv
[], void *userdata
) {
1004 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1005 sd_bus
*bus
= userdata
;
1011 polkit_agent_open_if_enabled();
1013 for (i
= 1; i
< argc
; i
++) {
1016 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1018 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1020 r
= sd_bus_call_method(
1022 "org.freedesktop.login1",
1023 "/org/freedesktop/login1",
1024 "org.freedesktop.login1.Manager",
1027 "u", (uint32_t) uid
);
1029 log_error("Could not terminate user: %s", bus_error_message(&error
, -r
));
1037 static int kill_user(int argc
, char *argv
[], void *userdata
) {
1038 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1039 sd_bus
*bus
= userdata
;
1045 polkit_agent_open_if_enabled();
1048 arg_kill_who
= "all";
1050 for (i
= 1; i
< argc
; i
++) {
1053 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1055 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1057 r
= sd_bus_call_method(
1059 "org.freedesktop.login1",
1060 "/org/freedesktop/login1",
1061 "org.freedesktop.login1.Manager",
1064 "ui", (uint32_t) uid
, arg_signal
);
1066 log_error("Could not kill user: %s", bus_error_message(&error
, -r
));
1074 static int attach(int argc
, char *argv
[], void *userdata
) {
1075 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1076 sd_bus
*bus
= userdata
;
1082 polkit_agent_open_if_enabled();
1084 for (i
= 2; i
< argc
; i
++) {
1086 r
= sd_bus_call_method(
1088 "org.freedesktop.login1",
1089 "/org/freedesktop/login1",
1090 "org.freedesktop.login1.Manager",
1093 "ssb", argv
[1], argv
[i
], true);
1096 log_error("Could not attach device: %s", bus_error_message(&error
, -r
));
1104 static int flush_devices(int argc
, char *argv
[], void *userdata
) {
1105 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1106 sd_bus
*bus
= userdata
;
1112 polkit_agent_open_if_enabled();
1114 r
= sd_bus_call_method(
1116 "org.freedesktop.login1",
1117 "/org/freedesktop/login1",
1118 "org.freedesktop.login1.Manager",
1123 log_error("Could not flush devices: %s", bus_error_message(&error
, -r
));
1128 static int lock_sessions(int argc
, char *argv
[], void *userdata
) {
1129 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1130 sd_bus
*bus
= userdata
;
1136 polkit_agent_open_if_enabled();
1138 r
= sd_bus_call_method(
1140 "org.freedesktop.login1",
1141 "/org/freedesktop/login1",
1142 "org.freedesktop.login1.Manager",
1143 streq(argv
[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1147 log_error("Could not lock sessions: %s", bus_error_message(&error
, -r
));
1152 static int terminate_seat(int argc
, char *argv
[], void *userdata
) {
1153 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1154 sd_bus
*bus
= userdata
;
1160 polkit_agent_open_if_enabled();
1162 for (i
= 1; i
< argc
; i
++) {
1164 r
= sd_bus_call_method(
1166 "org.freedesktop.login1",
1167 "/org/freedesktop/login1",
1168 "org.freedesktop.login1.Manager",
1173 log_error("Could not terminate seat: %s", bus_error_message(&error
, -r
));
1181 static int help(int argc
, char *argv
[], void *userdata
) {
1183 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1184 "Send control commands to or query the login manager.\n\n"
1185 " -h --help Show this help\n"
1186 " --version Show package version\n"
1187 " --no-pager Do not pipe output into a pager\n"
1188 " --no-legend Do not show the headers and footers\n"
1189 " --no-ask-password Don't prompt for password\n"
1190 " -H --host=[USER@]HOST Operate on remote host\n"
1191 " -M --machine=CONTAINER Operate on local container\n"
1192 " -p --property=NAME Show only properties by this name\n"
1193 " -a --all Show all properties, including empty ones\n"
1194 " -l --full Do not ellipsize output\n"
1195 " --kill-who=WHO Who to send signal to\n"
1196 " -s --signal=SIGNAL Which signal to send\n"
1197 " -n --lines=INTEGER Number of journal entries to show\n"
1198 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1199 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1200 "Session Commands:\n"
1201 " list-sessions List sessions\n"
1202 " session-status [ID...] Show session status\n"
1203 " show-session [ID...] Show properties of sessions or the manager\n"
1204 " activate [ID] Activate a session\n"
1205 " lock-session [ID...] Screen lock one or more sessions\n"
1206 " unlock-session [ID...] Screen unlock one or more sessions\n"
1207 " lock-sessions Screen lock all current sessions\n"
1208 " unlock-sessions Screen unlock all current sessions\n"
1209 " terminate-session ID... Terminate one or more sessions\n"
1210 " kill-session ID... Send signal to processes of a session\n\n"
1212 " list-users List users\n"
1213 " user-status [USER...] Show user status\n"
1214 " show-user [USER...] Show properties of users or the manager\n"
1215 " enable-linger [USER...] Enable linger state of one or more users\n"
1216 " disable-linger [USER...] Disable linger state of one or more users\n"
1217 " terminate-user USER... Terminate all sessions of one or more users\n"
1218 " kill-user USER... Send signal to processes of a user\n\n"
1220 " list-seats List seats\n"
1221 " seat-status [NAME...] Show seat status\n"
1222 " show-seat [NAME...] Show properties of seats or the manager\n"
1223 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1224 " flush-devices Flush all device associations\n"
1225 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1226 , program_invocation_short_name
);
1231 static int parse_argv(int argc
, char *argv
[]) {
1234 ARG_VERSION
= 0x100,
1238 ARG_NO_ASK_PASSWORD
,
1241 static const struct option options
[] = {
1242 { "help", no_argument
, NULL
, 'h' },
1243 { "version", no_argument
, NULL
, ARG_VERSION
},
1244 { "property", required_argument
, NULL
, 'p' },
1245 { "all", no_argument
, NULL
, 'a' },
1246 { "full", no_argument
, NULL
, 'l' },
1247 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1248 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1249 { "kill-who", required_argument
, NULL
, ARG_KILL_WHO
},
1250 { "signal", required_argument
, NULL
, 's' },
1251 { "host", required_argument
, NULL
, 'H' },
1252 { "machine", required_argument
, NULL
, 'M' },
1253 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
1254 { "lines", required_argument
, NULL
, 'n' },
1255 { "output", required_argument
, NULL
, 'o' },
1264 while ((c
= getopt_long(argc
, argv
, "hp:als:H:M:n:o:", options
, NULL
)) >= 0)
1269 help(0, NULL
, NULL
);
1273 puts(PACKAGE_STRING
);
1274 puts(SYSTEMD_FEATURES
);
1278 r
= strv_extend(&arg_property
, optarg
);
1282 /* If the user asked for a particular
1283 * property, show it to him, even if it is
1298 if (safe_atou(optarg
, &arg_lines
) < 0) {
1299 log_error("Failed to parse lines '%s'", optarg
);
1305 arg_output
= output_mode_from_string(optarg
);
1306 if (arg_output
< 0) {
1307 log_error("Unknown output '%s'.", optarg
);
1313 arg_no_pager
= true;
1320 case ARG_NO_ASK_PASSWORD
:
1321 arg_ask_password
= false;
1325 arg_kill_who
= optarg
;
1329 arg_signal
= signal_from_string_try_harder(optarg
);
1330 if (arg_signal
< 0) {
1331 log_error("Failed to parse signal string %s.", optarg
);
1337 arg_transport
= BUS_TRANSPORT_REMOTE
;
1342 arg_transport
= BUS_TRANSPORT_MACHINE
;
1350 assert_not_reached("Unhandled option");
1356 static int loginctl_main(int argc
, char *argv
[], sd_bus
*bus
) {
1358 static const Verb verbs
[] = {
1359 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1360 { "list-sessions", VERB_ANY
, 1, VERB_DEFAULT
, list_sessions
},
1361 { "session-status", VERB_ANY
, VERB_ANY
, 0, show_session
},
1362 { "show-session", VERB_ANY
, VERB_ANY
, 0, show_session
},
1363 { "activate", VERB_ANY
, 2, 0, activate
},
1364 { "lock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1365 { "unlock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1366 { "lock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1367 { "unlock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1368 { "terminate-session", 2, VERB_ANY
, 0, activate
},
1369 { "kill-session", 2, VERB_ANY
, 0, kill_session
},
1370 { "list-users", VERB_ANY
, 1, 0, list_users
},
1371 { "user-status", VERB_ANY
, VERB_ANY
, 0, show_user
},
1372 { "show-user", VERB_ANY
, VERB_ANY
, 0, show_user
},
1373 { "enable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1374 { "disable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1375 { "terminate-user", 2, VERB_ANY
, 0, terminate_user
},
1376 { "kill-user", 2, VERB_ANY
, 0, kill_user
},
1377 { "list-seats", VERB_ANY
, 1, 0, list_seats
},
1378 { "seat-status", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1379 { "show-seat", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1380 { "attach", 3, VERB_ANY
, 0, attach
},
1381 { "flush-devices", VERB_ANY
, 1, 0, flush_devices
},
1382 { "terminate-seat", 2, VERB_ANY
, 0, terminate_seat
},
1386 return dispatch_verb(argc
, argv
, verbs
, bus
);
1389 int main(int argc
, char *argv
[]) {
1390 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1393 setlocale(LC_ALL
, "");
1394 log_parse_environment();
1397 r
= parse_argv(argc
, argv
);
1401 r
= bus_open_transport(arg_transport
, arg_host
, false, &bus
);
1403 log_error_errno(r
, "Failed to create bus connection: %m");
1407 sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
1409 r
= loginctl_main(argc
, argv
, bus
);
1413 polkit_agent_close();
1415 strv_free(arg_property
);
1417 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;