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"
34 #include "path-util.h"
37 #include "terminal-util.h"
40 static bool arg_no_pager
= false;
41 static bool arg_legend
= true;
42 static char *arg_address
= NULL
;
43 static bool arg_unique
= false;
44 static bool arg_acquired
= false;
45 static bool arg_activatable
= false;
46 static bool arg_show_machine
= false;
47 static char **arg_matches
= NULL
;
48 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
49 static char *arg_host
= NULL
;
50 static bool arg_user
= false;
51 static size_t arg_snaplen
= 4096;
52 static bool arg_list
= false;
53 static bool arg_quiet
= false;
54 static bool arg_verbose
= false;
55 static bool arg_expect_reply
= true;
56 static bool arg_auto_start
= true;
57 static bool arg_allow_interactive_authorization
= true;
58 static bool arg_augment_creds
= true;
59 static usec_t arg_timeout
= 0;
61 static void pager_open_if_enabled(void) {
63 /* Cache result before we open the pager */
70 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
71 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
73 static int list_bus_names(sd_bus
*bus
, char **argv
) {
74 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
75 _cleanup_free_
char **merged
= NULL
;
76 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
87 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
88 arg_unique
= arg_acquired
= arg_activatable
= true;
90 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
92 return log_error_errno(r
, "Failed to list names: %m");
94 pager_open_if_enabled();
96 names
= hashmap_new(&string_hash_ops
);
100 STRV_FOREACH(i
, acquired
) {
101 max_i
= MAX(max_i
, strlen(*i
));
103 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
105 return log_error_errno(r
, "Failed to add to hashmap: %m");
108 STRV_FOREACH(i
, activatable
) {
109 max_i
= MAX(max_i
, strlen(*i
));
111 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
112 if (r
< 0 && r
!= -EEXIST
)
113 return log_error_errno(r
, "Failed to add to hashmap: %m");
116 merged
= new(char*, hashmap_size(names
) + 1);
117 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
124 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
125 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
127 if (arg_show_machine
)
133 STRV_FOREACH(i
, merged
) {
134 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
137 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
140 printf("%-*s", (int) max_i
, *i
);
141 printf(" - - - (activatable) - - ");
142 if (arg_show_machine
)
150 if (!arg_unique
&& (*i
)[0] == ':')
153 if (!arg_acquired
&& (*i
)[0] != ':')
156 printf("%-*s", (int) max_i
, *i
);
158 r
= sd_bus_get_name_creds(
160 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
161 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
162 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
163 SD_BUS_CREDS_DESCRIPTION
, &creds
);
165 const char *unique
, *session
, *unit
, *cn
;
169 r
= sd_bus_creds_get_pid(creds
, &pid
);
171 const char *comm
= NULL
;
173 sd_bus_creds_get_comm(creds
, &comm
);
175 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
177 fputs(" - - ", stdout
);
179 r
= sd_bus_creds_get_euid(creds
, &uid
);
181 _cleanup_free_
char *u
= NULL
;
183 u
= uid_to_name(uid
);
192 fputs(" - ", stdout
);
194 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
196 printf(" %-13s", unique
);
198 fputs(" - ", stdout
);
200 r
= sd_bus_creds_get_unit(creds
, &unit
);
202 _cleanup_free_
char *e
;
204 e
= ellipsize(unit
, 25, 100);
210 fputs(" - ", stdout
);
212 r
= sd_bus_creds_get_session(creds
, &session
);
214 printf(" %-10s", session
);
216 fputs(" - ", stdout
);
218 r
= sd_bus_creds_get_description(creds
, &cn
);
220 printf(" %-19s", cn
);
222 fputs(" - ", stdout
);
225 printf(" - - - - - - - ");
227 if (arg_show_machine
) {
228 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
230 char m
[SD_ID128_STRING_MAX
];
231 printf(" %s\n", sd_id128_to_string(mid
, m
));
241 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
242 const char *vertical
, *space
;
245 /* We assume the list is sorted. Let's first skip over the
246 * entry we are looking at. */
251 if (!streq(*l
, path
))
257 vertical
= strjoina(prefix
, draw_special_char(DRAW_TREE_VERTICAL
));
258 space
= strjoina(prefix
, draw_special_char(DRAW_TREE_SPACE
));
261 bool has_more
= false;
263 if (!*l
|| !path_startswith(*l
, path
))
268 if (!*n
|| !path_startswith(*n
, path
))
271 if (!path_startswith(*n
, *l
)) {
279 printf("%s%s%s\n", prefix
, draw_special_char(has_more
? DRAW_TREE_BRANCH
: DRAW_TREE_RIGHT
), *l
);
281 print_subtree(has_more
? vertical
: space
, *l
, l
);
286 static void print_tree(const char *prefix
, char **l
) {
288 pager_open_if_enabled();
290 prefix
= strempty(prefix
);
296 printf("%s%s\n", prefix
, *i
);
300 if (strv_isempty(l
)) {
301 printf("No objects discovered.\n");
305 if (streq(l
[0], "/") && !l
[1]) {
306 printf("Only root object discovered.\n");
310 print_subtree(prefix
, "/", l
);
313 static int on_path(const char *path
, void *userdata
) {
314 Set
*paths
= userdata
;
319 r
= set_put_strdup(paths
, path
);
326 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
327 static const XMLIntrospectOps ops
= {
331 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
332 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
336 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
339 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
341 log_error("Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
345 r
= sd_bus_message_read(reply
, "s", &xml
);
347 return bus_log_parse_error(r
);
349 return parse_xml_introspect(path
, xml
, &ops
, paths
);
352 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
353 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
354 _cleanup_free_
char **l
= NULL
;
358 paths
= set_new(&string_hash_ops
);
362 done
= set_new(&string_hash_ops
);
366 failed
= set_new(&string_hash_ops
);
374 r
= set_put(paths
, m
);
381 _cleanup_free_
char *p
= NULL
;
384 p
= set_steal_first(paths
);
388 if (set_contains(done
, p
) ||
389 set_contains(failed
, p
))
392 q
= find_nodes(bus
, service
, p
, paths
, many
);
397 q
= set_put(failed
, p
);
399 q
= set_put(done
, p
);
408 pager_open_if_enabled();
410 l
= set_get_strv(done
);
415 print_tree(prefix
, l
);
422 static int tree(sd_bus
*bus
, char **argv
) {
426 if (!arg_unique
&& !arg_acquired
)
429 if (strv_length(argv
) <= 1) {
430 _cleanup_strv_free_
char **names
= NULL
;
431 bool not_first
= false;
433 r
= sd_bus_list_names(bus
, &names
, NULL
);
435 return log_error_errno(r
, "Failed to get name list: %m");
437 pager_open_if_enabled();
439 STRV_FOREACH(i
, names
) {
442 if (!arg_unique
&& (*i
)[0] == ':')
445 if (!arg_acquired
&& (*i
)[0] == ':')
451 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
453 q
= tree_one(bus
, *i
, NULL
, true);
460 STRV_FOREACH(i
, argv
+1) {
467 pager_open_if_enabled();
468 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
471 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
480 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
484 const char *contents
= NULL
;
499 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
503 if (bus_type_is_container(type
) > 0) {
505 r
= sd_bus_message_enter_container(m
, type
, contents
);
509 if (type
== SD_BUS_TYPE_ARRAY
) {
512 /* count array entries */
515 r
= sd_bus_message_skip(m
, contents
);
524 r
= sd_bus_message_rewind(m
, false);
532 } else if (type
== SD_BUS_TYPE_VARIANT
) {
537 fprintf(f
, "%s", contents
);
540 r
= format_cmdline(m
, f
, needs_space
|| IN_SET(type
, SD_BUS_TYPE_ARRAY
, SD_BUS_TYPE_VARIANT
));
544 r
= sd_bus_message_exit_container(m
);
551 r
= sd_bus_message_read_basic(m
, type
, &basic
);
559 case SD_BUS_TYPE_BYTE
:
560 fprintf(f
, "%u", basic
.u8
);
563 case SD_BUS_TYPE_BOOLEAN
:
564 fputs(true_false(basic
.i
), f
);
567 case SD_BUS_TYPE_INT16
:
568 fprintf(f
, "%i", basic
.s16
);
571 case SD_BUS_TYPE_UINT16
:
572 fprintf(f
, "%u", basic
.u16
);
575 case SD_BUS_TYPE_INT32
:
576 fprintf(f
, "%i", basic
.s32
);
579 case SD_BUS_TYPE_UINT32
:
580 fprintf(f
, "%u", basic
.u32
);
583 case SD_BUS_TYPE_INT64
:
584 fprintf(f
, "%" PRIi64
, basic
.s64
);
587 case SD_BUS_TYPE_UINT64
:
588 fprintf(f
, "%" PRIu64
, basic
.u64
);
591 case SD_BUS_TYPE_DOUBLE
:
592 fprintf(f
, "%g", basic
.d64
);
595 case SD_BUS_TYPE_STRING
:
596 case SD_BUS_TYPE_OBJECT_PATH
:
597 case SD_BUS_TYPE_SIGNATURE
: {
598 _cleanup_free_
char *b
= NULL
;
600 b
= cescape(basic
.string
);
604 fprintf(f
, "\"%s\"", b
);
608 case SD_BUS_TYPE_UNIX_FD
:
609 fprintf(f
, "%i", basic
.i
);
613 assert_not_reached("Unknown basic type.");
620 typedef struct Member
{
631 static void member_hash_func(const void *p
, struct siphash
*state
) {
638 string_hash_func(m
->type
, state
);
640 arity
+= !!m
->name
+ !!m
->interface
;
642 uint64_hash_func(&arity
, state
);
645 string_hash_func(m
->name
, state
);
648 string_hash_func(m
->interface
, state
);
651 static int member_compare_func(const void *a
, const void *b
) {
652 const Member
*x
= a
, *y
= b
;
660 d
= strcmp_ptr(x
->interface
, y
->interface
);
664 d
= strcmp(x
->type
, y
->type
);
668 return strcmp_ptr(x
->name
, y
->name
);
671 static int member_compare_funcp(const void *a
, const void *b
) {
672 const Member
*const * x
= (const Member
*const *) a
, * const *y
= (const Member
*const *) b
;
674 return member_compare_func(*x
, *y
);
677 static void member_free(Member
*m
) {
689 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
691 static void member_set_free(Set
*s
) {
694 while ((m
= set_steal_first(s
)))
700 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
702 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
703 _cleanup_(member_freep
) Member
*m
;
704 Set
*members
= userdata
;
714 m
->type
= "interface";
717 r
= free_and_strdup(&m
->interface
, interface
);
721 r
= set_put(members
, m
);
723 log_error("Duplicate interface");
731 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
732 _cleanup_(member_freep
) Member
*m
;
733 Set
*members
= userdata
;
746 r
= free_and_strdup(&m
->interface
, interface
);
750 r
= free_and_strdup(&m
->name
, name
);
754 r
= free_and_strdup(&m
->signature
, signature
);
758 r
= free_and_strdup(&m
->result
, result
);
762 r
= set_put(members
, m
);
764 log_error("Duplicate method");
772 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
773 _cleanup_(member_freep
) Member
*m
;
774 Set
*members
= userdata
;
787 r
= free_and_strdup(&m
->interface
, interface
);
791 r
= free_and_strdup(&m
->name
, name
);
795 r
= free_and_strdup(&m
->signature
, signature
);
799 r
= set_put(members
, m
);
801 log_error("Duplicate signal");
809 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
810 _cleanup_(member_freep
) Member
*m
;
811 Set
*members
= userdata
;
821 m
->type
= "property";
823 m
->writable
= writable
;
825 r
= free_and_strdup(&m
->interface
, interface
);
829 r
= free_and_strdup(&m
->name
, name
);
833 r
= free_and_strdup(&m
->signature
, signature
);
837 r
= set_put(members
, m
);
839 log_error("Duplicate property");
847 static const char *strdash(const char *x
) {
848 return isempty(x
) ? "-" : x
;
851 static int introspect(sd_bus
*bus
, char **argv
) {
852 static const struct hash_ops member_hash_ops
= {
853 .hash
= member_hash_func
,
854 .compare
= member_compare_func
,
857 static const XMLIntrospectOps ops
= {
858 .on_interface
= on_interface
,
859 .on_method
= on_method
,
860 .on_signal
= on_signal
,
861 .on_property
= on_property
,
864 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
865 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
866 _cleanup_(member_set_freep
) Set
*members
= NULL
;
871 unsigned name_width
, type_width
, signature_width
, result_width
;
872 Member
**sorted
= NULL
;
873 unsigned k
= 0, j
, n_args
;
875 n_args
= strv_length(argv
);
877 log_error("Requires service and object path argument.");
882 log_error("Too many arguments.");
886 members
= set_new(&member_hash_ops
);
890 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
892 log_error("Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
896 r
= sd_bus_message_read(reply
, "s", &xml
);
898 return bus_log_parse_error(r
);
900 /* First, get list of all properties */
901 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
905 /* Second, find the current values for them */
906 SET_FOREACH(m
, members
, i
) {
908 if (!streq(m
->type
, "property"))
914 if (argv
[3] && !streq(argv
[3], m
->interface
))
917 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
919 log_error("%s", bus_error_message(&error
, r
));
923 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
925 return bus_log_parse_error(r
);
929 _cleanup_free_
char *buf
= NULL
;
930 _cleanup_fclose_
FILE *mf
= NULL
;
934 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
936 return bus_log_parse_error(r
);
941 r
= sd_bus_message_read(reply
, "s", &name
);
943 return bus_log_parse_error(r
);
945 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
947 return bus_log_parse_error(r
);
949 mf
= open_memstream(&buf
, &sz
);
953 r
= format_cmdline(reply
, mf
, false);
955 return bus_log_parse_error(r
);
960 z
= set_get(members
, &((Member
) {
962 .interface
= m
->interface
,
963 .name
= (char*) name
}));
970 r
= sd_bus_message_exit_container(reply
);
972 return bus_log_parse_error(r
);
974 r
= sd_bus_message_exit_container(reply
);
976 return bus_log_parse_error(r
);
979 r
= sd_bus_message_exit_container(reply
);
981 return bus_log_parse_error(r
);
984 pager_open_if_enabled();
986 name_width
= strlen("NAME");
987 type_width
= strlen("TYPE");
988 signature_width
= strlen("SIGNATURE");
989 result_width
= strlen("RESULT/VALUE");
991 sorted
= newa(Member
*, set_size(members
));
993 SET_FOREACH(m
, members
, i
) {
995 if (argv
[3] && !streq(argv
[3], m
->interface
))
999 name_width
= MAX(name_width
, strlen(m
->interface
));
1001 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1003 type_width
= MAX(type_width
, strlen(m
->type
));
1005 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1007 result_width
= MAX(result_width
, strlen(m
->result
));
1009 result_width
= MAX(result_width
, strlen(m
->value
));
1014 if (result_width
> 40)
1017 qsort(sorted
, k
, sizeof(Member
*), member_compare_funcp
);
1020 printf("%-*s %-*s %-*s %-*s %s\n",
1021 (int) name_width
, "NAME",
1022 (int) type_width
, "TYPE",
1023 (int) signature_width
, "SIGNATURE",
1024 (int) result_width
, "RESULT/VALUE",
1028 for (j
= 0; j
< k
; j
++) {
1029 _cleanup_free_
char *ellipsized
= NULL
;
1035 if (argv
[3] && !streq(argv
[3], m
->interface
))
1038 is_interface
= streq(m
->type
, "interface");
1040 if (argv
[3] && is_interface
)
1044 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1050 rv
= strdash(m
->result
);
1052 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1053 is_interface
? ansi_highlight() : "",
1054 is_interface
? "" : ".",
1055 - !is_interface
+ (int) name_width
, strdash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1056 is_interface
? ansi_normal() : "",
1057 (int) type_width
, strdash(m
->type
),
1058 (int) signature_width
, strdash(m
->signature
),
1059 (int) result_width
, rv
,
1060 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1061 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1062 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1063 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1064 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1065 m
->writable
? " writable" : "");
1071 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1072 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1075 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1076 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1079 static int monitor(sd_bus
*bus
, char *argv
[], int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1080 bool added_something
= false;
1084 STRV_FOREACH(i
, argv
+1) {
1085 _cleanup_free_
char *m
= NULL
;
1087 if (!service_name_is_valid(*i
)) {
1088 log_error("Invalid service name '%s'", *i
);
1092 m
= strjoin("sender='", *i
, "'", NULL
);
1096 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1098 return log_error_errno(r
, "Failed to add match: %m");
1101 m
= strjoin("destination='", *i
, "'", NULL
);
1105 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1107 return log_error_errno(r
, "Failed to add match: %m");
1109 added_something
= true;
1112 STRV_FOREACH(i
, arg_matches
) {
1113 r
= sd_bus_add_match(bus
, NULL
, *i
, NULL
, NULL
);
1115 return log_error_errno(r
, "Failed to add match: %m");
1117 added_something
= true;
1120 if (!added_something
) {
1121 r
= sd_bus_add_match(bus
, NULL
, "", NULL
, NULL
);
1123 return log_error_errno(r
, "Failed to add match: %m");
1126 log_info("Monitoring bus message stream.");
1129 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1131 r
= sd_bus_process(bus
, &m
);
1133 return log_error_errno(r
, "Failed to process bus: %m");
1139 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1140 log_info("Connection terminated, exiting.");
1150 r
= sd_bus_wait(bus
, (uint64_t) -1);
1152 return log_error_errno(r
, "Failed to wait for bus: %m");
1156 static int capture(sd_bus
*bus
, char *argv
[]) {
1159 if (isatty(fileno(stdout
)) > 0) {
1160 log_error("Refusing to write message data to console, please redirect output to a file.");
1164 bus_pcap_header(arg_snaplen
, stdout
);
1166 r
= monitor(bus
, argv
, message_pcap
);
1170 if (ferror(stdout
)) {
1171 log_error("Couldn't write capture file.");
1178 static int status(sd_bus
*bus
, char *argv
[]) {
1179 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1185 if (strv_length(argv
) > 2) {
1186 log_error("Expects no or one argument.");
1191 r
= parse_pid(argv
[1], &pid
);
1193 r
= sd_bus_get_name_creds(
1196 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1199 r
= sd_bus_creds_new_from_pid(
1204 const char *scope
, *address
;
1207 r
= sd_bus_get_address(bus
, &address
);
1209 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1211 r
= sd_bus_get_scope(bus
, &scope
);
1213 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1215 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1217 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1219 r
= sd_bus_get_owner_creds(
1221 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1226 return log_error_errno(r
, "Failed to get credentials: %m");
1228 bus_creds_dump(creds
, NULL
, false);
1232 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1252 log_error("Too few parameters for signature.");
1261 case SD_BUS_TYPE_BOOLEAN
:
1263 r
= parse_boolean(v
);
1265 log_error("Failed to parse as boolean: %s", v
);
1269 r
= sd_bus_message_append_basic(m
, t
, &r
);
1272 case SD_BUS_TYPE_BYTE
: {
1275 r
= safe_atou8(v
, &z
);
1277 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1281 r
= sd_bus_message_append_basic(m
, t
, &z
);
1285 case SD_BUS_TYPE_INT16
: {
1288 r
= safe_atoi16(v
, &z
);
1290 log_error("Failed to parse as signed 16bit integer: %s", v
);
1294 r
= sd_bus_message_append_basic(m
, t
, &z
);
1298 case SD_BUS_TYPE_UINT16
: {
1301 r
= safe_atou16(v
, &z
);
1303 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1307 r
= sd_bus_message_append_basic(m
, t
, &z
);
1311 case SD_BUS_TYPE_INT32
: {
1314 r
= safe_atoi32(v
, &z
);
1316 log_error("Failed to parse as signed 32bit integer: %s", v
);
1320 r
= sd_bus_message_append_basic(m
, t
, &z
);
1324 case SD_BUS_TYPE_UINT32
: {
1327 r
= safe_atou32(v
, &z
);
1329 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1333 r
= sd_bus_message_append_basic(m
, t
, &z
);
1337 case SD_BUS_TYPE_INT64
: {
1340 r
= safe_atoi64(v
, &z
);
1342 log_error("Failed to parse as signed 64bit integer: %s", v
);
1346 r
= sd_bus_message_append_basic(m
, t
, &z
);
1350 case SD_BUS_TYPE_UINT64
: {
1353 r
= safe_atou64(v
, &z
);
1355 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1359 r
= sd_bus_message_append_basic(m
, t
, &z
);
1364 case SD_BUS_TYPE_DOUBLE
: {
1367 r
= safe_atod(v
, &z
);
1369 log_error("Failed to parse as double precision floating point: %s", v
);
1373 r
= sd_bus_message_append_basic(m
, t
, &z
);
1377 case SD_BUS_TYPE_STRING
:
1378 case SD_BUS_TYPE_OBJECT_PATH
:
1379 case SD_BUS_TYPE_SIGNATURE
:
1381 r
= sd_bus_message_append_basic(m
, t
, v
);
1384 case SD_BUS_TYPE_ARRAY
: {
1388 r
= safe_atou32(v
, &n
);
1390 log_error("Failed to parse number of array entries: %s", v
);
1394 r
= signature_element_length(signature
, &k
);
1396 log_error("Invalid array signature.");
1403 memcpy(s
, signature
, k
);
1406 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1408 return bus_log_create_error(r
);
1410 for (i
= 0; i
< n
; i
++) {
1411 r
= message_append_cmdline(m
, s
, &p
);
1419 r
= sd_bus_message_close_container(m
);
1423 case SD_BUS_TYPE_VARIANT
:
1424 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1426 return bus_log_create_error(r
);
1428 r
= message_append_cmdline(m
, v
, &p
);
1432 r
= sd_bus_message_close_container(m
);
1435 case SD_BUS_TYPE_STRUCT_BEGIN
:
1436 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1442 r
= signature_element_length(signature
, &k
);
1444 log_error("Invalid struct/dict entry signature.");
1450 memcpy(s
, signature
+ 1, k
- 2);
1453 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1455 return bus_log_create_error(r
);
1457 r
= message_append_cmdline(m
, s
, &p
);
1464 r
= sd_bus_message_close_container(m
);
1468 case SD_BUS_TYPE_UNIX_FD
:
1469 log_error("UNIX file descriptor not supported as type.");
1473 log_error("Unknown signature type %c.", t
);
1478 return bus_log_create_error(r
);
1485 static int call(sd_bus
*bus
, char *argv
[]) {
1486 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1487 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1492 if (strv_length(argv
) < 5) {
1493 log_error("Expects at least four arguments.");
1497 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1499 return bus_log_create_error(r
);
1501 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1503 return bus_log_create_error(r
);
1505 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1507 return bus_log_create_error(r
);
1509 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1511 return bus_log_create_error(r
);
1513 if (!isempty(argv
[5])) {
1518 r
= message_append_cmdline(m
, argv
[5], &p
);
1523 log_error("Too many parameters for signature.");
1528 if (!arg_expect_reply
) {
1529 r
= sd_bus_send(bus
, m
, NULL
);
1531 log_error("Failed to send message.");
1538 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1540 log_error("%s", bus_error_message(&error
, r
));
1544 r
= sd_bus_message_is_empty(reply
);
1546 return bus_log_parse_error(r
);
1548 if (r
== 0 && !arg_quiet
) {
1551 pager_open_if_enabled();
1553 r
= bus_message_dump(reply
, stdout
, 0);
1558 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1561 r
= format_cmdline(reply
, stdout
, false);
1563 return bus_log_parse_error(r
);
1565 fputc('\n', stdout
);
1572 static int get_property(sd_bus
*bus
, char *argv
[]) {
1573 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1580 n
= strv_length(argv
);
1582 log_error("Expects at least four arguments.");
1586 STRV_FOREACH(i
, argv
+ 4) {
1587 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1588 const char *contents
= NULL
;
1591 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1593 log_error("%s", bus_error_message(&error
, r
));
1597 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1599 return bus_log_parse_error(r
);
1601 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1603 return bus_log_parse_error(r
);
1606 pager_open_if_enabled();
1608 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1612 fputs(contents
, stdout
);
1615 r
= format_cmdline(reply
, stdout
, false);
1617 return bus_log_parse_error(r
);
1619 fputc('\n', stdout
);
1622 r
= sd_bus_message_exit_container(reply
);
1624 return bus_log_parse_error(r
);
1630 static int set_property(sd_bus
*bus
, char *argv
[]) {
1631 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1632 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1639 n
= strv_length(argv
);
1641 log_error("Expects at least five arguments.");
1645 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1647 return bus_log_create_error(r
);
1649 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1651 return bus_log_create_error(r
);
1653 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1655 return bus_log_create_error(r
);
1658 r
= message_append_cmdline(m
, argv
[5], &p
);
1662 r
= sd_bus_message_close_container(m
);
1664 return bus_log_create_error(r
);
1667 log_error("Too many parameters for signature.");
1671 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1673 log_error("%s", bus_error_message(&error
, r
));
1680 static int help(void) {
1681 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1682 "Introspect the bus.\n\n"
1683 " -h --help Show this help\n"
1684 " --version Show package version\n"
1685 " --no-pager Do not pipe output into a pager\n"
1686 " --no-legend Do not show the headers and footers\n"
1687 " --system Connect to system bus\n"
1688 " --user Connect to user bus\n"
1689 " -H --host=[USER@]HOST Operate on remote host\n"
1690 " -M --machine=CONTAINER Operate on local container\n"
1691 " --address=ADDRESS Connect to bus specified by address\n"
1692 " --show-machine Show machine ID column in list\n"
1693 " --unique Only show unique names\n"
1694 " --acquired Only show acquired names\n"
1695 " --activatable Only show activatable names\n"
1696 " --match=MATCH Only show matching messages\n"
1697 " --size=SIZE Maximum length of captured packet\n"
1698 " --list Don't show tree, but simple object path list\n"
1699 " --quiet Don't show method call reply\n"
1700 " --verbose Show result values in long format\n"
1701 " --expect-reply=BOOL Expect a method call reply\n"
1702 " --auto-start=BOOL Auto-start destination service\n"
1703 " --allow-interactive-authorization=BOOL\n"
1704 " Allow interactive authorization for operation\n"
1705 " --timeout=SECS Maximum time to wait for method call completion\n"
1706 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1708 " list List bus names\n"
1709 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1710 " monitor [SERVICE...] Show bus traffic\n"
1711 " capture [SERVICE...] Capture bus traffic as pcap\n"
1712 " tree [SERVICE...] Show object tree of service\n"
1713 " introspect SERVICE OBJECT [INTERFACE]\n"
1714 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1716 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1717 " Get property value\n"
1718 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1719 " Set property value\n"
1720 " help Show this help\n"
1721 , program_invocation_short_name
);
1726 static int parse_argv(int argc
, char *argv
[]) {
1729 ARG_VERSION
= 0x100,
1745 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1750 static const struct option options
[] = {
1751 { "help", no_argument
, NULL
, 'h' },
1752 { "version", no_argument
, NULL
, ARG_VERSION
},
1753 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1754 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1755 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1756 { "user", no_argument
, NULL
, ARG_USER
},
1757 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1758 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1759 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1760 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1761 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1762 { "match", required_argument
, NULL
, ARG_MATCH
},
1763 { "host", required_argument
, NULL
, 'H' },
1764 { "machine", required_argument
, NULL
, 'M' },
1765 { "size", required_argument
, NULL
, ARG_SIZE
},
1766 { "list", no_argument
, NULL
, ARG_LIST
},
1767 { "quiet", no_argument
, NULL
, 'q' },
1768 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1769 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1770 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1771 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1772 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1773 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1782 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1793 arg_no_pager
= true;
1809 arg_address
= optarg
;
1812 case ARG_SHOW_MACHINE
:
1813 arg_show_machine
= true;
1821 arg_acquired
= true;
1824 case ARG_ACTIVATABLE
:
1825 arg_activatable
= true;
1829 if (strv_extend(&arg_matches
, optarg
) < 0)
1836 r
= parse_size(optarg
, 1024, &sz
);
1838 log_error("Failed to parse size: %s", optarg
);
1842 if ((uint64_t) (size_t) sz
!= sz
) {
1843 log_error("Size out of range.");
1847 arg_snaplen
= (size_t) sz
;
1856 arg_transport
= BUS_TRANSPORT_REMOTE
;
1861 arg_transport
= BUS_TRANSPORT_MACHINE
;
1873 case ARG_EXPECT_REPLY
:
1874 r
= parse_boolean(optarg
);
1876 log_error("Failed to parse --expect-reply= parameter.");
1880 arg_expect_reply
= !!r
;
1884 case ARG_AUTO_START
:
1885 r
= parse_boolean(optarg
);
1887 log_error("Failed to parse --auto-start= parameter.");
1891 arg_auto_start
= !!r
;
1895 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1896 r
= parse_boolean(optarg
);
1898 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1902 arg_allow_interactive_authorization
= !!r
;
1906 r
= parse_sec(optarg
, &arg_timeout
);
1908 log_error("Failed to parse --timeout= parameter.");
1914 case ARG_AUGMENT_CREDS
:
1915 r
= parse_boolean(optarg
);
1917 log_error("Failed to parse --augment-creds= parameter.");
1921 arg_augment_creds
= !!r
;
1928 assert_not_reached("Unhandled option");
1934 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1937 if (optind
>= argc
||
1938 streq(argv
[optind
], "list"))
1939 return list_bus_names(bus
, argv
+ optind
);
1941 if (streq(argv
[optind
], "monitor"))
1942 return monitor(bus
, argv
+ optind
, message_dump
);
1944 if (streq(argv
[optind
], "capture"))
1945 return capture(bus
, argv
+ optind
);
1947 if (streq(argv
[optind
], "status"))
1948 return status(bus
, argv
+ optind
);
1950 if (streq(argv
[optind
], "tree"))
1951 return tree(bus
, argv
+ optind
);
1953 if (streq(argv
[optind
], "introspect"))
1954 return introspect(bus
, argv
+ optind
);
1956 if (streq(argv
[optind
], "call"))
1957 return call(bus
, argv
+ optind
);
1959 if (streq(argv
[optind
], "get-property"))
1960 return get_property(bus
, argv
+ optind
);
1962 if (streq(argv
[optind
], "set-property"))
1963 return set_property(bus
, argv
+ optind
);
1965 if (streq(argv
[optind
], "help"))
1968 log_error("Unknown command '%s'", argv
[optind
]);
1972 int main(int argc
, char *argv
[]) {
1973 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1976 log_parse_environment();
1979 r
= parse_argv(argc
, argv
);
1983 r
= sd_bus_new(&bus
);
1985 log_error_errno(r
, "Failed to allocate bus: %m");
1989 if (streq_ptr(argv
[optind
], "monitor") ||
1990 streq_ptr(argv
[optind
], "capture")) {
1992 r
= sd_bus_set_monitor(bus
, true);
1994 log_error_errno(r
, "Failed to set monitor mode: %m");
1998 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
2000 log_error_errno(r
, "Failed to enable credentials: %m");
2004 r
= sd_bus_negotiate_timestamp(bus
, true);
2006 log_error_errno(r
, "Failed to enable timestamps: %m");
2010 r
= sd_bus_negotiate_fds(bus
, true);
2012 log_error_errno(r
, "Failed to enable fds: %m");
2017 r
= sd_bus_set_bus_client(bus
, true);
2019 log_error_errno(r
, "Failed to set bus client: %m");
2024 r
= sd_bus_set_address(bus
, arg_address
);
2026 switch (arg_transport
) {
2028 case BUS_TRANSPORT_LOCAL
:
2030 bus
->is_user
= true;
2031 r
= bus_set_address_user(bus
);
2033 bus
->is_system
= true;
2034 r
= bus_set_address_system(bus
);
2038 case BUS_TRANSPORT_REMOTE
:
2039 r
= bus_set_address_system_remote(bus
, arg_host
);
2042 case BUS_TRANSPORT_MACHINE
:
2043 r
= bus_set_address_system_machine(bus
, arg_host
);
2047 assert_not_reached("Hmm, unknown transport type.");
2051 log_error_errno(r
, "Failed to set address: %m");
2055 r
= sd_bus_start(bus
);
2057 log_error_errno(r
, "Failed to connect to bus: %m");
2061 r
= busctl_main(bus
, argc
, argv
);
2066 strv_free(arg_matches
);
2068 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;