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"
35 #include "bus-signature.h"
37 #include "busctl-introspect.h"
38 #include "terminal-util.h"
40 static bool arg_no_pager
= false;
41 static bool arg_legend
= true;
42 static char *arg_address
= NULL
;
43 static bool arg_unique
= false;
44 static bool arg_acquired
= false;
45 static bool arg_activatable
= false;
46 static bool arg_show_machine
= false;
47 static char **arg_matches
= NULL
;
48 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
49 static char *arg_host
= NULL
;
50 static bool arg_user
= false;
51 static size_t arg_snaplen
= 4096;
52 static bool arg_list
= false;
53 static bool arg_quiet
= false;
54 static bool arg_verbose
= false;
55 static bool arg_expect_reply
= true;
56 static bool arg_auto_start
= true;
57 static bool arg_allow_interactive_authorization
= true;
58 static bool arg_augment_creds
= true;
59 static usec_t arg_timeout
= 0;
61 static void pager_open_if_enabled(void) {
63 /* Cache result before we open the pager */
70 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
71 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
73 static int list_bus_names(sd_bus
*bus
, char **argv
) {
74 _cleanup_strv_free_
char **acquired
= NULL
, **activatable
= NULL
;
75 _cleanup_free_
char **merged
= NULL
;
76 _cleanup_hashmap_free_ Hashmap
*names
= NULL
;
87 if (!arg_unique
&& !arg_acquired
&& !arg_activatable
)
88 arg_unique
= arg_acquired
= arg_activatable
= true;
90 r
= sd_bus_list_names(bus
, (arg_acquired
|| arg_unique
) ? &acquired
: NULL
, arg_activatable
? &activatable
: NULL
);
92 return log_error_errno(r
, "Failed to list names: %m");
94 pager_open_if_enabled();
96 names
= hashmap_new(&string_hash_ops
);
100 STRV_FOREACH(i
, acquired
) {
101 max_i
= MAX(max_i
, strlen(*i
));
103 r
= hashmap_put(names
, *i
, NAME_IS_ACQUIRED
);
105 return log_error_errno(r
, "Failed to add to hashmap: %m");
108 STRV_FOREACH(i
, activatable
) {
109 max_i
= MAX(max_i
, strlen(*i
));
111 r
= hashmap_put(names
, *i
, NAME_IS_ACTIVATABLE
);
112 if (r
< 0 && r
!= -EEXIST
)
113 return log_error_errno(r
, "Failed to add to hashmap: %m");
116 merged
= new(char*, hashmap_size(names
) + 1);
117 HASHMAP_FOREACH_KEY(v
, k
, names
, iterator
)
124 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
125 (int) max_i
, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
127 if (arg_show_machine
)
133 STRV_FOREACH(i
, merged
) {
134 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
137 if (hashmap_get(names
, *i
) == NAME_IS_ACTIVATABLE
) {
140 printf("%-*s", (int) max_i
, *i
);
141 printf(" - - - (activatable) - - ");
142 if (arg_show_machine
)
150 if (!arg_unique
&& (*i
)[0] == ':')
153 if (!arg_acquired
&& (*i
)[0] != ':')
156 printf("%-*s", (int) max_i
, *i
);
158 r
= sd_bus_get_name_creds(
160 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) |
161 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_PID
|SD_BUS_CREDS_COMM
|
162 SD_BUS_CREDS_UNIQUE_NAME
|SD_BUS_CREDS_UNIT
|SD_BUS_CREDS_SESSION
|
163 SD_BUS_CREDS_DESCRIPTION
, &creds
);
165 const char *unique
, *session
, *unit
, *cn
;
169 r
= sd_bus_creds_get_pid(creds
, &pid
);
171 const char *comm
= NULL
;
173 sd_bus_creds_get_comm(creds
, &comm
);
175 printf(" %10lu %-15s", (unsigned long) pid
, strna(comm
));
177 fputs(" - - ", stdout
);
179 r
= sd_bus_creds_get_euid(creds
, &uid
);
181 _cleanup_free_
char *u
= NULL
;
183 u
= uid_to_name(uid
);
192 fputs(" - ", stdout
);
194 r
= sd_bus_creds_get_unique_name(creds
, &unique
);
196 printf(" %-13s", unique
);
198 fputs(" - ", stdout
);
200 r
= sd_bus_creds_get_unit(creds
, &unit
);
202 _cleanup_free_
char *e
;
204 e
= ellipsize(unit
, 25, 100);
210 fputs(" - ", stdout
);
212 r
= sd_bus_creds_get_session(creds
, &session
);
214 printf(" %-10s", session
);
216 fputs(" - ", stdout
);
218 r
= sd_bus_creds_get_description(creds
, &cn
);
220 printf(" %-19s", cn
);
222 fputs(" - ", stdout
);
225 printf(" - - - - - - - ");
227 if (arg_show_machine
) {
228 r
= sd_bus_get_name_machine_id(bus
, *i
, &mid
);
230 char m
[SD_ID128_STRING_MAX
];
231 printf(" %s\n", sd_id128_to_string(mid
, m
));
241 static void print_subtree(const char *prefix
, const char *path
, char **l
) {
242 const char *vertical
, *space
;
245 /* We assume the list is sorted. Let's first skip over the
246 * entry we are looking at. */
251 if (!streq(*l
, path
))
257 vertical
= strjoina(prefix
, draw_special_char(DRAW_TREE_VERTICAL
));
258 space
= strjoina(prefix
, draw_special_char(DRAW_TREE_SPACE
));
261 bool has_more
= false;
263 if (!*l
|| !path_startswith(*l
, path
))
268 if (!*n
|| !path_startswith(*n
, path
))
271 if (!path_startswith(*n
, *l
)) {
279 printf("%s%s%s\n", prefix
, draw_special_char(has_more
? DRAW_TREE_BRANCH
: DRAW_TREE_RIGHT
), *l
);
281 print_subtree(has_more
? vertical
: space
, *l
, l
);
286 static void print_tree(const char *prefix
, char **l
) {
288 pager_open_if_enabled();
290 prefix
= strempty(prefix
);
296 printf("%s%s\n", prefix
, *i
);
300 if (strv_isempty(l
)) {
301 printf("No objects discovered.\n");
305 if (streq(l
[0], "/") && !l
[1]) {
306 printf("Only root object discovered.\n");
310 print_subtree(prefix
, "/", l
);
313 static int on_path(const char *path
, void *userdata
) {
314 Set
*paths
= userdata
;
319 r
= set_put_strdup(paths
, path
);
326 static int find_nodes(sd_bus
*bus
, const char *service
, const char *path
, Set
*paths
, bool many
) {
327 static const XMLIntrospectOps ops
= {
331 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
332 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
336 r
= sd_bus_call_method(bus
, service
, path
, "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
339 printf("Failed to introspect object %s of service %s: %s\n", path
, service
, bus_error_message(&error
, r
));
341 log_error("Failed to introspect object %s of service %s: %s", path
, service
, bus_error_message(&error
, r
));
345 r
= sd_bus_message_read(reply
, "s", &xml
);
347 return bus_log_parse_error(r
);
349 return parse_xml_introspect(path
, xml
, &ops
, paths
);
352 static int tree_one(sd_bus
*bus
, const char *service
, const char *prefix
, bool many
) {
353 _cleanup_set_free_free_ Set
*paths
= NULL
, *done
= NULL
, *failed
= NULL
;
354 _cleanup_free_
char **l
= NULL
;
358 paths
= set_new(&string_hash_ops
);
362 done
= set_new(&string_hash_ops
);
366 failed
= set_new(&string_hash_ops
);
374 r
= set_put(paths
, m
);
381 _cleanup_free_
char *p
= NULL
;
384 p
= set_steal_first(paths
);
388 if (set_contains(done
, p
) ||
389 set_contains(failed
, p
))
392 q
= find_nodes(bus
, service
, p
, paths
, many
);
397 q
= set_put(failed
, p
);
399 q
= set_put(done
, p
);
408 pager_open_if_enabled();
410 l
= set_get_strv(done
);
415 print_tree(prefix
, l
);
422 static int tree(sd_bus
*bus
, char **argv
) {
426 if (!arg_unique
&& !arg_acquired
)
429 if (strv_length(argv
) <= 1) {
430 _cleanup_strv_free_
char **names
= NULL
;
431 bool not_first
= false;
433 r
= sd_bus_list_names(bus
, &names
, NULL
);
435 return log_error_errno(r
, "Failed to get name list: %m");
437 pager_open_if_enabled();
439 STRV_FOREACH(i
, names
) {
442 if (!arg_unique
&& (*i
)[0] == ':')
445 if (!arg_acquired
&& (*i
)[0] == ':')
451 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_highlight_off());
453 q
= tree_one(bus
, *i
, NULL
, true);
460 STRV_FOREACH(i
, argv
+1) {
467 pager_open_if_enabled();
468 printf("Service %s%s%s:\n", ansi_highlight(), *i
, ansi_highlight_off());
471 q
= tree_one(bus
, *i
, NULL
, !!argv
[2]);
480 static int format_cmdline(sd_bus_message
*m
, FILE *f
, bool needs_space
) {
484 const char *contents
= NULL
;
499 r
= sd_bus_message_peek_type(m
, &type
, &contents
);
503 if (bus_type_is_container(type
) > 0) {
505 r
= sd_bus_message_enter_container(m
, type
, contents
);
509 if (type
== SD_BUS_TYPE_ARRAY
) {
512 /* count array entries */
515 r
= sd_bus_message_skip(m
, contents
);
524 r
= sd_bus_message_rewind(m
, false);
532 } else if (type
== SD_BUS_TYPE_VARIANT
) {
537 fprintf(f
, "%s", contents
);
540 r
= format_cmdline(m
, f
, needs_space
|| IN_SET(type
, SD_BUS_TYPE_ARRAY
, SD_BUS_TYPE_VARIANT
));
544 r
= sd_bus_message_exit_container(m
);
551 r
= sd_bus_message_read_basic(m
, type
, &basic
);
559 case SD_BUS_TYPE_BYTE
:
560 fprintf(f
, "%u", basic
.u8
);
563 case SD_BUS_TYPE_BOOLEAN
:
564 fputs(true_false(basic
.i
), f
);
567 case SD_BUS_TYPE_INT16
:
568 fprintf(f
, "%i", basic
.s16
);
571 case SD_BUS_TYPE_UINT16
:
572 fprintf(f
, "%u", basic
.u16
);
575 case SD_BUS_TYPE_INT32
:
576 fprintf(f
, "%i", basic
.s32
);
579 case SD_BUS_TYPE_UINT32
:
580 fprintf(f
, "%u", basic
.u32
);
583 case SD_BUS_TYPE_INT64
:
584 fprintf(f
, "%" PRIi64
, basic
.s64
);
587 case SD_BUS_TYPE_UINT64
:
588 fprintf(f
, "%" PRIu64
, basic
.u64
);
591 case SD_BUS_TYPE_DOUBLE
:
592 fprintf(f
, "%g", basic
.d64
);
595 case SD_BUS_TYPE_STRING
:
596 case SD_BUS_TYPE_OBJECT_PATH
:
597 case SD_BUS_TYPE_SIGNATURE
: {
598 _cleanup_free_
char *b
= NULL
;
600 b
= cescape(basic
.string
);
604 fprintf(f
, "\"%s\"", b
);
608 case SD_BUS_TYPE_UNIX_FD
:
609 fprintf(f
, "%i", basic
.i
);
613 assert_not_reached("Unknown basic type.");
620 typedef struct Member
{
631 static unsigned long member_hash_func(const void *p
, const uint8_t hash_key
[]) {
638 ul
= string_hash_func(m
->type
, hash_key
);
641 ul
^= string_hash_func(m
->name
, hash_key
);
644 ul
^= string_hash_func(m
->interface
, hash_key
);
649 static int member_compare_func(const void *a
, const void *b
) {
650 const Member
*x
= a
, *y
= b
;
658 d
= strcmp_ptr(x
->interface
, y
->interface
);
662 d
= strcmp(x
->type
, y
->type
);
666 return strcmp_ptr(x
->name
, y
->name
);
669 static int member_compare_funcp(const void *a
, const void *b
) {
670 const Member
*const * x
= (const Member
*const *) a
, * const *y
= (const Member
*const *) b
;
672 return member_compare_func(*x
, *y
);
675 static void member_free(Member
*m
) {
687 DEFINE_TRIVIAL_CLEANUP_FUNC(Member
*, member_free
);
689 static void member_set_free(Set
*s
) {
692 while ((m
= set_steal_first(s
)))
698 DEFINE_TRIVIAL_CLEANUP_FUNC(Set
*, member_set_free
);
700 static int on_interface(const char *interface
, uint64_t flags
, void *userdata
) {
701 _cleanup_(member_freep
) Member
*m
;
702 Set
*members
= userdata
;
712 m
->type
= "interface";
715 r
= free_and_strdup(&m
->interface
, interface
);
719 r
= set_put(members
, m
);
721 log_error("Duplicate interface");
729 static int on_method(const char *interface
, const char *name
, const char *signature
, const char *result
, uint64_t flags
, void *userdata
) {
730 _cleanup_(member_freep
) Member
*m
;
731 Set
*members
= userdata
;
744 r
= free_and_strdup(&m
->interface
, interface
);
748 r
= free_and_strdup(&m
->name
, name
);
752 r
= free_and_strdup(&m
->signature
, signature
);
756 r
= free_and_strdup(&m
->result
, result
);
760 r
= set_put(members
, m
);
762 log_error("Duplicate method");
770 static int on_signal(const char *interface
, const char *name
, const char *signature
, uint64_t flags
, void *userdata
) {
771 _cleanup_(member_freep
) Member
*m
;
772 Set
*members
= userdata
;
785 r
= free_and_strdup(&m
->interface
, interface
);
789 r
= free_and_strdup(&m
->name
, name
);
793 r
= free_and_strdup(&m
->signature
, signature
);
797 r
= set_put(members
, m
);
799 log_error("Duplicate signal");
807 static int on_property(const char *interface
, const char *name
, const char *signature
, bool writable
, uint64_t flags
, void *userdata
) {
808 _cleanup_(member_freep
) Member
*m
;
809 Set
*members
= userdata
;
819 m
->type
= "property";
821 m
->writable
= writable
;
823 r
= free_and_strdup(&m
->interface
, interface
);
827 r
= free_and_strdup(&m
->name
, name
);
831 r
= free_and_strdup(&m
->signature
, signature
);
835 r
= set_put(members
, m
);
837 log_error("Duplicate property");
845 static const char *strdash(const char *x
) {
846 return isempty(x
) ? "-" : x
;
849 static int introspect(sd_bus
*bus
, char **argv
) {
850 static const struct hash_ops member_hash_ops
= {
851 .hash
= member_hash_func
,
852 .compare
= member_compare_func
,
855 static const XMLIntrospectOps ops
= {
856 .on_interface
= on_interface
,
857 .on_method
= on_method
,
858 .on_signal
= on_signal
,
859 .on_property
= on_property
,
862 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
863 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
864 _cleanup_(member_set_freep
) Set
*members
= NULL
;
869 unsigned name_width
, type_width
, signature_width
, result_width
;
870 Member
**sorted
= NULL
;
871 unsigned k
= 0, j
, n_args
;
873 n_args
= strv_length(argv
);
875 log_error("Requires service and object path argument.");
880 log_error("Too many arguments.");
884 members
= set_new(&member_hash_ops
);
888 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error
, &reply
, "");
890 log_error("Failed to introspect object %s of service %s: %s", argv
[2], argv
[1], bus_error_message(&error
, r
));
894 r
= sd_bus_message_read(reply
, "s", &xml
);
896 return bus_log_parse_error(r
);
898 /* First, get list of all properties */
899 r
= parse_xml_introspect(argv
[2], xml
, &ops
, members
);
903 /* Second, find the current values for them */
904 SET_FOREACH(m
, members
, i
) {
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 log_error("%s", bus_error_message(&error
, r
));
921 r
= sd_bus_message_enter_container(reply
, 'a', "{sv}");
923 return bus_log_parse_error(r
);
927 _cleanup_free_
char *buf
= NULL
;
928 _cleanup_fclose_
FILE *mf
= NULL
;
932 r
= sd_bus_message_enter_container(reply
, 'e', "sv");
934 return bus_log_parse_error(r
);
939 r
= sd_bus_message_read(reply
, "s", &name
);
941 return bus_log_parse_error(r
);
943 r
= sd_bus_message_enter_container(reply
, 'v', NULL
);
945 return bus_log_parse_error(r
);
947 mf
= open_memstream(&buf
, &sz
);
951 r
= format_cmdline(reply
, mf
, false);
953 return bus_log_parse_error(r
);
958 z
= set_get(members
, &((Member
) {
960 .interface
= m
->interface
,
961 .name
= (char*) name
}));
968 r
= sd_bus_message_exit_container(reply
);
970 return bus_log_parse_error(r
);
972 r
= sd_bus_message_exit_container(reply
);
974 return bus_log_parse_error(r
);
977 r
= sd_bus_message_exit_container(reply
);
979 return bus_log_parse_error(r
);
982 pager_open_if_enabled();
984 name_width
= strlen("NAME");
985 type_width
= strlen("TYPE");
986 signature_width
= strlen("SIGNATURE");
987 result_width
= strlen("RESULT/VALUE");
989 sorted
= newa(Member
*, set_size(members
));
991 SET_FOREACH(m
, members
, i
) {
993 if (argv
[3] && !streq(argv
[3], m
->interface
))
997 name_width
= MAX(name_width
, strlen(m
->interface
));
999 name_width
= MAX(name_width
, strlen(m
->name
) + 1);
1001 type_width
= MAX(type_width
, strlen(m
->type
));
1003 signature_width
= MAX(signature_width
, strlen(m
->signature
));
1005 result_width
= MAX(result_width
, strlen(m
->result
));
1007 result_width
= MAX(result_width
, strlen(m
->value
));
1012 if (result_width
> 40)
1015 qsort(sorted
, k
, sizeof(Member
*), member_compare_funcp
);
1018 printf("%-*s %-*s %-*s %-*s %s\n",
1019 (int) name_width
, "NAME",
1020 (int) type_width
, "TYPE",
1021 (int) signature_width
, "SIGNATURE",
1022 (int) result_width
, "RESULT/VALUE",
1026 for (j
= 0; j
< k
; j
++) {
1027 _cleanup_free_
char *ellipsized
= NULL
;
1033 if (argv
[3] && !streq(argv
[3], m
->interface
))
1036 is_interface
= streq(m
->type
, "interface");
1038 if (argv
[3] && is_interface
)
1042 ellipsized
= ellipsize(m
->value
, result_width
, 100);
1048 rv
= strdash(m
->result
);
1050 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1051 is_interface
? ansi_highlight() : "",
1052 is_interface
? "" : ".",
1053 - !is_interface
+ (int) name_width
, strdash(streq_ptr(m
->type
, "interface") ? m
->interface
: m
->name
),
1054 is_interface
? ansi_highlight_off() : "",
1055 (int) type_width
, strdash(m
->type
),
1056 (int) signature_width
, strdash(m
->signature
),
1057 (int) result_width
, rv
,
1058 (m
->flags
& SD_BUS_VTABLE_DEPRECATED
) ? " deprecated" : (m
->flags
|| m
->writable
? "" : " -"),
1059 (m
->flags
& SD_BUS_VTABLE_METHOD_NO_REPLY
) ? " no-reply" : "",
1060 (m
->flags
& SD_BUS_VTABLE_PROPERTY_CONST
) ? " const" : "",
1061 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
) ? " emits-change" : "",
1062 (m
->flags
& SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION
) ? " emits-invalidation" : "",
1063 m
->writable
? " writable" : "");
1069 static int message_dump(sd_bus_message
*m
, FILE *f
) {
1070 return bus_message_dump(m
, f
, BUS_MESSAGE_DUMP_WITH_HEADER
);
1073 static int message_pcap(sd_bus_message
*m
, FILE *f
) {
1074 return bus_message_pcap_frame(m
, arg_snaplen
, f
);
1077 static int monitor(sd_bus
*bus
, char *argv
[], int (*dump
)(sd_bus_message
*m
, FILE *f
)) {
1078 bool added_something
= false;
1082 STRV_FOREACH(i
, argv
+1) {
1083 _cleanup_free_
char *m
= NULL
;
1085 if (!service_name_is_valid(*i
)) {
1086 log_error("Invalid service name '%s'", *i
);
1090 m
= strjoin("sender='", *i
, "'", NULL
);
1094 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1096 return log_error_errno(r
, "Failed to add match: %m");
1098 added_something
= true;
1101 STRV_FOREACH(i
, arg_matches
) {
1102 r
= sd_bus_add_match(bus
, NULL
, *i
, NULL
, NULL
);
1104 return log_error_errno(r
, "Failed to add match: %m");
1106 added_something
= true;
1109 if (!added_something
) {
1110 r
= sd_bus_add_match(bus
, NULL
, "", NULL
, NULL
);
1112 return log_error_errno(r
, "Failed to add match: %m");
1115 log_info("Monitoring bus message stream.");
1118 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1120 r
= sd_bus_process(bus
, &m
);
1122 return log_error_errno(r
, "Failed to process bus: %m");
1128 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1129 log_info("Connection terminated, exiting.");
1139 r
= sd_bus_wait(bus
, (uint64_t) -1);
1141 return log_error_errno(r
, "Failed to wait for bus: %m");
1145 static int capture(sd_bus
*bus
, char *argv
[]) {
1148 if (isatty(fileno(stdout
)) > 0) {
1149 log_error("Refusing to write message data to console, please redirect output to a file.");
1153 bus_pcap_header(arg_snaplen
, stdout
);
1155 r
= monitor(bus
, argv
, message_pcap
);
1159 if (ferror(stdout
)) {
1160 log_error("Couldn't write capture file.");
1167 static int status(sd_bus
*bus
, char *argv
[]) {
1168 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1174 if (strv_length(argv
) > 2) {
1175 log_error("Expects no or one argument.");
1180 r
= parse_pid(argv
[1], &pid
);
1182 r
= sd_bus_get_name_creds(
1185 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1188 r
= sd_bus_creds_new_from_pid(
1193 const char *scope
, *address
;
1196 r
= sd_bus_get_address(bus
, &address
);
1198 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_highlight_off());
1200 r
= sd_bus_get_scope(bus
, &scope
);
1202 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_highlight_off());
1204 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1206 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_highlight_off());
1208 r
= sd_bus_get_owner_creds(
1210 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1215 return log_error_errno(r
, "Failed to get credentials: %m");
1217 bus_creds_dump(creds
, NULL
, false);
1221 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1241 log_error("Too few parameters for signature.");
1250 case SD_BUS_TYPE_BOOLEAN
:
1252 r
= parse_boolean(v
);
1254 log_error("Failed to parse as boolean: %s", v
);
1258 r
= sd_bus_message_append_basic(m
, t
, &r
);
1261 case SD_BUS_TYPE_BYTE
: {
1264 r
= safe_atou8(v
, &z
);
1266 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1270 r
= sd_bus_message_append_basic(m
, t
, &z
);
1274 case SD_BUS_TYPE_INT16
: {
1277 r
= safe_atoi16(v
, &z
);
1279 log_error("Failed to parse as signed 16bit integer: %s", v
);
1283 r
= sd_bus_message_append_basic(m
, t
, &z
);
1287 case SD_BUS_TYPE_UINT16
: {
1290 r
= safe_atou16(v
, &z
);
1292 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1296 r
= sd_bus_message_append_basic(m
, t
, &z
);
1300 case SD_BUS_TYPE_INT32
: {
1303 r
= safe_atoi32(v
, &z
);
1305 log_error("Failed to parse as signed 32bit integer: %s", v
);
1309 r
= sd_bus_message_append_basic(m
, t
, &z
);
1313 case SD_BUS_TYPE_UINT32
: {
1316 r
= safe_atou32(v
, &z
);
1318 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1322 r
= sd_bus_message_append_basic(m
, t
, &z
);
1326 case SD_BUS_TYPE_INT64
: {
1329 r
= safe_atoi64(v
, &z
);
1331 log_error("Failed to parse as signed 64bit integer: %s", v
);
1335 r
= sd_bus_message_append_basic(m
, t
, &z
);
1339 case SD_BUS_TYPE_UINT64
: {
1342 r
= safe_atou64(v
, &z
);
1344 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1348 r
= sd_bus_message_append_basic(m
, t
, &z
);
1353 case SD_BUS_TYPE_DOUBLE
: {
1356 r
= safe_atod(v
, &z
);
1358 log_error("Failed to parse as double precision floating point: %s", v
);
1362 r
= sd_bus_message_append_basic(m
, t
, &z
);
1366 case SD_BUS_TYPE_STRING
:
1367 case SD_BUS_TYPE_OBJECT_PATH
:
1368 case SD_BUS_TYPE_SIGNATURE
:
1370 r
= sd_bus_message_append_basic(m
, t
, v
);
1373 case SD_BUS_TYPE_ARRAY
: {
1377 r
= safe_atou32(v
, &n
);
1379 log_error("Failed to parse number of array entries: %s", v
);
1383 r
= signature_element_length(signature
, &k
);
1385 log_error("Invalid array signature.");
1392 memcpy(s
, signature
, k
);
1395 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1397 return bus_log_create_error(r
);
1399 for (i
= 0; i
< n
; i
++) {
1400 r
= message_append_cmdline(m
, s
, &p
);
1408 r
= sd_bus_message_close_container(m
);
1412 case SD_BUS_TYPE_VARIANT
:
1413 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1415 return bus_log_create_error(r
);
1417 r
= message_append_cmdline(m
, v
, &p
);
1421 r
= sd_bus_message_close_container(m
);
1424 case SD_BUS_TYPE_STRUCT_BEGIN
:
1425 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1431 r
= signature_element_length(signature
, &k
);
1433 log_error("Invalid struct/dict entry signature.");
1439 memcpy(s
, signature
+ 1, k
- 2);
1442 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1444 return bus_log_create_error(r
);
1446 r
= message_append_cmdline(m
, s
, &p
);
1453 r
= sd_bus_message_close_container(m
);
1457 case SD_BUS_TYPE_UNIX_FD
:
1458 log_error("UNIX file descriptor not supported as type.");
1462 log_error("Unknown signature type %c.", t
);
1467 return bus_log_create_error(r
);
1474 static int call(sd_bus
*bus
, char *argv
[]) {
1475 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1476 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1481 if (strv_length(argv
) < 5) {
1482 log_error("Expects at least four arguments.");
1486 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1488 return bus_log_create_error(r
);
1490 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1492 return bus_log_create_error(r
);
1494 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1496 return bus_log_create_error(r
);
1498 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1500 return bus_log_create_error(r
);
1502 if (!isempty(argv
[5])) {
1507 r
= message_append_cmdline(m
, argv
[5], &p
);
1512 log_error("Too many parameters for signature.");
1517 if (!arg_expect_reply
) {
1518 r
= sd_bus_send(bus
, m
, NULL
);
1520 log_error("Failed to send message.");
1527 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1529 log_error("%s", bus_error_message(&error
, r
));
1533 r
= sd_bus_message_is_empty(reply
);
1535 return bus_log_parse_error(r
);
1537 if (r
== 0 && !arg_quiet
) {
1540 pager_open_if_enabled();
1542 r
= bus_message_dump(reply
, stdout
, 0);
1547 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1550 r
= format_cmdline(reply
, stdout
, false);
1552 return bus_log_parse_error(r
);
1554 fputc('\n', stdout
);
1561 static int get_property(sd_bus
*bus
, char *argv
[]) {
1562 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1569 n
= strv_length(argv
);
1571 log_error("Expects at least four arguments.");
1575 STRV_FOREACH(i
, argv
+ 4) {
1576 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1577 const char *contents
= NULL
;
1580 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1582 log_error("%s", bus_error_message(&error
, r
));
1586 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1588 return bus_log_parse_error(r
);
1590 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1592 return bus_log_parse_error(r
);
1595 pager_open_if_enabled();
1597 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1601 fputs(contents
, stdout
);
1604 r
= format_cmdline(reply
, stdout
, false);
1606 return bus_log_parse_error(r
);
1608 fputc('\n', stdout
);
1611 r
= sd_bus_message_exit_container(reply
);
1613 return bus_log_parse_error(r
);
1619 static int set_property(sd_bus
*bus
, char *argv
[]) {
1620 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1621 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1628 n
= strv_length(argv
);
1630 log_error("Expects at least five arguments.");
1634 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1636 return bus_log_create_error(r
);
1638 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1640 return bus_log_create_error(r
);
1642 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1644 return bus_log_create_error(r
);
1647 r
= message_append_cmdline(m
, argv
[5], &p
);
1651 r
= sd_bus_message_close_container(m
);
1653 return bus_log_create_error(r
);
1656 log_error("Too many parameters for signature.");
1660 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1662 log_error("%s", bus_error_message(&error
, r
));
1669 static int help(void) {
1670 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1671 "Introspect the bus.\n\n"
1672 " -h --help Show this help\n"
1673 " --version Show package version\n"
1674 " --no-pager Do not pipe output into a pager\n"
1675 " --no-legend Do not show the headers and footers\n"
1676 " --system Connect to system bus\n"
1677 " --user Connect to user bus\n"
1678 " -H --host=[USER@]HOST Operate on remote host\n"
1679 " -M --machine=CONTAINER Operate on local container\n"
1680 " --address=ADDRESS Connect to bus specified by address\n"
1681 " --show-machine Show machine ID column in list\n"
1682 " --unique Only show unique names\n"
1683 " --acquired Only show acquired names\n"
1684 " --activatable Only show activatable names\n"
1685 " --match=MATCH Only show matching messages\n"
1686 " --size=SIZE Maximum length of captured packet\n"
1687 " --list Don't show tree, but simple object path list\n"
1688 " --quiet Don't show method call reply\n"
1689 " --verbose Show result values in long format\n"
1690 " --expect-reply=BOOL Expect a method call reply\n"
1691 " --auto-start=BOOL Auto-start destination service\n"
1692 " --allow-interactive-authorization=BOOL\n"
1693 " Allow interactive authorization for operation\n"
1694 " --timeout=SECS Maximum time to wait for method call completion\n"
1695 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1697 " list List bus names\n"
1698 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1699 " monitor [SERVICE...] Show bus traffic\n"
1700 " capture [SERVICE...] Capture bus traffic as pcap\n"
1701 " tree [SERVICE...] Show object tree of service\n"
1702 " introspect SERVICE OBJECT [INTERFACE]\n"
1703 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1705 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1706 " Get property value\n"
1707 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1708 " Set property value\n"
1709 " help Show this help\n"
1710 , program_invocation_short_name
);
1715 static int parse_argv(int argc
, char *argv
[]) {
1718 ARG_VERSION
= 0x100,
1734 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1739 static const struct option options
[] = {
1740 { "help", no_argument
, NULL
, 'h' },
1741 { "version", no_argument
, NULL
, ARG_VERSION
},
1742 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1743 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1744 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1745 { "user", no_argument
, NULL
, ARG_USER
},
1746 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1747 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1748 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1749 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1750 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1751 { "match", required_argument
, NULL
, ARG_MATCH
},
1752 { "host", required_argument
, NULL
, 'H' },
1753 { "machine", required_argument
, NULL
, 'M' },
1754 { "size", required_argument
, NULL
, ARG_SIZE
},
1755 { "list", no_argument
, NULL
, ARG_LIST
},
1756 { "quiet", no_argument
, NULL
, 'q' },
1757 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1758 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1759 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1760 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1761 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1762 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1771 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1779 puts(PACKAGE_STRING
);
1780 puts(SYSTEMD_FEATURES
);
1784 arg_no_pager
= true;
1800 arg_address
= optarg
;
1803 case ARG_SHOW_MACHINE
:
1804 arg_show_machine
= true;
1812 arg_acquired
= true;
1815 case ARG_ACTIVATABLE
:
1816 arg_activatable
= true;
1820 if (strv_extend(&arg_matches
, optarg
) < 0)
1827 r
= parse_size(optarg
, 1024, &o
);
1829 log_error("Failed to parse size: %s", optarg
);
1833 if ((off_t
) (size_t) o
!= o
) {
1834 log_error("Size out of range.");
1838 arg_snaplen
= (size_t) o
;
1847 arg_transport
= BUS_TRANSPORT_REMOTE
;
1852 arg_transport
= BUS_TRANSPORT_MACHINE
;
1864 case ARG_EXPECT_REPLY
:
1865 r
= parse_boolean(optarg
);
1867 log_error("Failed to parse --expect-reply= parameter.");
1871 arg_expect_reply
= !!r
;
1875 case ARG_AUTO_START
:
1876 r
= parse_boolean(optarg
);
1878 log_error("Failed to parse --auto-start= parameter.");
1882 arg_auto_start
= !!r
;
1886 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1887 r
= parse_boolean(optarg
);
1889 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1893 arg_allow_interactive_authorization
= !!r
;
1897 r
= parse_sec(optarg
, &arg_timeout
);
1899 log_error("Failed to parse --timeout= parameter.");
1905 case ARG_AUGMENT_CREDS
:
1906 r
= parse_boolean(optarg
);
1908 log_error("Failed to parse --augment-creds= parameter.");
1912 arg_augment_creds
= !!r
;
1919 assert_not_reached("Unhandled option");
1925 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1928 if (optind
>= argc
||
1929 streq(argv
[optind
], "list"))
1930 return list_bus_names(bus
, argv
+ optind
);
1932 if (streq(argv
[optind
], "monitor"))
1933 return monitor(bus
, argv
+ optind
, message_dump
);
1935 if (streq(argv
[optind
], "capture"))
1936 return capture(bus
, argv
+ optind
);
1938 if (streq(argv
[optind
], "status"))
1939 return status(bus
, argv
+ optind
);
1941 if (streq(argv
[optind
], "tree"))
1942 return tree(bus
, argv
+ optind
);
1944 if (streq(argv
[optind
], "introspect"))
1945 return introspect(bus
, argv
+ optind
);
1947 if (streq(argv
[optind
], "call"))
1948 return call(bus
, argv
+ optind
);
1950 if (streq(argv
[optind
], "get-property"))
1951 return get_property(bus
, argv
+ optind
);
1953 if (streq(argv
[optind
], "set-property"))
1954 return set_property(bus
, argv
+ optind
);
1956 if (streq(argv
[optind
], "help"))
1959 log_error("Unknown command '%s'", argv
[optind
]);
1963 int main(int argc
, char *argv
[]) {
1964 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1967 log_parse_environment();
1970 r
= parse_argv(argc
, argv
);
1974 r
= sd_bus_new(&bus
);
1976 log_error_errno(r
, "Failed to allocate bus: %m");
1980 if (streq_ptr(argv
[optind
], "monitor") ||
1981 streq_ptr(argv
[optind
], "capture")) {
1983 r
= sd_bus_set_monitor(bus
, true);
1985 log_error_errno(r
, "Failed to set monitor mode: %m");
1989 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
1991 log_error_errno(r
, "Failed to enable credentials: %m");
1995 r
= sd_bus_negotiate_timestamp(bus
, true);
1997 log_error_errno(r
, "Failed to enable timestamps: %m");
2001 r
= sd_bus_negotiate_fds(bus
, true);
2003 log_error_errno(r
, "Failed to enable fds: %m");
2008 r
= sd_bus_set_bus_client(bus
, true);
2010 log_error_errno(r
, "Failed to set bus client: %m");
2015 r
= sd_bus_set_address(bus
, arg_address
);
2017 switch (arg_transport
) {
2019 case BUS_TRANSPORT_LOCAL
:
2021 bus
->is_user
= true;
2022 r
= bus_set_address_user(bus
);
2024 bus
->is_system
= true;
2025 r
= bus_set_address_system(bus
);
2029 case BUS_TRANSPORT_REMOTE
:
2030 r
= bus_set_address_system_remote(bus
, arg_host
);
2033 case BUS_TRANSPORT_MACHINE
:
2034 r
= bus_set_address_system_machine(bus
, arg_host
);
2038 assert_not_reached("Hmm, unknown transport type.");
2042 log_error_errno(r
, "Failed to set address: %m");
2046 r
= sd_bus_start(bus
);
2048 log_error_errno(r
, "Failed to connect to bus: %m");
2052 r
= busctl_main(bus
, argc
, argv
);
2057 strv_free(arg_matches
);
2059 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;