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
;
289 const char *remote_host
;
290 const char *remote_user
;
300 typedef struct UserStatusInfo
{
303 struct dual_timestamp timestamp
;
310 typedef struct SeatStatusInfo
{
312 const char *active_session
;
316 static int prop_map_first_of_struct(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
317 const char *contents
;
320 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
324 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_STRUCT
, contents
);
328 if (contents
[0] == 's' || contents
[0] == 'o') {
330 char **p
= (char **) userdata
;
332 r
= sd_bus_message_read_basic(m
, contents
[0], &s
);
342 r
= sd_bus_message_read_basic(m
, contents
[0], userdata
);
347 r
= sd_bus_message_skip(m
, contents
+1);
351 r
= sd_bus_message_exit_container(m
);
358 static int prop_map_sessions_strv(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
365 r
= sd_bus_message_enter_container(m
, 'a', "(so)");
369 while ((r
= sd_bus_message_read(m
, "(so)", &name
, NULL
)) > 0) {
370 r
= strv_extend(userdata
, name
);
377 return sd_bus_message_exit_container(m
);
380 static int print_session_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
382 static const struct bus_properties_map map
[] = {
383 { "Id", "s", NULL
, offsetof(SessionStatusInfo
, id
) },
384 { "Name", "s", NULL
, offsetof(SessionStatusInfo
, name
) },
385 { "TTY", "s", NULL
, offsetof(SessionStatusInfo
, tty
) },
386 { "Display", "s", NULL
, offsetof(SessionStatusInfo
, display
) },
387 { "RemoteHost", "s", NULL
, offsetof(SessionStatusInfo
, remote_host
) },
388 { "RemoteUser", "s", NULL
, offsetof(SessionStatusInfo
, remote_user
) },
389 { "Service", "s", NULL
, offsetof(SessionStatusInfo
, service
) },
390 { "Desktop", "s", NULL
, offsetof(SessionStatusInfo
, desktop
) },
391 { "Type", "s", NULL
, offsetof(SessionStatusInfo
, type
) },
392 { "Class", "s", NULL
, offsetof(SessionStatusInfo
, class) },
393 { "Scope", "s", NULL
, offsetof(SessionStatusInfo
, scope
) },
394 { "State", "s", NULL
, offsetof(SessionStatusInfo
, state
) },
395 { "VTNr", "u", NULL
, offsetof(SessionStatusInfo
, vtnr
) },
396 { "Leader", "u", NULL
, offsetof(SessionStatusInfo
, leader
) },
397 { "Remote", "b", NULL
, offsetof(SessionStatusInfo
, remote
) },
398 { "Timestamp", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.realtime
) },
399 { "TimestampMonotonic", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.monotonic
) },
400 { "User", "(uo)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, uid
) },
401 { "Seat", "(so)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, seat
) },
405 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
406 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
407 SessionStatusInfo i
= {};
410 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
412 return log_error_errno(r
, "Could not get properties: %m");
419 printf("%s - ", strna(i
.id
));
422 printf("%s (%u)\n", i
.name
, (unsigned) i
.uid
);
424 printf("%u\n", (unsigned) i
.uid
);
426 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
427 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
430 printf("\t Since: %s; %s\n", s2
, s1
);
432 printf("\t Since: %s\n", s2
);
435 _cleanup_free_
char *t
= NULL
;
437 printf("\t Leader: %u", (unsigned) i
.leader
);
439 get_process_comm(i
.leader
, &t
);
446 if (!isempty(i
.seat
)) {
447 printf("\t Seat: %s", i
.seat
);
450 printf("; vc%u", i
.vtnr
);
456 printf("\t TTY: %s\n", i
.tty
);
458 printf("\t Display: %s\n", i
.display
);
460 if (i
.remote_host
&& i
.remote_user
)
461 printf("\t Remote: %s@%s\n", i
.remote_user
, i
.remote_host
);
462 else if (i
.remote_host
)
463 printf("\t Remote: %s\n", i
.remote_host
);
464 else if (i
.remote_user
)
465 printf("\t Remote: user %s\n", i
.remote_user
);
467 printf("\t Remote: Yes\n");
470 printf("\t Service: %s", i
.service
);
473 printf("; type %s", i
.type
);
476 printf("; class %s", i
.class);
480 printf("\t Type: %s", i
.type
);
483 printf("; class %s", i
.class);
487 printf("\t Class: %s\n", i
.class);
489 if (!isempty(i
.desktop
))
490 printf("\t Desktop: %s\n", i
.desktop
);
493 printf("\t State: %s\n", i
.state
);
496 printf("\t Unit: %s\n", i
.scope
);
497 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Scope", i
.scope
, i
.leader
);
499 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
501 show_journal_by_unit(
506 i
.timestamp
.monotonic
,
509 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
510 SD_JOURNAL_LOCAL_ONLY
,
519 static int print_user_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
521 static const struct bus_properties_map map
[] = {
522 { "Name", "s", NULL
, offsetof(UserStatusInfo
, name
) },
523 { "Slice", "s", NULL
, offsetof(UserStatusInfo
, slice
) },
524 { "State", "s", NULL
, offsetof(UserStatusInfo
, state
) },
525 { "UID", "u", NULL
, offsetof(UserStatusInfo
, uid
) },
526 { "Timestamp", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.realtime
) },
527 { "TimestampMonotonic", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.monotonic
) },
528 { "Display", "(so)", prop_map_first_of_struct
, offsetof(UserStatusInfo
, display
) },
529 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(UserStatusInfo
, sessions
) },
533 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
534 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
535 UserStatusInfo i
= {};
538 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
540 log_error_errno(r
, "Could not get properties: %m");
550 printf("%s (%u)\n", i
.name
, (unsigned) i
.uid
);
552 printf("%u\n", (unsigned) i
.uid
);
554 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
555 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
558 printf("\t Since: %s; %s\n", s2
, s1
);
560 printf("\t Since: %s\n", s2
);
562 if (!isempty(i
.state
))
563 printf("\t State: %s\n", i
.state
);
565 if (!strv_isempty(i
.sessions
)) {
567 printf("\tSessions:");
569 STRV_FOREACH(l
, i
.sessions
) {
570 if (streq_ptr(*l
, i
.display
))
580 printf("\t Unit: %s\n", i
.slice
);
581 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Slice", i
.slice
, 0);
583 show_journal_by_unit(
588 i
.timestamp
.monotonic
,
591 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
592 SD_JOURNAL_LOCAL_ONLY
,
598 strv_free(i
.sessions
);
603 static int print_seat_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
605 static const struct bus_properties_map map
[] = {
606 { "Id", "s", NULL
, offsetof(SeatStatusInfo
, id
) },
607 { "ActiveSession", "(so)", prop_map_first_of_struct
, offsetof(SeatStatusInfo
, active_session
) },
608 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(SeatStatusInfo
, sessions
) },
612 SeatStatusInfo i
= {};
615 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
617 log_error_errno(r
, "Could not get properties: %m");
626 printf("%s\n", strna(i
.id
));
628 if (!strv_isempty(i
.sessions
)) {
630 printf("\tSessions:");
632 STRV_FOREACH(l
, i
.sessions
) {
633 if (streq_ptr(*l
, i
.active_session
))
642 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
651 printf("\t Devices:\n");
653 show_sysfs(i
.id
, "\t\t ", c
);
657 strv_free(i
.sessions
);
662 static int show_properties(sd_bus
*bus
, const char *path
, bool *new_line
) {
670 r
= bus_print_all_properties(bus
, "org.freedesktop.login1", path
, arg_property
, arg_all
);
672 log_error_errno(r
, "Could not get properties: %m");
677 static int show_session(int argc
, char *argv
[], void *userdata
) {
678 bool properties
, new_line
= false;
679 sd_bus
*bus
= userdata
;
685 properties
= !strstr(argv
[0], "status");
687 pager_open_if_enabled();
690 /* If not argument is specified inspect the manager
693 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
695 /* And in the pretty case, show data of the calling session */
696 return print_session_status_info(bus
, "/org/freedesktop/login1/session/self", &new_line
);
699 for (i
= 1; i
< argc
; i
++) {
700 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
701 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
702 const char *path
= NULL
;
704 r
= sd_bus_call_method(
706 "org.freedesktop.login1",
707 "/org/freedesktop/login1",
708 "org.freedesktop.login1.Manager",
713 log_error("Failed to get session: %s", bus_error_message(&error
, r
));
717 r
= sd_bus_message_read(reply
, "o", &path
);
719 return bus_log_parse_error(r
);
722 r
= show_properties(bus
, path
, &new_line
);
724 r
= print_session_status_info(bus
, path
, &new_line
);
733 static int show_user(int argc
, char *argv
[], void *userdata
) {
734 bool properties
, new_line
= false;
735 sd_bus
*bus
= userdata
;
741 properties
= !strstr(argv
[0], "status");
743 pager_open_if_enabled();
746 /* If not argument is specified inspect the manager
749 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
751 return print_user_status_info(bus
, "/org/freedesktop/login1/user/self", &new_line
);
754 for (i
= 1; i
< argc
; i
++) {
755 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
756 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
757 const char *path
= NULL
;
760 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
762 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
764 r
= sd_bus_call_method(
766 "org.freedesktop.login1",
767 "/org/freedesktop/login1",
768 "org.freedesktop.login1.Manager",
771 "u", (uint32_t) uid
);
773 log_error("Failed to get user: %s", bus_error_message(&error
, r
));
777 r
= sd_bus_message_read(reply
, "o", &path
);
779 return bus_log_parse_error(r
);
782 r
= show_properties(bus
, path
, &new_line
);
784 r
= print_user_status_info(bus
, path
, &new_line
);
793 static int show_seat(int argc
, char *argv
[], void *userdata
) {
794 bool properties
, new_line
= false;
795 sd_bus
*bus
= userdata
;
801 properties
= !strstr(argv
[0], "status");
803 pager_open_if_enabled();
806 /* If not argument is specified inspect the manager
809 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
811 return print_seat_status_info(bus
, "/org/freedesktop/login1/seat/self", &new_line
);
814 for (i
= 1; i
< argc
; i
++) {
815 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
816 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
817 const char *path
= NULL
;
819 r
= sd_bus_call_method(
821 "org.freedesktop.login1",
822 "/org/freedesktop/login1",
823 "org.freedesktop.login1.Manager",
828 log_error("Failed to get seat: %s", bus_error_message(&error
, r
));
832 r
= sd_bus_message_read(reply
, "o", &path
);
834 return bus_log_parse_error(r
);
837 r
= show_properties(bus
, path
, &new_line
);
839 r
= print_seat_status_info(bus
, path
, &new_line
);
848 static int activate(int argc
, char *argv
[], void *userdata
) {
849 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
850 sd_bus
*bus
= userdata
;
857 polkit_agent_open_if_enabled();
860 /* No argument? Let's convert this into the empty
861 * session name, which the calls will then resolve to
862 * the caller's session. */
864 short_argv
[0] = argv
[0];
865 short_argv
[1] = (char*) "";
866 short_argv
[2] = NULL
;
872 for (i
= 1; i
< argc
; i
++) {
874 r
= sd_bus_call_method(
876 "org.freedesktop.login1",
877 "/org/freedesktop/login1",
878 "org.freedesktop.login1.Manager",
879 streq(argv
[0], "lock-session") ? "LockSession" :
880 streq(argv
[0], "unlock-session") ? "UnlockSession" :
881 streq(argv
[0], "terminate-session") ? "TerminateSession" :
886 log_error("Failed to issue method call: %s", bus_error_message(&error
, -r
));
894 static int kill_session(int argc
, char *argv
[], void *userdata
) {
895 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
896 sd_bus
*bus
= userdata
;
902 polkit_agent_open_if_enabled();
905 arg_kill_who
= "all";
907 for (i
= 1; i
< argc
; i
++) {
909 r
= sd_bus_call_method(
911 "org.freedesktop.login1",
912 "/org/freedesktop/login1",
913 "org.freedesktop.login1.Manager",
916 "ssi", argv
[i
], arg_kill_who
, arg_signal
);
918 log_error("Could not kill session: %s", bus_error_message(&error
, -r
));
926 static int enable_linger(int argc
, char *argv
[], void *userdata
) {
927 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
928 sd_bus
*bus
= userdata
;
936 polkit_agent_open_if_enabled();
938 b
= streq(argv
[0], "enable-linger");
941 short_argv
[0] = argv
[0];
942 short_argv
[1] = (char*) "";
943 short_argv
[2] = NULL
;
948 for (i
= 1; i
< argc
; i
++) {
951 if (isempty(argv
[i
]))
954 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
956 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
959 r
= sd_bus_call_method(
961 "org.freedesktop.login1",
962 "/org/freedesktop/login1",
963 "org.freedesktop.login1.Manager",
966 "ubb", (uint32_t) uid
, b
, true);
968 log_error("Could not enable linger: %s", bus_error_message(&error
, -r
));
976 static int terminate_user(int argc
, char *argv
[], void *userdata
) {
977 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
978 sd_bus
*bus
= userdata
;
984 polkit_agent_open_if_enabled();
986 for (i
= 1; i
< argc
; i
++) {
989 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
991 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
993 r
= sd_bus_call_method(
995 "org.freedesktop.login1",
996 "/org/freedesktop/login1",
997 "org.freedesktop.login1.Manager",
1000 "u", (uint32_t) uid
);
1002 log_error("Could not terminate user: %s", bus_error_message(&error
, -r
));
1010 static int kill_user(int argc
, char *argv
[], void *userdata
) {
1011 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1012 sd_bus
*bus
= userdata
;
1018 polkit_agent_open_if_enabled();
1021 arg_kill_who
= "all";
1023 for (i
= 1; i
< argc
; i
++) {
1026 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1028 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1030 r
= sd_bus_call_method(
1032 "org.freedesktop.login1",
1033 "/org/freedesktop/login1",
1034 "org.freedesktop.login1.Manager",
1037 "ui", (uint32_t) uid
, arg_signal
);
1039 log_error("Could not kill user: %s", bus_error_message(&error
, -r
));
1047 static int attach(int argc
, char *argv
[], void *userdata
) {
1048 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1049 sd_bus
*bus
= userdata
;
1055 polkit_agent_open_if_enabled();
1057 for (i
= 2; i
< argc
; i
++) {
1059 r
= sd_bus_call_method(
1061 "org.freedesktop.login1",
1062 "/org/freedesktop/login1",
1063 "org.freedesktop.login1.Manager",
1066 "ssb", argv
[1], argv
[i
], true);
1069 log_error("Could not attach device: %s", bus_error_message(&error
, -r
));
1077 static int flush_devices(int argc
, char *argv
[], void *userdata
) {
1078 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1079 sd_bus
*bus
= userdata
;
1085 polkit_agent_open_if_enabled();
1087 r
= sd_bus_call_method(
1089 "org.freedesktop.login1",
1090 "/org/freedesktop/login1",
1091 "org.freedesktop.login1.Manager",
1096 log_error("Could not flush devices: %s", bus_error_message(&error
, -r
));
1101 static int lock_sessions(int argc
, char *argv
[], void *userdata
) {
1102 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1103 sd_bus
*bus
= userdata
;
1109 polkit_agent_open_if_enabled();
1111 r
= sd_bus_call_method(
1113 "org.freedesktop.login1",
1114 "/org/freedesktop/login1",
1115 "org.freedesktop.login1.Manager",
1116 streq(argv
[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1120 log_error("Could not lock sessions: %s", bus_error_message(&error
, -r
));
1125 static int terminate_seat(int argc
, char *argv
[], void *userdata
) {
1126 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1127 sd_bus
*bus
= userdata
;
1133 polkit_agent_open_if_enabled();
1135 for (i
= 1; i
< argc
; i
++) {
1137 r
= sd_bus_call_method(
1139 "org.freedesktop.login1",
1140 "/org/freedesktop/login1",
1141 "org.freedesktop.login1.Manager",
1146 log_error("Could not terminate seat: %s", bus_error_message(&error
, -r
));
1154 static int help(int argc
, char *argv
[], void *userdata
) {
1156 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1157 "Send control commands to or query the login manager.\n\n"
1158 " -h --help Show this help\n"
1159 " --version Show package version\n"
1160 " --no-pager Do not pipe output into a pager\n"
1161 " --no-legend Do not show the headers and footers\n"
1162 " --no-ask-password Don't prompt for password\n"
1163 " -H --host=[USER@]HOST Operate on remote host\n"
1164 " -M --machine=CONTAINER Operate on local container\n"
1165 " -p --property=NAME Show only properties by this name\n"
1166 " -a --all Show all properties, including empty ones\n"
1167 " -l --full Do not ellipsize output\n"
1168 " --kill-who=WHO Who to send signal to\n"
1169 " -s --signal=SIGNAL Which signal to send\n"
1170 " -n --lines=INTEGER Number of journal entries to show\n"
1171 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1172 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1173 "Session Commands:\n"
1174 " list-sessions List sessions\n"
1175 " session-status [ID...] Show session status\n"
1176 " show-session [ID...] Show properties of sessions or the manager\n"
1177 " activate [ID] Activate a session\n"
1178 " lock-session [ID...] Screen lock one or more sessions\n"
1179 " unlock-session [ID...] Screen unlock one or more sessions\n"
1180 " lock-sessions Screen lock all current sessions\n"
1181 " unlock-sessions Screen unlock all current sessions\n"
1182 " terminate-session ID... Terminate one or more sessions\n"
1183 " kill-session ID... Send signal to processes of a session\n\n"
1185 " list-users List users\n"
1186 " user-status [USER...] Show user status\n"
1187 " show-user [USER...] Show properties of users or the manager\n"
1188 " enable-linger [USER...] Enable linger state of one or more users\n"
1189 " disable-linger [USER...] Disable linger state of one or more users\n"
1190 " terminate-user USER... Terminate all sessions of one or more users\n"
1191 " kill-user USER... Send signal to processes of a user\n\n"
1193 " list-seats List seats\n"
1194 " seat-status [NAME...] Show seat status\n"
1195 " show-seat [NAME...] Show properties of seats or the manager\n"
1196 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1197 " flush-devices Flush all device associations\n"
1198 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1199 , program_invocation_short_name
);
1204 static int parse_argv(int argc
, char *argv
[]) {
1207 ARG_VERSION
= 0x100,
1211 ARG_NO_ASK_PASSWORD
,
1214 static const struct option options
[] = {
1215 { "help", no_argument
, NULL
, 'h' },
1216 { "version", no_argument
, NULL
, ARG_VERSION
},
1217 { "property", required_argument
, NULL
, 'p' },
1218 { "all", no_argument
, NULL
, 'a' },
1219 { "full", no_argument
, NULL
, 'l' },
1220 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1221 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1222 { "kill-who", required_argument
, NULL
, ARG_KILL_WHO
},
1223 { "signal", required_argument
, NULL
, 's' },
1224 { "host", required_argument
, NULL
, 'H' },
1225 { "machine", required_argument
, NULL
, 'M' },
1226 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
1227 { "lines", required_argument
, NULL
, 'n' },
1228 { "output", required_argument
, NULL
, 'o' },
1237 while ((c
= getopt_long(argc
, argv
, "hp:als:H:M:n:o:", options
, NULL
)) >= 0)
1242 help(0, NULL
, NULL
);
1246 puts(PACKAGE_STRING
);
1247 puts(SYSTEMD_FEATURES
);
1251 r
= strv_extend(&arg_property
, optarg
);
1255 /* If the user asked for a particular
1256 * property, show it to him, even if it is
1271 if (safe_atou(optarg
, &arg_lines
) < 0) {
1272 log_error("Failed to parse lines '%s'", optarg
);
1278 arg_output
= output_mode_from_string(optarg
);
1279 if (arg_output
< 0) {
1280 log_error("Unknown output '%s'.", optarg
);
1286 arg_no_pager
= true;
1293 case ARG_NO_ASK_PASSWORD
:
1294 arg_ask_password
= false;
1298 arg_kill_who
= optarg
;
1302 arg_signal
= signal_from_string_try_harder(optarg
);
1303 if (arg_signal
< 0) {
1304 log_error("Failed to parse signal string %s.", optarg
);
1310 arg_transport
= BUS_TRANSPORT_REMOTE
;
1315 arg_transport
= BUS_TRANSPORT_MACHINE
;
1323 assert_not_reached("Unhandled option");
1329 static int loginctl_main(int argc
, char *argv
[], sd_bus
*bus
) {
1331 static const Verb verbs
[] = {
1332 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1333 { "list-sessions", VERB_ANY
, 1, VERB_DEFAULT
, list_sessions
},
1334 { "session-status", VERB_ANY
, VERB_ANY
, 0, show_session
},
1335 { "show-session", VERB_ANY
, VERB_ANY
, 0, show_session
},
1336 { "activate", VERB_ANY
, 2, 0, activate
},
1337 { "lock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1338 { "unlock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1339 { "lock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1340 { "unlock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1341 { "terminate-session", 2, VERB_ANY
, 0, activate
},
1342 { "kill-session", 2, VERB_ANY
, 0, kill_session
},
1343 { "list-users", VERB_ANY
, 1, 0, list_users
},
1344 { "user-status", VERB_ANY
, VERB_ANY
, 0, show_user
},
1345 { "show-user", VERB_ANY
, VERB_ANY
, 0, show_user
},
1346 { "enable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1347 { "disable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1348 { "terminate-user", 2, VERB_ANY
, 0, terminate_user
},
1349 { "kill-user", 2, VERB_ANY
, 0, kill_user
},
1350 { "list-seats", VERB_ANY
, 1, 0, list_seats
},
1351 { "seat-status", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1352 { "show-seat", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1353 { "attach", 3, VERB_ANY
, 0, attach
},
1354 { "flush-devices", VERB_ANY
, 1, 0, flush_devices
},
1355 { "terminate-seat", 2, VERB_ANY
, 0, terminate_seat
},
1359 return dispatch_verb(argc
, argv
, verbs
, bus
);
1362 int main(int argc
, char *argv
[]) {
1363 _cleanup_bus_close_unref_ sd_bus
*bus
= NULL
;
1366 setlocale(LC_ALL
, "");
1367 log_parse_environment();
1370 r
= parse_argv(argc
, argv
);
1374 r
= bus_open_transport(arg_transport
, arg_host
, false, &bus
);
1376 log_error_errno(r
, "Failed to create bus connection: %m");
1380 sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
1382 r
= loginctl_main(argc
, argv
, bus
);
1386 polkit_agent_close();
1388 strv_free(arg_property
);
1390 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;