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/>.
26 #include "alloc-util.h"
28 #include "bus-internal.h"
29 #include "bus-signature.h"
32 #include "busctl-introspect.h"
35 #include "locale-util.h"
38 #include "parse-util.h"
39 #include "path-util.h"
42 #include "terminal-util.h"
43 #include "user-util.h"
46 static bool arg_no_pager
= false;
47 static bool arg_legend
= true;
48 static char *arg_address
= NULL
;
49 static bool arg_unique
= false;
50 static bool arg_acquired
= false;
51 static bool arg_activatable
= false;
52 static bool arg_show_machine
= false;
53 static char **arg_matches
= NULL
;
54 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
55 static char *arg_host
= NULL
;
56 static bool arg_user
= false;
57 static size_t arg_snaplen
= 4096;
58 static bool arg_list
= false;
59 static bool arg_quiet
= false;
60 static bool arg_verbose
= false;
61 static bool arg_expect_reply
= true;
62 static bool arg_auto_start
= true;
63 static bool arg_allow_interactive_authorization
= true;
64 static bool arg_augment_creds
= true;
65 static usec_t arg_timeout
= 0;
67 static void pager_open_if_enabled(void) {
69 /* Cache result before we open the pager */
76 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
77 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
79 static int list_bus_names(sd_bus
*bus
, char **argv
) {
80 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
81 _cleanup_free_
char **merged
= NULL
;
82 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
93 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
94 arg_unique
= arg_acquired
= arg_activatable
= true;
96 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
98 return log_error_errno(r
, "Failed to list names: %m");
100 pager_open_if_enabled();
102 names
= hashmap_new(&string_hash_ops
);
106 STRV_FOREACH(i
, acquired
) {
107 max_i
= MAX(max_i
, strlen(*i
));
109 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
111 return log_error_errno(r
, "Failed to add to hashmap: %m");
114 STRV_FOREACH(i
, activatable
) {
115 max_i
= MAX(max_i
, strlen(*i
));
117 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
118 if (r
< 0 && r
!= -EEXIST
)
119 return log_error_errno(r
, "Failed to add to hashmap: %m");
122 merged
= new(char*, hashmap_size(names
) + 1);
123 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
130 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
131 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
133 if (arg_show_machine
)
139 STRV_FOREACH(i
, merged
) {
140 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
143 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
146 printf("%-*s", (int) max_i
, *i
);
147 printf(" - - - (activatable) - - ");
148 if (arg_show_machine
)
156 if (!arg_unique
&& (*i
)[0] == ':')
159 if (!arg_acquired
&& (*i
)[0] != ':')
162 printf("%-*s", (int) max_i
, *i
);
164 r
= sd_bus_get_name_creds(
166 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
167 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
168 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
169 SD_BUS_CREDS_DESCRIPTION
, &creds
);
171 const char *unique
, *session
, *unit
, *cn
;
175 r
= sd_bus_creds_get_pid(creds
, &pid
);
177 const char *comm
= NULL
;
179 sd_bus_creds_get_comm(creds
, &comm
);
181 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
183 fputs(" - - ", stdout
);
185 r
= sd_bus_creds_get_euid(creds
, &uid
);
187 _cleanup_free_
char *u
= NULL
;
189 u
= uid_to_name(uid
);
198 fputs(" - ", stdout
);
200 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
202 printf(" %-13s", unique
);
204 fputs(" - ", stdout
);
206 r
= sd_bus_creds_get_unit(creds
, &unit
);
208 _cleanup_free_
char *e
;
210 e
= ellipsize(unit
, 25, 100);
216 fputs(" - ", stdout
);
218 r
= sd_bus_creds_get_session(creds
, &session
);
220 printf(" %-10s", session
);
222 fputs(" - ", stdout
);
224 r
= sd_bus_creds_get_description(creds
, &cn
);
226 printf(" %-19s", cn
);
228 fputs(" - ", stdout
);
231 printf(" - - - - - - - ");
233 if (arg_show_machine
) {
234 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
236 char m
[SD_ID128_STRING_MAX
];
237 printf(" %s\n", sd_id128_to_string(mid
, m
));
247 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
248 const char *vertical
, *space
;
251 /* We assume the list is sorted. Let's first skip over the
252 * entry we are looking at. */
257 if (!streq(*l
, path
))
263 vertical
= strjoina(prefix
, draw_special_char(DRAW_TREE_VERTICAL
));
264 space
= strjoina(prefix
, draw_special_char(DRAW_TREE_SPACE
));
267 bool has_more
= false;
269 if (!*l
|| !path_startswith(*l
, path
))
274 if (!*n
|| !path_startswith(*n
, path
))
277 if (!path_startswith(*n
, *l
)) {
285 printf("%s%s%s\n", prefix
, draw_special_char(has_more
? DRAW_TREE_BRANCH
: DRAW_TREE_RIGHT
), *l
);
287 print_subtree(has_more
? vertical
: space
, *l
, l
);
292 static void print_tree(const char *prefix
, char **l
) {
294 pager_open_if_enabled();
296 prefix
= strempty(prefix
);
302 printf("%s%s\n", prefix
, *i
);
306 if (strv_isempty(l
)) {
307 printf("No objects discovered.\n");
311 if (streq(l
[0], "/") && !l
[1]) {
312 printf("Only root object discovered.\n");
316 print_subtree(prefix
, "/", l
);
319 static int on_path(const char *path
, void *userdata
) {
320 Set
*paths
= userdata
;
325 r
= set_put_strdup(paths
, path
);
332 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
333 static const XMLIntrospectOps ops
= {
337 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
338 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
342 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
345 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
347 log_error("Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
351 r
= sd_bus_message_read(reply
, "s", &xml
);
353 return bus_log_parse_error(r
);
355 return parse_xml_introspect(path
, xml
, &ops
, paths
);
358 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
359 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
360 _cleanup_free_
char **l
= NULL
;
364 paths
= set_new(&string_hash_ops
);
368 done
= set_new(&string_hash_ops
);
372 failed
= set_new(&string_hash_ops
);
380 r
= set_put(paths
, m
);
387 _cleanup_free_
char *p
= NULL
;
390 p
= set_steal_first(paths
);
394 if (set_contains(done
, p
) ||
395 set_contains(failed
, p
))
398 q
= find_nodes(bus
, service
, p
, paths
, many
);
403 q
= set_put(failed
, p
);
405 q
= set_put(done
, p
);
414 pager_open_if_enabled();
416 l
= set_get_strv(done
);
421 print_tree(prefix
, l
);
428 static int tree(sd_bus
*bus
, char **argv
) {
432 if (!arg_unique
&& !arg_acquired
)
435 if (strv_length(argv
) <= 1) {
436 _cleanup_strv_free_
char **names
= NULL
;
437 bool not_first
= false;
439 r
= sd_bus_list_names(bus
, &names
, NULL
);
441 return log_error_errno(r
, "Failed to get name list: %m");
443 pager_open_if_enabled();
445 STRV_FOREACH(i
, names
) {
448 if (!arg_unique
&& (*i
)[0] == ':')
451 if (!arg_acquired
&& (*i
)[0] == ':')
457 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
459 q
= tree_one(bus
, *i
, NULL
, true);
466 STRV_FOREACH(i
, argv
+1) {
473 pager_open_if_enabled();
474 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
477 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
486 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
490 const char *contents
= NULL
;
505 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
509 if (bus_type_is_container(type
) > 0) {
511 r
= sd_bus_message_enter_container(m
, type
, contents
);
515 if (type
== SD_BUS_TYPE_ARRAY
) {
518 /* count array entries */
521 r
= sd_bus_message_skip(m
, contents
);
530 r
= sd_bus_message_rewind(m
, false);
538 } else if (type
== SD_BUS_TYPE_VARIANT
) {
543 fprintf(f
, "%s", contents
);
546 r
= format_cmdline(m
, f
, needs_space
|| IN_SET(type
, SD_BUS_TYPE_ARRAY
, SD_BUS_TYPE_VARIANT
));
550 r
= sd_bus_message_exit_container(m
);
557 r
= sd_bus_message_read_basic(m
, type
, &basic
);
565 case SD_BUS_TYPE_BYTE
:
566 fprintf(f
, "%u", basic
.u8
);
569 case SD_BUS_TYPE_BOOLEAN
:
570 fputs(true_false(basic
.i
), f
);
573 case SD_BUS_TYPE_INT16
:
574 fprintf(f
, "%i", basic
.s16
);
577 case SD_BUS_TYPE_UINT16
:
578 fprintf(f
, "%u", basic
.u16
);
581 case SD_BUS_TYPE_INT32
:
582 fprintf(f
, "%i", basic
.s32
);
585 case SD_BUS_TYPE_UINT32
:
586 fprintf(f
, "%u", basic
.u32
);
589 case SD_BUS_TYPE_INT64
:
590 fprintf(f
, "%" PRIi64
, basic
.s64
);
593 case SD_BUS_TYPE_UINT64
:
594 fprintf(f
, "%" PRIu64
, basic
.u64
);
597 case SD_BUS_TYPE_DOUBLE
:
598 fprintf(f
, "%g", basic
.d64
);
601 case SD_BUS_TYPE_STRING
:
602 case SD_BUS_TYPE_OBJECT_PATH
:
603 case SD_BUS_TYPE_SIGNATURE
: {
604 _cleanup_free_
char *b
= NULL
;
606 b
= cescape(basic
.string
);
610 fprintf(f
, "\"%s\"", b
);
614 case SD_BUS_TYPE_UNIX_FD
:
615 fprintf(f
, "%i", basic
.i
);
619 assert_not_reached("Unknown basic type.");
626 typedef struct Member
{
637 static void member_hash_func(const void *p
, struct siphash
*state
) {
644 string_hash_func(m
->type
, state
);
646 arity
+= !!m
->name
+ !!m
->interface
;
648 uint64_hash_func(&arity
, state
);
651 string_hash_func(m
->name
, state
);
654 string_hash_func(m
->interface
, state
);
657 static int member_compare_func(const void *a
, const void *b
) {
658 const Member
*x
= a
, *y
= b
;
666 d
= strcmp_ptr(x
->interface
, y
->interface
);
670 d
= strcmp(x
->type
, y
->type
);
674 return strcmp_ptr(x
->name
, y
->name
);
677 static int member_compare_funcp(const void *a
, const void *b
) {
678 const Member
*const * x
= (const Member
*const *) a
, * const *y
= (const Member
*const *) b
;
680 return member_compare_func(*x
, *y
);
683 static void member_free(Member
*m
) {
695 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
697 static void member_set_free(Set
*s
) {
700 while ((m
= set_steal_first(s
)))
706 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
708 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
709 _cleanup_(member_freep
) Member
*m
;
710 Set
*members
= userdata
;
720 m
->type
= "interface";
723 r
= free_and_strdup(&m
->interface
, interface
);
727 r
= set_put(members
, m
);
729 log_error("Duplicate interface");
737 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
738 _cleanup_(member_freep
) Member
*m
;
739 Set
*members
= userdata
;
752 r
= free_and_strdup(&m
->interface
, interface
);
756 r
= free_and_strdup(&m
->name
, name
);
760 r
= free_and_strdup(&m
->signature
, signature
);
764 r
= free_and_strdup(&m
->result
, result
);
768 r
= set_put(members
, m
);
770 log_error("Duplicate method");
778 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
779 _cleanup_(member_freep
) Member
*m
;
780 Set
*members
= userdata
;
793 r
= free_and_strdup(&m
->interface
, interface
);
797 r
= free_and_strdup(&m
->name
, name
);
801 r
= free_and_strdup(&m
->signature
, signature
);
805 r
= set_put(members
, m
);
807 log_error("Duplicate signal");
815 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
816 _cleanup_(member_freep
) Member
*m
;
817 Set
*members
= userdata
;
827 m
->type
= "property";
829 m
->writable
= writable
;
831 r
= free_and_strdup(&m
->interface
, interface
);
835 r
= free_and_strdup(&m
->name
, name
);
839 r
= free_and_strdup(&m
->signature
, signature
);
843 r
= set_put(members
, m
);
845 log_error("Duplicate property");
853 static const char *strdash(const char *x
) {
854 return isempty(x
) ? "-" : x
;
857 static int introspect(sd_bus
*bus
, char **argv
) {
858 static const struct hash_ops member_hash_ops
= {
859 .hash
= member_hash_func
,
860 .compare
= member_compare_func
,
863 static const XMLIntrospectOps ops
= {
864 .on_interface
= on_interface
,
865 .on_method
= on_method
,
866 .on_signal
= on_signal
,
867 .on_property
= on_property
,
870 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
871 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
872 _cleanup_(member_set_freep
) Set
*members
= NULL
;
877 unsigned name_width
, type_width
, signature_width
, result_width
;
878 Member
**sorted
= NULL
;
879 unsigned k
= 0, j
, n_args
;
881 n_args
= strv_length(argv
);
883 log_error("Requires service and object path argument.");
888 log_error("Too many arguments.");
892 members
= set_new(&member_hash_ops
);
896 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
898 log_error("Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
902 r
= sd_bus_message_read(reply
, "s", &xml
);
904 return bus_log_parse_error(r
);
906 /* First, get list of all properties */
907 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
911 /* Second, find the current values for them */
912 SET_FOREACH(m
, members
, i
) {
914 if (!streq(m
->type
, "property"))
920 if (argv
[3] && !streq(argv
[3], m
->interface
))
923 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
925 log_error("%s", bus_error_message(&error
, r
));
929 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
931 return bus_log_parse_error(r
);
935 _cleanup_free_
char *buf
= NULL
;
936 _cleanup_fclose_
FILE *mf
= NULL
;
940 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
942 return bus_log_parse_error(r
);
947 r
= sd_bus_message_read(reply
, "s", &name
);
949 return bus_log_parse_error(r
);
951 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
953 return bus_log_parse_error(r
);
955 mf
= open_memstream(&buf
, &sz
);
959 r
= format_cmdline(reply
, mf
, false);
961 return bus_log_parse_error(r
);
966 z
= set_get(members
, &((Member
) {
968 .interface
= m
->interface
,
969 .name
= (char*) name
}));
976 r
= sd_bus_message_exit_container(reply
);
978 return bus_log_parse_error(r
);
980 r
= sd_bus_message_exit_container(reply
);
982 return bus_log_parse_error(r
);
985 r
= sd_bus_message_exit_container(reply
);
987 return bus_log_parse_error(r
);
990 pager_open_if_enabled();
992 name_width
= strlen("NAME");
993 type_width
= strlen("TYPE");
994 signature_width
= strlen("SIGNATURE");
995 result_width
= strlen("RESULT/VALUE");
997 sorted
= newa(Member
*, set_size(members
));
999 SET_FOREACH(m
, members
, i
) {
1001 if (argv
[3] && !streq(argv
[3], m
->interface
))
1005 name_width
= MAX(name_width
, strlen(m
->interface
));
1007 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1009 type_width
= MAX(type_width
, strlen(m
->type
));
1011 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1013 result_width
= MAX(result_width
, strlen(m
->result
));
1015 result_width
= MAX(result_width
, strlen(m
->value
));
1020 if (result_width
> 40)
1023 qsort(sorted
, k
, sizeof(Member
*), member_compare_funcp
);
1026 printf("%-*s %-*s %-*s %-*s %s\n",
1027 (int) name_width
, "NAME",
1028 (int) type_width
, "TYPE",
1029 (int) signature_width
, "SIGNATURE",
1030 (int) result_width
, "RESULT/VALUE",
1034 for (j
= 0; j
< k
; j
++) {
1035 _cleanup_free_
char *ellipsized
= NULL
;
1041 if (argv
[3] && !streq(argv
[3], m
->interface
))
1044 is_interface
= streq(m
->type
, "interface");
1046 if (argv
[3] && is_interface
)
1050 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1056 rv
= strdash(m
->result
);
1058 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1059 is_interface
? ansi_highlight() : "",
1060 is_interface
? "" : ".",
1061 - !is_interface
+ (int) name_width
, strdash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1062 is_interface
? ansi_normal() : "",
1063 (int) type_width
, strdash(m
->type
),
1064 (int) signature_width
, strdash(m
->signature
),
1065 (int) result_width
, rv
,
1066 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1067 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1068 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1069 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1070 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1071 m
->writable
? " writable" : "");
1077 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1078 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1081 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1082 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1085 static int monitor(sd_bus
*bus
, char *argv
[], int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1086 bool added_something
= false;
1090 STRV_FOREACH(i
, argv
+1) {
1091 _cleanup_free_
char *m
= NULL
;
1093 if (!service_name_is_valid(*i
)) {
1094 log_error("Invalid service name '%s'", *i
);
1098 m
= strjoin("sender='", *i
, "'", NULL
);
1102 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1104 return log_error_errno(r
, "Failed to add match: %m");
1107 m
= strjoin("destination='", *i
, "'", NULL
);
1111 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1113 return log_error_errno(r
, "Failed to add match: %m");
1115 added_something
= true;
1118 STRV_FOREACH(i
, arg_matches
) {
1119 r
= sd_bus_add_match(bus
, NULL
, *i
, NULL
, NULL
);
1121 return log_error_errno(r
, "Failed to add match: %m");
1123 added_something
= true;
1126 if (!added_something
) {
1127 r
= sd_bus_add_match(bus
, NULL
, "", NULL
, NULL
);
1129 return log_error_errno(r
, "Failed to add match: %m");
1132 log_info("Monitoring bus message stream.");
1135 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1137 r
= sd_bus_process(bus
, &m
);
1139 return log_error_errno(r
, "Failed to process bus: %m");
1145 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1146 log_info("Connection terminated, exiting.");
1156 r
= sd_bus_wait(bus
, (uint64_t) -1);
1158 return log_error_errno(r
, "Failed to wait for bus: %m");
1162 static int capture(sd_bus
*bus
, char *argv
[]) {
1165 if (isatty(fileno(stdout
)) > 0) {
1166 log_error("Refusing to write message data to console, please redirect output to a file.");
1170 bus_pcap_header(arg_snaplen
, stdout
);
1172 r
= monitor(bus
, argv
, message_pcap
);
1176 if (ferror(stdout
)) {
1177 log_error("Couldn't write capture file.");
1184 static int status(sd_bus
*bus
, char *argv
[]) {
1185 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1191 if (strv_length(argv
) > 2) {
1192 log_error("Expects no or one argument.");
1197 r
= parse_pid(argv
[1], &pid
);
1199 r
= sd_bus_get_name_creds(
1202 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1205 r
= sd_bus_creds_new_from_pid(
1210 const char *scope
, *address
;
1213 r
= sd_bus_get_address(bus
, &address
);
1215 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1217 r
= sd_bus_get_scope(bus
, &scope
);
1219 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1221 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1223 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1225 r
= sd_bus_get_owner_creds(
1227 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1232 return log_error_errno(r
, "Failed to get credentials: %m");
1234 bus_creds_dump(creds
, NULL
, false);
1238 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1258 log_error("Too few parameters for signature.");
1267 case SD_BUS_TYPE_BOOLEAN
:
1269 r
= parse_boolean(v
);
1271 log_error("Failed to parse as boolean: %s", v
);
1275 r
= sd_bus_message_append_basic(m
, t
, &r
);
1278 case SD_BUS_TYPE_BYTE
: {
1281 r
= safe_atou8(v
, &z
);
1283 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1287 r
= sd_bus_message_append_basic(m
, t
, &z
);
1291 case SD_BUS_TYPE_INT16
: {
1294 r
= safe_atoi16(v
, &z
);
1296 log_error("Failed to parse as signed 16bit integer: %s", v
);
1300 r
= sd_bus_message_append_basic(m
, t
, &z
);
1304 case SD_BUS_TYPE_UINT16
: {
1307 r
= safe_atou16(v
, &z
);
1309 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1313 r
= sd_bus_message_append_basic(m
, t
, &z
);
1317 case SD_BUS_TYPE_INT32
: {
1320 r
= safe_atoi32(v
, &z
);
1322 log_error("Failed to parse as signed 32bit integer: %s", v
);
1326 r
= sd_bus_message_append_basic(m
, t
, &z
);
1330 case SD_BUS_TYPE_UINT32
: {
1333 r
= safe_atou32(v
, &z
);
1335 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1339 r
= sd_bus_message_append_basic(m
, t
, &z
);
1343 case SD_BUS_TYPE_INT64
: {
1346 r
= safe_atoi64(v
, &z
);
1348 log_error("Failed to parse as signed 64bit integer: %s", v
);
1352 r
= sd_bus_message_append_basic(m
, t
, &z
);
1356 case SD_BUS_TYPE_UINT64
: {
1359 r
= safe_atou64(v
, &z
);
1361 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1365 r
= sd_bus_message_append_basic(m
, t
, &z
);
1370 case SD_BUS_TYPE_DOUBLE
: {
1373 r
= safe_atod(v
, &z
);
1375 log_error("Failed to parse as double precision floating point: %s", v
);
1379 r
= sd_bus_message_append_basic(m
, t
, &z
);
1383 case SD_BUS_TYPE_STRING
:
1384 case SD_BUS_TYPE_OBJECT_PATH
:
1385 case SD_BUS_TYPE_SIGNATURE
:
1387 r
= sd_bus_message_append_basic(m
, t
, v
);
1390 case SD_BUS_TYPE_ARRAY
: {
1394 r
= safe_atou32(v
, &n
);
1396 log_error("Failed to parse number of array entries: %s", v
);
1400 r
= signature_element_length(signature
, &k
);
1402 log_error("Invalid array signature.");
1409 memcpy(s
, signature
, k
);
1412 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1414 return bus_log_create_error(r
);
1416 for (i
= 0; i
< n
; i
++) {
1417 r
= message_append_cmdline(m
, s
, &p
);
1425 r
= sd_bus_message_close_container(m
);
1429 case SD_BUS_TYPE_VARIANT
:
1430 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1432 return bus_log_create_error(r
);
1434 r
= message_append_cmdline(m
, v
, &p
);
1438 r
= sd_bus_message_close_container(m
);
1441 case SD_BUS_TYPE_STRUCT_BEGIN
:
1442 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1448 r
= signature_element_length(signature
, &k
);
1450 log_error("Invalid struct/dict entry signature.");
1456 memcpy(s
, signature
+ 1, k
- 2);
1459 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1461 return bus_log_create_error(r
);
1463 r
= message_append_cmdline(m
, s
, &p
);
1470 r
= sd_bus_message_close_container(m
);
1474 case SD_BUS_TYPE_UNIX_FD
:
1475 log_error("UNIX file descriptor not supported as type.");
1479 log_error("Unknown signature type %c.", t
);
1484 return bus_log_create_error(r
);
1491 static int call(sd_bus
*bus
, char *argv
[]) {
1492 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1493 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1498 if (strv_length(argv
) < 5) {
1499 log_error("Expects at least four arguments.");
1503 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1505 return bus_log_create_error(r
);
1507 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1509 return bus_log_create_error(r
);
1511 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1513 return bus_log_create_error(r
);
1515 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1517 return bus_log_create_error(r
);
1519 if (!isempty(argv
[5])) {
1524 r
= message_append_cmdline(m
, argv
[5], &p
);
1529 log_error("Too many parameters for signature.");
1534 if (!arg_expect_reply
) {
1535 r
= sd_bus_send(bus
, m
, NULL
);
1537 log_error("Failed to send message.");
1544 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1546 log_error("%s", bus_error_message(&error
, r
));
1550 r
= sd_bus_message_is_empty(reply
);
1552 return bus_log_parse_error(r
);
1554 if (r
== 0 && !arg_quiet
) {
1557 pager_open_if_enabled();
1559 r
= bus_message_dump(reply
, stdout
, 0);
1564 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1567 r
= format_cmdline(reply
, stdout
, false);
1569 return bus_log_parse_error(r
);
1571 fputc('\n', stdout
);
1578 static int get_property(sd_bus
*bus
, char *argv
[]) {
1579 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1586 n
= strv_length(argv
);
1588 log_error("Expects at least four arguments.");
1592 STRV_FOREACH(i
, argv
+ 4) {
1593 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1594 const char *contents
= NULL
;
1597 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1599 log_error("%s", bus_error_message(&error
, r
));
1603 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1605 return bus_log_parse_error(r
);
1607 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1609 return bus_log_parse_error(r
);
1612 pager_open_if_enabled();
1614 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1618 fputs(contents
, stdout
);
1621 r
= format_cmdline(reply
, stdout
, false);
1623 return bus_log_parse_error(r
);
1625 fputc('\n', stdout
);
1628 r
= sd_bus_message_exit_container(reply
);
1630 return bus_log_parse_error(r
);
1636 static int set_property(sd_bus
*bus
, char *argv
[]) {
1637 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1638 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1645 n
= strv_length(argv
);
1647 log_error("Expects at least five arguments.");
1651 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1653 return bus_log_create_error(r
);
1655 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1657 return bus_log_create_error(r
);
1659 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1661 return bus_log_create_error(r
);
1664 r
= message_append_cmdline(m
, argv
[5], &p
);
1668 r
= sd_bus_message_close_container(m
);
1670 return bus_log_create_error(r
);
1673 log_error("Too many parameters for signature.");
1677 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1679 log_error("%s", bus_error_message(&error
, r
));
1686 static int help(void) {
1687 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1688 "Introspect the bus.\n\n"
1689 " -h --help Show this help\n"
1690 " --version Show package version\n"
1691 " --no-pager Do not pipe output into a pager\n"
1692 " --no-legend Do not show the headers and footers\n"
1693 " --system Connect to system bus\n"
1694 " --user Connect to user bus\n"
1695 " -H --host=[USER@]HOST Operate on remote host\n"
1696 " -M --machine=CONTAINER Operate on local container\n"
1697 " --address=ADDRESS Connect to bus specified by address\n"
1698 " --show-machine Show machine ID column in list\n"
1699 " --unique Only show unique names\n"
1700 " --acquired Only show acquired names\n"
1701 " --activatable Only show activatable names\n"
1702 " --match=MATCH Only show matching messages\n"
1703 " --size=SIZE Maximum length of captured packet\n"
1704 " --list Don't show tree, but simple object path list\n"
1705 " --quiet Don't show method call reply\n"
1706 " --verbose Show result values in long format\n"
1707 " --expect-reply=BOOL Expect a method call reply\n"
1708 " --auto-start=BOOL Auto-start destination service\n"
1709 " --allow-interactive-authorization=BOOL\n"
1710 " Allow interactive authorization for operation\n"
1711 " --timeout=SECS Maximum time to wait for method call completion\n"
1712 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1714 " list List bus names\n"
1715 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1716 " monitor [SERVICE...] Show bus traffic\n"
1717 " capture [SERVICE...] Capture bus traffic as pcap\n"
1718 " tree [SERVICE...] Show object tree of service\n"
1719 " introspect SERVICE OBJECT [INTERFACE]\n"
1720 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1722 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1723 " Get property value\n"
1724 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1725 " Set property value\n"
1726 " help Show this help\n"
1727 , program_invocation_short_name
);
1732 static int parse_argv(int argc
, char *argv
[]) {
1735 ARG_VERSION
= 0x100,
1751 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1756 static const struct option options
[] = {
1757 { "help", no_argument
, NULL
, 'h' },
1758 { "version", no_argument
, NULL
, ARG_VERSION
},
1759 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1760 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1761 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1762 { "user", no_argument
, NULL
, ARG_USER
},
1763 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1764 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1765 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1766 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1767 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1768 { "match", required_argument
, NULL
, ARG_MATCH
},
1769 { "host", required_argument
, NULL
, 'H' },
1770 { "machine", required_argument
, NULL
, 'M' },
1771 { "size", required_argument
, NULL
, ARG_SIZE
},
1772 { "list", no_argument
, NULL
, ARG_LIST
},
1773 { "quiet", no_argument
, NULL
, 'q' },
1774 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1775 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1776 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1777 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1778 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1779 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1788 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1799 arg_no_pager
= true;
1815 arg_address
= optarg
;
1818 case ARG_SHOW_MACHINE
:
1819 arg_show_machine
= true;
1827 arg_acquired
= true;
1830 case ARG_ACTIVATABLE
:
1831 arg_activatable
= true;
1835 if (strv_extend(&arg_matches
, optarg
) < 0)
1842 r
= parse_size(optarg
, 1024, &sz
);
1844 log_error("Failed to parse size: %s", optarg
);
1848 if ((uint64_t) (size_t) sz
!= sz
) {
1849 log_error("Size out of range.");
1853 arg_snaplen
= (size_t) sz
;
1862 arg_transport
= BUS_TRANSPORT_REMOTE
;
1867 arg_transport
= BUS_TRANSPORT_MACHINE
;
1879 case ARG_EXPECT_REPLY
:
1880 r
= parse_boolean(optarg
);
1882 log_error("Failed to parse --expect-reply= parameter.");
1886 arg_expect_reply
= !!r
;
1890 case ARG_AUTO_START
:
1891 r
= parse_boolean(optarg
);
1893 log_error("Failed to parse --auto-start= parameter.");
1897 arg_auto_start
= !!r
;
1901 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1902 r
= parse_boolean(optarg
);
1904 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1908 arg_allow_interactive_authorization
= !!r
;
1912 r
= parse_sec(optarg
, &arg_timeout
);
1914 log_error("Failed to parse --timeout= parameter.");
1920 case ARG_AUGMENT_CREDS
:
1921 r
= parse_boolean(optarg
);
1923 log_error("Failed to parse --augment-creds= parameter.");
1927 arg_augment_creds
= !!r
;
1934 assert_not_reached("Unhandled option");
1940 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1943 if (optind
>= argc
||
1944 streq(argv
[optind
], "list"))
1945 return list_bus_names(bus
, argv
+ optind
);
1947 if (streq(argv
[optind
], "monitor"))
1948 return monitor(bus
, argv
+ optind
, message_dump
);
1950 if (streq(argv
[optind
], "capture"))
1951 return capture(bus
, argv
+ optind
);
1953 if (streq(argv
[optind
], "status"))
1954 return status(bus
, argv
+ optind
);
1956 if (streq(argv
[optind
], "tree"))
1957 return tree(bus
, argv
+ optind
);
1959 if (streq(argv
[optind
], "introspect"))
1960 return introspect(bus
, argv
+ optind
);
1962 if (streq(argv
[optind
], "call"))
1963 return call(bus
, argv
+ optind
);
1965 if (streq(argv
[optind
], "get-property"))
1966 return get_property(bus
, argv
+ optind
);
1968 if (streq(argv
[optind
], "set-property"))
1969 return set_property(bus
, argv
+ optind
);
1971 if (streq(argv
[optind
], "help"))
1974 log_error("Unknown command '%s'", argv
[optind
]);
1978 int main(int argc
, char *argv
[]) {
1979 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1982 log_parse_environment();
1985 r
= parse_argv(argc
, argv
);
1989 r
= sd_bus_new(&bus
);
1991 log_error_errno(r
, "Failed to allocate bus: %m");
1995 if (streq_ptr(argv
[optind
], "monitor") ||
1996 streq_ptr(argv
[optind
], "capture")) {
1998 r
= sd_bus_set_monitor(bus
, true);
2000 log_error_errno(r
, "Failed to set monitor mode: %m");
2004 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
2006 log_error_errno(r
, "Failed to enable credentials: %m");
2010 r
= sd_bus_negotiate_timestamp(bus
, true);
2012 log_error_errno(r
, "Failed to enable timestamps: %m");
2016 r
= sd_bus_negotiate_fds(bus
, true);
2018 log_error_errno(r
, "Failed to enable fds: %m");
2023 r
= sd_bus_set_bus_client(bus
, true);
2025 log_error_errno(r
, "Failed to set bus client: %m");
2030 r
= sd_bus_set_address(bus
, arg_address
);
2032 switch (arg_transport
) {
2034 case BUS_TRANSPORT_LOCAL
:
2036 bus
->is_user
= true;
2037 r
= bus_set_address_user(bus
);
2039 bus
->is_system
= true;
2040 r
= bus_set_address_system(bus
);
2044 case BUS_TRANSPORT_REMOTE
:
2045 r
= bus_set_address_system_remote(bus
, arg_host
);
2048 case BUS_TRANSPORT_MACHINE
:
2049 r
= bus_set_address_system_machine(bus
, arg_host
);
2053 assert_not_reached("Hmm, unknown transport type.");
2057 log_error_errno(r
, "Failed to set address: %m");
2061 r
= sd_bus_start(bus
);
2063 log_error_errno(r
, "Failed to connect to bus: %m");
2067 r
= busctl_main(bus
, argc
, argv
);
2072 strv_free(arg_matches
);
2074 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;