1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "bus-internal.h"
28 #include "bus-signature.h"
31 #include "busctl-introspect.h"
36 #include "path-util.h"
39 #include "terminal-util.h"
42 static bool arg_no_pager
= false;
43 static bool arg_legend
= true;
44 static char *arg_address
= NULL
;
45 static bool arg_unique
= false;
46 static bool arg_acquired
= false;
47 static bool arg_activatable
= false;
48 static bool arg_show_machine
= false;
49 static char **arg_matches
= NULL
;
50 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
51 static char *arg_host
= NULL
;
52 static bool arg_user
= false;
53 static size_t arg_snaplen
= 4096;
54 static bool arg_list
= false;
55 static bool arg_quiet
= false;
56 static bool arg_verbose
= 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 usec_t arg_timeout
= 0;
63 static void pager_open_if_enabled(void) {
65 /* Cache result before we open the pager */
72 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
73 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
75 static int list_bus_names(sd_bus
*bus
, char **argv
) {
76 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
77 _cleanup_free_
char **merged
= NULL
;
78 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
89 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
90 arg_unique
= arg_acquired
= arg_activatable
= true;
92 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
94 return log_error_errno(r
, "Failed to list names: %m");
96 pager_open_if_enabled();
98 names
= hashmap_new(&string_hash_ops
);
102 STRV_FOREACH(i
, acquired
) {
103 max_i
= MAX(max_i
, strlen(*i
));
105 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
107 return log_error_errno(r
, "Failed to add to hashmap: %m");
110 STRV_FOREACH(i
, activatable
) {
111 max_i
= MAX(max_i
, strlen(*i
));
113 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
114 if (r
< 0 && r
!= -EEXIST
)
115 return log_error_errno(r
, "Failed to add to hashmap: %m");
118 merged
= new(char*, hashmap_size(names
) + 1);
119 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
126 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
127 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
129 if (arg_show_machine
)
135 STRV_FOREACH(i
, merged
) {
136 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
139 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
142 printf("%-*s", (int) max_i
, *i
);
143 printf(" - - - (activatable) - - ");
144 if (arg_show_machine
)
152 if (!arg_unique
&& (*i
)[0] == ':')
155 if (!arg_acquired
&& (*i
)[0] != ':')
158 printf("%-*s", (int) max_i
, *i
);
160 r
= sd_bus_get_name_creds(
162 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
163 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
164 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
165 SD_BUS_CREDS_DESCRIPTION
, &creds
);
167 const char *unique
, *session
, *unit
, *cn
;
171 r
= sd_bus_creds_get_pid(creds
, &pid
);
173 const char *comm
= NULL
;
175 sd_bus_creds_get_comm(creds
, &comm
);
177 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
179 fputs(" - - ", stdout
);
181 r
= sd_bus_creds_get_euid(creds
, &uid
);
183 _cleanup_free_
char *u
= NULL
;
185 u
= uid_to_name(uid
);
194 fputs(" - ", stdout
);
196 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
198 printf(" %-13s", unique
);
200 fputs(" - ", stdout
);
202 r
= sd_bus_creds_get_unit(creds
, &unit
);
204 _cleanup_free_
char *e
;
206 e
= ellipsize(unit
, 25, 100);
212 fputs(" - ", stdout
);
214 r
= sd_bus_creds_get_session(creds
, &session
);
216 printf(" %-10s", session
);
218 fputs(" - ", stdout
);
220 r
= sd_bus_creds_get_description(creds
, &cn
);
222 printf(" %-19s", cn
);
224 fputs(" - ", stdout
);
227 printf(" - - - - - - - ");
229 if (arg_show_machine
) {
230 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
232 char m
[SD_ID128_STRING_MAX
];
233 printf(" %s\n", sd_id128_to_string(mid
, m
));
243 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
244 const char *vertical
, *space
;
247 /* We assume the list is sorted. Let's first skip over the
248 * entry we are looking at. */
253 if (!streq(*l
, path
))
259 vertical
= strjoina(prefix
, draw_special_char(DRAW_TREE_VERTICAL
));
260 space
= strjoina(prefix
, draw_special_char(DRAW_TREE_SPACE
));
263 bool has_more
= false;
265 if (!*l
|| !path_startswith(*l
, path
))
270 if (!*n
|| !path_startswith(*n
, path
))
273 if (!path_startswith(*n
, *l
)) {
281 printf("%s%s%s\n", prefix
, draw_special_char(has_more
? DRAW_TREE_BRANCH
: DRAW_TREE_RIGHT
), *l
);
283 print_subtree(has_more
? vertical
: space
, *l
, l
);
288 static void print_tree(const char *prefix
, char **l
) {
290 pager_open_if_enabled();
292 prefix
= strempty(prefix
);
298 printf("%s%s\n", prefix
, *i
);
302 if (strv_isempty(l
)) {
303 printf("No objects discovered.\n");
307 if (streq(l
[0], "/") && !l
[1]) {
308 printf("Only root object discovered.\n");
312 print_subtree(prefix
, "/", l
);
315 static int on_path(const char *path
, void *userdata
) {
316 Set
*paths
= userdata
;
321 r
= set_put_strdup(paths
, path
);
328 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
329 static const XMLIntrospectOps ops
= {
333 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
334 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
338 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
341 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
343 log_error("Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
347 r
= sd_bus_message_read(reply
, "s", &xml
);
349 return bus_log_parse_error(r
);
351 return parse_xml_introspect(path
, xml
, &ops
, paths
);
354 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
355 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
356 _cleanup_free_
char **l
= NULL
;
360 paths
= set_new(&string_hash_ops
);
364 done
= set_new(&string_hash_ops
);
368 failed
= set_new(&string_hash_ops
);
376 r
= set_put(paths
, m
);
383 _cleanup_free_
char *p
= NULL
;
386 p
= set_steal_first(paths
);
390 if (set_contains(done
, p
) ||
391 set_contains(failed
, p
))
394 q
= find_nodes(bus
, service
, p
, paths
, many
);
399 q
= set_put(failed
, p
);
401 q
= set_put(done
, p
);
410 pager_open_if_enabled();
412 l
= set_get_strv(done
);
417 print_tree(prefix
, l
);
424 static int tree(sd_bus
*bus
, char **argv
) {
428 if (!arg_unique
&& !arg_acquired
)
431 if (strv_length(argv
) <= 1) {
432 _cleanup_strv_free_
char **names
= NULL
;
433 bool not_first
= false;
435 r
= sd_bus_list_names(bus
, &names
, NULL
);
437 return log_error_errno(r
, "Failed to get name list: %m");
439 pager_open_if_enabled();
441 STRV_FOREACH(i
, names
) {
444 if (!arg_unique
&& (*i
)[0] == ':')
447 if (!arg_acquired
&& (*i
)[0] == ':')
453 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
455 q
= tree_one(bus
, *i
, NULL
, true);
462 STRV_FOREACH(i
, argv
+1) {
469 pager_open_if_enabled();
470 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
473 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
482 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
486 const char *contents
= NULL
;
501 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
505 if (bus_type_is_container(type
) > 0) {
507 r
= sd_bus_message_enter_container(m
, type
, contents
);
511 if (type
== SD_BUS_TYPE_ARRAY
) {
514 /* count array entries */
517 r
= sd_bus_message_skip(m
, contents
);
526 r
= sd_bus_message_rewind(m
, false);
534 } else if (type
== SD_BUS_TYPE_VARIANT
) {
539 fprintf(f
, "%s", contents
);
542 r
= format_cmdline(m
, f
, needs_space
|| IN_SET(type
, SD_BUS_TYPE_ARRAY
, SD_BUS_TYPE_VARIANT
));
546 r
= sd_bus_message_exit_container(m
);
553 r
= sd_bus_message_read_basic(m
, type
, &basic
);
561 case SD_BUS_TYPE_BYTE
:
562 fprintf(f
, "%u", basic
.u8
);
565 case SD_BUS_TYPE_BOOLEAN
:
566 fputs(true_false(basic
.i
), f
);
569 case SD_BUS_TYPE_INT16
:
570 fprintf(f
, "%i", basic
.s16
);
573 case SD_BUS_TYPE_UINT16
:
574 fprintf(f
, "%u", basic
.u16
);
577 case SD_BUS_TYPE_INT32
:
578 fprintf(f
, "%i", basic
.s32
);
581 case SD_BUS_TYPE_UINT32
:
582 fprintf(f
, "%u", basic
.u32
);
585 case SD_BUS_TYPE_INT64
:
586 fprintf(f
, "%" PRIi64
, basic
.s64
);
589 case SD_BUS_TYPE_UINT64
:
590 fprintf(f
, "%" PRIu64
, basic
.u64
);
593 case SD_BUS_TYPE_DOUBLE
:
594 fprintf(f
, "%g", basic
.d64
);
597 case SD_BUS_TYPE_STRING
:
598 case SD_BUS_TYPE_OBJECT_PATH
:
599 case SD_BUS_TYPE_SIGNATURE
: {
600 _cleanup_free_
char *b
= NULL
;
602 b
= cescape(basic
.string
);
606 fprintf(f
, "\"%s\"", b
);
610 case SD_BUS_TYPE_UNIX_FD
:
611 fprintf(f
, "%i", basic
.i
);
615 assert_not_reached("Unknown basic type.");
622 typedef struct Member
{
633 static void member_hash_func(const void *p
, struct siphash
*state
) {
640 string_hash_func(m
->type
, state
);
642 arity
+= !!m
->name
+ !!m
->interface
;
644 uint64_hash_func(&arity
, state
);
647 string_hash_func(m
->name
, state
);
650 string_hash_func(m
->interface
, state
);
653 static int member_compare_func(const void *a
, const void *b
) {
654 const Member
*x
= a
, *y
= b
;
662 d
= strcmp_ptr(x
->interface
, y
->interface
);
666 d
= strcmp(x
->type
, y
->type
);
670 return strcmp_ptr(x
->name
, y
->name
);
673 static int member_compare_funcp(const void *a
, const void *b
) {
674 const Member
*const * x
= (const Member
*const *) a
, * const *y
= (const Member
*const *) b
;
676 return member_compare_func(*x
, *y
);
679 static void member_free(Member
*m
) {
691 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
693 static void member_set_free(Set
*s
) {
696 while ((m
= set_steal_first(s
)))
702 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
704 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
705 _cleanup_(member_freep
) Member
*m
;
706 Set
*members
= userdata
;
716 m
->type
= "interface";
719 r
= free_and_strdup(&m
->interface
, interface
);
723 r
= set_put(members
, m
);
725 log_error("Duplicate interface");
733 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
734 _cleanup_(member_freep
) Member
*m
;
735 Set
*members
= userdata
;
748 r
= free_and_strdup(&m
->interface
, interface
);
752 r
= free_and_strdup(&m
->name
, name
);
756 r
= free_and_strdup(&m
->signature
, signature
);
760 r
= free_and_strdup(&m
->result
, result
);
764 r
= set_put(members
, m
);
766 log_error("Duplicate method");
774 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
775 _cleanup_(member_freep
) Member
*m
;
776 Set
*members
= userdata
;
789 r
= free_and_strdup(&m
->interface
, interface
);
793 r
= free_and_strdup(&m
->name
, name
);
797 r
= free_and_strdup(&m
->signature
, signature
);
801 r
= set_put(members
, m
);
803 log_error("Duplicate signal");
811 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
812 _cleanup_(member_freep
) Member
*m
;
813 Set
*members
= userdata
;
823 m
->type
= "property";
825 m
->writable
= writable
;
827 r
= free_and_strdup(&m
->interface
, interface
);
831 r
= free_and_strdup(&m
->name
, name
);
835 r
= free_and_strdup(&m
->signature
, signature
);
839 r
= set_put(members
, m
);
841 log_error("Duplicate property");
849 static const char *strdash(const char *x
) {
850 return isempty(x
) ? "-" : x
;
853 static int introspect(sd_bus
*bus
, char **argv
) {
854 static const struct hash_ops member_hash_ops
= {
855 .hash
= member_hash_func
,
856 .compare
= member_compare_func
,
859 static const XMLIntrospectOps ops
= {
860 .on_interface
= on_interface
,
861 .on_method
= on_method
,
862 .on_signal
= on_signal
,
863 .on_property
= on_property
,
866 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
867 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
868 _cleanup_(member_set_freep
) Set
*members
= NULL
;
873 unsigned name_width
, type_width
, signature_width
, result_width
;
874 Member
**sorted
= NULL
;
875 unsigned k
= 0, j
, n_args
;
877 n_args
= strv_length(argv
);
879 log_error("Requires service and object path argument.");
884 log_error("Too many arguments.");
888 members
= set_new(&member_hash_ops
);
892 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
894 log_error("Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
898 r
= sd_bus_message_read(reply
, "s", &xml
);
900 return bus_log_parse_error(r
);
902 /* First, get list of all properties */
903 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
907 /* Second, find the current values for them */
908 SET_FOREACH(m
, members
, i
) {
910 if (!streq(m
->type
, "property"))
916 if (argv
[3] && !streq(argv
[3], m
->interface
))
919 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
921 log_error("%s", bus_error_message(&error
, r
));
925 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
927 return bus_log_parse_error(r
);
931 _cleanup_free_
char *buf
= NULL
;
932 _cleanup_fclose_
FILE *mf
= NULL
;
936 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
938 return bus_log_parse_error(r
);
943 r
= sd_bus_message_read(reply
, "s", &name
);
945 return bus_log_parse_error(r
);
947 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
949 return bus_log_parse_error(r
);
951 mf
= open_memstream(&buf
, &sz
);
955 r
= format_cmdline(reply
, mf
, false);
957 return bus_log_parse_error(r
);
962 z
= set_get(members
, &((Member
) {
964 .interface
= m
->interface
,
965 .name
= (char*) name
}));
972 r
= sd_bus_message_exit_container(reply
);
974 return bus_log_parse_error(r
);
976 r
= sd_bus_message_exit_container(reply
);
978 return bus_log_parse_error(r
);
981 r
= sd_bus_message_exit_container(reply
);
983 return bus_log_parse_error(r
);
986 pager_open_if_enabled();
988 name_width
= strlen("NAME");
989 type_width
= strlen("TYPE");
990 signature_width
= strlen("SIGNATURE");
991 result_width
= strlen("RESULT/VALUE");
993 sorted
= newa(Member
*, set_size(members
));
995 SET_FOREACH(m
, members
, i
) {
997 if (argv
[3] && !streq(argv
[3], m
->interface
))
1001 name_width
= MAX(name_width
, strlen(m
->interface
));
1003 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1005 type_width
= MAX(type_width
, strlen(m
->type
));
1007 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1009 result_width
= MAX(result_width
, strlen(m
->result
));
1011 result_width
= MAX(result_width
, strlen(m
->value
));
1016 if (result_width
> 40)
1019 qsort(sorted
, k
, sizeof(Member
*), member_compare_funcp
);
1022 printf("%-*s %-*s %-*s %-*s %s\n",
1023 (int) name_width
, "NAME",
1024 (int) type_width
, "TYPE",
1025 (int) signature_width
, "SIGNATURE",
1026 (int) result_width
, "RESULT/VALUE",
1030 for (j
= 0; j
< k
; j
++) {
1031 _cleanup_free_
char *ellipsized
= NULL
;
1037 if (argv
[3] && !streq(argv
[3], m
->interface
))
1040 is_interface
= streq(m
->type
, "interface");
1042 if (argv
[3] && is_interface
)
1046 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1052 rv
= strdash(m
->result
);
1054 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1055 is_interface
? ansi_highlight() : "",
1056 is_interface
? "" : ".",
1057 - !is_interface
+ (int) name_width
, strdash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1058 is_interface
? ansi_normal() : "",
1059 (int) type_width
, strdash(m
->type
),
1060 (int) signature_width
, strdash(m
->signature
),
1061 (int) result_width
, rv
,
1062 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1063 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1064 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1065 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1066 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1067 m
->writable
? " writable" : "");
1073 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1074 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1077 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1078 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1081 static int monitor(sd_bus
*bus
, char *argv
[], int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1082 bool added_something
= false;
1086 STRV_FOREACH(i
, argv
+1) {
1087 _cleanup_free_
char *m
= NULL
;
1089 if (!service_name_is_valid(*i
)) {
1090 log_error("Invalid service name '%s'", *i
);
1094 m
= strjoin("sender='", *i
, "'", NULL
);
1098 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1100 return log_error_errno(r
, "Failed to add match: %m");
1103 m
= strjoin("destination='", *i
, "'", NULL
);
1107 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1109 return log_error_errno(r
, "Failed to add match: %m");
1111 added_something
= true;
1114 STRV_FOREACH(i
, arg_matches
) {
1115 r
= sd_bus_add_match(bus
, NULL
, *i
, NULL
, NULL
);
1117 return log_error_errno(r
, "Failed to add match: %m");
1119 added_something
= true;
1122 if (!added_something
) {
1123 r
= sd_bus_add_match(bus
, NULL
, "", NULL
, NULL
);
1125 return log_error_errno(r
, "Failed to add match: %m");
1128 log_info("Monitoring bus message stream.");
1131 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1133 r
= sd_bus_process(bus
, &m
);
1135 return log_error_errno(r
, "Failed to process bus: %m");
1141 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1142 log_info("Connection terminated, exiting.");
1152 r
= sd_bus_wait(bus
, (uint64_t) -1);
1154 return log_error_errno(r
, "Failed to wait for bus: %m");
1158 static int capture(sd_bus
*bus
, char *argv
[]) {
1161 if (isatty(fileno(stdout
)) > 0) {
1162 log_error("Refusing to write message data to console, please redirect output to a file.");
1166 bus_pcap_header(arg_snaplen
, stdout
);
1168 r
= monitor(bus
, argv
, message_pcap
);
1172 if (ferror(stdout
)) {
1173 log_error("Couldn't write capture file.");
1180 static int status(sd_bus
*bus
, char *argv
[]) {
1181 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1187 if (strv_length(argv
) > 2) {
1188 log_error("Expects no or one argument.");
1193 r
= parse_pid(argv
[1], &pid
);
1195 r
= sd_bus_get_name_creds(
1198 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1201 r
= sd_bus_creds_new_from_pid(
1206 const char *scope
, *address
;
1209 r
= sd_bus_get_address(bus
, &address
);
1211 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1213 r
= sd_bus_get_scope(bus
, &scope
);
1215 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1217 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1219 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1221 r
= sd_bus_get_owner_creds(
1223 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1228 return log_error_errno(r
, "Failed to get credentials: %m");
1230 bus_creds_dump(creds
, NULL
, false);
1234 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1254 log_error("Too few parameters for signature.");
1263 case SD_BUS_TYPE_BOOLEAN
:
1265 r
= parse_boolean(v
);
1267 log_error("Failed to parse as boolean: %s", v
);
1271 r
= sd_bus_message_append_basic(m
, t
, &r
);
1274 case SD_BUS_TYPE_BYTE
: {
1277 r
= safe_atou8(v
, &z
);
1279 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1283 r
= sd_bus_message_append_basic(m
, t
, &z
);
1287 case SD_BUS_TYPE_INT16
: {
1290 r
= safe_atoi16(v
, &z
);
1292 log_error("Failed to parse as signed 16bit integer: %s", v
);
1296 r
= sd_bus_message_append_basic(m
, t
, &z
);
1300 case SD_BUS_TYPE_UINT16
: {
1303 r
= safe_atou16(v
, &z
);
1305 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1309 r
= sd_bus_message_append_basic(m
, t
, &z
);
1313 case SD_BUS_TYPE_INT32
: {
1316 r
= safe_atoi32(v
, &z
);
1318 log_error("Failed to parse as signed 32bit integer: %s", v
);
1322 r
= sd_bus_message_append_basic(m
, t
, &z
);
1326 case SD_BUS_TYPE_UINT32
: {
1329 r
= safe_atou32(v
, &z
);
1331 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1335 r
= sd_bus_message_append_basic(m
, t
, &z
);
1339 case SD_BUS_TYPE_INT64
: {
1342 r
= safe_atoi64(v
, &z
);
1344 log_error("Failed to parse as signed 64bit integer: %s", v
);
1348 r
= sd_bus_message_append_basic(m
, t
, &z
);
1352 case SD_BUS_TYPE_UINT64
: {
1355 r
= safe_atou64(v
, &z
);
1357 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1361 r
= sd_bus_message_append_basic(m
, t
, &z
);
1366 case SD_BUS_TYPE_DOUBLE
: {
1369 r
= safe_atod(v
, &z
);
1371 log_error("Failed to parse as double precision floating point: %s", v
);
1375 r
= sd_bus_message_append_basic(m
, t
, &z
);
1379 case SD_BUS_TYPE_STRING
:
1380 case SD_BUS_TYPE_OBJECT_PATH
:
1381 case SD_BUS_TYPE_SIGNATURE
:
1383 r
= sd_bus_message_append_basic(m
, t
, v
);
1386 case SD_BUS_TYPE_ARRAY
: {
1390 r
= safe_atou32(v
, &n
);
1392 log_error("Failed to parse number of array entries: %s", v
);
1396 r
= signature_element_length(signature
, &k
);
1398 log_error("Invalid array signature.");
1405 memcpy(s
, signature
, k
);
1408 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1410 return bus_log_create_error(r
);
1412 for (i
= 0; i
< n
; i
++) {
1413 r
= message_append_cmdline(m
, s
, &p
);
1421 r
= sd_bus_message_close_container(m
);
1425 case SD_BUS_TYPE_VARIANT
:
1426 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1428 return bus_log_create_error(r
);
1430 r
= message_append_cmdline(m
, v
, &p
);
1434 r
= sd_bus_message_close_container(m
);
1437 case SD_BUS_TYPE_STRUCT_BEGIN
:
1438 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1444 r
= signature_element_length(signature
, &k
);
1446 log_error("Invalid struct/dict entry signature.");
1452 memcpy(s
, signature
+ 1, k
- 2);
1455 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1457 return bus_log_create_error(r
);
1459 r
= message_append_cmdline(m
, s
, &p
);
1466 r
= sd_bus_message_close_container(m
);
1470 case SD_BUS_TYPE_UNIX_FD
:
1471 log_error("UNIX file descriptor not supported as type.");
1475 log_error("Unknown signature type %c.", t
);
1480 return bus_log_create_error(r
);
1487 static int call(sd_bus
*bus
, char *argv
[]) {
1488 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1489 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1494 if (strv_length(argv
) < 5) {
1495 log_error("Expects at least four arguments.");
1499 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1501 return bus_log_create_error(r
);
1503 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1505 return bus_log_create_error(r
);
1507 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1509 return bus_log_create_error(r
);
1511 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1513 return bus_log_create_error(r
);
1515 if (!isempty(argv
[5])) {
1520 r
= message_append_cmdline(m
, argv
[5], &p
);
1525 log_error("Too many parameters for signature.");
1530 if (!arg_expect_reply
) {
1531 r
= sd_bus_send(bus
, m
, NULL
);
1533 log_error("Failed to send message.");
1540 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1542 log_error("%s", bus_error_message(&error
, r
));
1546 r
= sd_bus_message_is_empty(reply
);
1548 return bus_log_parse_error(r
);
1550 if (r
== 0 && !arg_quiet
) {
1553 pager_open_if_enabled();
1555 r
= bus_message_dump(reply
, stdout
, 0);
1560 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1563 r
= format_cmdline(reply
, stdout
, false);
1565 return bus_log_parse_error(r
);
1567 fputc('\n', stdout
);
1574 static int get_property(sd_bus
*bus
, char *argv
[]) {
1575 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1582 n
= strv_length(argv
);
1584 log_error("Expects at least four arguments.");
1588 STRV_FOREACH(i
, argv
+ 4) {
1589 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1590 const char *contents
= NULL
;
1593 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1595 log_error("%s", bus_error_message(&error
, r
));
1599 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1601 return bus_log_parse_error(r
);
1603 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1605 return bus_log_parse_error(r
);
1608 pager_open_if_enabled();
1610 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1614 fputs(contents
, stdout
);
1617 r
= format_cmdline(reply
, stdout
, false);
1619 return bus_log_parse_error(r
);
1621 fputc('\n', stdout
);
1624 r
= sd_bus_message_exit_container(reply
);
1626 return bus_log_parse_error(r
);
1632 static int set_property(sd_bus
*bus
, char *argv
[]) {
1633 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1634 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1641 n
= strv_length(argv
);
1643 log_error("Expects at least five arguments.");
1647 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1649 return bus_log_create_error(r
);
1651 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1653 return bus_log_create_error(r
);
1655 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1657 return bus_log_create_error(r
);
1660 r
= message_append_cmdline(m
, argv
[5], &p
);
1664 r
= sd_bus_message_close_container(m
);
1666 return bus_log_create_error(r
);
1669 log_error("Too many parameters for signature.");
1673 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1675 log_error("%s", bus_error_message(&error
, r
));
1682 static int help(void) {
1683 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1684 "Introspect the bus.\n\n"
1685 " -h --help Show this help\n"
1686 " --version Show package version\n"
1687 " --no-pager Do not pipe output into a pager\n"
1688 " --no-legend Do not show the headers and footers\n"
1689 " --system Connect to system bus\n"
1690 " --user Connect to user bus\n"
1691 " -H --host=[USER@]HOST Operate on remote host\n"
1692 " -M --machine=CONTAINER Operate on local container\n"
1693 " --address=ADDRESS Connect to bus specified by address\n"
1694 " --show-machine Show machine ID column in list\n"
1695 " --unique Only show unique names\n"
1696 " --acquired Only show acquired names\n"
1697 " --activatable Only show activatable names\n"
1698 " --match=MATCH Only show matching messages\n"
1699 " --size=SIZE Maximum length of captured packet\n"
1700 " --list Don't show tree, but simple object path list\n"
1701 " --quiet Don't show method call reply\n"
1702 " --verbose Show result values in long format\n"
1703 " --expect-reply=BOOL Expect a method call reply\n"
1704 " --auto-start=BOOL Auto-start destination service\n"
1705 " --allow-interactive-authorization=BOOL\n"
1706 " Allow interactive authorization for operation\n"
1707 " --timeout=SECS Maximum time to wait for method call completion\n"
1708 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1710 " list List bus names\n"
1711 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1712 " monitor [SERVICE...] Show bus traffic\n"
1713 " capture [SERVICE...] Capture bus traffic as pcap\n"
1714 " tree [SERVICE...] Show object tree of service\n"
1715 " introspect SERVICE OBJECT [INTERFACE]\n"
1716 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1718 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1719 " Get property value\n"
1720 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1721 " Set property value\n"
1722 " help Show this help\n"
1723 , program_invocation_short_name
);
1728 static int parse_argv(int argc
, char *argv
[]) {
1731 ARG_VERSION
= 0x100,
1747 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1752 static const struct option options
[] = {
1753 { "help", no_argument
, NULL
, 'h' },
1754 { "version", no_argument
, NULL
, ARG_VERSION
},
1755 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1756 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1757 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1758 { "user", no_argument
, NULL
, ARG_USER
},
1759 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1760 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1761 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1762 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1763 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1764 { "match", required_argument
, NULL
, ARG_MATCH
},
1765 { "host", required_argument
, NULL
, 'H' },
1766 { "machine", required_argument
, NULL
, 'M' },
1767 { "size", required_argument
, NULL
, ARG_SIZE
},
1768 { "list", no_argument
, NULL
, ARG_LIST
},
1769 { "quiet", no_argument
, NULL
, 'q' },
1770 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1771 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1772 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1773 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1774 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1775 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1784 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1795 arg_no_pager
= true;
1811 arg_address
= optarg
;
1814 case ARG_SHOW_MACHINE
:
1815 arg_show_machine
= true;
1823 arg_acquired
= true;
1826 case ARG_ACTIVATABLE
:
1827 arg_activatable
= true;
1831 if (strv_extend(&arg_matches
, optarg
) < 0)
1838 r
= parse_size(optarg
, 1024, &sz
);
1840 log_error("Failed to parse size: %s", optarg
);
1844 if ((uint64_t) (size_t) sz
!= sz
) {
1845 log_error("Size out of range.");
1849 arg_snaplen
= (size_t) sz
;
1858 arg_transport
= BUS_TRANSPORT_REMOTE
;
1863 arg_transport
= BUS_TRANSPORT_MACHINE
;
1875 case ARG_EXPECT_REPLY
:
1876 r
= parse_boolean(optarg
);
1878 log_error("Failed to parse --expect-reply= parameter.");
1882 arg_expect_reply
= !!r
;
1886 case ARG_AUTO_START
:
1887 r
= parse_boolean(optarg
);
1889 log_error("Failed to parse --auto-start= parameter.");
1893 arg_auto_start
= !!r
;
1897 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1898 r
= parse_boolean(optarg
);
1900 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1904 arg_allow_interactive_authorization
= !!r
;
1908 r
= parse_sec(optarg
, &arg_timeout
);
1910 log_error("Failed to parse --timeout= parameter.");
1916 case ARG_AUGMENT_CREDS
:
1917 r
= parse_boolean(optarg
);
1919 log_error("Failed to parse --augment-creds= parameter.");
1923 arg_augment_creds
= !!r
;
1930 assert_not_reached("Unhandled option");
1936 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1939 if (optind
>= argc
||
1940 streq(argv
[optind
], "list"))
1941 return list_bus_names(bus
, argv
+ optind
);
1943 if (streq(argv
[optind
], "monitor"))
1944 return monitor(bus
, argv
+ optind
, message_dump
);
1946 if (streq(argv
[optind
], "capture"))
1947 return capture(bus
, argv
+ optind
);
1949 if (streq(argv
[optind
], "status"))
1950 return status(bus
, argv
+ optind
);
1952 if (streq(argv
[optind
], "tree"))
1953 return tree(bus
, argv
+ optind
);
1955 if (streq(argv
[optind
], "introspect"))
1956 return introspect(bus
, argv
+ optind
);
1958 if (streq(argv
[optind
], "call"))
1959 return call(bus
, argv
+ optind
);
1961 if (streq(argv
[optind
], "get-property"))
1962 return get_property(bus
, argv
+ optind
);
1964 if (streq(argv
[optind
], "set-property"))
1965 return set_property(bus
, argv
+ optind
);
1967 if (streq(argv
[optind
], "help"))
1970 log_error("Unknown command '%s'", argv
[optind
]);
1974 int main(int argc
, char *argv
[]) {
1975 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1978 log_parse_environment();
1981 r
= parse_argv(argc
, argv
);
1985 r
= sd_bus_new(&bus
);
1987 log_error_errno(r
, "Failed to allocate bus: %m");
1991 if (streq_ptr(argv
[optind
], "monitor") ||
1992 streq_ptr(argv
[optind
], "capture")) {
1994 r
= sd_bus_set_monitor(bus
, true);
1996 log_error_errno(r
, "Failed to set monitor mode: %m");
2000 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
2002 log_error_errno(r
, "Failed to enable credentials: %m");
2006 r
= sd_bus_negotiate_timestamp(bus
, true);
2008 log_error_errno(r
, "Failed to enable timestamps: %m");
2012 r
= sd_bus_negotiate_fds(bus
, true);
2014 log_error_errno(r
, "Failed to enable fds: %m");
2019 r
= sd_bus_set_bus_client(bus
, true);
2021 log_error_errno(r
, "Failed to set bus client: %m");
2026 r
= sd_bus_set_address(bus
, arg_address
);
2028 switch (arg_transport
) {
2030 case BUS_TRANSPORT_LOCAL
:
2032 bus
->is_user
= true;
2033 r
= bus_set_address_user(bus
);
2035 bus
->is_system
= true;
2036 r
= bus_set_address_system(bus
);
2040 case BUS_TRANSPORT_REMOTE
:
2041 r
= bus_set_address_system_remote(bus
, arg_host
);
2044 case BUS_TRANSPORT_MACHINE
:
2045 r
= bus_set_address_system_machine(bus
, arg_host
);
2049 assert_not_reached("Hmm, unknown transport type.");
2053 log_error_errno(r
, "Failed to set address: %m");
2057 r
= sd_bus_start(bus
);
2059 log_error_errno(r
, "Failed to connect to bus: %m");
2063 r
= busctl_main(bus
, argc
, argv
);
2068 strv_free(arg_matches
);
2070 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;