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;
60 static void pager_open_if_enabled(void) {
62 /* Cache result before we open the pager */
69 static int list_bus_names(sd_bus *bus, char **argv) {
70 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
71 _cleanup_free_ char **merged = NULL;
72 _cleanup_hashmap_free_ Hashmap *names = NULL;
83 if (!arg_unique && !arg_acquired && !arg_activatable)
84 arg_unique = arg_acquired = arg_activatable = true;
86 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
88 log_error("Failed to list names: %s", strerror(-r));
92 pager_open_if_enabled();
94 names = hashmap_new(&string_hash_ops);
98 STRV_FOREACH(i, acquired) {
99 max_i = MAX(max_i, strlen(*i));
101 r = hashmap_put(names, *i, INT_TO_PTR(1));
103 log_error("Failed to add to hashmap: %s", strerror(-r));
108 STRV_FOREACH(i, activatable) {
109 max_i = MAX(max_i, strlen(*i));
111 r = hashmap_put(names, *i, INT_TO_PTR(2));
112 if (r < 0 && r != -EEXIST) {
113 log_error("Failed to add to hashmap: %s", strerror(-r));
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) == INT_TO_PTR(2)) {
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(bus, *i,
161 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
162 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
163 SD_BUS_CREDS_DESCRIPTION, &creds);
165 const char *unique, *session, *unit, *cn;
169 r = sd_bus_creds_get_pid(creds, &pid);
171 const char *comm = NULL;
173 sd_bus_creds_get_comm(creds, &comm);
175 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
177 fputs(" - - ", stdout);
179 r = sd_bus_creds_get_uid(creds, &uid);
181 _cleanup_free_ char *u = NULL;
183 u = uid_to_name(uid);
192 fputs(" - ", stdout);
194 r = sd_bus_creds_get_unique_name(creds, &unique);
196 printf(" %-13s", unique);
198 fputs(" - ", stdout);
200 r = sd_bus_creds_get_unit(creds, &unit);
202 _cleanup_free_ char *e;
204 e = ellipsize(unit, 25, 100);
210 fputs(" - ", stdout);
212 r = sd_bus_creds_get_session(creds, &session);
214 printf(" %-10s", session);
216 fputs(" - ", stdout);
218 r = sd_bus_creds_get_description(creds, &cn);
220 printf(" %-19s", cn);
222 fputs(" - ", stdout);
225 printf(" - - - - - - - ");
227 if (arg_show_machine) {
228 r = sd_bus_get_name_machine_id(bus, *i, &mid);
230 char m[SD_ID128_STRING_MAX];
231 printf(" %s\n", sd_id128_to_string(mid, m));
241 static void print_subtree(const char *prefix, const char *path, char **l) {
242 const char *vertical, *space;
245 /* We assume the list is sorted. Let's first skip over the
246 * entry we are looking at. */
251 if (!streq(*l, path))
257 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
258 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
261 bool has_more = false;
263 if (!*l || !path_startswith(*l, path))
268 if (!*n || !path_startswith(*n, path))
271 if (!path_startswith(*n, *l)) {
279 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
281 print_subtree(has_more ? vertical : space, *l, l);
286 static void print_tree(const char *prefix, char **l) {
288 pager_open_if_enabled();
290 prefix = strempty(prefix);
296 printf("%s%s\n", prefix, *i);
300 if (strv_isempty(l)) {
301 printf("No objects discovered.\n");
305 if (streq(l[0], "/") && !l[1]) {
306 printf("Only root object discovered.\n");
310 print_subtree(prefix, "/", l);
313 static int on_path(const char *path, void *userdata) {
314 Set *paths = userdata;
319 r = set_put_strdup(paths, path);
326 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
327 static const XMLIntrospectOps ops = {
331 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
332 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
336 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
339 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
341 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
345 r = sd_bus_message_read(reply, "s", &xml);
347 return bus_log_parse_error(r);
349 return parse_xml_introspect(path, xml, &ops, paths);
352 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
353 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
354 _cleanup_free_ char **l = NULL;
358 paths = set_new(&string_hash_ops);
362 done = set_new(&string_hash_ops);
366 failed = set_new(&string_hash_ops);
374 r = set_put(paths, m);
381 _cleanup_free_ char *p = NULL;
384 p = set_steal_first(paths);
388 if (set_contains(done, p) ||
389 set_contains(failed, p))
392 q = find_nodes(bus, service, p, paths, many);
397 q = set_put(failed, p);
399 q = set_put(done, p);
408 pager_open_if_enabled();
410 l = set_get_strv(done);
415 print_tree(prefix, l);
422 static int tree(sd_bus *bus, char **argv) {
426 if (!arg_unique && !arg_acquired)
429 if (strv_length(argv) <= 1) {
430 _cleanup_strv_free_ char **names = NULL;
431 bool not_first = false;
433 r = sd_bus_list_names(bus, &names, NULL);
435 log_error("Failed to get name list: %s", strerror(-r));
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, true);
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.");
621 typedef struct Member {
632 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
639 ul = string_hash_func(m->type, hash_key);
642 ul ^= string_hash_func(m->name, hash_key);
645 ul ^= string_hash_func(m->interface, hash_key);
650 static int member_compare_func(const void *a, const void *b) {
651 const Member *x = a, *y = b;
659 if (!x->interface && y->interface)
661 if (x->interface && !y->interface)
663 if (x->interface && y->interface) {
664 d = strcmp(x->interface, y->interface);
669 d = strcmp(x->type, y->type);
673 if (!x->name && y->name)
675 if (x->name && !y->name)
677 if (x->name && y->name)
678 return strcmp(x->name, y->name);
683 static int member_compare_funcp(const void *a, const void *b) {
684 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
686 return member_compare_func(*x, *y);
689 static void member_free(Member *m) {
701 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
703 static void member_set_free(Set *s) {
706 while ((m = set_steal_first(s)))
712 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
714 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
715 _cleanup_(member_freep) Member *m;
716 Set *members = userdata;
726 m->type = "interface";
729 r = free_and_strdup(&m->interface, interface);
733 r = set_put(members, m);
735 log_error("Duplicate interface");
743 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
744 _cleanup_(member_freep) Member *m;
745 Set *members = userdata;
758 r = free_and_strdup(&m->interface, interface);
762 r = free_and_strdup(&m->name, name);
766 r = free_and_strdup(&m->signature, signature);
770 r = free_and_strdup(&m->result, result);
774 r = set_put(members, m);
776 log_error("Duplicate method");
784 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
785 _cleanup_(member_freep) Member *m;
786 Set *members = userdata;
799 r = free_and_strdup(&m->interface, interface);
803 r = free_and_strdup(&m->name, name);
807 r = free_and_strdup(&m->signature, signature);
811 r = set_put(members, m);
813 log_error("Duplicate signal");
821 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
822 _cleanup_(member_freep) Member *m;
823 Set *members = userdata;
833 m->type = "property";
835 m->writable = writable;
837 r = free_and_strdup(&m->interface, interface);
841 r = free_and_strdup(&m->name, name);
845 r = free_and_strdup(&m->signature, signature);
849 r = set_put(members, m);
851 log_error("Duplicate property");
859 static const char *strdash(const char *x) {
860 return isempty(x) ? "-" : x;
863 static int introspect(sd_bus *bus, char **argv) {
864 static const struct hash_ops member_hash_ops = {
865 .hash = member_hash_func,
866 .compare = member_compare_func,
869 static const XMLIntrospectOps ops = {
870 .on_interface = on_interface,
871 .on_method = on_method,
872 .on_signal = on_signal,
873 .on_property = on_property,
876 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
877 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
878 _cleanup_(member_set_freep) Set *members = NULL;
883 unsigned name_width, type_width, signature_width, result_width;
884 Member **sorted = NULL;
887 if (strv_length(argv) != 3) {
888 log_error("Requires service and object path argument.");
892 members = set_new(&member_hash_ops);
896 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
898 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
902 r = sd_bus_message_read(reply, "s", &xml);
904 return bus_log_parse_error(r);
906 /* First, get list of all properties */
907 r = parse_xml_introspect(argv[2], xml, &ops, members);
911 /* Second, find the current values for them */
912 SET_FOREACH(m, members, i) {
914 if (!streq(m->type, "property"))
920 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
922 log_error("%s", bus_error_message(&error, r));
926 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
928 return bus_log_parse_error(r);
932 _cleanup_free_ char *buf = NULL;
933 _cleanup_fclose_ FILE *mf = NULL;
937 r = sd_bus_message_enter_container(reply, 'e', "sv");
939 return bus_log_parse_error(r);
944 r = sd_bus_message_read(reply, "s", &name);
946 return bus_log_parse_error(r);
948 r = sd_bus_message_enter_container(reply, 'v', NULL);
950 return bus_log_parse_error(r);
952 mf = open_memstream(&buf, &sz);
956 r = format_cmdline(reply, mf, false);
958 return bus_log_parse_error(r);
963 z = set_get(members, &((Member) {
965 .interface = m->interface,
966 .name = (char*) name }));
973 r = sd_bus_message_exit_container(reply);
975 return bus_log_parse_error(r);
977 r = sd_bus_message_exit_container(reply);
979 return bus_log_parse_error(r);
982 r = sd_bus_message_exit_container(reply);
984 return bus_log_parse_error(r);
987 pager_open_if_enabled();
989 name_width = strlen("NAME");
990 type_width = strlen("TYPE");
991 signature_width = strlen("SIGNATURE");
992 result_width = strlen("RESULT/VALUE");
994 sorted = newa(Member*, set_size(members));
996 SET_FOREACH(m, members, i) {
998 name_width = MAX(name_width, strlen(m->interface));
1000 name_width = MAX(name_width, strlen(m->name) + 1);
1002 type_width = MAX(type_width, strlen(m->type));
1004 signature_width = MAX(signature_width, strlen(m->signature));
1006 result_width = MAX(result_width, strlen(m->result));
1008 result_width = MAX(result_width, strlen(m->value));
1013 if (result_width > 40)
1016 assert(k == set_size(members));
1017 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1020 printf("%-*s %-*s %-*s %-*s %s\n",
1021 (int) name_width, "NAME",
1022 (int) type_width, "TYPE",
1023 (int) signature_width, "SIGNATURE",
1024 (int) result_width, "RESULT/VALUE",
1028 for (j = 0; j < k; j++) {
1029 _cleanup_free_ char *ellipsized = NULL;
1035 is_interface = streq(m->type, "interface");
1038 ellipsized = ellipsize(m->value, result_width, 100);
1044 rv = strdash(m->result);
1046 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1047 is_interface ? ansi_highlight() : "",
1048 is_interface ? "" : ".",
1049 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1050 is_interface ? ansi_highlight_off() : "",
1051 (int) type_width, strdash(m->type),
1052 (int) signature_width, strdash(m->signature),
1053 (int) result_width, rv,
1054 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1055 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1056 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1057 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1058 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1059 m->writable ? " writable" : "");
1065 static int message_dump(sd_bus_message *m, FILE *f) {
1066 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1069 static int message_pcap(sd_bus_message *m, FILE *f) {
1070 return bus_message_pcap_frame(m, arg_snaplen, f);
1073 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1074 bool added_something = false;
1078 STRV_FOREACH(i, argv+1) {
1079 _cleanup_free_ char *m = NULL;
1081 if (!service_name_is_valid(*i)) {
1082 log_error("Invalid service name '%s'", *i);
1086 m = strjoin("sender='", *i, "'", NULL);
1090 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1092 log_error("Failed to add match: %s", strerror(-r));
1096 added_something = true;
1099 STRV_FOREACH(i, arg_matches) {
1100 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1102 log_error("Failed to add match: %s", strerror(-r));
1106 added_something = true;
1109 if (!added_something) {
1110 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1112 log_error("Failed to add match: %s", strerror(-r));
1118 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1120 r = sd_bus_process(bus, &m);
1122 log_error("Failed to process bus: %s", strerror(-r));
1134 r = sd_bus_wait(bus, (uint64_t) -1);
1136 log_error("Failed to wait for bus: %s", strerror(-r));
1142 static int capture(sd_bus *bus, char *argv[]) {
1145 if (isatty(fileno(stdout)) > 0) {
1146 log_error("Refusing to write message data to console, please redirect output to a file.");
1150 bus_pcap_header(arg_snaplen, stdout);
1152 r = monitor(bus, argv, message_pcap);
1156 if (ferror(stdout)) {
1157 log_error("Couldn't write capture file.");
1164 static int status(sd_bus *bus, char *argv[]) {
1165 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1171 if (strv_length(argv) != 2) {
1172 log_error("Expects one argument.");
1176 r = parse_pid(argv[1], &pid);
1178 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
1180 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
1183 log_error("Failed to get credentials: %s", strerror(-r));
1187 bus_creds_dump(creds, NULL, false);
1191 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1211 log_error("Too few parameters for signature.");
1220 case SD_BUS_TYPE_BOOLEAN:
1222 r = parse_boolean(v);
1224 log_error("Failed to parse as boolean: %s", v);
1228 r = sd_bus_message_append_basic(m, t, &r);
1231 case SD_BUS_TYPE_BYTE: {
1234 r = safe_atou8(v, &z);
1236 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1240 r = sd_bus_message_append_basic(m, t, &z);
1244 case SD_BUS_TYPE_INT16: {
1247 r = safe_atoi16(v, &z);
1249 log_error("Failed to parse as signed 16bit integer: %s", v);
1253 r = sd_bus_message_append_basic(m, t, &z);
1257 case SD_BUS_TYPE_UINT16: {
1260 r = safe_atou16(v, &z);
1262 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1266 r = sd_bus_message_append_basic(m, t, &z);
1270 case SD_BUS_TYPE_INT32: {
1273 r = safe_atoi32(v, &z);
1275 log_error("Failed to parse as signed 32bit integer: %s", v);
1279 r = sd_bus_message_append_basic(m, t, &z);
1283 case SD_BUS_TYPE_UINT32: {
1286 r = safe_atou32(v, &z);
1288 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1292 r = sd_bus_message_append_basic(m, t, &z);
1296 case SD_BUS_TYPE_INT64: {
1299 r = safe_atoi64(v, &z);
1301 log_error("Failed to parse as signed 64bit integer: %s", v);
1305 r = sd_bus_message_append_basic(m, t, &z);
1309 case SD_BUS_TYPE_UINT64: {
1312 r = safe_atou64(v, &z);
1314 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1318 r = sd_bus_message_append_basic(m, t, &z);
1323 case SD_BUS_TYPE_DOUBLE: {
1326 r = safe_atod(v, &z);
1328 log_error("Failed to parse as double precision floating point: %s", v);
1332 r = sd_bus_message_append_basic(m, t, &z);
1336 case SD_BUS_TYPE_STRING:
1337 case SD_BUS_TYPE_OBJECT_PATH:
1338 case SD_BUS_TYPE_SIGNATURE:
1340 r = sd_bus_message_append_basic(m, t, v);
1343 case SD_BUS_TYPE_ARRAY: {
1347 r = safe_atou32(v, &n);
1349 log_error("Failed to parse number of array entries: %s", v);
1353 r = signature_element_length(signature, &k);
1355 log_error("Invalid array signature.");
1362 memcpy(s, signature, k);
1365 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1367 return bus_log_create_error(r);
1369 for (i = 0; i < n; i++) {
1370 r = message_append_cmdline(m, s, &p);
1378 r = sd_bus_message_close_container(m);
1382 case SD_BUS_TYPE_VARIANT:
1383 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1385 return bus_log_create_error(r);
1387 r = message_append_cmdline(m, v, &p);
1391 r = sd_bus_message_close_container(m);
1394 case SD_BUS_TYPE_STRUCT_BEGIN:
1395 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1401 r = signature_element_length(signature, &k);
1403 log_error("Invalid struct/dict entry signature.");
1409 memcpy(s, signature + 1, k - 2);
1412 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1414 return bus_log_create_error(r);
1416 r = message_append_cmdline(m, s, &p);
1423 r = sd_bus_message_close_container(m);
1427 case SD_BUS_TYPE_UNIX_FD:
1428 log_error("UNIX file descriptor not supported as type.");
1432 log_error("Unknown signature type %c.", t);
1437 return bus_log_create_error(r);
1444 static int call(sd_bus *bus, char *argv[]) {
1445 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1446 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1451 if (strv_length(argv) < 5) {
1452 log_error("Expects at least four arguments.");
1456 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1458 return bus_log_create_error(r);
1460 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1462 return bus_log_create_error(r);
1464 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1466 return bus_log_create_error(r);
1468 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1470 return bus_log_create_error(r);
1472 if (!isempty(argv[5])) {
1477 r = message_append_cmdline(m, argv[5], &p);
1482 log_error("Too many parameters for signature.");
1487 if (!arg_expect_reply) {
1488 r = sd_bus_send(bus, m, NULL);
1490 log_error("Failed to send message.");
1497 r = sd_bus_call(bus, m, 0, &error, &reply);
1499 log_error("%s", bus_error_message(&error, r));
1503 r = sd_bus_message_is_empty(reply);
1505 return bus_log_parse_error(r);
1507 if (r == 0 && !arg_quiet) {
1510 pager_open_if_enabled();
1512 r = bus_message_dump(reply, stdout, 0);
1517 fputs(sd_bus_message_get_signature(reply, true), stdout);
1520 r = format_cmdline(reply, stdout, false);
1522 return bus_log_parse_error(r);
1524 fputc('\n', stdout);
1531 static int get_property(sd_bus *bus, char *argv[]) {
1532 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1539 n = strv_length(argv);
1541 log_error("Expects at least four arguments.");
1545 STRV_FOREACH(i, argv + 4) {
1546 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1547 const char *contents = NULL;
1550 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1552 log_error("%s", bus_error_message(&error, r));
1556 r = sd_bus_message_peek_type(reply, &type, &contents);
1558 return bus_log_parse_error(r);
1560 r = sd_bus_message_enter_container(reply, 'v', contents);
1562 return bus_log_parse_error(r);
1565 pager_open_if_enabled();
1567 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1571 fputs(contents, stdout);
1574 r = format_cmdline(reply, stdout, false);
1576 return bus_log_parse_error(r);
1578 fputc('\n', stdout);
1581 r = sd_bus_message_exit_container(reply);
1583 return bus_log_parse_error(r);
1589 static int set_property(sd_bus *bus, char *argv[]) {
1590 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1591 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1598 n = strv_length(argv);
1600 log_error("Expects at least five arguments.");
1604 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1606 return bus_log_create_error(r);
1608 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1610 return bus_log_create_error(r);
1612 r = sd_bus_message_open_container(m, 'v', argv[5]);
1614 return bus_log_create_error(r);
1617 r = message_append_cmdline(m, argv[5], &p);
1621 r = sd_bus_message_close_container(m);
1623 return bus_log_create_error(r);
1626 log_error("Too many parameters for signature.");
1630 r = sd_bus_call(bus, m, 0, &error, NULL);
1632 log_error("%s", bus_error_message(&error, r));
1639 static int help(void) {
1640 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1641 "Introspect the bus.\n\n"
1642 " -h --help Show this help\n"
1643 " --version Show package version\n"
1644 " --no-pager Do not pipe output into a pager\n"
1645 " --no-legend Do not show the headers and footers\n"
1646 " --system Connect to system bus\n"
1647 " --user Connect to user bus\n"
1648 " -H --host=[USER@]HOST Operate on remote host\n"
1649 " -M --machine=CONTAINER Operate on local container\n"
1650 " --address=ADDRESS Connect to bus specified by address\n"
1651 " --show-machine Show machine ID column in list\n"
1652 " --unique Only show unique names\n"
1653 " --acquired Only show acquired names\n"
1654 " --activatable Only show activatable names\n"
1655 " --match=MATCH Only show matching messages\n"
1656 " --list Don't show tree, but simple object path list\n"
1657 " --quiet Don't show method call reply\n"
1658 " --verbose Show result values in long format\n"
1659 " --expect-reply=BOOL Expect a method call reply\n"
1660 " --auto-start=BOOL Auto-start destination service\n"
1661 " --allow-interactive-authorization=BOOL\n"
1662 " Allow interactive authorization for operation\n\n"
1664 " list List bus names\n"
1665 " status SERVICE Show service name status\n"
1666 " monitor [SERVICE...] Show bus traffic\n"
1667 " capture [SERVICE...] Capture bus traffic as pcap\n"
1668 " tree [SERVICE...] Show object tree of service\n"
1669 " introspect SERVICE OBJECT\n"
1670 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1672 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1673 " Get property value\n"
1674 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1675 " Set property value\n"
1676 " help Show this help\n"
1677 , program_invocation_short_name);
1682 static int parse_argv(int argc, char *argv[]) {
1685 ARG_VERSION = 0x100,
1701 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1704 static const struct option options[] = {
1705 { "help", no_argument, NULL, 'h' },
1706 { "version", no_argument, NULL, ARG_VERSION },
1707 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1708 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1709 { "system", no_argument, NULL, ARG_SYSTEM },
1710 { "user", no_argument, NULL, ARG_USER },
1711 { "address", required_argument, NULL, ARG_ADDRESS },
1712 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1713 { "unique", no_argument, NULL, ARG_UNIQUE },
1714 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1715 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1716 { "match", required_argument, NULL, ARG_MATCH },
1717 { "host", required_argument, NULL, 'H' },
1718 { "machine", required_argument, NULL, 'M' },
1719 { "size", required_argument, NULL, ARG_SIZE },
1720 { "list", no_argument, NULL, ARG_LIST },
1721 { "quiet", no_argument, NULL, 'q' },
1722 { "verbose", no_argument, NULL, ARG_VERBOSE },
1723 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1724 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1725 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1734 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1742 puts(PACKAGE_STRING);
1743 puts(SYSTEMD_FEATURES);
1747 arg_no_pager = true;
1763 arg_address = optarg;
1766 case ARG_SHOW_MACHINE:
1767 arg_show_machine = true;
1775 arg_acquired = true;
1778 case ARG_ACTIVATABLE:
1779 arg_activatable = true;
1783 if (strv_extend(&arg_matches, optarg) < 0)
1790 r = parse_size(optarg, 0, &o);
1792 log_error("Failed to parse size: %s", optarg);
1796 if ((off_t) (size_t) o != o) {
1797 log_error("Size out of range.");
1801 arg_snaplen = (size_t) o;
1810 arg_transport = BUS_TRANSPORT_REMOTE;
1815 arg_transport = BUS_TRANSPORT_CONTAINER;
1827 case ARG_EXPECT_REPLY:
1828 r = parse_boolean(optarg);
1830 log_error("Failed to parse --expect-reply= parameter.");
1834 arg_expect_reply = !!r;
1838 case ARG_AUTO_START:
1839 r = parse_boolean(optarg);
1841 log_error("Failed to parse --auto-start= parameter.");
1845 arg_auto_start = !!r;
1849 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1850 r = parse_boolean(optarg);
1852 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1856 arg_allow_interactive_authorization = !!r;
1863 assert_not_reached("Unhandled option");
1869 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1872 if (optind >= argc ||
1873 streq(argv[optind], "list"))
1874 return list_bus_names(bus, argv + optind);
1876 if (streq(argv[optind], "monitor"))
1877 return monitor(bus, argv + optind, message_dump);
1879 if (streq(argv[optind], "capture"))
1880 return capture(bus, argv + optind);
1882 if (streq(argv[optind], "status"))
1883 return status(bus, argv + optind);
1885 if (streq(argv[optind], "tree"))
1886 return tree(bus, argv + optind);
1888 if (streq(argv[optind], "introspect"))
1889 return introspect(bus, argv + optind);
1891 if (streq(argv[optind], "call"))
1892 return call(bus, argv + optind);
1894 if (streq(argv[optind], "get-property"))
1895 return get_property(bus, argv + optind);
1897 if (streq(argv[optind], "set-property"))
1898 return set_property(bus, argv + optind);
1900 if (streq(argv[optind], "help"))
1903 log_error("Unknown command '%s'", argv[optind]);
1907 int main(int argc, char *argv[]) {
1908 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1911 log_parse_environment();
1914 r = parse_argv(argc, argv);
1918 r = sd_bus_new(&bus);
1920 log_error("Failed to allocate bus: %s", strerror(-r));
1924 if (streq_ptr(argv[optind], "monitor") ||
1925 streq_ptr(argv[optind], "capture")) {
1927 r = sd_bus_set_monitor(bus, true);
1929 log_error("Failed to set monitor mode: %s", strerror(-r));
1933 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1935 log_error("Failed to enable credentials: %s", strerror(-r));
1939 r = sd_bus_negotiate_timestamp(bus, true);
1941 log_error("Failed to enable timestamps: %s", strerror(-r));
1945 r = sd_bus_negotiate_fds(bus, true);
1947 log_error("Failed to enable fds: %s", strerror(-r));
1953 r = sd_bus_set_address(bus, arg_address);
1955 r = sd_bus_set_bus_client(bus, true);
1957 log_error("Failed to set bus client: %s", strerror(-r));
1961 switch (arg_transport) {
1963 case BUS_TRANSPORT_LOCAL:
1965 r = bus_set_address_user(bus);
1967 r = bus_set_address_system(bus);
1970 case BUS_TRANSPORT_REMOTE:
1971 r = bus_set_address_system_remote(bus, arg_host);
1974 case BUS_TRANSPORT_CONTAINER:
1975 r = bus_set_address_system_container(bus, arg_host);
1979 assert_not_reached("Hmm, unknown transport type.");
1983 log_error("Failed to set address: %s", strerror(-r));
1987 r = sd_bus_start(bus);
1989 log_error("Failed to connect to bus: %s", strerror(-r));
1993 r = busctl_main(bus, argc, argv);
1998 strv_free(arg_matches);
2000 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;