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/>.
30 #include "path-util.h"
33 #include "bus-message.h"
34 #include "bus-internal.h"
37 #include "bus-signature.h"
39 #include "busctl-introspect.h"
41 static bool arg_no_pager
= false;
42 static bool arg_legend
= true;
43 static char *arg_address
= NULL
;
44 static bool arg_unique
= false;
45 static bool arg_acquired
= false;
46 static bool arg_activatable
= false;
47 static bool arg_show_machine
= false;
48 static char **arg_matches
= NULL
;
49 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
50 static char *arg_host
= NULL
;
51 static bool arg_user
= false;
52 static size_t arg_snaplen
= 4096;
53 static bool arg_list
= false;
54 static bool arg_quiet
= false;
55 static bool arg_verbose
= false;
56 static bool arg_expect_reply
= true;
57 static bool arg_auto_start
= true;
58 static bool arg_allow_interactive_authorization
= true;
59 static bool arg_augment_creds
= true;
60 static usec_t arg_timeout
= 0;
62 static void pager_open_if_enabled(void) {
64 /* Cache result before we open the pager */
71 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
72 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
74 static int list_bus_names(sd_bus
*bus
, char **argv
) {
75 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
76 _cleanup_free_
char **merged
= NULL
;
77 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
88 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
89 arg_unique
= arg_acquired
= arg_activatable
= true;
91 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
93 return log_error_errno(r
, "Failed to list names: %m");
95 pager_open_if_enabled();
97 names
= hashmap_new(&string_hash_ops
);
101 STRV_FOREACH(i
, acquired
) {
102 max_i
= MAX(max_i
, strlen(*i
));
104 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
106 return log_error_errno(r
, "Failed to add to hashmap: %m");
109 STRV_FOREACH(i
, activatable
) {
110 max_i
= MAX(max_i
, strlen(*i
));
112 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
113 if (r
< 0 && r
!= -EEXIST
)
114 return log_error_errno(r
, "Failed to add to hashmap: %m");
117 merged
= new(char*, hashmap_size(names
) + 1);
118 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
125 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
126 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
128 if (arg_show_machine
)
134 STRV_FOREACH(i
, merged
) {
135 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
138 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
141 printf("%-*s", (int) max_i
, *i
);
142 printf(" - - - (activatable) - - ");
143 if (arg_show_machine
)
151 if (!arg_unique
&& (*i
)[0] == ':')
154 if (!arg_acquired
&& (*i
)[0] != ':')
157 printf("%-*s", (int) max_i
, *i
);
159 r
= sd_bus_get_name_creds(
161 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
162 SD_BUS_CREDS_UID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
163 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
164 SD_BUS_CREDS_DESCRIPTION
, &creds
);
166 const char *unique
, *session
, *unit
, *cn
;
170 r
= sd_bus_creds_get_pid(creds
, &pid
);
172 const char *comm
= NULL
;
174 sd_bus_creds_get_comm(creds
, &comm
);
176 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
178 fputs(" - - ", stdout
);
180 r
= sd_bus_creds_get_uid(creds
, &uid
);
182 _cleanup_free_
char *u
= NULL
;
184 u
= uid_to_name(uid
);
193 fputs(" - ", stdout
);
195 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
197 printf(" %-13s", unique
);
199 fputs(" - ", stdout
);
201 r
= sd_bus_creds_get_unit(creds
, &unit
);
203 _cleanup_free_
char *e
;
205 e
= ellipsize(unit
, 25, 100);
211 fputs(" - ", stdout
);
213 r
= sd_bus_creds_get_session(creds
, &session
);
215 printf(" %-10s", session
);
217 fputs(" - ", stdout
);
219 r
= sd_bus_creds_get_description(creds
, &cn
);
221 printf(" %-19s", cn
);
223 fputs(" - ", stdout
);
226 printf(" - - - - - - - ");
228 if (arg_show_machine
) {
229 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
231 char m
[SD_ID128_STRING_MAX
];
232 printf(" %s\n", sd_id128_to_string(mid
, m
));
242 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
243 const char *vertical
, *space
;
246 /* We assume the list is sorted. Let's first skip over the
247 * entry we are looking at. */
252 if (!streq(*l
, path
))
258 vertical
= strappenda(prefix
, draw_special_char(DRAW_TREE_VERTICAL
));
259 space
= strappenda(prefix
, draw_special_char(DRAW_TREE_SPACE
));
262 bool has_more
= false;
264 if (!*l
|| !path_startswith(*l
, path
))
269 if (!*n
|| !path_startswith(*n
, path
))
272 if (!path_startswith(*n
, *l
)) {
280 printf("%s%s%s\n", prefix
, draw_special_char(has_more
? DRAW_TREE_BRANCH
: DRAW_TREE_RIGHT
), *l
);
282 print_subtree(has_more
? vertical
: space
, *l
, l
);
287 static void print_tree(const char *prefix
, char **l
) {
289 pager_open_if_enabled();
291 prefix
= strempty(prefix
);
297 printf("%s%s\n", prefix
, *i
);
301 if (strv_isempty(l
)) {
302 printf("No objects discovered.\n");
306 if (streq(l
[0], "/") && !l
[1]) {
307 printf("Only root object discovered.\n");
311 print_subtree(prefix
, "/", l
);
314 static int on_path(const char *path
, void *userdata
) {
315 Set
*paths
= userdata
;
320 r
= set_put_strdup(paths
, path
);
327 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
328 static const XMLIntrospectOps ops
= {
332 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
333 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
337 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
340 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
342 log_error("Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
346 r
= sd_bus_message_read(reply
, "s", &xml
);
348 return bus_log_parse_error(r
);
350 return parse_xml_introspect(path
, xml
, &ops
, paths
);
353 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
354 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
355 _cleanup_free_
char **l
= NULL
;
359 paths
= set_new(&string_hash_ops
);
363 done
= set_new(&string_hash_ops
);
367 failed
= set_new(&string_hash_ops
);
375 r
= set_put(paths
, m
);
382 _cleanup_free_
char *p
= NULL
;
385 p
= set_steal_first(paths
);
389 if (set_contains(done
, p
) ||
390 set_contains(failed
, p
))
393 q
= find_nodes(bus
, service
, p
, paths
, many
);
398 q
= set_put(failed
, p
);
400 q
= set_put(done
, p
);
409 pager_open_if_enabled();
411 l
= set_get_strv(done
);
416 print_tree(prefix
, l
);
423 static int tree(sd_bus
*bus
, char **argv
) {
427 if (!arg_unique
&& !arg_acquired
)
430 if (strv_length(argv
) <= 1) {
431 _cleanup_strv_free_
char **names
= NULL
;
432 bool not_first
= false;
434 r
= sd_bus_list_names(bus
, &names
, NULL
);
436 return log_error_errno(r
, "Failed to get name list: %m");
438 pager_open_if_enabled();
440 STRV_FOREACH(i
, names
) {
443 if (!arg_unique
&& (*i
)[0] == ':')
446 if (!arg_acquired
&& (*i
)[0] == ':')
452 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_highlight_off());
454 q
= tree_one(bus
, *i
, NULL
, true);
461 STRV_FOREACH(i
, argv
+1) {
468 pager_open_if_enabled();
469 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_highlight_off());
472 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
481 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
485 const char *contents
= NULL
;
500 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
504 if (bus_type_is_container(type
) > 0) {
506 r
= sd_bus_message_enter_container(m
, type
, contents
);
510 if (type
== SD_BUS_TYPE_ARRAY
) {
513 /* count array entries */
516 r
= sd_bus_message_skip(m
, contents
);
525 r
= sd_bus_message_rewind(m
, false);
533 } else if (type
== SD_BUS_TYPE_VARIANT
) {
538 fprintf(f
, "%s", contents
);
541 r
= format_cmdline(m
, f
, true);
545 r
= sd_bus_message_exit_container(m
);
552 r
= sd_bus_message_read_basic(m
, type
, &basic
);
560 case SD_BUS_TYPE_BYTE
:
561 fprintf(f
, "%u", basic
.u8
);
564 case SD_BUS_TYPE_BOOLEAN
:
565 fputs(true_false(basic
.i
), f
);
568 case SD_BUS_TYPE_INT16
:
569 fprintf(f
, "%i", basic
.s16
);
572 case SD_BUS_TYPE_UINT16
:
573 fprintf(f
, "%u", basic
.u16
);
576 case SD_BUS_TYPE_INT32
:
577 fprintf(f
, "%i", basic
.s32
);
580 case SD_BUS_TYPE_UINT32
:
581 fprintf(f
, "%u", basic
.u32
);
584 case SD_BUS_TYPE_INT64
:
585 fprintf(f
, "%" PRIi64
, basic
.s64
);
588 case SD_BUS_TYPE_UINT64
:
589 fprintf(f
, "%" PRIu64
, basic
.u64
);
592 case SD_BUS_TYPE_DOUBLE
:
593 fprintf(f
, "%g", basic
.d64
);
596 case SD_BUS_TYPE_STRING
:
597 case SD_BUS_TYPE_OBJECT_PATH
:
598 case SD_BUS_TYPE_SIGNATURE
: {
599 _cleanup_free_
char *b
= NULL
;
601 b
= cescape(basic
.string
);
605 fprintf(f
, "\"%s\"", b
);
609 case SD_BUS_TYPE_UNIX_FD
:
610 fprintf(f
, "%i", basic
.i
);
614 assert_not_reached("Unknown basic type.");
620 typedef struct Member
{
631 static unsigned long member_hash_func(const void *p
, const uint8_t hash_key
[]) {
638 ul
= string_hash_func(m
->type
, hash_key
);
641 ul
^= string_hash_func(m
->name
, hash_key
);
644 ul
^= string_hash_func(m
->interface
, hash_key
);
649 static int member_compare_func(const void *a
, const void *b
) {
650 const Member
*x
= a
, *y
= b
;
658 if (!x
->interface
&& y
->interface
)
660 if (x
->interface
&& !y
->interface
)
662 if (x
->interface
&& y
->interface
) {
663 d
= strcmp(x
->interface
, y
->interface
);
668 d
= strcmp(x
->type
, y
->type
);
672 if (!x
->name
&& y
->name
)
674 if (x
->name
&& !y
->name
)
676 if (x
->name
&& y
->name
)
677 return strcmp(x
->name
, y
->name
);
682 static int member_compare_funcp(const void *a
, const void *b
) {
683 const Member
*const * x
= (const Member
*const *) a
, * const *y
= (const Member
*const *) b
;
685 return member_compare_func(*x
, *y
);
688 static void member_free(Member
*m
) {
700 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
702 static void member_set_free(Set
*s
) {
705 while ((m
= set_steal_first(s
)))
711 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
713 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
714 _cleanup_(member_freep
) Member
*m
;
715 Set
*members
= userdata
;
725 m
->type
= "interface";
728 r
= free_and_strdup(&m
->interface
, interface
);
732 r
= set_put(members
, m
);
734 log_error("Duplicate interface");
742 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
743 _cleanup_(member_freep
) Member
*m
;
744 Set
*members
= userdata
;
757 r
= free_and_strdup(&m
->interface
, interface
);
761 r
= free_and_strdup(&m
->name
, name
);
765 r
= free_and_strdup(&m
->signature
, signature
);
769 r
= free_and_strdup(&m
->result
, result
);
773 r
= set_put(members
, m
);
775 log_error("Duplicate method");
783 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
784 _cleanup_(member_freep
) Member
*m
;
785 Set
*members
= userdata
;
798 r
= free_and_strdup(&m
->interface
, interface
);
802 r
= free_and_strdup(&m
->name
, name
);
806 r
= free_and_strdup(&m
->signature
, signature
);
810 r
= set_put(members
, m
);
812 log_error("Duplicate signal");
820 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
821 _cleanup_(member_freep
) Member
*m
;
822 Set
*members
= userdata
;
832 m
->type
= "property";
834 m
->writable
= writable
;
836 r
= free_and_strdup(&m
->interface
, interface
);
840 r
= free_and_strdup(&m
->name
, name
);
844 r
= free_and_strdup(&m
->signature
, signature
);
848 r
= set_put(members
, m
);
850 log_error("Duplicate property");
858 static const char *strdash(const char *x
) {
859 return isempty(x
) ? "-" : x
;
862 static int introspect(sd_bus
*bus
, char **argv
) {
863 static const struct hash_ops member_hash_ops
= {
864 .hash
= member_hash_func
,
865 .compare
= member_compare_func
,
868 static const XMLIntrospectOps ops
= {
869 .on_interface
= on_interface
,
870 .on_method
= on_method
,
871 .on_signal
= on_signal
,
872 .on_property
= on_property
,
875 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
876 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
877 _cleanup_(member_set_freep
) Set
*members
= NULL
;
882 unsigned name_width
, type_width
, signature_width
, result_width
;
883 Member
**sorted
= NULL
;
886 if (strv_length(argv
) != 3) {
887 log_error("Requires service and object path argument.");
891 members
= set_new(&member_hash_ops
);
895 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
897 log_error("Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
901 r
= sd_bus_message_read(reply
, "s", &xml
);
903 return bus_log_parse_error(r
);
905 /* First, get list of all properties */
906 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
910 /* Second, find the current values for them */
911 SET_FOREACH(m
, members
, i
) {
913 if (!streq(m
->type
, "property"))
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 name_width
= MAX(name_width
, strlen(m
->interface
));
999 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1001 type_width
= MAX(type_width
, strlen(m
->type
));
1003 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1005 result_width
= MAX(result_width
, strlen(m
->result
));
1007 result_width
= MAX(result_width
, strlen(m
->value
));
1012 if (result_width
> 40)
1015 assert(k
== set_size(members
));
1016 qsort(sorted
, k
, sizeof(Member
*), member_compare_funcp
);
1019 printf("%-*s %-*s %-*s %-*s %s\n",
1020 (int) name_width
, "NAME",
1021 (int) type_width
, "TYPE",
1022 (int) signature_width
, "SIGNATURE",
1023 (int) result_width
, "RESULT/VALUE",
1027 for (j
= 0; j
< k
; j
++) {
1028 _cleanup_free_
char *ellipsized
= NULL
;
1034 is_interface
= streq(m
->type
, "interface");
1037 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1043 rv
= strdash(m
->result
);
1045 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1046 is_interface
? ansi_highlight() : "",
1047 is_interface
? "" : ".",
1048 - !is_interface
+ (int) name_width
, strdash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1049 is_interface
? ansi_highlight_off() : "",
1050 (int) type_width
, strdash(m
->type
),
1051 (int) signature_width
, strdash(m
->signature
),
1052 (int) result_width
, rv
,
1053 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1054 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1055 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1056 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1057 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1058 m
->writable
? " writable" : "");
1064 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1065 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1068 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1069 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1072 static int monitor(sd_bus
*bus
, char *argv
[], int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1073 bool added_something
= false;
1077 STRV_FOREACH(i
, argv
+1) {
1078 _cleanup_free_
char *m
= NULL
;
1080 if (!service_name_is_valid(*i
)) {
1081 log_error("Invalid service name '%s'", *i
);
1085 m
= strjoin("sender='", *i
, "'", NULL
);
1089 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1091 return log_error_errno(r
, "Failed to add match: %m");
1093 added_something
= true;
1096 STRV_FOREACH(i
, arg_matches
) {
1097 r
= sd_bus_add_match(bus
, NULL
, *i
, NULL
, NULL
);
1099 return log_error_errno(r
, "Failed to add match: %m");
1101 added_something
= true;
1104 if (!added_something
) {
1105 r
= sd_bus_add_match(bus
, NULL
, "", NULL
, NULL
);
1107 return log_error_errno(r
, "Failed to add match: %m");
1111 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1113 r
= sd_bus_process(bus
, &m
);
1115 return log_error_errno(r
, "Failed to process bus: %m");
1125 r
= sd_bus_wait(bus
, (uint64_t) -1);
1127 return log_error_errno(r
, "Failed to wait for bus: %m");
1131 static int capture(sd_bus
*bus
, char *argv
[]) {
1134 if (isatty(fileno(stdout
)) > 0) {
1135 log_error("Refusing to write message data to console, please redirect output to a file.");
1139 bus_pcap_header(arg_snaplen
, stdout
);
1141 r
= monitor(bus
, argv
, message_pcap
);
1145 if (ferror(stdout
)) {
1146 log_error("Couldn't write capture file.");
1153 static int status(sd_bus
*bus
, char *argv
[]) {
1154 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1160 if (strv_length(argv
) > 2) {
1161 log_error("Expects no or one argument.");
1166 r
= parse_pid(argv
[1], &pid
);
1168 r
= sd_bus_get_name_creds(
1171 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1174 r
= sd_bus_creds_new_from_pid(
1182 r
= sd_bus_get_scope(bus
, &scope
);
1184 printf("Scope=%s%s%s\n", ansi_highlight(), scope
, ansi_highlight_off());
1186 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1188 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_highlight_off());
1190 r
= sd_bus_get_owner_creds(
1192 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1197 return log_error_errno(r
, "Failed to get credentials: %m");
1199 bus_creds_dump(creds
, NULL
, false);
1203 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1223 log_error("Too few parameters for signature.");
1232 case SD_BUS_TYPE_BOOLEAN
:
1234 r
= parse_boolean(v
);
1236 log_error("Failed to parse as boolean: %s", v
);
1240 r
= sd_bus_message_append_basic(m
, t
, &r
);
1243 case SD_BUS_TYPE_BYTE
: {
1246 r
= safe_atou8(v
, &z
);
1248 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1252 r
= sd_bus_message_append_basic(m
, t
, &z
);
1256 case SD_BUS_TYPE_INT16
: {
1259 r
= safe_atoi16(v
, &z
);
1261 log_error("Failed to parse as signed 16bit integer: %s", v
);
1265 r
= sd_bus_message_append_basic(m
, t
, &z
);
1269 case SD_BUS_TYPE_UINT16
: {
1272 r
= safe_atou16(v
, &z
);
1274 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1278 r
= sd_bus_message_append_basic(m
, t
, &z
);
1282 case SD_BUS_TYPE_INT32
: {
1285 r
= safe_atoi32(v
, &z
);
1287 log_error("Failed to parse as signed 32bit integer: %s", v
);
1291 r
= sd_bus_message_append_basic(m
, t
, &z
);
1295 case SD_BUS_TYPE_UINT32
: {
1298 r
= safe_atou32(v
, &z
);
1300 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1304 r
= sd_bus_message_append_basic(m
, t
, &z
);
1308 case SD_BUS_TYPE_INT64
: {
1311 r
= safe_atoi64(v
, &z
);
1313 log_error("Failed to parse as signed 64bit integer: %s", v
);
1317 r
= sd_bus_message_append_basic(m
, t
, &z
);
1321 case SD_BUS_TYPE_UINT64
: {
1324 r
= safe_atou64(v
, &z
);
1326 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1330 r
= sd_bus_message_append_basic(m
, t
, &z
);
1335 case SD_BUS_TYPE_DOUBLE
: {
1338 r
= safe_atod(v
, &z
);
1340 log_error("Failed to parse as double precision floating point: %s", v
);
1344 r
= sd_bus_message_append_basic(m
, t
, &z
);
1348 case SD_BUS_TYPE_STRING
:
1349 case SD_BUS_TYPE_OBJECT_PATH
:
1350 case SD_BUS_TYPE_SIGNATURE
:
1352 r
= sd_bus_message_append_basic(m
, t
, v
);
1355 case SD_BUS_TYPE_ARRAY
: {
1359 r
= safe_atou32(v
, &n
);
1361 log_error("Failed to parse number of array entries: %s", v
);
1365 r
= signature_element_length(signature
, &k
);
1367 log_error("Invalid array signature.");
1374 memcpy(s
, signature
, k
);
1377 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1379 return bus_log_create_error(r
);
1381 for (i
= 0; i
< n
; i
++) {
1382 r
= message_append_cmdline(m
, s
, &p
);
1390 r
= sd_bus_message_close_container(m
);
1394 case SD_BUS_TYPE_VARIANT
:
1395 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1397 return bus_log_create_error(r
);
1399 r
= message_append_cmdline(m
, v
, &p
);
1403 r
= sd_bus_message_close_container(m
);
1406 case SD_BUS_TYPE_STRUCT_BEGIN
:
1407 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1413 r
= signature_element_length(signature
, &k
);
1415 log_error("Invalid struct/dict entry signature.");
1421 memcpy(s
, signature
+ 1, k
- 2);
1424 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1426 return bus_log_create_error(r
);
1428 r
= message_append_cmdline(m
, s
, &p
);
1435 r
= sd_bus_message_close_container(m
);
1439 case SD_BUS_TYPE_UNIX_FD
:
1440 log_error("UNIX file descriptor not supported as type.");
1444 log_error("Unknown signature type %c.", t
);
1449 return bus_log_create_error(r
);
1456 static int call(sd_bus
*bus
, char *argv
[]) {
1457 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1458 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1463 if (strv_length(argv
) < 5) {
1464 log_error("Expects at least four arguments.");
1468 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1470 return bus_log_create_error(r
);
1472 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1474 return bus_log_create_error(r
);
1476 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1478 return bus_log_create_error(r
);
1480 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1482 return bus_log_create_error(r
);
1484 if (!isempty(argv
[5])) {
1489 r
= message_append_cmdline(m
, argv
[5], &p
);
1494 log_error("Too many parameters for signature.");
1499 if (!arg_expect_reply
) {
1500 r
= sd_bus_send(bus
, m
, NULL
);
1502 log_error("Failed to send message.");
1509 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1511 log_error("%s", bus_error_message(&error
, r
));
1515 r
= sd_bus_message_is_empty(reply
);
1517 return bus_log_parse_error(r
);
1519 if (r
== 0 && !arg_quiet
) {
1522 pager_open_if_enabled();
1524 r
= bus_message_dump(reply
, stdout
, 0);
1529 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1532 r
= format_cmdline(reply
, stdout
, false);
1534 return bus_log_parse_error(r
);
1536 fputc('\n', stdout
);
1543 static int get_property(sd_bus
*bus
, char *argv
[]) {
1544 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1551 n
= strv_length(argv
);
1553 log_error("Expects at least four arguments.");
1557 STRV_FOREACH(i
, argv
+ 4) {
1558 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1559 const char *contents
= NULL
;
1562 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1564 log_error("%s", bus_error_message(&error
, r
));
1568 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1570 return bus_log_parse_error(r
);
1572 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1574 return bus_log_parse_error(r
);
1577 pager_open_if_enabled();
1579 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1583 fputs(contents
, stdout
);
1586 r
= format_cmdline(reply
, stdout
, false);
1588 return bus_log_parse_error(r
);
1590 fputc('\n', stdout
);
1593 r
= sd_bus_message_exit_container(reply
);
1595 return bus_log_parse_error(r
);
1601 static int set_property(sd_bus
*bus
, char *argv
[]) {
1602 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1603 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1610 n
= strv_length(argv
);
1612 log_error("Expects at least five arguments.");
1616 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1618 return bus_log_create_error(r
);
1620 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1622 return bus_log_create_error(r
);
1624 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1626 return bus_log_create_error(r
);
1629 r
= message_append_cmdline(m
, argv
[5], &p
);
1633 r
= sd_bus_message_close_container(m
);
1635 return bus_log_create_error(r
);
1638 log_error("Too many parameters for signature.");
1642 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1644 log_error("%s", bus_error_message(&error
, r
));
1651 static int help(void) {
1652 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1653 "Introspect the bus.\n\n"
1654 " -h --help Show this help\n"
1655 " --version Show package version\n"
1656 " --no-pager Do not pipe output into a pager\n"
1657 " --no-legend Do not show the headers and footers\n"
1658 " --system Connect to system bus\n"
1659 " --user Connect to user bus\n"
1660 " -H --host=[USER@]HOST Operate on remote host\n"
1661 " -M --machine=CONTAINER Operate on local container\n"
1662 " --address=ADDRESS Connect to bus specified by address\n"
1663 " --show-machine Show machine ID column in list\n"
1664 " --unique Only show unique names\n"
1665 " --acquired Only show acquired names\n"
1666 " --activatable Only show activatable names\n"
1667 " --match=MATCH Only show matching messages\n"
1668 " --list Don't show tree, but simple object path list\n"
1669 " --quiet Don't show method call reply\n"
1670 " --verbose Show result values in long format\n"
1671 " --expect-reply=BOOL Expect a method call reply\n"
1672 " --auto-start=BOOL Auto-start destination service\n"
1673 " --allow-interactive-authorization=BOOL\n"
1674 " Allow interactive authorization for operation\n"
1675 " --timeout=SECS Maximum time to wait for method call completion\n"
1676 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1678 " list List bus names\n"
1679 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1680 " monitor [SERVICE...] Show bus traffic\n"
1681 " capture [SERVICE...] Capture bus traffic as pcap\n"
1682 " tree [SERVICE...] Show object tree of service\n"
1683 " introspect SERVICE OBJECT\n"
1684 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1686 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1687 " Get property value\n"
1688 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1689 " Set property value\n"
1690 " help Show this help\n"
1691 , program_invocation_short_name
);
1696 static int parse_argv(int argc
, char *argv
[]) {
1699 ARG_VERSION
= 0x100,
1715 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1720 static const struct option options
[] = {
1721 { "help", no_argument
, NULL
, 'h' },
1722 { "version", no_argument
, NULL
, ARG_VERSION
},
1723 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1724 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1725 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1726 { "user", no_argument
, NULL
, ARG_USER
},
1727 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1728 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1729 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1730 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1731 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1732 { "match", required_argument
, NULL
, ARG_MATCH
},
1733 { "host", required_argument
, NULL
, 'H' },
1734 { "machine", required_argument
, NULL
, 'M' },
1735 { "size", required_argument
, NULL
, ARG_SIZE
},
1736 { "list", no_argument
, NULL
, ARG_LIST
},
1737 { "quiet", no_argument
, NULL
, 'q' },
1738 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1739 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1740 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1741 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1742 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1743 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1752 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1760 puts(PACKAGE_STRING
);
1761 puts(SYSTEMD_FEATURES
);
1765 arg_no_pager
= true;
1781 arg_address
= optarg
;
1784 case ARG_SHOW_MACHINE
:
1785 arg_show_machine
= true;
1793 arg_acquired
= true;
1796 case ARG_ACTIVATABLE
:
1797 arg_activatable
= true;
1801 if (strv_extend(&arg_matches
, optarg
) < 0)
1808 r
= parse_size(optarg
, 0, &o
);
1810 log_error("Failed to parse size: %s", optarg
);
1814 if ((off_t
) (size_t) o
!= o
) {
1815 log_error("Size out of range.");
1819 arg_snaplen
= (size_t) o
;
1828 arg_transport
= BUS_TRANSPORT_REMOTE
;
1833 arg_transport
= BUS_TRANSPORT_CONTAINER
;
1845 case ARG_EXPECT_REPLY
:
1846 r
= parse_boolean(optarg
);
1848 log_error("Failed to parse --expect-reply= parameter.");
1852 arg_expect_reply
= !!r
;
1856 case ARG_AUTO_START
:
1857 r
= parse_boolean(optarg
);
1859 log_error("Failed to parse --auto-start= parameter.");
1863 arg_auto_start
= !!r
;
1867 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1868 r
= parse_boolean(optarg
);
1870 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1874 arg_allow_interactive_authorization
= !!r
;
1878 r
= parse_sec(optarg
, &arg_timeout
);
1880 log_error("Failed to parse --timeout= parameter.");
1886 case ARG_AUGMENT_CREDS
:
1887 r
= parse_boolean(optarg
);
1889 log_error("Failed to parse --augment-creds= parameter.");
1893 arg_augment_creds
= !!r
;
1900 assert_not_reached("Unhandled option");
1906 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1909 if (optind
>= argc
||
1910 streq(argv
[optind
], "list"))
1911 return list_bus_names(bus
, argv
+ optind
);
1913 if (streq(argv
[optind
], "monitor"))
1914 return monitor(bus
, argv
+ optind
, message_dump
);
1916 if (streq(argv
[optind
], "capture"))
1917 return capture(bus
, argv
+ optind
);
1919 if (streq(argv
[optind
], "status"))
1920 return status(bus
, argv
+ optind
);
1922 if (streq(argv
[optind
], "tree"))
1923 return tree(bus
, argv
+ optind
);
1925 if (streq(argv
[optind
], "introspect"))
1926 return introspect(bus
, argv
+ optind
);
1928 if (streq(argv
[optind
], "call"))
1929 return call(bus
, argv
+ optind
);
1931 if (streq(argv
[optind
], "get-property"))
1932 return get_property(bus
, argv
+ optind
);
1934 if (streq(argv
[optind
], "set-property"))
1935 return set_property(bus
, argv
+ optind
);
1937 if (streq(argv
[optind
], "help"))
1940 log_error("Unknown command '%s'", argv
[optind
]);
1944 int main(int argc
, char *argv
[]) {
1945 _cleanup_bus_close_unref_ sd_bus
*bus
= NULL
;
1948 log_parse_environment();
1951 r
= parse_argv(argc
, argv
);
1955 r
= sd_bus_new(&bus
);
1957 log_error_errno(r
, "Failed to allocate bus: %m");
1961 if (streq_ptr(argv
[optind
], "monitor") ||
1962 streq_ptr(argv
[optind
], "capture")) {
1964 r
= sd_bus_set_monitor(bus
, true);
1966 log_error_errno(r
, "Failed to set monitor mode: %m");
1970 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
1972 log_error_errno(r
, "Failed to enable credentials: %m");
1976 r
= sd_bus_negotiate_timestamp(bus
, true);
1978 log_error_errno(r
, "Failed to enable timestamps: %m");
1982 r
= sd_bus_negotiate_fds(bus
, true);
1984 log_error_errno(r
, "Failed to enable fds: %m");
1990 r
= sd_bus_set_address(bus
, arg_address
);
1992 r
= sd_bus_set_bus_client(bus
, true);
1994 log_error_errno(r
, "Failed to set bus client: %m");
1998 switch (arg_transport
) {
2000 case BUS_TRANSPORT_LOCAL
:
2002 bus
->is_user
= true;
2003 r
= bus_set_address_user(bus
);
2005 bus
->is_system
= true;
2006 r
= bus_set_address_system(bus
);
2010 case BUS_TRANSPORT_REMOTE
:
2011 r
= bus_set_address_system_remote(bus
, arg_host
);
2014 case BUS_TRANSPORT_CONTAINER
:
2015 r
= bus_set_address_system_container(bus
, arg_host
);
2019 assert_not_reached("Hmm, unknown transport type.");
2023 log_error_errno(r
, "Failed to set address: %m");
2027 r
= sd_bus_start(bus
);
2029 log_error_errno(r
, "Failed to connect to bus: %m");
2033 r
= busctl_main(bus
, argc
, argv
);
2038 strv_free(arg_matches
);
2040 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;