1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 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/>.
27 #include "bus-internal.h"
28 #include "bus-signature.h"
31 #include "busctl-introspect.h"
36 #include "path-util.h"
39 #include "terminal-util.h"
40 #include "user-util.h"
43 static bool arg_no_pager
= false;
44 static bool arg_legend
= true;
45 static char *arg_address
= NULL
;
46 static bool arg_unique
= false;
47 static bool arg_acquired
= false;
48 static bool arg_activatable
= false;
49 static bool arg_show_machine
= false;
50 static char **arg_matches
= NULL
;
51 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
52 static char *arg_host
= NULL
;
53 static bool arg_user
= false;
54 static size_t arg_snaplen
= 4096;
55 static bool arg_list
= false;
56 static bool arg_quiet
= false;
57 static bool arg_verbose
= false;
58 static bool arg_expect_reply
= true;
59 static bool arg_auto_start
= true;
60 static bool arg_allow_interactive_authorization
= true;
61 static bool arg_augment_creds
= true;
62 static usec_t arg_timeout
= 0;
64 static void pager_open_if_enabled(void) {
66 /* Cache result before we open the pager */
73 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
74 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
76 static int list_bus_names(sd_bus
*bus
, char **argv
) {
77 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
78 _cleanup_free_
char **merged
= NULL
;
79 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
90 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
91 arg_unique
= arg_acquired
= arg_activatable
= true;
93 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
95 return log_error_errno(r
, "Failed to list names: %m");
97 pager_open_if_enabled();
99 names
= hashmap_new(&string_hash_ops
);
103 STRV_FOREACH(i
, acquired
) {
104 max_i
= MAX(max_i
, strlen(*i
));
106 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
108 return log_error_errno(r
, "Failed to add to hashmap: %m");
111 STRV_FOREACH(i
, activatable
) {
112 max_i
= MAX(max_i
, strlen(*i
));
114 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
115 if (r
< 0 && r
!= -EEXIST
)
116 return log_error_errno(r
, "Failed to add to hashmap: %m");
119 merged
= new(char*, hashmap_size(names
) + 1);
120 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
127 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
128 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
130 if (arg_show_machine
)
136 STRV_FOREACH(i
, merged
) {
137 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
140 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
143 printf("%-*s", (int) max_i
, *i
);
144 printf(" - - - (activatable) - - ");
145 if (arg_show_machine
)
153 if (!arg_unique
&& (*i
)[0] == ':')
156 if (!arg_acquired
&& (*i
)[0] != ':')
159 printf("%-*s", (int) max_i
, *i
);
161 r
= sd_bus_get_name_creds(
163 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
164 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
165 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
166 SD_BUS_CREDS_DESCRIPTION
, &creds
);
168 const char *unique
, *session
, *unit
, *cn
;
172 r
= sd_bus_creds_get_pid(creds
, &pid
);
174 const char *comm
= NULL
;
176 sd_bus_creds_get_comm(creds
, &comm
);
178 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
180 fputs(" - - ", stdout
);
182 r
= sd_bus_creds_get_euid(creds
, &uid
);
184 _cleanup_free_
char *u
= NULL
;
186 u
= uid_to_name(uid
);
195 fputs(" - ", stdout
);
197 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
199 printf(" %-13s", unique
);
201 fputs(" - ", stdout
);
203 r
= sd_bus_creds_get_unit(creds
, &unit
);
205 _cleanup_free_
char *e
;
207 e
= ellipsize(unit
, 25, 100);
213 fputs(" - ", stdout
);
215 r
= sd_bus_creds_get_session(creds
, &session
);
217 printf(" %-10s", session
);
219 fputs(" - ", stdout
);
221 r
= sd_bus_creds_get_description(creds
, &cn
);
223 printf(" %-19s", cn
);
225 fputs(" - ", stdout
);
228 printf(" - - - - - - - ");
230 if (arg_show_machine
) {
231 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
233 char m
[SD_ID128_STRING_MAX
];
234 printf(" %s\n", sd_id128_to_string(mid
, m
));
244 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
245 const char *vertical
, *space
;
248 /* We assume the list is sorted. Let's first skip over the
249 * entry we are looking at. */
254 if (!streq(*l
, path
))
260 vertical
= strjoina(prefix
, draw_special_char(DRAW_TREE_VERTICAL
));
261 space
= strjoina(prefix
, draw_special_char(DRAW_TREE_SPACE
));
264 bool has_more
= false;
266 if (!*l
|| !path_startswith(*l
, path
))
271 if (!*n
|| !path_startswith(*n
, path
))
274 if (!path_startswith(*n
, *l
)) {
282 printf("%s%s%s\n", prefix
, draw_special_char(has_more
? DRAW_TREE_BRANCH
: DRAW_TREE_RIGHT
), *l
);
284 print_subtree(has_more
? vertical
: space
, *l
, l
);
289 static void print_tree(const char *prefix
, char **l
) {
291 pager_open_if_enabled();
293 prefix
= strempty(prefix
);
299 printf("%s%s\n", prefix
, *i
);
303 if (strv_isempty(l
)) {
304 printf("No objects discovered.\n");
308 if (streq(l
[0], "/") && !l
[1]) {
309 printf("Only root object discovered.\n");
313 print_subtree(prefix
, "/", l
);
316 static int on_path(const char *path
, void *userdata
) {
317 Set
*paths
= userdata
;
322 r
= set_put_strdup(paths
, path
);
329 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
330 static const XMLIntrospectOps ops
= {
334 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
335 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
339 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
342 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
344 log_error("Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
348 r
= sd_bus_message_read(reply
, "s", &xml
);
350 return bus_log_parse_error(r
);
352 return parse_xml_introspect(path
, xml
, &ops
, paths
);
355 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
356 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
357 _cleanup_free_
char **l
= NULL
;
361 paths
= set_new(&string_hash_ops
);
365 done
= set_new(&string_hash_ops
);
369 failed
= set_new(&string_hash_ops
);
377 r
= set_put(paths
, m
);
384 _cleanup_free_
char *p
= NULL
;
387 p
= set_steal_first(paths
);
391 if (set_contains(done
, p
) ||
392 set_contains(failed
, p
))
395 q
= find_nodes(bus
, service
, p
, paths
, many
);
400 q
= set_put(failed
, p
);
402 q
= set_put(done
, p
);
411 pager_open_if_enabled();
413 l
= set_get_strv(done
);
418 print_tree(prefix
, l
);
425 static int tree(sd_bus
*bus
, char **argv
) {
429 if (!arg_unique
&& !arg_acquired
)
432 if (strv_length(argv
) <= 1) {
433 _cleanup_strv_free_
char **names
= NULL
;
434 bool not_first
= false;
436 r
= sd_bus_list_names(bus
, &names
, NULL
);
438 return log_error_errno(r
, "Failed to get name list: %m");
440 pager_open_if_enabled();
442 STRV_FOREACH(i
, names
) {
445 if (!arg_unique
&& (*i
)[0] == ':')
448 if (!arg_acquired
&& (*i
)[0] == ':')
454 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
456 q
= tree_one(bus
, *i
, NULL
, true);
463 STRV_FOREACH(i
, argv
+1) {
470 pager_open_if_enabled();
471 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
474 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
483 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
487 const char *contents
= NULL
;
502 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
506 if (bus_type_is_container(type
) > 0) {
508 r
= sd_bus_message_enter_container(m
, type
, contents
);
512 if (type
== SD_BUS_TYPE_ARRAY
) {
515 /* count array entries */
518 r
= sd_bus_message_skip(m
, contents
);
527 r
= sd_bus_message_rewind(m
, false);
535 } else if (type
== SD_BUS_TYPE_VARIANT
) {
540 fprintf(f
, "%s", contents
);
543 r
= format_cmdline(m
, f
, needs_space
|| IN_SET(type
, SD_BUS_TYPE_ARRAY
, SD_BUS_TYPE_VARIANT
));
547 r
= sd_bus_message_exit_container(m
);
554 r
= sd_bus_message_read_basic(m
, type
, &basic
);
562 case SD_BUS_TYPE_BYTE
:
563 fprintf(f
, "%u", basic
.u8
);
566 case SD_BUS_TYPE_BOOLEAN
:
567 fputs(true_false(basic
.i
), f
);
570 case SD_BUS_TYPE_INT16
:
571 fprintf(f
, "%i", basic
.s16
);
574 case SD_BUS_TYPE_UINT16
:
575 fprintf(f
, "%u", basic
.u16
);
578 case SD_BUS_TYPE_INT32
:
579 fprintf(f
, "%i", basic
.s32
);
582 case SD_BUS_TYPE_UINT32
:
583 fprintf(f
, "%u", basic
.u32
);
586 case SD_BUS_TYPE_INT64
:
587 fprintf(f
, "%" PRIi64
, basic
.s64
);
590 case SD_BUS_TYPE_UINT64
:
591 fprintf(f
, "%" PRIu64
, basic
.u64
);
594 case SD_BUS_TYPE_DOUBLE
:
595 fprintf(f
, "%g", basic
.d64
);
598 case SD_BUS_TYPE_STRING
:
599 case SD_BUS_TYPE_OBJECT_PATH
:
600 case SD_BUS_TYPE_SIGNATURE
: {
601 _cleanup_free_
char *b
= NULL
;
603 b
= cescape(basic
.string
);
607 fprintf(f
, "\"%s\"", b
);
611 case SD_BUS_TYPE_UNIX_FD
:
612 fprintf(f
, "%i", basic
.i
);
616 assert_not_reached("Unknown basic type.");
623 typedef struct Member
{
634 static void member_hash_func(const void *p
, struct siphash
*state
) {
641 string_hash_func(m
->type
, state
);
643 arity
+= !!m
->name
+ !!m
->interface
;
645 uint64_hash_func(&arity
, state
);
648 string_hash_func(m
->name
, state
);
651 string_hash_func(m
->interface
, state
);
654 static int member_compare_func(const void *a
, const void *b
) {
655 const Member
*x
= a
, *y
= b
;
663 d
= strcmp_ptr(x
->interface
, y
->interface
);
667 d
= strcmp(x
->type
, y
->type
);
671 return strcmp_ptr(x
->name
, y
->name
);
674 static int member_compare_funcp(const void *a
, const void *b
) {
675 const Member
*const * x
= (const Member
*const *) a
, * const *y
= (const Member
*const *) b
;
677 return member_compare_func(*x
, *y
);
680 static void member_free(Member
*m
) {
692 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
694 static void member_set_free(Set
*s
) {
697 while ((m
= set_steal_first(s
)))
703 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
705 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
706 _cleanup_(member_freep
) Member
*m
;
707 Set
*members
= userdata
;
717 m
->type
= "interface";
720 r
= free_and_strdup(&m
->interface
, interface
);
724 r
= set_put(members
, m
);
726 log_error("Duplicate interface");
734 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
735 _cleanup_(member_freep
) Member
*m
;
736 Set
*members
= userdata
;
749 r
= free_and_strdup(&m
->interface
, interface
);
753 r
= free_and_strdup(&m
->name
, name
);
757 r
= free_and_strdup(&m
->signature
, signature
);
761 r
= free_and_strdup(&m
->result
, result
);
765 r
= set_put(members
, m
);
767 log_error("Duplicate method");
775 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
776 _cleanup_(member_freep
) Member
*m
;
777 Set
*members
= userdata
;
790 r
= free_and_strdup(&m
->interface
, interface
);
794 r
= free_and_strdup(&m
->name
, name
);
798 r
= free_and_strdup(&m
->signature
, signature
);
802 r
= set_put(members
, m
);
804 log_error("Duplicate signal");
812 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
813 _cleanup_(member_freep
) Member
*m
;
814 Set
*members
= userdata
;
824 m
->type
= "property";
826 m
->writable
= writable
;
828 r
= free_and_strdup(&m
->interface
, interface
);
832 r
= free_and_strdup(&m
->name
, name
);
836 r
= free_and_strdup(&m
->signature
, signature
);
840 r
= set_put(members
, m
);
842 log_error("Duplicate property");
850 static const char *strdash(const char *x
) {
851 return isempty(x
) ? "-" : x
;
854 static int introspect(sd_bus
*bus
, char **argv
) {
855 static const struct hash_ops member_hash_ops
= {
856 .hash
= member_hash_func
,
857 .compare
= member_compare_func
,
860 static const XMLIntrospectOps ops
= {
861 .on_interface
= on_interface
,
862 .on_method
= on_method
,
863 .on_signal
= on_signal
,
864 .on_property
= on_property
,
867 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
868 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
869 _cleanup_(member_set_freep
) Set
*members
= NULL
;
874 unsigned name_width
, type_width
, signature_width
, result_width
;
875 Member
**sorted
= NULL
;
876 unsigned k
= 0, j
, n_args
;
878 n_args
= strv_length(argv
);
880 log_error("Requires service and object path argument.");
885 log_error("Too many arguments.");
889 members
= set_new(&member_hash_ops
);
893 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
895 log_error("Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
899 r
= sd_bus_message_read(reply
, "s", &xml
);
901 return bus_log_parse_error(r
);
903 /* First, get list of all properties */
904 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
908 /* Second, find the current values for them */
909 SET_FOREACH(m
, members
, i
) {
911 if (!streq(m
->type
, "property"))
917 if (argv
[3] && !streq(argv
[3], m
->interface
))
920 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
922 log_error("%s", bus_error_message(&error
, r
));
926 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
928 return bus_log_parse_error(r
);
932 _cleanup_free_
char *buf
= NULL
;
933 _cleanup_fclose_
FILE *mf
= NULL
;
937 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
939 return bus_log_parse_error(r
);
944 r
= sd_bus_message_read(reply
, "s", &name
);
946 return bus_log_parse_error(r
);
948 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
950 return bus_log_parse_error(r
);
952 mf
= open_memstream(&buf
, &sz
);
956 r
= format_cmdline(reply
, mf
, false);
958 return bus_log_parse_error(r
);
963 z
= set_get(members
, &((Member
) {
965 .interface
= m
->interface
,
966 .name
= (char*) name
}));
973 r
= sd_bus_message_exit_container(reply
);
975 return bus_log_parse_error(r
);
977 r
= sd_bus_message_exit_container(reply
);
979 return bus_log_parse_error(r
);
982 r
= sd_bus_message_exit_container(reply
);
984 return bus_log_parse_error(r
);
987 pager_open_if_enabled();
989 name_width
= strlen("NAME");
990 type_width
= strlen("TYPE");
991 signature_width
= strlen("SIGNATURE");
992 result_width
= strlen("RESULT/VALUE");
994 sorted
= newa(Member
*, set_size(members
));
996 SET_FOREACH(m
, members
, i
) {
998 if (argv
[3] && !streq(argv
[3], m
->interface
))
1002 name_width
= MAX(name_width
, strlen(m
->interface
));
1004 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1006 type_width
= MAX(type_width
, strlen(m
->type
));
1008 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1010 result_width
= MAX(result_width
, strlen(m
->result
));
1012 result_width
= MAX(result_width
, strlen(m
->value
));
1017 if (result_width
> 40)
1020 qsort(sorted
, k
, sizeof(Member
*), member_compare_funcp
);
1023 printf("%-*s %-*s %-*s %-*s %s\n",
1024 (int) name_width
, "NAME",
1025 (int) type_width
, "TYPE",
1026 (int) signature_width
, "SIGNATURE",
1027 (int) result_width
, "RESULT/VALUE",
1031 for (j
= 0; j
< k
; j
++) {
1032 _cleanup_free_
char *ellipsized
= NULL
;
1038 if (argv
[3] && !streq(argv
[3], m
->interface
))
1041 is_interface
= streq(m
->type
, "interface");
1043 if (argv
[3] && is_interface
)
1047 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1053 rv
= strdash(m
->result
);
1055 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1056 is_interface
? ansi_highlight() : "",
1057 is_interface
? "" : ".",
1058 - !is_interface
+ (int) name_width
, strdash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1059 is_interface
? ansi_normal() : "",
1060 (int) type_width
, strdash(m
->type
),
1061 (int) signature_width
, strdash(m
->signature
),
1062 (int) result_width
, rv
,
1063 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1064 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1065 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1066 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1067 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1068 m
->writable
? " writable" : "");
1074 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1075 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1078 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1079 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1082 static int monitor(sd_bus
*bus
, char *argv
[], int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1083 bool added_something
= false;
1087 STRV_FOREACH(i
, argv
+1) {
1088 _cleanup_free_
char *m
= NULL
;
1090 if (!service_name_is_valid(*i
)) {
1091 log_error("Invalid service name '%s'", *i
);
1095 m
= strjoin("sender='", *i
, "'", NULL
);
1099 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1101 return log_error_errno(r
, "Failed to add match: %m");
1104 m
= strjoin("destination='", *i
, "'", NULL
);
1108 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1110 return log_error_errno(r
, "Failed to add match: %m");
1112 added_something
= true;
1115 STRV_FOREACH(i
, arg_matches
) {
1116 r
= sd_bus_add_match(bus
, NULL
, *i
, NULL
, NULL
);
1118 return log_error_errno(r
, "Failed to add match: %m");
1120 added_something
= true;
1123 if (!added_something
) {
1124 r
= sd_bus_add_match(bus
, NULL
, "", NULL
, NULL
);
1126 return log_error_errno(r
, "Failed to add match: %m");
1129 log_info("Monitoring bus message stream.");
1132 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1134 r
= sd_bus_process(bus
, &m
);
1136 return log_error_errno(r
, "Failed to process bus: %m");
1142 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1143 log_info("Connection terminated, exiting.");
1153 r
= sd_bus_wait(bus
, (uint64_t) -1);
1155 return log_error_errno(r
, "Failed to wait for bus: %m");
1159 static int capture(sd_bus
*bus
, char *argv
[]) {
1162 if (isatty(fileno(stdout
)) > 0) {
1163 log_error("Refusing to write message data to console, please redirect output to a file.");
1167 bus_pcap_header(arg_snaplen
, stdout
);
1169 r
= monitor(bus
, argv
, message_pcap
);
1173 if (ferror(stdout
)) {
1174 log_error("Couldn't write capture file.");
1181 static int status(sd_bus
*bus
, char *argv
[]) {
1182 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1188 if (strv_length(argv
) > 2) {
1189 log_error("Expects no or one argument.");
1194 r
= parse_pid(argv
[1], &pid
);
1196 r
= sd_bus_get_name_creds(
1199 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1202 r
= sd_bus_creds_new_from_pid(
1207 const char *scope
, *address
;
1210 r
= sd_bus_get_address(bus
, &address
);
1212 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1214 r
= sd_bus_get_scope(bus
, &scope
);
1216 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1218 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1220 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1222 r
= sd_bus_get_owner_creds(
1224 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1229 return log_error_errno(r
, "Failed to get credentials: %m");
1231 bus_creds_dump(creds
, NULL
, false);
1235 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1255 log_error("Too few parameters for signature.");
1264 case SD_BUS_TYPE_BOOLEAN
:
1266 r
= parse_boolean(v
);
1268 log_error("Failed to parse as boolean: %s", v
);
1272 r
= sd_bus_message_append_basic(m
, t
, &r
);
1275 case SD_BUS_TYPE_BYTE
: {
1278 r
= safe_atou8(v
, &z
);
1280 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1284 r
= sd_bus_message_append_basic(m
, t
, &z
);
1288 case SD_BUS_TYPE_INT16
: {
1291 r
= safe_atoi16(v
, &z
);
1293 log_error("Failed to parse as signed 16bit integer: %s", v
);
1297 r
= sd_bus_message_append_basic(m
, t
, &z
);
1301 case SD_BUS_TYPE_UINT16
: {
1304 r
= safe_atou16(v
, &z
);
1306 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1310 r
= sd_bus_message_append_basic(m
, t
, &z
);
1314 case SD_BUS_TYPE_INT32
: {
1317 r
= safe_atoi32(v
, &z
);
1319 log_error("Failed to parse as signed 32bit integer: %s", v
);
1323 r
= sd_bus_message_append_basic(m
, t
, &z
);
1327 case SD_BUS_TYPE_UINT32
: {
1330 r
= safe_atou32(v
, &z
);
1332 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1336 r
= sd_bus_message_append_basic(m
, t
, &z
);
1340 case SD_BUS_TYPE_INT64
: {
1343 r
= safe_atoi64(v
, &z
);
1345 log_error("Failed to parse as signed 64bit integer: %s", v
);
1349 r
= sd_bus_message_append_basic(m
, t
, &z
);
1353 case SD_BUS_TYPE_UINT64
: {
1356 r
= safe_atou64(v
, &z
);
1358 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1362 r
= sd_bus_message_append_basic(m
, t
, &z
);
1367 case SD_BUS_TYPE_DOUBLE
: {
1370 r
= safe_atod(v
, &z
);
1372 log_error("Failed to parse as double precision floating point: %s", v
);
1376 r
= sd_bus_message_append_basic(m
, t
, &z
);
1380 case SD_BUS_TYPE_STRING
:
1381 case SD_BUS_TYPE_OBJECT_PATH
:
1382 case SD_BUS_TYPE_SIGNATURE
:
1384 r
= sd_bus_message_append_basic(m
, t
, v
);
1387 case SD_BUS_TYPE_ARRAY
: {
1391 r
= safe_atou32(v
, &n
);
1393 log_error("Failed to parse number of array entries: %s", v
);
1397 r
= signature_element_length(signature
, &k
);
1399 log_error("Invalid array signature.");
1406 memcpy(s
, signature
, k
);
1409 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1411 return bus_log_create_error(r
);
1413 for (i
= 0; i
< n
; i
++) {
1414 r
= message_append_cmdline(m
, s
, &p
);
1422 r
= sd_bus_message_close_container(m
);
1426 case SD_BUS_TYPE_VARIANT
:
1427 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1429 return bus_log_create_error(r
);
1431 r
= message_append_cmdline(m
, v
, &p
);
1435 r
= sd_bus_message_close_container(m
);
1438 case SD_BUS_TYPE_STRUCT_BEGIN
:
1439 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1445 r
= signature_element_length(signature
, &k
);
1447 log_error("Invalid struct/dict entry signature.");
1453 memcpy(s
, signature
+ 1, k
- 2);
1456 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1458 return bus_log_create_error(r
);
1460 r
= message_append_cmdline(m
, s
, &p
);
1467 r
= sd_bus_message_close_container(m
);
1471 case SD_BUS_TYPE_UNIX_FD
:
1472 log_error("UNIX file descriptor not supported as type.");
1476 log_error("Unknown signature type %c.", t
);
1481 return bus_log_create_error(r
);
1488 static int call(sd_bus
*bus
, char *argv
[]) {
1489 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1490 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1495 if (strv_length(argv
) < 5) {
1496 log_error("Expects at least four arguments.");
1500 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1502 return bus_log_create_error(r
);
1504 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1506 return bus_log_create_error(r
);
1508 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1510 return bus_log_create_error(r
);
1512 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1514 return bus_log_create_error(r
);
1516 if (!isempty(argv
[5])) {
1521 r
= message_append_cmdline(m
, argv
[5], &p
);
1526 log_error("Too many parameters for signature.");
1531 if (!arg_expect_reply
) {
1532 r
= sd_bus_send(bus
, m
, NULL
);
1534 log_error("Failed to send message.");
1541 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1543 log_error("%s", bus_error_message(&error
, r
));
1547 r
= sd_bus_message_is_empty(reply
);
1549 return bus_log_parse_error(r
);
1551 if (r
== 0 && !arg_quiet
) {
1554 pager_open_if_enabled();
1556 r
= bus_message_dump(reply
, stdout
, 0);
1561 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1564 r
= format_cmdline(reply
, stdout
, false);
1566 return bus_log_parse_error(r
);
1568 fputc('\n', stdout
);
1575 static int get_property(sd_bus
*bus
, char *argv
[]) {
1576 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1583 n
= strv_length(argv
);
1585 log_error("Expects at least four arguments.");
1589 STRV_FOREACH(i
, argv
+ 4) {
1590 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1591 const char *contents
= NULL
;
1594 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1596 log_error("%s", bus_error_message(&error
, r
));
1600 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1602 return bus_log_parse_error(r
);
1604 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1606 return bus_log_parse_error(r
);
1609 pager_open_if_enabled();
1611 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1615 fputs(contents
, stdout
);
1618 r
= format_cmdline(reply
, stdout
, false);
1620 return bus_log_parse_error(r
);
1622 fputc('\n', stdout
);
1625 r
= sd_bus_message_exit_container(reply
);
1627 return bus_log_parse_error(r
);
1633 static int set_property(sd_bus
*bus
, char *argv
[]) {
1634 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1635 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1642 n
= strv_length(argv
);
1644 log_error("Expects at least five arguments.");
1648 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1650 return bus_log_create_error(r
);
1652 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1654 return bus_log_create_error(r
);
1656 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1658 return bus_log_create_error(r
);
1661 r
= message_append_cmdline(m
, argv
[5], &p
);
1665 r
= sd_bus_message_close_container(m
);
1667 return bus_log_create_error(r
);
1670 log_error("Too many parameters for signature.");
1674 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1676 log_error("%s", bus_error_message(&error
, r
));
1683 static int help(void) {
1684 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1685 "Introspect the bus.\n\n"
1686 " -h --help Show this help\n"
1687 " --version Show package version\n"
1688 " --no-pager Do not pipe output into a pager\n"
1689 " --no-legend Do not show the headers and footers\n"
1690 " --system Connect to system bus\n"
1691 " --user Connect to user bus\n"
1692 " -H --host=[USER@]HOST Operate on remote host\n"
1693 " -M --machine=CONTAINER Operate on local container\n"
1694 " --address=ADDRESS Connect to bus specified by address\n"
1695 " --show-machine Show machine ID column in list\n"
1696 " --unique Only show unique names\n"
1697 " --acquired Only show acquired names\n"
1698 " --activatable Only show activatable names\n"
1699 " --match=MATCH Only show matching messages\n"
1700 " --size=SIZE Maximum length of captured packet\n"
1701 " --list Don't show tree, but simple object path list\n"
1702 " --quiet Don't show method call reply\n"
1703 " --verbose Show result values in long format\n"
1704 " --expect-reply=BOOL Expect a method call reply\n"
1705 " --auto-start=BOOL Auto-start destination service\n"
1706 " --allow-interactive-authorization=BOOL\n"
1707 " Allow interactive authorization for operation\n"
1708 " --timeout=SECS Maximum time to wait for method call completion\n"
1709 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1711 " list List bus names\n"
1712 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1713 " monitor [SERVICE...] Show bus traffic\n"
1714 " capture [SERVICE...] Capture bus traffic as pcap\n"
1715 " tree [SERVICE...] Show object tree of service\n"
1716 " introspect SERVICE OBJECT [INTERFACE]\n"
1717 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1719 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1720 " Get property value\n"
1721 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1722 " Set property value\n"
1723 " help Show this help\n"
1724 , program_invocation_short_name
);
1729 static int parse_argv(int argc
, char *argv
[]) {
1732 ARG_VERSION
= 0x100,
1748 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1753 static const struct option options
[] = {
1754 { "help", no_argument
, NULL
, 'h' },
1755 { "version", no_argument
, NULL
, ARG_VERSION
},
1756 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1757 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1758 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1759 { "user", no_argument
, NULL
, ARG_USER
},
1760 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1761 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1762 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1763 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1764 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1765 { "match", required_argument
, NULL
, ARG_MATCH
},
1766 { "host", required_argument
, NULL
, 'H' },
1767 { "machine", required_argument
, NULL
, 'M' },
1768 { "size", required_argument
, NULL
, ARG_SIZE
},
1769 { "list", no_argument
, NULL
, ARG_LIST
},
1770 { "quiet", no_argument
, NULL
, 'q' },
1771 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1772 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1773 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1774 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1775 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1776 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1785 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1796 arg_no_pager
= true;
1812 arg_address
= optarg
;
1815 case ARG_SHOW_MACHINE
:
1816 arg_show_machine
= true;
1824 arg_acquired
= true;
1827 case ARG_ACTIVATABLE
:
1828 arg_activatable
= true;
1832 if (strv_extend(&arg_matches
, optarg
) < 0)
1839 r
= parse_size(optarg
, 1024, &sz
);
1841 log_error("Failed to parse size: %s", optarg
);
1845 if ((uint64_t) (size_t) sz
!= sz
) {
1846 log_error("Size out of range.");
1850 arg_snaplen
= (size_t) sz
;
1859 arg_transport
= BUS_TRANSPORT_REMOTE
;
1864 arg_transport
= BUS_TRANSPORT_MACHINE
;
1876 case ARG_EXPECT_REPLY
:
1877 r
= parse_boolean(optarg
);
1879 log_error("Failed to parse --expect-reply= parameter.");
1883 arg_expect_reply
= !!r
;
1887 case ARG_AUTO_START
:
1888 r
= parse_boolean(optarg
);
1890 log_error("Failed to parse --auto-start= parameter.");
1894 arg_auto_start
= !!r
;
1898 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1899 r
= parse_boolean(optarg
);
1901 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1905 arg_allow_interactive_authorization
= !!r
;
1909 r
= parse_sec(optarg
, &arg_timeout
);
1911 log_error("Failed to parse --timeout= parameter.");
1917 case ARG_AUGMENT_CREDS
:
1918 r
= parse_boolean(optarg
);
1920 log_error("Failed to parse --augment-creds= parameter.");
1924 arg_augment_creds
= !!r
;
1931 assert_not_reached("Unhandled option");
1937 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1940 if (optind
>= argc
||
1941 streq(argv
[optind
], "list"))
1942 return list_bus_names(bus
, argv
+ optind
);
1944 if (streq(argv
[optind
], "monitor"))
1945 return monitor(bus
, argv
+ optind
, message_dump
);
1947 if (streq(argv
[optind
], "capture"))
1948 return capture(bus
, argv
+ optind
);
1950 if (streq(argv
[optind
], "status"))
1951 return status(bus
, argv
+ optind
);
1953 if (streq(argv
[optind
], "tree"))
1954 return tree(bus
, argv
+ optind
);
1956 if (streq(argv
[optind
], "introspect"))
1957 return introspect(bus
, argv
+ optind
);
1959 if (streq(argv
[optind
], "call"))
1960 return call(bus
, argv
+ optind
);
1962 if (streq(argv
[optind
], "get-property"))
1963 return get_property(bus
, argv
+ optind
);
1965 if (streq(argv
[optind
], "set-property"))
1966 return set_property(bus
, argv
+ optind
);
1968 if (streq(argv
[optind
], "help"))
1971 log_error("Unknown command '%s'", argv
[optind
]);
1975 int main(int argc
, char *argv
[]) {
1976 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1979 log_parse_environment();
1982 r
= parse_argv(argc
, argv
);
1986 r
= sd_bus_new(&bus
);
1988 log_error_errno(r
, "Failed to allocate bus: %m");
1992 if (streq_ptr(argv
[optind
], "monitor") ||
1993 streq_ptr(argv
[optind
], "capture")) {
1995 r
= sd_bus_set_monitor(bus
, true);
1997 log_error_errno(r
, "Failed to set monitor mode: %m");
2001 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
2003 log_error_errno(r
, "Failed to enable credentials: %m");
2007 r
= sd_bus_negotiate_timestamp(bus
, true);
2009 log_error_errno(r
, "Failed to enable timestamps: %m");
2013 r
= sd_bus_negotiate_fds(bus
, true);
2015 log_error_errno(r
, "Failed to enable fds: %m");
2020 r
= sd_bus_set_bus_client(bus
, true);
2022 log_error_errno(r
, "Failed to set bus client: %m");
2027 r
= sd_bus_set_address(bus
, arg_address
);
2029 switch (arg_transport
) {
2031 case BUS_TRANSPORT_LOCAL
:
2033 bus
->is_user
= true;
2034 r
= bus_set_address_user(bus
);
2036 bus
->is_system
= true;
2037 r
= bus_set_address_system(bus
);
2041 case BUS_TRANSPORT_REMOTE
:
2042 r
= bus_set_address_system_remote(bus
, arg_host
);
2045 case BUS_TRANSPORT_MACHINE
:
2046 r
= bus_set_address_system_machine(bus
, arg_host
);
2050 assert_not_reached("Hmm, unknown transport type.");
2054 log_error_errno(r
, "Failed to set address: %m");
2058 r
= sd_bus_start(bus
);
2060 log_error_errno(r
, "Failed to connect to bus: %m");
2064 r
= busctl_main(bus
, argc
, argv
);
2069 strv_free(arg_matches
);
2071 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;