1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "bus-error.h"
32 #include "cgroup-show.h"
33 #include "cgroup-util.h"
35 #include "logs-show.h"
38 #include "parse-util.h"
39 #include "process-util.h"
40 #include "signal-util.h"
41 #include "spawn-polkit-agent.h"
43 #include "sysfs-show.h"
44 #include "terminal-util.h"
45 #include "unit-name.h"
46 #include "user-util.h"
50 static char **arg_property
= NULL
;
51 static bool arg_all
= false;
52 static bool arg_full
= false;
53 static bool arg_no_pager
= false;
54 static bool arg_legend
= true;
55 static const char *arg_kill_who
= NULL
;
56 static int arg_signal
= SIGTERM
;
57 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
58 static char *arg_host
= NULL
;
59 static bool arg_ask_password
= true;
60 static unsigned arg_lines
= 10;
61 static OutputMode arg_output
= OUTPUT_SHORT
;
63 static void pager_open_if_enabled(void) {
71 static void polkit_agent_open_if_enabled(void) {
73 /* Open the polkit agent as a child process if necessary */
75 if (!arg_ask_password
)
78 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
84 static OutputFlags
get_output_flags(void) {
87 arg_all
* OUTPUT_SHOW_ALL
|
88 arg_full
* OUTPUT_FULL_WIDTH
|
89 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH
|
90 on_tty() * OUTPUT_COLOR
;
93 static int list_sessions(int argc
, char *argv
[], void *userdata
) {
94 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
95 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
96 const char *id
, *user
, *seat
, *object
;
97 sd_bus
*bus
= userdata
;
105 pager_open_if_enabled();
107 r
= sd_bus_call_method(
109 "org.freedesktop.login1",
110 "/org/freedesktop/login1",
111 "org.freedesktop.login1.Manager",
116 log_error("Failed to list sessions: %s", bus_error_message(&error
, r
));
120 r
= sd_bus_message_enter_container(reply
, 'a', "(susso)");
122 return bus_log_parse_error(r
);
125 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
127 while ((r
= sd_bus_message_read(reply
, "(susso)", &id
, &uid
, &user
, &seat
, &object
)) > 0) {
128 printf("%10s %10u %-16s %-16s\n", id
, (unsigned) uid
, user
, seat
);
132 return bus_log_parse_error(r
);
135 printf("\n%u sessions listed.\n", k
);
140 static int list_users(int argc
, char *argv
[], void *userdata
) {
141 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
142 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
143 const char *user
, *object
;
144 sd_bus
*bus
= userdata
;
152 pager_open_if_enabled();
154 r
= sd_bus_call_method(
156 "org.freedesktop.login1",
157 "/org/freedesktop/login1",
158 "org.freedesktop.login1.Manager",
163 log_error("Failed to list users: %s", bus_error_message(&error
, r
));
167 r
= sd_bus_message_enter_container(reply
, 'a', "(uso)");
169 return bus_log_parse_error(r
);
172 printf("%10s %-16s\n", "UID", "USER");
174 while ((r
= sd_bus_message_read(reply
, "(uso)", &uid
, &user
, &object
)) > 0) {
175 printf("%10u %-16s\n", (unsigned) uid
, user
);
179 return bus_log_parse_error(r
);
182 printf("\n%u users listed.\n", k
);
187 static int list_seats(int argc
, char *argv
[], void *userdata
) {
188 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
189 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
190 const char *seat
, *object
;
191 sd_bus
*bus
= userdata
;
198 pager_open_if_enabled();
200 r
= sd_bus_call_method(
202 "org.freedesktop.login1",
203 "/org/freedesktop/login1",
204 "org.freedesktop.login1.Manager",
209 log_error("Failed to list seats: %s", bus_error_message(&error
, r
));
213 r
= sd_bus_message_enter_container(reply
, 'a', "(so)");
215 return bus_log_parse_error(r
);
218 printf("%-16s\n", "SEAT");
220 while ((r
= sd_bus_message_read(reply
, "(so)", &seat
, &object
)) > 0) {
221 printf("%-16s\n", seat
);
225 return bus_log_parse_error(r
);
228 printf("\n%u seats listed.\n", k
);
233 static int show_unit_cgroup(sd_bus
*bus
, const char *interface
, const char *unit
, pid_t leader
) {
234 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
235 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
236 _cleanup_free_
char *path
= NULL
;
244 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
247 path
= unit_dbus_path_from_name(unit
);
251 r
= sd_bus_get_property(
253 "org.freedesktop.systemd1",
257 &error
, &reply
, "s");
261 r
= sd_bus_message_read(reply
, "s", &cgroup
);
268 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER
, cgroup
) != 0 && leader
<= 0)
277 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER
, cgroup
, "\t\t ", c
, false, &leader
, leader
> 0, get_output_flags());
281 typedef struct SessionStatusInfo
{
285 struct dual_timestamp timestamp
;
302 typedef struct UserStatusInfo
{
305 struct dual_timestamp timestamp
;
312 typedef struct SeatStatusInfo
{
314 char *active_session
;
318 static void session_status_info_clear(SessionStatusInfo
*info
) {
325 free(info
->remote_host
);
326 free(info
->remote_user
);
337 static void user_status_info_clear(UserStatusInfo
*info
) {
341 strv_free(info
->sessions
);
348 static void seat_status_info_clear(SeatStatusInfo
*info
) {
351 free(info
->active_session
);
352 strv_free(info
->sessions
);
357 static int prop_map_first_of_struct(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
358 const char *contents
;
361 r
= sd_bus_message_peek_type(m
, NULL
, &contents
);
365 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_STRUCT
, contents
);
369 if (contents
[0] == 's' || contents
[0] == 'o') {
371 char **p
= (char **) userdata
;
373 r
= sd_bus_message_read_basic(m
, contents
[0], &s
);
377 r
= free_and_strdup(p
, 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 print_property(const char *name
, sd_bus_message
*m
, const char *contents
) {
698 if (arg_property
&& !strv_find(arg_property
, name
))
699 /* skip what we didn't read */
700 return sd_bus_message_skip(m
, contents
);
702 switch (contents
[0]) {
704 case SD_BUS_TYPE_STRUCT_BEGIN
:
706 if (contents
[1] == SD_BUS_TYPE_STRING
&& STR_IN_SET(name
, "Display", "Seat", "ActiveSession")) {
709 r
= sd_bus_message_read(m
, "(so)", &s
, NULL
);
711 return bus_log_parse_error(r
);
713 if (arg_all
|| !isempty(s
))
714 printf("%s=%s\n", name
, s
);
718 } else if (contents
[1] == SD_BUS_TYPE_UINT32
&& streq(name
, "User")) {
721 r
= sd_bus_message_read(m
, "(uo)", &uid
, NULL
);
723 return bus_log_parse_error(r
);
725 if (!uid_is_valid(uid
)) {
726 log_error("Invalid user ID: " UID_FMT
, uid
);
730 printf("%s=" UID_FMT
"\n", name
, uid
);
737 case SD_BUS_TYPE_ARRAY
:
739 if (contents
[1] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "Sessions")) {
743 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(so)");
745 return bus_log_parse_error(r
);
749 while ((r
= sd_bus_message_read(m
, "(so)", &s
, NULL
)) > 0) {
750 printf("%s%s", space
? " " : "", s
);
757 return bus_log_parse_error(r
);
759 r
= sd_bus_message_exit_container(m
);
761 return bus_log_parse_error(r
);
769 r
= bus_print_property(name
, m
, arg_all
);
771 return bus_log_parse_error(r
);
774 r
= sd_bus_message_skip(m
, contents
);
776 return bus_log_parse_error(r
);
779 printf("%s=[unprintable]\n", name
);
785 static int show_properties(sd_bus
*bus
, const char *path
, bool *new_line
) {
786 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
787 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
794 r
= sd_bus_call_method(
796 "org.freedesktop.login1",
798 "org.freedesktop.DBus.Properties",
804 return log_error_errno(r
, "Failed to get properties: %s", bus_error_message(&error
, r
));
806 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "{sv}");
808 return bus_log_parse_error(r
);
815 while ((r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_DICT_ENTRY
, "sv")) > 0) {
816 const char *name
, *contents
;
818 r
= sd_bus_message_read(reply
, "s", &name
);
820 return bus_log_parse_error(r
);
822 r
= sd_bus_message_peek_type(reply
, NULL
, &contents
);
824 return bus_log_parse_error(r
);
826 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_VARIANT
, contents
);
828 return bus_log_parse_error(r
);
830 r
= print_property(name
, reply
, contents
);
834 r
= sd_bus_message_exit_container(reply
);
836 return bus_log_parse_error(r
);
838 r
= sd_bus_message_exit_container(reply
);
840 return bus_log_parse_error(r
);
843 return bus_log_parse_error(r
);
845 r
= sd_bus_message_exit_container(reply
);
847 return bus_log_parse_error(r
);
852 static int show_session(int argc
, char *argv
[], void *userdata
) {
853 bool properties
, new_line
= false;
854 sd_bus
*bus
= userdata
;
860 properties
= !strstr(argv
[0], "status");
862 pager_open_if_enabled();
865 /* If not argument is specified inspect the manager
868 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
870 /* And in the pretty case, show data of the calling session */
871 return print_session_status_info(bus
, "/org/freedesktop/login1/session/self", &new_line
);
874 for (i
= 1; i
< argc
; i
++) {
875 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
876 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
877 const char *path
= NULL
;
879 r
= sd_bus_call_method(
881 "org.freedesktop.login1",
882 "/org/freedesktop/login1",
883 "org.freedesktop.login1.Manager",
888 log_error("Failed to get session: %s", bus_error_message(&error
, r
));
892 r
= sd_bus_message_read(reply
, "o", &path
);
894 return bus_log_parse_error(r
);
897 r
= show_properties(bus
, path
, &new_line
);
899 r
= print_session_status_info(bus
, path
, &new_line
);
908 static int show_user(int argc
, char *argv
[], void *userdata
) {
909 bool properties
, new_line
= false;
910 sd_bus
*bus
= userdata
;
916 properties
= !strstr(argv
[0], "status");
918 pager_open_if_enabled();
921 /* If not argument is specified inspect the manager
924 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
926 return print_user_status_info(bus
, "/org/freedesktop/login1/user/self", &new_line
);
929 for (i
= 1; i
< argc
; i
++) {
930 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
931 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
932 const char *path
= NULL
;
935 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
937 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
939 r
= sd_bus_call_method(
941 "org.freedesktop.login1",
942 "/org/freedesktop/login1",
943 "org.freedesktop.login1.Manager",
946 "u", (uint32_t) uid
);
948 log_error("Failed to get user: %s", bus_error_message(&error
, r
));
952 r
= sd_bus_message_read(reply
, "o", &path
);
954 return bus_log_parse_error(r
);
957 r
= show_properties(bus
, path
, &new_line
);
959 r
= print_user_status_info(bus
, path
, &new_line
);
968 static int show_seat(int argc
, char *argv
[], void *userdata
) {
969 bool properties
, new_line
= false;
970 sd_bus
*bus
= userdata
;
976 properties
= !strstr(argv
[0], "status");
978 pager_open_if_enabled();
981 /* If not argument is specified inspect the manager
984 return show_properties(bus
, "/org/freedesktop/login1", &new_line
);
986 return print_seat_status_info(bus
, "/org/freedesktop/login1/seat/self", &new_line
);
989 for (i
= 1; i
< argc
; i
++) {
990 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
991 _cleanup_bus_message_unref_ sd_bus_message
* reply
= NULL
;
992 const char *path
= NULL
;
994 r
= sd_bus_call_method(
996 "org.freedesktop.login1",
997 "/org/freedesktop/login1",
998 "org.freedesktop.login1.Manager",
1003 log_error("Failed to get seat: %s", bus_error_message(&error
, r
));
1007 r
= sd_bus_message_read(reply
, "o", &path
);
1009 return bus_log_parse_error(r
);
1012 r
= show_properties(bus
, path
, &new_line
);
1014 r
= print_seat_status_info(bus
, path
, &new_line
);
1023 static int activate(int argc
, char *argv
[], void *userdata
) {
1024 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1025 sd_bus
*bus
= userdata
;
1026 char *short_argv
[3];
1032 polkit_agent_open_if_enabled();
1035 /* No argument? Let's convert this into the empty
1036 * session name, which the calls will then resolve to
1037 * the caller's session. */
1039 short_argv
[0] = argv
[0];
1040 short_argv
[1] = (char*) "";
1041 short_argv
[2] = NULL
;
1047 for (i
= 1; i
< argc
; i
++) {
1049 r
= sd_bus_call_method(
1051 "org.freedesktop.login1",
1052 "/org/freedesktop/login1",
1053 "org.freedesktop.login1.Manager",
1054 streq(argv
[0], "lock-session") ? "LockSession" :
1055 streq(argv
[0], "unlock-session") ? "UnlockSession" :
1056 streq(argv
[0], "terminate-session") ? "TerminateSession" :
1061 log_error("Failed to issue method call: %s", bus_error_message(&error
, -r
));
1069 static int kill_session(int argc
, char *argv
[], void *userdata
) {
1070 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1071 sd_bus
*bus
= userdata
;
1077 polkit_agent_open_if_enabled();
1080 arg_kill_who
= "all";
1082 for (i
= 1; i
< argc
; i
++) {
1084 r
= sd_bus_call_method(
1086 "org.freedesktop.login1",
1087 "/org/freedesktop/login1",
1088 "org.freedesktop.login1.Manager",
1091 "ssi", argv
[i
], arg_kill_who
, arg_signal
);
1093 log_error("Could not kill session: %s", bus_error_message(&error
, -r
));
1101 static int enable_linger(int argc
, char *argv
[], void *userdata
) {
1102 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1103 sd_bus
*bus
= userdata
;
1104 char* short_argv
[3];
1111 polkit_agent_open_if_enabled();
1113 b
= streq(argv
[0], "enable-linger");
1116 short_argv
[0] = argv
[0];
1117 short_argv
[1] = (char*) "";
1118 short_argv
[2] = NULL
;
1123 for (i
= 1; i
< argc
; i
++) {
1126 if (isempty(argv
[i
]))
1129 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1131 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1134 r
= sd_bus_call_method(
1136 "org.freedesktop.login1",
1137 "/org/freedesktop/login1",
1138 "org.freedesktop.login1.Manager",
1141 "ubb", (uint32_t) uid
, b
, true);
1143 log_error("Could not enable linger: %s", bus_error_message(&error
, -r
));
1151 static int terminate_user(int argc
, char *argv
[], void *userdata
) {
1152 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1153 sd_bus
*bus
= userdata
;
1159 polkit_agent_open_if_enabled();
1161 for (i
= 1; i
< argc
; i
++) {
1164 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1166 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1168 r
= sd_bus_call_method(
1170 "org.freedesktop.login1",
1171 "/org/freedesktop/login1",
1172 "org.freedesktop.login1.Manager",
1175 "u", (uint32_t) uid
);
1177 log_error("Could not terminate user: %s", bus_error_message(&error
, -r
));
1185 static int kill_user(int argc
, char *argv
[], void *userdata
) {
1186 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1187 sd_bus
*bus
= userdata
;
1193 polkit_agent_open_if_enabled();
1196 arg_kill_who
= "all";
1198 for (i
= 1; i
< argc
; i
++) {
1201 r
= get_user_creds((const char**) (argv
+i
), &uid
, NULL
, NULL
, NULL
);
1203 return log_error_errno(r
, "Failed to look up user %s: %m", argv
[i
]);
1205 r
= sd_bus_call_method(
1207 "org.freedesktop.login1",
1208 "/org/freedesktop/login1",
1209 "org.freedesktop.login1.Manager",
1212 "ui", (uint32_t) uid
, arg_signal
);
1214 log_error("Could not kill user: %s", bus_error_message(&error
, -r
));
1222 static int attach(int argc
, char *argv
[], void *userdata
) {
1223 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1224 sd_bus
*bus
= userdata
;
1230 polkit_agent_open_if_enabled();
1232 for (i
= 2; i
< argc
; i
++) {
1234 r
= sd_bus_call_method(
1236 "org.freedesktop.login1",
1237 "/org/freedesktop/login1",
1238 "org.freedesktop.login1.Manager",
1241 "ssb", argv
[1], argv
[i
], true);
1244 log_error("Could not attach device: %s", bus_error_message(&error
, -r
));
1252 static int flush_devices(int argc
, char *argv
[], void *userdata
) {
1253 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1254 sd_bus
*bus
= userdata
;
1260 polkit_agent_open_if_enabled();
1262 r
= sd_bus_call_method(
1264 "org.freedesktop.login1",
1265 "/org/freedesktop/login1",
1266 "org.freedesktop.login1.Manager",
1271 log_error("Could not flush devices: %s", bus_error_message(&error
, -r
));
1276 static int lock_sessions(int argc
, char *argv
[], void *userdata
) {
1277 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1278 sd_bus
*bus
= userdata
;
1284 polkit_agent_open_if_enabled();
1286 r
= sd_bus_call_method(
1288 "org.freedesktop.login1",
1289 "/org/freedesktop/login1",
1290 "org.freedesktop.login1.Manager",
1291 streq(argv
[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1295 log_error("Could not lock sessions: %s", bus_error_message(&error
, -r
));
1300 static int terminate_seat(int argc
, char *argv
[], void *userdata
) {
1301 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1302 sd_bus
*bus
= userdata
;
1308 polkit_agent_open_if_enabled();
1310 for (i
= 1; i
< argc
; i
++) {
1312 r
= sd_bus_call_method(
1314 "org.freedesktop.login1",
1315 "/org/freedesktop/login1",
1316 "org.freedesktop.login1.Manager",
1321 log_error("Could not terminate seat: %s", bus_error_message(&error
, -r
));
1329 static int help(int argc
, char *argv
[], void *userdata
) {
1331 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1332 "Send control commands to or query the login manager.\n\n"
1333 " -h --help Show this help\n"
1334 " --version Show package version\n"
1335 " --no-pager Do not pipe output into a pager\n"
1336 " --no-legend Do not show the headers and footers\n"
1337 " --no-ask-password Don't prompt for password\n"
1338 " -H --host=[USER@]HOST Operate on remote host\n"
1339 " -M --machine=CONTAINER Operate on local container\n"
1340 " -p --property=NAME Show only properties by this name\n"
1341 " -a --all Show all properties, including empty ones\n"
1342 " -l --full Do not ellipsize output\n"
1343 " --kill-who=WHO Who to send signal to\n"
1344 " -s --signal=SIGNAL Which signal to send\n"
1345 " -n --lines=INTEGER Number of journal entries to show\n"
1346 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1347 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1348 "Session Commands:\n"
1349 " list-sessions List sessions\n"
1350 " session-status [ID...] Show session status\n"
1351 " show-session [ID...] Show properties of sessions or the manager\n"
1352 " activate [ID] Activate a session\n"
1353 " lock-session [ID...] Screen lock one or more sessions\n"
1354 " unlock-session [ID...] Screen unlock one or more sessions\n"
1355 " lock-sessions Screen lock all current sessions\n"
1356 " unlock-sessions Screen unlock all current sessions\n"
1357 " terminate-session ID... Terminate one or more sessions\n"
1358 " kill-session ID... Send signal to processes of a session\n\n"
1360 " list-users List users\n"
1361 " user-status [USER...] Show user status\n"
1362 " show-user [USER...] Show properties of users or the manager\n"
1363 " enable-linger [USER...] Enable linger state of one or more users\n"
1364 " disable-linger [USER...] Disable linger state of one or more users\n"
1365 " terminate-user USER... Terminate all sessions of one or more users\n"
1366 " kill-user USER... Send signal to processes of a user\n\n"
1368 " list-seats List seats\n"
1369 " seat-status [NAME...] Show seat status\n"
1370 " show-seat [NAME...] Show properties of seats or the manager\n"
1371 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1372 " flush-devices Flush all device associations\n"
1373 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1374 , program_invocation_short_name
);
1379 static int parse_argv(int argc
, char *argv
[]) {
1382 ARG_VERSION
= 0x100,
1386 ARG_NO_ASK_PASSWORD
,
1389 static const struct option options
[] = {
1390 { "help", no_argument
, NULL
, 'h' },
1391 { "version", no_argument
, NULL
, ARG_VERSION
},
1392 { "property", required_argument
, NULL
, 'p' },
1393 { "all", no_argument
, NULL
, 'a' },
1394 { "full", no_argument
, NULL
, 'l' },
1395 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1396 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1397 { "kill-who", required_argument
, NULL
, ARG_KILL_WHO
},
1398 { "signal", required_argument
, NULL
, 's' },
1399 { "host", required_argument
, NULL
, 'H' },
1400 { "machine", required_argument
, NULL
, 'M' },
1401 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
1402 { "lines", required_argument
, NULL
, 'n' },
1403 { "output", required_argument
, NULL
, 'o' },
1412 while ((c
= getopt_long(argc
, argv
, "hp:als:H:M:n:o:", options
, NULL
)) >= 0)
1417 help(0, NULL
, NULL
);
1424 r
= strv_extend(&arg_property
, optarg
);
1428 /* If the user asked for a particular
1429 * property, show it to him, even if it is
1444 if (safe_atou(optarg
, &arg_lines
) < 0) {
1445 log_error("Failed to parse lines '%s'", optarg
);
1451 arg_output
= output_mode_from_string(optarg
);
1452 if (arg_output
< 0) {
1453 log_error("Unknown output '%s'.", optarg
);
1459 arg_no_pager
= true;
1466 case ARG_NO_ASK_PASSWORD
:
1467 arg_ask_password
= false;
1471 arg_kill_who
= optarg
;
1475 arg_signal
= signal_from_string_try_harder(optarg
);
1476 if (arg_signal
< 0) {
1477 log_error("Failed to parse signal string %s.", optarg
);
1483 arg_transport
= BUS_TRANSPORT_REMOTE
;
1488 arg_transport
= BUS_TRANSPORT_MACHINE
;
1496 assert_not_reached("Unhandled option");
1502 static int loginctl_main(int argc
, char *argv
[], sd_bus
*bus
) {
1504 static const Verb verbs
[] = {
1505 { "help", VERB_ANY
, VERB_ANY
, 0, help
},
1506 { "list-sessions", VERB_ANY
, 1, VERB_DEFAULT
, list_sessions
},
1507 { "session-status", VERB_ANY
, VERB_ANY
, 0, show_session
},
1508 { "show-session", VERB_ANY
, VERB_ANY
, 0, show_session
},
1509 { "activate", VERB_ANY
, 2, 0, activate
},
1510 { "lock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1511 { "unlock-session", VERB_ANY
, VERB_ANY
, 0, activate
},
1512 { "lock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1513 { "unlock-sessions", VERB_ANY
, 1, 0, lock_sessions
},
1514 { "terminate-session", 2, VERB_ANY
, 0, activate
},
1515 { "kill-session", 2, VERB_ANY
, 0, kill_session
},
1516 { "list-users", VERB_ANY
, 1, 0, list_users
},
1517 { "user-status", VERB_ANY
, VERB_ANY
, 0, show_user
},
1518 { "show-user", VERB_ANY
, VERB_ANY
, 0, show_user
},
1519 { "enable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1520 { "disable-linger", VERB_ANY
, VERB_ANY
, 0, enable_linger
},
1521 { "terminate-user", 2, VERB_ANY
, 0, terminate_user
},
1522 { "kill-user", 2, VERB_ANY
, 0, kill_user
},
1523 { "list-seats", VERB_ANY
, 1, 0, list_seats
},
1524 { "seat-status", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1525 { "show-seat", VERB_ANY
, VERB_ANY
, 0, show_seat
},
1526 { "attach", 3, VERB_ANY
, 0, attach
},
1527 { "flush-devices", VERB_ANY
, 1, 0, flush_devices
},
1528 { "terminate-seat", 2, VERB_ANY
, 0, terminate_seat
},
1532 return dispatch_verb(argc
, argv
, verbs
, bus
);
1535 int main(int argc
, char *argv
[]) {
1536 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1539 setlocale(LC_ALL
, "");
1540 log_parse_environment();
1543 r
= parse_argv(argc
, argv
);
1547 r
= bus_connect_transport(arg_transport
, arg_host
, false, &bus
);
1549 log_error_errno(r
, "Failed to create bus connection: %m");
1553 sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
1555 r
= loginctl_main(argc
, argv
, bus
);
1559 polkit_agent_close();
1561 strv_free(arg_property
);
1563 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;