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/>.
29 #include "path-util.h"
33 #include "bus-internal.h"
36 #include "bus-signature.h"
38 #include "busctl-introspect.h"
39 #include "terminal-util.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_EUID
|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_euid(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
= strjoina(prefix
, draw_special_char(DRAW_TREE_VERTICAL
));
259 space
= strjoina(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_normal());
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_normal());
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
, needs_space
|| IN_SET(type
, SD_BUS_TYPE_ARRAY
, SD_BUS_TYPE_VARIANT
));
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.");
621 typedef struct Member
{
632 static unsigned long member_hash_func(const void *p
, const uint8_t hash_key
[]) {
639 ul
= string_hash_func(m
->type
, hash_key
);
642 ul
^= string_hash_func(m
->name
, hash_key
);
645 ul
^= string_hash_func(m
->interface
, hash_key
);
650 static int member_compare_func(const void *a
, const void *b
) {
651 const Member
*x
= a
, *y
= b
;
659 d
= strcmp_ptr(x
->interface
, y
->interface
);
663 d
= strcmp(x
->type
, y
->type
);
667 return strcmp_ptr(x
->name
, y
->name
);
670 static int member_compare_funcp(const void *a
, const void *b
) {
671 const Member
*const * x
= (const Member
*const *) a
, * const *y
= (const Member
*const *) b
;
673 return member_compare_func(*x
, *y
);
676 static void member_free(Member
*m
) {
688 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
690 static void member_set_free(Set
*s
) {
693 while ((m
= set_steal_first(s
)))
699 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
701 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
702 _cleanup_(member_freep
) Member
*m
;
703 Set
*members
= userdata
;
713 m
->type
= "interface";
716 r
= free_and_strdup(&m
->interface
, interface
);
720 r
= set_put(members
, m
);
722 log_error("Duplicate interface");
730 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
731 _cleanup_(member_freep
) Member
*m
;
732 Set
*members
= userdata
;
745 r
= free_and_strdup(&m
->interface
, interface
);
749 r
= free_and_strdup(&m
->name
, name
);
753 r
= free_and_strdup(&m
->signature
, signature
);
757 r
= free_and_strdup(&m
->result
, result
);
761 r
= set_put(members
, m
);
763 log_error("Duplicate method");
771 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
772 _cleanup_(member_freep
) Member
*m
;
773 Set
*members
= userdata
;
786 r
= free_and_strdup(&m
->interface
, interface
);
790 r
= free_and_strdup(&m
->name
, name
);
794 r
= free_and_strdup(&m
->signature
, signature
);
798 r
= set_put(members
, m
);
800 log_error("Duplicate signal");
808 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
809 _cleanup_(member_freep
) Member
*m
;
810 Set
*members
= userdata
;
820 m
->type
= "property";
822 m
->writable
= writable
;
824 r
= free_and_strdup(&m
->interface
, interface
);
828 r
= free_and_strdup(&m
->name
, name
);
832 r
= free_and_strdup(&m
->signature
, signature
);
836 r
= set_put(members
, m
);
838 log_error("Duplicate property");
846 static const char *strdash(const char *x
) {
847 return isempty(x
) ? "-" : x
;
850 static int introspect(sd_bus
*bus
, char **argv
) {
851 static const struct hash_ops member_hash_ops
= {
852 .hash
= member_hash_func
,
853 .compare
= member_compare_func
,
856 static const XMLIntrospectOps ops
= {
857 .on_interface
= on_interface
,
858 .on_method
= on_method
,
859 .on_signal
= on_signal
,
860 .on_property
= on_property
,
863 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
864 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
865 _cleanup_(member_set_freep
) Set
*members
= NULL
;
870 unsigned name_width
, type_width
, signature_width
, result_width
;
871 Member
**sorted
= NULL
;
872 unsigned k
= 0, j
, n_args
;
874 n_args
= strv_length(argv
);
876 log_error("Requires service and object path argument.");
881 log_error("Too many arguments.");
885 members
= set_new(&member_hash_ops
);
889 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
891 log_error("Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
895 r
= sd_bus_message_read(reply
, "s", &xml
);
897 return bus_log_parse_error(r
);
899 /* First, get list of all properties */
900 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
904 /* Second, find the current values for them */
905 SET_FOREACH(m
, members
, i
) {
907 if (!streq(m
->type
, "property"))
913 if (argv
[3] && !streq(argv
[3], m
->interface
))
916 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
918 log_error("%s", bus_error_message(&error
, r
));
922 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
924 return bus_log_parse_error(r
);
928 _cleanup_free_
char *buf
= NULL
;
929 _cleanup_fclose_
FILE *mf
= NULL
;
933 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
935 return bus_log_parse_error(r
);
940 r
= sd_bus_message_read(reply
, "s", &name
);
942 return bus_log_parse_error(r
);
944 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
946 return bus_log_parse_error(r
);
948 mf
= open_memstream(&buf
, &sz
);
952 r
= format_cmdline(reply
, mf
, false);
954 return bus_log_parse_error(r
);
959 z
= set_get(members
, &((Member
) {
961 .interface
= m
->interface
,
962 .name
= (char*) name
}));
969 r
= sd_bus_message_exit_container(reply
);
971 return bus_log_parse_error(r
);
973 r
= sd_bus_message_exit_container(reply
);
975 return bus_log_parse_error(r
);
978 r
= sd_bus_message_exit_container(reply
);
980 return bus_log_parse_error(r
);
983 pager_open_if_enabled();
985 name_width
= strlen("NAME");
986 type_width
= strlen("TYPE");
987 signature_width
= strlen("SIGNATURE");
988 result_width
= strlen("RESULT/VALUE");
990 sorted
= newa(Member
*, set_size(members
));
992 SET_FOREACH(m
, members
, i
) {
994 if (argv
[3] && !streq(argv
[3], m
->interface
))
998 name_width
= MAX(name_width
, strlen(m
->interface
));
1000 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1002 type_width
= MAX(type_width
, strlen(m
->type
));
1004 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1006 result_width
= MAX(result_width
, strlen(m
->result
));
1008 result_width
= MAX(result_width
, strlen(m
->value
));
1013 if (result_width
> 40)
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 if (argv
[3] && !streq(argv
[3], m
->interface
))
1037 is_interface
= streq(m
->type
, "interface");
1039 if (argv
[3] && is_interface
)
1043 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1049 rv
= strdash(m
->result
);
1051 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1052 is_interface
? ansi_highlight() : "",
1053 is_interface
? "" : ".",
1054 - !is_interface
+ (int) name_width
, strdash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1055 is_interface
? ansi_normal() : "",
1056 (int) type_width
, strdash(m
->type
),
1057 (int) signature_width
, strdash(m
->signature
),
1058 (int) result_width
, rv
,
1059 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1060 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1061 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1062 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1063 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1064 m
->writable
? " writable" : "");
1070 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1071 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1074 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1075 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1078 static int monitor(sd_bus
*bus
, char *argv
[], int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1079 bool added_something
= false;
1083 STRV_FOREACH(i
, argv
+1) {
1084 _cleanup_free_
char *m
= NULL
;
1086 if (!service_name_is_valid(*i
)) {
1087 log_error("Invalid service name '%s'", *i
);
1091 m
= strjoin("sender='", *i
, "'", NULL
);
1095 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1097 return log_error_errno(r
, "Failed to add match: %m");
1100 m
= strjoin("destination='", *i
, "'", NULL
);
1104 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1106 return log_error_errno(r
, "Failed to add match: %m");
1108 added_something
= true;
1111 STRV_FOREACH(i
, arg_matches
) {
1112 r
= sd_bus_add_match(bus
, NULL
, *i
, NULL
, NULL
);
1114 return log_error_errno(r
, "Failed to add match: %m");
1116 added_something
= true;
1119 if (!added_something
) {
1120 r
= sd_bus_add_match(bus
, NULL
, "", NULL
, NULL
);
1122 return log_error_errno(r
, "Failed to add match: %m");
1125 log_info("Monitoring bus message stream.");
1128 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1130 r
= sd_bus_process(bus
, &m
);
1132 return log_error_errno(r
, "Failed to process bus: %m");
1138 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1139 log_info("Connection terminated, exiting.");
1149 r
= sd_bus_wait(bus
, (uint64_t) -1);
1151 return log_error_errno(r
, "Failed to wait for bus: %m");
1155 static int capture(sd_bus
*bus
, char *argv
[]) {
1158 if (isatty(fileno(stdout
)) > 0) {
1159 log_error("Refusing to write message data to console, please redirect output to a file.");
1163 bus_pcap_header(arg_snaplen
, stdout
);
1165 r
= monitor(bus
, argv
, message_pcap
);
1169 if (ferror(stdout
)) {
1170 log_error("Couldn't write capture file.");
1177 static int status(sd_bus
*bus
, char *argv
[]) {
1178 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1184 if (strv_length(argv
) > 2) {
1185 log_error("Expects no or one argument.");
1190 r
= parse_pid(argv
[1], &pid
);
1192 r
= sd_bus_get_name_creds(
1195 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1198 r
= sd_bus_creds_new_from_pid(
1203 const char *scope
, *address
;
1206 r
= sd_bus_get_address(bus
, &address
);
1208 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1210 r
= sd_bus_get_scope(bus
, &scope
);
1212 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1214 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1216 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1218 r
= sd_bus_get_owner_creds(
1220 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1225 return log_error_errno(r
, "Failed to get credentials: %m");
1227 bus_creds_dump(creds
, NULL
, false);
1231 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1251 log_error("Too few parameters for signature.");
1260 case SD_BUS_TYPE_BOOLEAN
:
1262 r
= parse_boolean(v
);
1264 log_error("Failed to parse as boolean: %s", v
);
1268 r
= sd_bus_message_append_basic(m
, t
, &r
);
1271 case SD_BUS_TYPE_BYTE
: {
1274 r
= safe_atou8(v
, &z
);
1276 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1280 r
= sd_bus_message_append_basic(m
, t
, &z
);
1284 case SD_BUS_TYPE_INT16
: {
1287 r
= safe_atoi16(v
, &z
);
1289 log_error("Failed to parse as signed 16bit integer: %s", v
);
1293 r
= sd_bus_message_append_basic(m
, t
, &z
);
1297 case SD_BUS_TYPE_UINT16
: {
1300 r
= safe_atou16(v
, &z
);
1302 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1306 r
= sd_bus_message_append_basic(m
, t
, &z
);
1310 case SD_BUS_TYPE_INT32
: {
1313 r
= safe_atoi32(v
, &z
);
1315 log_error("Failed to parse as signed 32bit integer: %s", v
);
1319 r
= sd_bus_message_append_basic(m
, t
, &z
);
1323 case SD_BUS_TYPE_UINT32
: {
1326 r
= safe_atou32(v
, &z
);
1328 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1332 r
= sd_bus_message_append_basic(m
, t
, &z
);
1336 case SD_BUS_TYPE_INT64
: {
1339 r
= safe_atoi64(v
, &z
);
1341 log_error("Failed to parse as signed 64bit integer: %s", v
);
1345 r
= sd_bus_message_append_basic(m
, t
, &z
);
1349 case SD_BUS_TYPE_UINT64
: {
1352 r
= safe_atou64(v
, &z
);
1354 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1358 r
= sd_bus_message_append_basic(m
, t
, &z
);
1363 case SD_BUS_TYPE_DOUBLE
: {
1366 r
= safe_atod(v
, &z
);
1368 log_error("Failed to parse as double precision floating point: %s", v
);
1372 r
= sd_bus_message_append_basic(m
, t
, &z
);
1376 case SD_BUS_TYPE_STRING
:
1377 case SD_BUS_TYPE_OBJECT_PATH
:
1378 case SD_BUS_TYPE_SIGNATURE
:
1380 r
= sd_bus_message_append_basic(m
, t
, v
);
1383 case SD_BUS_TYPE_ARRAY
: {
1387 r
= safe_atou32(v
, &n
);
1389 log_error("Failed to parse number of array entries: %s", v
);
1393 r
= signature_element_length(signature
, &k
);
1395 log_error("Invalid array signature.");
1402 memcpy(s
, signature
, k
);
1405 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1407 return bus_log_create_error(r
);
1409 for (i
= 0; i
< n
; i
++) {
1410 r
= message_append_cmdline(m
, s
, &p
);
1418 r
= sd_bus_message_close_container(m
);
1422 case SD_BUS_TYPE_VARIANT
:
1423 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1425 return bus_log_create_error(r
);
1427 r
= message_append_cmdline(m
, v
, &p
);
1431 r
= sd_bus_message_close_container(m
);
1434 case SD_BUS_TYPE_STRUCT_BEGIN
:
1435 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1441 r
= signature_element_length(signature
, &k
);
1443 log_error("Invalid struct/dict entry signature.");
1449 memcpy(s
, signature
+ 1, k
- 2);
1452 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1454 return bus_log_create_error(r
);
1456 r
= message_append_cmdline(m
, s
, &p
);
1463 r
= sd_bus_message_close_container(m
);
1467 case SD_BUS_TYPE_UNIX_FD
:
1468 log_error("UNIX file descriptor not supported as type.");
1472 log_error("Unknown signature type %c.", t
);
1477 return bus_log_create_error(r
);
1484 static int call(sd_bus
*bus
, char *argv
[]) {
1485 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1486 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1491 if (strv_length(argv
) < 5) {
1492 log_error("Expects at least four arguments.");
1496 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1498 return bus_log_create_error(r
);
1500 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1502 return bus_log_create_error(r
);
1504 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1506 return bus_log_create_error(r
);
1508 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1510 return bus_log_create_error(r
);
1512 if (!isempty(argv
[5])) {
1517 r
= message_append_cmdline(m
, argv
[5], &p
);
1522 log_error("Too many parameters for signature.");
1527 if (!arg_expect_reply
) {
1528 r
= sd_bus_send(bus
, m
, NULL
);
1530 log_error("Failed to send message.");
1537 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1539 log_error("%s", bus_error_message(&error
, r
));
1543 r
= sd_bus_message_is_empty(reply
);
1545 return bus_log_parse_error(r
);
1547 if (r
== 0 && !arg_quiet
) {
1550 pager_open_if_enabled();
1552 r
= bus_message_dump(reply
, stdout
, 0);
1557 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1560 r
= format_cmdline(reply
, stdout
, false);
1562 return bus_log_parse_error(r
);
1564 fputc('\n', stdout
);
1571 static int get_property(sd_bus
*bus
, char *argv
[]) {
1572 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1579 n
= strv_length(argv
);
1581 log_error("Expects at least four arguments.");
1585 STRV_FOREACH(i
, argv
+ 4) {
1586 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1587 const char *contents
= NULL
;
1590 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1592 log_error("%s", bus_error_message(&error
, r
));
1596 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1598 return bus_log_parse_error(r
);
1600 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1602 return bus_log_parse_error(r
);
1605 pager_open_if_enabled();
1607 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1611 fputs(contents
, stdout
);
1614 r
= format_cmdline(reply
, stdout
, false);
1616 return bus_log_parse_error(r
);
1618 fputc('\n', stdout
);
1621 r
= sd_bus_message_exit_container(reply
);
1623 return bus_log_parse_error(r
);
1629 static int set_property(sd_bus
*bus
, char *argv
[]) {
1630 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1631 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1638 n
= strv_length(argv
);
1640 log_error("Expects at least five arguments.");
1644 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1646 return bus_log_create_error(r
);
1648 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1650 return bus_log_create_error(r
);
1652 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1654 return bus_log_create_error(r
);
1657 r
= message_append_cmdline(m
, argv
[5], &p
);
1661 r
= sd_bus_message_close_container(m
);
1663 return bus_log_create_error(r
);
1666 log_error("Too many parameters for signature.");
1670 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1672 log_error("%s", bus_error_message(&error
, r
));
1679 static int help(void) {
1680 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1681 "Introspect the bus.\n\n"
1682 " -h --help Show this help\n"
1683 " --version Show package version\n"
1684 " --no-pager Do not pipe output into a pager\n"
1685 " --no-legend Do not show the headers and footers\n"
1686 " --system Connect to system bus\n"
1687 " --user Connect to user bus\n"
1688 " -H --host=[USER@]HOST Operate on remote host\n"
1689 " -M --machine=CONTAINER Operate on local container\n"
1690 " --address=ADDRESS Connect to bus specified by address\n"
1691 " --show-machine Show machine ID column in list\n"
1692 " --unique Only show unique names\n"
1693 " --acquired Only show acquired names\n"
1694 " --activatable Only show activatable names\n"
1695 " --match=MATCH Only show matching messages\n"
1696 " --size=SIZE Maximum length of captured packet\n"
1697 " --list Don't show tree, but simple object path list\n"
1698 " --quiet Don't show method call reply\n"
1699 " --verbose Show result values in long format\n"
1700 " --expect-reply=BOOL Expect a method call reply\n"
1701 " --auto-start=BOOL Auto-start destination service\n"
1702 " --allow-interactive-authorization=BOOL\n"
1703 " Allow interactive authorization for operation\n"
1704 " --timeout=SECS Maximum time to wait for method call completion\n"
1705 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1707 " list List bus names\n"
1708 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1709 " monitor [SERVICE...] Show bus traffic\n"
1710 " capture [SERVICE...] Capture bus traffic as pcap\n"
1711 " tree [SERVICE...] Show object tree of service\n"
1712 " introspect SERVICE OBJECT [INTERFACE]\n"
1713 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1715 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1716 " Get property value\n"
1717 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1718 " Set property value\n"
1719 " help Show this help\n"
1720 , program_invocation_short_name
);
1725 static int parse_argv(int argc
, char *argv
[]) {
1728 ARG_VERSION
= 0x100,
1744 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1749 static const struct option options
[] = {
1750 { "help", no_argument
, NULL
, 'h' },
1751 { "version", no_argument
, NULL
, ARG_VERSION
},
1752 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1753 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1754 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1755 { "user", no_argument
, NULL
, ARG_USER
},
1756 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1757 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1758 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1759 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1760 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1761 { "match", required_argument
, NULL
, ARG_MATCH
},
1762 { "host", required_argument
, NULL
, 'H' },
1763 { "machine", required_argument
, NULL
, 'M' },
1764 { "size", required_argument
, NULL
, ARG_SIZE
},
1765 { "list", no_argument
, NULL
, ARG_LIST
},
1766 { "quiet", no_argument
, NULL
, 'q' },
1767 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1768 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1769 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1770 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1771 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1772 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1781 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1789 puts(PACKAGE_STRING
);
1790 puts(SYSTEMD_FEATURES
);
1794 arg_no_pager
= true;
1810 arg_address
= optarg
;
1813 case ARG_SHOW_MACHINE
:
1814 arg_show_machine
= true;
1822 arg_acquired
= true;
1825 case ARG_ACTIVATABLE
:
1826 arg_activatable
= true;
1830 if (strv_extend(&arg_matches
, optarg
) < 0)
1837 r
= parse_size(optarg
, 1024, &sz
);
1839 log_error("Failed to parse size: %s", optarg
);
1843 if ((uint64_t) (size_t) sz
!= sz
) {
1844 log_error("Size out of range.");
1848 arg_snaplen
= (size_t) sz
;
1857 arg_transport
= BUS_TRANSPORT_REMOTE
;
1862 arg_transport
= BUS_TRANSPORT_MACHINE
;
1874 case ARG_EXPECT_REPLY
:
1875 r
= parse_boolean(optarg
);
1877 log_error("Failed to parse --expect-reply= parameter.");
1881 arg_expect_reply
= !!r
;
1885 case ARG_AUTO_START
:
1886 r
= parse_boolean(optarg
);
1888 log_error("Failed to parse --auto-start= parameter.");
1892 arg_auto_start
= !!r
;
1896 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1897 r
= parse_boolean(optarg
);
1899 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1903 arg_allow_interactive_authorization
= !!r
;
1907 r
= parse_sec(optarg
, &arg_timeout
);
1909 log_error("Failed to parse --timeout= parameter.");
1915 case ARG_AUGMENT_CREDS
:
1916 r
= parse_boolean(optarg
);
1918 log_error("Failed to parse --augment-creds= parameter.");
1922 arg_augment_creds
= !!r
;
1929 assert_not_reached("Unhandled option");
1935 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1938 if (optind
>= argc
||
1939 streq(argv
[optind
], "list"))
1940 return list_bus_names(bus
, argv
+ optind
);
1942 if (streq(argv
[optind
], "monitor"))
1943 return monitor(bus
, argv
+ optind
, message_dump
);
1945 if (streq(argv
[optind
], "capture"))
1946 return capture(bus
, argv
+ optind
);
1948 if (streq(argv
[optind
], "status"))
1949 return status(bus
, argv
+ optind
);
1951 if (streq(argv
[optind
], "tree"))
1952 return tree(bus
, argv
+ optind
);
1954 if (streq(argv
[optind
], "introspect"))
1955 return introspect(bus
, argv
+ optind
);
1957 if (streq(argv
[optind
], "call"))
1958 return call(bus
, argv
+ optind
);
1960 if (streq(argv
[optind
], "get-property"))
1961 return get_property(bus
, argv
+ optind
);
1963 if (streq(argv
[optind
], "set-property"))
1964 return set_property(bus
, argv
+ optind
);
1966 if (streq(argv
[optind
], "help"))
1969 log_error("Unknown command '%s'", argv
[optind
]);
1973 int main(int argc
, char *argv
[]) {
1974 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1977 log_parse_environment();
1980 r
= parse_argv(argc
, argv
);
1984 r
= sd_bus_new(&bus
);
1986 log_error_errno(r
, "Failed to allocate bus: %m");
1990 if (streq_ptr(argv
[optind
], "monitor") ||
1991 streq_ptr(argv
[optind
], "capture")) {
1993 r
= sd_bus_set_monitor(bus
, true);
1995 log_error_errno(r
, "Failed to set monitor mode: %m");
1999 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
2001 log_error_errno(r
, "Failed to enable credentials: %m");
2005 r
= sd_bus_negotiate_timestamp(bus
, true);
2007 log_error_errno(r
, "Failed to enable timestamps: %m");
2011 r
= sd_bus_negotiate_fds(bus
, true);
2013 log_error_errno(r
, "Failed to enable fds: %m");
2018 r
= sd_bus_set_bus_client(bus
, true);
2020 log_error_errno(r
, "Failed to set bus client: %m");
2025 r
= sd_bus_set_address(bus
, arg_address
);
2027 switch (arg_transport
) {
2029 case BUS_TRANSPORT_LOCAL
:
2031 bus
->is_user
= true;
2032 r
= bus_set_address_user(bus
);
2034 bus
->is_system
= true;
2035 r
= bus_set_address_system(bus
);
2039 case BUS_TRANSPORT_REMOTE
:
2040 r
= bus_set_address_system_remote(bus
, arg_host
);
2043 case BUS_TRANSPORT_MACHINE
:
2044 r
= bus_set_address_system_machine(bus
, arg_host
);
2048 assert_not_reached("Hmm, unknown transport type.");
2052 log_error_errno(r
, "Failed to set address: %m");
2056 r
= sd_bus_start(bus
);
2058 log_error_errno(r
, "Failed to connect to bus: %m");
2062 r
= busctl_main(bus
, argc
, argv
);
2067 strv_free(arg_matches
);
2069 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;