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"
33 #include "bus-message.h"
34 #include "bus-internal.h"
37 #include "bus-signature.h"
39 #include "busctl-introspect.h"
41 static bool arg_no_pager = false;
42 static bool arg_legend = true;
43 static char *arg_address = NULL;
44 static bool arg_unique = false;
45 static bool arg_acquired = false;
46 static bool arg_activatable = false;
47 static bool arg_show_machine = false;
48 static char **arg_matches = NULL;
49 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
50 static char *arg_host = NULL;
51 static bool arg_user = false;
52 static size_t arg_snaplen = 4096;
53 static bool arg_list = false;
54 static bool arg_quiet = false;
55 static bool arg_verbose = false;
56 static bool arg_expect_reply = true;
57 static bool arg_auto_start = true;
58 static bool arg_allow_interactive_authorization = true;
59 static bool arg_augment_creds = true;
60 static usec_t arg_timeout = 0;
62 static void pager_open_if_enabled(void) {
64 /* Cache result before we open the pager */
71 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
72 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
74 static int list_bus_names(sd_bus *bus, char **argv) {
75 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
76 _cleanup_free_ char **merged = NULL;
77 _cleanup_hashmap_free_ Hashmap *names = NULL;
88 if (!arg_unique && !arg_acquired && !arg_activatable)
89 arg_unique = arg_acquired = arg_activatable = true;
91 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
93 log_error("Failed to list names: %s", strerror(-r));
97 pager_open_if_enabled();
99 names = hashmap_new(&string_hash_ops);
103 STRV_FOREACH(i, acquired) {
104 max_i = MAX(max_i, strlen(*i));
106 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
108 log_error("Failed to add to hashmap: %s", strerror(-r));
113 STRV_FOREACH(i, activatable) {
114 max_i = MAX(max_i, strlen(*i));
116 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
117 if (r < 0 && r != -EEXIST) {
118 log_error("Failed to add to hashmap: %s", strerror(-r));
123 merged = new(char*, hashmap_size(names) + 1);
124 HASHMAP_FOREACH_KEY(v, k, names, iterator)
131 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
132 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
134 if (arg_show_machine)
140 STRV_FOREACH(i, merged) {
141 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
144 if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
147 printf("%-*s", (int) max_i, *i);
148 printf(" - - - (activatable) - - ");
149 if (arg_show_machine)
157 if (!arg_unique && (*i)[0] == ':')
160 if (!arg_acquired && (*i)[0] != ':')
163 printf("%-*s", (int) max_i, *i);
165 r = sd_bus_get_name_creds(
167 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
168 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
169 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
170 SD_BUS_CREDS_DESCRIPTION, &creds);
172 const char *unique, *session, *unit, *cn;
176 r = sd_bus_creds_get_pid(creds, &pid);
178 const char *comm = NULL;
180 sd_bus_creds_get_comm(creds, &comm);
182 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
184 fputs(" - - ", stdout);
186 r = sd_bus_creds_get_uid(creds, &uid);
188 _cleanup_free_ char *u = NULL;
190 u = uid_to_name(uid);
199 fputs(" - ", stdout);
201 r = sd_bus_creds_get_unique_name(creds, &unique);
203 printf(" %-13s", unique);
205 fputs(" - ", stdout);
207 r = sd_bus_creds_get_unit(creds, &unit);
209 _cleanup_free_ char *e;
211 e = ellipsize(unit, 25, 100);
217 fputs(" - ", stdout);
219 r = sd_bus_creds_get_session(creds, &session);
221 printf(" %-10s", session);
223 fputs(" - ", stdout);
225 r = sd_bus_creds_get_description(creds, &cn);
227 printf(" %-19s", cn);
229 fputs(" - ", stdout);
232 printf(" - - - - - - - ");
234 if (arg_show_machine) {
235 r = sd_bus_get_name_machine_id(bus, *i, &mid);
237 char m[SD_ID128_STRING_MAX];
238 printf(" %s\n", sd_id128_to_string(mid, m));
248 static void print_subtree(const char *prefix, const char *path, char **l) {
249 const char *vertical, *space;
252 /* We assume the list is sorted. Let's first skip over the
253 * entry we are looking at. */
258 if (!streq(*l, path))
264 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
265 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
268 bool has_more = false;
270 if (!*l || !path_startswith(*l, path))
275 if (!*n || !path_startswith(*n, path))
278 if (!path_startswith(*n, *l)) {
286 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
288 print_subtree(has_more ? vertical : space, *l, l);
293 static void print_tree(const char *prefix, char **l) {
295 pager_open_if_enabled();
297 prefix = strempty(prefix);
303 printf("%s%s\n", prefix, *i);
307 if (strv_isempty(l)) {
308 printf("No objects discovered.\n");
312 if (streq(l[0], "/") && !l[1]) {
313 printf("Only root object discovered.\n");
317 print_subtree(prefix, "/", l);
320 static int on_path(const char *path, void *userdata) {
321 Set *paths = userdata;
326 r = set_put_strdup(paths, path);
333 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
334 static const XMLIntrospectOps ops = {
338 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
339 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
343 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
346 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
348 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
352 r = sd_bus_message_read(reply, "s", &xml);
354 return bus_log_parse_error(r);
356 return parse_xml_introspect(path, xml, &ops, paths);
359 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
360 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
361 _cleanup_free_ char **l = NULL;
365 paths = set_new(&string_hash_ops);
369 done = set_new(&string_hash_ops);
373 failed = set_new(&string_hash_ops);
381 r = set_put(paths, m);
388 _cleanup_free_ char *p = NULL;
391 p = set_steal_first(paths);
395 if (set_contains(done, p) ||
396 set_contains(failed, p))
399 q = find_nodes(bus, service, p, paths, many);
404 q = set_put(failed, p);
406 q = set_put(done, p);
415 pager_open_if_enabled();
417 l = set_get_strv(done);
422 print_tree(prefix, l);
429 static int tree(sd_bus *bus, char **argv) {
433 if (!arg_unique && !arg_acquired)
436 if (strv_length(argv) <= 1) {
437 _cleanup_strv_free_ char **names = NULL;
438 bool not_first = false;
440 r = sd_bus_list_names(bus, &names, NULL);
442 log_error("Failed to get name list: %s", strerror(-r));
446 pager_open_if_enabled();
448 STRV_FOREACH(i, names) {
451 if (!arg_unique && (*i)[0] == ':')
454 if (!arg_acquired && (*i)[0] == ':')
460 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
462 q = tree_one(bus, *i, NULL, true);
469 STRV_FOREACH(i, argv+1) {
476 pager_open_if_enabled();
477 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
480 q = tree_one(bus, *i, NULL, !!argv[2]);
489 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
493 const char *contents = NULL;
508 r = sd_bus_message_peek_type(m, &type, &contents);
512 if (bus_type_is_container(type) > 0) {
514 r = sd_bus_message_enter_container(m, type, contents);
518 if (type == SD_BUS_TYPE_ARRAY) {
521 /* count array entries */
524 r = sd_bus_message_skip(m, contents);
533 r = sd_bus_message_rewind(m, false);
541 } else if (type == SD_BUS_TYPE_VARIANT) {
546 fprintf(f, "%s", contents);
549 r = format_cmdline(m, f, true);
553 r = sd_bus_message_exit_container(m);
560 r = sd_bus_message_read_basic(m, type, &basic);
568 case SD_BUS_TYPE_BYTE:
569 fprintf(f, "%u", basic.u8);
572 case SD_BUS_TYPE_BOOLEAN:
573 fputs(true_false(basic.i), f);
576 case SD_BUS_TYPE_INT16:
577 fprintf(f, "%i", basic.s16);
580 case SD_BUS_TYPE_UINT16:
581 fprintf(f, "%u", basic.u16);
584 case SD_BUS_TYPE_INT32:
585 fprintf(f, "%i", basic.s32);
588 case SD_BUS_TYPE_UINT32:
589 fprintf(f, "%u", basic.u32);
592 case SD_BUS_TYPE_INT64:
593 fprintf(f, "%" PRIi64, basic.s64);
596 case SD_BUS_TYPE_UINT64:
597 fprintf(f, "%" PRIu64, basic.u64);
600 case SD_BUS_TYPE_DOUBLE:
601 fprintf(f, "%g", basic.d64);
604 case SD_BUS_TYPE_STRING:
605 case SD_BUS_TYPE_OBJECT_PATH:
606 case SD_BUS_TYPE_SIGNATURE: {
607 _cleanup_free_ char *b = NULL;
609 b = cescape(basic.string);
613 fprintf(f, "\"%s\"", b);
617 case SD_BUS_TYPE_UNIX_FD:
618 fprintf(f, "%i", basic.i);
622 assert_not_reached("Unknown basic type.");
628 typedef struct Member {
639 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
646 ul = string_hash_func(m->type, hash_key);
649 ul ^= string_hash_func(m->name, hash_key);
652 ul ^= string_hash_func(m->interface, hash_key);
657 static int member_compare_func(const void *a, const void *b) {
658 const Member *x = a, *y = b;
666 if (!x->interface && y->interface)
668 if (x->interface && !y->interface)
670 if (x->interface && y->interface) {
671 d = strcmp(x->interface, y->interface);
676 d = strcmp(x->type, y->type);
680 if (!x->name && y->name)
682 if (x->name && !y->name)
684 if (x->name && y->name)
685 return strcmp(x->name, y->name);
690 static int member_compare_funcp(const void *a, const void *b) {
691 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
693 return member_compare_func(*x, *y);
696 static void member_free(Member *m) {
708 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
710 static void member_set_free(Set *s) {
713 while ((m = set_steal_first(s)))
719 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
721 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
722 _cleanup_(member_freep) Member *m;
723 Set *members = userdata;
733 m->type = "interface";
736 r = free_and_strdup(&m->interface, interface);
740 r = set_put(members, m);
742 log_error("Duplicate interface");
750 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
751 _cleanup_(member_freep) Member *m;
752 Set *members = userdata;
765 r = free_and_strdup(&m->interface, interface);
769 r = free_and_strdup(&m->name, name);
773 r = free_and_strdup(&m->signature, signature);
777 r = free_and_strdup(&m->result, result);
781 r = set_put(members, m);
783 log_error("Duplicate method");
791 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
792 _cleanup_(member_freep) Member *m;
793 Set *members = userdata;
806 r = free_and_strdup(&m->interface, interface);
810 r = free_and_strdup(&m->name, name);
814 r = free_and_strdup(&m->signature, signature);
818 r = set_put(members, m);
820 log_error("Duplicate signal");
828 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
829 _cleanup_(member_freep) Member *m;
830 Set *members = userdata;
840 m->type = "property";
842 m->writable = writable;
844 r = free_and_strdup(&m->interface, interface);
848 r = free_and_strdup(&m->name, name);
852 r = free_and_strdup(&m->signature, signature);
856 r = set_put(members, m);
858 log_error("Duplicate property");
866 static const char *strdash(const char *x) {
867 return isempty(x) ? "-" : x;
870 static int introspect(sd_bus *bus, char **argv) {
871 static const struct hash_ops member_hash_ops = {
872 .hash = member_hash_func,
873 .compare = member_compare_func,
876 static const XMLIntrospectOps ops = {
877 .on_interface = on_interface,
878 .on_method = on_method,
879 .on_signal = on_signal,
880 .on_property = on_property,
883 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
884 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
885 _cleanup_(member_set_freep) Set *members = NULL;
890 unsigned name_width, type_width, signature_width, result_width;
891 Member **sorted = NULL;
894 if (strv_length(argv) != 3) {
895 log_error("Requires service and object path argument.");
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 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
929 log_error("%s", bus_error_message(&error, r));
933 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
935 return bus_log_parse_error(r);
939 _cleanup_free_ char *buf = NULL;
940 _cleanup_fclose_ FILE *mf = NULL;
944 r = sd_bus_message_enter_container(reply, 'e', "sv");
946 return bus_log_parse_error(r);
951 r = sd_bus_message_read(reply, "s", &name);
953 return bus_log_parse_error(r);
955 r = sd_bus_message_enter_container(reply, 'v', NULL);
957 return bus_log_parse_error(r);
959 mf = open_memstream(&buf, &sz);
963 r = format_cmdline(reply, mf, false);
965 return bus_log_parse_error(r);
970 z = set_get(members, &((Member) {
972 .interface = m->interface,
973 .name = (char*) name }));
980 r = sd_bus_message_exit_container(reply);
982 return bus_log_parse_error(r);
984 r = sd_bus_message_exit_container(reply);
986 return bus_log_parse_error(r);
989 r = sd_bus_message_exit_container(reply);
991 return bus_log_parse_error(r);
994 pager_open_if_enabled();
996 name_width = strlen("NAME");
997 type_width = strlen("TYPE");
998 signature_width = strlen("SIGNATURE");
999 result_width = strlen("RESULT/VALUE");
1001 sorted = newa(Member*, set_size(members));
1003 SET_FOREACH(m, members, i) {
1005 name_width = MAX(name_width, strlen(m->interface));
1007 name_width = MAX(name_width, strlen(m->name) + 1);
1009 type_width = MAX(type_width, strlen(m->type));
1011 signature_width = MAX(signature_width, strlen(m->signature));
1013 result_width = MAX(result_width, strlen(m->result));
1015 result_width = MAX(result_width, strlen(m->value));
1020 if (result_width > 40)
1023 assert(k == set_size(members));
1024 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1027 printf("%-*s %-*s %-*s %-*s %s\n",
1028 (int) name_width, "NAME",
1029 (int) type_width, "TYPE",
1030 (int) signature_width, "SIGNATURE",
1031 (int) result_width, "RESULT/VALUE",
1035 for (j = 0; j < k; j++) {
1036 _cleanup_free_ char *ellipsized = NULL;
1042 is_interface = streq(m->type, "interface");
1045 ellipsized = ellipsize(m->value, result_width, 100);
1051 rv = strdash(m->result);
1053 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1054 is_interface ? ansi_highlight() : "",
1055 is_interface ? "" : ".",
1056 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1057 is_interface ? ansi_highlight_off() : "",
1058 (int) type_width, strdash(m->type),
1059 (int) signature_width, strdash(m->signature),
1060 (int) result_width, rv,
1061 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1062 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1063 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1064 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1065 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1066 m->writable ? " writable" : "");
1072 static int message_dump(sd_bus_message *m, FILE *f) {
1073 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1076 static int message_pcap(sd_bus_message *m, FILE *f) {
1077 return bus_message_pcap_frame(m, arg_snaplen, f);
1080 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1081 bool added_something = false;
1085 STRV_FOREACH(i, argv+1) {
1086 _cleanup_free_ char *m = NULL;
1088 if (!service_name_is_valid(*i)) {
1089 log_error("Invalid service name '%s'", *i);
1093 m = strjoin("sender='", *i, "'", NULL);
1097 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1099 log_error("Failed to add match: %s", strerror(-r));
1103 added_something = true;
1106 STRV_FOREACH(i, arg_matches) {
1107 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1109 log_error("Failed to add match: %s", strerror(-r));
1113 added_something = true;
1116 if (!added_something) {
1117 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1119 log_error("Failed to add match: %s", strerror(-r));
1125 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1127 r = sd_bus_process(bus, &m);
1129 log_error("Failed to process bus: %s", strerror(-r));
1141 r = sd_bus_wait(bus, (uint64_t) -1);
1143 log_error("Failed to wait for bus: %s", strerror(-r));
1149 static int capture(sd_bus *bus, char *argv[]) {
1152 if (isatty(fileno(stdout)) > 0) {
1153 log_error("Refusing to write message data to console, please redirect output to a file.");
1157 bus_pcap_header(arg_snaplen, stdout);
1159 r = monitor(bus, argv, message_pcap);
1163 if (ferror(stdout)) {
1164 log_error("Couldn't write capture file.");
1171 static int status(sd_bus *bus, char *argv[]) {
1172 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1178 if (strv_length(argv) > 2) {
1179 log_error("Expects no or one argument.");
1184 r = parse_pid(argv[1], &pid);
1186 r = sd_bus_get_name_creds(
1189 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1192 r = sd_bus_creds_new_from_pid(
1197 r = sd_bus_get_owner_creds(
1199 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1203 log_error("Failed to get credentials: %s", strerror(-r));
1207 bus_creds_dump(creds, NULL, false);
1211 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1231 log_error("Too few parameters for signature.");
1240 case SD_BUS_TYPE_BOOLEAN:
1242 r = parse_boolean(v);
1244 log_error("Failed to parse as boolean: %s", v);
1248 r = sd_bus_message_append_basic(m, t, &r);
1251 case SD_BUS_TYPE_BYTE: {
1254 r = safe_atou8(v, &z);
1256 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1260 r = sd_bus_message_append_basic(m, t, &z);
1264 case SD_BUS_TYPE_INT16: {
1267 r = safe_atoi16(v, &z);
1269 log_error("Failed to parse as signed 16bit integer: %s", v);
1273 r = sd_bus_message_append_basic(m, t, &z);
1277 case SD_BUS_TYPE_UINT16: {
1280 r = safe_atou16(v, &z);
1282 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1286 r = sd_bus_message_append_basic(m, t, &z);
1290 case SD_BUS_TYPE_INT32: {
1293 r = safe_atoi32(v, &z);
1295 log_error("Failed to parse as signed 32bit integer: %s", v);
1299 r = sd_bus_message_append_basic(m, t, &z);
1303 case SD_BUS_TYPE_UINT32: {
1306 r = safe_atou32(v, &z);
1308 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1312 r = sd_bus_message_append_basic(m, t, &z);
1316 case SD_BUS_TYPE_INT64: {
1319 r = safe_atoi64(v, &z);
1321 log_error("Failed to parse as signed 64bit integer: %s", v);
1325 r = sd_bus_message_append_basic(m, t, &z);
1329 case SD_BUS_TYPE_UINT64: {
1332 r = safe_atou64(v, &z);
1334 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1338 r = sd_bus_message_append_basic(m, t, &z);
1343 case SD_BUS_TYPE_DOUBLE: {
1346 r = safe_atod(v, &z);
1348 log_error("Failed to parse as double precision floating point: %s", v);
1352 r = sd_bus_message_append_basic(m, t, &z);
1356 case SD_BUS_TYPE_STRING:
1357 case SD_BUS_TYPE_OBJECT_PATH:
1358 case SD_BUS_TYPE_SIGNATURE:
1360 r = sd_bus_message_append_basic(m, t, v);
1363 case SD_BUS_TYPE_ARRAY: {
1367 r = safe_atou32(v, &n);
1369 log_error("Failed to parse number of array entries: %s", v);
1373 r = signature_element_length(signature, &k);
1375 log_error("Invalid array signature.");
1382 memcpy(s, signature, k);
1385 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1387 return bus_log_create_error(r);
1389 for (i = 0; i < n; i++) {
1390 r = message_append_cmdline(m, s, &p);
1398 r = sd_bus_message_close_container(m);
1402 case SD_BUS_TYPE_VARIANT:
1403 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1405 return bus_log_create_error(r);
1407 r = message_append_cmdline(m, v, &p);
1411 r = sd_bus_message_close_container(m);
1414 case SD_BUS_TYPE_STRUCT_BEGIN:
1415 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1421 r = signature_element_length(signature, &k);
1423 log_error("Invalid struct/dict entry signature.");
1429 memcpy(s, signature + 1, k - 2);
1432 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1434 return bus_log_create_error(r);
1436 r = message_append_cmdline(m, s, &p);
1443 r = sd_bus_message_close_container(m);
1447 case SD_BUS_TYPE_UNIX_FD:
1448 log_error("UNIX file descriptor not supported as type.");
1452 log_error("Unknown signature type %c.", t);
1457 return bus_log_create_error(r);
1464 static int call(sd_bus *bus, char *argv[]) {
1465 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1466 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1471 if (strv_length(argv) < 5) {
1472 log_error("Expects at least four arguments.");
1476 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1478 return bus_log_create_error(r);
1480 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1482 return bus_log_create_error(r);
1484 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1486 return bus_log_create_error(r);
1488 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1490 return bus_log_create_error(r);
1492 if (!isempty(argv[5])) {
1497 r = message_append_cmdline(m, argv[5], &p);
1502 log_error("Too many parameters for signature.");
1507 if (!arg_expect_reply) {
1508 r = sd_bus_send(bus, m, NULL);
1510 log_error("Failed to send message.");
1517 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1519 log_error("%s", bus_error_message(&error, r));
1523 r = sd_bus_message_is_empty(reply);
1525 return bus_log_parse_error(r);
1527 if (r == 0 && !arg_quiet) {
1530 pager_open_if_enabled();
1532 r = bus_message_dump(reply, stdout, 0);
1537 fputs(sd_bus_message_get_signature(reply, true), stdout);
1540 r = format_cmdline(reply, stdout, false);
1542 return bus_log_parse_error(r);
1544 fputc('\n', stdout);
1551 static int get_property(sd_bus *bus, char *argv[]) {
1552 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1559 n = strv_length(argv);
1561 log_error("Expects at least four arguments.");
1565 STRV_FOREACH(i, argv + 4) {
1566 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1567 const char *contents = NULL;
1570 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1572 log_error("%s", bus_error_message(&error, r));
1576 r = sd_bus_message_peek_type(reply, &type, &contents);
1578 return bus_log_parse_error(r);
1580 r = sd_bus_message_enter_container(reply, 'v', contents);
1582 return bus_log_parse_error(r);
1585 pager_open_if_enabled();
1587 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1591 fputs(contents, stdout);
1594 r = format_cmdline(reply, stdout, false);
1596 return bus_log_parse_error(r);
1598 fputc('\n', stdout);
1601 r = sd_bus_message_exit_container(reply);
1603 return bus_log_parse_error(r);
1609 static int set_property(sd_bus *bus, char *argv[]) {
1610 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1611 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1618 n = strv_length(argv);
1620 log_error("Expects at least five arguments.");
1624 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1626 return bus_log_create_error(r);
1628 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1630 return bus_log_create_error(r);
1632 r = sd_bus_message_open_container(m, 'v', argv[5]);
1634 return bus_log_create_error(r);
1637 r = message_append_cmdline(m, argv[5], &p);
1641 r = sd_bus_message_close_container(m);
1643 return bus_log_create_error(r);
1646 log_error("Too many parameters for signature.");
1650 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1652 log_error("%s", bus_error_message(&error, r));
1659 static int help(void) {
1660 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1661 "Introspect the bus.\n\n"
1662 " -h --help Show this help\n"
1663 " --version Show package version\n"
1664 " --no-pager Do not pipe output into a pager\n"
1665 " --no-legend Do not show the headers and footers\n"
1666 " --system Connect to system bus\n"
1667 " --user Connect to user bus\n"
1668 " -H --host=[USER@]HOST Operate on remote host\n"
1669 " -M --machine=CONTAINER Operate on local container\n"
1670 " --address=ADDRESS Connect to bus specified by address\n"
1671 " --show-machine Show machine ID column in list\n"
1672 " --unique Only show unique names\n"
1673 " --acquired Only show acquired names\n"
1674 " --activatable Only show activatable names\n"
1675 " --match=MATCH Only show matching messages\n"
1676 " --list Don't show tree, but simple object path list\n"
1677 " --quiet Don't show method call reply\n"
1678 " --verbose Show result values in long format\n"
1679 " --expect-reply=BOOL Expect a method call reply\n"
1680 " --auto-start=BOOL Auto-start destination service\n"
1681 " --allow-interactive-authorization=BOOL\n"
1682 " Allow interactive authorization for operation\n"
1683 " --timeout=SECS Maximum time to wait for method call completion\n"
1684 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1686 " list List bus names\n"
1687 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1688 " monitor [SERVICE...] Show bus traffic\n"
1689 " capture [SERVICE...] Capture bus traffic as pcap\n"
1690 " tree [SERVICE...] Show object tree of service\n"
1691 " introspect SERVICE OBJECT\n"
1692 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1694 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1695 " Get property value\n"
1696 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1697 " Set property value\n"
1698 " help Show this help\n"
1699 , program_invocation_short_name);
1704 static int parse_argv(int argc, char *argv[]) {
1707 ARG_VERSION = 0x100,
1723 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1728 static const struct option options[] = {
1729 { "help", no_argument, NULL, 'h' },
1730 { "version", no_argument, NULL, ARG_VERSION },
1731 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1732 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1733 { "system", no_argument, NULL, ARG_SYSTEM },
1734 { "user", no_argument, NULL, ARG_USER },
1735 { "address", required_argument, NULL, ARG_ADDRESS },
1736 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1737 { "unique", no_argument, NULL, ARG_UNIQUE },
1738 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1739 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1740 { "match", required_argument, NULL, ARG_MATCH },
1741 { "host", required_argument, NULL, 'H' },
1742 { "machine", required_argument, NULL, 'M' },
1743 { "size", required_argument, NULL, ARG_SIZE },
1744 { "list", no_argument, NULL, ARG_LIST },
1745 { "quiet", no_argument, NULL, 'q' },
1746 { "verbose", no_argument, NULL, ARG_VERBOSE },
1747 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1748 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1749 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1750 { "timeout", required_argument, NULL, ARG_TIMEOUT },
1751 { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
1760 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1768 puts(PACKAGE_STRING);
1769 puts(SYSTEMD_FEATURES);
1773 arg_no_pager = true;
1789 arg_address = optarg;
1792 case ARG_SHOW_MACHINE:
1793 arg_show_machine = true;
1801 arg_acquired = true;
1804 case ARG_ACTIVATABLE:
1805 arg_activatable = true;
1809 if (strv_extend(&arg_matches, optarg) < 0)
1816 r = parse_size(optarg, 0, &o);
1818 log_error("Failed to parse size: %s", optarg);
1822 if ((off_t) (size_t) o != o) {
1823 log_error("Size out of range.");
1827 arg_snaplen = (size_t) o;
1836 arg_transport = BUS_TRANSPORT_REMOTE;
1841 arg_transport = BUS_TRANSPORT_CONTAINER;
1853 case ARG_EXPECT_REPLY:
1854 r = parse_boolean(optarg);
1856 log_error("Failed to parse --expect-reply= parameter.");
1860 arg_expect_reply = !!r;
1864 case ARG_AUTO_START:
1865 r = parse_boolean(optarg);
1867 log_error("Failed to parse --auto-start= parameter.");
1871 arg_auto_start = !!r;
1875 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1876 r = parse_boolean(optarg);
1878 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1882 arg_allow_interactive_authorization = !!r;
1886 r = parse_sec(optarg, &arg_timeout);
1888 log_error("Failed to parse --timeout= parameter.");
1894 case ARG_AUGMENT_CREDS:
1895 r = parse_boolean(optarg);
1897 log_error("Failed to parse --augment-creds= parameter.");
1901 arg_augment_creds = !!r;
1908 assert_not_reached("Unhandled option");
1914 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1917 if (optind >= argc ||
1918 streq(argv[optind], "list"))
1919 return list_bus_names(bus, argv + optind);
1921 if (streq(argv[optind], "monitor"))
1922 return monitor(bus, argv + optind, message_dump);
1924 if (streq(argv[optind], "capture"))
1925 return capture(bus, argv + optind);
1927 if (streq(argv[optind], "status"))
1928 return status(bus, argv + optind);
1930 if (streq(argv[optind], "tree"))
1931 return tree(bus, argv + optind);
1933 if (streq(argv[optind], "introspect"))
1934 return introspect(bus, argv + optind);
1936 if (streq(argv[optind], "call"))
1937 return call(bus, argv + optind);
1939 if (streq(argv[optind], "get-property"))
1940 return get_property(bus, argv + optind);
1942 if (streq(argv[optind], "set-property"))
1943 return set_property(bus, argv + optind);
1945 if (streq(argv[optind], "help"))
1948 log_error("Unknown command '%s'", argv[optind]);
1952 int main(int argc, char *argv[]) {
1953 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1956 log_parse_environment();
1959 r = parse_argv(argc, argv);
1963 r = sd_bus_new(&bus);
1965 log_error("Failed to allocate bus: %s", strerror(-r));
1969 if (streq_ptr(argv[optind], "monitor") ||
1970 streq_ptr(argv[optind], "capture")) {
1972 r = sd_bus_set_monitor(bus, true);
1974 log_error("Failed to set monitor mode: %s", strerror(-r));
1978 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
1980 log_error("Failed to enable credentials: %s", strerror(-r));
1984 r = sd_bus_negotiate_timestamp(bus, true);
1986 log_error("Failed to enable timestamps: %s", strerror(-r));
1990 r = sd_bus_negotiate_fds(bus, true);
1992 log_error("Failed to enable fds: %s", strerror(-r));
1998 r = sd_bus_set_address(bus, arg_address);
2000 r = sd_bus_set_bus_client(bus, true);
2002 log_error("Failed to set bus client: %s", strerror(-r));
2006 switch (arg_transport) {
2008 case BUS_TRANSPORT_LOCAL:
2010 r = bus_set_address_user(bus);
2012 r = bus_set_address_system(bus);
2015 case BUS_TRANSPORT_REMOTE:
2016 r = bus_set_address_system_remote(bus, arg_host);
2019 case BUS_TRANSPORT_CONTAINER:
2020 r = bus_set_address_system_container(bus, arg_host);
2024 assert_not_reached("Hmm, unknown transport type.");
2028 log_error("Failed to set address: %s", strerror(-r));
2032 r = sd_bus_start(bus);
2034 log_error("Failed to connect to bus: %s", strerror(-r));
2038 r = busctl_main(bus, argc, argv);
2043 strv_free(arg_matches);
2045 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;