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/>.
29 #include "path-util.h"
33 #include "bus-internal.h"
36 #include "bus-signature.h"
38 #include "busctl-introspect.h"
40 static bool arg_no_pager = false;
41 static bool arg_legend = true;
42 static char *arg_address = NULL;
43 static bool arg_unique = false;
44 static bool arg_acquired = false;
45 static bool arg_activatable = false;
46 static bool arg_show_machine = false;
47 static char **arg_matches = NULL;
48 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
49 static char *arg_host = NULL;
50 static bool arg_user = false;
51 static size_t arg_snaplen = 4096;
52 static bool arg_list = false;
53 static bool arg_quiet = false;
54 static bool arg_verbose = false;
55 static bool arg_expect_reply = true;
56 static bool arg_auto_start = true;
57 static bool arg_allow_interactive_authorization = true;
58 static bool arg_augment_creds = 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 return log_error_errno(r, "Failed to list names: %m");
94 pager_open_if_enabled();
96 names = hashmap_new(&string_hash_ops);
100 STRV_FOREACH(i, acquired) {
101 max_i = MAX(max_i, strlen(*i));
103 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
105 return log_error_errno(r, "Failed to add to hashmap: %m");
108 STRV_FOREACH(i, activatable) {
109 max_i = MAX(max_i, strlen(*i));
111 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
112 if (r < 0 && r != -EEXIST)
113 return log_error_errno(r, "Failed to add to hashmap: %m");
116 merged = new(char*, hashmap_size(names) + 1);
117 HASHMAP_FOREACH_KEY(v, k, names, iterator)
124 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
125 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
127 if (arg_show_machine)
133 STRV_FOREACH(i, merged) {
134 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
137 if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
140 printf("%-*s", (int) max_i, *i);
141 printf(" - - - (activatable) - - ");
142 if (arg_show_machine)
150 if (!arg_unique && (*i)[0] == ':')
153 if (!arg_acquired && (*i)[0] != ':')
156 printf("%-*s", (int) max_i, *i);
158 r = sd_bus_get_name_creds(
160 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
161 SD_BUS_CREDS_EUID|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_euid(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 = strjoina(prefix, draw_special_char(DRAW_TREE_VERTICAL));
258 space = strjoina(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 return log_error_errno(r, "Failed to get name list: %m");
437 pager_open_if_enabled();
439 STRV_FOREACH(i, names) {
442 if (!arg_unique && (*i)[0] == ':')
445 if (!arg_acquired && (*i)[0] == ':')
451 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
453 q = tree_one(bus, *i, NULL, true);
460 STRV_FOREACH(i, argv+1) {
467 pager_open_if_enabled();
468 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
471 q = tree_one(bus, *i, NULL, !!argv[2]);
480 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
484 const char *contents = NULL;
499 r = sd_bus_message_peek_type(m, &type, &contents);
503 if (bus_type_is_container(type) > 0) {
505 r = sd_bus_message_enter_container(m, type, contents);
509 if (type == SD_BUS_TYPE_ARRAY) {
512 /* count array entries */
515 r = sd_bus_message_skip(m, contents);
524 r = sd_bus_message_rewind(m, false);
532 } else if (type == SD_BUS_TYPE_VARIANT) {
537 fprintf(f, "%s", contents);
540 r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT));
544 r = sd_bus_message_exit_container(m);
551 r = sd_bus_message_read_basic(m, type, &basic);
559 case SD_BUS_TYPE_BYTE:
560 fprintf(f, "%u", basic.u8);
563 case SD_BUS_TYPE_BOOLEAN:
564 fputs(true_false(basic.i), f);
567 case SD_BUS_TYPE_INT16:
568 fprintf(f, "%i", basic.s16);
571 case SD_BUS_TYPE_UINT16:
572 fprintf(f, "%u", basic.u16);
575 case SD_BUS_TYPE_INT32:
576 fprintf(f, "%i", basic.s32);
579 case SD_BUS_TYPE_UINT32:
580 fprintf(f, "%u", basic.u32);
583 case SD_BUS_TYPE_INT64:
584 fprintf(f, "%" PRIi64, basic.s64);
587 case SD_BUS_TYPE_UINT64:
588 fprintf(f, "%" PRIu64, basic.u64);
591 case SD_BUS_TYPE_DOUBLE:
592 fprintf(f, "%g", basic.d64);
595 case SD_BUS_TYPE_STRING:
596 case SD_BUS_TYPE_OBJECT_PATH:
597 case SD_BUS_TYPE_SIGNATURE: {
598 _cleanup_free_ char *b = NULL;
600 b = cescape(basic.string);
604 fprintf(f, "\"%s\"", b);
608 case SD_BUS_TYPE_UNIX_FD:
609 fprintf(f, "%i", basic.i);
613 assert_not_reached("Unknown basic type.");
620 typedef struct Member {
631 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
638 ul = string_hash_func(m->type, hash_key);
641 ul ^= string_hash_func(m->name, hash_key);
644 ul ^= string_hash_func(m->interface, hash_key);
649 static int member_compare_func(const void *a, const void *b) {
650 const Member *x = a, *y = b;
658 if (!x->interface && y->interface)
660 if (x->interface && !y->interface)
662 if (x->interface && y->interface) {
663 d = strcmp(x->interface, y->interface);
668 d = strcmp(x->type, y->type);
672 if (!x->name && y->name)
674 if (x->name && !y->name)
676 if (x->name && y->name)
677 return strcmp(x->name, y->name);
682 static int member_compare_funcp(const void *a, const void *b) {
683 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
685 return member_compare_func(*x, *y);
688 static void member_free(Member *m) {
700 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
702 static void member_set_free(Set *s) {
705 while ((m = set_steal_first(s)))
711 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
713 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
714 _cleanup_(member_freep) Member *m;
715 Set *members = userdata;
725 m->type = "interface";
728 r = free_and_strdup(&m->interface, interface);
732 r = set_put(members, m);
734 log_error("Duplicate interface");
742 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
743 _cleanup_(member_freep) Member *m;
744 Set *members = userdata;
757 r = free_and_strdup(&m->interface, interface);
761 r = free_and_strdup(&m->name, name);
765 r = free_and_strdup(&m->signature, signature);
769 r = free_and_strdup(&m->result, result);
773 r = set_put(members, m);
775 log_error("Duplicate method");
783 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
784 _cleanup_(member_freep) Member *m;
785 Set *members = userdata;
798 r = free_and_strdup(&m->interface, interface);
802 r = free_and_strdup(&m->name, name);
806 r = free_and_strdup(&m->signature, signature);
810 r = set_put(members, m);
812 log_error("Duplicate signal");
820 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
821 _cleanup_(member_freep) Member *m;
822 Set *members = userdata;
832 m->type = "property";
834 m->writable = writable;
836 r = free_and_strdup(&m->interface, interface);
840 r = free_and_strdup(&m->name, name);
844 r = free_and_strdup(&m->signature, signature);
848 r = set_put(members, m);
850 log_error("Duplicate property");
858 static const char *strdash(const char *x) {
859 return isempty(x) ? "-" : x;
862 static int introspect(sd_bus *bus, char **argv) {
863 static const struct hash_ops member_hash_ops = {
864 .hash = member_hash_func,
865 .compare = member_compare_func,
868 static const XMLIntrospectOps ops = {
869 .on_interface = on_interface,
870 .on_method = on_method,
871 .on_signal = on_signal,
872 .on_property = on_property,
875 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
876 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
877 _cleanup_(member_set_freep) Set *members = NULL;
882 unsigned name_width, type_width, signature_width, result_width;
883 Member **sorted = NULL;
884 unsigned k = 0, j, n_args;
886 n_args = strv_length(argv);
888 log_error("Requires service and object path argument.");
893 log_error("Too many arguments.");
897 members = set_new(&member_hash_ops);
901 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
903 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
907 r = sd_bus_message_read(reply, "s", &xml);
909 return bus_log_parse_error(r);
911 /* First, get list of all properties */
912 r = parse_xml_introspect(argv[2], xml, &ops, members);
916 /* Second, find the current values for them */
917 SET_FOREACH(m, members, i) {
919 if (!streq(m->type, "property"))
925 if (argv[3] && !streq(argv[3], m->interface))
928 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
930 log_error("%s", bus_error_message(&error, r));
934 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
936 return bus_log_parse_error(r);
940 _cleanup_free_ char *buf = NULL;
941 _cleanup_fclose_ FILE *mf = NULL;
945 r = sd_bus_message_enter_container(reply, 'e', "sv");
947 return bus_log_parse_error(r);
952 r = sd_bus_message_read(reply, "s", &name);
954 return bus_log_parse_error(r);
956 r = sd_bus_message_enter_container(reply, 'v', NULL);
958 return bus_log_parse_error(r);
960 mf = open_memstream(&buf, &sz);
964 r = format_cmdline(reply, mf, false);
966 return bus_log_parse_error(r);
971 z = set_get(members, &((Member) {
973 .interface = m->interface,
974 .name = (char*) name }));
981 r = sd_bus_message_exit_container(reply);
983 return bus_log_parse_error(r);
985 r = sd_bus_message_exit_container(reply);
987 return bus_log_parse_error(r);
990 r = sd_bus_message_exit_container(reply);
992 return bus_log_parse_error(r);
995 pager_open_if_enabled();
997 name_width = strlen("NAME");
998 type_width = strlen("TYPE");
999 signature_width = strlen("SIGNATURE");
1000 result_width = strlen("RESULT/VALUE");
1002 sorted = newa(Member*, set_size(members));
1004 SET_FOREACH(m, members, i) {
1006 if (argv[3] && !streq(argv[3], m->interface))
1010 name_width = MAX(name_width, strlen(m->interface));
1012 name_width = MAX(name_width, strlen(m->name) + 1);
1014 type_width = MAX(type_width, strlen(m->type));
1016 signature_width = MAX(signature_width, strlen(m->signature));
1018 result_width = MAX(result_width, strlen(m->result));
1020 result_width = MAX(result_width, strlen(m->value));
1025 if (result_width > 40)
1028 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1031 printf("%-*s %-*s %-*s %-*s %s\n",
1032 (int) name_width, "NAME",
1033 (int) type_width, "TYPE",
1034 (int) signature_width, "SIGNATURE",
1035 (int) result_width, "RESULT/VALUE",
1039 for (j = 0; j < k; j++) {
1040 _cleanup_free_ char *ellipsized = NULL;
1046 if (argv[3] && !streq(argv[3], m->interface))
1049 is_interface = streq(m->type, "interface");
1051 if (argv[3] && is_interface)
1055 ellipsized = ellipsize(m->value, result_width, 100);
1061 rv = strdash(m->result);
1063 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1064 is_interface ? ansi_highlight() : "",
1065 is_interface ? "" : ".",
1066 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1067 is_interface ? ansi_highlight_off() : "",
1068 (int) type_width, strdash(m->type),
1069 (int) signature_width, strdash(m->signature),
1070 (int) result_width, rv,
1071 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1072 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1073 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1074 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1075 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1076 m->writable ? " writable" : "");
1082 static int message_dump(sd_bus_message *m, FILE *f) {
1083 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1086 static int message_pcap(sd_bus_message *m, FILE *f) {
1087 return bus_message_pcap_frame(m, arg_snaplen, f);
1090 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1091 bool added_something = false;
1095 STRV_FOREACH(i, argv+1) {
1096 _cleanup_free_ char *m = NULL;
1098 if (!service_name_is_valid(*i)) {
1099 log_error("Invalid service name '%s'", *i);
1103 m = strjoin("sender='", *i, "'", NULL);
1107 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1109 return log_error_errno(r, "Failed to add match: %m");
1111 added_something = true;
1114 STRV_FOREACH(i, arg_matches) {
1115 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1117 return log_error_errno(r, "Failed to add match: %m");
1119 added_something = true;
1122 if (!added_something) {
1123 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1125 return log_error_errno(r, "Failed to add match: %m");
1128 log_info("Monitoring bus message stream.");
1131 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1133 r = sd_bus_process(bus, &m);
1135 return log_error_errno(r, "Failed to process bus: %m");
1140 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1141 log_info("Connection terminated, exiting.");
1151 r = sd_bus_wait(bus, (uint64_t) -1);
1153 return log_error_errno(r, "Failed to wait for bus: %m");
1157 static int capture(sd_bus *bus, char *argv[]) {
1160 if (isatty(fileno(stdout)) > 0) {
1161 log_error("Refusing to write message data to console, please redirect output to a file.");
1165 bus_pcap_header(arg_snaplen, stdout);
1167 r = monitor(bus, argv, message_pcap);
1171 if (ferror(stdout)) {
1172 log_error("Couldn't write capture file.");
1179 static int status(sd_bus *bus, char *argv[]) {
1180 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1186 if (strv_length(argv) > 2) {
1187 log_error("Expects no or one argument.");
1192 r = parse_pid(argv[1], &pid);
1194 r = sd_bus_get_name_creds(
1197 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1200 r = sd_bus_creds_new_from_pid(
1205 const char *scope, *address;
1208 r = sd_bus_get_address(bus, &address);
1210 printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off());
1212 r = sd_bus_get_scope(bus, &scope);
1214 printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off());
1216 r = sd_bus_get_bus_id(bus, &bus_id);
1218 printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off());
1220 r = sd_bus_get_owner_creds(
1222 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1227 return log_error_errno(r, "Failed to get credentials: %m");
1229 bus_creds_dump(creds, NULL, false);
1233 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1253 log_error("Too few parameters for signature.");
1262 case SD_BUS_TYPE_BOOLEAN:
1264 r = parse_boolean(v);
1266 log_error("Failed to parse as boolean: %s", v);
1270 r = sd_bus_message_append_basic(m, t, &r);
1273 case SD_BUS_TYPE_BYTE: {
1276 r = safe_atou8(v, &z);
1278 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1282 r = sd_bus_message_append_basic(m, t, &z);
1286 case SD_BUS_TYPE_INT16: {
1289 r = safe_atoi16(v, &z);
1291 log_error("Failed to parse as signed 16bit integer: %s", v);
1295 r = sd_bus_message_append_basic(m, t, &z);
1299 case SD_BUS_TYPE_UINT16: {
1302 r = safe_atou16(v, &z);
1304 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1308 r = sd_bus_message_append_basic(m, t, &z);
1312 case SD_BUS_TYPE_INT32: {
1315 r = safe_atoi32(v, &z);
1317 log_error("Failed to parse as signed 32bit integer: %s", v);
1321 r = sd_bus_message_append_basic(m, t, &z);
1325 case SD_BUS_TYPE_UINT32: {
1328 r = safe_atou32(v, &z);
1330 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1334 r = sd_bus_message_append_basic(m, t, &z);
1338 case SD_BUS_TYPE_INT64: {
1341 r = safe_atoi64(v, &z);
1343 log_error("Failed to parse as signed 64bit integer: %s", v);
1347 r = sd_bus_message_append_basic(m, t, &z);
1351 case SD_BUS_TYPE_UINT64: {
1354 r = safe_atou64(v, &z);
1356 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1360 r = sd_bus_message_append_basic(m, t, &z);
1365 case SD_BUS_TYPE_DOUBLE: {
1368 r = safe_atod(v, &z);
1370 log_error("Failed to parse as double precision floating point: %s", v);
1374 r = sd_bus_message_append_basic(m, t, &z);
1378 case SD_BUS_TYPE_STRING:
1379 case SD_BUS_TYPE_OBJECT_PATH:
1380 case SD_BUS_TYPE_SIGNATURE:
1382 r = sd_bus_message_append_basic(m, t, v);
1385 case SD_BUS_TYPE_ARRAY: {
1389 r = safe_atou32(v, &n);
1391 log_error("Failed to parse number of array entries: %s", v);
1395 r = signature_element_length(signature, &k);
1397 log_error("Invalid array signature.");
1404 memcpy(s, signature, k);
1407 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1409 return bus_log_create_error(r);
1411 for (i = 0; i < n; i++) {
1412 r = message_append_cmdline(m, s, &p);
1420 r = sd_bus_message_close_container(m);
1424 case SD_BUS_TYPE_VARIANT:
1425 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1427 return bus_log_create_error(r);
1429 r = message_append_cmdline(m, v, &p);
1433 r = sd_bus_message_close_container(m);
1436 case SD_BUS_TYPE_STRUCT_BEGIN:
1437 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1443 r = signature_element_length(signature, &k);
1445 log_error("Invalid struct/dict entry signature.");
1451 memcpy(s, signature + 1, k - 2);
1454 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1456 return bus_log_create_error(r);
1458 r = message_append_cmdline(m, s, &p);
1465 r = sd_bus_message_close_container(m);
1469 case SD_BUS_TYPE_UNIX_FD:
1470 log_error("UNIX file descriptor not supported as type.");
1474 log_error("Unknown signature type %c.", t);
1479 return bus_log_create_error(r);
1486 static int call(sd_bus *bus, char *argv[]) {
1487 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1488 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1493 if (strv_length(argv) < 5) {
1494 log_error("Expects at least four arguments.");
1498 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1500 return bus_log_create_error(r);
1502 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1504 return bus_log_create_error(r);
1506 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1508 return bus_log_create_error(r);
1510 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1512 return bus_log_create_error(r);
1514 if (!isempty(argv[5])) {
1519 r = message_append_cmdline(m, argv[5], &p);
1524 log_error("Too many parameters for signature.");
1529 if (!arg_expect_reply) {
1530 r = sd_bus_send(bus, m, NULL);
1532 log_error("Failed to send message.");
1539 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1541 log_error("%s", bus_error_message(&error, r));
1545 r = sd_bus_message_is_empty(reply);
1547 return bus_log_parse_error(r);
1549 if (r == 0 && !arg_quiet) {
1552 pager_open_if_enabled();
1554 r = bus_message_dump(reply, stdout, 0);
1559 fputs(sd_bus_message_get_signature(reply, true), stdout);
1562 r = format_cmdline(reply, stdout, false);
1564 return bus_log_parse_error(r);
1566 fputc('\n', stdout);
1573 static int get_property(sd_bus *bus, char *argv[]) {
1574 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1581 n = strv_length(argv);
1583 log_error("Expects at least four arguments.");
1587 STRV_FOREACH(i, argv + 4) {
1588 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1589 const char *contents = NULL;
1592 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1594 log_error("%s", bus_error_message(&error, r));
1598 r = sd_bus_message_peek_type(reply, &type, &contents);
1600 return bus_log_parse_error(r);
1602 r = sd_bus_message_enter_container(reply, 'v', contents);
1604 return bus_log_parse_error(r);
1607 pager_open_if_enabled();
1609 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1613 fputs(contents, stdout);
1616 r = format_cmdline(reply, stdout, false);
1618 return bus_log_parse_error(r);
1620 fputc('\n', stdout);
1623 r = sd_bus_message_exit_container(reply);
1625 return bus_log_parse_error(r);
1631 static int set_property(sd_bus *bus, char *argv[]) {
1632 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1633 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1640 n = strv_length(argv);
1642 log_error("Expects at least five arguments.");
1646 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1648 return bus_log_create_error(r);
1650 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1652 return bus_log_create_error(r);
1654 r = sd_bus_message_open_container(m, 'v', argv[5]);
1656 return bus_log_create_error(r);
1659 r = message_append_cmdline(m, argv[5], &p);
1663 r = sd_bus_message_close_container(m);
1665 return bus_log_create_error(r);
1668 log_error("Too many parameters for signature.");
1672 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1674 log_error("%s", bus_error_message(&error, r));
1681 static int help(void) {
1682 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1683 "Introspect the bus.\n\n"
1684 " -h --help Show this help\n"
1685 " --version Show package version\n"
1686 " --no-pager Do not pipe output into a pager\n"
1687 " --no-legend Do not show the headers and footers\n"
1688 " --system Connect to system bus\n"
1689 " --user Connect to user bus\n"
1690 " -H --host=[USER@]HOST Operate on remote host\n"
1691 " -M --machine=CONTAINER Operate on local container\n"
1692 " --address=ADDRESS Connect to bus specified by address\n"
1693 " --show-machine Show machine ID column in list\n"
1694 " --unique Only show unique names\n"
1695 " --acquired Only show acquired names\n"
1696 " --activatable Only show activatable names\n"
1697 " --match=MATCH Only show matching messages\n"
1698 " --list Don't show tree, but simple object path list\n"
1699 " --quiet Don't show method call reply\n"
1700 " --verbose Show result values in long format\n"
1701 " --expect-reply=BOOL Expect a method call reply\n"
1702 " --auto-start=BOOL Auto-start destination service\n"
1703 " --allow-interactive-authorization=BOOL\n"
1704 " Allow interactive authorization for operation\n"
1705 " --timeout=SECS Maximum time to wait for method call completion\n"
1706 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1708 " list List bus names\n"
1709 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1710 " monitor [SERVICE...] Show bus traffic\n"
1711 " capture [SERVICE...] Capture bus traffic as pcap\n"
1712 " tree [SERVICE...] Show object tree of service\n"
1713 " introspect SERVICE OBJECT [INTERFACE]\n"
1714 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1716 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1717 " Get property value\n"
1718 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1719 " Set property value\n"
1720 " help Show this help\n"
1721 , program_invocation_short_name);
1726 static int parse_argv(int argc, char *argv[]) {
1729 ARG_VERSION = 0x100,
1745 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1750 static const struct option options[] = {
1751 { "help", no_argument, NULL, 'h' },
1752 { "version", no_argument, NULL, ARG_VERSION },
1753 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1754 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1755 { "system", no_argument, NULL, ARG_SYSTEM },
1756 { "user", no_argument, NULL, ARG_USER },
1757 { "address", required_argument, NULL, ARG_ADDRESS },
1758 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1759 { "unique", no_argument, NULL, ARG_UNIQUE },
1760 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1761 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1762 { "match", required_argument, NULL, ARG_MATCH },
1763 { "host", required_argument, NULL, 'H' },
1764 { "machine", required_argument, NULL, 'M' },
1765 { "size", required_argument, NULL, ARG_SIZE },
1766 { "list", no_argument, NULL, ARG_LIST },
1767 { "quiet", no_argument, NULL, 'q' },
1768 { "verbose", no_argument, NULL, ARG_VERBOSE },
1769 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1770 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1771 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1772 { "timeout", required_argument, NULL, ARG_TIMEOUT },
1773 { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
1782 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1790 puts(PACKAGE_STRING);
1791 puts(SYSTEMD_FEATURES);
1795 arg_no_pager = true;
1811 arg_address = optarg;
1814 case ARG_SHOW_MACHINE:
1815 arg_show_machine = true;
1823 arg_acquired = true;
1826 case ARG_ACTIVATABLE:
1827 arg_activatable = true;
1831 if (strv_extend(&arg_matches, optarg) < 0)
1838 r = parse_size(optarg, 0, &o);
1840 log_error("Failed to parse size: %s", optarg);
1844 if ((off_t) (size_t) o != o) {
1845 log_error("Size out of range.");
1849 arg_snaplen = (size_t) o;
1858 arg_transport = BUS_TRANSPORT_REMOTE;
1863 arg_transport = BUS_TRANSPORT_MACHINE;
1875 case ARG_EXPECT_REPLY:
1876 r = parse_boolean(optarg);
1878 log_error("Failed to parse --expect-reply= parameter.");
1882 arg_expect_reply = !!r;
1886 case ARG_AUTO_START:
1887 r = parse_boolean(optarg);
1889 log_error("Failed to parse --auto-start= parameter.");
1893 arg_auto_start = !!r;
1897 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1898 r = parse_boolean(optarg);
1900 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1904 arg_allow_interactive_authorization = !!r;
1908 r = parse_sec(optarg, &arg_timeout);
1910 log_error("Failed to parse --timeout= parameter.");
1916 case ARG_AUGMENT_CREDS:
1917 r = parse_boolean(optarg);
1919 log_error("Failed to parse --augment-creds= parameter.");
1923 arg_augment_creds = !!r;
1930 assert_not_reached("Unhandled option");
1936 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1939 if (optind >= argc ||
1940 streq(argv[optind], "list"))
1941 return list_bus_names(bus, argv + optind);
1943 if (streq(argv[optind], "monitor"))
1944 return monitor(bus, argv + optind, message_dump);
1946 if (streq(argv[optind], "capture"))
1947 return capture(bus, argv + optind);
1949 if (streq(argv[optind], "status"))
1950 return status(bus, argv + optind);
1952 if (streq(argv[optind], "tree"))
1953 return tree(bus, argv + optind);
1955 if (streq(argv[optind], "introspect"))
1956 return introspect(bus, argv + optind);
1958 if (streq(argv[optind], "call"))
1959 return call(bus, argv + optind);
1961 if (streq(argv[optind], "get-property"))
1962 return get_property(bus, argv + optind);
1964 if (streq(argv[optind], "set-property"))
1965 return set_property(bus, argv + optind);
1967 if (streq(argv[optind], "help"))
1970 log_error("Unknown command '%s'", argv[optind]);
1974 int main(int argc, char *argv[]) {
1975 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1978 log_parse_environment();
1981 r = parse_argv(argc, argv);
1985 r = sd_bus_new(&bus);
1987 log_error_errno(r, "Failed to allocate bus: %m");
1991 if (streq_ptr(argv[optind], "monitor") ||
1992 streq_ptr(argv[optind], "capture")) {
1994 r = sd_bus_set_monitor(bus, true);
1996 log_error_errno(r, "Failed to set monitor mode: %m");
2000 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
2002 log_error_errno(r, "Failed to enable credentials: %m");
2006 r = sd_bus_negotiate_timestamp(bus, true);
2008 log_error_errno(r, "Failed to enable timestamps: %m");
2012 r = sd_bus_negotiate_fds(bus, true);
2014 log_error_errno(r, "Failed to enable fds: %m");
2020 r = sd_bus_set_address(bus, arg_address);
2022 r = sd_bus_set_bus_client(bus, true);
2024 log_error_errno(r, "Failed to set bus client: %m");
2028 switch (arg_transport) {
2030 case BUS_TRANSPORT_LOCAL:
2032 bus->is_user = true;
2033 r = bus_set_address_user(bus);
2035 bus->is_system = true;
2036 r = bus_set_address_system(bus);
2040 case BUS_TRANSPORT_REMOTE:
2041 r = bus_set_address_system_remote(bus, arg_host);
2044 case BUS_TRANSPORT_MACHINE:
2045 r = bus_set_address_system_machine(bus, arg_host);
2049 assert_not_reached("Hmm, unknown transport type.");
2053 log_error_errno(r, "Failed to set address: %m");
2057 r = sd_bus_start(bus);
2059 log_error_errno(r, "Failed to connect to bus: %m");
2063 r = busctl_main(bus, argc, argv);
2068 strv_free(arg_matches);
2070 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;