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"
34 #include "path-util.h"
37 #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_normal());
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_normal());
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_normal() : "",
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");
1099 m
= strjoin("destination='", *i
, "'", NULL
);
1103 r
= sd_bus_add_match(bus
, NULL
, m
, NULL
, NULL
);
1105 return log_error_errno(r
, "Failed to add match: %m");
1107 added_something
= true;
1110 STRV_FOREACH(i
, arg_matches
) {
1111 r
= sd_bus_add_match(bus
, NULL
, *i
, NULL
, NULL
);
1113 return log_error_errno(r
, "Failed to add match: %m");
1115 added_something
= true;
1118 if (!added_something
) {
1119 r
= sd_bus_add_match(bus
, NULL
, "", NULL
, NULL
);
1121 return log_error_errno(r
, "Failed to add match: %m");
1124 log_info("Monitoring bus message stream.");
1127 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1129 r
= sd_bus_process(bus
, &m
);
1131 return log_error_errno(r
, "Failed to process bus: %m");
1137 if (sd_bus_message_is_signal(m
, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1138 log_info("Connection terminated, exiting.");
1148 r
= sd_bus_wait(bus
, (uint64_t) -1);
1150 return log_error_errno(r
, "Failed to wait for bus: %m");
1154 static int capture(sd_bus
*bus
, char *argv
[]) {
1157 if (isatty(fileno(stdout
)) > 0) {
1158 log_error("Refusing to write message data to console, please redirect output to a file.");
1162 bus_pcap_header(arg_snaplen
, stdout
);
1164 r
= monitor(bus
, argv
, message_pcap
);
1168 if (ferror(stdout
)) {
1169 log_error("Couldn't write capture file.");
1176 static int status(sd_bus
*bus
, char *argv
[]) {
1177 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1183 if (strv_length(argv
) > 2) {
1184 log_error("Expects no or one argument.");
1189 r
= parse_pid(argv
[1], &pid
);
1191 r
= sd_bus_get_name_creds(
1194 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1197 r
= sd_bus_creds_new_from_pid(
1202 const char *scope
, *address
;
1205 r
= sd_bus_get_address(bus
, &address
);
1207 printf("BusAddress=%s%s%s\n", ansi_highlight(), address
, ansi_normal());
1209 r
= sd_bus_get_scope(bus
, &scope
);
1211 printf("BusScope=%s%s%s\n", ansi_highlight(), scope
, ansi_normal());
1213 r
= sd_bus_get_bus_id(bus
, &bus_id
);
1215 printf("BusID=%s" SD_ID128_FORMAT_STR
"%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id
), ansi_normal());
1217 r
= sd_bus_get_owner_creds(
1219 (arg_augment_creds
? SD_BUS_CREDS_AUGMENT
: 0) | _SD_BUS_CREDS_ALL
,
1224 return log_error_errno(r
, "Failed to get credentials: %m");
1226 bus_creds_dump(creds
, NULL
, false);
1230 static int message_append_cmdline(sd_bus_message
*m
, const char *signature
, char ***x
) {
1250 log_error("Too few parameters for signature.");
1259 case SD_BUS_TYPE_BOOLEAN
:
1261 r
= parse_boolean(v
);
1263 log_error("Failed to parse as boolean: %s", v
);
1267 r
= sd_bus_message_append_basic(m
, t
, &r
);
1270 case SD_BUS_TYPE_BYTE
: {
1273 r
= safe_atou8(v
, &z
);
1275 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v
);
1279 r
= sd_bus_message_append_basic(m
, t
, &z
);
1283 case SD_BUS_TYPE_INT16
: {
1286 r
= safe_atoi16(v
, &z
);
1288 log_error("Failed to parse as signed 16bit integer: %s", v
);
1292 r
= sd_bus_message_append_basic(m
, t
, &z
);
1296 case SD_BUS_TYPE_UINT16
: {
1299 r
= safe_atou16(v
, &z
);
1301 log_error("Failed to parse as unsigned 16bit integer: %s", v
);
1305 r
= sd_bus_message_append_basic(m
, t
, &z
);
1309 case SD_BUS_TYPE_INT32
: {
1312 r
= safe_atoi32(v
, &z
);
1314 log_error("Failed to parse as signed 32bit integer: %s", v
);
1318 r
= sd_bus_message_append_basic(m
, t
, &z
);
1322 case SD_BUS_TYPE_UINT32
: {
1325 r
= safe_atou32(v
, &z
);
1327 log_error("Failed to parse as unsigned 32bit integer: %s", v
);
1331 r
= sd_bus_message_append_basic(m
, t
, &z
);
1335 case SD_BUS_TYPE_INT64
: {
1338 r
= safe_atoi64(v
, &z
);
1340 log_error("Failed to parse as signed 64bit integer: %s", v
);
1344 r
= sd_bus_message_append_basic(m
, t
, &z
);
1348 case SD_BUS_TYPE_UINT64
: {
1351 r
= safe_atou64(v
, &z
);
1353 log_error("Failed to parse as unsigned 64bit integer: %s", v
);
1357 r
= sd_bus_message_append_basic(m
, t
, &z
);
1362 case SD_BUS_TYPE_DOUBLE
: {
1365 r
= safe_atod(v
, &z
);
1367 log_error("Failed to parse as double precision floating point: %s", v
);
1371 r
= sd_bus_message_append_basic(m
, t
, &z
);
1375 case SD_BUS_TYPE_STRING
:
1376 case SD_BUS_TYPE_OBJECT_PATH
:
1377 case SD_BUS_TYPE_SIGNATURE
:
1379 r
= sd_bus_message_append_basic(m
, t
, v
);
1382 case SD_BUS_TYPE_ARRAY
: {
1386 r
= safe_atou32(v
, &n
);
1388 log_error("Failed to parse number of array entries: %s", v
);
1392 r
= signature_element_length(signature
, &k
);
1394 log_error("Invalid array signature.");
1401 memcpy(s
, signature
, k
);
1404 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_ARRAY
, s
);
1406 return bus_log_create_error(r
);
1408 for (i
= 0; i
< n
; i
++) {
1409 r
= message_append_cmdline(m
, s
, &p
);
1417 r
= sd_bus_message_close_container(m
);
1421 case SD_BUS_TYPE_VARIANT
:
1422 r
= sd_bus_message_open_container(m
, SD_BUS_TYPE_VARIANT
, v
);
1424 return bus_log_create_error(r
);
1426 r
= message_append_cmdline(m
, v
, &p
);
1430 r
= sd_bus_message_close_container(m
);
1433 case SD_BUS_TYPE_STRUCT_BEGIN
:
1434 case SD_BUS_TYPE_DICT_ENTRY_BEGIN
: {
1440 r
= signature_element_length(signature
, &k
);
1442 log_error("Invalid struct/dict entry signature.");
1448 memcpy(s
, signature
+ 1, k
- 2);
1451 r
= sd_bus_message_open_container(m
, t
== SD_BUS_TYPE_STRUCT_BEGIN
? SD_BUS_TYPE_STRUCT
: SD_BUS_TYPE_DICT_ENTRY
, s
);
1453 return bus_log_create_error(r
);
1455 r
= message_append_cmdline(m
, s
, &p
);
1462 r
= sd_bus_message_close_container(m
);
1466 case SD_BUS_TYPE_UNIX_FD
:
1467 log_error("UNIX file descriptor not supported as type.");
1471 log_error("Unknown signature type %c.", t
);
1476 return bus_log_create_error(r
);
1483 static int call(sd_bus
*bus
, char *argv
[]) {
1484 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1485 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1490 if (strv_length(argv
) < 5) {
1491 log_error("Expects at least four arguments.");
1495 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], argv
[3], argv
[4]);
1497 return bus_log_create_error(r
);
1499 r
= sd_bus_message_set_expect_reply(m
, arg_expect_reply
);
1501 return bus_log_create_error(r
);
1503 r
= sd_bus_message_set_auto_start(m
, arg_auto_start
);
1505 return bus_log_create_error(r
);
1507 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_allow_interactive_authorization
);
1509 return bus_log_create_error(r
);
1511 if (!isempty(argv
[5])) {
1516 r
= message_append_cmdline(m
, argv
[5], &p
);
1521 log_error("Too many parameters for signature.");
1526 if (!arg_expect_reply
) {
1527 r
= sd_bus_send(bus
, m
, NULL
);
1529 log_error("Failed to send message.");
1536 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, &reply
);
1538 log_error("%s", bus_error_message(&error
, r
));
1542 r
= sd_bus_message_is_empty(reply
);
1544 return bus_log_parse_error(r
);
1546 if (r
== 0 && !arg_quiet
) {
1549 pager_open_if_enabled();
1551 r
= bus_message_dump(reply
, stdout
, 0);
1556 fputs(sd_bus_message_get_signature(reply
, true), stdout
);
1559 r
= format_cmdline(reply
, stdout
, false);
1561 return bus_log_parse_error(r
);
1563 fputc('\n', stdout
);
1570 static int get_property(sd_bus
*bus
, char *argv
[]) {
1571 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1578 n
= strv_length(argv
);
1580 log_error("Expects at least four arguments.");
1584 STRV_FOREACH(i
, argv
+ 4) {
1585 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
1586 const char *contents
= NULL
;
1589 r
= sd_bus_call_method(bus
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Get", &error
, &reply
, "ss", argv
[3], *i
);
1591 log_error("%s", bus_error_message(&error
, r
));
1595 r
= sd_bus_message_peek_type(reply
, &type
, &contents
);
1597 return bus_log_parse_error(r
);
1599 r
= sd_bus_message_enter_container(reply
, 'v', contents
);
1601 return bus_log_parse_error(r
);
1604 pager_open_if_enabled();
1606 r
= bus_message_dump(reply
, stdout
, BUS_MESSAGE_DUMP_SUBTREE_ONLY
);
1610 fputs(contents
, stdout
);
1613 r
= format_cmdline(reply
, stdout
, false);
1615 return bus_log_parse_error(r
);
1617 fputc('\n', stdout
);
1620 r
= sd_bus_message_exit_container(reply
);
1622 return bus_log_parse_error(r
);
1628 static int set_property(sd_bus
*bus
, char *argv
[]) {
1629 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
1630 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1637 n
= strv_length(argv
);
1639 log_error("Expects at least five arguments.");
1643 r
= sd_bus_message_new_method_call(bus
, &m
, argv
[1], argv
[2], "org.freedesktop.DBus.Properties", "Set");
1645 return bus_log_create_error(r
);
1647 r
= sd_bus_message_append(m
, "ss", argv
[3], argv
[4]);
1649 return bus_log_create_error(r
);
1651 r
= sd_bus_message_open_container(m
, 'v', argv
[5]);
1653 return bus_log_create_error(r
);
1656 r
= message_append_cmdline(m
, argv
[5], &p
);
1660 r
= sd_bus_message_close_container(m
);
1662 return bus_log_create_error(r
);
1665 log_error("Too many parameters for signature.");
1669 r
= sd_bus_call(bus
, m
, arg_timeout
, &error
, NULL
);
1671 log_error("%s", bus_error_message(&error
, r
));
1678 static int help(void) {
1679 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1680 "Introspect the bus.\n\n"
1681 " -h --help Show this help\n"
1682 " --version Show package version\n"
1683 " --no-pager Do not pipe output into a pager\n"
1684 " --no-legend Do not show the headers and footers\n"
1685 " --system Connect to system bus\n"
1686 " --user Connect to user bus\n"
1687 " -H --host=[USER@]HOST Operate on remote host\n"
1688 " -M --machine=CONTAINER Operate on local container\n"
1689 " --address=ADDRESS Connect to bus specified by address\n"
1690 " --show-machine Show machine ID column in list\n"
1691 " --unique Only show unique names\n"
1692 " --acquired Only show acquired names\n"
1693 " --activatable Only show activatable names\n"
1694 " --match=MATCH Only show matching messages\n"
1695 " --size=SIZE Maximum length of captured packet\n"
1696 " --list Don't show tree, but simple object path list\n"
1697 " --quiet Don't show method call reply\n"
1698 " --verbose Show result values in long format\n"
1699 " --expect-reply=BOOL Expect a method call reply\n"
1700 " --auto-start=BOOL Auto-start destination service\n"
1701 " --allow-interactive-authorization=BOOL\n"
1702 " Allow interactive authorization for operation\n"
1703 " --timeout=SECS Maximum time to wait for method call completion\n"
1704 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1706 " list List bus names\n"
1707 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1708 " monitor [SERVICE...] Show bus traffic\n"
1709 " capture [SERVICE...] Capture bus traffic as pcap\n"
1710 " tree [SERVICE...] Show object tree of service\n"
1711 " introspect SERVICE OBJECT [INTERFACE]\n"
1712 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1714 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1715 " Get property value\n"
1716 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1717 " Set property value\n"
1718 " help Show this help\n"
1719 , program_invocation_short_name
);
1724 static int parse_argv(int argc
, char *argv
[]) {
1727 ARG_VERSION
= 0x100,
1743 ARG_ALLOW_INTERACTIVE_AUTHORIZATION
,
1748 static const struct option options
[] = {
1749 { "help", no_argument
, NULL
, 'h' },
1750 { "version", no_argument
, NULL
, ARG_VERSION
},
1751 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1752 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1753 { "system", no_argument
, NULL
, ARG_SYSTEM
},
1754 { "user", no_argument
, NULL
, ARG_USER
},
1755 { "address", required_argument
, NULL
, ARG_ADDRESS
},
1756 { "show-machine", no_argument
, NULL
, ARG_SHOW_MACHINE
},
1757 { "unique", no_argument
, NULL
, ARG_UNIQUE
},
1758 { "acquired", no_argument
, NULL
, ARG_ACQUIRED
},
1759 { "activatable", no_argument
, NULL
, ARG_ACTIVATABLE
},
1760 { "match", required_argument
, NULL
, ARG_MATCH
},
1761 { "host", required_argument
, NULL
, 'H' },
1762 { "machine", required_argument
, NULL
, 'M' },
1763 { "size", required_argument
, NULL
, ARG_SIZE
},
1764 { "list", no_argument
, NULL
, ARG_LIST
},
1765 { "quiet", no_argument
, NULL
, 'q' },
1766 { "verbose", no_argument
, NULL
, ARG_VERBOSE
},
1767 { "expect-reply", required_argument
, NULL
, ARG_EXPECT_REPLY
},
1768 { "auto-start", required_argument
, NULL
, ARG_AUTO_START
},
1769 { "allow-interactive-authorization", required_argument
, NULL
, ARG_ALLOW_INTERACTIVE_AUTHORIZATION
},
1770 { "timeout", required_argument
, NULL
, ARG_TIMEOUT
},
1771 { "augment-creds",required_argument
, NULL
, ARG_AUGMENT_CREDS
},
1780 while ((c
= getopt_long(argc
, argv
, "hH:M:q", options
, NULL
)) >= 0)
1791 arg_no_pager
= true;
1807 arg_address
= optarg
;
1810 case ARG_SHOW_MACHINE
:
1811 arg_show_machine
= true;
1819 arg_acquired
= true;
1822 case ARG_ACTIVATABLE
:
1823 arg_activatable
= true;
1827 if (strv_extend(&arg_matches
, optarg
) < 0)
1834 r
= parse_size(optarg
, 1024, &sz
);
1836 log_error("Failed to parse size: %s", optarg
);
1840 if ((uint64_t) (size_t) sz
!= sz
) {
1841 log_error("Size out of range.");
1845 arg_snaplen
= (size_t) sz
;
1854 arg_transport
= BUS_TRANSPORT_REMOTE
;
1859 arg_transport
= BUS_TRANSPORT_MACHINE
;
1871 case ARG_EXPECT_REPLY
:
1872 r
= parse_boolean(optarg
);
1874 log_error("Failed to parse --expect-reply= parameter.");
1878 arg_expect_reply
= !!r
;
1882 case ARG_AUTO_START
:
1883 r
= parse_boolean(optarg
);
1885 log_error("Failed to parse --auto-start= parameter.");
1889 arg_auto_start
= !!r
;
1893 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION
:
1894 r
= parse_boolean(optarg
);
1896 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1900 arg_allow_interactive_authorization
= !!r
;
1904 r
= parse_sec(optarg
, &arg_timeout
);
1906 log_error("Failed to parse --timeout= parameter.");
1912 case ARG_AUGMENT_CREDS
:
1913 r
= parse_boolean(optarg
);
1915 log_error("Failed to parse --augment-creds= parameter.");
1919 arg_augment_creds
= !!r
;
1926 assert_not_reached("Unhandled option");
1932 static int busctl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
1935 if (optind
>= argc
||
1936 streq(argv
[optind
], "list"))
1937 return list_bus_names(bus
, argv
+ optind
);
1939 if (streq(argv
[optind
], "monitor"))
1940 return monitor(bus
, argv
+ optind
, message_dump
);
1942 if (streq(argv
[optind
], "capture"))
1943 return capture(bus
, argv
+ optind
);
1945 if (streq(argv
[optind
], "status"))
1946 return status(bus
, argv
+ optind
);
1948 if (streq(argv
[optind
], "tree"))
1949 return tree(bus
, argv
+ optind
);
1951 if (streq(argv
[optind
], "introspect"))
1952 return introspect(bus
, argv
+ optind
);
1954 if (streq(argv
[optind
], "call"))
1955 return call(bus
, argv
+ optind
);
1957 if (streq(argv
[optind
], "get-property"))
1958 return get_property(bus
, argv
+ optind
);
1960 if (streq(argv
[optind
], "set-property"))
1961 return set_property(bus
, argv
+ optind
);
1963 if (streq(argv
[optind
], "help"))
1966 log_error("Unknown command '%s'", argv
[optind
]);
1970 int main(int argc
, char *argv
[]) {
1971 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1974 log_parse_environment();
1977 r
= parse_argv(argc
, argv
);
1981 r
= sd_bus_new(&bus
);
1983 log_error_errno(r
, "Failed to allocate bus: %m");
1987 if (streq_ptr(argv
[optind
], "monitor") ||
1988 streq_ptr(argv
[optind
], "capture")) {
1990 r
= sd_bus_set_monitor(bus
, true);
1992 log_error_errno(r
, "Failed to set monitor mode: %m");
1996 r
= sd_bus_negotiate_creds(bus
, true, _SD_BUS_CREDS_ALL
);
1998 log_error_errno(r
, "Failed to enable credentials: %m");
2002 r
= sd_bus_negotiate_timestamp(bus
, true);
2004 log_error_errno(r
, "Failed to enable timestamps: %m");
2008 r
= sd_bus_negotiate_fds(bus
, true);
2010 log_error_errno(r
, "Failed to enable fds: %m");
2015 r
= sd_bus_set_bus_client(bus
, true);
2017 log_error_errno(r
, "Failed to set bus client: %m");
2022 r
= sd_bus_set_address(bus
, arg_address
);
2024 switch (arg_transport
) {
2026 case BUS_TRANSPORT_LOCAL
:
2028 bus
->is_user
= true;
2029 r
= bus_set_address_user(bus
);
2031 bus
->is_system
= true;
2032 r
= bus_set_address_system(bus
);
2036 case BUS_TRANSPORT_REMOTE
:
2037 r
= bus_set_address_system_remote(bus
, arg_host
);
2040 case BUS_TRANSPORT_MACHINE
:
2041 r
= bus_set_address_system_machine(bus
, arg_host
);
2045 assert_not_reached("Hmm, unknown transport type.");
2049 log_error_errno(r
, "Failed to set address: %m");
2053 r
= sd_bus_start(bus
);
2055 log_error_errno(r
, "Failed to connect to bus: %m");
2059 r
= busctl_main(bus
, argc
, argv
);
2064 strv_free(arg_matches
);
2066 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;