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
);
381 r
= sd_bus_message_read_basic(m
, contents
[0], userdata
);
386 r
= sd_bus_message_skip(m
, contents
+1);
390 r
= sd_bus_message_exit_container(m
);
397 static int prop_map_sessions_strv(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
404 r
= sd_bus_message_enter_container(m
, 'a', "(so)");
408 while ((r
= sd_bus_message_read(m
, "(so)", &name
, NULL
)) > 0) {
409 r
= strv_extend(userdata
, name
);
416 return sd_bus_message_exit_container(m
);
419 static int print_session_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
421 static const struct bus_properties_map map
[] = {
422 { "Id", "s", NULL
, offsetof(SessionStatusInfo
, id
) },
423 { "Name", "s", NULL
, offsetof(SessionStatusInfo
, name
) },
424 { "TTY", "s", NULL
, offsetof(SessionStatusInfo
, tty
) },
425 { "Display", "s", NULL
, offsetof(SessionStatusInfo
, display
) },
426 { "RemoteHost", "s", NULL
, offsetof(SessionStatusInfo
, remote_host
) },
427 { "RemoteUser", "s", NULL
, offsetof(SessionStatusInfo
, remote_user
) },
428 { "Service", "s", NULL
, offsetof(SessionStatusInfo
, service
) },
429 { "Desktop", "s", NULL
, offsetof(SessionStatusInfo
, desktop
) },
430 { "Type", "s", NULL
, offsetof(SessionStatusInfo
, type
) },
431 { "Class", "s", NULL
, offsetof(SessionStatusInfo
, class) },
432 { "Scope", "s", NULL
, offsetof(SessionStatusInfo
, scope
) },
433 { "State", "s", NULL
, offsetof(SessionStatusInfo
, state
) },
434 { "VTNr", "u", NULL
, offsetof(SessionStatusInfo
, vtnr
) },
435 { "Leader", "u", NULL
, offsetof(SessionStatusInfo
, leader
) },
436 { "Remote", "b", NULL
, offsetof(SessionStatusInfo
, remote
) },
437 { "Timestamp", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.realtime
) },
438 { "TimestampMonotonic", "t", NULL
, offsetof(SessionStatusInfo
, timestamp
.monotonic
) },
439 { "User", "(uo)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, uid
) },
440 { "Seat", "(so)", prop_map_first_of_struct
, offsetof(SessionStatusInfo
, seat
) },
444 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
445 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
446 _cleanup_(session_status_info_clear
) SessionStatusInfo i
= {};
449 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
451 return log_error_errno(r
, "Could not get properties: %m");
458 printf("%s - ", strna(i
.id
));
461 printf("%s (%u)\n", i
.name
, (unsigned) i
.uid
);
463 printf("%u\n", (unsigned) i
.uid
);
465 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
466 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
469 printf("\t Since: %s; %s\n", s2
, s1
);
471 printf("\t Since: %s\n", s2
);
474 _cleanup_free_
char *t
= NULL
;
476 printf("\t Leader: %u", (unsigned) i
.leader
);
478 get_process_comm(i
.leader
, &t
);
485 if (!isempty(i
.seat
)) {
486 printf("\t Seat: %s", i
.seat
);
489 printf("; vc%u", i
.vtnr
);
495 printf("\t TTY: %s\n", i
.tty
);
497 printf("\t Display: %s\n", i
.display
);
499 if (i
.remote_host
&& i
.remote_user
)
500 printf("\t Remote: %s@%s\n", i
.remote_user
, i
.remote_host
);
501 else if (i
.remote_host
)
502 printf("\t Remote: %s\n", i
.remote_host
);
503 else if (i
.remote_user
)
504 printf("\t Remote: user %s\n", i
.remote_user
);
506 printf("\t Remote: Yes\n");
509 printf("\t Service: %s", i
.service
);
512 printf("; type %s", i
.type
);
515 printf("; class %s", i
.class);
519 printf("\t Type: %s", i
.type
);
522 printf("; class %s", i
.class);
526 printf("\t Class: %s\n", i
.class);
528 if (!isempty(i
.desktop
))
529 printf("\t Desktop: %s\n", i
.desktop
);
532 printf("\t State: %s\n", i
.state
);
535 printf("\t Unit: %s\n", i
.scope
);
536 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Scope", i
.scope
, i
.leader
);
538 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
540 show_journal_by_unit(
545 i
.timestamp
.monotonic
,
548 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
549 SD_JOURNAL_LOCAL_ONLY
,
558 static int print_user_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
560 static const struct bus_properties_map map
[] = {
561 { "Name", "s", NULL
, offsetof(UserStatusInfo
, name
) },
562 { "Slice", "s", NULL
, offsetof(UserStatusInfo
, slice
) },
563 { "State", "s", NULL
, offsetof(UserStatusInfo
, state
) },
564 { "UID", "u", NULL
, offsetof(UserStatusInfo
, uid
) },
565 { "Timestamp", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.realtime
) },
566 { "TimestampMonotonic", "t", NULL
, offsetof(UserStatusInfo
, timestamp
.monotonic
) },
567 { "Display", "(so)", prop_map_first_of_struct
, offsetof(UserStatusInfo
, display
) },
568 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(UserStatusInfo
, sessions
) },
572 char since1
[FORMAT_TIMESTAMP_RELATIVE_MAX
], *s1
;
573 char since2
[FORMAT_TIMESTAMP_MAX
], *s2
;
574 _cleanup_(user_status_info_clear
) UserStatusInfo i
= {};
577 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
579 return log_error_errno(r
, "Could not get properties: %m");
587 printf("%s (%u)\n", i
.name
, (unsigned) i
.uid
);
589 printf("%u\n", (unsigned) i
.uid
);
591 s1
= format_timestamp_relative(since1
, sizeof(since1
), i
.timestamp
.realtime
);
592 s2
= format_timestamp(since2
, sizeof(since2
), i
.timestamp
.realtime
);
595 printf("\t Since: %s; %s\n", s2
, s1
);
597 printf("\t Since: %s\n", s2
);
599 if (!isempty(i
.state
))
600 printf("\t State: %s\n", i
.state
);
602 if (!strv_isempty(i
.sessions
)) {
604 printf("\tSessions:");
606 STRV_FOREACH(l
, i
.sessions
) {
607 if (streq_ptr(*l
, i
.display
))
617 printf("\t Unit: %s\n", i
.slice
);
618 show_unit_cgroup(bus
, "org.freedesktop.systemd1.Slice", i
.slice
, 0);
620 show_journal_by_unit(
625 i
.timestamp
.monotonic
,
628 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
629 SD_JOURNAL_LOCAL_ONLY
,
637 static int print_seat_status_info(sd_bus
*bus
, const char *path
, bool *new_line
) {
639 static const struct bus_properties_map map
[] = {
640 { "Id", "s", NULL
, offsetof(SeatStatusInfo
, id
) },
641 { "ActiveSession", "(so)", prop_map_first_of_struct
, offsetof(SeatStatusInfo
, active_session
) },
642 { "Sessions", "a(so)", prop_map_sessions_strv
, offsetof(SeatStatusInfo
, sessions
) },
646 _cleanup_(seat_status_info_clear
) SeatStatusInfo i
= {};
649 r
= bus_map_all_properties(bus
, "org.freedesktop.login1", path
, map
, &i
);
651 return log_error_errno(r
, "Could not get properties: %m");
658 printf("%s\n", strna(i
.id
));
660 if (!strv_isempty(i
.sessions
)) {
662 printf("\tSessions:");
664 STRV_FOREACH(l
, i
.sessions
) {
665 if (streq_ptr(*l
, i
.active_session
))
674 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
683 printf("\t Devices:\n");
685 show_sysfs(i
.id
, "\t\t ", c
);
691 static int show_properties(sd_bus
*bus
, const char *path
, bool *new_line
) {
699 r
= bus_print_all_properties(bus
, "org.freedesktop.login1", path
, arg_property
, arg_all
);
701 log_error_errno(r
, "Could not get properties: %m");
706 static int show_session(int argc
, char *argv
[], void *userdata
) {
707 bool properties
, new_line
= false;
708 sd_bus
*bus
= userdata
;
714 properties
= !strstr(argv
[0], "status");
716 pager_open_if_enabled();
719 /* If not argument is specified inspect the manager
722 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
724 /* And in the pretty case, show data of the calling session */
725 return print_session_status_info(bus
, "/org/freedesktop/login1/session/self", &new_line
);
728 for (i
= 1; i
< argc
; i
++) {
729 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
730 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
731 const char *path
= NULL
;
733 r
= sd_bus_call_method(
735 "org.freedesktop.login1",
736 "/org/freedesktop/login1",
737 "org.freedesktop.login1.Manager",
742 log_error("Failed to get session: %s", bus_error_message(&error
, r
));
746 r
= sd_bus_message_read(reply
, "o", &path
);
748 return bus_log_parse_error(r
);
751 r
= show_properties(bus
, path
, &new_line
);
753 r
= print_session_status_info(bus
, path
, &new_line
);
762 static int show_user(int argc
, char *argv
[], void *userdata
) {
763 bool properties
, new_line
= false;
764 sd_bus
*bus
= userdata
;
770 properties
= !strstr(argv
[0], "status");
772 pager_open_if_enabled();
775 /* If not argument is specified inspect the manager
778 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
780 return print_user_status_info(bus
, "/org/freedesktop/login1/user/self", &new_line
);
783 for (i
= 1; i
< argc
; i
++) {
784 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
785 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
786 const char *path
= NULL
;
789 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
791 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
793 r
= sd_bus_call_method(
795 "org.freedesktop.login1",
796 "/org/freedesktop/login1",
797 "org.freedesktop.login1.Manager",
800 "u", (uint32_t) uid
);
802 log_error("Failed to get user: %s", bus_error_message(&error
, r
));
806 r
= sd_bus_message_read(reply
, "o", &path
);
808 return bus_log_parse_error(r
);
811 r
= show_properties(bus
, path
, &new_line
);
813 r
= print_user_status_info(bus
, path
, &new_line
);
822 static int show_seat(int argc
, char *argv
[], void *userdata
) {
823 bool properties
, new_line
= false;
824 sd_bus
*bus
= userdata
;
830 properties
= !strstr(argv
[0], "status");
832 pager_open_if_enabled();
835 /* If not argument is specified inspect the manager
838 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
840 return print_seat_status_info(bus
, "/org/freedesktop/login1/seat/self", &new_line
);
843 for (i
= 1; i
< argc
; i
++) {
844 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
845 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
846 const char *path
= NULL
;
848 r
= sd_bus_call_method(
850 "org.freedesktop.login1",
851 "/org/freedesktop/login1",
852 "org.freedesktop.login1.Manager",
857 log_error("Failed to get seat: %s", bus_error_message(&error
, r
));
861 r
= sd_bus_message_read(reply
, "o", &path
);
863 return bus_log_parse_error(r
);
866 r
= show_properties(bus
, path
, &new_line
);
868 r
= print_seat_status_info(bus
, path
, &new_line
);
877 static int activate(int argc
, char *argv
[], void *userdata
) {
878 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
879 sd_bus
*bus
= userdata
;
886 polkit_agent_open_if_enabled();
889 /* No argument? Let's convert this into the empty
890 * session name, which the calls will then resolve to
891 * the caller's session. */
893 short_argv
[0] = argv
[0];
894 short_argv
[1] = (char*) "";
895 short_argv
[2] = NULL
;
901 for (i
= 1; i
< argc
; i
++) {
903 r
= sd_bus_call_method(
905 "org.freedesktop.login1",
906 "/org/freedesktop/login1",
907 "org.freedesktop.login1.Manager",
908 streq(argv
[0], "lock-session") ? "LockSession" :
909 streq(argv
[0], "unlock-session") ? "UnlockSession" :
910 streq(argv
[0], "terminate-session") ? "TerminateSession" :
915 log_error("Failed to issue method call: %s", bus_error_message(&error
, -r
));
923 static int kill_session(int argc
, char *argv
[], void *userdata
) {
924 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
925 sd_bus
*bus
= userdata
;
931 polkit_agent_open_if_enabled();
934 arg_kill_who
= "all";
936 for (i
= 1; i
< argc
; i
++) {
938 r
= sd_bus_call_method(
940 "org.freedesktop.login1",
941 "/org/freedesktop/login1",
942 "org.freedesktop.login1.Manager",
945 "ssi", argv
[i
], arg_kill_who
, arg_signal
);
947 log_error("Could not kill session: %s", bus_error_message(&error
, -r
));
955 static int enable_linger(int argc
, char *argv
[], void *userdata
) {
956 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
957 sd_bus
*bus
= userdata
;
965 polkit_agent_open_if_enabled();
967 b
= streq(argv
[0], "enable-linger");
970 short_argv
[0] = argv
[0];
971 short_argv
[1] = (char*) "";
972 short_argv
[2] = NULL
;
977 for (i
= 1; i
< argc
; i
++) {
980 if (isempty(argv
[i
]))
983 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
985 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
988 r
= sd_bus_call_method(
990 "org.freedesktop.login1",
991 "/org/freedesktop/login1",
992 "org.freedesktop.login1.Manager",
995 "ubb", (uint32_t) uid
, b
, true);
997 log_error("Could not enable linger: %s", bus_error_message(&error
, -r
));
1005 static int terminate_user(int argc
, char *argv
[], void *userdata
) {
1006 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1007 sd_bus
*bus
= userdata
;
1013 polkit_agent_open_if_enabled();
1015 for (i
= 1; i
< argc
; i
++) {
1018 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1020 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1022 r
= sd_bus_call_method(
1024 "org.freedesktop.login1",
1025 "/org/freedesktop/login1",
1026 "org.freedesktop.login1.Manager",
1029 "u", (uint32_t) uid
);
1031 log_error("Could not terminate user: %s", bus_error_message(&error
, -r
));
1039 static int kill_user(int argc
, char *argv
[], void *userdata
) {
1040 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1041 sd_bus
*bus
= userdata
;
1047 polkit_agent_open_if_enabled();
1050 arg_kill_who
= "all";
1052 for (i
= 1; i
< argc
; i
++) {
1055 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1057 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1059 r
= sd_bus_call_method(
1061 "org.freedesktop.login1",
1062 "/org/freedesktop/login1",
1063 "org.freedesktop.login1.Manager",
1066 "ui", (uint32_t) uid
, arg_signal
);
1068 log_error("Could not kill user: %s", bus_error_message(&error
, -r
));
1076 static int attach(int argc
, char *argv
[], void *userdata
) {
1077 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1078 sd_bus
*bus
= userdata
;
1084 polkit_agent_open_if_enabled();
1086 for (i
= 2; i
< argc
; i
++) {
1088 r
= sd_bus_call_method(
1090 "org.freedesktop.login1",
1091 "/org/freedesktop/login1",
1092 "org.freedesktop.login1.Manager",
1095 "ssb", argv
[1], argv
[i
], true);
1098 log_error("Could not attach device: %s", bus_error_message(&error
, -r
));
1106 static int flush_devices(int argc
, char *argv
[], void *userdata
) {
1107 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1108 sd_bus
*bus
= userdata
;
1114 polkit_agent_open_if_enabled();
1116 r
= sd_bus_call_method(
1118 "org.freedesktop.login1",
1119 "/org/freedesktop/login1",
1120 "org.freedesktop.login1.Manager",
1125 log_error("Could not flush devices: %s", bus_error_message(&error
, -r
));
1130 static int lock_sessions(int argc
, char *argv
[], void *userdata
) {
1131 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1132 sd_bus
*bus
= userdata
;
1138 polkit_agent_open_if_enabled();
1140 r
= sd_bus_call_method(
1142 "org.freedesktop.login1",
1143 "/org/freedesktop/login1",
1144 "org.freedesktop.login1.Manager",
1145 streq(argv
[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1149 log_error("Could not lock sessions: %s", bus_error_message(&error
, -r
));
1154 static int terminate_seat(int argc
, char *argv
[], void *userdata
) {
1155 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1156 sd_bus
*bus
= userdata
;
1162 polkit_agent_open_if_enabled();
1164 for (i
= 1; i
< argc
; i
++) {
1166 r
= sd_bus_call_method(
1168 "org.freedesktop.login1",
1169 "/org/freedesktop/login1",
1170 "org.freedesktop.login1.Manager",
1175 log_error("Could not terminate seat: %s", bus_error_message(&error
, -r
));
1183 static int help(int argc
, char *argv
[], void *userdata
) {
1185 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1186 "Send control commands to or query the login manager.\n\n"
1187 " -h --help Show this help\n"
1188 " --version Show package version\n"
1189 " --no-pager Do not pipe output into a pager\n"
1190 " --no-legend Do not show the headers and footers\n"
1191 " --no-ask-password Don't prompt for password\n"
1192 " -H --host=[USER@]HOST Operate on remote host\n"
1193 " -M --machine=CONTAINER Operate on local container\n"
1194 " -p --property=NAME Show only properties by this name\n"
1195 " -a --all Show all properties, including empty ones\n"
1196 " -l --full Do not ellipsize output\n"
1197 " --kill-who=WHO Who to send signal to\n"
1198 " -s --signal=SIGNAL Which signal to send\n"
1199 " -n --lines=INTEGER Number of journal entries to show\n"
1200 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1201 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1202 "Session Commands:\n"
1203 " list-sessions List sessions\n"
1204 " session-status [ID...] Show session status\n"
1205 " show-session [ID...] Show properties of sessions or the manager\n"
1206 " activate [ID] Activate a session\n"
1207 " lock-session [ID...] Screen lock one or more sessions\n"
1208 " unlock-session [ID...] Screen unlock one or more sessions\n"
1209 " lock-sessions Screen lock all current sessions\n"
1210 " unlock-sessions Screen unlock all current sessions\n"
1211 " terminate-session ID... Terminate one or more sessions\n"
1212 " kill-session ID... Send signal to processes of a session\n\n"
1214 " list-users List users\n"
1215 " user-status [USER...] Show user status\n"
1216 " show-user [USER...] Show properties of users or the manager\n"
1217 " enable-linger [USER...] Enable linger state of one or more users\n"
1218 " disable-linger [USER...] Disable linger state of one or more users\n"
1219 " terminate-user USER... Terminate all sessions of one or more users\n"
1220 " kill-user USER... Send signal to processes of a user\n\n"
1222 " list-seats List seats\n"
1223 " seat-status [NAME...] Show seat status\n"
1224 " show-seat [NAME...] Show properties of seats or the manager\n"
1225 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1226 " flush-devices Flush all device associations\n"
1227 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1228 , program_invocation_short_name
);
1233 static int parse_argv(int argc
, char *argv
[]) {
1236 ARG_VERSION
= 0x100,
1240 ARG_NO_ASK_PASSWORD
,
1243 static const struct option options
[] = {
1244 { "help", no_argument
, NULL
, 'h' },
1245 { "version", no_argument
, NULL
, ARG_VERSION
},
1246 { "property", required_argument
, NULL
, 'p' },
1247 { "all", no_argument
, NULL
, 'a' },
1248 { "full", no_argument
, NULL
, 'l' },
1249 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1250 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1251 { "kill-who", required_argument
, NULL
, ARG_KILL_WHO
},
1252 { "signal", required_argument
, NULL
, 's' },
1253 { "host", required_argument
, NULL
, 'H' },
1254 { "machine", required_argument
, NULL
, 'M' },
1255 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
1256 { "lines", required_argument
, NULL
, 'n' },
1257 { "output", required_argument
, NULL
, 'o' },
1266 while ((c
= getopt_long(argc
, argv
, "hp:als:H:M:n:o:", options
, NULL
)) >= 0)
1271 help(0, NULL
, NULL
);
1275 puts(PACKAGE_STRING
);
1276 puts(SYSTEMD_FEATURES
);
1280 r
= strv_extend(&arg_property
, optarg
);
1284 /* If the user asked for a particular
1285 * property, show it to him, even if it is
1300 if (safe_atou(optarg
, &arg_lines
) < 0) {
1301 log_error("Failed to parse lines '%s'", optarg
);
1307 arg_output
= output_mode_from_string(optarg
);
1308 if (arg_output
< 0) {
1309 log_error("Unknown output '%s'.", optarg
);
1315 arg_no_pager
= true;
1322 case ARG_NO_ASK_PASSWORD
:
1323 arg_ask_password
= false;
1327 arg_kill_who
= optarg
;
1331 arg_signal
= signal_from_string_try_harder(optarg
);
1332 if (arg_signal
< 0) {
1333 log_error("Failed to parse signal string %s.", optarg
);
1339 arg_transport
= BUS_TRANSPORT_REMOTE
;
1344 arg_transport
= BUS_TRANSPORT_MACHINE
;
1352 assert_not_reached("Unhandled option");
1358 static int loginctl_main(int argc
, char *argv
[], sd_bus
*bus
) {
1360 static const Verb verbs
[] = {
1361 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1362 { "list-sessions", VERB_ANY
, 1, VERB_DEFAULT
, list_sessions
},
1363 { "session-status", VERB_ANY
, VERB_ANY
, 0, show_session
},
1364 { "show-session", VERB_ANY
, VERB_ANY
, 0, show_session
},
1365 { "activate", VERB_ANY
, 2, 0, activate
},
1366 { "lock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1367 { "unlock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1368 { "lock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1369 { "unlock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1370 { "terminate-session", 2, VERB_ANY
, 0, activate
},
1371 { "kill-session", 2, VERB_ANY
, 0, kill_session
},
1372 { "list-users", VERB_ANY
, 1, 0, list_users
},
1373 { "user-status", VERB_ANY
, VERB_ANY
, 0, show_user
},
1374 { "show-user", VERB_ANY
, VERB_ANY
, 0, show_user
},
1375 { "enable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1376 { "disable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1377 { "terminate-user", 2, VERB_ANY
, 0, terminate_user
},
1378 { "kill-user", 2, VERB_ANY
, 0, kill_user
},
1379 { "list-seats", VERB_ANY
, 1, 0, list_seats
},
1380 { "seat-status", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1381 { "show-seat", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1382 { "attach", 3, VERB_ANY
, 0, attach
},
1383 { "flush-devices", VERB_ANY
, 1, 0, flush_devices
},
1384 { "terminate-seat", 2, VERB_ANY
, 0, terminate_seat
},
1388 return dispatch_verb(argc
, argv
, verbs
, bus
);
1391 int main(int argc
, char *argv
[]) {
1392 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1395 setlocale(LC_ALL
, "");
1396 log_parse_environment();
1399 r
= parse_argv(argc
, argv
);
1403 r
= bus_open_transport(arg_transport
, arg_host
, false, &bus
);
1405 log_error_errno(r
, "Failed to create bus connection: %m");
1409 sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
1411 r
= loginctl_main(argc
, argv
, bus
);
1415 polkit_agent_close();
1417 strv_free(arg_property
);
1419 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;