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;
57 static void pager_open_if_enabled(void) {
59 /* Cache result before we open the pager */
66 static int list_bus_names(sd_bus *bus, char **argv) {
67 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
68 _cleanup_free_ char **merged = NULL;
69 _cleanup_hashmap_free_ Hashmap *names = NULL;
80 if (!arg_unique && !arg_acquired && !arg_activatable)
81 arg_unique = arg_acquired = arg_activatable = true;
83 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
85 log_error("Failed to list names: %s", strerror(-r));
89 pager_open_if_enabled();
91 names = hashmap_new(&string_hash_ops);
95 STRV_FOREACH(i, acquired) {
96 max_i = MAX(max_i, strlen(*i));
98 r = hashmap_put(names, *i, INT_TO_PTR(1));
100 log_error("Failed to add to hashmap: %s", strerror(-r));
105 STRV_FOREACH(i, activatable) {
106 max_i = MAX(max_i, strlen(*i));
108 r = hashmap_put(names, *i, INT_TO_PTR(2));
109 if (r < 0 && r != -EEXIST) {
110 log_error("Failed to add to hashmap: %s", strerror(-r));
115 merged = new(char*, hashmap_size(names) + 1);
116 HASHMAP_FOREACH_KEY(v, k, names, iterator)
123 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
124 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
126 if (arg_show_machine)
132 STRV_FOREACH(i, merged) {
133 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
136 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
139 printf("%-*s", (int) max_i, *i);
140 printf(" - - - (activatable) - - ");
141 if (arg_show_machine)
149 if (!arg_unique && (*i)[0] == ':')
152 if (!arg_acquired && (*i)[0] != ':')
155 printf("%-*s", (int) max_i, *i);
157 r = sd_bus_get_name_creds(bus, *i,
158 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
159 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
160 SD_BUS_CREDS_DESCRIPTION, &creds);
162 const char *unique, *session, *unit, *cn;
166 r = sd_bus_creds_get_pid(creds, &pid);
168 const char *comm = NULL;
170 sd_bus_creds_get_comm(creds, &comm);
172 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
174 fputs(" - - ", stdout);
176 r = sd_bus_creds_get_uid(creds, &uid);
178 _cleanup_free_ char *u = NULL;
180 u = uid_to_name(uid);
189 fputs(" - ", stdout);
191 r = sd_bus_creds_get_unique_name(creds, &unique);
193 printf(" %-13s", unique);
195 fputs(" - ", stdout);
197 r = sd_bus_creds_get_unit(creds, &unit);
199 _cleanup_free_ char *e;
201 e = ellipsize(unit, 25, 100);
207 fputs(" - ", stdout);
209 r = sd_bus_creds_get_session(creds, &session);
211 printf(" %-10s", session);
213 fputs(" - ", stdout);
215 r = sd_bus_creds_get_description(creds, &cn);
217 printf(" %-19s", cn);
219 fputs(" - ", stdout);
222 printf(" - - - - - - - ");
224 if (arg_show_machine) {
225 r = sd_bus_get_name_machine_id(bus, *i, &mid);
227 char m[SD_ID128_STRING_MAX];
228 printf(" %s\n", sd_id128_to_string(mid, m));
238 static void print_subtree(const char *prefix, const char *path, char **l) {
239 const char *vertical, *space;
242 /* We assume the list is sorted. Let's first skip over the
243 * entry we are looking at. */
248 if (!streq(*l, path))
254 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
255 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
258 bool has_more = false;
260 if (!*l || !path_startswith(*l, path))
265 if (!*n || !path_startswith(*n, path))
268 if (!path_startswith(*n, *l)) {
276 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
278 print_subtree(has_more ? vertical : space, *l, l);
283 static void print_tree(const char *prefix, char **l) {
285 pager_open_if_enabled();
287 prefix = strempty(prefix);
293 printf("%s%s\n", prefix, *i);
297 if (strv_isempty(l)) {
298 printf("No objects discovered.\n");
302 if (streq(l[0], "/") && !l[1]) {
303 printf("Only root object discovered.\n");
307 print_subtree(prefix, "/", l);
310 static int on_path(const char *path, void *userdata) {
311 Set *paths = userdata;
316 r = set_put_strdup(paths, path);
323 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
324 static const XMLIntrospectOps ops = {
328 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
329 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
333 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
336 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
338 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
342 r = sd_bus_message_read(reply, "s", &xml);
344 return bus_log_parse_error(r);
346 return parse_xml_introspect(path, xml, &ops, paths);
349 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
350 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
351 _cleanup_free_ char **l = NULL;
355 paths = set_new(&string_hash_ops);
359 done = set_new(&string_hash_ops);
363 failed = set_new(&string_hash_ops);
371 r = set_put(paths, m);
378 _cleanup_free_ char *p = NULL;
381 p = set_steal_first(paths);
385 if (set_contains(done, p) ||
386 set_contains(failed, p))
389 q = find_nodes(bus, service, p, paths, many);
394 q = set_put(failed, p);
396 q = set_put(done, p);
405 pager_open_if_enabled();
407 l = set_get_strv(done);
412 print_tree(prefix, l);
419 static int tree(sd_bus *bus, char **argv) {
423 if (!arg_unique && !arg_acquired)
426 if (strv_length(argv) <= 1) {
427 _cleanup_strv_free_ char **names = NULL;
428 bool not_first = false;
430 r = sd_bus_list_names(bus, &names, NULL);
432 log_error("Failed to get name list: %s", strerror(-r));
436 pager_open_if_enabled();
438 STRV_FOREACH(i, names) {
441 if (!arg_unique && (*i)[0] == ':')
444 if (!arg_acquired && (*i)[0] == ':')
450 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
452 q = tree_one(bus, *i, NULL, true);
459 STRV_FOREACH(i, argv+1) {
466 pager_open_if_enabled();
467 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
470 q = tree_one(bus, *i, NULL, !!argv[2]);
479 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
483 const char *contents = NULL;
498 r = sd_bus_message_peek_type(m, &type, &contents);
502 if (bus_type_is_container(type) > 0) {
504 r = sd_bus_message_enter_container(m, type, contents);
508 if (type == SD_BUS_TYPE_ARRAY) {
511 /* count array entries */
514 r = sd_bus_message_skip(m, contents);
523 r = sd_bus_message_rewind(m, false);
531 } else if (type == SD_BUS_TYPE_VARIANT) {
536 fprintf(f, "%s", contents);
539 r = format_cmdline(m, f, true);
543 r = sd_bus_message_exit_container(m);
550 r = sd_bus_message_read_basic(m, type, &basic);
558 case SD_BUS_TYPE_BYTE:
559 fprintf(f, "%u", basic.u8);
562 case SD_BUS_TYPE_BOOLEAN:
563 fputs(true_false(basic.i), f);
566 case SD_BUS_TYPE_INT16:
567 fprintf(f, "%i", basic.s16);
570 case SD_BUS_TYPE_UINT16:
571 fprintf(f, "%u", basic.u16);
574 case SD_BUS_TYPE_INT32:
575 fprintf(f, "%i", basic.s32);
578 case SD_BUS_TYPE_UINT32:
579 fprintf(f, "%u", basic.u32);
582 case SD_BUS_TYPE_INT64:
583 fprintf(f, "%" PRIi64, basic.s64);
586 case SD_BUS_TYPE_UINT64:
587 fprintf(f, "%" PRIu64, basic.u64);
590 case SD_BUS_TYPE_DOUBLE:
591 fprintf(f, "%g", basic.d64);
594 case SD_BUS_TYPE_STRING:
595 case SD_BUS_TYPE_OBJECT_PATH:
596 case SD_BUS_TYPE_SIGNATURE: {
597 _cleanup_free_ char *b = NULL;
599 b = cescape(basic.string);
603 fprintf(f, "\"%s\"", b);
607 case SD_BUS_TYPE_UNIX_FD:
608 fprintf(f, "%i", basic.i);
612 assert_not_reached("Unknown basic type.");
618 typedef struct Member {
629 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
636 ul = string_hash_func(m->type, hash_key);
639 ul ^= string_hash_func(m->name, hash_key);
642 ul ^= string_hash_func(m->interface, hash_key);
647 static int member_compare_func(const void *a, const void *b) {
648 const Member *x = a, *y = b;
656 if (!x->interface && y->interface)
658 if (x->interface && !y->interface)
660 if (x->interface && y->interface) {
661 d = strcmp(x->interface, y->interface);
666 d = strcmp(x->type, y->type);
670 if (!x->name && y->name)
672 if (x->name && !y->name)
674 if (x->name && y->name)
675 return strcmp(x->name, y->name);
680 static int member_compare_funcp(const void *a, const void *b) {
681 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
683 return member_compare_func(*x, *y);
686 static void member_free(Member *m) {
698 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
700 static void member_set_free(Set *s) {
703 while ((m = set_steal_first(s)))
709 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
711 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
712 _cleanup_(member_freep) Member *m;
713 Set *members = userdata;
723 m->type = "interface";
726 r = free_and_strdup(&m->interface, interface);
730 r = set_put(members, m);
732 log_error("Duplicate interface");
740 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
741 _cleanup_(member_freep) Member *m;
742 Set *members = userdata;
755 r = free_and_strdup(&m->interface, interface);
759 r = free_and_strdup(&m->name, name);
763 r = free_and_strdup(&m->signature, signature);
767 r = free_and_strdup(&m->result, result);
771 r = set_put(members, m);
773 log_error("Duplicate method");
781 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
782 _cleanup_(member_freep) Member *m;
783 Set *members = userdata;
796 r = free_and_strdup(&m->interface, interface);
800 r = free_and_strdup(&m->name, name);
804 r = free_and_strdup(&m->signature, signature);
808 r = set_put(members, m);
810 log_error("Duplicate signal");
818 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
819 _cleanup_(member_freep) Member *m;
820 Set *members = userdata;
830 m->type = "property";
832 m->writable = writable;
834 r = free_and_strdup(&m->interface, interface);
838 r = free_and_strdup(&m->name, name);
842 r = free_and_strdup(&m->signature, signature);
846 r = set_put(members, m);
848 log_error("Duplicate property");
856 static const char *strdash(const char *x) {
857 return isempty(x) ? "-" : x;
860 static int introspect(sd_bus *bus, char **argv) {
861 static const struct hash_ops member_hash_ops = {
862 .hash = member_hash_func,
863 .compare = member_compare_func,
866 static const XMLIntrospectOps ops = {
867 .on_interface = on_interface,
868 .on_method = on_method,
869 .on_signal = on_signal,
870 .on_property = on_property,
873 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
874 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
875 _cleanup_(member_set_freep) Set *members = NULL;
880 unsigned name_width, type_width, signature_width, result_width;
881 Member **sorted = NULL;
884 if (strv_length(argv) != 3) {
885 log_error("Requires service and object path argument.");
889 members = set_new(&member_hash_ops);
893 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
895 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
899 r = sd_bus_message_read(reply, "s", &xml);
901 return bus_log_parse_error(r);
903 /* First, get list of all properties */
904 r = parse_xml_introspect(argv[2], xml, &ops, members);
908 /* Second, find the current values for them */
909 SET_FOREACH(m, members, i) {
911 if (!streq(m->type, "property"))
917 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
919 log_error("%s", bus_error_message(&error, r));
923 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
925 return bus_log_parse_error(r);
929 _cleanup_free_ char *buf = NULL;
930 _cleanup_fclose_ FILE *mf = NULL;
934 r = sd_bus_message_enter_container(reply, 'e', "sv");
936 return bus_log_parse_error(r);
941 r = sd_bus_message_read(reply, "s", &name);
943 return bus_log_parse_error(r);
945 r = sd_bus_message_enter_container(reply, 'v', NULL);
947 return bus_log_parse_error(r);
949 mf = open_memstream(&buf, &sz);
953 r = format_cmdline(reply, mf, false);
955 return bus_log_parse_error(r);
960 z = set_get(members, &((Member) {
962 .interface = m->interface,
963 .name = (char*) name }));
970 r = sd_bus_message_exit_container(reply);
972 return bus_log_parse_error(r);
974 r = sd_bus_message_exit_container(reply);
976 return bus_log_parse_error(r);
979 r = sd_bus_message_exit_container(reply);
981 return bus_log_parse_error(r);
984 pager_open_if_enabled();
986 name_width = strlen("NAME");
987 type_width = strlen("TYPE");
988 signature_width = strlen("SIGNATURE");
989 result_width = strlen("RESULT/VALUE");
991 sorted = newa(Member*, set_size(members));
993 SET_FOREACH(m, members, i) {
995 name_width = MAX(name_width, strlen(m->interface));
997 name_width = MAX(name_width, strlen(m->name) + 1);
999 type_width = MAX(type_width, strlen(m->type));
1001 signature_width = MAX(signature_width, strlen(m->signature));
1003 result_width = MAX(result_width, strlen(m->result));
1005 result_width = MAX(result_width, strlen(m->value));
1010 if (result_width > 40)
1013 assert(k == set_size(members));
1014 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1017 printf("%-*s %-*s %-*s %-*s %s\n",
1018 (int) name_width, "NAME",
1019 (int) type_width, "TYPE",
1020 (int) signature_width, "SIGNATURE",
1021 (int) result_width, "RESULT/VALUE",
1025 for (j = 0; j < k; j++) {
1026 _cleanup_free_ char *ellipsized = NULL;
1032 is_interface = streq(m->type, "interface");
1035 ellipsized = ellipsize(m->value, result_width, 100);
1041 rv = strdash(m->result);
1043 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1044 is_interface ? ansi_highlight() : "",
1045 is_interface ? "" : ".",
1046 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1047 is_interface ? ansi_highlight_off() : "",
1048 (int) type_width, strdash(m->type),
1049 (int) signature_width, strdash(m->signature),
1050 (int) result_width, rv,
1051 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1052 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1053 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1054 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1055 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1056 m->writable ? " writable" : "");
1062 static int message_dump(sd_bus_message *m, FILE *f) {
1063 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1066 static int message_pcap(sd_bus_message *m, FILE *f) {
1067 return bus_message_pcap_frame(m, arg_snaplen, f);
1070 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1071 bool added_something = false;
1075 STRV_FOREACH(i, argv+1) {
1076 _cleanup_free_ char *m = NULL;
1078 if (!service_name_is_valid(*i)) {
1079 log_error("Invalid service name '%s'", *i);
1083 m = strjoin("sender='", *i, "'", NULL);
1087 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1089 log_error("Failed to add match: %s", strerror(-r));
1093 added_something = true;
1096 STRV_FOREACH(i, arg_matches) {
1097 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1099 log_error("Failed to add match: %s", strerror(-r));
1103 added_something = true;
1106 if (!added_something) {
1107 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1109 log_error("Failed to add match: %s", strerror(-r));
1115 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1117 r = sd_bus_process(bus, &m);
1119 log_error("Failed to process bus: %s", strerror(-r));
1131 r = sd_bus_wait(bus, (uint64_t) -1);
1133 log_error("Failed to wait for bus: %s", strerror(-r));
1139 static int capture(sd_bus *bus, char *argv[]) {
1142 if (isatty(fileno(stdout)) > 0) {
1143 log_error("Refusing to write message data to console, please redirect output to a file.");
1147 bus_pcap_header(arg_snaplen, stdout);
1149 r = monitor(bus, argv, message_pcap);
1153 if (ferror(stdout)) {
1154 log_error("Couldn't write capture file.");
1161 static int status(sd_bus *bus, char *argv[]) {
1162 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1168 if (strv_length(argv) != 2) {
1169 log_error("Expects one argument.");
1173 r = parse_pid(argv[1], &pid);
1175 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
1177 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
1180 log_error("Failed to get credentials: %s", strerror(-r));
1184 bus_creds_dump(creds, NULL, false);
1188 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1208 log_error("Too few parameters for signature.");
1217 case SD_BUS_TYPE_BOOLEAN:
1219 r = parse_boolean(v);
1221 log_error("Failed to parse as boolean: %s", v);
1225 r = sd_bus_message_append_basic(m, t, &r);
1228 case SD_BUS_TYPE_BYTE: {
1231 r = safe_atou8(v, &z);
1233 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1237 r = sd_bus_message_append_basic(m, t, &z);
1241 case SD_BUS_TYPE_INT16: {
1244 r = safe_atoi16(v, &z);
1246 log_error("Failed to parse as signed 16bit integer: %s", v);
1250 r = sd_bus_message_append_basic(m, t, &z);
1254 case SD_BUS_TYPE_UINT16: {
1257 r = safe_atou16(v, &z);
1259 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1263 r = sd_bus_message_append_basic(m, t, &z);
1267 case SD_BUS_TYPE_INT32: {
1270 r = safe_atoi32(v, &z);
1272 log_error("Failed to parse as signed 32bit integer: %s", v);
1276 r = sd_bus_message_append_basic(m, t, &z);
1280 case SD_BUS_TYPE_UINT32: {
1283 r = safe_atou32(v, &z);
1285 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1289 r = sd_bus_message_append_basic(m, t, &z);
1293 case SD_BUS_TYPE_INT64: {
1296 r = safe_atoi64(v, &z);
1298 log_error("Failed to parse as signed 64bit integer: %s", v);
1302 r = sd_bus_message_append_basic(m, t, &z);
1306 case SD_BUS_TYPE_UINT64: {
1309 r = safe_atou64(v, &z);
1311 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1315 r = sd_bus_message_append_basic(m, t, &z);
1320 case SD_BUS_TYPE_DOUBLE: {
1323 r = safe_atod(v, &z);
1325 log_error("Failed to parse as double precision floating point: %s", v);
1329 r = sd_bus_message_append_basic(m, t, &z);
1333 case SD_BUS_TYPE_STRING:
1334 case SD_BUS_TYPE_OBJECT_PATH:
1335 case SD_BUS_TYPE_SIGNATURE:
1337 r = sd_bus_message_append_basic(m, t, v);
1340 case SD_BUS_TYPE_ARRAY: {
1344 r = safe_atou32(v, &n);
1346 log_error("Failed to parse number of array entries: %s", v);
1350 r = signature_element_length(signature, &k);
1352 log_error("Invalid array signature.");
1359 memcpy(s, signature, k);
1362 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1364 return bus_log_create_error(r);
1366 for (i = 0; i < n; i++) {
1367 r = message_append_cmdline(m, s, &p);
1375 r = sd_bus_message_close_container(m);
1379 case SD_BUS_TYPE_VARIANT:
1380 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1382 return bus_log_create_error(r);
1384 r = message_append_cmdline(m, v, &p);
1388 r = sd_bus_message_close_container(m);
1391 case SD_BUS_TYPE_STRUCT_BEGIN:
1392 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1398 r = signature_element_length(signature, &k);
1400 log_error("Invalid struct/dict entry signature.");
1406 memcpy(s, signature + 1, k - 2);
1409 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1411 return bus_log_create_error(r);
1413 r = message_append_cmdline(m, s, &p);
1420 r = sd_bus_message_close_container(m);
1424 case SD_BUS_TYPE_UNIX_FD:
1425 log_error("UNIX file descriptor not supported as type.");
1429 log_error("Unknown signature type %c.", t);
1434 return bus_log_create_error(r);
1441 static int call(sd_bus *bus, char *argv[]) {
1442 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1443 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1448 if (strv_length(argv) < 5) {
1449 log_error("Expects at least four arguments.");
1453 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1455 return bus_log_create_error(r);
1457 if (!isempty(argv[5])) {
1462 r = message_append_cmdline(m, argv[5], &p);
1467 log_error("Too many parameters for signature.");
1472 r = sd_bus_call(bus, m, 0, &error, &reply);
1474 log_error("%s", bus_error_message(&error, r));
1478 r = sd_bus_message_is_empty(reply);
1480 return bus_log_parse_error(r);
1482 if (r == 0 && !arg_quiet) {
1485 pager_open_if_enabled();
1487 r = bus_message_dump(reply, stdout, 0);
1492 fputs(sd_bus_message_get_signature(reply, true), stdout);
1495 r = format_cmdline(reply, stdout, false);
1497 return bus_log_parse_error(r);
1499 fputc('\n', stdout);
1506 static int get_property(sd_bus *bus, char *argv[]) {
1507 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1514 n = strv_length(argv);
1516 log_error("Expects at least four arguments.");
1520 STRV_FOREACH(i, argv + 4) {
1521 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1522 const char *contents = NULL;
1525 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1527 log_error("%s", bus_error_message(&error, r));
1531 r = sd_bus_message_peek_type(reply, &type, &contents);
1533 return bus_log_parse_error(r);
1535 r = sd_bus_message_enter_container(reply, 'v', contents);
1537 return bus_log_parse_error(r);
1540 pager_open_if_enabled();
1542 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1546 fputs(contents, stdout);
1549 r = format_cmdline(reply, stdout, false);
1551 return bus_log_parse_error(r);
1553 fputc('\n', stdout);
1556 r = sd_bus_message_exit_container(reply);
1558 return bus_log_parse_error(r);
1564 static int set_property(sd_bus *bus, char *argv[]) {
1565 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1566 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1573 n = strv_length(argv);
1575 log_error("Expects at least five arguments.");
1579 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1581 return bus_log_create_error(r);
1583 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1585 return bus_log_create_error(r);
1587 r = sd_bus_message_open_container(m, 'v', argv[5]);
1589 return bus_log_create_error(r);
1592 r = message_append_cmdline(m, argv[5], &p);
1596 r = sd_bus_message_close_container(m);
1598 return bus_log_create_error(r);
1601 log_error("Too many parameters for signature.");
1605 r = sd_bus_call(bus, m, 0, &error, NULL);
1607 log_error("%s", bus_error_message(&error, r));
1614 static int help(void) {
1615 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1616 "Introspect the bus.\n\n"
1617 " -h --help Show this help\n"
1618 " --version Show package version\n"
1619 " --no-pager Do not pipe output into a pager\n"
1620 " --no-legend Do not show the headers and footers\n"
1621 " --system Connect to system bus\n"
1622 " --user Connect to user bus\n"
1623 " -H --host=[USER@]HOST Operate on remote host\n"
1624 " -M --machine=CONTAINER Operate on local container\n"
1625 " --address=ADDRESS Connect to bus specified by address\n"
1626 " --show-machine Show machine ID column in list\n"
1627 " --unique Only show unique names\n"
1628 " --acquired Only show acquired names\n"
1629 " --activatable Only show activatable names\n"
1630 " --match=MATCH Only show matching messages\n"
1631 " --list Don't show tree, but simple object path list\n"
1632 " --quiet Don't show method call reply\n"
1633 " --verbose Show result values in long format\n\n"
1635 " list List bus names\n"
1636 " status SERVICE Show service name status\n"
1637 " monitor [SERVICE...] Show bus traffic\n"
1638 " capture [SERVICE...] Capture bus traffic as pcap\n"
1639 " tree [SERVICE...] Show object tree of service\n"
1640 " introspect SERVICE OBJECT\n"
1641 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1643 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1644 " Get property value\n"
1645 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1646 " Set property value\n"
1647 " help Show this help\n"
1648 , program_invocation_short_name);
1653 static int parse_argv(int argc, char *argv[]) {
1656 ARG_VERSION = 0x100,
1672 static const struct option options[] = {
1673 { "help", no_argument, NULL, 'h' },
1674 { "version", no_argument, NULL, ARG_VERSION },
1675 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1676 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1677 { "system", no_argument, NULL, ARG_SYSTEM },
1678 { "user", no_argument, NULL, ARG_USER },
1679 { "address", required_argument, NULL, ARG_ADDRESS },
1680 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1681 { "unique", no_argument, NULL, ARG_UNIQUE },
1682 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1683 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1684 { "match", required_argument, NULL, ARG_MATCH },
1685 { "host", required_argument, NULL, 'H' },
1686 { "machine", required_argument, NULL, 'M' },
1687 { "size", required_argument, NULL, ARG_SIZE },
1688 { "list", no_argument, NULL, ARG_LIST },
1689 { "quiet", no_argument, NULL, 'q' },
1690 { "verbose", no_argument, NULL, ARG_VERBOSE },
1699 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1707 puts(PACKAGE_STRING);
1708 puts(SYSTEMD_FEATURES);
1712 arg_no_pager = true;
1728 arg_address = optarg;
1731 case ARG_SHOW_MACHINE:
1732 arg_show_machine = true;
1740 arg_acquired = true;
1743 case ARG_ACTIVATABLE:
1744 arg_activatable = true;
1748 if (strv_extend(&arg_matches, optarg) < 0)
1755 r = parse_size(optarg, 0, &o);
1757 log_error("Failed to parse size: %s", optarg);
1761 if ((off_t) (size_t) o != o) {
1762 log_error("Size out of range.");
1766 arg_snaplen = (size_t) o;
1775 arg_transport = BUS_TRANSPORT_REMOTE;
1780 arg_transport = BUS_TRANSPORT_CONTAINER;
1796 assert_not_reached("Unhandled option");
1802 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1805 if (optind >= argc ||
1806 streq(argv[optind], "list"))
1807 return list_bus_names(bus, argv + optind);
1809 if (streq(argv[optind], "monitor"))
1810 return monitor(bus, argv + optind, message_dump);
1812 if (streq(argv[optind], "capture"))
1813 return capture(bus, argv + optind);
1815 if (streq(argv[optind], "status"))
1816 return status(bus, argv + optind);
1818 if (streq(argv[optind], "tree"))
1819 return tree(bus, argv + optind);
1821 if (streq(argv[optind], "introspect"))
1822 return introspect(bus, argv + optind);
1824 if (streq(argv[optind], "call"))
1825 return call(bus, argv + optind);
1827 if (streq(argv[optind], "get-property"))
1828 return get_property(bus, argv + optind);
1830 if (streq(argv[optind], "set-property"))
1831 return set_property(bus, argv + optind);
1833 if (streq(argv[optind], "help"))
1836 log_error("Unknown command '%s'", argv[optind]);
1840 int main(int argc, char *argv[]) {
1841 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1844 log_parse_environment();
1847 r = parse_argv(argc, argv);
1851 r = sd_bus_new(&bus);
1853 log_error("Failed to allocate bus: %s", strerror(-r));
1857 if (streq_ptr(argv[optind], "monitor") ||
1858 streq_ptr(argv[optind], "capture")) {
1860 r = sd_bus_set_monitor(bus, true);
1862 log_error("Failed to set monitor mode: %s", strerror(-r));
1866 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1868 log_error("Failed to enable credentials: %s", strerror(-r));
1872 r = sd_bus_negotiate_timestamp(bus, true);
1874 log_error("Failed to enable timestamps: %s", strerror(-r));
1878 r = sd_bus_negotiate_fds(bus, true);
1880 log_error("Failed to enable fds: %s", strerror(-r));
1886 r = sd_bus_set_address(bus, arg_address);
1888 r = sd_bus_set_bus_client(bus, true);
1890 log_error("Failed to set bus client: %s", strerror(-r));
1894 switch (arg_transport) {
1896 case BUS_TRANSPORT_LOCAL:
1898 r = bus_set_address_user(bus);
1900 r = bus_set_address_system(bus);
1903 case BUS_TRANSPORT_REMOTE:
1904 r = bus_set_address_system_remote(bus, arg_host);
1907 case BUS_TRANSPORT_CONTAINER:
1908 r = bus_set_address_system_container(bus, arg_host);
1912 assert_not_reached("Hmm, unknown transport type.");
1916 log_error("Failed to set address: %s", strerror(-r));
1920 r = sd_bus_start(bus);
1922 log_error("Failed to connect to bus: %s", strerror(-r));
1926 r = busctl_main(bus, argc, argv);
1931 strv_free(arg_matches);
1933 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;