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 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
71 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
73 static int list_bus_names(sd_bus *bus, char **argv) {
74 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
75 _cleanup_free_ char **merged = NULL;
76 _cleanup_hashmap_free_ Hashmap *names = NULL;
87 if (!arg_unique && !arg_acquired && !arg_activatable)
88 arg_unique = arg_acquired = arg_activatable = true;
90 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
92 log_error("Failed to list names: %s", strerror(-r));
96 pager_open_if_enabled();
98 names = hashmap_new(&string_hash_ops);
102 STRV_FOREACH(i, acquired) {
103 max_i = MAX(max_i, strlen(*i));
105 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
107 log_error("Failed to add to hashmap: %s", strerror(-r));
112 STRV_FOREACH(i, activatable) {
113 max_i = MAX(max_i, strlen(*i));
115 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
116 if (r < 0 && r != -EEXIST) {
117 log_error("Failed to add to hashmap: %s", strerror(-r));
122 merged = new(char*, hashmap_size(names) + 1);
123 HASHMAP_FOREACH_KEY(v, k, names, iterator)
130 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
131 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
133 if (arg_show_machine)
139 STRV_FOREACH(i, merged) {
140 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
143 if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
146 printf("%-*s", (int) max_i, *i);
147 printf(" - - - (activatable) - - ");
148 if (arg_show_machine)
156 if (!arg_unique && (*i)[0] == ':')
159 if (!arg_acquired && (*i)[0] != ':')
162 printf("%-*s", (int) max_i, *i);
164 r = sd_bus_get_name_creds(bus, *i,
165 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
166 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
167 SD_BUS_CREDS_DESCRIPTION, &creds);
169 const char *unique, *session, *unit, *cn;
173 r = sd_bus_creds_get_pid(creds, &pid);
175 const char *comm = NULL;
177 sd_bus_creds_get_comm(creds, &comm);
179 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
181 fputs(" - - ", stdout);
183 r = sd_bus_creds_get_uid(creds, &uid);
185 _cleanup_free_ char *u = NULL;
187 u = uid_to_name(uid);
196 fputs(" - ", stdout);
198 r = sd_bus_creds_get_unique_name(creds, &unique);
200 printf(" %-13s", unique);
202 fputs(" - ", stdout);
204 r = sd_bus_creds_get_unit(creds, &unit);
206 _cleanup_free_ char *e;
208 e = ellipsize(unit, 25, 100);
214 fputs(" - ", stdout);
216 r = sd_bus_creds_get_session(creds, &session);
218 printf(" %-10s", session);
220 fputs(" - ", stdout);
222 r = sd_bus_creds_get_description(creds, &cn);
224 printf(" %-19s", cn);
226 fputs(" - ", stdout);
229 printf(" - - - - - - - ");
231 if (arg_show_machine) {
232 r = sd_bus_get_name_machine_id(bus, *i, &mid);
234 char m[SD_ID128_STRING_MAX];
235 printf(" %s\n", sd_id128_to_string(mid, m));
245 static void print_subtree(const char *prefix, const char *path, char **l) {
246 const char *vertical, *space;
249 /* We assume the list is sorted. Let's first skip over the
250 * entry we are looking at. */
255 if (!streq(*l, path))
261 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
262 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
265 bool has_more = false;
267 if (!*l || !path_startswith(*l, path))
272 if (!*n || !path_startswith(*n, path))
275 if (!path_startswith(*n, *l)) {
283 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
285 print_subtree(has_more ? vertical : space, *l, l);
290 static void print_tree(const char *prefix, char **l) {
292 pager_open_if_enabled();
294 prefix = strempty(prefix);
300 printf("%s%s\n", prefix, *i);
304 if (strv_isempty(l)) {
305 printf("No objects discovered.\n");
309 if (streq(l[0], "/") && !l[1]) {
310 printf("Only root object discovered.\n");
314 print_subtree(prefix, "/", l);
317 static int on_path(const char *path, void *userdata) {
318 Set *paths = userdata;
323 r = set_put_strdup(paths, path);
330 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
331 static const XMLIntrospectOps ops = {
335 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
336 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
340 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
343 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
345 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
349 r = sd_bus_message_read(reply, "s", &xml);
351 return bus_log_parse_error(r);
353 return parse_xml_introspect(path, xml, &ops, paths);
356 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
357 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
358 _cleanup_free_ char **l = NULL;
362 paths = set_new(&string_hash_ops);
366 done = set_new(&string_hash_ops);
370 failed = set_new(&string_hash_ops);
378 r = set_put(paths, m);
385 _cleanup_free_ char *p = NULL;
388 p = set_steal_first(paths);
392 if (set_contains(done, p) ||
393 set_contains(failed, p))
396 q = find_nodes(bus, service, p, paths, many);
401 q = set_put(failed, p);
403 q = set_put(done, p);
412 pager_open_if_enabled();
414 l = set_get_strv(done);
419 print_tree(prefix, l);
426 static int tree(sd_bus *bus, char **argv) {
430 if (!arg_unique && !arg_acquired)
433 if (strv_length(argv) <= 1) {
434 _cleanup_strv_free_ char **names = NULL;
435 bool not_first = false;
437 r = sd_bus_list_names(bus, &names, NULL);
439 log_error("Failed to get name list: %s", strerror(-r));
443 pager_open_if_enabled();
445 STRV_FOREACH(i, names) {
448 if (!arg_unique && (*i)[0] == ':')
451 if (!arg_acquired && (*i)[0] == ':')
457 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
459 q = tree_one(bus, *i, NULL, true);
466 STRV_FOREACH(i, argv+1) {
473 pager_open_if_enabled();
474 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
477 q = tree_one(bus, *i, NULL, !!argv[2]);
486 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
490 const char *contents = NULL;
505 r = sd_bus_message_peek_type(m, &type, &contents);
509 if (bus_type_is_container(type) > 0) {
511 r = sd_bus_message_enter_container(m, type, contents);
515 if (type == SD_BUS_TYPE_ARRAY) {
518 /* count array entries */
521 r = sd_bus_message_skip(m, contents);
530 r = sd_bus_message_rewind(m, false);
538 } else if (type == SD_BUS_TYPE_VARIANT) {
543 fprintf(f, "%s", contents);
546 r = format_cmdline(m, f, true);
550 r = sd_bus_message_exit_container(m);
557 r = sd_bus_message_read_basic(m, type, &basic);
565 case SD_BUS_TYPE_BYTE:
566 fprintf(f, "%u", basic.u8);
569 case SD_BUS_TYPE_BOOLEAN:
570 fputs(true_false(basic.i), f);
573 case SD_BUS_TYPE_INT16:
574 fprintf(f, "%i", basic.s16);
577 case SD_BUS_TYPE_UINT16:
578 fprintf(f, "%u", basic.u16);
581 case SD_BUS_TYPE_INT32:
582 fprintf(f, "%i", basic.s32);
585 case SD_BUS_TYPE_UINT32:
586 fprintf(f, "%u", basic.u32);
589 case SD_BUS_TYPE_INT64:
590 fprintf(f, "%" PRIi64, basic.s64);
593 case SD_BUS_TYPE_UINT64:
594 fprintf(f, "%" PRIu64, basic.u64);
597 case SD_BUS_TYPE_DOUBLE:
598 fprintf(f, "%g", basic.d64);
601 case SD_BUS_TYPE_STRING:
602 case SD_BUS_TYPE_OBJECT_PATH:
603 case SD_BUS_TYPE_SIGNATURE: {
604 _cleanup_free_ char *b = NULL;
606 b = cescape(basic.string);
610 fprintf(f, "\"%s\"", b);
614 case SD_BUS_TYPE_UNIX_FD:
615 fprintf(f, "%i", basic.i);
619 assert_not_reached("Unknown basic type.");
625 typedef struct Member {
636 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
643 ul = string_hash_func(m->type, hash_key);
646 ul ^= string_hash_func(m->name, hash_key);
649 ul ^= string_hash_func(m->interface, hash_key);
654 static int member_compare_func(const void *a, const void *b) {
655 const Member *x = a, *y = b;
663 if (!x->interface && y->interface)
665 if (x->interface && !y->interface)
667 if (x->interface && y->interface) {
668 d = strcmp(x->interface, y->interface);
673 d = strcmp(x->type, y->type);
677 if (!x->name && y->name)
679 if (x->name && !y->name)
681 if (x->name && y->name)
682 return strcmp(x->name, y->name);
687 static int member_compare_funcp(const void *a, const void *b) {
688 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
690 return member_compare_func(*x, *y);
693 static void member_free(Member *m) {
705 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
707 static void member_set_free(Set *s) {
710 while ((m = set_steal_first(s)))
716 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
718 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
719 _cleanup_(member_freep) Member *m;
720 Set *members = userdata;
730 m->type = "interface";
733 r = free_and_strdup(&m->interface, interface);
737 r = set_put(members, m);
739 log_error("Duplicate interface");
747 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
748 _cleanup_(member_freep) Member *m;
749 Set *members = userdata;
762 r = free_and_strdup(&m->interface, interface);
766 r = free_and_strdup(&m->name, name);
770 r = free_and_strdup(&m->signature, signature);
774 r = free_and_strdup(&m->result, result);
778 r = set_put(members, m);
780 log_error("Duplicate method");
788 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
789 _cleanup_(member_freep) Member *m;
790 Set *members = userdata;
803 r = free_and_strdup(&m->interface, interface);
807 r = free_and_strdup(&m->name, name);
811 r = free_and_strdup(&m->signature, signature);
815 r = set_put(members, m);
817 log_error("Duplicate signal");
825 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
826 _cleanup_(member_freep) Member *m;
827 Set *members = userdata;
837 m->type = "property";
839 m->writable = writable;
841 r = free_and_strdup(&m->interface, interface);
845 r = free_and_strdup(&m->name, name);
849 r = free_and_strdup(&m->signature, signature);
853 r = set_put(members, m);
855 log_error("Duplicate property");
863 static const char *strdash(const char *x) {
864 return isempty(x) ? "-" : x;
867 static int introspect(sd_bus *bus, char **argv) {
868 static const struct hash_ops member_hash_ops = {
869 .hash = member_hash_func,
870 .compare = member_compare_func,
873 static const XMLIntrospectOps ops = {
874 .on_interface = on_interface,
875 .on_method = on_method,
876 .on_signal = on_signal,
877 .on_property = on_property,
880 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
881 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
882 _cleanup_(member_set_freep) Set *members = NULL;
887 unsigned name_width, type_width, signature_width, result_width;
888 Member **sorted = NULL;
891 if (strv_length(argv) != 3) {
892 log_error("Requires service and object path argument.");
896 members = set_new(&member_hash_ops);
900 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
902 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
906 r = sd_bus_message_read(reply, "s", &xml);
908 return bus_log_parse_error(r);
910 /* First, get list of all properties */
911 r = parse_xml_introspect(argv[2], xml, &ops, members);
915 /* Second, find the current values for them */
916 SET_FOREACH(m, members, i) {
918 if (!streq(m->type, "property"))
924 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
926 log_error("%s", bus_error_message(&error, r));
930 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
932 return bus_log_parse_error(r);
936 _cleanup_free_ char *buf = NULL;
937 _cleanup_fclose_ FILE *mf = NULL;
941 r = sd_bus_message_enter_container(reply, 'e', "sv");
943 return bus_log_parse_error(r);
948 r = sd_bus_message_read(reply, "s", &name);
950 return bus_log_parse_error(r);
952 r = sd_bus_message_enter_container(reply, 'v', NULL);
954 return bus_log_parse_error(r);
956 mf = open_memstream(&buf, &sz);
960 r = format_cmdline(reply, mf, false);
962 return bus_log_parse_error(r);
967 z = set_get(members, &((Member) {
969 .interface = m->interface,
970 .name = (char*) name }));
977 r = sd_bus_message_exit_container(reply);
979 return bus_log_parse_error(r);
981 r = sd_bus_message_exit_container(reply);
983 return bus_log_parse_error(r);
986 r = sd_bus_message_exit_container(reply);
988 return bus_log_parse_error(r);
991 pager_open_if_enabled();
993 name_width = strlen("NAME");
994 type_width = strlen("TYPE");
995 signature_width = strlen("SIGNATURE");
996 result_width = strlen("RESULT/VALUE");
998 sorted = newa(Member*, set_size(members));
1000 SET_FOREACH(m, members, i) {
1002 name_width = MAX(name_width, strlen(m->interface));
1004 name_width = MAX(name_width, strlen(m->name) + 1);
1006 type_width = MAX(type_width, strlen(m->type));
1008 signature_width = MAX(signature_width, strlen(m->signature));
1010 result_width = MAX(result_width, strlen(m->result));
1012 result_width = MAX(result_width, strlen(m->value));
1017 if (result_width > 40)
1020 assert(k == set_size(members));
1021 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1024 printf("%-*s %-*s %-*s %-*s %s\n",
1025 (int) name_width, "NAME",
1026 (int) type_width, "TYPE",
1027 (int) signature_width, "SIGNATURE",
1028 (int) result_width, "RESULT/VALUE",
1032 for (j = 0; j < k; j++) {
1033 _cleanup_free_ char *ellipsized = NULL;
1039 is_interface = streq(m->type, "interface");
1042 ellipsized = ellipsize(m->value, result_width, 100);
1048 rv = strdash(m->result);
1050 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1051 is_interface ? ansi_highlight() : "",
1052 is_interface ? "" : ".",
1053 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1054 is_interface ? ansi_highlight_off() : "",
1055 (int) type_width, strdash(m->type),
1056 (int) signature_width, strdash(m->signature),
1057 (int) result_width, rv,
1058 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1059 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1060 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1061 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1062 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1063 m->writable ? " writable" : "");
1069 static int message_dump(sd_bus_message *m, FILE *f) {
1070 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1073 static int message_pcap(sd_bus_message *m, FILE *f) {
1074 return bus_message_pcap_frame(m, arg_snaplen, f);
1077 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1078 bool added_something = false;
1082 STRV_FOREACH(i, argv+1) {
1083 _cleanup_free_ char *m = NULL;
1085 if (!service_name_is_valid(*i)) {
1086 log_error("Invalid service name '%s'", *i);
1090 m = strjoin("sender='", *i, "'", NULL);
1094 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1096 log_error("Failed to add match: %s", strerror(-r));
1100 added_something = true;
1103 STRV_FOREACH(i, arg_matches) {
1104 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1106 log_error("Failed to add match: %s", strerror(-r));
1110 added_something = true;
1113 if (!added_something) {
1114 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1116 log_error("Failed to add match: %s", strerror(-r));
1122 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1124 r = sd_bus_process(bus, &m);
1126 log_error("Failed to process bus: %s", strerror(-r));
1138 r = sd_bus_wait(bus, (uint64_t) -1);
1140 log_error("Failed to wait for bus: %s", strerror(-r));
1146 static int capture(sd_bus *bus, char *argv[]) {
1149 if (isatty(fileno(stdout)) > 0) {
1150 log_error("Refusing to write message data to console, please redirect output to a file.");
1154 bus_pcap_header(arg_snaplen, stdout);
1156 r = monitor(bus, argv, message_pcap);
1160 if (ferror(stdout)) {
1161 log_error("Couldn't write capture file.");
1168 static int status(sd_bus *bus, char *argv[]) {
1169 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1175 if (strv_length(argv) != 2) {
1176 log_error("Expects one argument.");
1180 r = parse_pid(argv[1], &pid);
1182 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
1184 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
1187 log_error("Failed to get credentials: %s", strerror(-r));
1191 bus_creds_dump(creds, NULL, false);
1195 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1215 log_error("Too few parameters for signature.");
1224 case SD_BUS_TYPE_BOOLEAN:
1226 r = parse_boolean(v);
1228 log_error("Failed to parse as boolean: %s", v);
1232 r = sd_bus_message_append_basic(m, t, &r);
1235 case SD_BUS_TYPE_BYTE: {
1238 r = safe_atou8(v, &z);
1240 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1244 r = sd_bus_message_append_basic(m, t, &z);
1248 case SD_BUS_TYPE_INT16: {
1251 r = safe_atoi16(v, &z);
1253 log_error("Failed to parse as signed 16bit integer: %s", v);
1257 r = sd_bus_message_append_basic(m, t, &z);
1261 case SD_BUS_TYPE_UINT16: {
1264 r = safe_atou16(v, &z);
1266 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1270 r = sd_bus_message_append_basic(m, t, &z);
1274 case SD_BUS_TYPE_INT32: {
1277 r = safe_atoi32(v, &z);
1279 log_error("Failed to parse as signed 32bit integer: %s", v);
1283 r = sd_bus_message_append_basic(m, t, &z);
1287 case SD_BUS_TYPE_UINT32: {
1290 r = safe_atou32(v, &z);
1292 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1296 r = sd_bus_message_append_basic(m, t, &z);
1300 case SD_BUS_TYPE_INT64: {
1303 r = safe_atoi64(v, &z);
1305 log_error("Failed to parse as signed 64bit integer: %s", v);
1309 r = sd_bus_message_append_basic(m, t, &z);
1313 case SD_BUS_TYPE_UINT64: {
1316 r = safe_atou64(v, &z);
1318 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1322 r = sd_bus_message_append_basic(m, t, &z);
1327 case SD_BUS_TYPE_DOUBLE: {
1330 r = safe_atod(v, &z);
1332 log_error("Failed to parse as double precision floating point: %s", v);
1336 r = sd_bus_message_append_basic(m, t, &z);
1340 case SD_BUS_TYPE_STRING:
1341 case SD_BUS_TYPE_OBJECT_PATH:
1342 case SD_BUS_TYPE_SIGNATURE:
1344 r = sd_bus_message_append_basic(m, t, v);
1347 case SD_BUS_TYPE_ARRAY: {
1351 r = safe_atou32(v, &n);
1353 log_error("Failed to parse number of array entries: %s", v);
1357 r = signature_element_length(signature, &k);
1359 log_error("Invalid array signature.");
1366 memcpy(s, signature, k);
1369 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1371 return bus_log_create_error(r);
1373 for (i = 0; i < n; i++) {
1374 r = message_append_cmdline(m, s, &p);
1382 r = sd_bus_message_close_container(m);
1386 case SD_BUS_TYPE_VARIANT:
1387 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1389 return bus_log_create_error(r);
1391 r = message_append_cmdline(m, v, &p);
1395 r = sd_bus_message_close_container(m);
1398 case SD_BUS_TYPE_STRUCT_BEGIN:
1399 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1405 r = signature_element_length(signature, &k);
1407 log_error("Invalid struct/dict entry signature.");
1413 memcpy(s, signature + 1, k - 2);
1416 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1418 return bus_log_create_error(r);
1420 r = message_append_cmdline(m, s, &p);
1427 r = sd_bus_message_close_container(m);
1431 case SD_BUS_TYPE_UNIX_FD:
1432 log_error("UNIX file descriptor not supported as type.");
1436 log_error("Unknown signature type %c.", t);
1441 return bus_log_create_error(r);
1448 static int call(sd_bus *bus, char *argv[]) {
1449 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1450 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1455 if (strv_length(argv) < 5) {
1456 log_error("Expects at least four arguments.");
1460 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1462 return bus_log_create_error(r);
1464 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1466 return bus_log_create_error(r);
1468 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1470 return bus_log_create_error(r);
1472 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1474 return bus_log_create_error(r);
1476 if (!isempty(argv[5])) {
1481 r = message_append_cmdline(m, argv[5], &p);
1486 log_error("Too many parameters for signature.");
1491 if (!arg_expect_reply) {
1492 r = sd_bus_send(bus, m, NULL);
1494 log_error("Failed to send message.");
1501 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1503 log_error("%s", bus_error_message(&error, r));
1507 r = sd_bus_message_is_empty(reply);
1509 return bus_log_parse_error(r);
1511 if (r == 0 && !arg_quiet) {
1514 pager_open_if_enabled();
1516 r = bus_message_dump(reply, stdout, 0);
1521 fputs(sd_bus_message_get_signature(reply, true), stdout);
1524 r = format_cmdline(reply, stdout, false);
1526 return bus_log_parse_error(r);
1528 fputc('\n', stdout);
1535 static int get_property(sd_bus *bus, char *argv[]) {
1536 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1543 n = strv_length(argv);
1545 log_error("Expects at least four arguments.");
1549 STRV_FOREACH(i, argv + 4) {
1550 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1551 const char *contents = NULL;
1554 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1556 log_error("%s", bus_error_message(&error, r));
1560 r = sd_bus_message_peek_type(reply, &type, &contents);
1562 return bus_log_parse_error(r);
1564 r = sd_bus_message_enter_container(reply, 'v', contents);
1566 return bus_log_parse_error(r);
1569 pager_open_if_enabled();
1571 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1575 fputs(contents, stdout);
1578 r = format_cmdline(reply, stdout, false);
1580 return bus_log_parse_error(r);
1582 fputc('\n', stdout);
1585 r = sd_bus_message_exit_container(reply);
1587 return bus_log_parse_error(r);
1593 static int set_property(sd_bus *bus, char *argv[]) {
1594 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1595 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1602 n = strv_length(argv);
1604 log_error("Expects at least five arguments.");
1608 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1610 return bus_log_create_error(r);
1612 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1614 return bus_log_create_error(r);
1616 r = sd_bus_message_open_container(m, 'v', argv[5]);
1618 return bus_log_create_error(r);
1621 r = message_append_cmdline(m, argv[5], &p);
1625 r = sd_bus_message_close_container(m);
1627 return bus_log_create_error(r);
1630 log_error("Too many parameters for signature.");
1634 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1636 log_error("%s", bus_error_message(&error, r));
1643 static int help(void) {
1644 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1645 "Introspect the bus.\n\n"
1646 " -h --help Show this help\n"
1647 " --version Show package version\n"
1648 " --no-pager Do not pipe output into a pager\n"
1649 " --no-legend Do not show the headers and footers\n"
1650 " --system Connect to system bus\n"
1651 " --user Connect to user bus\n"
1652 " -H --host=[USER@]HOST Operate on remote host\n"
1653 " -M --machine=CONTAINER Operate on local container\n"
1654 " --address=ADDRESS Connect to bus specified by address\n"
1655 " --show-machine Show machine ID column in list\n"
1656 " --unique Only show unique names\n"
1657 " --acquired Only show acquired names\n"
1658 " --activatable Only show activatable names\n"
1659 " --match=MATCH Only show matching messages\n"
1660 " --list Don't show tree, but simple object path list\n"
1661 " --quiet Don't show method call reply\n"
1662 " --verbose Show result values in long format\n"
1663 " --expect-reply=BOOL Expect a method call reply\n"
1664 " --auto-start=BOOL Auto-start destination service\n"
1665 " --allow-interactive-authorization=BOOL\n"
1666 " Allow interactive authorization for operation\n"
1667 " --timeout=SECS Maximum time to wait for method call completion\n\n"
1669 " list List bus names\n"
1670 " status SERVICE Show service name status\n"
1671 " monitor [SERVICE...] Show bus traffic\n"
1672 " capture [SERVICE...] Capture bus traffic as pcap\n"
1673 " tree [SERVICE...] Show object tree of service\n"
1674 " introspect SERVICE OBJECT\n"
1675 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1677 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1678 " Get property value\n"
1679 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1680 " Set property value\n"
1681 " help Show this help\n"
1682 , program_invocation_short_name);
1687 static int parse_argv(int argc, char *argv[]) {
1690 ARG_VERSION = 0x100,
1706 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1710 static const struct option options[] = {
1711 { "help", no_argument, NULL, 'h' },
1712 { "version", no_argument, NULL, ARG_VERSION },
1713 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1714 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1715 { "system", no_argument, NULL, ARG_SYSTEM },
1716 { "user", no_argument, NULL, ARG_USER },
1717 { "address", required_argument, NULL, ARG_ADDRESS },
1718 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1719 { "unique", no_argument, NULL, ARG_UNIQUE },
1720 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1721 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1722 { "match", required_argument, NULL, ARG_MATCH },
1723 { "host", required_argument, NULL, 'H' },
1724 { "machine", required_argument, NULL, 'M' },
1725 { "size", required_argument, NULL, ARG_SIZE },
1726 { "list", no_argument, NULL, ARG_LIST },
1727 { "quiet", no_argument, NULL, 'q' },
1728 { "verbose", no_argument, NULL, ARG_VERBOSE },
1729 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1730 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1731 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1732 { "timeout", required_argument, NULL, ARG_TIMEOUT },
1741 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1749 puts(PACKAGE_STRING);
1750 puts(SYSTEMD_FEATURES);
1754 arg_no_pager = true;
1770 arg_address = optarg;
1773 case ARG_SHOW_MACHINE:
1774 arg_show_machine = true;
1782 arg_acquired = true;
1785 case ARG_ACTIVATABLE:
1786 arg_activatable = true;
1790 if (strv_extend(&arg_matches, optarg) < 0)
1797 r = parse_size(optarg, 0, &o);
1799 log_error("Failed to parse size: %s", optarg);
1803 if ((off_t) (size_t) o != o) {
1804 log_error("Size out of range.");
1808 arg_snaplen = (size_t) o;
1817 arg_transport = BUS_TRANSPORT_REMOTE;
1822 arg_transport = BUS_TRANSPORT_CONTAINER;
1834 case ARG_EXPECT_REPLY:
1835 r = parse_boolean(optarg);
1837 log_error("Failed to parse --expect-reply= parameter.");
1841 arg_expect_reply = !!r;
1845 case ARG_AUTO_START:
1846 r = parse_boolean(optarg);
1848 log_error("Failed to parse --auto-start= parameter.");
1852 arg_auto_start = !!r;
1856 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1857 r = parse_boolean(optarg);
1859 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1863 arg_allow_interactive_authorization = !!r;
1867 r = parse_sec(optarg, &arg_timeout);
1869 log_error("Failed to parse --timeout= parameter.");
1879 assert_not_reached("Unhandled option");
1885 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1888 if (optind >= argc ||
1889 streq(argv[optind], "list"))
1890 return list_bus_names(bus, argv + optind);
1892 if (streq(argv[optind], "monitor"))
1893 return monitor(bus, argv + optind, message_dump);
1895 if (streq(argv[optind], "capture"))
1896 return capture(bus, argv + optind);
1898 if (streq(argv[optind], "status"))
1899 return status(bus, argv + optind);
1901 if (streq(argv[optind], "tree"))
1902 return tree(bus, argv + optind);
1904 if (streq(argv[optind], "introspect"))
1905 return introspect(bus, argv + optind);
1907 if (streq(argv[optind], "call"))
1908 return call(bus, argv + optind);
1910 if (streq(argv[optind], "get-property"))
1911 return get_property(bus, argv + optind);
1913 if (streq(argv[optind], "set-property"))
1914 return set_property(bus, argv + optind);
1916 if (streq(argv[optind], "help"))
1919 log_error("Unknown command '%s'", argv[optind]);
1923 int main(int argc, char *argv[]) {
1924 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1927 log_parse_environment();
1930 r = parse_argv(argc, argv);
1934 r = sd_bus_new(&bus);
1936 log_error("Failed to allocate bus: %s", strerror(-r));
1940 if (streq_ptr(argv[optind], "monitor") ||
1941 streq_ptr(argv[optind], "capture")) {
1943 r = sd_bus_set_monitor(bus, true);
1945 log_error("Failed to set monitor mode: %s", strerror(-r));
1949 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1951 log_error("Failed to enable credentials: %s", strerror(-r));
1955 r = sd_bus_negotiate_timestamp(bus, true);
1957 log_error("Failed to enable timestamps: %s", strerror(-r));
1961 r = sd_bus_negotiate_fds(bus, true);
1963 log_error("Failed to enable fds: %s", strerror(-r));
1969 r = sd_bus_set_address(bus, arg_address);
1971 r = sd_bus_set_bus_client(bus, true);
1973 log_error("Failed to set bus client: %s", strerror(-r));
1977 switch (arg_transport) {
1979 case BUS_TRANSPORT_LOCAL:
1981 r = bus_set_address_user(bus);
1983 r = bus_set_address_system(bus);
1986 case BUS_TRANSPORT_REMOTE:
1987 r = bus_set_address_system_remote(bus, arg_host);
1990 case BUS_TRANSPORT_CONTAINER:
1991 r = bus_set_address_system_container(bus, arg_host);
1995 assert_not_reached("Hmm, unknown transport type.");
1999 log_error("Failed to set address: %s", strerror(-r));
2003 r = sd_bus_start(bus);
2005 log_error("Failed to connect to bus: %s", strerror(-r));
2009 r = busctl_main(bus, argc, argv);
2014 strv_free(arg_matches);
2016 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;