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 usec_t arg_timeout = 0;
61 static void pager_open_if_enabled(void) {
63 /* Cache result before we open the pager */
70 static int list_bus_names(sd_bus *bus, char **argv) {
71 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
72 _cleanup_free_ char **merged = NULL;
73 _cleanup_hashmap_free_ Hashmap *names = NULL;
84 if (!arg_unique && !arg_acquired && !arg_activatable)
85 arg_unique = arg_acquired = arg_activatable = true;
87 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
89 log_error("Failed to list names: %s", strerror(-r));
93 pager_open_if_enabled();
95 names = hashmap_new(&string_hash_ops);
99 STRV_FOREACH(i, acquired) {
100 max_i = MAX(max_i, strlen(*i));
102 r = hashmap_put(names, *i, INT_TO_PTR(1));
104 log_error("Failed to add to hashmap: %s", strerror(-r));
109 STRV_FOREACH(i, activatable) {
110 max_i = MAX(max_i, strlen(*i));
112 r = hashmap_put(names, *i, INT_TO_PTR(2));
113 if (r < 0 && r != -EEXIST) {
114 log_error("Failed to add to hashmap: %s", strerror(-r));
119 merged = new(char*, hashmap_size(names) + 1);
120 HASHMAP_FOREACH_KEY(v, k, names, iterator)
127 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
128 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
130 if (arg_show_machine)
136 STRV_FOREACH(i, merged) {
137 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
140 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
143 printf("%-*s", (int) max_i, *i);
144 printf(" - - - (activatable) - - ");
145 if (arg_show_machine)
153 if (!arg_unique && (*i)[0] == ':')
156 if (!arg_acquired && (*i)[0] != ':')
159 printf("%-*s", (int) max_i, *i);
161 r = sd_bus_get_name_creds(bus, *i,
162 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
163 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
164 SD_BUS_CREDS_DESCRIPTION, &creds);
166 const char *unique, *session, *unit, *cn;
170 r = sd_bus_creds_get_pid(creds, &pid);
172 const char *comm = NULL;
174 sd_bus_creds_get_comm(creds, &comm);
176 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
178 fputs(" - - ", stdout);
180 r = sd_bus_creds_get_uid(creds, &uid);
182 _cleanup_free_ char *u = NULL;
184 u = uid_to_name(uid);
193 fputs(" - ", stdout);
195 r = sd_bus_creds_get_unique_name(creds, &unique);
197 printf(" %-13s", unique);
199 fputs(" - ", stdout);
201 r = sd_bus_creds_get_unit(creds, &unit);
203 _cleanup_free_ char *e;
205 e = ellipsize(unit, 25, 100);
211 fputs(" - ", stdout);
213 r = sd_bus_creds_get_session(creds, &session);
215 printf(" %-10s", session);
217 fputs(" - ", stdout);
219 r = sd_bus_creds_get_description(creds, &cn);
221 printf(" %-19s", cn);
223 fputs(" - ", stdout);
226 printf(" - - - - - - - ");
228 if (arg_show_machine) {
229 r = sd_bus_get_name_machine_id(bus, *i, &mid);
231 char m[SD_ID128_STRING_MAX];
232 printf(" %s\n", sd_id128_to_string(mid, m));
242 static void print_subtree(const char *prefix, const char *path, char **l) {
243 const char *vertical, *space;
246 /* We assume the list is sorted. Let's first skip over the
247 * entry we are looking at. */
252 if (!streq(*l, path))
258 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
259 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
262 bool has_more = false;
264 if (!*l || !path_startswith(*l, path))
269 if (!*n || !path_startswith(*n, path))
272 if (!path_startswith(*n, *l)) {
280 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
282 print_subtree(has_more ? vertical : space, *l, l);
287 static void print_tree(const char *prefix, char **l) {
289 pager_open_if_enabled();
291 prefix = strempty(prefix);
297 printf("%s%s\n", prefix, *i);
301 if (strv_isempty(l)) {
302 printf("No objects discovered.\n");
306 if (streq(l[0], "/") && !l[1]) {
307 printf("Only root object discovered.\n");
311 print_subtree(prefix, "/", l);
314 static int on_path(const char *path, void *userdata) {
315 Set *paths = userdata;
320 r = set_put_strdup(paths, path);
327 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
328 static const XMLIntrospectOps ops = {
332 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
333 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
337 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
340 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
342 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
346 r = sd_bus_message_read(reply, "s", &xml);
348 return bus_log_parse_error(r);
350 return parse_xml_introspect(path, xml, &ops, paths);
353 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
354 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
355 _cleanup_free_ char **l = NULL;
359 paths = set_new(&string_hash_ops);
363 done = set_new(&string_hash_ops);
367 failed = set_new(&string_hash_ops);
375 r = set_put(paths, m);
382 _cleanup_free_ char *p = NULL;
385 p = set_steal_first(paths);
389 if (set_contains(done, p) ||
390 set_contains(failed, p))
393 q = find_nodes(bus, service, p, paths, many);
398 q = set_put(failed, p);
400 q = set_put(done, p);
409 pager_open_if_enabled();
411 l = set_get_strv(done);
416 print_tree(prefix, l);
423 static int tree(sd_bus *bus, char **argv) {
427 if (!arg_unique && !arg_acquired)
430 if (strv_length(argv) <= 1) {
431 _cleanup_strv_free_ char **names = NULL;
432 bool not_first = false;
434 r = sd_bus_list_names(bus, &names, NULL);
436 log_error("Failed to get name list: %s", strerror(-r));
440 pager_open_if_enabled();
442 STRV_FOREACH(i, names) {
445 if (!arg_unique && (*i)[0] == ':')
448 if (!arg_acquired && (*i)[0] == ':')
454 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
456 q = tree_one(bus, *i, NULL, true);
463 STRV_FOREACH(i, argv+1) {
470 pager_open_if_enabled();
471 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
474 q = tree_one(bus, *i, NULL, !!argv[2]);
483 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
487 const char *contents = NULL;
502 r = sd_bus_message_peek_type(m, &type, &contents);
506 if (bus_type_is_container(type) > 0) {
508 r = sd_bus_message_enter_container(m, type, contents);
512 if (type == SD_BUS_TYPE_ARRAY) {
515 /* count array entries */
518 r = sd_bus_message_skip(m, contents);
527 r = sd_bus_message_rewind(m, false);
535 } else if (type == SD_BUS_TYPE_VARIANT) {
540 fprintf(f, "%s", contents);
543 r = format_cmdline(m, f, true);
547 r = sd_bus_message_exit_container(m);
554 r = sd_bus_message_read_basic(m, type, &basic);
562 case SD_BUS_TYPE_BYTE:
563 fprintf(f, "%u", basic.u8);
566 case SD_BUS_TYPE_BOOLEAN:
567 fputs(true_false(basic.i), f);
570 case SD_BUS_TYPE_INT16:
571 fprintf(f, "%i", basic.s16);
574 case SD_BUS_TYPE_UINT16:
575 fprintf(f, "%u", basic.u16);
578 case SD_BUS_TYPE_INT32:
579 fprintf(f, "%i", basic.s32);
582 case SD_BUS_TYPE_UINT32:
583 fprintf(f, "%u", basic.u32);
586 case SD_BUS_TYPE_INT64:
587 fprintf(f, "%" PRIi64, basic.s64);
590 case SD_BUS_TYPE_UINT64:
591 fprintf(f, "%" PRIu64, basic.u64);
594 case SD_BUS_TYPE_DOUBLE:
595 fprintf(f, "%g", basic.d64);
598 case SD_BUS_TYPE_STRING:
599 case SD_BUS_TYPE_OBJECT_PATH:
600 case SD_BUS_TYPE_SIGNATURE: {
601 _cleanup_free_ char *b = NULL;
603 b = cescape(basic.string);
607 fprintf(f, "\"%s\"", b);
611 case SD_BUS_TYPE_UNIX_FD:
612 fprintf(f, "%i", basic.i);
616 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;
888 if (strv_length(argv) != 3) {
889 log_error("Requires service and object path argument.");
893 members = set_new(&member_hash_ops);
897 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
899 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
903 r = sd_bus_message_read(reply, "s", &xml);
905 return bus_log_parse_error(r);
907 /* First, get list of all properties */
908 r = parse_xml_introspect(argv[2], xml, &ops, members);
912 /* Second, find the current values for them */
913 SET_FOREACH(m, members, i) {
915 if (!streq(m->type, "property"))
921 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
923 log_error("%s", bus_error_message(&error, r));
927 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
929 return bus_log_parse_error(r);
933 _cleanup_free_ char *buf = NULL;
934 _cleanup_fclose_ FILE *mf = NULL;
938 r = sd_bus_message_enter_container(reply, 'e', "sv");
940 return bus_log_parse_error(r);
945 r = sd_bus_message_read(reply, "s", &name);
947 return bus_log_parse_error(r);
949 r = sd_bus_message_enter_container(reply, 'v', NULL);
951 return bus_log_parse_error(r);
953 mf = open_memstream(&buf, &sz);
957 r = format_cmdline(reply, mf, false);
959 return bus_log_parse_error(r);
964 z = set_get(members, &((Member) {
966 .interface = m->interface,
967 .name = (char*) name }));
974 r = sd_bus_message_exit_container(reply);
976 return bus_log_parse_error(r);
978 r = sd_bus_message_exit_container(reply);
980 return bus_log_parse_error(r);
983 r = sd_bus_message_exit_container(reply);
985 return bus_log_parse_error(r);
988 pager_open_if_enabled();
990 name_width = strlen("NAME");
991 type_width = strlen("TYPE");
992 signature_width = strlen("SIGNATURE");
993 result_width = strlen("RESULT/VALUE");
995 sorted = newa(Member*, set_size(members));
997 SET_FOREACH(m, members, i) {
999 name_width = MAX(name_width, strlen(m->interface));
1001 name_width = MAX(name_width, strlen(m->name) + 1);
1003 type_width = MAX(type_width, strlen(m->type));
1005 signature_width = MAX(signature_width, strlen(m->signature));
1007 result_width = MAX(result_width, strlen(m->result));
1009 result_width = MAX(result_width, strlen(m->value));
1014 if (result_width > 40)
1017 assert(k == set_size(members));
1018 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1021 printf("%-*s %-*s %-*s %-*s %s\n",
1022 (int) name_width, "NAME",
1023 (int) type_width, "TYPE",
1024 (int) signature_width, "SIGNATURE",
1025 (int) result_width, "RESULT/VALUE",
1029 for (j = 0; j < k; j++) {
1030 _cleanup_free_ char *ellipsized = NULL;
1036 is_interface = streq(m->type, "interface");
1039 ellipsized = ellipsize(m->value, result_width, 100);
1045 rv = strdash(m->result);
1047 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1048 is_interface ? ansi_highlight() : "",
1049 is_interface ? "" : ".",
1050 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1051 is_interface ? ansi_highlight_off() : "",
1052 (int) type_width, strdash(m->type),
1053 (int) signature_width, strdash(m->signature),
1054 (int) result_width, rv,
1055 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1056 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1057 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1058 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1059 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1060 m->writable ? " writable" : "");
1066 static int message_dump(sd_bus_message *m, FILE *f) {
1067 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1070 static int message_pcap(sd_bus_message *m, FILE *f) {
1071 return bus_message_pcap_frame(m, arg_snaplen, f);
1074 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1075 bool added_something = false;
1079 STRV_FOREACH(i, argv+1) {
1080 _cleanup_free_ char *m = NULL;
1082 if (!service_name_is_valid(*i)) {
1083 log_error("Invalid service name '%s'", *i);
1087 m = strjoin("sender='", *i, "'", NULL);
1091 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1093 log_error("Failed to add match: %s", strerror(-r));
1097 added_something = true;
1100 STRV_FOREACH(i, arg_matches) {
1101 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1103 log_error("Failed to add match: %s", strerror(-r));
1107 added_something = true;
1110 if (!added_something) {
1111 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1113 log_error("Failed to add match: %s", strerror(-r));
1119 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1121 r = sd_bus_process(bus, &m);
1123 log_error("Failed to process bus: %s", strerror(-r));
1135 r = sd_bus_wait(bus, (uint64_t) -1);
1137 log_error("Failed to wait for bus: %s", strerror(-r));
1143 static int capture(sd_bus *bus, char *argv[]) {
1146 if (isatty(fileno(stdout)) > 0) {
1147 log_error("Refusing to write message data to console, please redirect output to a file.");
1151 bus_pcap_header(arg_snaplen, stdout);
1153 r = monitor(bus, argv, message_pcap);
1157 if (ferror(stdout)) {
1158 log_error("Couldn't write capture file.");
1165 static int status(sd_bus *bus, char *argv[]) {
1166 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1172 if (strv_length(argv) != 2) {
1173 log_error("Expects one argument.");
1177 r = parse_pid(argv[1], &pid);
1179 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
1181 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
1184 log_error("Failed to get credentials: %s", strerror(-r));
1188 bus_creds_dump(creds, NULL, false);
1192 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1212 log_error("Too few parameters for signature.");
1221 case SD_BUS_TYPE_BOOLEAN:
1223 r = parse_boolean(v);
1225 log_error("Failed to parse as boolean: %s", v);
1229 r = sd_bus_message_append_basic(m, t, &r);
1232 case SD_BUS_TYPE_BYTE: {
1235 r = safe_atou8(v, &z);
1237 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1241 r = sd_bus_message_append_basic(m, t, &z);
1245 case SD_BUS_TYPE_INT16: {
1248 r = safe_atoi16(v, &z);
1250 log_error("Failed to parse as signed 16bit integer: %s", v);
1254 r = sd_bus_message_append_basic(m, t, &z);
1258 case SD_BUS_TYPE_UINT16: {
1261 r = safe_atou16(v, &z);
1263 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1267 r = sd_bus_message_append_basic(m, t, &z);
1271 case SD_BUS_TYPE_INT32: {
1274 r = safe_atoi32(v, &z);
1276 log_error("Failed to parse as signed 32bit integer: %s", v);
1280 r = sd_bus_message_append_basic(m, t, &z);
1284 case SD_BUS_TYPE_UINT32: {
1287 r = safe_atou32(v, &z);
1289 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1293 r = sd_bus_message_append_basic(m, t, &z);
1297 case SD_BUS_TYPE_INT64: {
1300 r = safe_atoi64(v, &z);
1302 log_error("Failed to parse as signed 64bit integer: %s", v);
1306 r = sd_bus_message_append_basic(m, t, &z);
1310 case SD_BUS_TYPE_UINT64: {
1313 r = safe_atou64(v, &z);
1315 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1319 r = sd_bus_message_append_basic(m, t, &z);
1324 case SD_BUS_TYPE_DOUBLE: {
1327 r = safe_atod(v, &z);
1329 log_error("Failed to parse as double precision floating point: %s", v);
1333 r = sd_bus_message_append_basic(m, t, &z);
1337 case SD_BUS_TYPE_STRING:
1338 case SD_BUS_TYPE_OBJECT_PATH:
1339 case SD_BUS_TYPE_SIGNATURE:
1341 r = sd_bus_message_append_basic(m, t, v);
1344 case SD_BUS_TYPE_ARRAY: {
1348 r = safe_atou32(v, &n);
1350 log_error("Failed to parse number of array entries: %s", v);
1354 r = signature_element_length(signature, &k);
1356 log_error("Invalid array signature.");
1363 memcpy(s, signature, k);
1366 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1368 return bus_log_create_error(r);
1370 for (i = 0; i < n; i++) {
1371 r = message_append_cmdline(m, s, &p);
1379 r = sd_bus_message_close_container(m);
1383 case SD_BUS_TYPE_VARIANT:
1384 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1386 return bus_log_create_error(r);
1388 r = message_append_cmdline(m, v, &p);
1392 r = sd_bus_message_close_container(m);
1395 case SD_BUS_TYPE_STRUCT_BEGIN:
1396 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1402 r = signature_element_length(signature, &k);
1404 log_error("Invalid struct/dict entry signature.");
1410 memcpy(s, signature + 1, k - 2);
1413 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1415 return bus_log_create_error(r);
1417 r = message_append_cmdline(m, s, &p);
1424 r = sd_bus_message_close_container(m);
1428 case SD_BUS_TYPE_UNIX_FD:
1429 log_error("UNIX file descriptor not supported as type.");
1433 log_error("Unknown signature type %c.", t);
1438 return bus_log_create_error(r);
1445 static int call(sd_bus *bus, char *argv[]) {
1446 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1447 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1452 if (strv_length(argv) < 5) {
1453 log_error("Expects at least four arguments.");
1457 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1459 return bus_log_create_error(r);
1461 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1463 return bus_log_create_error(r);
1465 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1467 return bus_log_create_error(r);
1469 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1471 return bus_log_create_error(r);
1473 if (!isempty(argv[5])) {
1478 r = message_append_cmdline(m, argv[5], &p);
1483 log_error("Too many parameters for signature.");
1488 if (!arg_expect_reply) {
1489 r = sd_bus_send(bus, m, NULL);
1491 log_error("Failed to send message.");
1498 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1500 log_error("%s", bus_error_message(&error, r));
1504 r = sd_bus_message_is_empty(reply);
1506 return bus_log_parse_error(r);
1508 if (r == 0 && !arg_quiet) {
1511 pager_open_if_enabled();
1513 r = bus_message_dump(reply, stdout, 0);
1518 fputs(sd_bus_message_get_signature(reply, true), stdout);
1521 r = format_cmdline(reply, stdout, false);
1523 return bus_log_parse_error(r);
1525 fputc('\n', stdout);
1532 static int get_property(sd_bus *bus, char *argv[]) {
1533 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1540 n = strv_length(argv);
1542 log_error("Expects at least four arguments.");
1546 STRV_FOREACH(i, argv + 4) {
1547 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1548 const char *contents = NULL;
1551 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1553 log_error("%s", bus_error_message(&error, r));
1557 r = sd_bus_message_peek_type(reply, &type, &contents);
1559 return bus_log_parse_error(r);
1561 r = sd_bus_message_enter_container(reply, 'v', contents);
1563 return bus_log_parse_error(r);
1566 pager_open_if_enabled();
1568 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1572 fputs(contents, stdout);
1575 r = format_cmdline(reply, stdout, false);
1577 return bus_log_parse_error(r);
1579 fputc('\n', stdout);
1582 r = sd_bus_message_exit_container(reply);
1584 return bus_log_parse_error(r);
1590 static int set_property(sd_bus *bus, char *argv[]) {
1591 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1592 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1599 n = strv_length(argv);
1601 log_error("Expects at least five arguments.");
1605 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1607 return bus_log_create_error(r);
1609 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1611 return bus_log_create_error(r);
1613 r = sd_bus_message_open_container(m, 'v', argv[5]);
1615 return bus_log_create_error(r);
1618 r = message_append_cmdline(m, argv[5], &p);
1622 r = sd_bus_message_close_container(m);
1624 return bus_log_create_error(r);
1627 log_error("Too many parameters for signature.");
1631 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1633 log_error("%s", bus_error_message(&error, r));
1640 static int help(void) {
1641 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1642 "Introspect the bus.\n\n"
1643 " -h --help Show this help\n"
1644 " --version Show package version\n"
1645 " --no-pager Do not pipe output into a pager\n"
1646 " --no-legend Do not show the headers and footers\n"
1647 " --system Connect to system bus\n"
1648 " --user Connect to user bus\n"
1649 " -H --host=[USER@]HOST Operate on remote host\n"
1650 " -M --machine=CONTAINER Operate on local container\n"
1651 " --address=ADDRESS Connect to bus specified by address\n"
1652 " --show-machine Show machine ID column in list\n"
1653 " --unique Only show unique names\n"
1654 " --acquired Only show acquired names\n"
1655 " --activatable Only show activatable names\n"
1656 " --match=MATCH Only show matching messages\n"
1657 " --list Don't show tree, but simple object path list\n"
1658 " --quiet Don't show method call reply\n"
1659 " --verbose Show result values in long format\n"
1660 " --expect-reply=BOOL Expect a method call reply\n"
1661 " --auto-start=BOOL Auto-start destination service\n"
1662 " --allow-interactive-authorization=BOOL\n"
1663 " Allow interactive authorization for operation\n"
1664 " --timeout=SECS Maximum time to wait for method call completion\n\n"
1666 " list List bus names\n"
1667 " status SERVICE Show service name status\n"
1668 " monitor [SERVICE...] Show bus traffic\n"
1669 " capture [SERVICE...] Capture bus traffic as pcap\n"
1670 " tree [SERVICE...] Show object tree of service\n"
1671 " introspect SERVICE OBJECT\n"
1672 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1674 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1675 " Get property value\n"
1676 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1677 " Set property value\n"
1678 " help Show this help\n"
1679 , program_invocation_short_name);
1684 static int parse_argv(int argc, char *argv[]) {
1687 ARG_VERSION = 0x100,
1703 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1707 static const struct option options[] = {
1708 { "help", no_argument, NULL, 'h' },
1709 { "version", no_argument, NULL, ARG_VERSION },
1710 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1711 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1712 { "system", no_argument, NULL, ARG_SYSTEM },
1713 { "user", no_argument, NULL, ARG_USER },
1714 { "address", required_argument, NULL, ARG_ADDRESS },
1715 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1716 { "unique", no_argument, NULL, ARG_UNIQUE },
1717 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1718 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1719 { "match", required_argument, NULL, ARG_MATCH },
1720 { "host", required_argument, NULL, 'H' },
1721 { "machine", required_argument, NULL, 'M' },
1722 { "size", required_argument, NULL, ARG_SIZE },
1723 { "list", no_argument, NULL, ARG_LIST },
1724 { "quiet", no_argument, NULL, 'q' },
1725 { "verbose", no_argument, NULL, ARG_VERBOSE },
1726 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1727 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1728 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1729 { "timeout", required_argument, NULL, ARG_TIMEOUT },
1738 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1746 puts(PACKAGE_STRING);
1747 puts(SYSTEMD_FEATURES);
1751 arg_no_pager = true;
1767 arg_address = optarg;
1770 case ARG_SHOW_MACHINE:
1771 arg_show_machine = true;
1779 arg_acquired = true;
1782 case ARG_ACTIVATABLE:
1783 arg_activatable = true;
1787 if (strv_extend(&arg_matches, optarg) < 0)
1794 r = parse_size(optarg, 0, &o);
1796 log_error("Failed to parse size: %s", optarg);
1800 if ((off_t) (size_t) o != o) {
1801 log_error("Size out of range.");
1805 arg_snaplen = (size_t) o;
1814 arg_transport = BUS_TRANSPORT_REMOTE;
1819 arg_transport = BUS_TRANSPORT_CONTAINER;
1831 case ARG_EXPECT_REPLY:
1832 r = parse_boolean(optarg);
1834 log_error("Failed to parse --expect-reply= parameter.");
1838 arg_expect_reply = !!r;
1842 case ARG_AUTO_START:
1843 r = parse_boolean(optarg);
1845 log_error("Failed to parse --auto-start= parameter.");
1849 arg_auto_start = !!r;
1853 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1854 r = parse_boolean(optarg);
1856 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1860 arg_allow_interactive_authorization = !!r;
1864 r = parse_sec(optarg, &arg_timeout);
1866 log_error("Failed to parse --timeout= parameter.");
1876 assert_not_reached("Unhandled option");
1882 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1885 if (optind >= argc ||
1886 streq(argv[optind], "list"))
1887 return list_bus_names(bus, argv + optind);
1889 if (streq(argv[optind], "monitor"))
1890 return monitor(bus, argv + optind, message_dump);
1892 if (streq(argv[optind], "capture"))
1893 return capture(bus, argv + optind);
1895 if (streq(argv[optind], "status"))
1896 return status(bus, argv + optind);
1898 if (streq(argv[optind], "tree"))
1899 return tree(bus, argv + optind);
1901 if (streq(argv[optind], "introspect"))
1902 return introspect(bus, argv + optind);
1904 if (streq(argv[optind], "call"))
1905 return call(bus, argv + optind);
1907 if (streq(argv[optind], "get-property"))
1908 return get_property(bus, argv + optind);
1910 if (streq(argv[optind], "set-property"))
1911 return set_property(bus, argv + optind);
1913 if (streq(argv[optind], "help"))
1916 log_error("Unknown command '%s'", argv[optind]);
1920 int main(int argc, char *argv[]) {
1921 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1924 log_parse_environment();
1927 r = parse_argv(argc, argv);
1931 r = sd_bus_new(&bus);
1933 log_error("Failed to allocate bus: %s", strerror(-r));
1937 if (streq_ptr(argv[optind], "monitor") ||
1938 streq_ptr(argv[optind], "capture")) {
1940 r = sd_bus_set_monitor(bus, true);
1942 log_error("Failed to set monitor mode: %s", strerror(-r));
1946 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1948 log_error("Failed to enable credentials: %s", strerror(-r));
1952 r = sd_bus_negotiate_timestamp(bus, true);
1954 log_error("Failed to enable timestamps: %s", strerror(-r));
1958 r = sd_bus_negotiate_fds(bus, true);
1960 log_error("Failed to enable fds: %s", strerror(-r));
1966 r = sd_bus_set_address(bus, arg_address);
1968 r = sd_bus_set_bus_client(bus, true);
1970 log_error("Failed to set bus client: %s", strerror(-r));
1974 switch (arg_transport) {
1976 case BUS_TRANSPORT_LOCAL:
1978 r = bus_set_address_user(bus);
1980 r = bus_set_address_system(bus);
1983 case BUS_TRANSPORT_REMOTE:
1984 r = bus_set_address_system_remote(bus, arg_host);
1987 case BUS_TRANSPORT_CONTAINER:
1988 r = bus_set_address_system_container(bus, arg_host);
1992 assert_not_reached("Hmm, unknown transport type.");
1996 log_error("Failed to set address: %s", strerror(-r));
2000 r = sd_bus_start(bus);
2002 log_error("Failed to connect to bus: %s", strerror(-r));
2006 r = busctl_main(bus, argc, argv);
2011 strv_free(arg_matches);
2013 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;