1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
10 #include "bus-internal.h"
11 #include "bus-signature.h"
14 #include "busctl-introspect.h"
18 #include "locale-util.h"
21 #include "parse-util.h"
22 #include "path-util.h"
25 #include "terminal-util.h"
26 #include "user-util.h"
30 static bool arg_no_pager
= false;
31 static bool arg_legend
= true;
32 static char *arg_address
= NULL
;
33 static bool arg_unique
= false;
34 static bool arg_acquired
= false;
35 static bool arg_activatable
= false;
36 static bool arg_show_machine
= false;
37 static char **arg_matches
= NULL
;
38 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
39 static const char *arg_host
= NULL
;
40 static bool arg_user
= false;
41 static size_t arg_snaplen
= 4096;
42 static bool arg_list
= false;
43 static bool arg_quiet
= false;
44 static bool arg_verbose
= false;
45 static bool arg_expect_reply
= true;
46 static bool arg_auto_start
= true;
47 static bool arg_allow_interactive_authorization
= true;
48 static bool arg_augment_creds
= true;
49 static bool arg_watch_bind
= false;
50 static usec_t arg_timeout
= 0;
52 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
53 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
55 static int acquire_bus(bool set_monitor
, sd_bus
**ret
) {
56 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
61 return log_error_errno(r
, "Failed to allocate bus: %m");
64 r
= sd_bus_set_monitor(bus
, true);
66 return log_error_errno(r
, "Failed to set monitor mode: %m");
68 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
70 return log_error_errno(r
, "Failed to enable credentials: %m");
72 r
= sd_bus_negotiate_timestamp(bus
, true);
74 return log_error_errno(r
, "Failed to enable timestamps: %m");
76 r
= sd_bus_negotiate_fds(bus
, true);
78 return log_error_errno(r
, "Failed to enable fds: %m");
81 r
= sd_bus_set_bus_client(bus
, true);
83 return log_error_errno(r
, "Failed to set bus client: %m");
85 r
= sd_bus_set_watch_bind(bus
, arg_watch_bind
);
87 return log_error_errno(r
, "Failed to set watch-bind setting to '%s': %m", yes_no(arg_watch_bind
));
90 r
= sd_bus_set_address(bus
, arg_address
);
92 switch (arg_transport
) {
94 case BUS_TRANSPORT_LOCAL
:
97 r
= bus_set_address_user(bus
);
99 bus
->is_system
= true;
100 r
= bus_set_address_system(bus
);
104 case BUS_TRANSPORT_REMOTE
:
105 r
= bus_set_address_system_remote(bus
, arg_host
);
108 case BUS_TRANSPORT_MACHINE
:
109 r
= bus_set_address_system_machine(bus
, arg_host
);
113 assert_not_reached("Hmm, unknown transport type.");
117 return log_error_errno(r
, "Failed to set address: %m");
119 r
= sd_bus_start(bus
);
121 return log_error_errno(r
, "Failed to connect to bus: %m");
123 *ret
= TAKE_PTR(bus
);
128 static int list_bus_names(int argc
, char **argv
, void *userdata
) {
129 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
130 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
131 _cleanup_free_
char **merged
= NULL
;
132 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
141 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
142 arg_unique
= arg_acquired
= arg_activatable
= true;
144 r
= acquire_bus(false, &bus
);
148 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
150 return log_error_errno(r
, "Failed to list names: %m");
152 (void) pager_open(arg_no_pager
, false);
154 names
= hashmap_new(&string_hash_ops
);
158 STRV_FOREACH(i
, acquired
) {
159 max_i
= MAX(max_i
, strlen(*i
));
161 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
163 return log_error_errno(r
, "Failed to add to hashmap: %m");
166 STRV_FOREACH(i
, activatable
) {
167 max_i
= MAX(max_i
, strlen(*i
));
169 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
170 if (r
< 0 && r
!= -EEXIST
)
171 return log_error_errno(r
, "Failed to add to hashmap: %m");
174 merged
= new(char*, hashmap_size(names
) + 1);
178 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
185 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
186 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
188 if (arg_show_machine
)
194 STRV_FOREACH(i
, merged
) {
195 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
198 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
201 printf("%-*s", (int) max_i
, *i
);
202 printf(" - - - (activatable) - - ");
203 if (arg_show_machine
)
211 if (!arg_unique
&& (*i
)[0] == ':')
214 if (!arg_acquired
&& (*i
)[0] != ':')
217 printf("%-*s", (int) max_i
, *i
);
219 r
= sd_bus_get_name_creds(
221 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
222 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
223 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
224 SD_BUS_CREDS_DESCRIPTION
, &creds
);
226 const char *unique
, *session
, *unit
, *cn
;
230 r
= sd_bus_creds_get_pid(creds
, &pid
);
232 const char *comm
= NULL
;
234 sd_bus_creds_get_comm(creds
, &comm
);
236 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
238 fputs(" - - ", stdout
);
240 r
= sd_bus_creds_get_euid(creds
, &uid
);
242 _cleanup_free_
char *u
= NULL
;
244 u
= uid_to_name(uid
);
253 fputs(" - ", stdout
);
255 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
257 printf(" %-13s", unique
);
259 fputs(" - ", stdout
);
261 r
= sd_bus_creds_get_unit(creds
, &unit
);
263 _cleanup_free_
char *e
;
265 e
= ellipsize(unit
, 25, 100);
271 fputs(" - ", stdout
);
273 r
= sd_bus_creds_get_session(creds
, &session
);
275 printf(" %-10s", session
);
277 fputs(" - ", stdout
);
279 r
= sd_bus_creds_get_description(creds
, &cn
);
281 printf(" %-19s", cn
);
283 fputs(" - ", stdout
);
286 printf(" - - - - - - - ");
288 if (arg_show_machine
) {
289 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
291 char m
[SD_ID128_STRING_MAX
];
292 printf(" %s\n", sd_id128_to_string(mid
, m
));
302 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
303 const char *vertical
, *space
;
306 /* We assume the list is sorted. Let's first skip over the
307 * entry we are looking at. */
312 if (!streq(*l
, path
))
318 vertical
= strjoina(prefix
, special_glyph(TREE_VERTICAL
));
319 space
= strjoina(prefix
, special_glyph(TREE_SPACE
));
322 bool has_more
= false;
324 if (!*l
|| !path_startswith(*l
, path
))
329 if (!*n
|| !path_startswith(*n
, path
))
332 if (!path_startswith(*n
, *l
)) {
340 printf("%s%s%s\n", prefix
, special_glyph(has_more
? TREE_BRANCH
: TREE_RIGHT
), *l
);
342 print_subtree(has_more
? vertical
: space
, *l
, l
);
347 static void print_tree(const char *prefix
, char **l
) {
349 prefix
= strempty(prefix
);
355 printf("%s%s\n", prefix
, *i
);
359 if (strv_isempty(l
)) {
360 printf("No objects discovered.\n");
364 if (streq(l
[0], "/") && !l
[1]) {
365 printf("Only root object discovered.\n");
369 print_subtree(prefix
, "/", l
);
372 static int on_path(const char *path
, void *userdata
) {
373 Set
*paths
= userdata
;
378 r
= set_put_strdup(paths
, path
);
385 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
386 static const XMLIntrospectOps ops
= {
390 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
391 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
395 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
398 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
400 log_error_errno(r
, "Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
404 r
= sd_bus_message_read(reply
, "s", &xml
);
406 return bus_log_parse_error(r
);
408 return parse_xml_introspect(path
, xml
, &ops
, paths
);
411 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
412 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
413 _cleanup_free_
char **l
= NULL
;
417 paths
= set_new(&string_hash_ops
);
421 done
= set_new(&string_hash_ops
);
425 failed
= set_new(&string_hash_ops
);
433 r
= set_put(paths
, m
);
440 _cleanup_free_
char *p
= NULL
;
443 p
= set_steal_first(paths
);
447 if (set_contains(done
, p
) ||
448 set_contains(failed
, p
))
451 q
= find_nodes(bus
, service
, p
, paths
, many
);
456 q
= set_put(failed
, p
);
458 q
= set_put(done
, p
);
467 (void) pager_open(arg_no_pager
, false);
469 l
= set_get_strv(done
);
474 print_tree(prefix
, l
);
481 static int tree(int argc
, char **argv
, void *userdata
) {
482 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
486 if (!arg_unique
&& !arg_acquired
)
489 r
= acquire_bus(false, &bus
);
494 _cleanup_strv_free_
char **names
= NULL
;
495 bool not_first
= false;
497 r
= sd_bus_list_names(bus
, &names
, NULL
);
499 return log_error_errno(r
, "Failed to get name list: %m");
501 (void) pager_open(arg_no_pager
, false);
503 STRV_FOREACH(i
, names
) {
506 if (!arg_unique
&& (*i
)[0] == ':')
509 if (!arg_acquired
&& (*i
)[0] == ':')
515 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
517 q
= tree_one(bus
, *i
, NULL
, true);
524 STRV_FOREACH(i
, argv
+1) {
531 (void) pager_open(arg_no_pager
, false);
532 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
535 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
544 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
548 const char *contents
= NULL
;
563 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
569 if (bus_type_is_container(type
) > 0) {
571 r
= sd_bus_message_enter_container(m
, type
, contents
);
575 if (type
== SD_BUS_TYPE_ARRAY
) {
578 /* count array entries */
581 r
= sd_bus_message_skip(m
, contents
);
590 r
= sd_bus_message_rewind(m
, false);
600 } else if (type
== SD_BUS_TYPE_VARIANT
) {
605 fprintf(f
, "%s", contents
);
609 r
= format_cmdline(m
, f
, needs_space
);
615 r
= sd_bus_message_exit_container(m
);
622 r
= sd_bus_message_read_basic(m
, type
, &basic
);
630 case SD_BUS_TYPE_BYTE
:
631 fprintf(f
, "%u", basic
.u8
);
634 case SD_BUS_TYPE_BOOLEAN
:
635 fputs(true_false(basic
.i
), f
);
638 case SD_BUS_TYPE_INT16
:
639 fprintf(f
, "%i", basic
.s16
);
642 case SD_BUS_TYPE_UINT16
:
643 fprintf(f
, "%u", basic
.u16
);
646 case SD_BUS_TYPE_INT32
:
647 fprintf(f
, "%i", basic
.s32
);
650 case SD_BUS_TYPE_UINT32
:
651 fprintf(f
, "%u", basic
.u32
);
654 case SD_BUS_TYPE_INT64
:
655 fprintf(f
, "%" PRIi64
, basic
.s64
);
658 case SD_BUS_TYPE_UINT64
:
659 fprintf(f
, "%" PRIu64
, basic
.u64
);
662 case SD_BUS_TYPE_DOUBLE
:
663 fprintf(f
, "%g", basic
.d64
);
666 case SD_BUS_TYPE_STRING
:
667 case SD_BUS_TYPE_OBJECT_PATH
:
668 case SD_BUS_TYPE_SIGNATURE
: {
669 _cleanup_free_
char *b
= NULL
;
671 b
= cescape(basic
.string
);
675 fprintf(f
, "\"%s\"", b
);
679 case SD_BUS_TYPE_UNIX_FD
:
680 fprintf(f
, "%i", basic
.i
);
684 assert_not_reached("Unknown basic type.");
691 typedef struct Member
{
702 static void member_hash_func(const void *p
, struct siphash
*state
) {
709 string_hash_func(m
->type
, state
);
711 arity
+= !!m
->name
+ !!m
->interface
;
713 uint64_hash_func(&arity
, state
);
716 string_hash_func(m
->name
, state
);
719 string_hash_func(m
->interface
, state
);
722 static int member_compare_func(const void *a
, const void *b
) {
723 const Member
*x
= a
, *y
= b
;
731 d
= strcmp_ptr(x
->interface
, y
->interface
);
735 d
= strcmp(x
->type
, y
->type
);
739 return strcmp_ptr(x
->name
, y
->name
);
742 static int member_compare_funcp(const void *a
, const void *b
) {
743 const Member
*const * x
= (const Member
*const *) a
, * const *y
= (const Member
*const *) b
;
745 return member_compare_func(*x
, *y
);
748 static void member_free(Member
*m
) {
760 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
762 static void member_set_free(Set
*s
) {
763 set_free_with_destructor(s
, member_free
);
766 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
768 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
769 _cleanup_(member_freep
) Member
*m
;
770 Set
*members
= userdata
;
780 m
->type
= "interface";
783 r
= free_and_strdup(&m
->interface
, interface
);
787 r
= set_put(members
, m
);
789 log_error("Duplicate interface");
797 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
798 _cleanup_(member_freep
) Member
*m
;
799 Set
*members
= userdata
;
812 r
= free_and_strdup(&m
->interface
, interface
);
816 r
= free_and_strdup(&m
->name
, name
);
820 r
= free_and_strdup(&m
->signature
, signature
);
824 r
= free_and_strdup(&m
->result
, result
);
828 r
= set_put(members
, m
);
830 log_error("Duplicate method");
838 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
839 _cleanup_(member_freep
) Member
*m
;
840 Set
*members
= userdata
;
853 r
= free_and_strdup(&m
->interface
, interface
);
857 r
= free_and_strdup(&m
->name
, name
);
861 r
= free_and_strdup(&m
->signature
, signature
);
865 r
= set_put(members
, m
);
867 log_error("Duplicate signal");
875 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
876 _cleanup_(member_freep
) Member
*m
;
877 Set
*members
= userdata
;
887 m
->type
= "property";
889 m
->writable
= writable
;
891 r
= free_and_strdup(&m
->interface
, interface
);
895 r
= free_and_strdup(&m
->name
, name
);
899 r
= free_and_strdup(&m
->signature
, signature
);
903 r
= set_put(members
, m
);
905 log_error("Duplicate property");
913 static int introspect(int argc
, char **argv
, void *userdata
) {
914 static const struct hash_ops member_hash_ops
= {
915 .hash
= member_hash_func
,
916 .compare
= member_compare_func
,
919 static const XMLIntrospectOps ops
= {
920 .on_interface
= on_interface
,
921 .on_method
= on_method
,
922 .on_signal
= on_signal
,
923 .on_property
= on_property
,
926 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
927 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply_xml
= NULL
;
928 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
929 _cleanup_(member_set_freep
) Set
*members
= NULL
;
930 unsigned name_width
, type_width
, signature_width
, result_width
, j
, k
= 0;
931 Member
*m
, **sorted
= NULL
;
936 r
= acquire_bus(false, &bus
);
940 members
= set_new(&member_hash_ops
);
944 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply_xml
, "");
946 return log_error_errno(r
, "Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
948 r
= sd_bus_message_read(reply_xml
, "s", &xml
);
950 return bus_log_parse_error(r
);
952 /* First, get list of all properties */
953 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
957 /* Second, find the current values for them */
958 SET_FOREACH(m
, members
, i
) {
959 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
961 if (!streq(m
->type
, "property"))
967 if (argv
[3] && !streq(argv
[3], m
->interface
))
970 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
972 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
974 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
976 return bus_log_parse_error(r
);
980 _cleanup_free_
char *buf
= NULL
;
981 _cleanup_fclose_
FILE *mf
= NULL
;
985 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
987 return bus_log_parse_error(r
);
992 r
= sd_bus_message_read(reply
, "s", &name
);
994 return bus_log_parse_error(r
);
996 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
998 return bus_log_parse_error(r
);
1000 mf
= open_memstream(&buf
, &sz
);
1004 (void) __fsetlocking(mf
, FSETLOCKING_BYCALLER
);
1006 r
= format_cmdline(reply
, mf
, false);
1008 return bus_log_parse_error(r
);
1010 mf
= safe_fclose(mf
);
1012 z
= set_get(members
, &((Member
) {
1014 .interface
= m
->interface
,
1015 .name
= (char*) name
}));
1017 free_and_replace(z
->value
, buf
);
1019 r
= sd_bus_message_exit_container(reply
);
1021 return bus_log_parse_error(r
);
1023 r
= sd_bus_message_exit_container(reply
);
1025 return bus_log_parse_error(r
);
1028 r
= sd_bus_message_exit_container(reply
);
1030 return bus_log_parse_error(r
);
1033 (void) pager_open(arg_no_pager
, false);
1035 name_width
= STRLEN("NAME");
1036 type_width
= STRLEN("TYPE");
1037 signature_width
= STRLEN("SIGNATURE");
1038 result_width
= STRLEN("RESULT/VALUE");
1040 sorted
= newa(Member
*, set_size(members
));
1042 SET_FOREACH(m
, members
, i
) {
1044 if (argv
[3] && !streq(argv
[3], m
->interface
))
1048 name_width
= MAX(name_width
, strlen(m
->interface
));
1050 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1052 type_width
= MAX(type_width
, strlen(m
->type
));
1054 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1056 result_width
= MAX(result_width
, strlen(m
->result
));
1058 result_width
= MAX(result_width
, strlen(m
->value
));
1063 if (result_width
> 40)
1066 qsort(sorted
, k
, sizeof(Member
*), member_compare_funcp
);
1069 printf("%-*s %-*s %-*s %-*s %s\n",
1070 (int) name_width
, "NAME",
1071 (int) type_width
, "TYPE",
1072 (int) signature_width
, "SIGNATURE",
1073 (int) result_width
, "RESULT/VALUE",
1077 for (j
= 0; j
< k
; j
++) {
1078 _cleanup_free_
char *ellipsized
= NULL
;
1084 if (argv
[3] && !streq(argv
[3], m
->interface
))
1087 is_interface
= streq(m
->type
, "interface");
1089 if (argv
[3] && is_interface
)
1093 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1099 rv
= empty_to_dash(m
->result
);
1101 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1102 is_interface
? ansi_highlight() : "",
1103 is_interface
? "" : ".",
1104 - !is_interface
+ (int) name_width
, empty_to_dash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1105 is_interface
? ansi_normal() : "",
1106 (int) type_width
, empty_to_dash(m
->type
),
1107 (int) signature_width
, empty_to_dash(m
->signature
),
1108 (int) result_width
, rv
,
1109 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1110 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1111 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1112 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1113 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1114 m
->writable
? " writable" : "");
1120 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1121 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1124 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1125 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1128 static int monitor(int argc
, char **argv
, int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1129 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1130 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*message
= NULL
;
1131 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1134 const char *unique_name
;
1135 bool is_monitor
= false;
1138 r
= acquire_bus(true, &bus
);
1142 /* upgrade connection; it's not used for anything else after this call */
1143 r
= sd_bus_message_new_method_call(bus
, &message
, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
1145 return bus_log_create_error(r
);
1147 r
= sd_bus_message_open_container(message
, 'a', "s");
1149 return bus_log_create_error(r
);
1151 STRV_FOREACH(i
, argv
+1) {
1152 _cleanup_free_
char *m
= NULL
;
1154 if (!service_name_is_valid(*i
)) {
1155 log_error("Invalid service name '%s'", *i
);
1159 m
= strjoin("sender='", *i
, "'");
1163 r
= sd_bus_message_append_basic(message
, 's', m
);
1165 return bus_log_create_error(r
);
1168 m
= strjoin("destination='", *i
, "'");
1172 r
= sd_bus_message_append_basic(message
, 's', m
);
1174 return bus_log_create_error(r
);
1177 STRV_FOREACH(i
, arg_matches
) {
1178 r
= sd_bus_message_append_basic(message
, 's', *i
);
1180 return bus_log_create_error(r
);
1183 r
= sd_bus_message_close_container(message
);
1185 return bus_log_create_error(r
);
1187 r
= sd_bus_message_append_basic(message
, 'u', &flags
);
1189 return bus_log_create_error(r
);
1191 r
= sd_bus_call(bus
, message
, arg_timeout
, &error
, NULL
);
1193 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
1195 r
= sd_bus_get_unique_name(bus
, &unique_name
);
1197 return log_error_errno(r
, "Failed to get unique name: %m");
1199 log_info("Monitoring bus message stream.");
1202 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1204 r
= sd_bus_process(bus
, &m
);
1206 return log_error_errno(r
, "Failed to process bus: %m");
1211 /* wait until we lose our unique name */
1212 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus", "NameLost") <= 0)
1215 r
= sd_bus_message_read(m
, "s", &name
);
1217 return log_error_errno(r
, "Failed to read lost name: %m");
1219 if (streq(name
, unique_name
))
1229 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1230 log_info("Connection terminated, exiting.");
1240 r
= sd_bus_wait(bus
, (uint64_t) -1);
1242 return log_error_errno(r
, "Failed to wait for bus: %m");
1246 static int verb_monitor(int argc
, char **argv
, void *userdata
) {
1247 return monitor(argc
, argv
, message_dump
);
1250 static int verb_capture(int argc
, char **argv
, void *userdata
) {
1253 if (isatty(fileno(stdout
)) > 0) {
1254 log_error("Refusing to write message data to console, please redirect output to a file.");
1258 bus_pcap_header(arg_snaplen
, stdout
);
1260 r
= monitor(argc
, argv
, message_pcap
);
1264 r
= fflush_and_check(stdout
);
1266 return log_error_errno(r
, "Couldn't write capture file: %m");
1271 static int status(int argc
, char **argv
, void *userdata
) {
1272 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1273 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
1277 r
= acquire_bus(false, &bus
);
1281 if (!isempty(argv
[1])) {
1282 r
= parse_pid(argv
[1], &pid
);
1284 r
= sd_bus_get_name_creds(
1287 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1290 r
= sd_bus_creds_new_from_pid(
1295 const char *scope
, *address
;
1298 r
= sd_bus_get_address(bus
, &address
);
1300 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1302 r
= sd_bus_get_scope(bus
, &scope
);
1304 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1306 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1308 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1310 r
= sd_bus_get_owner_creds(
1312 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1317 return log_error_errno(r
, "Failed to get credentials: %m");
1319 bus_creds_dump(creds
, NULL
, false);
1323 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1343 log_error("Too few parameters for signature.");
1352 case SD_BUS_TYPE_BOOLEAN
:
1354 r
= parse_boolean(v
);
1356 return log_error_errno(r
, "Failed to parse as boolean: %s", v
);
1358 r
= sd_bus_message_append_basic(m
, t
, &r
);
1361 case SD_BUS_TYPE_BYTE
: {
1364 r
= safe_atou8(v
, &z
);
1366 return log_error_errno(r
, "Failed to parse as byte (unsigned 8bit integer): %s", v
);
1368 r
= sd_bus_message_append_basic(m
, t
, &z
);
1372 case SD_BUS_TYPE_INT16
: {
1375 r
= safe_atoi16(v
, &z
);
1377 return log_error_errno(r
, "Failed to parse as signed 16bit integer: %s", v
);
1379 r
= sd_bus_message_append_basic(m
, t
, &z
);
1383 case SD_BUS_TYPE_UINT16
: {
1386 r
= safe_atou16(v
, &z
);
1388 return log_error_errno(r
, "Failed to parse as unsigned 16bit integer: %s", v
);
1390 r
= sd_bus_message_append_basic(m
, t
, &z
);
1394 case SD_BUS_TYPE_INT32
: {
1397 r
= safe_atoi32(v
, &z
);
1399 return log_error_errno(r
, "Failed to parse as signed 32bit integer: %s", v
);
1401 r
= sd_bus_message_append_basic(m
, t
, &z
);
1405 case SD_BUS_TYPE_UINT32
: {
1408 r
= safe_atou32(v
, &z
);
1410 return log_error_errno(r
, "Failed to parse as unsigned 32bit integer: %s", v
);
1412 r
= sd_bus_message_append_basic(m
, t
, &z
);
1416 case SD_BUS_TYPE_INT64
: {
1419 r
= safe_atoi64(v
, &z
);
1421 return log_error_errno(r
, "Failed to parse as signed 64bit integer: %s", v
);
1423 r
= sd_bus_message_append_basic(m
, t
, &z
);
1427 case SD_BUS_TYPE_UINT64
: {
1430 r
= safe_atou64(v
, &z
);
1432 return log_error_errno(r
, "Failed to parse as unsigned 64bit integer: %s", v
);
1434 r
= sd_bus_message_append_basic(m
, t
, &z
);
1438 case SD_BUS_TYPE_DOUBLE
: {
1441 r
= safe_atod(v
, &z
);
1443 return log_error_errno(r
, "Failed to parse as double precision floating point: %s", v
);
1445 r
= sd_bus_message_append_basic(m
, t
, &z
);
1449 case SD_BUS_TYPE_STRING
:
1450 case SD_BUS_TYPE_OBJECT_PATH
:
1451 case SD_BUS_TYPE_SIGNATURE
:
1453 r
= sd_bus_message_append_basic(m
, t
, v
);
1456 case SD_BUS_TYPE_ARRAY
: {
1460 r
= safe_atou32(v
, &n
);
1462 return log_error_errno(r
, "Failed to parse number of array entries: %s", v
);
1464 r
= signature_element_length(signature
, &k
);
1466 return log_error_errno(r
, "Invalid array signature.");
1471 memcpy(s
, signature
, k
);
1474 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1476 return bus_log_create_error(r
);
1478 for (i
= 0; i
< n
; i
++) {
1479 r
= message_append_cmdline(m
, s
, &p
);
1487 r
= sd_bus_message_close_container(m
);
1491 case SD_BUS_TYPE_VARIANT
:
1492 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1494 return bus_log_create_error(r
);
1496 r
= message_append_cmdline(m
, v
, &p
);
1500 r
= sd_bus_message_close_container(m
);
1503 case SD_BUS_TYPE_STRUCT_BEGIN
:
1504 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1510 r
= signature_element_length(signature
, &k
);
1512 return log_error_errno(r
, "Invalid struct/dict entry signature.");
1516 memcpy(s
, signature
+ 1, k
- 2);
1519 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1521 return bus_log_create_error(r
);
1523 r
= message_append_cmdline(m
, s
, &p
);
1530 r
= sd_bus_message_close_container(m
);
1534 case SD_BUS_TYPE_UNIX_FD
:
1535 log_error("UNIX file descriptor not supported as type.");
1539 log_error("Unknown signature type %c.", t
);
1544 return bus_log_create_error(r
);
1551 static int call(int argc
, char **argv
, void *userdata
) {
1552 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1553 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1554 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1557 r
= acquire_bus(false, &bus
);
1561 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1563 return bus_log_create_error(r
);
1565 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1567 return bus_log_create_error(r
);
1569 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1571 return bus_log_create_error(r
);
1573 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1575 return bus_log_create_error(r
);
1577 if (!isempty(argv
[5])) {
1582 r
= message_append_cmdline(m
, argv
[5], &p
);
1587 log_error("Too many parameters for signature.");
1592 if (!arg_expect_reply
) {
1593 r
= sd_bus_send(bus
, m
, NULL
);
1595 return log_error_errno(r
, "Failed to send message: %m");
1600 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1602 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
1604 r
= sd_bus_message_is_empty(reply
);
1606 return bus_log_parse_error(r
);
1608 if (r
== 0 && !arg_quiet
) {
1611 (void) pager_open(arg_no_pager
, false);
1613 r
= bus_message_dump(reply
, stdout
, 0);
1618 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1621 r
= format_cmdline(reply
, stdout
, false);
1623 return bus_log_parse_error(r
);
1625 fputc('\n', stdout
);
1632 static int get_property(int argc
, char **argv
, void *userdata
) {
1633 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1634 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1638 r
= acquire_bus(false, &bus
);
1642 STRV_FOREACH(i
, argv
+ 4) {
1643 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1644 const char *contents
= NULL
;
1647 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1649 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
1651 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1653 return bus_log_parse_error(r
);
1655 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1657 return bus_log_parse_error(r
);
1660 (void) pager_open(arg_no_pager
, false);
1662 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1666 fputs(contents
, stdout
);
1669 r
= format_cmdline(reply
, stdout
, false);
1671 return bus_log_parse_error(r
);
1673 fputc('\n', stdout
);
1676 r
= sd_bus_message_exit_container(reply
);
1678 return bus_log_parse_error(r
);
1684 static int set_property(int argc
, char **argv
, void *userdata
) {
1685 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1686 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1687 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1691 r
= acquire_bus(false, &bus
);
1695 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1697 return bus_log_create_error(r
);
1699 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1701 return bus_log_create_error(r
);
1703 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1705 return bus_log_create_error(r
);
1708 r
= message_append_cmdline(m
, argv
[5], &p
);
1712 r
= sd_bus_message_close_container(m
);
1714 return bus_log_create_error(r
);
1717 log_error("Too many parameters for signature.");
1721 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1723 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
1728 static int help(void) {
1729 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1730 "Introspect the bus.\n\n"
1731 " -h --help Show this help\n"
1732 " --version Show package version\n"
1733 " --no-pager Do not pipe output into a pager\n"
1734 " --no-legend Do not show the headers and footers\n"
1735 " --system Connect to system bus\n"
1736 " --user Connect to user bus\n"
1737 " -H --host=[USER@]HOST Operate on remote host\n"
1738 " -M --machine=CONTAINER Operate on local container\n"
1739 " --address=ADDRESS Connect to bus specified by address\n"
1740 " --show-machine Show machine ID column in list\n"
1741 " --unique Only show unique names\n"
1742 " --acquired Only show acquired names\n"
1743 " --activatable Only show activatable names\n"
1744 " --match=MATCH Only show matching messages\n"
1745 " --size=SIZE Maximum length of captured packet\n"
1746 " --list Don't show tree, but simple object path list\n"
1747 " -q --quiet Don't show method call reply\n"
1748 " --verbose Show result values in long format\n"
1749 " --expect-reply=BOOL Expect a method call reply\n"
1750 " --auto-start=BOOL Auto-start destination service\n"
1751 " --allow-interactive-authorization=BOOL\n"
1752 " Allow interactive authorization for operation\n"
1753 " --timeout=SECS Maximum time to wait for method call completion\n"
1754 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
1755 " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n"
1758 " list List bus names\n"
1759 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1760 " monitor [SERVICE...] Show bus traffic\n"
1761 " capture [SERVICE...] Capture bus traffic as pcap\n"
1762 " tree [SERVICE...] Show object tree of service\n"
1763 " introspect SERVICE OBJECT [INTERFACE]\n"
1764 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1766 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1767 " Get property value\n"
1768 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1769 " Set property value\n"
1770 " help Show this help\n"
1771 , program_invocation_short_name
);
1776 static int verb_help(int argc
, char **argv
, void *userdata
) {
1780 static int parse_argv(int argc
, char *argv
[]) {
1783 ARG_VERSION
= 0x100,
1799 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1805 static const struct option options
[] = {
1806 { "help", no_argument
, NULL
, 'h' },
1807 { "version", no_argument
, NULL
, ARG_VERSION
},
1808 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1809 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1810 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1811 { "user", no_argument
, NULL
, ARG_USER
},
1812 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1813 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1814 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1815 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1816 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1817 { "match", required_argument
, NULL
, ARG_MATCH
},
1818 { "host", required_argument
, NULL
, 'H' },
1819 { "machine", required_argument
, NULL
, 'M' },
1820 { "size", required_argument
, NULL
, ARG_SIZE
},
1821 { "list", no_argument
, NULL
, ARG_LIST
},
1822 { "quiet", no_argument
, NULL
, 'q' },
1823 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1824 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1825 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1826 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1827 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1828 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1829 { "watch-bind", required_argument
, NULL
, ARG_WATCH_BIND
},
1838 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1849 arg_no_pager
= true;
1865 arg_address
= optarg
;
1868 case ARG_SHOW_MACHINE
:
1869 arg_show_machine
= true;
1877 arg_acquired
= true;
1880 case ARG_ACTIVATABLE
:
1881 arg_activatable
= true;
1885 if (strv_extend(&arg_matches
, optarg
) < 0)
1892 r
= parse_size(optarg
, 1024, &sz
);
1894 return log_error_errno(r
, "Failed to parse size: %s", optarg
);
1896 if ((uint64_t) (size_t) sz
!= sz
) {
1897 log_error("Size out of range.");
1901 arg_snaplen
= (size_t) sz
;
1910 arg_transport
= BUS_TRANSPORT_REMOTE
;
1915 arg_transport
= BUS_TRANSPORT_MACHINE
;
1927 case ARG_EXPECT_REPLY
:
1928 r
= parse_boolean(optarg
);
1930 return log_error_errno(r
, "Failed to parse --expect-reply= parameter: %s", optarg
);
1932 arg_expect_reply
= r
;
1935 case ARG_AUTO_START
:
1936 r
= parse_boolean(optarg
);
1938 return log_error_errno(r
, "Failed to parse --auto-start= parameter: %s", optarg
);
1943 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1944 r
= parse_boolean(optarg
);
1946 return log_error_errno(r
, "Failed to parse --allow-interactive-authorization= parameter: %s", optarg
);
1948 arg_allow_interactive_authorization
= r
;
1952 r
= parse_sec(optarg
, &arg_timeout
);
1954 return log_error_errno(r
, "Failed to parse --timeout= parameter: %s", optarg
);
1958 case ARG_AUGMENT_CREDS
:
1959 r
= parse_boolean(optarg
);
1961 return log_error_errno(r
, "Failed to parse --augment-creds= parameter: %s", optarg
);
1963 arg_augment_creds
= r
;
1966 case ARG_WATCH_BIND
:
1967 r
= parse_boolean(optarg
);
1969 return log_error_errno(r
, "Failed to parse --watch-bind= parameter: %s", optarg
);
1978 assert_not_reached("Unhandled option");
1984 static int busctl_main(int argc
, char *argv
[]) {
1986 static const Verb verbs
[] = {
1987 { "list", VERB_ANY
, 1, VERB_DEFAULT
, list_bus_names
},
1988 { "status", VERB_ANY
, 2, 0, status
},
1989 { "monitor", VERB_ANY
, VERB_ANY
, 0, verb_monitor
},
1990 { "capture", VERB_ANY
, VERB_ANY
, 0, verb_capture
},
1991 { "tree", VERB_ANY
, VERB_ANY
, 0, tree
},
1992 { "introspect", 3, 4, 0, introspect
},
1993 { "call", 5, VERB_ANY
, 0, call
},
1994 { "get-property", 5, VERB_ANY
, 0, get_property
},
1995 { "set-property", 6, VERB_ANY
, 0, set_property
},
1996 { "help", VERB_ANY
, VERB_ANY
, 0, verb_help
},
2000 return dispatch_verb(argc
, argv
, verbs
, NULL
);
2003 int main(int argc
, char *argv
[]) {
2006 log_parse_environment();
2009 r
= parse_argv(argc
, argv
);
2013 r
= busctl_main(argc
, argv
);
2016 /* make sure we terminate the bus connection first, and then close the
2017 * pager, see issue #3543 for the details. */
2020 arg_matches
= strv_free(arg_matches
);
2022 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;