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/>.
30 #include "path-util.h"
34 #include "bus-message.h"
35 #include "bus-internal.h"
38 #include "bus-signature.h"
40 #include "busctl-introspect.h"
42 static bool arg_no_pager = false;
43 static bool arg_legend = true;
44 static char *arg_address = NULL;
45 static bool arg_unique = false;
46 static bool arg_acquired = false;
47 static bool arg_activatable = false;
48 static bool arg_show_machine = false;
49 static char **arg_matches = NULL;
50 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
51 static char *arg_host = NULL;
52 static bool arg_user = false;
53 static size_t arg_snaplen = 4096;
54 static bool arg_list = false;
55 static bool arg_quiet = false;
56 static bool arg_verbose = false;
57 static bool arg_expect_reply = true;
58 static bool arg_auto_start = true;
59 static bool arg_allow_interactive_authorization = true;
60 static bool arg_augment_creds = true;
61 static usec_t arg_timeout = 0;
63 static void pager_open_if_enabled(void) {
65 /* Cache result before we open the pager */
72 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
73 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
75 static int list_bus_names(sd_bus *bus, char **argv) {
76 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
77 _cleanup_free_ char **merged = NULL;
78 _cleanup_hashmap_free_ Hashmap *names = NULL;
89 if (!arg_unique && !arg_acquired && !arg_activatable)
90 arg_unique = arg_acquired = arg_activatable = true;
92 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
94 return log_error_errno(r, "Failed to list names: %m");
96 pager_open_if_enabled();
98 names = hashmap_new(&string_hash_ops);
102 STRV_FOREACH(i, acquired) {
103 max_i = MAX(max_i, strlen(*i));
105 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
107 return log_error_errno(r, "Failed to add to hashmap: %m");
110 STRV_FOREACH(i, activatable) {
111 max_i = MAX(max_i, strlen(*i));
113 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
114 if (r < 0 && r != -EEXIST)
115 return log_error_errno(r, "Failed to add to hashmap: %m");
118 merged = new(char*, hashmap_size(names) + 1);
119 HASHMAP_FOREACH_KEY(v, k, names, iterator)
126 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
127 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
129 if (arg_show_machine)
135 STRV_FOREACH(i, merged) {
136 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
139 if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
142 printf("%-*s", (int) max_i, *i);
143 printf(" - - - (activatable) - - ");
144 if (arg_show_machine)
152 if (!arg_unique && (*i)[0] == ':')
155 if (!arg_acquired && (*i)[0] != ':')
158 printf("%-*s", (int) max_i, *i);
160 r = sd_bus_get_name_creds(
162 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
163 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
164 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
165 SD_BUS_CREDS_DESCRIPTION, &creds);
167 const char *unique, *session, *unit, *cn;
171 r = sd_bus_creds_get_pid(creds, &pid);
173 const char *comm = NULL;
175 sd_bus_creds_get_comm(creds, &comm);
177 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
179 fputs(" - - ", stdout);
181 r = sd_bus_creds_get_uid(creds, &uid);
183 _cleanup_free_ char *u = NULL;
185 u = uid_to_name(uid);
194 fputs(" - ", stdout);
196 r = sd_bus_creds_get_unique_name(creds, &unique);
198 printf(" %-13s", unique);
200 fputs(" - ", stdout);
202 r = sd_bus_creds_get_unit(creds, &unit);
204 _cleanup_free_ char *e;
206 e = ellipsize(unit, 25, 100);
212 fputs(" - ", stdout);
214 r = sd_bus_creds_get_session(creds, &session);
216 printf(" %-10s", session);
218 fputs(" - ", stdout);
220 r = sd_bus_creds_get_description(creds, &cn);
222 printf(" %-19s", cn);
224 fputs(" - ", stdout);
227 printf(" - - - - - - - ");
229 if (arg_show_machine) {
230 r = sd_bus_get_name_machine_id(bus, *i, &mid);
232 char m[SD_ID128_STRING_MAX];
233 printf(" %s\n", sd_id128_to_string(mid, m));
243 static void print_subtree(const char *prefix, const char *path, char **l) {
244 const char *vertical, *space;
247 /* We assume the list is sorted. Let's first skip over the
248 * entry we are looking at. */
253 if (!streq(*l, path))
259 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
260 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
263 bool has_more = false;
265 if (!*l || !path_startswith(*l, path))
270 if (!*n || !path_startswith(*n, path))
273 if (!path_startswith(*n, *l)) {
281 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
283 print_subtree(has_more ? vertical : space, *l, l);
288 static void print_tree(const char *prefix, char **l) {
290 pager_open_if_enabled();
292 prefix = strempty(prefix);
298 printf("%s%s\n", prefix, *i);
302 if (strv_isempty(l)) {
303 printf("No objects discovered.\n");
307 if (streq(l[0], "/") && !l[1]) {
308 printf("Only root object discovered.\n");
312 print_subtree(prefix, "/", l);
315 static int on_path(const char *path, void *userdata) {
316 Set *paths = userdata;
321 r = set_put_strdup(paths, path);
328 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
329 static const XMLIntrospectOps ops = {
333 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
334 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
338 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
341 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
343 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
347 r = sd_bus_message_read(reply, "s", &xml);
349 return bus_log_parse_error(r);
351 return parse_xml_introspect(path, xml, &ops, paths);
354 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
355 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
356 _cleanup_free_ char **l = NULL;
360 paths = set_new(&string_hash_ops);
364 done = set_new(&string_hash_ops);
368 failed = set_new(&string_hash_ops);
376 r = set_put(paths, m);
383 _cleanup_free_ char *p = NULL;
386 p = set_steal_first(paths);
390 if (set_contains(done, p) ||
391 set_contains(failed, p))
394 q = find_nodes(bus, service, p, paths, many);
399 q = set_put(failed, p);
401 q = set_put(done, p);
410 pager_open_if_enabled();
412 l = set_get_strv(done);
417 print_tree(prefix, l);
424 static int tree(sd_bus *bus, char **argv) {
428 if (!arg_unique && !arg_acquired)
431 if (strv_length(argv) <= 1) {
432 _cleanup_strv_free_ char **names = NULL;
433 bool not_first = false;
435 r = sd_bus_list_names(bus, &names, NULL);
437 return log_error_errno(r, "Failed to get name list: %m");
439 pager_open_if_enabled();
441 STRV_FOREACH(i, names) {
444 if (!arg_unique && (*i)[0] == ':')
447 if (!arg_acquired && (*i)[0] == ':')
453 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
455 q = tree_one(bus, *i, NULL, true);
462 STRV_FOREACH(i, argv+1) {
469 pager_open_if_enabled();
470 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
473 q = tree_one(bus, *i, NULL, !!argv[2]);
482 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
486 const char *contents = NULL;
501 r = sd_bus_message_peek_type(m, &type, &contents);
505 if (bus_type_is_container(type) > 0) {
507 r = sd_bus_message_enter_container(m, type, contents);
511 if (type == SD_BUS_TYPE_ARRAY) {
514 /* count array entries */
517 r = sd_bus_message_skip(m, contents);
526 r = sd_bus_message_rewind(m, false);
534 } else if (type == SD_BUS_TYPE_VARIANT) {
539 fprintf(f, "%s", contents);
542 r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT));
546 r = sd_bus_message_exit_container(m);
553 r = sd_bus_message_read_basic(m, type, &basic);
561 case SD_BUS_TYPE_BYTE:
562 fprintf(f, "%u", basic.u8);
565 case SD_BUS_TYPE_BOOLEAN:
566 fputs(true_false(basic.i), f);
569 case SD_BUS_TYPE_INT16:
570 fprintf(f, "%i", basic.s16);
573 case SD_BUS_TYPE_UINT16:
574 fprintf(f, "%u", basic.u16);
577 case SD_BUS_TYPE_INT32:
578 fprintf(f, "%i", basic.s32);
581 case SD_BUS_TYPE_UINT32:
582 fprintf(f, "%u", basic.u32);
585 case SD_BUS_TYPE_INT64:
586 fprintf(f, "%" PRIi64, basic.s64);
589 case SD_BUS_TYPE_UINT64:
590 fprintf(f, "%" PRIu64, basic.u64);
593 case SD_BUS_TYPE_DOUBLE:
594 fprintf(f, "%g", basic.d64);
597 case SD_BUS_TYPE_STRING:
598 case SD_BUS_TYPE_OBJECT_PATH:
599 case SD_BUS_TYPE_SIGNATURE: {
600 _cleanup_free_ char *b = NULL;
602 b = cescape(basic.string);
606 fprintf(f, "\"%s\"", b);
610 case SD_BUS_TYPE_UNIX_FD:
611 fprintf(f, "%i", basic.i);
615 assert_not_reached("Unknown basic type.");
622 typedef struct Member {
633 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
640 ul = string_hash_func(m->type, hash_key);
643 ul ^= string_hash_func(m->name, hash_key);
646 ul ^= string_hash_func(m->interface, hash_key);
651 static int member_compare_func(const void *a, const void *b) {
652 const Member *x = a, *y = b;
660 if (!x->interface && y->interface)
662 if (x->interface && !y->interface)
664 if (x->interface && y->interface) {
665 d = strcmp(x->interface, y->interface);
670 d = strcmp(x->type, y->type);
674 if (!x->name && y->name)
676 if (x->name && !y->name)
678 if (x->name && y->name)
679 return strcmp(x->name, y->name);
684 static int member_compare_funcp(const void *a, const void *b) {
685 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
687 return member_compare_func(*x, *y);
690 static void member_free(Member *m) {
702 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
704 static void member_set_free(Set *s) {
707 while ((m = set_steal_first(s)))
713 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
715 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
716 _cleanup_(member_freep) Member *m;
717 Set *members = userdata;
727 m->type = "interface";
730 r = free_and_strdup(&m->interface, interface);
734 r = set_put(members, m);
736 log_error("Duplicate interface");
744 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
745 _cleanup_(member_freep) Member *m;
746 Set *members = userdata;
759 r = free_and_strdup(&m->interface, interface);
763 r = free_and_strdup(&m->name, name);
767 r = free_and_strdup(&m->signature, signature);
771 r = free_and_strdup(&m->result, result);
775 r = set_put(members, m);
777 log_error("Duplicate method");
785 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
786 _cleanup_(member_freep) Member *m;
787 Set *members = userdata;
800 r = free_and_strdup(&m->interface, interface);
804 r = free_and_strdup(&m->name, name);
808 r = free_and_strdup(&m->signature, signature);
812 r = set_put(members, m);
814 log_error("Duplicate signal");
822 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
823 _cleanup_(member_freep) Member *m;
824 Set *members = userdata;
834 m->type = "property";
836 m->writable = writable;
838 r = free_and_strdup(&m->interface, interface);
842 r = free_and_strdup(&m->name, name);
846 r = free_and_strdup(&m->signature, signature);
850 r = set_put(members, m);
852 log_error("Duplicate property");
860 static const char *strdash(const char *x) {
861 return isempty(x) ? "-" : x;
864 static int introspect(sd_bus *bus, char **argv) {
865 static const struct hash_ops member_hash_ops = {
866 .hash = member_hash_func,
867 .compare = member_compare_func,
870 static const XMLIntrospectOps ops = {
871 .on_interface = on_interface,
872 .on_method = on_method,
873 .on_signal = on_signal,
874 .on_property = on_property,
877 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
878 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
879 _cleanup_(member_set_freep) Set *members = NULL;
884 unsigned name_width, type_width, signature_width, result_width;
885 Member **sorted = NULL;
886 unsigned k = 0, j, n_args;
888 n_args = strv_length(argv);
890 log_error("Requires service and object path argument.");
895 log_error("Too many arguments.");
899 members = set_new(&member_hash_ops);
903 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
905 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
909 r = sd_bus_message_read(reply, "s", &xml);
911 return bus_log_parse_error(r);
913 /* First, get list of all properties */
914 r = parse_xml_introspect(argv[2], xml, &ops, members);
918 /* Second, find the current values for them */
919 SET_FOREACH(m, members, i) {
921 if (!streq(m->type, "property"))
927 if (argv[3] && !streq(argv[3], m->interface))
930 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
932 log_error("%s", bus_error_message(&error, r));
936 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
938 return bus_log_parse_error(r);
942 _cleanup_free_ char *buf = NULL;
943 _cleanup_fclose_ FILE *mf = NULL;
947 r = sd_bus_message_enter_container(reply, 'e', "sv");
949 return bus_log_parse_error(r);
954 r = sd_bus_message_read(reply, "s", &name);
956 return bus_log_parse_error(r);
958 r = sd_bus_message_enter_container(reply, 'v', NULL);
960 return bus_log_parse_error(r);
962 mf = open_memstream(&buf, &sz);
966 r = format_cmdline(reply, mf, false);
968 return bus_log_parse_error(r);
973 z = set_get(members, &((Member) {
975 .interface = m->interface,
976 .name = (char*) name }));
983 r = sd_bus_message_exit_container(reply);
985 return bus_log_parse_error(r);
987 r = sd_bus_message_exit_container(reply);
989 return bus_log_parse_error(r);
992 r = sd_bus_message_exit_container(reply);
994 return bus_log_parse_error(r);
997 pager_open_if_enabled();
999 name_width = strlen("NAME");
1000 type_width = strlen("TYPE");
1001 signature_width = strlen("SIGNATURE");
1002 result_width = strlen("RESULT/VALUE");
1004 sorted = newa(Member*, set_size(members));
1006 SET_FOREACH(m, members, i) {
1008 if (argv[3] && !streq(argv[3], m->interface))
1012 name_width = MAX(name_width, strlen(m->interface));
1014 name_width = MAX(name_width, strlen(m->name) + 1);
1016 type_width = MAX(type_width, strlen(m->type));
1018 signature_width = MAX(signature_width, strlen(m->signature));
1020 result_width = MAX(result_width, strlen(m->result));
1022 result_width = MAX(result_width, strlen(m->value));
1027 if (result_width > 40)
1030 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1033 printf("%-*s %-*s %-*s %-*s %s\n",
1034 (int) name_width, "NAME",
1035 (int) type_width, "TYPE",
1036 (int) signature_width, "SIGNATURE",
1037 (int) result_width, "RESULT/VALUE",
1041 for (j = 0; j < k; j++) {
1042 _cleanup_free_ char *ellipsized = NULL;
1048 if (argv[3] && !streq(argv[3], m->interface))
1051 is_interface = streq(m->type, "interface");
1053 if (argv[3] && is_interface)
1057 ellipsized = ellipsize(m->value, result_width, 100);
1063 rv = strdash(m->result);
1065 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1066 is_interface ? ansi_highlight() : "",
1067 is_interface ? "" : ".",
1068 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1069 is_interface ? ansi_highlight_off() : "",
1070 (int) type_width, strdash(m->type),
1071 (int) signature_width, strdash(m->signature),
1072 (int) result_width, rv,
1073 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1074 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1075 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1076 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1077 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1078 m->writable ? " writable" : "");
1084 static int message_dump(sd_bus_message *m, FILE *f) {
1085 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1088 static int message_pcap(sd_bus_message *m, FILE *f) {
1089 return bus_message_pcap_frame(m, arg_snaplen, f);
1092 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1093 bool added_something = false;
1097 STRV_FOREACH(i, argv+1) {
1098 _cleanup_free_ char *m = NULL;
1100 if (!service_name_is_valid(*i)) {
1101 log_error("Invalid service name '%s'", *i);
1105 m = strjoin("sender='", *i, "'", NULL);
1109 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1111 return log_error_errno(r, "Failed to add match: %m");
1113 added_something = true;
1116 STRV_FOREACH(i, arg_matches) {
1117 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1119 return log_error_errno(r, "Failed to add match: %m");
1121 added_something = true;
1124 if (!added_something) {
1125 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1127 return log_error_errno(r, "Failed to add match: %m");
1131 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1133 r = sd_bus_process(bus, &m);
1135 return log_error_errno(r, "Failed to process bus: %m");
1145 r = sd_bus_wait(bus, (uint64_t) -1);
1147 return log_error_errno(r, "Failed to wait for bus: %m");
1151 static int capture(sd_bus *bus, char *argv[]) {
1154 if (isatty(fileno(stdout)) > 0) {
1155 log_error("Refusing to write message data to console, please redirect output to a file.");
1159 bus_pcap_header(arg_snaplen, stdout);
1161 r = monitor(bus, argv, message_pcap);
1165 if (ferror(stdout)) {
1166 log_error("Couldn't write capture file.");
1173 static int status(sd_bus *bus, char *argv[]) {
1174 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1180 if (strv_length(argv) > 2) {
1181 log_error("Expects no or one argument.");
1186 r = parse_pid(argv[1], &pid);
1188 r = sd_bus_get_name_creds(
1191 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1194 r = sd_bus_creds_new_from_pid(
1199 const char *scope, *address;
1202 r = sd_bus_get_address(bus, &address);
1204 printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off());
1206 r = sd_bus_get_scope(bus, &scope);
1208 printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off());
1210 r = sd_bus_get_bus_id(bus, &bus_id);
1212 printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off());
1214 r = sd_bus_get_owner_creds(
1216 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1221 return log_error_errno(r, "Failed to get credentials: %m");
1223 bus_creds_dump(creds, NULL, false);
1227 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1247 log_error("Too few parameters for signature.");
1256 case SD_BUS_TYPE_BOOLEAN:
1258 r = parse_boolean(v);
1260 log_error("Failed to parse as boolean: %s", v);
1264 r = sd_bus_message_append_basic(m, t, &r);
1267 case SD_BUS_TYPE_BYTE: {
1270 r = safe_atou8(v, &z);
1272 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1276 r = sd_bus_message_append_basic(m, t, &z);
1280 case SD_BUS_TYPE_INT16: {
1283 r = safe_atoi16(v, &z);
1285 log_error("Failed to parse as signed 16bit integer: %s", v);
1289 r = sd_bus_message_append_basic(m, t, &z);
1293 case SD_BUS_TYPE_UINT16: {
1296 r = safe_atou16(v, &z);
1298 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1302 r = sd_bus_message_append_basic(m, t, &z);
1306 case SD_BUS_TYPE_INT32: {
1309 r = safe_atoi32(v, &z);
1311 log_error("Failed to parse as signed 32bit integer: %s", v);
1315 r = sd_bus_message_append_basic(m, t, &z);
1319 case SD_BUS_TYPE_UINT32: {
1322 r = safe_atou32(v, &z);
1324 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1328 r = sd_bus_message_append_basic(m, t, &z);
1332 case SD_BUS_TYPE_INT64: {
1335 r = safe_atoi64(v, &z);
1337 log_error("Failed to parse as signed 64bit integer: %s", v);
1341 r = sd_bus_message_append_basic(m, t, &z);
1345 case SD_BUS_TYPE_UINT64: {
1348 r = safe_atou64(v, &z);
1350 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1354 r = sd_bus_message_append_basic(m, t, &z);
1359 case SD_BUS_TYPE_DOUBLE: {
1362 r = safe_atod(v, &z);
1364 log_error("Failed to parse as double precision floating point: %s", v);
1368 r = sd_bus_message_append_basic(m, t, &z);
1372 case SD_BUS_TYPE_STRING:
1373 case SD_BUS_TYPE_OBJECT_PATH:
1374 case SD_BUS_TYPE_SIGNATURE:
1376 r = sd_bus_message_append_basic(m, t, v);
1379 case SD_BUS_TYPE_ARRAY: {
1383 r = safe_atou32(v, &n);
1385 log_error("Failed to parse number of array entries: %s", v);
1389 r = signature_element_length(signature, &k);
1391 log_error("Invalid array signature.");
1398 memcpy(s, signature, k);
1401 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1403 return bus_log_create_error(r);
1405 for (i = 0; i < n; i++) {
1406 r = message_append_cmdline(m, s, &p);
1414 r = sd_bus_message_close_container(m);
1418 case SD_BUS_TYPE_VARIANT:
1419 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1421 return bus_log_create_error(r);
1423 r = message_append_cmdline(m, v, &p);
1427 r = sd_bus_message_close_container(m);
1430 case SD_BUS_TYPE_STRUCT_BEGIN:
1431 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1437 r = signature_element_length(signature, &k);
1439 log_error("Invalid struct/dict entry signature.");
1445 memcpy(s, signature + 1, k - 2);
1448 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1450 return bus_log_create_error(r);
1452 r = message_append_cmdline(m, s, &p);
1459 r = sd_bus_message_close_container(m);
1463 case SD_BUS_TYPE_UNIX_FD:
1464 log_error("UNIX file descriptor not supported as type.");
1468 log_error("Unknown signature type %c.", t);
1473 return bus_log_create_error(r);
1480 static int call(sd_bus *bus, char *argv[]) {
1481 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1482 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1487 if (strv_length(argv) < 5) {
1488 log_error("Expects at least four arguments.");
1492 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1494 return bus_log_create_error(r);
1496 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1498 return bus_log_create_error(r);
1500 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1502 return bus_log_create_error(r);
1504 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1506 return bus_log_create_error(r);
1508 if (!isempty(argv[5])) {
1513 r = message_append_cmdline(m, argv[5], &p);
1518 log_error("Too many parameters for signature.");
1523 if (!arg_expect_reply) {
1524 r = sd_bus_send(bus, m, NULL);
1526 log_error("Failed to send message.");
1533 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1535 log_error("%s", bus_error_message(&error, r));
1539 r = sd_bus_message_is_empty(reply);
1541 return bus_log_parse_error(r);
1543 if (r == 0 && !arg_quiet) {
1546 pager_open_if_enabled();
1548 r = bus_message_dump(reply, stdout, 0);
1553 fputs(sd_bus_message_get_signature(reply, true), stdout);
1556 r = format_cmdline(reply, stdout, false);
1558 return bus_log_parse_error(r);
1560 fputc('\n', stdout);
1567 static int get_property(sd_bus *bus, char *argv[]) {
1568 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1575 n = strv_length(argv);
1577 log_error("Expects at least four arguments.");
1581 STRV_FOREACH(i, argv + 4) {
1582 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1583 const char *contents = NULL;
1586 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1588 log_error("%s", bus_error_message(&error, r));
1592 r = sd_bus_message_peek_type(reply, &type, &contents);
1594 return bus_log_parse_error(r);
1596 r = sd_bus_message_enter_container(reply, 'v', contents);
1598 return bus_log_parse_error(r);
1601 pager_open_if_enabled();
1603 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1607 fputs(contents, stdout);
1610 r = format_cmdline(reply, stdout, false);
1612 return bus_log_parse_error(r);
1614 fputc('\n', stdout);
1617 r = sd_bus_message_exit_container(reply);
1619 return bus_log_parse_error(r);
1625 static int set_property(sd_bus *bus, char *argv[]) {
1626 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1627 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1634 n = strv_length(argv);
1636 log_error("Expects at least five arguments.");
1640 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1642 return bus_log_create_error(r);
1644 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1646 return bus_log_create_error(r);
1648 r = sd_bus_message_open_container(m, 'v', argv[5]);
1650 return bus_log_create_error(r);
1653 r = message_append_cmdline(m, argv[5], &p);
1657 r = sd_bus_message_close_container(m);
1659 return bus_log_create_error(r);
1662 log_error("Too many parameters for signature.");
1666 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1668 log_error("%s", bus_error_message(&error, r));
1675 static int help(void) {
1676 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1677 "Introspect the bus.\n\n"
1678 " -h --help Show this help\n"
1679 " --version Show package version\n"
1680 " --no-pager Do not pipe output into a pager\n"
1681 " --no-legend Do not show the headers and footers\n"
1682 " --system Connect to system bus\n"
1683 " --user Connect to user bus\n"
1684 " -H --host=[USER@]HOST Operate on remote host\n"
1685 " -M --machine=CONTAINER Operate on local container\n"
1686 " --address=ADDRESS Connect to bus specified by address\n"
1687 " --show-machine Show machine ID column in list\n"
1688 " --unique Only show unique names\n"
1689 " --acquired Only show acquired names\n"
1690 " --activatable Only show activatable names\n"
1691 " --match=MATCH Only show matching messages\n"
1692 " --list Don't show tree, but simple object path list\n"
1693 " --quiet Don't show method call reply\n"
1694 " --verbose Show result values in long format\n"
1695 " --expect-reply=BOOL Expect a method call reply\n"
1696 " --auto-start=BOOL Auto-start destination service\n"
1697 " --allow-interactive-authorization=BOOL\n"
1698 " Allow interactive authorization for operation\n"
1699 " --timeout=SECS Maximum time to wait for method call completion\n"
1700 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1702 " list List bus names\n"
1703 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1704 " monitor [SERVICE...] Show bus traffic\n"
1705 " capture [SERVICE...] Capture bus traffic as pcap\n"
1706 " tree [SERVICE...] Show object tree of service\n"
1707 " introspect SERVICE OBJECT [INTERFACE]\n"
1708 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1710 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1711 " Get property value\n"
1712 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1713 " Set property value\n"
1714 " help Show this help\n"
1715 , program_invocation_short_name);
1720 static int parse_argv(int argc, char *argv[]) {
1723 ARG_VERSION = 0x100,
1739 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1744 static const struct option options[] = {
1745 { "help", no_argument, NULL, 'h' },
1746 { "version", no_argument, NULL, ARG_VERSION },
1747 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1748 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1749 { "system", no_argument, NULL, ARG_SYSTEM },
1750 { "user", no_argument, NULL, ARG_USER },
1751 { "address", required_argument, NULL, ARG_ADDRESS },
1752 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1753 { "unique", no_argument, NULL, ARG_UNIQUE },
1754 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1755 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1756 { "match", required_argument, NULL, ARG_MATCH },
1757 { "host", required_argument, NULL, 'H' },
1758 { "machine", required_argument, NULL, 'M' },
1759 { "size", required_argument, NULL, ARG_SIZE },
1760 { "list", no_argument, NULL, ARG_LIST },
1761 { "quiet", no_argument, NULL, 'q' },
1762 { "verbose", no_argument, NULL, ARG_VERBOSE },
1763 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1764 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1765 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1766 { "timeout", required_argument, NULL, ARG_TIMEOUT },
1767 { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
1776 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1784 puts(PACKAGE_STRING);
1785 puts(SYSTEMD_FEATURES);
1789 arg_no_pager = true;
1805 arg_address = optarg;
1808 case ARG_SHOW_MACHINE:
1809 arg_show_machine = true;
1817 arg_acquired = true;
1820 case ARG_ACTIVATABLE:
1821 arg_activatable = true;
1825 if (strv_extend(&arg_matches, optarg) < 0)
1832 r = parse_size(optarg, 0, &o);
1834 log_error("Failed to parse size: %s", optarg);
1838 if ((off_t) (size_t) o != o) {
1839 log_error("Size out of range.");
1843 arg_snaplen = (size_t) o;
1852 arg_transport = BUS_TRANSPORT_REMOTE;
1857 arg_transport = BUS_TRANSPORT_MACHINE;
1869 case ARG_EXPECT_REPLY:
1870 r = parse_boolean(optarg);
1872 log_error("Failed to parse --expect-reply= parameter.");
1876 arg_expect_reply = !!r;
1880 case ARG_AUTO_START:
1881 r = parse_boolean(optarg);
1883 log_error("Failed to parse --auto-start= parameter.");
1887 arg_auto_start = !!r;
1891 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1892 r = parse_boolean(optarg);
1894 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1898 arg_allow_interactive_authorization = !!r;
1902 r = parse_sec(optarg, &arg_timeout);
1904 log_error("Failed to parse --timeout= parameter.");
1910 case ARG_AUGMENT_CREDS:
1911 r = parse_boolean(optarg);
1913 log_error("Failed to parse --augment-creds= parameter.");
1917 arg_augment_creds = !!r;
1924 assert_not_reached("Unhandled option");
1930 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1933 if (optind >= argc ||
1934 streq(argv[optind], "list"))
1935 return list_bus_names(bus, argv + optind);
1937 if (streq(argv[optind], "monitor"))
1938 return monitor(bus, argv + optind, message_dump);
1940 if (streq(argv[optind], "capture"))
1941 return capture(bus, argv + optind);
1943 if (streq(argv[optind], "status"))
1944 return status(bus, argv + optind);
1946 if (streq(argv[optind], "tree"))
1947 return tree(bus, argv + optind);
1949 if (streq(argv[optind], "introspect"))
1950 return introspect(bus, argv + optind);
1952 if (streq(argv[optind], "call"))
1953 return call(bus, argv + optind);
1955 if (streq(argv[optind], "get-property"))
1956 return get_property(bus, argv + optind);
1958 if (streq(argv[optind], "set-property"))
1959 return set_property(bus, argv + optind);
1961 if (streq(argv[optind], "help"))
1964 log_error("Unknown command '%s'", argv[optind]);
1968 int main(int argc, char *argv[]) {
1969 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1972 log_parse_environment();
1975 r = parse_argv(argc, argv);
1979 r = sd_bus_new(&bus);
1981 log_error_errno(r, "Failed to allocate bus: %m");
1985 if (streq_ptr(argv[optind], "monitor") ||
1986 streq_ptr(argv[optind], "capture")) {
1988 r = sd_bus_set_monitor(bus, true);
1990 log_error_errno(r, "Failed to set monitor mode: %m");
1994 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
1996 log_error_errno(r, "Failed to enable credentials: %m");
2000 r = sd_bus_negotiate_timestamp(bus, true);
2002 log_error_errno(r, "Failed to enable timestamps: %m");
2006 r = sd_bus_negotiate_fds(bus, true);
2008 log_error_errno(r, "Failed to enable fds: %m");
2014 r = sd_bus_set_address(bus, arg_address);
2016 r = sd_bus_set_bus_client(bus, true);
2018 log_error_errno(r, "Failed to set bus client: %m");
2022 switch (arg_transport) {
2024 case BUS_TRANSPORT_LOCAL:
2026 bus->is_user = true;
2027 r = bus_set_address_user(bus);
2029 bus->is_system = true;
2030 r = bus_set_address_system(bus);
2034 case BUS_TRANSPORT_REMOTE:
2035 r = bus_set_address_system_remote(bus, arg_host);
2038 case BUS_TRANSPORT_MACHINE:
2039 r = bus_set_address_system_machine(bus, arg_host);
2043 assert_not_reached("Hmm, unknown transport type.");
2047 log_error_errno(r, "Failed to set address: %m");
2051 r = sd_bus_start(bus);
2053 log_error_errno(r, "Failed to connect to bus: %m");
2057 r = busctl_main(bus, argc, argv);
2062 strv_free(arg_matches);
2064 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;