1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #include "alloc-util.h"
9 #include "bus-internal.h"
10 #include "bus-message.h"
11 #include "bus-signature.h"
14 #include "busctl-introspect.h"
18 #include "format-table.h"
20 #include "locale-util.h"
22 #include "main-func.h"
24 #include "parse-util.h"
25 #include "path-util.h"
26 #include "pretty-print.h"
28 #include "sort-util.h"
30 #include "terminal-util.h"
31 #include "user-util.h"
38 } arg_json
= JSON_OFF
;
39 static PagerFlags arg_pager_flags
= 0;
40 static bool arg_legend
= true;
41 static const char *arg_address
= NULL
;
42 static bool arg_unique
= false;
43 static bool arg_acquired
= false;
44 static bool arg_activatable
= false;
45 static bool arg_show_machine
= false;
46 static char **arg_matches
= NULL
;
47 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
48 static const char *arg_host
= NULL
;
49 static bool arg_user
= false;
50 static size_t arg_snaplen
= 4096;
51 static bool arg_list
= false;
52 static bool arg_quiet
= false;
53 static bool arg_verbose
= false;
54 static bool arg_xml_interface
= false;
55 static bool arg_expect_reply
= true;
56 static bool arg_auto_start
= true;
57 static bool arg_allow_interactive_authorization
= true;
58 static bool arg_augment_creds
= true;
59 static bool arg_watch_bind
= false;
60 static usec_t arg_timeout
= 0;
61 static const char *arg_destination
= NULL
;
63 STATIC_DESTRUCTOR_REGISTER(arg_matches
, strv_freep
);
65 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
66 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
68 static int json_transform_message(sd_bus_message
*m
, JsonVariant
**ret
);
69 static void json_dump_with_flags(JsonVariant
*v
, FILE *f
);
71 static int acquire_bus(bool set_monitor
, sd_bus
**ret
) {
72 _cleanup_(sd_bus_close_unrefp
) sd_bus
*bus
= NULL
;
77 return log_error_errno(r
, "Failed to allocate bus: %m");
80 r
= sd_bus_set_monitor(bus
, true);
82 return log_error_errno(r
, "Failed to set monitor mode: %m");
84 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
86 return log_error_errno(r
, "Failed to enable credentials: %m");
88 r
= sd_bus_negotiate_timestamp(bus
, true);
90 return log_error_errno(r
, "Failed to enable timestamps: %m");
92 r
= sd_bus_negotiate_fds(bus
, true);
94 return log_error_errno(r
, "Failed to enable fds: %m");
97 r
= sd_bus_set_bus_client(bus
, true);
99 return log_error_errno(r
, "Failed to set bus client: %m");
101 r
= sd_bus_set_watch_bind(bus
, arg_watch_bind
);
103 return log_error_errno(r
, "Failed to set watch-bind setting to '%s': %m", yes_no(arg_watch_bind
));
106 r
= sd_bus_set_address(bus
, arg_address
);
108 switch (arg_transport
) {
110 case BUS_TRANSPORT_LOCAL
:
113 r
= bus_set_address_user(bus
);
115 bus
->is_system
= true;
116 r
= bus_set_address_system(bus
);
120 case BUS_TRANSPORT_REMOTE
:
121 r
= bus_set_address_system_remote(bus
, arg_host
);
124 case BUS_TRANSPORT_MACHINE
:
125 r
= bus_set_address_system_machine(bus
, arg_host
);
129 assert_not_reached("Hmm, unknown transport type.");
133 return log_error_errno(r
, "Failed to set address: %m");
135 r
= sd_bus_start(bus
);
137 return log_error_errno(r
, "Failed to connect to bus: %m");
139 *ret
= TAKE_PTR(bus
);
144 static int list_bus_names(int argc
, char **argv
, void *userdata
) {
145 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
146 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
147 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
148 _cleanup_(table_unrefp
) Table
*table
= NULL
;
167 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
168 arg_unique
= arg_acquired
= arg_activatable
= true;
170 r
= acquire_bus(false, &bus
);
174 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
176 return log_error_errno(r
, "Failed to list names: %m");
178 names
= hashmap_new(&string_hash_ops
);
182 STRV_FOREACH(i
, acquired
) {
183 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
185 return log_error_errno(r
, "Failed to add to hashmap: %m");
188 STRV_FOREACH(i
, activatable
) {
189 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
190 if (r
< 0 && r
!= -EEXIST
)
191 return log_error_errno(r
, "Failed to add to hashmap: %m");
194 table
= table_new("activatable", "name", "pid", "process", "user", "connection", "unit", "session", "description", "machine");
198 r
= table_set_align_percent(table
, table_get_cell(table
, 0, COLUMN_PID
), 100);
200 return log_error_errno(r
, "Failed to set alignment: %m");
202 r
= table_set_empty_string(table
, "-");
204 return log_error_errno(r
, "Failed to set empty string: %m");
206 r
= table_set_sort(table
, COLUMN_NAME
, (size_t) -1);
208 return log_error_errno(r
, "Failed to set sort column: %m");
210 if (arg_show_machine
)
211 r
= table_set_display(table
, COLUMN_NAME
, COLUMN_PID
, COLUMN_PROCESS
, COLUMN_USER
, COLUMN_CONNECTION
, COLUMN_UNIT
, COLUMN_SESSION
, COLUMN_DESCRIPTION
, COLUMN_MACHINE
, (size_t) -1);
213 r
= table_set_display(table
, COLUMN_NAME
, COLUMN_PID
, COLUMN_PROCESS
, COLUMN_USER
, COLUMN_CONNECTION
, COLUMN_UNIT
, COLUMN_SESSION
, COLUMN_DESCRIPTION
, (size_t) -1);
215 return log_error_errno(r
, "Failed to set columns to display: %m");
217 table_set_header(table
, arg_legend
);
219 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
) {
220 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
222 if (v
== NAME_IS_ACTIVATABLE
) {
225 TABLE_INT
, PTR_TO_INT(v
),
230 TABLE_STRING
, "(activatable)", TABLE_SET_COLOR
, ansi_grey(),
236 return log_error_errno(r
, "Failed to fill line: %m");
241 assert(v
== NAME_IS_ACQUIRED
);
243 if (!arg_unique
&& k
[0] == ':')
246 if (!arg_acquired
&& k
[0] != ':')
249 r
= table_add_many(table
,
250 TABLE_INT
, PTR_TO_INT(v
),
253 return log_error_errno(r
, "Failed to add name %s to table: %m", k
);
255 r
= sd_bus_get_name_creds(
257 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
258 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
259 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
260 SD_BUS_CREDS_DESCRIPTION
, &creds
);
262 log_debug_errno(r
, "Failed to acquire credentials of service %s, ignoring: %m", k
);
264 r
= table_fill_empty(table
, COLUMN_MACHINE
);
266 const char *unique
= NULL
, *session
= NULL
, *unit
= NULL
, *cn
= NULL
;
270 r
= sd_bus_creds_get_pid(creds
, &pid
);
272 const char *comm
= NULL
;
274 (void) sd_bus_creds_get_comm(creds
, &comm
);
276 r
= table_add_many(table
,
278 TABLE_STRING
, strna(comm
));
280 r
= table_add_many(table
, TABLE_EMPTY
, TABLE_EMPTY
);
282 return log_error_errno(r
, "Failed to add fields to table: %m");
284 r
= sd_bus_creds_get_euid(creds
, &uid
);
286 _cleanup_free_
char *u
= NULL
;
288 u
= uid_to_name(uid
);
292 r
= table_add_cell(table
, NULL
, TABLE_STRING
, u
);
294 r
= table_add_cell(table
, NULL
, TABLE_EMPTY
, NULL
);
296 return log_error_errno(r
, "Failed to add field to table: %m");
298 (void) sd_bus_creds_get_unique_name(creds
, &unique
);
299 (void) sd_bus_creds_get_unit(creds
, &unit
);
300 (void) sd_bus_creds_get_session(creds
, &session
);
301 (void) sd_bus_creds_get_description(creds
, &cn
);
305 TABLE_STRING
, unique
,
307 TABLE_STRING
, session
,
311 return log_error_errno(r
, "Failed to add fields to table: %m");
313 if (arg_show_machine
) {
316 r
= sd_bus_get_name_machine_id(bus
, k
, &mid
);
318 log_debug_errno(r
, "Failed to acquire credentials of service %s, ignoring: %m", k
);
320 char m
[SD_ID128_STRING_MAX
];
322 r
= table_add_cell(table
, NULL
, TABLE_STRING
, sd_id128_to_string(mid
, m
));
324 return log_error_errno(r
, "Failed to add field to table: %m");
326 continue; /* line fully filled, no need to fill the remainder below */
330 r
= table_fill_empty(table
, 0);
332 return log_error_errno(r
, "Failed to fill line: %m");
335 if (IN_SET(arg_json
, JSON_OFF
, JSON_PRETTY
))
336 (void) pager_open(arg_pager_flags
);
339 r
= table_print_json(table
, stdout
, (arg_json
== JSON_PRETTY
? JSON_FORMAT_PRETTY
: JSON_FORMAT_NEWLINE
) | JSON_FORMAT_COLOR_AUTO
);
341 r
= table_print(table
, stdout
);
343 return log_error_errno(r
, "Failed to show table: %m");
348 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
349 const char *vertical
, *space
;
352 /* We assume the list is sorted. Let's first skip over the
353 * entry we are looking at. */
358 if (!streq(*l
, path
))
364 vertical
= strjoina(prefix
, special_glyph(SPECIAL_GLYPH_TREE_VERTICAL
));
365 space
= strjoina(prefix
, special_glyph(SPECIAL_GLYPH_TREE_SPACE
));
368 bool has_more
= false;
370 if (!*l
|| !path_startswith(*l
, path
))
375 if (!*n
|| !path_startswith(*n
, path
))
378 if (!path_startswith(*n
, *l
)) {
386 printf("%s%s%s\n", prefix
, special_glyph(has_more
? SPECIAL_GLYPH_TREE_BRANCH
: SPECIAL_GLYPH_TREE_RIGHT
), *l
);
388 print_subtree(has_more
? vertical
: space
, *l
, l
);
393 static void print_tree(const char *prefix
, char **l
) {
395 prefix
= strempty(prefix
);
401 printf("%s%s\n", prefix
, *i
);
405 if (strv_isempty(l
)) {
406 printf("No objects discovered.\n");
410 if (streq(l
[0], "/") && !l
[1]) {
411 printf("Only root object discovered.\n");
415 print_subtree(prefix
, "/", l
);
418 static int on_path(const char *path
, void *userdata
) {
419 Set
*paths
= userdata
;
424 r
= set_put_strdup(paths
, path
);
431 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
432 static const XMLIntrospectOps ops
= {
436 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
437 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
441 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
444 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
446 log_error_errno(r
, "Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
450 r
= sd_bus_message_read(reply
, "s", &xml
);
452 return bus_log_parse_error(r
);
454 return parse_xml_introspect(path
, xml
, &ops
, paths
);
457 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
458 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
459 _cleanup_free_
char **l
= NULL
;
463 paths
= set_new(&string_hash_ops
);
467 done
= set_new(&string_hash_ops
);
471 failed
= set_new(&string_hash_ops
);
479 r
= set_put(paths
, m
);
486 _cleanup_free_
char *p
= NULL
;
489 p
= set_steal_first(paths
);
493 if (set_contains(done
, p
) ||
494 set_contains(failed
, p
))
497 q
= find_nodes(bus
, service
, p
, paths
, many
);
502 q
= set_put(failed
, p
);
504 q
= set_put(done
, p
);
513 (void) pager_open(arg_pager_flags
);
515 l
= set_get_strv(done
);
520 print_tree(prefix
, l
);
527 static int tree(int argc
, char **argv
, void *userdata
) {
528 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
532 if (!arg_unique
&& !arg_acquired
)
535 r
= acquire_bus(false, &bus
);
540 _cleanup_strv_free_
char **names
= NULL
;
541 bool not_first
= false;
543 r
= sd_bus_list_names(bus
, &names
, NULL
);
545 return log_error_errno(r
, "Failed to get name list: %m");
547 (void) pager_open(arg_pager_flags
);
549 STRV_FOREACH(i
, names
) {
552 if (!arg_unique
&& (*i
)[0] == ':')
555 if (!arg_acquired
&& (*i
)[0] == ':')
561 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
563 q
= tree_one(bus
, *i
, NULL
, true);
570 STRV_FOREACH(i
, argv
+1) {
577 (void) pager_open(arg_pager_flags
);
578 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
581 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
590 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
594 const char *contents
= NULL
;
609 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
615 if (bus_type_is_container(type
) > 0) {
617 r
= sd_bus_message_enter_container(m
, type
, contents
);
621 if (type
== SD_BUS_TYPE_ARRAY
) {
624 /* count array entries */
627 r
= sd_bus_message_skip(m
, contents
);
636 r
= sd_bus_message_rewind(m
, false);
646 } else if (type
== SD_BUS_TYPE_VARIANT
) {
651 fprintf(f
, "%s", contents
);
655 r
= format_cmdline(m
, f
, needs_space
);
661 r
= sd_bus_message_exit_container(m
);
668 r
= sd_bus_message_read_basic(m
, type
, &basic
);
676 case SD_BUS_TYPE_BYTE
:
677 fprintf(f
, "%u", basic
.u8
);
680 case SD_BUS_TYPE_BOOLEAN
:
681 fputs(true_false(basic
.i
), f
);
684 case SD_BUS_TYPE_INT16
:
685 fprintf(f
, "%i", basic
.s16
);
688 case SD_BUS_TYPE_UINT16
:
689 fprintf(f
, "%u", basic
.u16
);
692 case SD_BUS_TYPE_INT32
:
693 fprintf(f
, "%i", basic
.s32
);
696 case SD_BUS_TYPE_UINT32
:
697 fprintf(f
, "%u", basic
.u32
);
700 case SD_BUS_TYPE_INT64
:
701 fprintf(f
, "%" PRIi64
, basic
.s64
);
704 case SD_BUS_TYPE_UINT64
:
705 fprintf(f
, "%" PRIu64
, basic
.u64
);
708 case SD_BUS_TYPE_DOUBLE
:
709 fprintf(f
, "%g", basic
.d64
);
712 case SD_BUS_TYPE_STRING
:
713 case SD_BUS_TYPE_OBJECT_PATH
:
714 case SD_BUS_TYPE_SIGNATURE
: {
715 _cleanup_free_
char *b
= NULL
;
717 b
= cescape(basic
.string
);
721 fprintf(f
, "\"%s\"", b
);
725 case SD_BUS_TYPE_UNIX_FD
:
726 fprintf(f
, "%i", basic
.i
);
730 assert_not_reached("Unknown basic type.");
737 typedef struct Member
{
748 static void member_hash_func(const Member
*m
, struct siphash
*state
) {
754 string_hash_func(m
->type
, state
);
756 arity
+= !!m
->name
+ !!m
->interface
;
758 uint64_hash_func(&arity
, state
);
761 string_hash_func(m
->name
, state
);
764 string_hash_func(m
->interface
, state
);
767 static int member_compare_func(const Member
*x
, const Member
*y
) {
775 d
= strcmp_ptr(x
->interface
, y
->interface
);
779 d
= strcmp(x
->type
, y
->type
);
783 return strcmp_ptr(x
->name
, y
->name
);
786 static int member_compare_funcp(Member
* const *a
, Member
* const *b
) {
787 return member_compare_func(*a
, *b
);
790 static void member_free(Member
*m
) {
802 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
804 static void member_set_free(Set
*s
) {
805 set_free_with_destructor(s
, member_free
);
808 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
810 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
811 _cleanup_(member_freep
) Member
*m
;
812 Set
*members
= userdata
;
822 m
->type
= "interface";
825 r
= free_and_strdup(&m
->interface
, interface
);
829 r
= set_put(members
, m
);
831 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Duplicate interface");
837 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
838 _cleanup_(member_freep
) Member
*m
;
839 Set
*members
= userdata
;
852 r
= free_and_strdup(&m
->interface
, interface
);
856 r
= free_and_strdup(&m
->name
, name
);
860 r
= free_and_strdup(&m
->signature
, signature
);
864 r
= free_and_strdup(&m
->result
, result
);
868 r
= set_put(members
, m
);
870 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Duplicate method");
876 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
877 _cleanup_(member_freep
) Member
*m
;
878 Set
*members
= userdata
;
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 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Duplicate signal");
911 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
912 _cleanup_(member_freep
) Member
*m
;
913 Set
*members
= userdata
;
923 m
->type
= "property";
925 m
->writable
= writable
;
927 r
= free_and_strdup(&m
->interface
, interface
);
931 r
= free_and_strdup(&m
->name
, name
);
935 r
= free_and_strdup(&m
->signature
, signature
);
939 r
= set_put(members
, m
);
941 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Duplicate property");
947 DEFINE_PRIVATE_HASH_OPS(member_hash_ops
, Member
, member_hash_func
, member_compare_func
);
949 static int introspect(int argc
, char **argv
, void *userdata
) {
950 static const XMLIntrospectOps ops
= {
951 .on_interface
= on_interface
,
952 .on_method
= on_method
,
953 .on_signal
= on_signal
,
954 .on_property
= on_property
,
957 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
958 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply_xml
= NULL
;
959 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
960 _cleanup_(member_set_freep
) Set
*members
= NULL
;
961 unsigned name_width
, type_width
, signature_width
, result_width
, j
, k
= 0;
962 Member
*m
, **sorted
= NULL
;
967 r
= acquire_bus(false, &bus
);
971 members
= set_new(&member_hash_ops
);
975 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply_xml
, "");
977 return log_error_errno(r
, "Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
979 r
= sd_bus_message_read(reply_xml
, "s", &xml
);
981 return bus_log_parse_error(r
);
983 if (arg_xml_interface
) {
984 /* Just dump the received XML and finish */
989 /* First, get list of all properties */
990 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
994 /* Second, find the current values for them */
995 SET_FOREACH(m
, members
, i
) {
996 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
998 if (!streq(m
->type
, "property"))
1004 if (argv
[3] && !streq(argv
[3], m
->interface
))
1007 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
1009 return log_error_errno(r
, "Failed to get all properties on interface %s: %s",
1010 m
->interface
, bus_error_message(&error
, r
));
1012 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
1014 return bus_log_parse_error(r
);
1018 _cleanup_free_
char *buf
= NULL
;
1019 _cleanup_fclose_
FILE *mf
= NULL
;
1023 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
1025 return bus_log_parse_error(r
);
1030 r
= sd_bus_message_read(reply
, "s", &name
);
1032 return bus_log_parse_error(r
);
1034 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
1036 return bus_log_parse_error(r
);
1038 mf
= open_memstream_unlocked(&buf
, &sz
);
1042 r
= format_cmdline(reply
, mf
, false);
1044 return bus_log_parse_error(r
);
1046 mf
= safe_fclose(mf
);
1048 z
= set_get(members
, &((Member
) {
1050 .interface
= m
->interface
,
1051 .name
= (char*) name
}));
1053 free_and_replace(z
->value
, buf
);
1055 r
= sd_bus_message_exit_container(reply
);
1057 return bus_log_parse_error(r
);
1059 r
= sd_bus_message_exit_container(reply
);
1061 return bus_log_parse_error(r
);
1064 r
= sd_bus_message_exit_container(reply
);
1066 return bus_log_parse_error(r
);
1069 (void) pager_open(arg_pager_flags
);
1071 name_width
= STRLEN("NAME");
1072 type_width
= STRLEN("TYPE");
1073 signature_width
= STRLEN("SIGNATURE");
1074 result_width
= STRLEN("RESULT/VALUE");
1076 sorted
= newa(Member
*, set_size(members
));
1078 SET_FOREACH(m
, members
, i
) {
1080 if (argv
[3] && !streq(argv
[3], m
->interface
))
1084 name_width
= MAX(name_width
, strlen(m
->interface
));
1086 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1088 type_width
= MAX(type_width
, strlen(m
->type
));
1090 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1092 result_width
= MAX(result_width
, strlen(m
->result
));
1094 result_width
= MAX(result_width
, strlen(m
->value
));
1099 if (result_width
> 40)
1102 typesafe_qsort(sorted
, k
, member_compare_funcp
);
1105 printf("%-*s %-*s %-*s %-*s %s\n",
1106 (int) name_width
, "NAME",
1107 (int) type_width
, "TYPE",
1108 (int) signature_width
, "SIGNATURE",
1109 (int) result_width
, "RESULT/VALUE",
1113 for (j
= 0; j
< k
; j
++) {
1114 _cleanup_free_
char *ellipsized
= NULL
;
1120 if (argv
[3] && !streq(argv
[3], m
->interface
))
1123 is_interface
= streq(m
->type
, "interface");
1125 if (argv
[3] && is_interface
)
1129 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1135 rv
= empty_to_dash(m
->result
);
1137 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1138 is_interface
? ansi_highlight() : "",
1139 is_interface
? "" : ".",
1140 - !is_interface
+ (int) name_width
, empty_to_dash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1141 is_interface
? ansi_normal() : "",
1142 (int) type_width
, empty_to_dash(m
->type
),
1143 (int) signature_width
, empty_to_dash(m
->signature
),
1144 (int) result_width
, rv
,
1145 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1146 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1147 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1148 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1149 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1150 m
->writable
? " writable" : "");
1156 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1157 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1160 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1161 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1164 static int message_json(sd_bus_message
*m
, FILE *f
) {
1165 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
, *w
= NULL
;
1169 r
= json_transform_message(m
, &v
);
1173 e
[0] = m
->header
->endian
;
1176 r
= json_build(&w
, JSON_BUILD_OBJECT(
1177 JSON_BUILD_PAIR("type", JSON_BUILD_STRING(bus_message_type_to_string(m
->header
->type
))),
1178 JSON_BUILD_PAIR("endian", JSON_BUILD_STRING(e
)),
1179 JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(m
->header
->flags
)),
1180 JSON_BUILD_PAIR("version", JSON_BUILD_INTEGER(m
->header
->version
)),
1181 JSON_BUILD_PAIR_CONDITION(m
->priority
!= 0, "priority", JSON_BUILD_INTEGER(m
->priority
)),
1182 JSON_BUILD_PAIR("cookie", JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m
))),
1183 JSON_BUILD_PAIR_CONDITION(m
->reply_cookie
!= 0, "reply_cookie", JSON_BUILD_INTEGER(m
->reply_cookie
)),
1184 JSON_BUILD_PAIR_CONDITION(m
->sender
, "sender", JSON_BUILD_STRING(m
->sender
)),
1185 JSON_BUILD_PAIR_CONDITION(m
->destination
, "destination", JSON_BUILD_STRING(m
->destination
)),
1186 JSON_BUILD_PAIR_CONDITION(m
->path
, "path", JSON_BUILD_STRING(m
->path
)),
1187 JSON_BUILD_PAIR_CONDITION(m
->interface
, "interface", JSON_BUILD_STRING(m
->interface
)),
1188 JSON_BUILD_PAIR_CONDITION(m
->member
, "member", JSON_BUILD_STRING(m
->member
)),
1189 JSON_BUILD_PAIR_CONDITION(m
->monotonic
!= 0, "monotonic", JSON_BUILD_INTEGER(m
->monotonic
)),
1190 JSON_BUILD_PAIR_CONDITION(m
->realtime
!= 0, "realtime", JSON_BUILD_INTEGER(m
->realtime
)),
1191 JSON_BUILD_PAIR_CONDITION(m
->seqnum
!= 0, "seqnum", JSON_BUILD_INTEGER(m
->seqnum
)),
1192 JSON_BUILD_PAIR_CONDITION(m
->error
.name
, "error_name", JSON_BUILD_STRING(m
->error
.name
)),
1193 JSON_BUILD_PAIR("payload", JSON_BUILD_VARIANT(v
))));
1195 return log_error_errno(r
, "Failed to build JSON object: %m");
1197 json_dump_with_flags(w
, f
);
1201 static int monitor(int argc
, char **argv
, int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1202 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1203 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*message
= NULL
;
1204 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1207 const char *unique_name
;
1208 bool is_monitor
= false;
1211 r
= acquire_bus(true, &bus
);
1215 /* upgrade connection; it's not used for anything else after this call */
1216 r
= sd_bus_message_new_method_call(bus
,
1218 "org.freedesktop.DBus",
1219 "/org/freedesktop/DBus",
1220 "org.freedesktop.DBus.Monitoring",
1223 return bus_log_create_error(r
);
1225 r
= sd_bus_message_open_container(message
, 'a', "s");
1227 return bus_log_create_error(r
);
1229 STRV_FOREACH(i
, argv
+1) {
1230 _cleanup_free_
char *m
= NULL
;
1232 if (!service_name_is_valid(*i
))
1233 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid service name '%s'", *i
);
1235 m
= strjoin("sender='", *i
, "'");
1239 r
= sd_bus_message_append_basic(message
, 's', m
);
1241 return bus_log_create_error(r
);
1244 m
= strjoin("destination='", *i
, "'");
1248 r
= sd_bus_message_append_basic(message
, 's', m
);
1250 return bus_log_create_error(r
);
1253 STRV_FOREACH(i
, arg_matches
) {
1254 r
= sd_bus_message_append_basic(message
, 's', *i
);
1256 return bus_log_create_error(r
);
1259 r
= sd_bus_message_close_container(message
);
1261 return bus_log_create_error(r
);
1263 r
= sd_bus_message_append_basic(message
, 'u', &flags
);
1265 return bus_log_create_error(r
);
1267 r
= sd_bus_call(bus
, message
, arg_timeout
, &error
, NULL
);
1269 return log_error_errno(r
, "Call to org.freedesktop.DBus.Monitoring.BecomeMonitor failed: %s",
1270 bus_error_message(&error
, r
));
1272 r
= sd_bus_get_unique_name(bus
, &unique_name
);
1274 return log_error_errno(r
, "Failed to get unique name: %m");
1276 log_info("Monitoring bus message stream.");
1279 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1281 r
= sd_bus_process(bus
, &m
);
1283 return log_error_errno(r
, "Failed to process bus: %m");
1288 /* wait until we lose our unique name */
1289 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus", "NameLost") <= 0)
1292 r
= sd_bus_message_read(m
, "s", &name
);
1294 return log_error_errno(r
, "Failed to read lost name: %m");
1296 if (streq(name
, unique_name
))
1306 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1307 log_info("Connection terminated, exiting.");
1317 r
= sd_bus_wait(bus
, (uint64_t) -1);
1319 return log_error_errno(r
, "Failed to wait for bus: %m");
1323 static int verb_monitor(int argc
, char **argv
, void *userdata
) {
1324 return monitor(argc
, argv
, arg_json
!= JSON_OFF
? message_json
: message_dump
);
1327 static int verb_capture(int argc
, char **argv
, void *userdata
) {
1330 if (isatty(fileno(stdout
)) > 0)
1331 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1332 "Refusing to write message data to console, please redirect output to a file.");
1334 bus_pcap_header(arg_snaplen
, stdout
);
1336 r
= monitor(argc
, argv
, message_pcap
);
1340 r
= fflush_and_check(stdout
);
1342 return log_error_errno(r
, "Couldn't write capture file: %m");
1347 static int status(int argc
, char **argv
, void *userdata
) {
1348 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1349 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
1353 r
= acquire_bus(false, &bus
);
1357 if (!isempty(argv
[1])) {
1358 r
= parse_pid(argv
[1], &pid
);
1360 r
= sd_bus_get_name_creds(
1363 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1366 r
= sd_bus_creds_new_from_pid(
1371 const char *scope
, *address
;
1374 r
= sd_bus_get_address(bus
, &address
);
1376 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1378 r
= sd_bus_get_scope(bus
, &scope
);
1380 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1382 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1384 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1386 r
= sd_bus_get_owner_creds(
1388 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1393 return log_error_errno(r
, "Failed to get credentials: %m");
1395 bus_creds_dump(creds
, NULL
, false);
1399 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1419 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1420 "Too few parameters for signature.");
1427 case SD_BUS_TYPE_BOOLEAN
:
1429 r
= parse_boolean(v
);
1431 return log_error_errno(r
, "Failed to parse '%s' as boolean: %m", v
);
1433 r
= sd_bus_message_append_basic(m
, t
, &r
);
1436 case SD_BUS_TYPE_BYTE
: {
1439 r
= safe_atou8(v
, &z
);
1441 return log_error_errno(r
, "Failed to parse '%s' as byte (unsigned 8bit integer): %m", v
);
1443 r
= sd_bus_message_append_basic(m
, t
, &z
);
1447 case SD_BUS_TYPE_INT16
: {
1450 r
= safe_atoi16(v
, &z
);
1452 return log_error_errno(r
, "Failed to parse '%s' as signed 16bit integer: %m", v
);
1454 r
= sd_bus_message_append_basic(m
, t
, &z
);
1458 case SD_BUS_TYPE_UINT16
: {
1461 r
= safe_atou16(v
, &z
);
1463 return log_error_errno(r
, "Failed to parse '%s' as unsigned 16bit integer: %m", v
);
1465 r
= sd_bus_message_append_basic(m
, t
, &z
);
1469 case SD_BUS_TYPE_INT32
: {
1472 r
= safe_atoi32(v
, &z
);
1474 return log_error_errno(r
, "Failed to parse '%s' as signed 32bit integer: %m", v
);
1476 r
= sd_bus_message_append_basic(m
, t
, &z
);
1480 case SD_BUS_TYPE_UINT32
: {
1483 r
= safe_atou32(v
, &z
);
1485 return log_error_errno(r
, "Failed to parse '%s' as unsigned 32bit integer: %m", v
);
1487 r
= sd_bus_message_append_basic(m
, t
, &z
);
1491 case SD_BUS_TYPE_INT64
: {
1494 r
= safe_atoi64(v
, &z
);
1496 return log_error_errno(r
, "Failed to parse '%s' as signed 64bit integer: %m", v
);
1498 r
= sd_bus_message_append_basic(m
, t
, &z
);
1502 case SD_BUS_TYPE_UINT64
: {
1505 r
= safe_atou64(v
, &z
);
1507 return log_error_errno(r
, "Failed to parse '%s' as unsigned 64bit integer: %m", v
);
1509 r
= sd_bus_message_append_basic(m
, t
, &z
);
1513 case SD_BUS_TYPE_DOUBLE
: {
1516 r
= safe_atod(v
, &z
);
1518 return log_error_errno(r
, "Failed to parse '%s' as double precision floating point: %m", v
);
1520 r
= sd_bus_message_append_basic(m
, t
, &z
);
1524 case SD_BUS_TYPE_STRING
:
1525 case SD_BUS_TYPE_OBJECT_PATH
:
1526 case SD_BUS_TYPE_SIGNATURE
:
1528 r
= sd_bus_message_append_basic(m
, t
, v
);
1531 case SD_BUS_TYPE_ARRAY
: {
1535 r
= safe_atou32(v
, &n
);
1537 return log_error_errno(r
, "Failed to parse '%s' number of array entries: %m", v
);
1539 r
= signature_element_length(signature
, &k
);
1541 return log_error_errno(r
, "Invalid array signature: %m");
1546 memcpy(s
, signature
, k
);
1549 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1551 return bus_log_create_error(r
);
1553 for (i
= 0; i
< n
; i
++) {
1554 r
= message_append_cmdline(m
, s
, &p
);
1562 r
= sd_bus_message_close_container(m
);
1566 case SD_BUS_TYPE_VARIANT
:
1567 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1569 return bus_log_create_error(r
);
1571 r
= message_append_cmdline(m
, v
, &p
);
1575 r
= sd_bus_message_close_container(m
);
1578 case SD_BUS_TYPE_STRUCT_BEGIN
:
1579 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1585 r
= signature_element_length(signature
, &k
);
1587 return log_error_errno(r
, "Invalid struct/dict entry signature: %m");
1591 memcpy(s
, signature
+ 1, k
- 2);
1594 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1596 return bus_log_create_error(r
);
1598 r
= message_append_cmdline(m
, s
, &p
);
1605 r
= sd_bus_message_close_container(m
);
1609 case SD_BUS_TYPE_UNIX_FD
:
1610 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1611 "UNIX file descriptor not supported as type.");
1614 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1615 "Unknown signature type %c.", t
);
1619 return bus_log_create_error(r
);
1626 static int json_transform_one(sd_bus_message
*m
, JsonVariant
**ret
);
1628 static int json_transform_array_or_struct(sd_bus_message
*m
, JsonVariant
**ret
) {
1629 size_t n_elements
= 0, n_allocated
= 0;
1630 JsonVariant
**elements
= NULL
;
1637 r
= sd_bus_message_at_end(m
, false);
1639 bus_log_parse_error(r
);
1645 if (!GREEDY_REALLOC(elements
, n_allocated
, n_elements
+ 1)) {
1650 r
= json_transform_one(m
, elements
+ n_elements
);
1657 r
= json_variant_new_array(ret
, elements
, n_elements
);
1660 json_variant_unref_many(elements
, n_elements
);
1666 static int json_transform_variant(sd_bus_message
*m
, const char *contents
, JsonVariant
**ret
) {
1667 _cleanup_(json_variant_unrefp
) JsonVariant
*value
= NULL
;
1674 r
= json_transform_one(m
, &value
);
1678 r
= json_build(ret
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(contents
)),
1679 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(value
))));
1686 static int json_transform_dict_array(sd_bus_message
*m
, JsonVariant
**ret
) {
1687 size_t n_elements
= 0, n_allocated
= 0;
1688 JsonVariant
**elements
= NULL
;
1695 const char *contents
;
1698 r
= sd_bus_message_at_end(m
, false);
1700 bus_log_parse_error(r
);
1706 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
1710 assert(type
== 'e');
1712 if (!GREEDY_REALLOC(elements
, n_allocated
, n_elements
+ 2)) {
1717 r
= sd_bus_message_enter_container(m
, type
, contents
);
1719 bus_log_parse_error(r
);
1723 r
= json_transform_one(m
, elements
+ n_elements
);
1729 r
= json_transform_one(m
, elements
+ n_elements
);
1735 r
= sd_bus_message_exit_container(m
);
1737 bus_log_parse_error(r
);
1742 r
= json_variant_new_object(ret
, elements
, n_elements
);
1745 json_variant_unref_many(elements
, n_elements
);
1751 static int json_transform_one(sd_bus_message
*m
, JsonVariant
**ret
) {
1752 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1753 const char *contents
;
1760 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
1762 return bus_log_parse_error(r
);
1766 case SD_BUS_TYPE_BYTE
: {
1769 r
= sd_bus_message_read_basic(m
, type
, &b
);
1771 return bus_log_parse_error(r
);
1773 r
= json_variant_new_unsigned(&v
, b
);
1775 return log_error_errno(r
, "Failed to transform byte: %m");
1780 case SD_BUS_TYPE_BOOLEAN
: {
1783 r
= sd_bus_message_read_basic(m
, type
, &b
);
1785 return bus_log_parse_error(r
);
1787 r
= json_variant_new_boolean(&v
, b
);
1789 return log_error_errno(r
, "Failed to transform boolean: %m");
1794 case SD_BUS_TYPE_INT16
: {
1797 r
= sd_bus_message_read_basic(m
, type
, &b
);
1799 return bus_log_parse_error(r
);
1801 r
= json_variant_new_integer(&v
, b
);
1803 return log_error_errno(r
, "Failed to transform int16: %m");
1808 case SD_BUS_TYPE_UINT16
: {
1811 r
= sd_bus_message_read_basic(m
, type
, &b
);
1813 return bus_log_parse_error(r
);
1815 r
= json_variant_new_unsigned(&v
, b
);
1817 return log_error_errno(r
, "Failed to transform uint16: %m");
1822 case SD_BUS_TYPE_INT32
: {
1825 r
= sd_bus_message_read_basic(m
, type
, &b
);
1827 return bus_log_parse_error(r
);
1829 r
= json_variant_new_integer(&v
, b
);
1831 return log_error_errno(r
, "Failed to transform int32: %m");
1836 case SD_BUS_TYPE_UINT32
: {
1839 r
= sd_bus_message_read_basic(m
, type
, &b
);
1841 return bus_log_parse_error(r
);
1843 r
= json_variant_new_unsigned(&v
, b
);
1845 return log_error_errno(r
, "Failed to transform uint32: %m");
1850 case SD_BUS_TYPE_INT64
: {
1853 r
= sd_bus_message_read_basic(m
, type
, &b
);
1855 return bus_log_parse_error(r
);
1857 r
= json_variant_new_integer(&v
, b
);
1859 return log_error_errno(r
, "Failed to transform int64: %m");
1864 case SD_BUS_TYPE_UINT64
: {
1867 r
= sd_bus_message_read_basic(m
, type
, &b
);
1869 return bus_log_parse_error(r
);
1871 r
= json_variant_new_unsigned(&v
, b
);
1873 return log_error_errno(r
, "Failed to transform uint64: %m");
1878 case SD_BUS_TYPE_DOUBLE
: {
1881 r
= sd_bus_message_read_basic(m
, type
, &d
);
1883 return bus_log_parse_error(r
);
1885 r
= json_variant_new_real(&v
, d
);
1887 return log_error_errno(r
, "Failed to transform double: %m");
1892 case SD_BUS_TYPE_STRING
:
1893 case SD_BUS_TYPE_OBJECT_PATH
:
1894 case SD_BUS_TYPE_SIGNATURE
: {
1897 r
= sd_bus_message_read_basic(m
, type
, &s
);
1899 return bus_log_parse_error(r
);
1901 r
= json_variant_new_string(&v
, s
);
1903 return log_error_errno(r
, "Failed to transform double: %m");
1908 case SD_BUS_TYPE_UNIX_FD
:
1909 r
= sd_bus_message_read_basic(m
, type
, NULL
);
1911 return bus_log_parse_error(r
);
1913 r
= json_variant_new_null(&v
);
1915 return log_error_errno(r
, "Failed to transform fd: %m");
1919 case SD_BUS_TYPE_ARRAY
:
1920 case SD_BUS_TYPE_VARIANT
:
1921 case SD_BUS_TYPE_STRUCT
:
1922 r
= sd_bus_message_enter_container(m
, type
, contents
);
1924 return bus_log_parse_error(r
);
1926 if (type
== SD_BUS_TYPE_VARIANT
)
1927 r
= json_transform_variant(m
, contents
, &v
);
1928 else if (type
== SD_BUS_TYPE_ARRAY
&& contents
[0] == '{')
1929 r
= json_transform_dict_array(m
, &v
);
1931 r
= json_transform_array_or_struct(m
, &v
);
1935 r
= sd_bus_message_exit_container(m
);
1937 return bus_log_parse_error(r
);
1942 assert_not_reached("Unexpected element type");
1949 static int json_transform_message(sd_bus_message
*m
, JsonVariant
**ret
) {
1950 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1957 assert_se(type
= sd_bus_message_get_signature(m
, false));
1959 r
= json_transform_array_or_struct(m
, &v
);
1963 r
= json_build(ret
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(type
)),
1964 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(v
))));
1971 static void json_dump_with_flags(JsonVariant
*v
, FILE *f
) {
1973 json_variant_dump(v
,
1974 (arg_json
== JSON_PRETTY
? JSON_FORMAT_PRETTY
: JSON_FORMAT_NEWLINE
) |
1975 JSON_FORMAT_COLOR_AUTO
,
1979 static int call(int argc
, char **argv
, void *userdata
) {
1980 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1981 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1982 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1985 r
= acquire_bus(false, &bus
);
1989 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1991 return bus_log_create_error(r
);
1993 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1995 return bus_log_create_error(r
);
1997 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1999 return bus_log_create_error(r
);
2001 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
2003 return bus_log_create_error(r
);
2005 if (!isempty(argv
[5])) {
2010 r
= message_append_cmdline(m
, argv
[5], &p
);
2015 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Too many parameters for signature.");
2018 if (!arg_expect_reply
) {
2019 r
= sd_bus_send(bus
, m
, NULL
);
2021 return log_error_errno(r
, "Failed to send message: %m");
2026 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
2028 return log_error_errno(r
, "Call failed: %s", bus_error_message(&error
, r
));
2030 r
= sd_bus_message_is_empty(reply
);
2032 return bus_log_parse_error(r
);
2034 if (r
== 0 && !arg_quiet
) {
2036 if (arg_json
!= JSON_OFF
) {
2037 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
2039 if (arg_json
!= JSON_SHORT
)
2040 (void) pager_open(arg_pager_flags
);
2042 r
= json_transform_message(reply
, &v
);
2046 json_dump_with_flags(v
, stdout
);
2048 } else if (arg_verbose
) {
2049 (void) pager_open(arg_pager_flags
);
2051 r
= bus_message_dump(reply
, stdout
, 0);
2056 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
2059 r
= format_cmdline(reply
, stdout
, false);
2061 return bus_log_parse_error(r
);
2063 fputc('\n', stdout
);
2070 static int emit_signal(int argc
, char **argv
, void *userdata
) {
2071 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2072 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2075 r
= acquire_bus(false, &bus
);
2079 r
= sd_bus_message_new_signal(bus
, &m
, argv
[1], argv
[2], argv
[3]);
2081 return bus_log_create_error(r
);
2083 if (arg_destination
) {
2084 r
= sd_bus_message_set_destination(m
, arg_destination
);
2086 return bus_log_create_error(r
);
2089 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
2091 return bus_log_create_error(r
);
2093 if (!isempty(argv
[4])) {
2098 r
= message_append_cmdline(m
, argv
[4], &p
);
2103 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Too many parameters for signature.");
2106 r
= sd_bus_send(bus
, m
, NULL
);
2108 return log_error_errno(r
, "Failed to send signal: %m");
2113 static int get_property(int argc
, char **argv
, void *userdata
) {
2114 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2115 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2119 r
= acquire_bus(false, &bus
);
2123 STRV_FOREACH(i
, argv
+ 4) {
2124 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2125 const char *contents
= NULL
;
2128 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
2130 return log_error_errno(r
, "Failed to get property %s on interface %s: %s",
2132 bus_error_message(&error
, r
));
2134 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
2136 return bus_log_parse_error(r
);
2138 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
2140 return bus_log_parse_error(r
);
2142 if (arg_json
!= JSON_OFF
) {
2143 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
2145 if (arg_json
!= JSON_SHORT
)
2146 (void) pager_open(arg_pager_flags
);
2148 r
= json_transform_variant(reply
, contents
, &v
);
2152 json_dump_with_flags(v
, stdout
);
2154 } else if (arg_verbose
) {
2155 (void) pager_open(arg_pager_flags
);
2157 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
2161 fputs(contents
, stdout
);
2164 r
= format_cmdline(reply
, stdout
, false);
2166 return bus_log_parse_error(r
);
2168 fputc('\n', stdout
);
2171 r
= sd_bus_message_exit_container(reply
);
2173 return bus_log_parse_error(r
);
2179 static int set_property(int argc
, char **argv
, void *userdata
) {
2180 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2181 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2182 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2186 r
= acquire_bus(false, &bus
);
2190 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
2192 return bus_log_create_error(r
);
2194 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
2196 return bus_log_create_error(r
);
2198 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
2200 return bus_log_create_error(r
);
2203 r
= message_append_cmdline(m
, argv
[5], &p
);
2207 r
= sd_bus_message_close_container(m
);
2209 return bus_log_create_error(r
);
2212 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Too many parameters for signature.");
2214 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
2216 return log_error_errno(r
, "Failed to set property %s on interface %s: %s",
2218 bus_error_message(&error
, r
));
2223 static int help(void) {
2224 _cleanup_free_
char *link
= NULL
;
2227 r
= terminal_urlify_man("busctl", "1", &link
);
2231 printf("%s%s [OPTIONS...] {COMMAND} ...\n\n"
2232 "Introspect the bus.%s\n\n"
2234 " list List bus names\n"
2235 " status [SERVICE] Show bus service, process or bus owner credentials\n"
2236 " monitor [SERVICE...] Show bus traffic\n"
2237 " capture [SERVICE...] Capture bus traffic as pcap\n"
2238 " tree [SERVICE...] Show object tree of service\n"
2239 " introspect SERVICE OBJECT [INTERFACE]\n"
2240 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
2242 " emit OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT...]]\n"
2244 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
2245 " Get property value\n"
2246 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
2247 " Set property value\n"
2248 " help Show this help\n"
2250 " -h --help Show this help\n"
2251 " --version Show package version\n"
2252 " --no-pager Do not pipe output into a pager\n"
2253 " --no-legend Do not show the headers and footers\n"
2254 " --system Connect to system bus\n"
2255 " --user Connect to user bus\n"
2256 " -H --host=[USER@]HOST Operate on remote host\n"
2257 " -M --machine=CONTAINER Operate on local container\n"
2258 " --address=ADDRESS Connect to bus specified by address\n"
2259 " --show-machine Show machine ID column in list\n"
2260 " --unique Only show unique names\n"
2261 " --acquired Only show acquired names\n"
2262 " --activatable Only show activatable names\n"
2263 " --match=MATCH Only show matching messages\n"
2264 " --size=SIZE Maximum length of captured packet\n"
2265 " --list Don't show tree, but simple object path list\n"
2266 " -q --quiet Don't show method call reply\n"
2267 " --verbose Show result values in long format\n"
2268 " --json=MODE Output as JSON\n"
2269 " -j Same as --json=pretty on tty, --json=short otherwise\n"
2270 " --expect-reply=BOOL Expect a method call reply\n"
2271 " --auto-start=BOOL Auto-start destination service\n"
2272 " --allow-interactive-authorization=BOOL\n"
2273 " Allow interactive authorization for operation\n"
2274 " --timeout=SECS Maximum time to wait for method call completion\n"
2275 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
2276 " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n"
2278 " --destination=SERVICE Destination service of a signal\n"
2279 "\nSee the %s for details.\n"
2281 , program_invocation_short_name
2289 static int verb_help(int argc
, char **argv
, void *userdata
) {
2293 static int parse_argv(int argc
, char *argv
[]) {
2296 ARG_VERSION
= 0x100,
2313 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
2321 static const struct option options
[] = {
2322 { "help", no_argument
, NULL
, 'h' },
2323 { "version", no_argument
, NULL
, ARG_VERSION
},
2324 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
2325 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
2326 { "system", no_argument
, NULL
, ARG_SYSTEM
},
2327 { "user", no_argument
, NULL
, ARG_USER
},
2328 { "address", required_argument
, NULL
, ARG_ADDRESS
},
2329 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
2330 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
2331 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
2332 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
2333 { "match", required_argument
, NULL
, ARG_MATCH
},
2334 { "host", required_argument
, NULL
, 'H' },
2335 { "machine", required_argument
, NULL
, 'M' },
2336 { "size", required_argument
, NULL
, ARG_SIZE
},
2337 { "list", no_argument
, NULL
, ARG_LIST
},
2338 { "quiet", no_argument
, NULL
, 'q' },
2339 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
2340 { "xml-interface", no_argument
, NULL
, ARG_XML_INTERFACE
},
2341 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
2342 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
2343 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
2344 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
2345 { "augment-creds", required_argument
, NULL
, ARG_AUGMENT_CREDS
},
2346 { "watch-bind", required_argument
, NULL
, ARG_WATCH_BIND
},
2347 { "json", required_argument
, NULL
, ARG_JSON
},
2348 { "destination", required_argument
, NULL
, ARG_DESTINATION
},
2357 while ((c
= getopt_long(argc
, argv
, "hH:M:qj", options
, NULL
)) >= 0)
2368 arg_pager_flags
|= PAGER_DISABLE
;
2384 arg_address
= optarg
;
2387 case ARG_SHOW_MACHINE
:
2388 arg_show_machine
= true;
2396 arg_acquired
= true;
2399 case ARG_ACTIVATABLE
:
2400 arg_activatable
= true;
2404 if (strv_extend(&arg_matches
, optarg
) < 0)
2411 r
= parse_size(optarg
, 1024, &sz
);
2413 return log_error_errno(r
, "Failed to parse size '%s': %m", optarg
);
2415 if ((uint64_t) (size_t) sz
!= sz
)
2416 return log_error_errno(SYNTHETIC_ERRNO(E2BIG
),
2417 "Size out of range.");
2419 arg_snaplen
= (size_t) sz
;
2428 arg_transport
= BUS_TRANSPORT_REMOTE
;
2433 arg_transport
= BUS_TRANSPORT_MACHINE
;
2445 case ARG_XML_INTERFACE
:
2446 arg_xml_interface
= true;
2449 case ARG_EXPECT_REPLY
:
2450 r
= parse_boolean(optarg
);
2452 return log_error_errno(r
, "Failed to parse --expect-reply= parameter '%s': %m", optarg
);
2454 arg_expect_reply
= r
;
2457 case ARG_AUTO_START
:
2458 r
= parse_boolean(optarg
);
2460 return log_error_errno(r
, "Failed to parse --auto-start= parameter '%s': %m", optarg
);
2465 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
2466 r
= parse_boolean(optarg
);
2468 return log_error_errno(r
, "Failed to parse --allow-interactive-authorization= parameter '%s': %m", optarg
);
2470 arg_allow_interactive_authorization
= r
;
2474 r
= parse_sec(optarg
, &arg_timeout
);
2476 return log_error_errno(r
, "Failed to parse --timeout= parameter '%s': %m", optarg
);
2480 case ARG_AUGMENT_CREDS
:
2481 r
= parse_boolean(optarg
);
2483 return log_error_errno(r
, "Failed to parse --augment-creds= parameter '%s': %m", optarg
);
2485 arg_augment_creds
= r
;
2488 case ARG_WATCH_BIND
:
2489 r
= parse_boolean(optarg
);
2491 return log_error_errno(r
, "Failed to parse --watch-bind= parameter '%s': %m", optarg
);
2498 arg_json
= JSON_PRETTY
;
2500 arg_json
= JSON_SHORT
;
2504 if (streq(optarg
, "short"))
2505 arg_json
= JSON_SHORT
;
2506 else if (streq(optarg
, "pretty"))
2507 arg_json
= JSON_PRETTY
;
2508 else if (streq(optarg
, "help")) {
2510 "pretty\n", stdout
);
2513 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2514 "Unknown JSON out mode: %s",
2519 case ARG_DESTINATION
:
2520 arg_destination
= optarg
;
2527 assert_not_reached("Unhandled option");
2533 static int busctl_main(int argc
, char *argv
[]) {
2535 static const Verb verbs
[] = {
2536 { "list", VERB_ANY
, 1, VERB_DEFAULT
, list_bus_names
},
2537 { "status", VERB_ANY
, 2, 0, status
},
2538 { "monitor", VERB_ANY
, VERB_ANY
, 0, verb_monitor
},
2539 { "capture", VERB_ANY
, VERB_ANY
, 0, verb_capture
},
2540 { "tree", VERB_ANY
, VERB_ANY
, 0, tree
},
2541 { "introspect", 3, 4, 0, introspect
},
2542 { "call", 5, VERB_ANY
, 0, call
},
2543 { "emit", 4, VERB_ANY
, 0, emit_signal
},
2544 { "get-property", 5, VERB_ANY
, 0, get_property
},
2545 { "set-property", 6, VERB_ANY
, 0, set_property
},
2546 { "help", VERB_ANY
, VERB_ANY
, 0, verb_help
},
2550 return dispatch_verb(argc
, argv
, verbs
, NULL
);
2553 static int run(int argc
, char *argv
[]) {
2556 log_show_color(true);
2557 log_parse_environment();
2560 r
= parse_argv(argc
, argv
);
2564 return busctl_main(argc
, argv
);
2567 DEFINE_MAIN_FUNCTION(run
);