1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "bus-internal.h"
28 #include "bus-signature.h"
31 #include "busctl-introspect.h"
36 #include "parse-util.h"
37 #include "path-util.h"
40 #include "terminal-util.h"
41 #include "user-util.h"
44 static bool arg_no_pager
= false;
45 static bool arg_legend
= true;
46 static char *arg_address
= NULL
;
47 static bool arg_unique
= false;
48 static bool arg_acquired
= false;
49 static bool arg_activatable
= false;
50 static bool arg_show_machine
= false;
51 static char **arg_matches
= NULL
;
52 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
53 static char *arg_host
= NULL
;
54 static bool arg_user
= false;
55 static size_t arg_snaplen
= 4096;
56 static bool arg_list
= false;
57 static bool arg_quiet
= false;
58 static bool arg_verbose
= false;
59 static bool arg_expect_reply
= true;
60 static bool arg_auto_start
= true;
61 static bool arg_allow_interactive_authorization
= true;
62 static bool arg_augment_creds
= true;
63 static usec_t arg_timeout
= 0;
65 static void pager_open_if_enabled(void) {
67 /* Cache result before we open the pager */
74 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
75 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
77 static int list_bus_names(sd_bus
*bus
, char **argv
) {
78 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
79 _cleanup_free_
char **merged
= NULL
;
80 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
91 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
92 arg_unique
= arg_acquired
= arg_activatable
= true;
94 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
96 return log_error_errno(r
, "Failed to list names: %m");
98 pager_open_if_enabled();
100 names
= hashmap_new(&string_hash_ops
);
104 STRV_FOREACH(i
, acquired
) {
105 max_i
= MAX(max_i
, strlen(*i
));
107 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
109 return log_error_errno(r
, "Failed to add to hashmap: %m");
112 STRV_FOREACH(i
, activatable
) {
113 max_i
= MAX(max_i
, strlen(*i
));
115 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
116 if (r
< 0 && r
!= -EEXIST
)
117 return log_error_errno(r
, "Failed to add to hashmap: %m");
120 merged
= new(char*, hashmap_size(names
) + 1);
121 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
128 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
129 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
131 if (arg_show_machine
)
137 STRV_FOREACH(i
, merged
) {
138 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
141 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
144 printf("%-*s", (int) max_i
, *i
);
145 printf(" - - - (activatable) - - ");
146 if (arg_show_machine
)
154 if (!arg_unique
&& (*i
)[0] == ':')
157 if (!arg_acquired
&& (*i
)[0] != ':')
160 printf("%-*s", (int) max_i
, *i
);
162 r
= sd_bus_get_name_creds(
164 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
165 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
166 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
167 SD_BUS_CREDS_DESCRIPTION
, &creds
);
169 const char *unique
, *session
, *unit
, *cn
;
173 r
= sd_bus_creds_get_pid(creds
, &pid
);
175 const char *comm
= NULL
;
177 sd_bus_creds_get_comm(creds
, &comm
);
179 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
181 fputs(" - - ", stdout
);
183 r
= sd_bus_creds_get_euid(creds
, &uid
);
185 _cleanup_free_
char *u
= NULL
;
187 u
= uid_to_name(uid
);
196 fputs(" - ", stdout
);
198 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
200 printf(" %-13s", unique
);
202 fputs(" - ", stdout
);
204 r
= sd_bus_creds_get_unit(creds
, &unit
);
206 _cleanup_free_
char *e
;
208 e
= ellipsize(unit
, 25, 100);
214 fputs(" - ", stdout
);
216 r
= sd_bus_creds_get_session(creds
, &session
);
218 printf(" %-10s", session
);
220 fputs(" - ", stdout
);
222 r
= sd_bus_creds_get_description(creds
, &cn
);
224 printf(" %-19s", cn
);
226 fputs(" - ", stdout
);
229 printf(" - - - - - - - ");
231 if (arg_show_machine
) {
232 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
234 char m
[SD_ID128_STRING_MAX
];
235 printf(" %s\n", sd_id128_to_string(mid
, m
));
245 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
246 const char *vertical
, *space
;
249 /* We assume the list is sorted. Let's first skip over the
250 * entry we are looking at. */
255 if (!streq(*l
, path
))
261 vertical
= strjoina(prefix
, draw_special_char(DRAW_TREE_VERTICAL
));
262 space
= strjoina(prefix
, draw_special_char(DRAW_TREE_SPACE
));
265 bool has_more
= false;
267 if (!*l
|| !path_startswith(*l
, path
))
272 if (!*n
|| !path_startswith(*n
, path
))
275 if (!path_startswith(*n
, *l
)) {
283 printf("%s%s%s\n", prefix
, draw_special_char(has_more
? DRAW_TREE_BRANCH
: DRAW_TREE_RIGHT
), *l
);
285 print_subtree(has_more
? vertical
: space
, *l
, l
);
290 static void print_tree(const char *prefix
, char **l
) {
292 pager_open_if_enabled();
294 prefix
= strempty(prefix
);
300 printf("%s%s\n", prefix
, *i
);
304 if (strv_isempty(l
)) {
305 printf("No objects discovered.\n");
309 if (streq(l
[0], "/") && !l
[1]) {
310 printf("Only root object discovered.\n");
314 print_subtree(prefix
, "/", l
);
317 static int on_path(const char *path
, void *userdata
) {
318 Set
*paths
= userdata
;
323 r
= set_put_strdup(paths
, path
);
330 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
331 static const XMLIntrospectOps ops
= {
335 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
336 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
340 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
343 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
345 log_error("Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
349 r
= sd_bus_message_read(reply
, "s", &xml
);
351 return bus_log_parse_error(r
);
353 return parse_xml_introspect(path
, xml
, &ops
, paths
);
356 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
357 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
358 _cleanup_free_
char **l
= NULL
;
362 paths
= set_new(&string_hash_ops
);
366 done
= set_new(&string_hash_ops
);
370 failed
= set_new(&string_hash_ops
);
378 r
= set_put(paths
, m
);
385 _cleanup_free_
char *p
= NULL
;
388 p
= set_steal_first(paths
);
392 if (set_contains(done
, p
) ||
393 set_contains(failed
, p
))
396 q
= find_nodes(bus
, service
, p
, paths
, many
);
401 q
= set_put(failed
, p
);
403 q
= set_put(done
, p
);
412 pager_open_if_enabled();
414 l
= set_get_strv(done
);
419 print_tree(prefix
, l
);
426 static int tree(sd_bus
*bus
, char **argv
) {
430 if (!arg_unique
&& !arg_acquired
)
433 if (strv_length(argv
) <= 1) {
434 _cleanup_strv_free_
char **names
= NULL
;
435 bool not_first
= false;
437 r
= sd_bus_list_names(bus
, &names
, NULL
);
439 return log_error_errno(r
, "Failed to get name list: %m");
441 pager_open_if_enabled();
443 STRV_FOREACH(i
, names
) {
446 if (!arg_unique
&& (*i
)[0] == ':')
449 if (!arg_acquired
&& (*i
)[0] == ':')
455 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
457 q
= tree_one(bus
, *i
, NULL
, true);
464 STRV_FOREACH(i
, argv
+1) {
471 pager_open_if_enabled();
472 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
475 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
484 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
488 const char *contents
= NULL
;
503 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
507 if (bus_type_is_container(type
) > 0) {
509 r
= sd_bus_message_enter_container(m
, type
, contents
);
513 if (type
== SD_BUS_TYPE_ARRAY
) {
516 /* count array entries */
519 r
= sd_bus_message_skip(m
, contents
);
528 r
= sd_bus_message_rewind(m
, false);
536 } else if (type
== SD_BUS_TYPE_VARIANT
) {
541 fprintf(f
, "%s", contents
);
544 r
= format_cmdline(m
, f
, needs_space
|| IN_SET(type
, SD_BUS_TYPE_ARRAY
, SD_BUS_TYPE_VARIANT
));
548 r
= sd_bus_message_exit_container(m
);
555 r
= sd_bus_message_read_basic(m
, type
, &basic
);
563 case SD_BUS_TYPE_BYTE
:
564 fprintf(f
, "%u", basic
.u8
);
567 case SD_BUS_TYPE_BOOLEAN
:
568 fputs(true_false(basic
.i
), f
);
571 case SD_BUS_TYPE_INT16
:
572 fprintf(f
, "%i", basic
.s16
);
575 case SD_BUS_TYPE_UINT16
:
576 fprintf(f
, "%u", basic
.u16
);
579 case SD_BUS_TYPE_INT32
:
580 fprintf(f
, "%i", basic
.s32
);
583 case SD_BUS_TYPE_UINT32
:
584 fprintf(f
, "%u", basic
.u32
);
587 case SD_BUS_TYPE_INT64
:
588 fprintf(f
, "%" PRIi64
, basic
.s64
);
591 case SD_BUS_TYPE_UINT64
:
592 fprintf(f
, "%" PRIu64
, basic
.u64
);
595 case SD_BUS_TYPE_DOUBLE
:
596 fprintf(f
, "%g", basic
.d64
);
599 case SD_BUS_TYPE_STRING
:
600 case SD_BUS_TYPE_OBJECT_PATH
:
601 case SD_BUS_TYPE_SIGNATURE
: {
602 _cleanup_free_
char *b
= NULL
;
604 b
= cescape(basic
.string
);
608 fprintf(f
, "\"%s\"", b
);
612 case SD_BUS_TYPE_UNIX_FD
:
613 fprintf(f
, "%i", basic
.i
);
617 assert_not_reached("Unknown basic type.");
624 typedef struct Member
{
635 static void member_hash_func(const void *p
, struct siphash
*state
) {
642 string_hash_func(m
->type
, state
);
644 arity
+= !!m
->name
+ !!m
->interface
;
646 uint64_hash_func(&arity
, state
);
649 string_hash_func(m
->name
, state
);
652 string_hash_func(m
->interface
, state
);
655 static int member_compare_func(const void *a
, const void *b
) {
656 const Member
*x
= a
, *y
= b
;
664 d
= strcmp_ptr(x
->interface
, y
->interface
);
668 d
= strcmp(x
->type
, y
->type
);
672 return strcmp_ptr(x
->name
, y
->name
);
675 static int member_compare_funcp(const void *a
, const void *b
) {
676 const Member
*const * x
= (const Member
*const *) a
, * const *y
= (const Member
*const *) b
;
678 return member_compare_func(*x
, *y
);
681 static void member_free(Member
*m
) {
693 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
695 static void member_set_free(Set
*s
) {
698 while ((m
= set_steal_first(s
)))
704 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
706 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
707 _cleanup_(member_freep
) Member
*m
;
708 Set
*members
= userdata
;
718 m
->type
= "interface";
721 r
= free_and_strdup(&m
->interface
, interface
);
725 r
= set_put(members
, m
);
727 log_error("Duplicate interface");
735 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
736 _cleanup_(member_freep
) Member
*m
;
737 Set
*members
= userdata
;
750 r
= free_and_strdup(&m
->interface
, interface
);
754 r
= free_and_strdup(&m
->name
, name
);
758 r
= free_and_strdup(&m
->signature
, signature
);
762 r
= free_and_strdup(&m
->result
, result
);
766 r
= set_put(members
, m
);
768 log_error("Duplicate method");
776 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
777 _cleanup_(member_freep
) Member
*m
;
778 Set
*members
= userdata
;
791 r
= free_and_strdup(&m
->interface
, interface
);
795 r
= free_and_strdup(&m
->name
, name
);
799 r
= free_and_strdup(&m
->signature
, signature
);
803 r
= set_put(members
, m
);
805 log_error("Duplicate signal");
813 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
814 _cleanup_(member_freep
) Member
*m
;
815 Set
*members
= userdata
;
825 m
->type
= "property";
827 m
->writable
= writable
;
829 r
= free_and_strdup(&m
->interface
, interface
);
833 r
= free_and_strdup(&m
->name
, name
);
837 r
= free_and_strdup(&m
->signature
, signature
);
841 r
= set_put(members
, m
);
843 log_error("Duplicate property");
851 static const char *strdash(const char *x
) {
852 return isempty(x
) ? "-" : x
;
855 static int introspect(sd_bus
*bus
, char **argv
) {
856 static const struct hash_ops member_hash_ops
= {
857 .hash
= member_hash_func
,
858 .compare
= member_compare_func
,
861 static const XMLIntrospectOps ops
= {
862 .on_interface
= on_interface
,
863 .on_method
= on_method
,
864 .on_signal
= on_signal
,
865 .on_property
= on_property
,
868 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
869 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
870 _cleanup_(member_set_freep
) Set
*members
= NULL
;
875 unsigned name_width
, type_width
, signature_width
, result_width
;
876 Member
**sorted
= NULL
;
877 unsigned k
= 0, j
, n_args
;
879 n_args
= strv_length(argv
);
881 log_error("Requires service and object path argument.");
886 log_error("Too many arguments.");
890 members
= set_new(&member_hash_ops
);
894 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
896 log_error("Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
900 r
= sd_bus_message_read(reply
, "s", &xml
);
902 return bus_log_parse_error(r
);
904 /* First, get list of all properties */
905 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
909 /* Second, find the current values for them */
910 SET_FOREACH(m
, members
, i
) {
912 if (!streq(m
->type
, "property"))
918 if (argv
[3] && !streq(argv
[3], m
->interface
))
921 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
923 log_error("%s", bus_error_message(&error
, r
));
927 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
929 return bus_log_parse_error(r
);
933 _cleanup_free_
char *buf
= NULL
;
934 _cleanup_fclose_
FILE *mf
= NULL
;
938 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
940 return bus_log_parse_error(r
);
945 r
= sd_bus_message_read(reply
, "s", &name
);
947 return bus_log_parse_error(r
);
949 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
951 return bus_log_parse_error(r
);
953 mf
= open_memstream(&buf
, &sz
);
957 r
= format_cmdline(reply
, mf
, false);
959 return bus_log_parse_error(r
);
964 z
= set_get(members
, &((Member
) {
966 .interface
= m
->interface
,
967 .name
= (char*) name
}));
974 r
= sd_bus_message_exit_container(reply
);
976 return bus_log_parse_error(r
);
978 r
= sd_bus_message_exit_container(reply
);
980 return bus_log_parse_error(r
);
983 r
= sd_bus_message_exit_container(reply
);
985 return bus_log_parse_error(r
);
988 pager_open_if_enabled();
990 name_width
= strlen("NAME");
991 type_width
= strlen("TYPE");
992 signature_width
= strlen("SIGNATURE");
993 result_width
= strlen("RESULT/VALUE");
995 sorted
= newa(Member
*, set_size(members
));
997 SET_FOREACH(m
, members
, i
) {
999 if (argv
[3] && !streq(argv
[3], m
->interface
))
1003 name_width
= MAX(name_width
, strlen(m
->interface
));
1005 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1007 type_width
= MAX(type_width
, strlen(m
->type
));
1009 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1011 result_width
= MAX(result_width
, strlen(m
->result
));
1013 result_width
= MAX(result_width
, strlen(m
->value
));
1018 if (result_width
> 40)
1021 qsort(sorted
, k
, sizeof(Member
*), member_compare_funcp
);
1024 printf("%-*s %-*s %-*s %-*s %s\n",
1025 (int) name_width
, "NAME",
1026 (int) type_width
, "TYPE",
1027 (int) signature_width
, "SIGNATURE",
1028 (int) result_width
, "RESULT/VALUE",
1032 for (j
= 0; j
< k
; j
++) {
1033 _cleanup_free_
char *ellipsized
= NULL
;
1039 if (argv
[3] && !streq(argv
[3], m
->interface
))
1042 is_interface
= streq(m
->type
, "interface");
1044 if (argv
[3] && is_interface
)
1048 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1054 rv
= strdash(m
->result
);
1056 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1057 is_interface
? ansi_highlight() : "",
1058 is_interface
? "" : ".",
1059 - !is_interface
+ (int) name_width
, strdash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1060 is_interface
? ansi_normal() : "",
1061 (int) type_width
, strdash(m
->type
),
1062 (int) signature_width
, strdash(m
->signature
),
1063 (int) result_width
, rv
,
1064 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1065 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1066 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1067 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1068 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1069 m
->writable
? " writable" : "");
1075 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1076 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1079 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1080 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1083 static int monitor(sd_bus
*bus
, char *argv
[], int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1084 bool added_something
= false;
1088 STRV_FOREACH(i
, argv
+1) {
1089 _cleanup_free_
char *m
= NULL
;
1091 if (!service_name_is_valid(*i
)) {
1092 log_error("Invalid service name '%s'", *i
);
1096 m
= strjoin("sender='", *i
, "'", NULL
);
1100 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1102 return log_error_errno(r
, "Failed to add match: %m");
1105 m
= strjoin("destination='", *i
, "'", NULL
);
1109 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1111 return log_error_errno(r
, "Failed to add match: %m");
1113 added_something
= true;
1116 STRV_FOREACH(i
, arg_matches
) {
1117 r
= sd_bus_add_match(bus
, NULL
, *i
, NULL
, NULL
);
1119 return log_error_errno(r
, "Failed to add match: %m");
1121 added_something
= true;
1124 if (!added_something
) {
1125 r
= sd_bus_add_match(bus
, NULL
, "", NULL
, NULL
);
1127 return log_error_errno(r
, "Failed to add match: %m");
1130 log_info("Monitoring bus message stream.");
1133 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1135 r
= sd_bus_process(bus
, &m
);
1137 return log_error_errno(r
, "Failed to process bus: %m");
1143 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1144 log_info("Connection terminated, exiting.");
1154 r
= sd_bus_wait(bus
, (uint64_t) -1);
1156 return log_error_errno(r
, "Failed to wait for bus: %m");
1160 static int capture(sd_bus
*bus
, char *argv
[]) {
1163 if (isatty(fileno(stdout
)) > 0) {
1164 log_error("Refusing to write message data to console, please redirect output to a file.");
1168 bus_pcap_header(arg_snaplen
, stdout
);
1170 r
= monitor(bus
, argv
, message_pcap
);
1174 if (ferror(stdout
)) {
1175 log_error("Couldn't write capture file.");
1182 static int status(sd_bus
*bus
, char *argv
[]) {
1183 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1189 if (strv_length(argv
) > 2) {
1190 log_error("Expects no or one argument.");
1195 r
= parse_pid(argv
[1], &pid
);
1197 r
= sd_bus_get_name_creds(
1200 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1203 r
= sd_bus_creds_new_from_pid(
1208 const char *scope
, *address
;
1211 r
= sd_bus_get_address(bus
, &address
);
1213 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1215 r
= sd_bus_get_scope(bus
, &scope
);
1217 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1219 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1221 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1223 r
= sd_bus_get_owner_creds(
1225 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1230 return log_error_errno(r
, "Failed to get credentials: %m");
1232 bus_creds_dump(creds
, NULL
, false);
1236 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1256 log_error("Too few parameters for signature.");
1265 case SD_BUS_TYPE_BOOLEAN
:
1267 r
= parse_boolean(v
);
1269 log_error("Failed to parse as boolean: %s", v
);
1273 r
= sd_bus_message_append_basic(m
, t
, &r
);
1276 case SD_BUS_TYPE_BYTE
: {
1279 r
= safe_atou8(v
, &z
);
1281 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1285 r
= sd_bus_message_append_basic(m
, t
, &z
);
1289 case SD_BUS_TYPE_INT16
: {
1292 r
= safe_atoi16(v
, &z
);
1294 log_error("Failed to parse as signed 16bit integer: %s", v
);
1298 r
= sd_bus_message_append_basic(m
, t
, &z
);
1302 case SD_BUS_TYPE_UINT16
: {
1305 r
= safe_atou16(v
, &z
);
1307 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1311 r
= sd_bus_message_append_basic(m
, t
, &z
);
1315 case SD_BUS_TYPE_INT32
: {
1318 r
= safe_atoi32(v
, &z
);
1320 log_error("Failed to parse as signed 32bit integer: %s", v
);
1324 r
= sd_bus_message_append_basic(m
, t
, &z
);
1328 case SD_BUS_TYPE_UINT32
: {
1331 r
= safe_atou32(v
, &z
);
1333 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1337 r
= sd_bus_message_append_basic(m
, t
, &z
);
1341 case SD_BUS_TYPE_INT64
: {
1344 r
= safe_atoi64(v
, &z
);
1346 log_error("Failed to parse as signed 64bit integer: %s", v
);
1350 r
= sd_bus_message_append_basic(m
, t
, &z
);
1354 case SD_BUS_TYPE_UINT64
: {
1357 r
= safe_atou64(v
, &z
);
1359 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1363 r
= sd_bus_message_append_basic(m
, t
, &z
);
1368 case SD_BUS_TYPE_DOUBLE
: {
1371 r
= safe_atod(v
, &z
);
1373 log_error("Failed to parse as double precision floating point: %s", v
);
1377 r
= sd_bus_message_append_basic(m
, t
, &z
);
1381 case SD_BUS_TYPE_STRING
:
1382 case SD_BUS_TYPE_OBJECT_PATH
:
1383 case SD_BUS_TYPE_SIGNATURE
:
1385 r
= sd_bus_message_append_basic(m
, t
, v
);
1388 case SD_BUS_TYPE_ARRAY
: {
1392 r
= safe_atou32(v
, &n
);
1394 log_error("Failed to parse number of array entries: %s", v
);
1398 r
= signature_element_length(signature
, &k
);
1400 log_error("Invalid array signature.");
1407 memcpy(s
, signature
, k
);
1410 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1412 return bus_log_create_error(r
);
1414 for (i
= 0; i
< n
; i
++) {
1415 r
= message_append_cmdline(m
, s
, &p
);
1423 r
= sd_bus_message_close_container(m
);
1427 case SD_BUS_TYPE_VARIANT
:
1428 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1430 return bus_log_create_error(r
);
1432 r
= message_append_cmdline(m
, v
, &p
);
1436 r
= sd_bus_message_close_container(m
);
1439 case SD_BUS_TYPE_STRUCT_BEGIN
:
1440 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1446 r
= signature_element_length(signature
, &k
);
1448 log_error("Invalid struct/dict entry signature.");
1454 memcpy(s
, signature
+ 1, k
- 2);
1457 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1459 return bus_log_create_error(r
);
1461 r
= message_append_cmdline(m
, s
, &p
);
1468 r
= sd_bus_message_close_container(m
);
1472 case SD_BUS_TYPE_UNIX_FD
:
1473 log_error("UNIX file descriptor not supported as type.");
1477 log_error("Unknown signature type %c.", t
);
1482 return bus_log_create_error(r
);
1489 static int call(sd_bus
*bus
, char *argv
[]) {
1490 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1491 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1496 if (strv_length(argv
) < 5) {
1497 log_error("Expects at least four arguments.");
1501 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1503 return bus_log_create_error(r
);
1505 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1507 return bus_log_create_error(r
);
1509 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1511 return bus_log_create_error(r
);
1513 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1515 return bus_log_create_error(r
);
1517 if (!isempty(argv
[5])) {
1522 r
= message_append_cmdline(m
, argv
[5], &p
);
1527 log_error("Too many parameters for signature.");
1532 if (!arg_expect_reply
) {
1533 r
= sd_bus_send(bus
, m
, NULL
);
1535 log_error("Failed to send message.");
1542 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1544 log_error("%s", bus_error_message(&error
, r
));
1548 r
= sd_bus_message_is_empty(reply
);
1550 return bus_log_parse_error(r
);
1552 if (r
== 0 && !arg_quiet
) {
1555 pager_open_if_enabled();
1557 r
= bus_message_dump(reply
, stdout
, 0);
1562 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1565 r
= format_cmdline(reply
, stdout
, false);
1567 return bus_log_parse_error(r
);
1569 fputc('\n', stdout
);
1576 static int get_property(sd_bus
*bus
, char *argv
[]) {
1577 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1584 n
= strv_length(argv
);
1586 log_error("Expects at least four arguments.");
1590 STRV_FOREACH(i
, argv
+ 4) {
1591 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1592 const char *contents
= NULL
;
1595 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1597 log_error("%s", bus_error_message(&error
, r
));
1601 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1603 return bus_log_parse_error(r
);
1605 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1607 return bus_log_parse_error(r
);
1610 pager_open_if_enabled();
1612 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1616 fputs(contents
, stdout
);
1619 r
= format_cmdline(reply
, stdout
, false);
1621 return bus_log_parse_error(r
);
1623 fputc('\n', stdout
);
1626 r
= sd_bus_message_exit_container(reply
);
1628 return bus_log_parse_error(r
);
1634 static int set_property(sd_bus
*bus
, char *argv
[]) {
1635 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1636 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1643 n
= strv_length(argv
);
1645 log_error("Expects at least five arguments.");
1649 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1651 return bus_log_create_error(r
);
1653 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1655 return bus_log_create_error(r
);
1657 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1659 return bus_log_create_error(r
);
1662 r
= message_append_cmdline(m
, argv
[5], &p
);
1666 r
= sd_bus_message_close_container(m
);
1668 return bus_log_create_error(r
);
1671 log_error("Too many parameters for signature.");
1675 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1677 log_error("%s", bus_error_message(&error
, r
));
1684 static int help(void) {
1685 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1686 "Introspect the bus.\n\n"
1687 " -h --help Show this help\n"
1688 " --version Show package version\n"
1689 " --no-pager Do not pipe output into a pager\n"
1690 " --no-legend Do not show the headers and footers\n"
1691 " --system Connect to system bus\n"
1692 " --user Connect to user bus\n"
1693 " -H --host=[USER@]HOST Operate on remote host\n"
1694 " -M --machine=CONTAINER Operate on local container\n"
1695 " --address=ADDRESS Connect to bus specified by address\n"
1696 " --show-machine Show machine ID column in list\n"
1697 " --unique Only show unique names\n"
1698 " --acquired Only show acquired names\n"
1699 " --activatable Only show activatable names\n"
1700 " --match=MATCH Only show matching messages\n"
1701 " --size=SIZE Maximum length of captured packet\n"
1702 " --list Don't show tree, but simple object path list\n"
1703 " --quiet Don't show method call reply\n"
1704 " --verbose Show result values in long format\n"
1705 " --expect-reply=BOOL Expect a method call reply\n"
1706 " --auto-start=BOOL Auto-start destination service\n"
1707 " --allow-interactive-authorization=BOOL\n"
1708 " Allow interactive authorization for operation\n"
1709 " --timeout=SECS Maximum time to wait for method call completion\n"
1710 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1712 " list List bus names\n"
1713 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1714 " monitor [SERVICE...] Show bus traffic\n"
1715 " capture [SERVICE...] Capture bus traffic as pcap\n"
1716 " tree [SERVICE...] Show object tree of service\n"
1717 " introspect SERVICE OBJECT [INTERFACE]\n"
1718 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1720 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1721 " Get property value\n"
1722 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1723 " Set property value\n"
1724 " help Show this help\n"
1725 , program_invocation_short_name
);
1730 static int parse_argv(int argc
, char *argv
[]) {
1733 ARG_VERSION
= 0x100,
1749 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1754 static const struct option options
[] = {
1755 { "help", no_argument
, NULL
, 'h' },
1756 { "version", no_argument
, NULL
, ARG_VERSION
},
1757 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1758 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1759 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1760 { "user", no_argument
, NULL
, ARG_USER
},
1761 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1762 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1763 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1764 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1765 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1766 { "match", required_argument
, NULL
, ARG_MATCH
},
1767 { "host", required_argument
, NULL
, 'H' },
1768 { "machine", required_argument
, NULL
, 'M' },
1769 { "size", required_argument
, NULL
, ARG_SIZE
},
1770 { "list", no_argument
, NULL
, ARG_LIST
},
1771 { "quiet", no_argument
, NULL
, 'q' },
1772 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1773 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1774 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1775 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1776 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1777 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1786 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1797 arg_no_pager
= true;
1813 arg_address
= optarg
;
1816 case ARG_SHOW_MACHINE
:
1817 arg_show_machine
= true;
1825 arg_acquired
= true;
1828 case ARG_ACTIVATABLE
:
1829 arg_activatable
= true;
1833 if (strv_extend(&arg_matches
, optarg
) < 0)
1840 r
= parse_size(optarg
, 1024, &sz
);
1842 log_error("Failed to parse size: %s", optarg
);
1846 if ((uint64_t) (size_t) sz
!= sz
) {
1847 log_error("Size out of range.");
1851 arg_snaplen
= (size_t) sz
;
1860 arg_transport
= BUS_TRANSPORT_REMOTE
;
1865 arg_transport
= BUS_TRANSPORT_MACHINE
;
1877 case ARG_EXPECT_REPLY
:
1878 r
= parse_boolean(optarg
);
1880 log_error("Failed to parse --expect-reply= parameter.");
1884 arg_expect_reply
= !!r
;
1888 case ARG_AUTO_START
:
1889 r
= parse_boolean(optarg
);
1891 log_error("Failed to parse --auto-start= parameter.");
1895 arg_auto_start
= !!r
;
1899 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1900 r
= parse_boolean(optarg
);
1902 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1906 arg_allow_interactive_authorization
= !!r
;
1910 r
= parse_sec(optarg
, &arg_timeout
);
1912 log_error("Failed to parse --timeout= parameter.");
1918 case ARG_AUGMENT_CREDS
:
1919 r
= parse_boolean(optarg
);
1921 log_error("Failed to parse --augment-creds= parameter.");
1925 arg_augment_creds
= !!r
;
1932 assert_not_reached("Unhandled option");
1938 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1941 if (optind
>= argc
||
1942 streq(argv
[optind
], "list"))
1943 return list_bus_names(bus
, argv
+ optind
);
1945 if (streq(argv
[optind
], "monitor"))
1946 return monitor(bus
, argv
+ optind
, message_dump
);
1948 if (streq(argv
[optind
], "capture"))
1949 return capture(bus
, argv
+ optind
);
1951 if (streq(argv
[optind
], "status"))
1952 return status(bus
, argv
+ optind
);
1954 if (streq(argv
[optind
], "tree"))
1955 return tree(bus
, argv
+ optind
);
1957 if (streq(argv
[optind
], "introspect"))
1958 return introspect(bus
, argv
+ optind
);
1960 if (streq(argv
[optind
], "call"))
1961 return call(bus
, argv
+ optind
);
1963 if (streq(argv
[optind
], "get-property"))
1964 return get_property(bus
, argv
+ optind
);
1966 if (streq(argv
[optind
], "set-property"))
1967 return set_property(bus
, argv
+ optind
);
1969 if (streq(argv
[optind
], "help"))
1972 log_error("Unknown command '%s'", argv
[optind
]);
1976 int main(int argc
, char *argv
[]) {
1977 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1980 log_parse_environment();
1983 r
= parse_argv(argc
, argv
);
1987 r
= sd_bus_new(&bus
);
1989 log_error_errno(r
, "Failed to allocate bus: %m");
1993 if (streq_ptr(argv
[optind
], "monitor") ||
1994 streq_ptr(argv
[optind
], "capture")) {
1996 r
= sd_bus_set_monitor(bus
, true);
1998 log_error_errno(r
, "Failed to set monitor mode: %m");
2002 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
2004 log_error_errno(r
, "Failed to enable credentials: %m");
2008 r
= sd_bus_negotiate_timestamp(bus
, true);
2010 log_error_errno(r
, "Failed to enable timestamps: %m");
2014 r
= sd_bus_negotiate_fds(bus
, true);
2016 log_error_errno(r
, "Failed to enable fds: %m");
2021 r
= sd_bus_set_bus_client(bus
, true);
2023 log_error_errno(r
, "Failed to set bus client: %m");
2028 r
= sd_bus_set_address(bus
, arg_address
);
2030 switch (arg_transport
) {
2032 case BUS_TRANSPORT_LOCAL
:
2034 bus
->is_user
= true;
2035 r
= bus_set_address_user(bus
);
2037 bus
->is_system
= true;
2038 r
= bus_set_address_system(bus
);
2042 case BUS_TRANSPORT_REMOTE
:
2043 r
= bus_set_address_system_remote(bus
, arg_host
);
2046 case BUS_TRANSPORT_MACHINE
:
2047 r
= bus_set_address_system_machine(bus
, arg_host
);
2051 assert_not_reached("Hmm, unknown transport type.");
2055 log_error_errno(r
, "Failed to set address: %m");
2059 r
= sd_bus_start(bus
);
2061 log_error_errno(r
, "Failed to connect to bus: %m");
2065 r
= busctl_main(bus
, argc
, argv
);
2070 strv_free(arg_matches
);
2072 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;