1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <stdio_ext.h>
26 #include "alloc-util.h"
28 #include "bus-internal.h"
29 #include "bus-signature.h"
32 #include "busctl-introspect.h"
35 #include "locale-util.h"
38 #include "parse-util.h"
39 #include "path-util.h"
42 #include "terminal-util.h"
43 #include "user-util.h"
46 static bool arg_no_pager
= false;
47 static bool arg_legend
= true;
48 static char *arg_address
= NULL
;
49 static bool arg_unique
= false;
50 static bool arg_acquired
= false;
51 static bool arg_activatable
= false;
52 static bool arg_show_machine
= false;
53 static char **arg_matches
= NULL
;
54 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
55 static char *arg_host
= NULL
;
56 static bool arg_user
= false;
57 static size_t arg_snaplen
= 4096;
58 static bool arg_list
= false;
59 static bool arg_quiet
= false;
60 static bool arg_verbose
= false;
61 static bool arg_expect_reply
= true;
62 static bool arg_auto_start
= true;
63 static bool arg_allow_interactive_authorization
= true;
64 static bool arg_augment_creds
= true;
65 static usec_t arg_timeout
= 0;
67 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
68 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
70 static int list_bus_names(sd_bus
*bus
, char **argv
) {
71 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
72 _cleanup_free_
char **merged
= NULL
;
73 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
84 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
85 arg_unique
= arg_acquired
= arg_activatable
= true;
87 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
89 return log_error_errno(r
, "Failed to list names: %m");
91 pager_open(arg_no_pager
, false);
93 names
= hashmap_new(&string_hash_ops
);
97 STRV_FOREACH(i
, acquired
) {
98 max_i
= MAX(max_i
, strlen(*i
));
100 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
102 return log_error_errno(r
, "Failed to add to hashmap: %m");
105 STRV_FOREACH(i
, activatable
) {
106 max_i
= MAX(max_i
, strlen(*i
));
108 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
109 if (r
< 0 && r
!= -EEXIST
)
110 return log_error_errno(r
, "Failed to add to hashmap: %m");
113 merged
= new(char*, hashmap_size(names
) + 1);
114 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
121 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
122 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
124 if (arg_show_machine
)
130 STRV_FOREACH(i
, merged
) {
131 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
134 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
137 printf("%-*s", (int) max_i
, *i
);
138 printf(" - - - (activatable) - - ");
139 if (arg_show_machine
)
147 if (!arg_unique
&& (*i
)[0] == ':')
150 if (!arg_acquired
&& (*i
)[0] != ':')
153 printf("%-*s", (int) max_i
, *i
);
155 r
= sd_bus_get_name_creds(
157 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
158 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
159 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
160 SD_BUS_CREDS_DESCRIPTION
, &creds
);
162 const char *unique
, *session
, *unit
, *cn
;
166 r
= sd_bus_creds_get_pid(creds
, &pid
);
168 const char *comm
= NULL
;
170 sd_bus_creds_get_comm(creds
, &comm
);
172 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
174 fputs(" - - ", stdout
);
176 r
= sd_bus_creds_get_euid(creds
, &uid
);
178 _cleanup_free_
char *u
= NULL
;
180 u
= uid_to_name(uid
);
189 fputs(" - ", stdout
);
191 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
193 printf(" %-13s", unique
);
195 fputs(" - ", stdout
);
197 r
= sd_bus_creds_get_unit(creds
, &unit
);
199 _cleanup_free_
char *e
;
201 e
= ellipsize(unit
, 25, 100);
207 fputs(" - ", stdout
);
209 r
= sd_bus_creds_get_session(creds
, &session
);
211 printf(" %-10s", session
);
213 fputs(" - ", stdout
);
215 r
= sd_bus_creds_get_description(creds
, &cn
);
217 printf(" %-19s", cn
);
219 fputs(" - ", stdout
);
222 printf(" - - - - - - - ");
224 if (arg_show_machine
) {
225 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
227 char m
[SD_ID128_STRING_MAX
];
228 printf(" %s\n", sd_id128_to_string(mid
, m
));
238 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
239 const char *vertical
, *space
;
242 /* We assume the list is sorted. Let's first skip over the
243 * entry we are looking at. */
248 if (!streq(*l
, path
))
254 vertical
= strjoina(prefix
, special_glyph(TREE_VERTICAL
));
255 space
= strjoina(prefix
, special_glyph(TREE_SPACE
));
258 bool has_more
= false;
260 if (!*l
|| !path_startswith(*l
, path
))
265 if (!*n
|| !path_startswith(*n
, path
))
268 if (!path_startswith(*n
, *l
)) {
276 printf("%s%s%s\n", prefix
, special_glyph(has_more
? TREE_BRANCH
: TREE_RIGHT
), *l
);
278 print_subtree(has_more
? vertical
: space
, *l
, l
);
283 static void print_tree(const char *prefix
, char **l
) {
285 pager_open(arg_no_pager
, false);
287 prefix
= strempty(prefix
);
293 printf("%s%s\n", prefix
, *i
);
297 if (strv_isempty(l
)) {
298 printf("No objects discovered.\n");
302 if (streq(l
[0], "/") && !l
[1]) {
303 printf("Only root object discovered.\n");
307 print_subtree(prefix
, "/", l
);
310 static int on_path(const char *path
, void *userdata
) {
311 Set
*paths
= userdata
;
316 r
= set_put_strdup(paths
, path
);
323 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
324 static const XMLIntrospectOps ops
= {
328 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
329 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
333 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
336 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
338 log_error("Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
342 r
= sd_bus_message_read(reply
, "s", &xml
);
344 return bus_log_parse_error(r
);
346 return parse_xml_introspect(path
, xml
, &ops
, paths
);
349 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
350 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
351 _cleanup_free_
char **l
= NULL
;
355 paths
= set_new(&string_hash_ops
);
359 done
= set_new(&string_hash_ops
);
363 failed
= set_new(&string_hash_ops
);
371 r
= set_put(paths
, m
);
378 _cleanup_free_
char *p
= NULL
;
381 p
= set_steal_first(paths
);
385 if (set_contains(done
, p
) ||
386 set_contains(failed
, p
))
389 q
= find_nodes(bus
, service
, p
, paths
, many
);
394 q
= set_put(failed
, p
);
396 q
= set_put(done
, p
);
405 pager_open(arg_no_pager
, false);
407 l
= set_get_strv(done
);
412 print_tree(prefix
, l
);
419 static int tree(sd_bus
*bus
, char **argv
) {
423 if (!arg_unique
&& !arg_acquired
)
426 if (strv_length(argv
) <= 1) {
427 _cleanup_strv_free_
char **names
= NULL
;
428 bool not_first
= false;
430 r
= sd_bus_list_names(bus
, &names
, NULL
);
432 return log_error_errno(r
, "Failed to get name list: %m");
434 pager_open(arg_no_pager
, false);
436 STRV_FOREACH(i
, names
) {
439 if (!arg_unique
&& (*i
)[0] == ':')
442 if (!arg_acquired
&& (*i
)[0] == ':')
448 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
450 q
= tree_one(bus
, *i
, NULL
, true);
457 STRV_FOREACH(i
, argv
+1) {
464 pager_open(arg_no_pager
, false);
465 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_normal());
468 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
477 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
481 const char *contents
= NULL
;
496 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
502 if (bus_type_is_container(type
) > 0) {
504 r
= sd_bus_message_enter_container(m
, type
, contents
);
508 if (type
== SD_BUS_TYPE_ARRAY
) {
511 /* count array entries */
514 r
= sd_bus_message_skip(m
, contents
);
523 r
= sd_bus_message_rewind(m
, false);
533 } else if (type
== SD_BUS_TYPE_VARIANT
) {
538 fprintf(f
, "%s", contents
);
542 r
= format_cmdline(m
, f
, needs_space
);
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
) {
696 set_free_with_destructor(s
, member_free
);
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_(sd_bus_message_unrefp
) sd_bus_message
*reply_xml
= NULL
;
864 _cleanup_(sd_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_xml
, "");
891 return log_error_errno(r
, "Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
893 r
= sd_bus_message_read(reply_xml
, "s", &xml
);
895 return bus_log_parse_error(r
);
897 /* First, get list of all properties */
898 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
902 /* Second, find the current values for them */
903 SET_FOREACH(m
, members
, i
) {
904 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
906 if (!streq(m
->type
, "property"))
912 if (argv
[3] && !streq(argv
[3], m
->interface
))
915 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "GetAll", &error
, &reply
, "s", m
->interface
);
917 return log_error_errno(r
, "%s", bus_error_message(&error
, r
));
919 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
921 return bus_log_parse_error(r
);
925 _cleanup_free_
char *buf
= NULL
;
926 _cleanup_fclose_
FILE *mf
= NULL
;
930 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
932 return bus_log_parse_error(r
);
937 r
= sd_bus_message_read(reply
, "s", &name
);
939 return bus_log_parse_error(r
);
941 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
943 return bus_log_parse_error(r
);
945 mf
= open_memstream(&buf
, &sz
);
949 (void) __fsetlocking(mf
, FSETLOCKING_BYCALLER
);
951 r
= format_cmdline(reply
, mf
, false);
953 return bus_log_parse_error(r
);
955 mf
= safe_fclose(mf
);
957 z
= set_get(members
, &((Member
) {
959 .interface
= m
->interface
,
960 .name
= (char*) name
}));
962 free_and_replace(z
->value
, buf
);
964 r
= sd_bus_message_exit_container(reply
);
966 return bus_log_parse_error(r
);
968 r
= sd_bus_message_exit_container(reply
);
970 return bus_log_parse_error(r
);
973 r
= sd_bus_message_exit_container(reply
);
975 return bus_log_parse_error(r
);
978 pager_open(arg_no_pager
, false);
980 name_width
= STRLEN("NAME");
981 type_width
= STRLEN("TYPE");
982 signature_width
= STRLEN("SIGNATURE");
983 result_width
= STRLEN("RESULT/VALUE");
985 sorted
= newa(Member
*, set_size(members
));
987 SET_FOREACH(m
, members
, i
) {
989 if (argv
[3] && !streq(argv
[3], m
->interface
))
993 name_width
= MAX(name_width
, strlen(m
->interface
));
995 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
997 type_width
= MAX(type_width
, strlen(m
->type
));
999 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1001 result_width
= MAX(result_width
, strlen(m
->result
));
1003 result_width
= MAX(result_width
, strlen(m
->value
));
1008 if (result_width
> 40)
1011 qsort(sorted
, k
, sizeof(Member
*), member_compare_funcp
);
1014 printf("%-*s %-*s %-*s %-*s %s\n",
1015 (int) name_width
, "NAME",
1016 (int) type_width
, "TYPE",
1017 (int) signature_width
, "SIGNATURE",
1018 (int) result_width
, "RESULT/VALUE",
1022 for (j
= 0; j
< k
; j
++) {
1023 _cleanup_free_
char *ellipsized
= NULL
;
1029 if (argv
[3] && !streq(argv
[3], m
->interface
))
1032 is_interface
= streq(m
->type
, "interface");
1034 if (argv
[3] && is_interface
)
1038 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1044 rv
= strdash(m
->result
);
1046 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1047 is_interface
? ansi_highlight() : "",
1048 is_interface
? "" : ".",
1049 - !is_interface
+ (int) name_width
, strdash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1050 is_interface
? ansi_normal() : "",
1051 (int) type_width
, strdash(m
->type
),
1052 (int) signature_width
, strdash(m
->signature
),
1053 (int) result_width
, rv
,
1054 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1055 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1056 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1057 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1058 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1059 m
->writable
? " writable" : "");
1065 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1066 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1069 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1070 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1073 static int monitor(sd_bus
*bus
, char *argv
[], int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1074 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*message
= NULL
;
1075 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1078 const char *unique_name
;
1079 bool is_monitor
= false;
1082 /* upgrade connection; it's not used for anything else after this call */
1083 r
= sd_bus_message_new_method_call(bus
, &message
, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
1085 return bus_log_create_error(r
);
1087 r
= sd_bus_message_open_container(message
, 'a', "s");
1089 return bus_log_create_error(r
);
1091 STRV_FOREACH(i
, argv
+1) {
1092 _cleanup_free_
char *m
= NULL
;
1094 if (!service_name_is_valid(*i
)) {
1095 log_error("Invalid service name '%s'", *i
);
1099 m
= strjoin("sender='", *i
, "'");
1103 r
= sd_bus_message_append_basic(message
, 's', m
);
1105 return bus_log_create_error(r
);
1108 m
= strjoin("destination='", *i
, "'");
1112 r
= sd_bus_message_append_basic(message
, 's', m
);
1114 return bus_log_create_error(r
);
1117 STRV_FOREACH(i
, arg_matches
) {
1118 r
= sd_bus_message_append_basic(message
, 's', *i
);
1120 return bus_log_create_error(r
);
1123 r
= sd_bus_message_close_container(message
);
1125 return bus_log_create_error(r
);
1127 r
= sd_bus_message_append_basic(message
, 'u', &flags
);
1129 return bus_log_create_error(r
);
1131 r
= sd_bus_call(bus
, message
, arg_timeout
, &error
, NULL
);
1133 log_error("%s", bus_error_message(&error
, r
));
1137 r
= sd_bus_get_unique_name(bus
, &unique_name
);
1139 return log_error_errno(r
, "Failed to get unique name: %m");
1141 log_info("Monitoring bus message stream.");
1144 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1146 r
= sd_bus_process(bus
, &m
);
1148 return log_error_errno(r
, "Failed to process bus: %m");
1153 /* wait until we lose our unique name */
1154 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus", "NameLost") <= 0)
1157 r
= sd_bus_message_read(m
, "s", &name
);
1159 return log_error_errno(r
, "Failed to read lost name: %m");
1161 if (streq(name
, unique_name
))
1171 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1172 log_info("Connection terminated, exiting.");
1182 r
= sd_bus_wait(bus
, (uint64_t) -1);
1184 return log_error_errno(r
, "Failed to wait for bus: %m");
1188 static int capture(sd_bus
*bus
, char *argv
[]) {
1191 if (isatty(fileno(stdout
)) > 0) {
1192 log_error("Refusing to write message data to console, please redirect output to a file.");
1196 bus_pcap_header(arg_snaplen
, stdout
);
1198 r
= monitor(bus
, argv
, message_pcap
);
1202 if (ferror(stdout
)) {
1203 log_error("Couldn't write capture file.");
1210 static int status(sd_bus
*bus
, char *argv
[]) {
1211 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
1217 if (strv_length(argv
) > 2) {
1218 log_error("Expects no or one argument.");
1223 r
= parse_pid(argv
[1], &pid
);
1225 r
= sd_bus_get_name_creds(
1228 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1231 r
= sd_bus_creds_new_from_pid(
1236 const char *scope
, *address
;
1239 r
= sd_bus_get_address(bus
, &address
);
1241 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1243 r
= sd_bus_get_scope(bus
, &scope
);
1245 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1247 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1249 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1251 r
= sd_bus_get_owner_creds(
1253 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1258 return log_error_errno(r
, "Failed to get credentials: %m");
1260 bus_creds_dump(creds
, NULL
, false);
1264 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1284 log_error("Too few parameters for signature.");
1293 case SD_BUS_TYPE_BOOLEAN
:
1295 r
= parse_boolean(v
);
1297 log_error("Failed to parse as boolean: %s", v
);
1301 r
= sd_bus_message_append_basic(m
, t
, &r
);
1304 case SD_BUS_TYPE_BYTE
: {
1307 r
= safe_atou8(v
, &z
);
1309 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1313 r
= sd_bus_message_append_basic(m
, t
, &z
);
1317 case SD_BUS_TYPE_INT16
: {
1320 r
= safe_atoi16(v
, &z
);
1322 log_error("Failed to parse as signed 16bit integer: %s", v
);
1326 r
= sd_bus_message_append_basic(m
, t
, &z
);
1330 case SD_BUS_TYPE_UINT16
: {
1333 r
= safe_atou16(v
, &z
);
1335 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1339 r
= sd_bus_message_append_basic(m
, t
, &z
);
1343 case SD_BUS_TYPE_INT32
: {
1346 r
= safe_atoi32(v
, &z
);
1348 log_error("Failed to parse as signed 32bit integer: %s", v
);
1352 r
= sd_bus_message_append_basic(m
, t
, &z
);
1356 case SD_BUS_TYPE_UINT32
: {
1359 r
= safe_atou32(v
, &z
);
1361 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1365 r
= sd_bus_message_append_basic(m
, t
, &z
);
1369 case SD_BUS_TYPE_INT64
: {
1372 r
= safe_atoi64(v
, &z
);
1374 log_error("Failed to parse as signed 64bit integer: %s", v
);
1378 r
= sd_bus_message_append_basic(m
, t
, &z
);
1382 case SD_BUS_TYPE_UINT64
: {
1385 r
= safe_atou64(v
, &z
);
1387 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1391 r
= sd_bus_message_append_basic(m
, t
, &z
);
1396 case SD_BUS_TYPE_DOUBLE
: {
1399 r
= safe_atod(v
, &z
);
1401 log_error("Failed to parse as double precision floating point: %s", v
);
1405 r
= sd_bus_message_append_basic(m
, t
, &z
);
1409 case SD_BUS_TYPE_STRING
:
1410 case SD_BUS_TYPE_OBJECT_PATH
:
1411 case SD_BUS_TYPE_SIGNATURE
:
1413 r
= sd_bus_message_append_basic(m
, t
, v
);
1416 case SD_BUS_TYPE_ARRAY
: {
1420 r
= safe_atou32(v
, &n
);
1422 log_error("Failed to parse number of array entries: %s", v
);
1426 r
= signature_element_length(signature
, &k
);
1428 log_error("Invalid array signature.");
1435 memcpy(s
, signature
, k
);
1438 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1440 return bus_log_create_error(r
);
1442 for (i
= 0; i
< n
; i
++) {
1443 r
= message_append_cmdline(m
, s
, &p
);
1451 r
= sd_bus_message_close_container(m
);
1455 case SD_BUS_TYPE_VARIANT
:
1456 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1458 return bus_log_create_error(r
);
1460 r
= message_append_cmdline(m
, v
, &p
);
1464 r
= sd_bus_message_close_container(m
);
1467 case SD_BUS_TYPE_STRUCT_BEGIN
:
1468 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1474 r
= signature_element_length(signature
, &k
);
1476 log_error("Invalid struct/dict entry signature.");
1482 memcpy(s
, signature
+ 1, k
- 2);
1485 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1487 return bus_log_create_error(r
);
1489 r
= message_append_cmdline(m
, s
, &p
);
1496 r
= sd_bus_message_close_container(m
);
1500 case SD_BUS_TYPE_UNIX_FD
:
1501 log_error("UNIX file descriptor not supported as type.");
1505 log_error("Unknown signature type %c.", t
);
1510 return bus_log_create_error(r
);
1517 static int call(sd_bus
*bus
, char *argv
[]) {
1518 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1519 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1524 if (strv_length(argv
) < 5) {
1525 log_error("Expects at least four arguments.");
1529 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1531 return bus_log_create_error(r
);
1533 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1535 return bus_log_create_error(r
);
1537 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1539 return bus_log_create_error(r
);
1541 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1543 return bus_log_create_error(r
);
1545 if (!isempty(argv
[5])) {
1550 r
= message_append_cmdline(m
, argv
[5], &p
);
1555 log_error("Too many parameters for signature.");
1560 if (!arg_expect_reply
) {
1561 r
= sd_bus_send(bus
, m
, NULL
);
1563 log_error("Failed to send message.");
1570 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1572 log_error("%s", bus_error_message(&error
, r
));
1576 r
= sd_bus_message_is_empty(reply
);
1578 return bus_log_parse_error(r
);
1580 if (r
== 0 && !arg_quiet
) {
1583 pager_open(arg_no_pager
, false);
1585 r
= bus_message_dump(reply
, stdout
, 0);
1590 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1593 r
= format_cmdline(reply
, stdout
, false);
1595 return bus_log_parse_error(r
);
1597 fputc('\n', stdout
);
1604 static int get_property(sd_bus
*bus
, char *argv
[]) {
1605 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1612 n
= strv_length(argv
);
1614 log_error("Expects at least four arguments.");
1618 STRV_FOREACH(i
, argv
+ 4) {
1619 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1620 const char *contents
= NULL
;
1623 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1625 log_error("%s", bus_error_message(&error
, r
));
1629 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1631 return bus_log_parse_error(r
);
1633 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1635 return bus_log_parse_error(r
);
1638 pager_open(arg_no_pager
, false);
1640 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1644 fputs(contents
, stdout
);
1647 r
= format_cmdline(reply
, stdout
, false);
1649 return bus_log_parse_error(r
);
1651 fputc('\n', stdout
);
1654 r
= sd_bus_message_exit_container(reply
);
1656 return bus_log_parse_error(r
);
1662 static int set_property(sd_bus
*bus
, char *argv
[]) {
1663 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1664 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1671 n
= strv_length(argv
);
1673 log_error("Expects at least five arguments.");
1677 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1679 return bus_log_create_error(r
);
1681 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1683 return bus_log_create_error(r
);
1685 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1687 return bus_log_create_error(r
);
1690 r
= message_append_cmdline(m
, argv
[5], &p
);
1694 r
= sd_bus_message_close_container(m
);
1696 return bus_log_create_error(r
);
1699 log_error("Too many parameters for signature.");
1703 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1705 log_error("%s", bus_error_message(&error
, r
));
1712 static int help(void) {
1713 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1714 "Introspect the bus.\n\n"
1715 " -h --help Show this help\n"
1716 " --version Show package version\n"
1717 " --no-pager Do not pipe output into a pager\n"
1718 " --no-legend Do not show the headers and footers\n"
1719 " --system Connect to system bus\n"
1720 " --user Connect to user bus\n"
1721 " -H --host=[USER@]HOST Operate on remote host\n"
1722 " -M --machine=CONTAINER Operate on local container\n"
1723 " --address=ADDRESS Connect to bus specified by address\n"
1724 " --show-machine Show machine ID column in list\n"
1725 " --unique Only show unique names\n"
1726 " --acquired Only show acquired names\n"
1727 " --activatable Only show activatable names\n"
1728 " --match=MATCH Only show matching messages\n"
1729 " --size=SIZE Maximum length of captured packet\n"
1730 " --list Don't show tree, but simple object path list\n"
1731 " -q --quiet Don't show method call reply\n"
1732 " --verbose Show result values in long format\n"
1733 " --expect-reply=BOOL Expect a method call reply\n"
1734 " --auto-start=BOOL Auto-start destination service\n"
1735 " --allow-interactive-authorization=BOOL\n"
1736 " Allow interactive authorization for operation\n"
1737 " --timeout=SECS Maximum time to wait for method call completion\n"
1738 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1740 " list List bus names\n"
1741 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1742 " monitor [SERVICE...] Show bus traffic\n"
1743 " capture [SERVICE...] Capture bus traffic as pcap\n"
1744 " tree [SERVICE...] Show object tree of service\n"
1745 " introspect SERVICE OBJECT [INTERFACE]\n"
1746 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1748 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1749 " Get property value\n"
1750 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1751 " Set property value\n"
1752 " help Show this help\n"
1753 , program_invocation_short_name
);
1758 static int parse_argv(int argc
, char *argv
[]) {
1761 ARG_VERSION
= 0x100,
1777 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1782 static const struct option options
[] = {
1783 { "help", no_argument
, NULL
, 'h' },
1784 { "version", no_argument
, NULL
, ARG_VERSION
},
1785 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1786 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1787 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1788 { "user", no_argument
, NULL
, ARG_USER
},
1789 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1790 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1791 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1792 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1793 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1794 { "match", required_argument
, NULL
, ARG_MATCH
},
1795 { "host", required_argument
, NULL
, 'H' },
1796 { "machine", required_argument
, NULL
, 'M' },
1797 { "size", required_argument
, NULL
, ARG_SIZE
},
1798 { "list", no_argument
, NULL
, ARG_LIST
},
1799 { "quiet", no_argument
, NULL
, 'q' },
1800 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1801 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1802 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1803 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1804 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1805 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1814 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1825 arg_no_pager
= true;
1841 arg_address
= optarg
;
1844 case ARG_SHOW_MACHINE
:
1845 arg_show_machine
= true;
1853 arg_acquired
= true;
1856 case ARG_ACTIVATABLE
:
1857 arg_activatable
= true;
1861 if (strv_extend(&arg_matches
, optarg
) < 0)
1868 r
= parse_size(optarg
, 1024, &sz
);
1870 log_error("Failed to parse size: %s", optarg
);
1874 if ((uint64_t) (size_t) sz
!= sz
) {
1875 log_error("Size out of range.");
1879 arg_snaplen
= (size_t) sz
;
1888 arg_transport
= BUS_TRANSPORT_REMOTE
;
1893 arg_transport
= BUS_TRANSPORT_MACHINE
;
1905 case ARG_EXPECT_REPLY
:
1906 r
= parse_boolean(optarg
);
1908 log_error("Failed to parse --expect-reply= parameter.");
1912 arg_expect_reply
= !!r
;
1916 case ARG_AUTO_START
:
1917 r
= parse_boolean(optarg
);
1919 log_error("Failed to parse --auto-start= parameter.");
1923 arg_auto_start
= !!r
;
1927 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1928 r
= parse_boolean(optarg
);
1930 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1934 arg_allow_interactive_authorization
= !!r
;
1938 r
= parse_sec(optarg
, &arg_timeout
);
1940 log_error("Failed to parse --timeout= parameter.");
1946 case ARG_AUGMENT_CREDS
:
1947 r
= parse_boolean(optarg
);
1949 log_error("Failed to parse --augment-creds= parameter.");
1953 arg_augment_creds
= !!r
;
1960 assert_not_reached("Unhandled option");
1966 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1969 if (optind
>= argc
||
1970 streq(argv
[optind
], "list"))
1971 return list_bus_names(bus
, argv
+ optind
);
1973 if (streq(argv
[optind
], "monitor"))
1974 return monitor(bus
, argv
+ optind
, message_dump
);
1976 if (streq(argv
[optind
], "capture"))
1977 return capture(bus
, argv
+ optind
);
1979 if (streq(argv
[optind
], "status"))
1980 return status(bus
, argv
+ optind
);
1982 if (streq(argv
[optind
], "tree"))
1983 return tree(bus
, argv
+ optind
);
1985 if (streq(argv
[optind
], "introspect"))
1986 return introspect(bus
, argv
+ optind
);
1988 if (streq(argv
[optind
], "call"))
1989 return call(bus
, argv
+ optind
);
1991 if (streq(argv
[optind
], "get-property"))
1992 return get_property(bus
, argv
+ optind
);
1994 if (streq(argv
[optind
], "set-property"))
1995 return set_property(bus
, argv
+ optind
);
1997 if (streq(argv
[optind
], "help"))
2000 log_error("Unknown command '%s'", argv
[optind
]);
2004 int main(int argc
, char *argv
[]) {
2005 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2008 log_parse_environment();
2011 r
= parse_argv(argc
, argv
);
2015 r
= sd_bus_new(&bus
);
2017 log_error_errno(r
, "Failed to allocate bus: %m");
2021 if (STRPTR_IN_SET(argv
[optind
], "monitor", "capture")) {
2023 r
= sd_bus_set_monitor(bus
, true);
2025 log_error_errno(r
, "Failed to set monitor mode: %m");
2029 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
2031 log_error_errno(r
, "Failed to enable credentials: %m");
2035 r
= sd_bus_negotiate_timestamp(bus
, true);
2037 log_error_errno(r
, "Failed to enable timestamps: %m");
2041 r
= sd_bus_negotiate_fds(bus
, true);
2043 log_error_errno(r
, "Failed to enable fds: %m");
2048 r
= sd_bus_set_bus_client(bus
, true);
2050 log_error_errno(r
, "Failed to set bus client: %m");
2055 r
= sd_bus_set_address(bus
, arg_address
);
2057 switch (arg_transport
) {
2059 case BUS_TRANSPORT_LOCAL
:
2061 bus
->is_user
= true;
2062 r
= bus_set_address_user(bus
);
2064 bus
->is_system
= true;
2065 r
= bus_set_address_system(bus
);
2069 case BUS_TRANSPORT_REMOTE
:
2070 r
= bus_set_address_system_remote(bus
, arg_host
);
2073 case BUS_TRANSPORT_MACHINE
:
2074 r
= bus_set_address_system_machine(bus
, arg_host
);
2078 assert_not_reached("Hmm, unknown transport type.");
2082 log_error_errno(r
, "Failed to set address: %m");
2086 r
= sd_bus_start(bus
);
2088 log_error_errno(r
, "Failed to connect to bus: %m");
2092 r
= busctl_main(bus
, argc
, argv
);
2097 strv_free(arg_matches
);
2099 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;