1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
10 #include "bus-internal.h"
11 #include "bus-message.h"
12 #include "bus-signature.h"
15 #include "busctl-introspect.h"
19 #include "format-table.h"
20 #include "glyph-util.h"
23 #include "main-func.h"
26 #include "parse-argument.h"
27 #include "parse-util.h"
28 #include "path-util.h"
29 #include "pretty-print.h"
30 #include "runtime-scope.h"
32 #include "sort-util.h"
34 #include "terminal-util.h"
35 #include "user-util.h"
39 static JsonFormatFlags arg_json_format_flags
= JSON_FORMAT_OFF
;
40 static PagerFlags arg_pager_flags
= 0;
41 static bool arg_legend
= true;
42 static int arg_full
= -1;
43 static const char *arg_address
= NULL
;
44 static bool arg_unique
= false;
45 static bool arg_acquired
= false;
46 static bool arg_activatable
= false;
47 static bool arg_show_machine
= false;
48 static char **arg_matches
= NULL
;
49 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
50 static const char *arg_host
= NULL
;
51 static RuntimeScope arg_runtime_scope
= RUNTIME_SCOPE_SYSTEM
;
52 static size_t arg_snaplen
= 4096;
53 static bool arg_list
= false;
54 static bool arg_quiet
= false;
55 static bool arg_verbose
= false;
56 static bool arg_xml_interface
= false;
57 static bool arg_expect_reply
= true;
58 static bool arg_auto_start
= true;
59 static bool arg_allow_interactive_authorization
= true;
60 static bool arg_augment_creds
= true;
61 static bool arg_watch_bind
= false;
62 static usec_t arg_timeout
= 0;
63 static const char *arg_destination
= NULL
;
65 STATIC_DESTRUCTOR_REGISTER(arg_matches
, strv_freep
);
67 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
68 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
70 static int json_transform_message(sd_bus_message
*m
, JsonVariant
**ret
);
72 static int acquire_bus(bool set_monitor
, sd_bus
**ret
) {
73 _cleanup_(sd_bus_close_unrefp
) sd_bus
*bus
= NULL
;
78 return log_error_errno(r
, "Failed to allocate bus: %m");
81 r
= sd_bus_set_monitor(bus
, true);
83 return log_error_errno(r
, "Failed to set monitor mode: %m");
85 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
87 return log_error_errno(r
, "Failed to enable credentials: %m");
89 r
= sd_bus_negotiate_timestamp(bus
, true);
91 return log_error_errno(r
, "Failed to enable timestamps: %m");
93 r
= sd_bus_negotiate_fds(bus
, true);
95 return log_error_errno(r
, "Failed to enable fds: %m");
98 r
= sd_bus_set_bus_client(bus
, true);
100 return log_error_errno(r
, "Failed to set bus client: %m");
102 r
= sd_bus_set_watch_bind(bus
, arg_watch_bind
);
104 return log_error_errno(r
, "Failed to set watch-bind setting to '%s': %m",
105 yes_no(arg_watch_bind
));
108 r
= sd_bus_set_address(bus
, arg_address
);
110 switch (arg_transport
) {
112 case BUS_TRANSPORT_LOCAL
:
114 switch (arg_runtime_scope
) {
116 case RUNTIME_SCOPE_USER
:
117 r
= bus_set_address_user(bus
);
120 case RUNTIME_SCOPE_SYSTEM
:
121 r
= bus_set_address_system(bus
);
125 assert_not_reached();
130 case BUS_TRANSPORT_REMOTE
:
131 r
= bus_set_address_system_remote(bus
, arg_host
);
134 case BUS_TRANSPORT_MACHINE
:
135 r
= bus_set_address_machine(bus
, arg_runtime_scope
, arg_host
);
139 assert_not_reached();
143 return bus_log_address_error(r
, arg_transport
);
145 r
= sd_bus_start(bus
);
147 return bus_log_connect_error(r
, arg_transport
);
149 *ret
= TAKE_PTR(bus
);
154 static int list_bus_names(int argc
, char **argv
, void *userdata
) {
155 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
156 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
157 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
158 _cleanup_(table_unrefp
) Table
*table
= NULL
;
176 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
177 arg_unique
= arg_acquired
= arg_activatable
= true;
179 r
= acquire_bus(false, &bus
);
183 r
= sd_bus_list_names(bus
,
184 (arg_acquired
|| arg_unique
) ? &acquired
: NULL
,
185 arg_activatable
? &activatable
: NULL
);
187 return log_error_errno(r
, "Failed to list names: %m");
189 names
= hashmap_new(&string_hash_ops
);
193 STRV_FOREACH(i
, acquired
) {
194 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
196 return log_error_errno(r
, "Failed to add to hashmap: %m");
199 STRV_FOREACH(i
, activatable
) {
200 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
201 if (r
< 0 && r
!= -EEXIST
)
202 return log_error_errno(r
, "Failed to add to hashmap: %m");
205 table
= table_new("activatable",
219 table_set_width(table
, 0);
221 r
= table_set_align_percent(table
, table_get_cell(table
, 0, COLUMN_PID
), 100);
223 return log_error_errno(r
, "Failed to set alignment: %m");
225 table_set_ersatz_string(table
, TABLE_ERSATZ_DASH
);
227 r
= table_set_sort(table
, (size_t) COLUMN_NAME
);
229 return log_error_errno(r
, "Failed to set sort column: %m");
231 if (arg_show_machine
)
232 r
= table_set_display(table
, (size_t) COLUMN_NAME
,
234 (size_t) COLUMN_PROCESS
,
235 (size_t) COLUMN_USER
,
236 (size_t) COLUMN_CONNECTION
,
237 (size_t) COLUMN_UNIT
,
238 (size_t) COLUMN_SESSION
,
239 (size_t) COLUMN_DESCRIPTION
,
240 (size_t) COLUMN_MACHINE
);
242 r
= table_set_display(table
, (size_t) COLUMN_NAME
,
244 (size_t) COLUMN_PROCESS
,
245 (size_t) COLUMN_USER
,
246 (size_t) COLUMN_CONNECTION
,
247 (size_t) COLUMN_UNIT
,
248 (size_t) COLUMN_SESSION
,
249 (size_t) COLUMN_DESCRIPTION
);
252 return log_error_errno(r
, "Failed to set columns to display: %m");
254 HASHMAP_FOREACH_KEY(v
, k
, names
) {
255 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
257 if (v
== NAME_IS_ACTIVATABLE
) {
260 TABLE_INT
, PTR_TO_INT(v
),
265 TABLE_STRING
, "(activatable)", TABLE_SET_COLOR
, ansi_grey(),
271 return table_log_add_error(r
);
276 assert(v
== NAME_IS_ACQUIRED
);
278 if (!arg_unique
&& k
[0] == ':')
281 if (!arg_acquired
&& k
[0] != ':')
284 r
= table_add_many(table
,
285 TABLE_INT
, PTR_TO_INT(v
),
288 return table_log_add_error(r
);
290 r
= sd_bus_get_name_creds(
292 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
293 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
294 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
295 SD_BUS_CREDS_DESCRIPTION
, &creds
);
297 log_debug_errno(r
, "Failed to acquire credentials of service %s, ignoring: %m", k
);
299 r
= table_fill_empty(table
, COLUMN_MACHINE
);
301 const char *unique
= NULL
, *session
= NULL
, *unit
= NULL
, *cn
= NULL
;
305 r
= sd_bus_creds_get_pid(creds
, &pid
);
307 const char *comm
= NULL
;
309 (void) sd_bus_creds_get_comm(creds
, &comm
);
311 r
= table_add_many(table
,
313 TABLE_STRING
, strna(comm
));
315 r
= table_add_many(table
, TABLE_EMPTY
, TABLE_EMPTY
);
317 return table_log_add_error(r
);
319 r
= sd_bus_creds_get_euid(creds
, &uid
);
321 _cleanup_free_
char *u
= NULL
;
323 u
= uid_to_name(uid
);
327 r
= table_add_cell(table
, NULL
, TABLE_STRING
, u
);
329 r
= table_add_cell(table
, NULL
, TABLE_EMPTY
, NULL
);
331 return table_log_add_error(r
);
333 (void) sd_bus_creds_get_unique_name(creds
, &unique
);
334 (void) sd_bus_creds_get_unit(creds
, &unit
);
335 (void) sd_bus_creds_get_session(creds
, &session
);
336 (void) sd_bus_creds_get_description(creds
, &cn
);
340 TABLE_STRING
, unique
,
342 TABLE_STRING
, session
,
346 return table_log_add_error(r
);
348 if (arg_show_machine
) {
351 r
= sd_bus_get_name_machine_id(bus
, k
, &mid
);
353 log_debug_errno(r
, "Failed to acquire credentials of service %s, ignoring: %m", k
);
355 r
= table_add_cell(table
, NULL
, TABLE_ID128
, &mid
);
357 return table_log_add_error(r
);
359 continue; /* line fully filled, no need to fill the remainder below */
363 r
= table_fill_empty(table
, 0);
365 return log_error_errno(r
, "Failed to fill line: %m");
368 return table_print_with_pager(table
, arg_json_format_flags
, arg_pager_flags
, arg_legend
);
371 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
372 /* We assume the list is sorted. Let's first skip over the
373 * entry we are looking at. */
378 if (!streq(*l
, path
))
385 *vertical
= strjoina(prefix
, special_glyph(SPECIAL_GLYPH_TREE_VERTICAL
)),
386 *space
= strjoina(prefix
, special_glyph(SPECIAL_GLYPH_TREE_SPACE
));
389 bool has_more
= false;
392 if (!*l
|| !path_startswith(*l
, path
))
397 if (!*n
|| !path_startswith(*n
, path
))
400 if (!path_startswith(*n
, *l
)) {
410 special_glyph(has_more
? SPECIAL_GLYPH_TREE_BRANCH
: SPECIAL_GLYPH_TREE_RIGHT
),
413 print_subtree(has_more
? vertical
: space
, *l
, l
);
418 static void print_tree(char **l
) {
421 else if (strv_isempty(l
))
422 printf("No objects discovered.\n");
423 else if (streq(l
[0], "/") && !l
[1])
424 printf("Only root object discovered.\n");
426 print_subtree("", "/", l
);
429 static int on_path(const char *path
, void *userdata
) {
430 Set
*paths
= ASSERT_PTR(userdata
);
433 r
= set_put_strdup(&paths
, path
);
440 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
) {
441 static const XMLIntrospectOps ops
= {
445 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
446 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
450 r
= sd_bus_call_method(bus
, service
, path
,
451 "org.freedesktop.DBus.Introspectable", "Introspect",
452 &error
, &reply
, NULL
);
454 printf("%sFailed to introspect object %s of service %s: %s%s\n",
455 ansi_highlight_red(),
456 path
, service
, bus_error_message(&error
, r
),
461 r
= sd_bus_message_read(reply
, "s", &xml
);
463 return bus_log_parse_error(r
);
465 return parse_xml_introspect(path
, xml
, &ops
, paths
);
468 static int tree_one(sd_bus
*bus
, const char *service
) {
469 _cleanup_set_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
470 _cleanup_free_
char **l
= NULL
;
473 r
= set_put_strdup(&paths
, "/");
478 _cleanup_free_
char *p
= NULL
;
481 p
= set_steal_first(paths
);
485 if (set_contains(done
, p
) ||
486 set_contains(failed
, p
))
489 q
= find_nodes(bus
, service
, p
, paths
);
493 q
= set_ensure_consume(q
< 0 ? &failed
: &done
, &string_hash_ops_free
, TAKE_PTR(p
));
499 pager_open(arg_pager_flags
);
501 l
= set_get_strv(done
);
513 static int tree(int argc
, char **argv
, void *userdata
) {
514 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
517 /* Do superficial verification of arguments before even opening the bus */
518 STRV_FOREACH(i
, strv_skip(argv
, 1))
519 if (!sd_bus_service_name_is_valid(*i
))
520 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
521 "Invalid bus service name: %s", *i
);
523 if (!arg_unique
&& !arg_acquired
)
526 r
= acquire_bus(false, &bus
);
531 _cleanup_strv_free_
char **names
= NULL
;
532 bool not_first
= false;
534 r
= sd_bus_list_names(bus
, &names
, NULL
);
536 return log_error_errno(r
, "Failed to get name list: %m");
538 pager_open(arg_pager_flags
);
540 STRV_FOREACH(i
, names
) {
543 if (!arg_unique
&& (*i
)[0] == ':')
546 if (!arg_acquired
&& (*i
)[0] == ':')
552 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
554 q
= tree_one(bus
, *i
);
561 STRV_FOREACH(i
, strv_skip(argv
, 1)) {
568 pager_open(arg_pager_flags
);
569 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
572 q
= tree_one(bus
, *i
);
580 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
584 const char *contents
= NULL
;
599 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
605 if (bus_type_is_container(type
) > 0) {
607 r
= sd_bus_message_enter_container(m
, type
, contents
);
611 if (type
== SD_BUS_TYPE_ARRAY
) {
614 /* count array entries */
617 r
= sd_bus_message_skip(m
, contents
);
626 r
= sd_bus_message_rewind(m
, false);
636 } else if (type
== SD_BUS_TYPE_VARIANT
) {
641 fprintf(f
, "%s", contents
);
645 r
= format_cmdline(m
, f
, needs_space
);
651 r
= sd_bus_message_exit_container(m
);
658 r
= sd_bus_message_read_basic(m
, type
, &basic
);
666 case SD_BUS_TYPE_BYTE
:
667 fprintf(f
, "%u", basic
.u8
);
670 case SD_BUS_TYPE_BOOLEAN
:
671 fputs(true_false(basic
.i
), f
);
674 case SD_BUS_TYPE_INT16
:
675 fprintf(f
, "%i", basic
.s16
);
678 case SD_BUS_TYPE_UINT16
:
679 fprintf(f
, "%u", basic
.u16
);
682 case SD_BUS_TYPE_INT32
:
683 fprintf(f
, "%i", basic
.s32
);
686 case SD_BUS_TYPE_UINT32
:
687 fprintf(f
, "%u", basic
.u32
);
690 case SD_BUS_TYPE_INT64
:
691 fprintf(f
, "%" PRIi64
, basic
.s64
);
694 case SD_BUS_TYPE_UINT64
:
695 fprintf(f
, "%" PRIu64
, basic
.u64
);
698 case SD_BUS_TYPE_DOUBLE
:
699 fprintf(f
, "%g", basic
.d64
);
702 case SD_BUS_TYPE_STRING
:
703 case SD_BUS_TYPE_OBJECT_PATH
:
704 case SD_BUS_TYPE_SIGNATURE
: {
705 _cleanup_free_
char *b
= NULL
;
707 b
= cescape(basic
.string
);
711 fprintf(f
, "\"%s\"", b
);
715 case SD_BUS_TYPE_UNIX_FD
:
716 fprintf(f
, "%i", basic
.i
);
720 assert_not_reached();
727 typedef struct Member
{
738 static void member_hash_func(const Member
*m
, struct siphash
*state
) {
744 string_hash_func(m
->type
, state
);
746 arity
+= !!m
->name
+ !!m
->interface
;
748 uint64_hash_func(&arity
, state
);
751 string_hash_func(m
->name
, state
);
754 string_hash_func(m
->signature
, state
);
757 string_hash_func(m
->interface
, state
);
760 static int member_compare_func(const Member
*x
, const Member
*y
) {
768 d
= strcmp_ptr(x
->interface
, y
->interface
);
772 d
= strcmp(x
->type
, y
->type
);
776 d
= strcmp_ptr(x
->name
, y
->name
);
780 return strcmp_ptr(x
->signature
, y
->signature
);
783 static int member_compare_funcp(Member
* const *a
, Member
* const *b
) {
784 return member_compare_func(*a
, *b
);
787 static Member
* member_free(Member
*m
) {
798 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
800 static Set
* member_set_free(Set
*s
) {
801 return set_free_with_destructor(s
, member_free
);
803 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
805 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
806 _cleanup_(member_freep
) Member
*m
= NULL
;
807 Set
*members
= ASSERT_PTR(userdata
);
821 r
= free_and_strdup(&m
->interface
, interface
);
825 r
= set_put(members
, m
);
827 return log_error_errno(SYNTHETIC_ERRNO(EEXIST
),
828 "Invalid introspection data: duplicate interface '%s'.", interface
);
836 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
837 _cleanup_(member_freep
) Member
*m
= NULL
;
838 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
= free_and_strdup(&m
->result
, result
);
869 r
= set_put(members
, m
);
871 return log_error_errno(SYNTHETIC_ERRNO(EEXIST
),
872 "Invalid introspection data: duplicate method '%s' on interface '%s'.", name
, interface
);
880 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
881 _cleanup_(member_freep
) Member
*m
= NULL
;
882 Set
*members
= userdata
;
897 r
= free_and_strdup(&m
->interface
, interface
);
901 r
= free_and_strdup(&m
->name
, name
);
905 r
= free_and_strdup(&m
->signature
, signature
);
909 r
= set_put(members
, m
);
911 return log_error_errno(SYNTHETIC_ERRNO(EEXIST
),
912 "Invalid introspection data: duplicate signal '%s' on interface '%s'.", name
, interface
);
920 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
921 _cleanup_(member_freep
) Member
*m
= NULL
;
922 Set
*members
= userdata
;
935 .writable
= writable
,
938 r
= free_and_strdup(&m
->interface
, interface
);
942 r
= free_and_strdup(&m
->name
, name
);
946 r
= free_and_strdup(&m
->signature
, signature
);
950 r
= set_put(members
, m
);
952 return log_error_errno(SYNTHETIC_ERRNO(EEXIST
),
953 "Invalid introspection data: duplicate property '%s' on interface '%s'.", name
, interface
);
961 DEFINE_PRIVATE_HASH_OPS(member_hash_ops
, Member
, member_hash_func
, member_compare_func
);
963 static int introspect(int argc
, char **argv
, void *userdata
) {
964 static const XMLIntrospectOps ops
= {
965 .on_interface
= on_interface
,
966 .on_method
= on_method
,
967 .on_signal
= on_signal
,
968 .on_property
= on_property
,
971 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
972 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply_xml
= NULL
;
973 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
974 _cleanup_(member_set_freep
) Set
*members
= NULL
;
975 unsigned name_width
, type_width
, signature_width
, result_width
;
980 r
= acquire_bus(false, &bus
);
984 members
= set_new(&member_hash_ops
);
988 r
= sd_bus_call_method(bus
, argv
[1], argv
[2],
989 "org.freedesktop.DBus.Introspectable", "Introspect",
990 &error
, &reply_xml
, NULL
);
992 return log_error_errno(r
, "Failed to introspect object %s of service %s: %s",
993 argv
[2], argv
[1], bus_error_message(&error
, r
));
995 r
= sd_bus_message_read(reply_xml
, "s", &xml
);
997 return bus_log_parse_error(r
);
999 if (arg_xml_interface
) {
1000 /* Just dump the received XML and finish */
1001 pager_open(arg_pager_flags
);
1006 /* First, get list of all properties */
1007 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
1011 /* Second, find the current values for them */
1012 SET_FOREACH(m
, members
) {
1013 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1015 if (!streq(m
->type
, "property"))
1021 if (argv
[3] && !streq(argv
[3], m
->interface
))
1024 r
= sd_bus_call_method(bus
, argv
[1], argv
[2],
1025 "org.freedesktop.DBus.Properties", "GetAll",
1026 &error
, &reply
, "s", m
->interface
);
1028 return log_error_errno(r
, "Failed to get all properties on interface %s: %s",
1029 m
->interface
, bus_error_message(&error
, r
));
1031 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
1033 return bus_log_parse_error(r
);
1036 _cleanup_fclose_
FILE *mf
= NULL
;
1037 _cleanup_free_
char *buf
= NULL
;
1038 const char *name
, *contents
;
1043 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
1045 return bus_log_parse_error(r
);
1049 r
= sd_bus_message_read(reply
, "s", &name
);
1051 return bus_log_parse_error(r
);
1053 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1055 return bus_log_parse_error(r
);
1057 return bus_log_parse_error(EINVAL
);
1059 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1061 return bus_log_parse_error(r
);
1063 mf
= open_memstream_unlocked(&buf
, &sz
);
1067 r
= format_cmdline(reply
, mf
, false);
1069 return bus_log_parse_error(r
);
1071 mf
= safe_fclose(mf
);
1073 z
= set_get(members
, &((Member
) {
1075 .interface
= m
->interface
,
1076 .signature
= (char*) contents
,
1077 .name
= (char*) name
}));
1079 free_and_replace(z
->value
, buf
);
1081 r
= sd_bus_message_exit_container(reply
);
1083 return bus_log_parse_error(r
);
1085 r
= sd_bus_message_exit_container(reply
);
1087 return bus_log_parse_error(r
);
1090 r
= sd_bus_message_exit_container(reply
);
1092 return bus_log_parse_error(r
);
1095 name_width
= strlen("NAME");
1096 type_width
= strlen("TYPE");
1097 signature_width
= strlen("SIGNATURE");
1098 result_width
= strlen("RESULT/VALUE");
1100 Member
**sorted
= newa(Member
*, set_size(members
));
1103 SET_FOREACH(m
, members
) {
1104 if (argv
[3] && !streq(argv
[3], m
->interface
))
1108 name_width
= MAX(name_width
, strlen(m
->interface
));
1110 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1112 type_width
= MAX(type_width
, strlen(m
->type
));
1114 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1116 result_width
= MAX(result_width
, strlen(m
->result
));
1118 result_width
= MAX(result_width
, strlen(m
->value
));
1123 if (result_width
> 40 && arg_full
<= 0)
1126 typesafe_qsort(sorted
, k
, member_compare_funcp
);
1128 pager_open(arg_pager_flags
);
1131 printf("%-*s %-*s %-*s %-*s %s\n",
1132 (int) name_width
, "NAME",
1133 (int) type_width
, "TYPE",
1134 (int) signature_width
, "SIGNATURE",
1135 (int) result_width
, "RESULT/VALUE",
1138 for (size_t j
= 0; j
< k
; j
++) {
1139 _cleanup_free_
char *ellipsized
= NULL
;
1145 if (argv
[3] && !streq(argv
[3], m
->interface
))
1148 is_interface
= streq(m
->type
, "interface");
1150 if (argv
[3] && is_interface
)
1154 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1160 rv
= empty_to_dash(m
->result
);
1162 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1163 is_interface
? ansi_highlight() : "",
1164 is_interface
? "" : ".",
1165 - !is_interface
+ (int) name_width
,
1166 empty_to_dash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1167 is_interface
? ansi_normal() : "",
1168 (int) type_width
, empty_to_dash(m
->type
),
1169 (int) signature_width
, empty_to_dash(m
->signature
),
1170 (int) result_width
, rv
,
1171 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1172 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1173 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1174 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1175 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1176 m
->writable
? " writable" : "");
1182 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1183 return sd_bus_message_dump(m
, f
, SD_BUS_MESSAGE_DUMP_WITH_HEADER
);
1186 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1187 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1190 static int message_json(sd_bus_message
*m
, FILE *f
) {
1191 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
, *w
= NULL
;
1196 r
= json_transform_message(m
, &v
);
1200 e
[0] = m
->header
->endian
;
1205 ts
= now(CLOCK_REALTIME
);
1207 r
= json_build(&w
, JSON_BUILD_OBJECT(
1208 JSON_BUILD_PAIR("type", JSON_BUILD_STRING(bus_message_type_to_string(m
->header
->type
))),
1209 JSON_BUILD_PAIR("endian", JSON_BUILD_STRING(e
)),
1210 JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(m
->header
->flags
)),
1211 JSON_BUILD_PAIR("version", JSON_BUILD_INTEGER(m
->header
->version
)),
1212 JSON_BUILD_PAIR("cookie", JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m
))),
1213 JSON_BUILD_PAIR_CONDITION(m
->reply_cookie
!= 0, "reply_cookie", JSON_BUILD_INTEGER(m
->reply_cookie
)),
1214 JSON_BUILD_PAIR("timestamp-realtime", JSON_BUILD_UNSIGNED(ts
)),
1215 JSON_BUILD_PAIR_CONDITION(m
->sender
, "sender", JSON_BUILD_STRING(m
->sender
)),
1216 JSON_BUILD_PAIR_CONDITION(m
->destination
, "destination", JSON_BUILD_STRING(m
->destination
)),
1217 JSON_BUILD_PAIR_CONDITION(m
->path
, "path", JSON_BUILD_STRING(m
->path
)),
1218 JSON_BUILD_PAIR_CONDITION(m
->interface
, "interface", JSON_BUILD_STRING(m
->interface
)),
1219 JSON_BUILD_PAIR_CONDITION(m
->member
, "member", JSON_BUILD_STRING(m
->member
)),
1220 JSON_BUILD_PAIR_CONDITION(m
->monotonic
!= 0, "monotonic", JSON_BUILD_INTEGER(m
->monotonic
)),
1221 JSON_BUILD_PAIR_CONDITION(m
->realtime
!= 0, "realtime", JSON_BUILD_INTEGER(m
->realtime
)),
1222 JSON_BUILD_PAIR_CONDITION(m
->seqnum
!= 0, "seqnum", JSON_BUILD_INTEGER(m
->seqnum
)),
1223 JSON_BUILD_PAIR_CONDITION(m
->error
.name
, "error_name", JSON_BUILD_STRING(m
->error
.name
)),
1224 JSON_BUILD_PAIR("payload", JSON_BUILD_VARIANT(v
))));
1226 return log_error_errno(r
, "Failed to build JSON object: %m");
1228 json_variant_dump(w
, arg_json_format_flags
, f
, NULL
);
1232 static int monitor(int argc
, char **argv
, int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1233 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1234 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*message
= NULL
;
1235 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1237 const char *unique_name
;
1238 bool is_monitor
= false;
1241 r
= acquire_bus(true, &bus
);
1245 /* upgrade connection; it's not used for anything else after this call */
1246 r
= sd_bus_message_new_method_call(bus
,
1248 "org.freedesktop.DBus",
1249 "/org/freedesktop/DBus",
1250 "org.freedesktop.DBus.Monitoring",
1253 return bus_log_create_error(r
);
1255 r
= sd_bus_message_open_container(message
, 'a', "s");
1257 return bus_log_create_error(r
);
1259 STRV_FOREACH(i
, argv
+1) {
1260 _cleanup_free_
char *m
= NULL
;
1262 if (!sd_bus_service_name_is_valid(*i
))
1263 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid service name '%s'", *i
);
1265 m
= strjoin("sender='", *i
, "'");
1269 r
= sd_bus_message_append_basic(message
, 's', m
);
1271 return bus_log_create_error(r
);
1274 m
= strjoin("destination='", *i
, "'");
1278 r
= sd_bus_message_append_basic(message
, 's', m
);
1280 return bus_log_create_error(r
);
1283 STRV_FOREACH(i
, arg_matches
) {
1284 r
= sd_bus_message_append_basic(message
, 's', *i
);
1286 return bus_log_create_error(r
);
1289 r
= sd_bus_message_close_container(message
);
1291 return bus_log_create_error(r
);
1293 r
= sd_bus_message_append_basic(message
, 'u', &flags
);
1295 return bus_log_create_error(r
);
1297 r
= sd_bus_call(bus
, message
, arg_timeout
, &error
, NULL
);
1299 return log_error_errno(r
, "Call to org.freedesktop.DBus.Monitoring.BecomeMonitor failed: %s",
1300 bus_error_message(&error
, r
));
1302 r
= sd_bus_get_unique_name(bus
, &unique_name
);
1304 return log_error_errno(r
, "Failed to get unique name: %m");
1306 log_info("Monitoring bus message stream.");
1309 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1311 r
= sd_bus_process(bus
, &m
);
1313 return log_error_errno(r
, "Failed to process bus: %m");
1318 /* wait until we lose our unique name */
1319 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus", "NameLost") <= 0)
1322 r
= sd_bus_message_read(m
, "s", &name
);
1324 return bus_log_parse_error(r
);
1326 if (streq(name
, unique_name
))
1336 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1337 log_info("Connection terminated, exiting.");
1347 r
= sd_bus_wait(bus
, UINT64_MAX
);
1349 return log_error_errno(r
, "Failed to wait for bus: %m");
1353 static int verb_monitor(int argc
, char **argv
, void *userdata
) {
1354 return monitor(argc
, argv
, (arg_json_format_flags
& JSON_FORMAT_OFF
) ? message_dump
: message_json
);
1357 static int verb_capture(int argc
, char **argv
, void *userdata
) {
1358 _cleanup_free_
char *osname
= NULL
;
1359 static const char info
[] =
1360 "busctl (systemd) " STRINGIFY(PROJECT_VERSION
) " (Git " GIT_VERSION
")";
1363 if (isatty(fileno(stdout
)) > 0)
1364 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1365 "Refusing to write message data to console, please redirect output to a file.");
1367 r
= parse_os_release(NULL
, "PRETTY_NAME", &osname
);
1369 log_full_errno(r
== -ENOENT
? LOG_DEBUG
: LOG_INFO
, r
,
1370 "Failed to read os-release file, ignoring: %m");
1371 bus_pcap_header(arg_snaplen
, osname
, info
, stdout
);
1373 r
= monitor(argc
, argv
, message_pcap
);
1377 r
= fflush_and_check(stdout
);
1379 return log_error_errno(r
, "Couldn't write capture file: %m");
1384 static int status(int argc
, char **argv
, void *userdata
) {
1385 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1386 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
1390 r
= acquire_bus(false, &bus
);
1394 pager_open(arg_pager_flags
);
1396 if (!isempty(argv
[1])) {
1397 r
= parse_pid(argv
[1], &pid
);
1399 r
= sd_bus_get_name_creds(
1402 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1405 r
= sd_bus_creds_new_from_pid(
1410 const char *scope
, *address
;
1413 r
= sd_bus_get_address(bus
, &address
);
1415 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1417 r
= sd_bus_get_scope(bus
, &scope
);
1419 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1421 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1423 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n",
1424 ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1426 r
= sd_bus_get_owner_creds(
1428 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1433 return log_error_errno(r
, "Failed to get credentials: %m");
1435 bus_creds_dump(creds
, NULL
, false);
1439 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1459 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1460 "Too few parameters for signature.");
1467 case SD_BUS_TYPE_BOOLEAN
:
1469 r
= parse_boolean(v
);
1471 return log_error_errno(r
, "Failed to parse '%s' as boolean: %m", v
);
1473 r
= sd_bus_message_append_basic(m
, t
, &r
);
1476 case SD_BUS_TYPE_BYTE
: {
1479 r
= safe_atou8(v
, &z
);
1481 return log_error_errno(r
, "Failed to parse '%s' as byte (unsigned 8bit integer): %m", v
);
1483 r
= sd_bus_message_append_basic(m
, t
, &z
);
1487 case SD_BUS_TYPE_INT16
: {
1490 r
= safe_atoi16(v
, &z
);
1492 return log_error_errno(r
, "Failed to parse '%s' as signed 16bit integer: %m", v
);
1494 r
= sd_bus_message_append_basic(m
, t
, &z
);
1498 case SD_BUS_TYPE_UINT16
: {
1501 r
= safe_atou16(v
, &z
);
1503 return log_error_errno(r
, "Failed to parse '%s' as unsigned 16bit integer: %m", v
);
1505 r
= sd_bus_message_append_basic(m
, t
, &z
);
1509 case SD_BUS_TYPE_INT32
: {
1512 r
= safe_atoi32(v
, &z
);
1514 return log_error_errno(r
, "Failed to parse '%s' as signed 32bit integer: %m", v
);
1516 r
= sd_bus_message_append_basic(m
, t
, &z
);
1520 case SD_BUS_TYPE_UINT32
: {
1523 r
= safe_atou32(v
, &z
);
1525 return log_error_errno(r
, "Failed to parse '%s' as unsigned 32bit integer: %m", v
);
1527 r
= sd_bus_message_append_basic(m
, t
, &z
);
1531 case SD_BUS_TYPE_INT64
: {
1534 r
= safe_atoi64(v
, &z
);
1536 return log_error_errno(r
, "Failed to parse '%s' as signed 64bit integer: %m", v
);
1538 r
= sd_bus_message_append_basic(m
, t
, &z
);
1542 case SD_BUS_TYPE_UINT64
: {
1545 r
= safe_atou64(v
, &z
);
1547 return log_error_errno(r
, "Failed to parse '%s' as unsigned 64bit integer: %m", v
);
1549 r
= sd_bus_message_append_basic(m
, t
, &z
);
1553 case SD_BUS_TYPE_DOUBLE
: {
1556 r
= safe_atod(v
, &z
);
1558 return log_error_errno(r
, "Failed to parse '%s' as double precision floating point: %m", v
);
1560 r
= sd_bus_message_append_basic(m
, t
, &z
);
1564 case SD_BUS_TYPE_STRING
:
1565 case SD_BUS_TYPE_OBJECT_PATH
:
1566 case SD_BUS_TYPE_SIGNATURE
:
1568 r
= sd_bus_message_append_basic(m
, t
, v
);
1571 case SD_BUS_TYPE_ARRAY
: {
1575 r
= safe_atou32(v
, &n
);
1577 return log_error_errno(r
, "Failed to parse '%s' number of array entries: %m", v
);
1579 r
= signature_element_length(signature
, &k
);
1581 return log_error_errno(r
, "Invalid array signature: %m");
1585 memcpy(s
, signature
, k
);
1588 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1590 return bus_log_create_error(r
);
1592 for (unsigned i
= 0; i
< n
; i
++) {
1593 r
= message_append_cmdline(m
, s
, &p
);
1601 r
= sd_bus_message_close_container(m
);
1605 case SD_BUS_TYPE_VARIANT
:
1606 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1608 return bus_log_create_error(r
);
1610 r
= message_append_cmdline(m
, v
, &p
);
1614 r
= sd_bus_message_close_container(m
);
1617 case SD_BUS_TYPE_STRUCT_BEGIN
:
1618 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1624 r
= signature_element_length(signature
, &k
);
1626 return log_error_errno(r
, "Invalid struct/dict entry signature: %m");
1630 memcpy(s
, signature
+ 1, k
- 2);
1633 const char ctype
= t
== SD_BUS_TYPE_STRUCT_BEGIN
?
1634 SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
;
1635 r
= sd_bus_message_open_container(m
, ctype
, s
);
1637 return bus_log_create_error(r
);
1639 r
= message_append_cmdline(m
, s
, &p
);
1646 r
= sd_bus_message_close_container(m
);
1650 case SD_BUS_TYPE_UNIX_FD
:
1651 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1652 "UNIX file descriptor not supported as type.");
1655 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1656 "Unknown signature type %c.", t
);
1660 return bus_log_create_error(r
);
1667 static int json_transform_one(sd_bus_message
*m
, JsonVariant
**ret
);
1669 static int json_transform_array_or_struct(sd_bus_message
*m
, JsonVariant
**ret
) {
1670 JsonVariant
**elements
= NULL
;
1671 size_t n_elements
= 0;
1678 r
= sd_bus_message_at_end(m
, false);
1680 bus_log_parse_error(r
);
1686 if (!GREEDY_REALLOC(elements
, n_elements
+ 1)) {
1691 r
= json_transform_one(m
, elements
+ n_elements
);
1698 r
= json_variant_new_array(ret
, elements
, n_elements
);
1701 json_variant_unref_many(elements
, n_elements
);
1707 static int json_transform_variant(sd_bus_message
*m
, const char *contents
, JsonVariant
**ret
) {
1708 _cleanup_(json_variant_unrefp
) JsonVariant
*value
= NULL
;
1715 r
= json_transform_one(m
, &value
);
1719 r
= json_build(ret
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(contents
)),
1720 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(value
))));
1727 static int json_transform_dict_array(sd_bus_message
*m
, JsonVariant
**ret
) {
1728 JsonVariant
**elements
= NULL
;
1729 size_t n_elements
= 0;
1736 const char *contents
;
1739 r
= sd_bus_message_at_end(m
, false);
1741 bus_log_parse_error(r
);
1747 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
1751 assert(type
== 'e');
1753 if (!GREEDY_REALLOC(elements
, n_elements
+ 2)) {
1758 r
= sd_bus_message_enter_container(m
, type
, contents
);
1760 bus_log_parse_error(r
);
1764 r
= json_transform_one(m
, elements
+ n_elements
);
1770 r
= json_transform_one(m
, elements
+ n_elements
);
1776 r
= sd_bus_message_exit_container(m
);
1778 bus_log_parse_error(r
);
1783 r
= json_variant_new_object(ret
, elements
, n_elements
);
1786 json_variant_unref_many(elements
, n_elements
);
1792 static int json_transform_one(sd_bus_message
*m
, JsonVariant
**ret
) {
1793 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1794 const char *contents
;
1801 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
1803 return bus_log_parse_error(r
);
1807 case SD_BUS_TYPE_BYTE
: {
1810 r
= sd_bus_message_read_basic(m
, type
, &b
);
1812 return bus_log_parse_error(r
);
1814 r
= json_variant_new_unsigned(&v
, b
);
1816 return log_error_errno(r
, "Failed to transform byte: %m");
1821 case SD_BUS_TYPE_BOOLEAN
: {
1824 r
= sd_bus_message_read_basic(m
, type
, &b
);
1826 return bus_log_parse_error(r
);
1828 r
= json_variant_new_boolean(&v
, b
);
1830 return log_error_errno(r
, "Failed to transform boolean: %m");
1835 case SD_BUS_TYPE_INT16
: {
1838 r
= sd_bus_message_read_basic(m
, type
, &b
);
1840 return bus_log_parse_error(r
);
1842 r
= json_variant_new_integer(&v
, b
);
1844 return log_error_errno(r
, "Failed to transform int16: %m");
1849 case SD_BUS_TYPE_UINT16
: {
1852 r
= sd_bus_message_read_basic(m
, type
, &b
);
1854 return bus_log_parse_error(r
);
1856 r
= json_variant_new_unsigned(&v
, b
);
1858 return log_error_errno(r
, "Failed to transform uint16: %m");
1863 case SD_BUS_TYPE_INT32
: {
1866 r
= sd_bus_message_read_basic(m
, type
, &b
);
1868 return bus_log_parse_error(r
);
1870 r
= json_variant_new_integer(&v
, b
);
1872 return log_error_errno(r
, "Failed to transform int32: %m");
1877 case SD_BUS_TYPE_UINT32
: {
1880 r
= sd_bus_message_read_basic(m
, type
, &b
);
1882 return bus_log_parse_error(r
);
1884 r
= json_variant_new_unsigned(&v
, b
);
1886 return log_error_errno(r
, "Failed to transform uint32: %m");
1891 case SD_BUS_TYPE_INT64
: {
1894 r
= sd_bus_message_read_basic(m
, type
, &b
);
1896 return bus_log_parse_error(r
);
1898 r
= json_variant_new_integer(&v
, b
);
1900 return log_error_errno(r
, "Failed to transform int64: %m");
1905 case SD_BUS_TYPE_UINT64
: {
1908 r
= sd_bus_message_read_basic(m
, type
, &b
);
1910 return bus_log_parse_error(r
);
1912 r
= json_variant_new_unsigned(&v
, b
);
1914 return log_error_errno(r
, "Failed to transform uint64: %m");
1919 case SD_BUS_TYPE_DOUBLE
: {
1922 r
= sd_bus_message_read_basic(m
, type
, &d
);
1924 return bus_log_parse_error(r
);
1926 r
= json_variant_new_real(&v
, d
);
1928 return log_error_errno(r
, "Failed to transform double: %m");
1933 case SD_BUS_TYPE_STRING
:
1934 case SD_BUS_TYPE_OBJECT_PATH
:
1935 case SD_BUS_TYPE_SIGNATURE
: {
1938 r
= sd_bus_message_read_basic(m
, type
, &s
);
1940 return bus_log_parse_error(r
);
1942 r
= json_variant_new_string(&v
, s
);
1944 return log_error_errno(r
, "Failed to transform double: %m");
1949 case SD_BUS_TYPE_UNIX_FD
:
1950 r
= sd_bus_message_read_basic(m
, type
, NULL
);
1952 return bus_log_parse_error(r
);
1954 r
= json_variant_new_null(&v
);
1956 return log_error_errno(r
, "Failed to transform fd: %m");
1960 case SD_BUS_TYPE_ARRAY
:
1961 case SD_BUS_TYPE_VARIANT
:
1962 case SD_BUS_TYPE_STRUCT
:
1963 r
= sd_bus_message_enter_container(m
, type
, contents
);
1965 return bus_log_parse_error(r
);
1967 if (type
== SD_BUS_TYPE_VARIANT
)
1968 r
= json_transform_variant(m
, contents
, &v
);
1969 else if (type
== SD_BUS_TYPE_ARRAY
&& contents
[0] == '{')
1970 r
= json_transform_dict_array(m
, &v
);
1972 r
= json_transform_array_or_struct(m
, &v
);
1976 r
= sd_bus_message_exit_container(m
);
1978 return bus_log_parse_error(r
);
1983 assert_not_reached();
1990 static int json_transform_message(sd_bus_message
*m
, JsonVariant
**ret
) {
1991 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1998 assert_se(type
= sd_bus_message_get_signature(m
, false));
2000 r
= json_transform_array_or_struct(m
, &v
);
2004 r
= json_build(ret
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(type
)),
2005 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(v
))));
2012 static int call(int argc
, char **argv
, void *userdata
) {
2013 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2014 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2015 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
2018 r
= acquire_bus(false, &bus
);
2022 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
2024 return bus_log_create_error(r
);
2026 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
2028 return bus_log_create_error(r
);
2030 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
2032 return bus_log_create_error(r
);
2034 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
2036 return bus_log_create_error(r
);
2038 if (!isempty(argv
[5])) {
2043 r
= message_append_cmdline(m
, argv
[5], &p
);
2048 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2049 "Too many parameters for signature.");
2052 if (!arg_expect_reply
) {
2053 r
= sd_bus_send(bus
, m
, NULL
);
2055 return log_error_errno(r
, "Failed to send message: %m");
2060 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
2062 return log_error_errno(r
, "Call failed: %s", bus_error_message(&error
, r
));
2064 r
= sd_bus_message_is_empty(reply
);
2066 return bus_log_parse_error(r
);
2068 if (r
== 0 && !arg_quiet
) {
2070 if (!FLAGS_SET(arg_json_format_flags
, JSON_FORMAT_OFF
)) {
2071 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
2073 if (arg_json_format_flags
& (JSON_FORMAT_PRETTY
|JSON_FORMAT_PRETTY_AUTO
))
2074 pager_open(arg_pager_flags
);
2076 r
= json_transform_message(reply
, &v
);
2080 json_variant_dump(v
, arg_json_format_flags
, NULL
, NULL
);
2082 } else if (arg_verbose
) {
2083 pager_open(arg_pager_flags
);
2085 r
= sd_bus_message_dump(reply
, stdout
, 0);
2090 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
2093 r
= format_cmdline(reply
, stdout
, false);
2095 return bus_log_parse_error(r
);
2097 fputc('\n', stdout
);
2104 static int emit_signal(int argc
, char **argv
, void *userdata
) {
2105 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2106 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2109 r
= acquire_bus(false, &bus
);
2113 r
= sd_bus_message_new_signal(bus
, &m
, argv
[1], argv
[2], argv
[3]);
2115 return bus_log_create_error(r
);
2117 if (arg_destination
) {
2118 r
= sd_bus_message_set_destination(m
, arg_destination
);
2120 return bus_log_create_error(r
);
2123 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
2125 return bus_log_create_error(r
);
2127 if (!isempty(argv
[4])) {
2132 r
= message_append_cmdline(m
, argv
[4], &p
);
2137 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2138 "Too many parameters for signature.");
2141 r
= sd_bus_send(bus
, m
, NULL
);
2143 return log_error_errno(r
, "Failed to send signal: %m");
2148 static int get_property(int argc
, char **argv
, void *userdata
) {
2149 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2150 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2153 r
= acquire_bus(false, &bus
);
2157 STRV_FOREACH(i
, argv
+ 4) {
2158 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2159 const char *contents
= NULL
;
2162 r
= sd_bus_call_method(bus
, argv
[1], argv
[2],
2163 "org.freedesktop.DBus.Properties", "Get",
2164 &error
, &reply
, "ss", argv
[3], *i
);
2166 return log_error_errno(r
, "Failed to get property %s on interface %s: %s",
2168 bus_error_message(&error
, r
));
2170 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
2172 return bus_log_parse_error(r
);
2174 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
2176 return bus_log_parse_error(r
);
2178 if (!FLAGS_SET(arg_json_format_flags
, JSON_FORMAT_OFF
)) {
2179 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
2181 if (arg_json_format_flags
& (JSON_FORMAT_PRETTY
|JSON_FORMAT_PRETTY_AUTO
))
2182 pager_open(arg_pager_flags
);
2184 r
= json_transform_variant(reply
, contents
, &v
);
2188 json_variant_dump(v
, arg_json_format_flags
, NULL
, NULL
);
2190 } else if (arg_verbose
) {
2191 pager_open(arg_pager_flags
);
2193 r
= sd_bus_message_dump(reply
, stdout
, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
2197 fputs(contents
, stdout
);
2200 r
= format_cmdline(reply
, stdout
, false);
2202 return bus_log_parse_error(r
);
2204 fputc('\n', stdout
);
2207 r
= sd_bus_message_exit_container(reply
);
2209 return bus_log_parse_error(r
);
2215 static int set_property(int argc
, char **argv
, void *userdata
) {
2216 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2217 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2218 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2222 r
= acquire_bus(false, &bus
);
2226 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2],
2227 "org.freedesktop.DBus.Properties", "Set");
2229 return bus_log_create_error(r
);
2231 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
2233 return bus_log_create_error(r
);
2235 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
2237 return bus_log_create_error(r
);
2240 r
= message_append_cmdline(m
, argv
[5], &p
);
2244 r
= sd_bus_message_close_container(m
);
2246 return bus_log_create_error(r
);
2249 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Too many parameters for signature.");
2251 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
2253 return log_error_errno(r
, "Failed to set property %s on interface %s: %s",
2255 bus_error_message(&error
, r
));
2260 static int help(void) {
2261 _cleanup_free_
char *link
= NULL
;
2264 r
= terminal_urlify_man("busctl", "1", &link
);
2268 pager_open(arg_pager_flags
);
2270 printf("%s [OPTIONS...] COMMAND ...\n\n"
2271 "%sIntrospect the D-Bus IPC bus.%s\n"
2273 " list List bus names\n"
2274 " status [SERVICE] Show bus service, process or bus owner credentials\n"
2275 " monitor [SERVICE...] Show bus traffic\n"
2276 " capture [SERVICE...] Capture bus traffic as pcap\n"
2277 " tree [SERVICE...] Show object tree of service\n"
2278 " introspect SERVICE OBJECT [INTERFACE]\n"
2279 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
2281 " emit OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT...]]\n"
2283 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
2284 " Get property value\n"
2285 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
2286 " Set property value\n"
2287 " help Show this help\n"
2289 " -h --help Show this help\n"
2290 " --version Show package version\n"
2291 " --no-pager Do not pipe output into a pager\n"
2292 " --no-legend Do not show the headers and footers\n"
2293 " -l --full Do not ellipsize output\n"
2294 " --system Connect to system bus\n"
2295 " --user Connect to user bus\n"
2296 " -H --host=[USER@]HOST Operate on remote host\n"
2297 " -M --machine=CONTAINER Operate on local container\n"
2298 " --address=ADDRESS Connect to bus specified by address\n"
2299 " --show-machine Show machine ID column in list\n"
2300 " --unique Only show unique names\n"
2301 " --acquired Only show acquired names\n"
2302 " --activatable Only show activatable names\n"
2303 " --match=MATCH Only show matching messages\n"
2304 " --size=SIZE Maximum length of captured packet\n"
2305 " --list Don't show tree, but simple object path list\n"
2306 " -q --quiet Don't show method call reply\n"
2307 " --verbose Show result values in long format\n"
2308 " --json=MODE Output as JSON\n"
2309 " -j Same as --json=pretty on tty, --json=short otherwise\n"
2310 " --expect-reply=BOOL Expect a method call reply\n"
2311 " --auto-start=BOOL Auto-start destination service\n"
2312 " --allow-interactive-authorization=BOOL\n"
2313 " Allow interactive authorization for operation\n"
2314 " --timeout=SECS Maximum time to wait for method call completion\n"
2315 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
2316 " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n"
2318 " --destination=SERVICE Destination service of a signal\n"
2319 "\nSee the %s for details.\n",
2320 program_invocation_short_name
,
2328 static int verb_help(int argc
, char **argv
, void *userdata
) {
2332 static int parse_argv(int argc
, char *argv
[]) {
2335 ARG_VERSION
= 0x100,
2352 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
2360 static const struct option options
[] = {
2361 { "help", no_argument
, NULL
, 'h' },
2362 { "version", no_argument
, NULL
, ARG_VERSION
},
2363 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
2364 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
2365 { "full", no_argument
, NULL
, 'l' },
2366 { "system", no_argument
, NULL
, ARG_SYSTEM
},
2367 { "user", no_argument
, NULL
, ARG_USER
},
2368 { "address", required_argument
, NULL
, ARG_ADDRESS
},
2369 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
2370 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
2371 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
2372 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
2373 { "match", required_argument
, NULL
, ARG_MATCH
},
2374 { "host", required_argument
, NULL
, 'H' },
2375 { "machine", required_argument
, NULL
, 'M' },
2376 { "size", required_argument
, NULL
, ARG_SIZE
},
2377 { "list", no_argument
, NULL
, ARG_LIST
},
2378 { "quiet", no_argument
, NULL
, 'q' },
2379 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
2380 { "xml-interface", no_argument
, NULL
, ARG_XML_INTERFACE
},
2381 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
2382 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
2383 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
2384 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
2385 { "augment-creds", required_argument
, NULL
, ARG_AUGMENT_CREDS
},
2386 { "watch-bind", required_argument
, NULL
, ARG_WATCH_BIND
},
2387 { "json", required_argument
, NULL
, ARG_JSON
},
2388 { "destination", required_argument
, NULL
, ARG_DESTINATION
},
2397 while ((c
= getopt_long(argc
, argv
, "hH:M:qjl", options
, NULL
)) >= 0)
2408 arg_pager_flags
|= PAGER_DISABLE
;
2420 arg_runtime_scope
= RUNTIME_SCOPE_USER
;
2424 arg_runtime_scope
= RUNTIME_SCOPE_SYSTEM
;
2428 arg_address
= optarg
;
2431 case ARG_SHOW_MACHINE
:
2432 arg_show_machine
= true;
2440 arg_acquired
= true;
2443 case ARG_ACTIVATABLE
:
2444 arg_activatable
= true;
2448 if (strv_extend(&arg_matches
, optarg
) < 0)
2455 r
= parse_size(optarg
, 1024, &sz
);
2457 return log_error_errno(r
, "Failed to parse size '%s': %m", optarg
);
2459 if ((uint64_t) (size_t) sz
!= sz
)
2460 return log_error_errno(SYNTHETIC_ERRNO(E2BIG
),
2461 "Size out of range.");
2463 arg_snaplen
= (size_t) sz
;
2472 arg_transport
= BUS_TRANSPORT_REMOTE
;
2477 arg_transport
= BUS_TRANSPORT_MACHINE
;
2489 case ARG_XML_INTERFACE
:
2490 arg_xml_interface
= true;
2493 case ARG_EXPECT_REPLY
:
2494 r
= parse_boolean_argument("--expect-reply=", optarg
, &arg_expect_reply
);
2499 case ARG_AUTO_START
:
2500 r
= parse_boolean_argument("--auto-start=", optarg
, &arg_auto_start
);
2505 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
2506 r
= parse_boolean_argument("--allow-interactive-authorization=", optarg
,
2507 &arg_allow_interactive_authorization
);
2513 r
= parse_sec(optarg
, &arg_timeout
);
2515 return log_error_errno(r
, "Failed to parse --timeout= parameter '%s': %m", optarg
);
2519 case ARG_AUGMENT_CREDS
:
2520 r
= parse_boolean_argument("--augment-creds=", optarg
, &arg_augment_creds
);
2525 case ARG_WATCH_BIND
:
2526 r
= parse_boolean_argument("--watch-bind=", optarg
, &arg_watch_bind
);
2532 arg_json_format_flags
= JSON_FORMAT_PRETTY_AUTO
|JSON_FORMAT_COLOR_AUTO
;
2536 r
= parse_json_argument(optarg
, &arg_json_format_flags
);
2542 case ARG_DESTINATION
:
2543 arg_destination
= optarg
;
2550 assert_not_reached();
2554 arg_full
= terminal_is_dumb();
2559 static int busctl_main(int argc
, char *argv
[]) {
2560 static const Verb verbs
[] = {
2561 { "list", VERB_ANY
, 1, VERB_DEFAULT
, list_bus_names
},
2562 { "status", VERB_ANY
, 2, 0, status
},
2563 { "monitor", VERB_ANY
, VERB_ANY
, 0, verb_monitor
},
2564 { "capture", VERB_ANY
, VERB_ANY
, 0, verb_capture
},
2565 { "tree", VERB_ANY
, VERB_ANY
, 0, tree
},
2566 { "introspect", 3, 4, 0, introspect
},
2567 { "call", 5, VERB_ANY
, 0, call
},
2568 { "emit", 4, VERB_ANY
, 0, emit_signal
},
2569 { "get-property", 5, VERB_ANY
, 0, get_property
},
2570 { "set-property", 6, VERB_ANY
, 0, set_property
},
2571 { "help", VERB_ANY
, VERB_ANY
, 0, verb_help
},
2575 return dispatch_verb(argc
, argv
, verbs
, NULL
);
2578 static int run(int argc
, char *argv
[]) {
2583 r
= parse_argv(argc
, argv
);
2587 return busctl_main(argc
, argv
);
2590 DEFINE_MAIN_FUNCTION(run
);