1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
10 #include "bus-internal.h"
11 #include "bus-signature.h"
14 #include "busctl-introspect.h"
19 #include "locale-util.h"
22 #include "parse-util.h"
23 #include "path-util.h"
26 #include "terminal-util.h"
27 #include "user-util.h"
35 } arg_json
= JSON_OFF
;
36 static bool arg_no_pager
= false;
37 static bool arg_legend
= true;
38 static const char *arg_address
= NULL
;
39 static bool arg_unique
= false;
40 static bool arg_acquired
= false;
41 static bool arg_activatable
= false;
42 static bool arg_show_machine
= false;
43 static char **arg_matches
= NULL
;
44 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
45 static const char *arg_host
= NULL
;
46 static bool arg_user
= false;
47 static size_t arg_snaplen
= 4096;
48 static bool arg_list
= false;
49 static bool arg_quiet
= false;
50 static bool arg_verbose
= false;
51 static bool arg_expect_reply
= true;
52 static bool arg_auto_start
= true;
53 static bool arg_allow_interactive_authorization
= true;
54 static bool arg_augment_creds
= true;
55 static bool arg_watch_bind
= false;
56 static usec_t arg_timeout
= 0;
58 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
59 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
61 static int acquire_bus(bool set_monitor
, sd_bus
**ret
) {
62 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
67 return log_error_errno(r
, "Failed to allocate bus: %m");
70 r
= sd_bus_set_monitor(bus
, true);
72 return log_error_errno(r
, "Failed to set monitor mode: %m");
74 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
76 return log_error_errno(r
, "Failed to enable credentials: %m");
78 r
= sd_bus_negotiate_timestamp(bus
, true);
80 return log_error_errno(r
, "Failed to enable timestamps: %m");
82 r
= sd_bus_negotiate_fds(bus
, true);
84 return log_error_errno(r
, "Failed to enable fds: %m");
87 r
= sd_bus_set_bus_client(bus
, true);
89 return log_error_errno(r
, "Failed to set bus client: %m");
91 r
= sd_bus_set_watch_bind(bus
, arg_watch_bind
);
93 return log_error_errno(r
, "Failed to set watch-bind setting to '%s': %m", yes_no(arg_watch_bind
));
96 r
= sd_bus_set_address(bus
, arg_address
);
98 switch (arg_transport
) {
100 case BUS_TRANSPORT_LOCAL
:
103 r
= bus_set_address_user(bus
);
105 bus
->is_system
= true;
106 r
= bus_set_address_system(bus
);
110 case BUS_TRANSPORT_REMOTE
:
111 r
= bus_set_address_system_remote(bus
, arg_host
);
114 case BUS_TRANSPORT_MACHINE
:
115 r
= bus_set_address_system_machine(bus
, arg_host
);
119 assert_not_reached("Hmm, unknown transport type.");
123 return log_error_errno(r
, "Failed to set address: %m");
125 r
= sd_bus_start(bus
);
127 return log_error_errno(r
, "Failed to connect to bus: %m");
129 *ret
= TAKE_PTR(bus
);
134 static int list_bus_names(int argc
, char **argv
, void *userdata
) {
135 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
136 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
137 _cleanup_free_
char **merged
= NULL
;
138 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
147 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
148 arg_unique
= arg_acquired
= arg_activatable
= true;
150 r
= acquire_bus(false, &bus
);
154 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
156 return log_error_errno(r
, "Failed to list names: %m");
158 (void) pager_open(arg_no_pager
, false);
160 names
= hashmap_new(&string_hash_ops
);
164 STRV_FOREACH(i
, acquired
) {
165 max_i
= MAX(max_i
, strlen(*i
));
167 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
169 return log_error_errno(r
, "Failed to add to hashmap: %m");
172 STRV_FOREACH(i
, activatable
) {
173 max_i
= MAX(max_i
, strlen(*i
));
175 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
176 if (r
< 0 && r
!= -EEXIST
)
177 return log_error_errno(r
, "Failed to add to hashmap: %m");
180 merged
= new(char*, hashmap_size(names
) + 1);
184 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
191 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
192 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
194 if (arg_show_machine
)
200 STRV_FOREACH(i
, merged
) {
201 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
204 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
207 printf("%-*s", (int) max_i
, *i
);
208 printf(" - - - (activatable) - - ");
209 if (arg_show_machine
)
217 if (!arg_unique
&& (*i
)[0] == ':')
220 if (!arg_acquired
&& (*i
)[0] != ':')
223 printf("%-*s", (int) max_i
, *i
);
225 r
= sd_bus_get_name_creds(
227 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
228 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
229 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
230 SD_BUS_CREDS_DESCRIPTION
, &creds
);
232 const char *unique
, *session
, *unit
, *cn
;
236 r
= sd_bus_creds_get_pid(creds
, &pid
);
238 const char *comm
= NULL
;
240 sd_bus_creds_get_comm(creds
, &comm
);
242 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
244 fputs(" - - ", stdout
);
246 r
= sd_bus_creds_get_euid(creds
, &uid
);
248 _cleanup_free_
char *u
= NULL
;
250 u
= uid_to_name(uid
);
259 fputs(" - ", stdout
);
261 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
263 printf(" %-13s", unique
);
265 fputs(" - ", stdout
);
267 r
= sd_bus_creds_get_unit(creds
, &unit
);
269 _cleanup_free_
char *e
;
271 e
= ellipsize(unit
, 25, 100);
277 fputs(" - ", stdout
);
279 r
= sd_bus_creds_get_session(creds
, &session
);
281 printf(" %-10s", session
);
283 fputs(" - ", stdout
);
285 r
= sd_bus_creds_get_description(creds
, &cn
);
287 printf(" %-19s", cn
);
289 fputs(" - ", stdout
);
292 printf(" - - - - - - - ");
294 if (arg_show_machine
) {
295 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
297 char m
[SD_ID128_STRING_MAX
];
298 printf(" %s\n", sd_id128_to_string(mid
, m
));
308 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
309 const char *vertical
, *space
;
312 /* We assume the list is sorted. Let's first skip over the
313 * entry we are looking at. */
318 if (!streq(*l
, path
))
324 vertical
= strjoina(prefix
, special_glyph(TREE_VERTICAL
));
325 space
= strjoina(prefix
, special_glyph(TREE_SPACE
));
328 bool has_more
= false;
330 if (!*l
|| !path_startswith(*l
, path
))
335 if (!*n
|| !path_startswith(*n
, path
))
338 if (!path_startswith(*n
, *l
)) {
346 printf("%s%s%s\n", prefix
, special_glyph(has_more
? TREE_BRANCH
: TREE_RIGHT
), *l
);
348 print_subtree(has_more
? vertical
: space
, *l
, l
);
353 static void print_tree(const char *prefix
, char **l
) {
355 prefix
= strempty(prefix
);
361 printf("%s%s\n", prefix
, *i
);
365 if (strv_isempty(l
)) {
366 printf("No objects discovered.\n");
370 if (streq(l
[0], "/") && !l
[1]) {
371 printf("Only root object discovered.\n");
375 print_subtree(prefix
, "/", l
);
378 static int on_path(const char *path
, void *userdata
) {
379 Set
*paths
= userdata
;
384 r
= set_put_strdup(paths
, path
);
391 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
392 static const XMLIntrospectOps ops
= {
396 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
397 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
401 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
404 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
406 log_error_errno(r
, "Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
410 r
= sd_bus_message_read(reply
, "s", &xml
);
412 return bus_log_parse_error(r
);
414 return parse_xml_introspect(path
, xml
, &ops
, paths
);
417 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
418 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
419 _cleanup_free_
char **l
= NULL
;
423 paths
= set_new(&string_hash_ops
);
427 done
= set_new(&string_hash_ops
);
431 failed
= set_new(&string_hash_ops
);
439 r
= set_put(paths
, m
);
446 _cleanup_free_
char *p
= NULL
;
449 p
= set_steal_first(paths
);
453 if (set_contains(done
, p
) ||
454 set_contains(failed
, p
))
457 q
= find_nodes(bus
, service
, p
, paths
, many
);
462 q
= set_put(failed
, p
);
464 q
= set_put(done
, p
);
473 (void) pager_open(arg_no_pager
, false);
475 l
= set_get_strv(done
);
480 print_tree(prefix
, l
);
487 static int tree(int argc
, char **argv
, void *userdata
) {
488 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
492 if (!arg_unique
&& !arg_acquired
)
495 r
= acquire_bus(false, &bus
);
500 _cleanup_strv_free_
char **names
= NULL
;
501 bool not_first
= false;
503 r
= sd_bus_list_names(bus
, &names
, NULL
);
505 return log_error_errno(r
, "Failed to get name list: %m");
507 (void) pager_open(arg_no_pager
, false);
509 STRV_FOREACH(i
, names
) {
512 if (!arg_unique
&& (*i
)[0] == ':')
515 if (!arg_acquired
&& (*i
)[0] == ':')
521 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
523 q
= tree_one(bus
, *i
, NULL
, true);
530 STRV_FOREACH(i
, argv
+1) {
537 (void) pager_open(arg_no_pager
, false);
538 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
541 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
550 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
554 const char *contents
= NULL
;
569 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
575 if (bus_type_is_container(type
) > 0) {
577 r
= sd_bus_message_enter_container(m
, type
, contents
);
581 if (type
== SD_BUS_TYPE_ARRAY
) {
584 /* count array entries */
587 r
= sd_bus_message_skip(m
, contents
);
596 r
= sd_bus_message_rewind(m
, false);
606 } else if (type
== SD_BUS_TYPE_VARIANT
) {
611 fprintf(f
, "%s", contents
);
615 r
= format_cmdline(m
, f
, needs_space
);
621 r
= sd_bus_message_exit_container(m
);
628 r
= sd_bus_message_read_basic(m
, type
, &basic
);
636 case SD_BUS_TYPE_BYTE
:
637 fprintf(f
, "%u", basic
.u8
);
640 case SD_BUS_TYPE_BOOLEAN
:
641 fputs(true_false(basic
.i
), f
);
644 case SD_BUS_TYPE_INT16
:
645 fprintf(f
, "%i", basic
.s16
);
648 case SD_BUS_TYPE_UINT16
:
649 fprintf(f
, "%u", basic
.u16
);
652 case SD_BUS_TYPE_INT32
:
653 fprintf(f
, "%i", basic
.s32
);
656 case SD_BUS_TYPE_UINT32
:
657 fprintf(f
, "%u", basic
.u32
);
660 case SD_BUS_TYPE_INT64
:
661 fprintf(f
, "%" PRIi64
, basic
.s64
);
664 case SD_BUS_TYPE_UINT64
:
665 fprintf(f
, "%" PRIu64
, basic
.u64
);
668 case SD_BUS_TYPE_DOUBLE
:
669 fprintf(f
, "%g", basic
.d64
);
672 case SD_BUS_TYPE_STRING
:
673 case SD_BUS_TYPE_OBJECT_PATH
:
674 case SD_BUS_TYPE_SIGNATURE
: {
675 _cleanup_free_
char *b
= NULL
;
677 b
= cescape(basic
.string
);
681 fprintf(f
, "\"%s\"", b
);
685 case SD_BUS_TYPE_UNIX_FD
:
686 fprintf(f
, "%i", basic
.i
);
690 assert_not_reached("Unknown basic type.");
697 typedef struct Member
{
708 static void member_hash_func(const void *p
, struct siphash
*state
) {
715 string_hash_func(m
->type
, state
);
717 arity
+= !!m
->name
+ !!m
->interface
;
719 uint64_hash_func(&arity
, state
);
722 string_hash_func(m
->name
, state
);
725 string_hash_func(m
->interface
, state
);
728 static int member_compare_func(const Member
*x
, const Member
*y
) {
736 d
= strcmp_ptr(x
->interface
, y
->interface
);
740 d
= strcmp(x
->type
, y
->type
);
744 return strcmp_ptr(x
->name
, y
->name
);
747 static int member_compare_funcp(Member
* const *a
, Member
* const *b
) {
748 return member_compare_func(*a
, *b
);
751 static void member_free(Member
*m
) {
763 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
765 static void member_set_free(Set
*s
) {
766 set_free_with_destructor(s
, member_free
);
769 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
771 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
772 _cleanup_(member_freep
) Member
*m
;
773 Set
*members
= userdata
;
783 m
->type
= "interface";
786 r
= free_and_strdup(&m
->interface
, interface
);
790 r
= set_put(members
, m
);
792 log_error("Duplicate interface");
800 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
801 _cleanup_(member_freep
) Member
*m
;
802 Set
*members
= userdata
;
815 r
= free_and_strdup(&m
->interface
, interface
);
819 r
= free_and_strdup(&m
->name
, name
);
823 r
= free_and_strdup(&m
->signature
, signature
);
827 r
= free_and_strdup(&m
->result
, result
);
831 r
= set_put(members
, m
);
833 log_error("Duplicate method");
841 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
842 _cleanup_(member_freep
) Member
*m
;
843 Set
*members
= userdata
;
856 r
= free_and_strdup(&m
->interface
, interface
);
860 r
= free_and_strdup(&m
->name
, name
);
864 r
= free_and_strdup(&m
->signature
, signature
);
868 r
= set_put(members
, m
);
870 log_error("Duplicate signal");
878 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
879 _cleanup_(member_freep
) Member
*m
;
880 Set
*members
= userdata
;
890 m
->type
= "property";
892 m
->writable
= writable
;
894 r
= free_and_strdup(&m
->interface
, interface
);
898 r
= free_and_strdup(&m
->name
, name
);
902 r
= free_and_strdup(&m
->signature
, signature
);
906 r
= set_put(members
, m
);
908 log_error("Duplicate property");
916 static int introspect(int argc
, char **argv
, void *userdata
) {
917 static const struct hash_ops member_hash_ops
= {
918 .hash
= member_hash_func
,
919 .compare
= (__compar_fn_t
) member_compare_func
,
922 static const XMLIntrospectOps ops
= {
923 .on_interface
= on_interface
,
924 .on_method
= on_method
,
925 .on_signal
= on_signal
,
926 .on_property
= on_property
,
929 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
930 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply_xml
= NULL
;
931 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
932 _cleanup_(member_set_freep
) Set
*members
= NULL
;
933 unsigned name_width
, type_width
, signature_width
, result_width
, j
, k
= 0;
934 Member
*m
, **sorted
= NULL
;
939 r
= acquire_bus(false, &bus
);
943 members
= set_new(&member_hash_ops
);
947 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply_xml
, "");
949 return log_error_errno(r
, "Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
951 r
= sd_bus_message_read(reply_xml
, "s", &xml
);
953 return bus_log_parse_error(r
);
955 /* First, get list of all properties */
956 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
960 /* Second, find the current values for them */
961 SET_FOREACH(m
, members
, i
) {
962 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
964 if (!streq(m
->type
, "property"))
970 if (argv
[3] && !streq(argv
[3], m
->interface
))
973 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
975 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
977 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
979 return bus_log_parse_error(r
);
983 _cleanup_free_
char *buf
= NULL
;
984 _cleanup_fclose_
FILE *mf
= NULL
;
988 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
990 return bus_log_parse_error(r
);
995 r
= sd_bus_message_read(reply
, "s", &name
);
997 return bus_log_parse_error(r
);
999 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
1001 return bus_log_parse_error(r
);
1003 mf
= open_memstream(&buf
, &sz
);
1007 (void) __fsetlocking(mf
, FSETLOCKING_BYCALLER
);
1009 r
= format_cmdline(reply
, mf
, false);
1011 return bus_log_parse_error(r
);
1013 mf
= safe_fclose(mf
);
1015 z
= set_get(members
, &((Member
) {
1017 .interface
= m
->interface
,
1018 .name
= (char*) name
}));
1020 free_and_replace(z
->value
, buf
);
1022 r
= sd_bus_message_exit_container(reply
);
1024 return bus_log_parse_error(r
);
1026 r
= sd_bus_message_exit_container(reply
);
1028 return bus_log_parse_error(r
);
1031 r
= sd_bus_message_exit_container(reply
);
1033 return bus_log_parse_error(r
);
1036 (void) pager_open(arg_no_pager
, false);
1038 name_width
= STRLEN("NAME");
1039 type_width
= STRLEN("TYPE");
1040 signature_width
= STRLEN("SIGNATURE");
1041 result_width
= STRLEN("RESULT/VALUE");
1043 sorted
= newa(Member
*, set_size(members
));
1045 SET_FOREACH(m
, members
, i
) {
1047 if (argv
[3] && !streq(argv
[3], m
->interface
))
1051 name_width
= MAX(name_width
, strlen(m
->interface
));
1053 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1055 type_width
= MAX(type_width
, strlen(m
->type
));
1057 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1059 result_width
= MAX(result_width
, strlen(m
->result
));
1061 result_width
= MAX(result_width
, strlen(m
->value
));
1066 if (result_width
> 40)
1069 typesafe_qsort(sorted
, k
, member_compare_funcp
);
1072 printf("%-*s %-*s %-*s %-*s %s\n",
1073 (int) name_width
, "NAME",
1074 (int) type_width
, "TYPE",
1075 (int) signature_width
, "SIGNATURE",
1076 (int) result_width
, "RESULT/VALUE",
1080 for (j
= 0; j
< k
; j
++) {
1081 _cleanup_free_
char *ellipsized
= NULL
;
1087 if (argv
[3] && !streq(argv
[3], m
->interface
))
1090 is_interface
= streq(m
->type
, "interface");
1092 if (argv
[3] && is_interface
)
1096 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1102 rv
= empty_to_dash(m
->result
);
1104 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1105 is_interface
? ansi_highlight() : "",
1106 is_interface
? "" : ".",
1107 - !is_interface
+ (int) name_width
, empty_to_dash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1108 is_interface
? ansi_normal() : "",
1109 (int) type_width
, empty_to_dash(m
->type
),
1110 (int) signature_width
, empty_to_dash(m
->signature
),
1111 (int) result_width
, rv
,
1112 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1113 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1114 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1115 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1116 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1117 m
->writable
? " writable" : "");
1123 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1124 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1127 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1128 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1131 static int monitor(int argc
, char **argv
, int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1132 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1133 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*message
= NULL
;
1134 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1137 const char *unique_name
;
1138 bool is_monitor
= false;
1141 r
= acquire_bus(true, &bus
);
1145 /* upgrade connection; it's not used for anything else after this call */
1146 r
= sd_bus_message_new_method_call(bus
, &message
, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
1148 return bus_log_create_error(r
);
1150 r
= sd_bus_message_open_container(message
, 'a', "s");
1152 return bus_log_create_error(r
);
1154 STRV_FOREACH(i
, argv
+1) {
1155 _cleanup_free_
char *m
= NULL
;
1157 if (!service_name_is_valid(*i
)) {
1158 log_error("Invalid service name '%s'", *i
);
1162 m
= strjoin("sender='", *i
, "'");
1166 r
= sd_bus_message_append_basic(message
, 's', m
);
1168 return bus_log_create_error(r
);
1171 m
= strjoin("destination='", *i
, "'");
1175 r
= sd_bus_message_append_basic(message
, 's', m
);
1177 return bus_log_create_error(r
);
1180 STRV_FOREACH(i
, arg_matches
) {
1181 r
= sd_bus_message_append_basic(message
, 's', *i
);
1183 return bus_log_create_error(r
);
1186 r
= sd_bus_message_close_container(message
);
1188 return bus_log_create_error(r
);
1190 r
= sd_bus_message_append_basic(message
, 'u', &flags
);
1192 return bus_log_create_error(r
);
1194 r
= sd_bus_call(bus
, message
, arg_timeout
, &error
, NULL
);
1196 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
1198 r
= sd_bus_get_unique_name(bus
, &unique_name
);
1200 return log_error_errno(r
, "Failed to get unique name: %m");
1202 log_info("Monitoring bus message stream.");
1205 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1207 r
= sd_bus_process(bus
, &m
);
1209 return log_error_errno(r
, "Failed to process bus: %m");
1214 /* wait until we lose our unique name */
1215 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus", "NameLost") <= 0)
1218 r
= sd_bus_message_read(m
, "s", &name
);
1220 return log_error_errno(r
, "Failed to read lost name: %m");
1222 if (streq(name
, unique_name
))
1232 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1233 log_info("Connection terminated, exiting.");
1243 r
= sd_bus_wait(bus
, (uint64_t) -1);
1245 return log_error_errno(r
, "Failed to wait for bus: %m");
1249 static int verb_monitor(int argc
, char **argv
, void *userdata
) {
1250 return monitor(argc
, argv
, message_dump
);
1253 static int verb_capture(int argc
, char **argv
, void *userdata
) {
1256 if (isatty(fileno(stdout
)) > 0) {
1257 log_error("Refusing to write message data to console, please redirect output to a file.");
1261 bus_pcap_header(arg_snaplen
, stdout
);
1263 r
= monitor(argc
, argv
, message_pcap
);
1267 r
= fflush_and_check(stdout
);
1269 return log_error_errno(r
, "Couldn't write capture file: %m");
1274 static int status(int argc
, char **argv
, void *userdata
) {
1275 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1276 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
1280 r
= acquire_bus(false, &bus
);
1284 if (!isempty(argv
[1])) {
1285 r
= parse_pid(argv
[1], &pid
);
1287 r
= sd_bus_get_name_creds(
1290 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1293 r
= sd_bus_creds_new_from_pid(
1298 const char *scope
, *address
;
1301 r
= sd_bus_get_address(bus
, &address
);
1303 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1305 r
= sd_bus_get_scope(bus
, &scope
);
1307 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1309 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1311 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1313 r
= sd_bus_get_owner_creds(
1315 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1320 return log_error_errno(r
, "Failed to get credentials: %m");
1322 bus_creds_dump(creds
, NULL
, false);
1326 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1346 log_error("Too few parameters for signature.");
1355 case SD_BUS_TYPE_BOOLEAN
:
1357 r
= parse_boolean(v
);
1359 return log_error_errno(r
, "Failed to parse as boolean: %s", v
);
1361 r
= sd_bus_message_append_basic(m
, t
, &r
);
1364 case SD_BUS_TYPE_BYTE
: {
1367 r
= safe_atou8(v
, &z
);
1369 return log_error_errno(r
, "Failed to parse as byte (unsigned 8bit integer): %s", v
);
1371 r
= sd_bus_message_append_basic(m
, t
, &z
);
1375 case SD_BUS_TYPE_INT16
: {
1378 r
= safe_atoi16(v
, &z
);
1380 return log_error_errno(r
, "Failed to parse as signed 16bit integer: %s", v
);
1382 r
= sd_bus_message_append_basic(m
, t
, &z
);
1386 case SD_BUS_TYPE_UINT16
: {
1389 r
= safe_atou16(v
, &z
);
1391 return log_error_errno(r
, "Failed to parse as unsigned 16bit integer: %s", v
);
1393 r
= sd_bus_message_append_basic(m
, t
, &z
);
1397 case SD_BUS_TYPE_INT32
: {
1400 r
= safe_atoi32(v
, &z
);
1402 return log_error_errno(r
, "Failed to parse as signed 32bit integer: %s", v
);
1404 r
= sd_bus_message_append_basic(m
, t
, &z
);
1408 case SD_BUS_TYPE_UINT32
: {
1411 r
= safe_atou32(v
, &z
);
1413 return log_error_errno(r
, "Failed to parse as unsigned 32bit integer: %s", v
);
1415 r
= sd_bus_message_append_basic(m
, t
, &z
);
1419 case SD_BUS_TYPE_INT64
: {
1422 r
= safe_atoi64(v
, &z
);
1424 return log_error_errno(r
, "Failed to parse as signed 64bit integer: %s", v
);
1426 r
= sd_bus_message_append_basic(m
, t
, &z
);
1430 case SD_BUS_TYPE_UINT64
: {
1433 r
= safe_atou64(v
, &z
);
1435 return log_error_errno(r
, "Failed to parse as unsigned 64bit integer: %s", v
);
1437 r
= sd_bus_message_append_basic(m
, t
, &z
);
1441 case SD_BUS_TYPE_DOUBLE
: {
1444 r
= safe_atod(v
, &z
);
1446 return log_error_errno(r
, "Failed to parse as double precision floating point: %s", v
);
1448 r
= sd_bus_message_append_basic(m
, t
, &z
);
1452 case SD_BUS_TYPE_STRING
:
1453 case SD_BUS_TYPE_OBJECT_PATH
:
1454 case SD_BUS_TYPE_SIGNATURE
:
1456 r
= sd_bus_message_append_basic(m
, t
, v
);
1459 case SD_BUS_TYPE_ARRAY
: {
1463 r
= safe_atou32(v
, &n
);
1465 return log_error_errno(r
, "Failed to parse number of array entries: %s", v
);
1467 r
= signature_element_length(signature
, &k
);
1469 return log_error_errno(r
, "Invalid array signature.");
1474 memcpy(s
, signature
, k
);
1477 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1479 return bus_log_create_error(r
);
1481 for (i
= 0; i
< n
; i
++) {
1482 r
= message_append_cmdline(m
, s
, &p
);
1490 r
= sd_bus_message_close_container(m
);
1494 case SD_BUS_TYPE_VARIANT
:
1495 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1497 return bus_log_create_error(r
);
1499 r
= message_append_cmdline(m
, v
, &p
);
1503 r
= sd_bus_message_close_container(m
);
1506 case SD_BUS_TYPE_STRUCT_BEGIN
:
1507 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1513 r
= signature_element_length(signature
, &k
);
1515 return log_error_errno(r
, "Invalid struct/dict entry signature.");
1519 memcpy(s
, signature
+ 1, k
- 2);
1522 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1524 return bus_log_create_error(r
);
1526 r
= message_append_cmdline(m
, s
, &p
);
1533 r
= sd_bus_message_close_container(m
);
1537 case SD_BUS_TYPE_UNIX_FD
:
1538 log_error("UNIX file descriptor not supported as type.");
1542 log_error("Unknown signature type %c.", t
);
1547 return bus_log_create_error(r
);
1554 static int json_transform_one(sd_bus_message
*m
, JsonVariant
**ret
);
1556 static int json_transform_array_or_struct(sd_bus_message
*m
, JsonVariant
**ret
) {
1557 size_t n_elements
= 0, n_allocated
= 0;
1558 JsonVariant
**elements
= NULL
;
1565 r
= sd_bus_message_at_end(m
, false);
1567 bus_log_parse_error(r
);
1573 if (!GREEDY_REALLOC(elements
, n_allocated
, n_elements
+ 1)) {
1578 r
= json_transform_one(m
, elements
+ n_elements
);
1585 r
= json_variant_new_array(ret
, elements
, n_elements
);
1588 json_variant_unref_many(elements
, n_elements
);
1594 static int json_transform_variant(sd_bus_message
*m
, const char *contents
, JsonVariant
**ret
) {
1595 _cleanup_(json_variant_unrefp
) JsonVariant
*value
= NULL
;
1602 r
= json_transform_one(m
, &value
);
1606 r
= json_build(ret
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(contents
)),
1607 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(value
))));
1614 static int json_transform_dict_array(sd_bus_message
*m
, JsonVariant
**ret
) {
1615 size_t n_elements
= 0, n_allocated
= 0;
1616 JsonVariant
**elements
= NULL
;
1623 const char *contents
;
1626 r
= sd_bus_message_at_end(m
, false);
1628 bus_log_parse_error(r
);
1634 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
1638 assert(type
== 'e');
1640 if (!GREEDY_REALLOC(elements
, n_allocated
, n_elements
+ 2)) {
1645 r
= sd_bus_message_enter_container(m
, type
, contents
);
1647 bus_log_parse_error(r
);
1651 r
= json_transform_one(m
, elements
+ n_elements
);
1657 r
= json_transform_one(m
, elements
+ n_elements
);
1663 r
= sd_bus_message_exit_container(m
);
1665 bus_log_parse_error(r
);
1670 r
= json_variant_new_object(ret
, elements
, n_elements
);
1673 json_variant_unref_many(elements
, n_elements
);
1679 static int json_transform_one(sd_bus_message
*m
, JsonVariant
**ret
) {
1680 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1681 const char *contents
;
1688 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
1690 return bus_log_parse_error(r
);
1694 case SD_BUS_TYPE_BYTE
: {
1697 r
= sd_bus_message_read_basic(m
, type
, &b
);
1699 return bus_log_parse_error(r
);
1701 r
= json_variant_new_unsigned(&v
, b
);
1703 return log_error_errno(r
, "Failed to transform byte: %m");
1708 case SD_BUS_TYPE_BOOLEAN
: {
1711 r
= sd_bus_message_read_basic(m
, type
, &b
);
1713 return bus_log_parse_error(r
);
1715 r
= json_variant_new_boolean(&v
, b
);
1717 return log_error_errno(r
, "Failed to transform boolean: %m");
1722 case SD_BUS_TYPE_INT16
: {
1725 r
= sd_bus_message_read_basic(m
, type
, &b
);
1727 return bus_log_parse_error(r
);
1729 r
= json_variant_new_integer(&v
, b
);
1731 return log_error_errno(r
, "Failed to transform int16: %m");
1736 case SD_BUS_TYPE_UINT16
: {
1739 r
= sd_bus_message_read_basic(m
, type
, &b
);
1741 return bus_log_parse_error(r
);
1743 r
= json_variant_new_unsigned(&v
, b
);
1745 return log_error_errno(r
, "Failed to transform uint16: %m");
1750 case SD_BUS_TYPE_INT32
: {
1753 r
= sd_bus_message_read_basic(m
, type
, &b
);
1755 return bus_log_parse_error(r
);
1757 r
= json_variant_new_integer(&v
, b
);
1759 return log_error_errno(r
, "Failed to transform int32: %m");
1764 case SD_BUS_TYPE_UINT32
: {
1767 r
= sd_bus_message_read_basic(m
, type
, &b
);
1769 return bus_log_parse_error(r
);
1771 r
= json_variant_new_unsigned(&v
, b
);
1773 return log_error_errno(r
, "Failed to transform uint32: %m");
1778 case SD_BUS_TYPE_INT64
: {
1781 r
= sd_bus_message_read_basic(m
, type
, &b
);
1783 return bus_log_parse_error(r
);
1785 r
= json_variant_new_integer(&v
, b
);
1787 return log_error_errno(r
, "Failed to transform int64: %m");
1792 case SD_BUS_TYPE_UINT64
: {
1795 r
= sd_bus_message_read_basic(m
, type
, &b
);
1797 return bus_log_parse_error(r
);
1799 r
= json_variant_new_unsigned(&v
, b
);
1801 return log_error_errno(r
, "Failed to transform uint64: %m");
1806 case SD_BUS_TYPE_DOUBLE
: {
1809 r
= sd_bus_message_read_basic(m
, type
, &d
);
1811 return bus_log_parse_error(r
);
1813 r
= json_variant_new_real(&v
, d
);
1815 return log_error_errno(r
, "Failed to transform double: %m");
1820 case SD_BUS_TYPE_STRING
:
1821 case SD_BUS_TYPE_OBJECT_PATH
:
1822 case SD_BUS_TYPE_SIGNATURE
: {
1825 r
= sd_bus_message_read_basic(m
, type
, &s
);
1827 return bus_log_parse_error(r
);
1829 r
= json_variant_new_string(&v
, s
);
1831 return log_error_errno(r
, "Failed to transform double: %m");
1836 case SD_BUS_TYPE_UNIX_FD
:
1837 r
= sd_bus_message_read_basic(m
, type
, NULL
);
1839 return bus_log_parse_error(r
);
1841 r
= json_variant_new_null(&v
);
1843 return log_error_errno(r
, "Failed to transform fd: %m");
1847 case SD_BUS_TYPE_ARRAY
:
1848 case SD_BUS_TYPE_VARIANT
:
1849 case SD_BUS_TYPE_STRUCT
:
1850 r
= sd_bus_message_enter_container(m
, type
, contents
);
1852 return bus_log_parse_error(r
);
1854 if (type
== SD_BUS_TYPE_VARIANT
)
1855 r
= json_transform_variant(m
, contents
, &v
);
1856 else if (type
== SD_BUS_TYPE_ARRAY
&& contents
[0] == '{')
1857 r
= json_transform_dict_array(m
, &v
);
1859 r
= json_transform_array_or_struct(m
, &v
);
1863 r
= sd_bus_message_exit_container(m
);
1865 return bus_log_parse_error(r
);
1870 assert_not_reached("Unexpected element type");
1877 static int json_transform_message(sd_bus_message
*m
, JsonVariant
**ret
) {
1878 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1885 assert_se(type
= sd_bus_message_get_signature(m
, false));
1887 r
= json_transform_array_or_struct(m
, &v
);
1891 r
= json_build(ret
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(type
)),
1892 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(v
))));
1899 static void json_dump_with_flags(JsonVariant
*v
, FILE *f
) {
1901 json_variant_dump(v
,
1902 (arg_json
== JSON_PRETTY
? JSON_FORMAT_PRETTY
: JSON_FORMAT_NEWLINE
) |
1903 colors_enabled() * JSON_FORMAT_COLOR
,
1907 static int call(int argc
, char **argv
, void *userdata
) {
1908 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1909 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1910 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1913 r
= acquire_bus(false, &bus
);
1917 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1919 return bus_log_create_error(r
);
1921 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1923 return bus_log_create_error(r
);
1925 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1927 return bus_log_create_error(r
);
1929 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1931 return bus_log_create_error(r
);
1933 if (!isempty(argv
[5])) {
1938 r
= message_append_cmdline(m
, argv
[5], &p
);
1943 log_error("Too many parameters for signature.");
1948 if (!arg_expect_reply
) {
1949 r
= sd_bus_send(bus
, m
, NULL
);
1951 return log_error_errno(r
, "Failed to send message: %m");
1956 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1958 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
1960 r
= sd_bus_message_is_empty(reply
);
1962 return bus_log_parse_error(r
);
1964 if (r
== 0 && !arg_quiet
) {
1966 if (arg_json
!= JSON_OFF
) {
1967 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
1969 if (arg_json
!= JSON_SHORT
)
1970 (void) pager_open(arg_no_pager
, false);
1972 r
= json_transform_message(reply
, &v
);
1976 json_dump_with_flags(v
, stdout
);
1978 } else if (arg_verbose
) {
1979 (void) pager_open(arg_no_pager
, false);
1981 r
= bus_message_dump(reply
, stdout
, 0);
1986 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1989 r
= format_cmdline(reply
, stdout
, false);
1991 return bus_log_parse_error(r
);
1993 fputc('\n', stdout
);
2000 static int get_property(int argc
, char **argv
, void *userdata
) {
2001 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2002 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2006 r
= acquire_bus(false, &bus
);
2010 STRV_FOREACH(i
, argv
+ 4) {
2011 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2012 const char *contents
= NULL
;
2015 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
2017 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
2019 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
2021 return bus_log_parse_error(r
);
2023 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
2025 return bus_log_parse_error(r
);
2027 if (arg_json
!= JSON_OFF
) {
2028 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
2030 if (arg_json
!= JSON_SHORT
)
2031 (void) pager_open(arg_no_pager
, false);
2033 r
= json_transform_variant(reply
, contents
, &v
);
2037 json_dump_with_flags(v
, stdout
);
2039 } else if (arg_verbose
) {
2040 (void) pager_open(arg_no_pager
, false);
2042 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
2046 fputs(contents
, stdout
);
2049 r
= format_cmdline(reply
, stdout
, false);
2051 return bus_log_parse_error(r
);
2053 fputc('\n', stdout
);
2056 r
= sd_bus_message_exit_container(reply
);
2058 return bus_log_parse_error(r
);
2064 static int set_property(int argc
, char **argv
, void *userdata
) {
2065 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2066 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2067 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2071 r
= acquire_bus(false, &bus
);
2075 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
2077 return bus_log_create_error(r
);
2079 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
2081 return bus_log_create_error(r
);
2083 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
2085 return bus_log_create_error(r
);
2088 r
= message_append_cmdline(m
, argv
[5], &p
);
2092 r
= sd_bus_message_close_container(m
);
2094 return bus_log_create_error(r
);
2097 log_error("Too many parameters for signature.");
2101 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
2103 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
2108 static int help(void) {
2109 _cleanup_free_
char *link
= NULL
;
2112 r
= terminal_urlify_man("busctl", "1", &link
);
2116 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
2117 "Introspect the bus.\n\n"
2118 " -h --help Show this help\n"
2119 " --version Show package version\n"
2120 " --no-pager Do not pipe output into a pager\n"
2121 " --no-legend Do not show the headers and footers\n"
2122 " --system Connect to system bus\n"
2123 " --user Connect to user bus\n"
2124 " -H --host=[USER@]HOST Operate on remote host\n"
2125 " -M --machine=CONTAINER Operate on local container\n"
2126 " --address=ADDRESS Connect to bus specified by address\n"
2127 " --show-machine Show machine ID column in list\n"
2128 " --unique Only show unique names\n"
2129 " --acquired Only show acquired names\n"
2130 " --activatable Only show activatable names\n"
2131 " --match=MATCH Only show matching messages\n"
2132 " --size=SIZE Maximum length of captured packet\n"
2133 " --list Don't show tree, but simple object path list\n"
2134 " -q --quiet Don't show method call reply\n"
2135 " --verbose Show result values in long format\n"
2136 " --json=MODE Output as JSON\n"
2137 " -j Same as --json=pretty on tty, --json=short otherwise\n"
2138 " --expect-reply=BOOL Expect a method call reply\n"
2139 " --auto-start=BOOL Auto-start destination service\n"
2140 " --allow-interactive-authorization=BOOL\n"
2141 " Allow interactive authorization for operation\n"
2142 " --timeout=SECS Maximum time to wait for method call completion\n"
2143 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
2144 " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n"
2147 " list List bus names\n"
2148 " status [SERVICE] Show bus service, process or bus owner credentials\n"
2149 " monitor [SERVICE...] Show bus traffic\n"
2150 " capture [SERVICE...] Capture bus traffic as pcap\n"
2151 " tree [SERVICE...] Show object tree of service\n"
2152 " introspect SERVICE OBJECT [INTERFACE]\n"
2153 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
2155 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
2156 " Get property value\n"
2157 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
2158 " Set property value\n"
2159 " help Show this help\n"
2160 "\nSee the %s for details.\n"
2161 , program_invocation_short_name
2168 static int verb_help(int argc
, char **argv
, void *userdata
) {
2172 static int parse_argv(int argc
, char *argv
[]) {
2175 ARG_VERSION
= 0x100,
2191 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
2198 static const struct option options
[] = {
2199 { "help", no_argument
, NULL
, 'h' },
2200 { "version", no_argument
, NULL
, ARG_VERSION
},
2201 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
2202 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
2203 { "system", no_argument
, NULL
, ARG_SYSTEM
},
2204 { "user", no_argument
, NULL
, ARG_USER
},
2205 { "address", required_argument
, NULL
, ARG_ADDRESS
},
2206 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
2207 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
2208 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
2209 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
2210 { "match", required_argument
, NULL
, ARG_MATCH
},
2211 { "host", required_argument
, NULL
, 'H' },
2212 { "machine", required_argument
, NULL
, 'M' },
2213 { "size", required_argument
, NULL
, ARG_SIZE
},
2214 { "list", no_argument
, NULL
, ARG_LIST
},
2215 { "quiet", no_argument
, NULL
, 'q' },
2216 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
2217 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
2218 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
2219 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
2220 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
2221 { "augment-creds", required_argument
, NULL
, ARG_AUGMENT_CREDS
},
2222 { "watch-bind", required_argument
, NULL
, ARG_WATCH_BIND
},
2223 { "json", required_argument
, NULL
, ARG_JSON
},
2232 while ((c
= getopt_long(argc
, argv
, "hH:M:qj", options
, NULL
)) >= 0)
2243 arg_no_pager
= true;
2259 arg_address
= optarg
;
2262 case ARG_SHOW_MACHINE
:
2263 arg_show_machine
= true;
2271 arg_acquired
= true;
2274 case ARG_ACTIVATABLE
:
2275 arg_activatable
= true;
2279 if (strv_extend(&arg_matches
, optarg
) < 0)
2286 r
= parse_size(optarg
, 1024, &sz
);
2288 return log_error_errno(r
, "Failed to parse size: %s", optarg
);
2290 if ((uint64_t) (size_t) sz
!= sz
) {
2291 log_error("Size out of range.");
2295 arg_snaplen
= (size_t) sz
;
2304 arg_transport
= BUS_TRANSPORT_REMOTE
;
2309 arg_transport
= BUS_TRANSPORT_MACHINE
;
2321 case ARG_EXPECT_REPLY
:
2322 r
= parse_boolean(optarg
);
2324 return log_error_errno(r
, "Failed to parse --expect-reply= parameter: %s", optarg
);
2326 arg_expect_reply
= r
;
2329 case ARG_AUTO_START
:
2330 r
= parse_boolean(optarg
);
2332 return log_error_errno(r
, "Failed to parse --auto-start= parameter: %s", optarg
);
2337 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
2338 r
= parse_boolean(optarg
);
2340 return log_error_errno(r
, "Failed to parse --allow-interactive-authorization= parameter: %s", optarg
);
2342 arg_allow_interactive_authorization
= r
;
2346 r
= parse_sec(optarg
, &arg_timeout
);
2348 return log_error_errno(r
, "Failed to parse --timeout= parameter: %s", optarg
);
2352 case ARG_AUGMENT_CREDS
:
2353 r
= parse_boolean(optarg
);
2355 return log_error_errno(r
, "Failed to parse --augment-creds= parameter: %s", optarg
);
2357 arg_augment_creds
= r
;
2360 case ARG_WATCH_BIND
:
2361 r
= parse_boolean(optarg
);
2363 return log_error_errno(r
, "Failed to parse --watch-bind= parameter: %s", optarg
);
2370 arg_json
= JSON_PRETTY
;
2372 arg_json
= JSON_SHORT
;
2376 if (streq(optarg
, "short"))
2377 arg_json
= JSON_SHORT
;
2378 else if (streq(optarg
, "pretty"))
2379 arg_json
= JSON_PRETTY
;
2380 else if (streq(optarg
, "help")) {
2382 "pretty\n", stdout
);
2385 log_error("Unknown JSON out mode: %s", optarg
);
2395 assert_not_reached("Unhandled option");
2401 static int busctl_main(int argc
, char *argv
[]) {
2403 static const Verb verbs
[] = {
2404 { "list", VERB_ANY
, 1, VERB_DEFAULT
, list_bus_names
},
2405 { "status", VERB_ANY
, 2, 0, status
},
2406 { "monitor", VERB_ANY
, VERB_ANY
, 0, verb_monitor
},
2407 { "capture", VERB_ANY
, VERB_ANY
, 0, verb_capture
},
2408 { "tree", VERB_ANY
, VERB_ANY
, 0, tree
},
2409 { "introspect", 3, 4, 0, introspect
},
2410 { "call", 5, VERB_ANY
, 0, call
},
2411 { "get-property", 5, VERB_ANY
, 0, get_property
},
2412 { "set-property", 6, VERB_ANY
, 0, set_property
},
2413 { "help", VERB_ANY
, VERB_ANY
, 0, verb_help
},
2417 return dispatch_verb(argc
, argv
, verbs
, NULL
);
2420 int main(int argc
, char *argv
[]) {
2423 log_parse_environment();
2426 r
= parse_argv(argc
, argv
);
2430 r
= busctl_main(argc
, argv
);
2433 /* make sure we terminate the bus connection first, and then close the
2434 * pager, see issue #3543 for the details. */
2437 arg_matches
= strv_free(arg_matches
);
2439 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;