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"
39 #include "terminal-util.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 bool arg_augment_creds = true;
60 static usec_t arg_timeout = 0;
62 static void pager_open_if_enabled(void) {
64 /* Cache result before we open the pager */
71 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
72 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
74 static int list_bus_names(sd_bus *bus, char **argv) {
75 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
76 _cleanup_free_ char **merged = NULL;
77 _cleanup_hashmap_free_ Hashmap *names = NULL;
88 if (!arg_unique && !arg_acquired && !arg_activatable)
89 arg_unique = arg_acquired = arg_activatable = true;
91 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
93 return log_error_errno(r, "Failed to list names: %m");
95 pager_open_if_enabled();
97 names = hashmap_new(&string_hash_ops);
101 STRV_FOREACH(i, acquired) {
102 max_i = MAX(max_i, strlen(*i));
104 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
106 return log_error_errno(r, "Failed to add to hashmap: %m");
109 STRV_FOREACH(i, activatable) {
110 max_i = MAX(max_i, strlen(*i));
112 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
113 if (r < 0 && r != -EEXIST)
114 return log_error_errno(r, "Failed to add to hashmap: %m");
117 merged = new(char*, hashmap_size(names) + 1);
118 HASHMAP_FOREACH_KEY(v, k, names, iterator)
125 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
126 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
128 if (arg_show_machine)
134 STRV_FOREACH(i, merged) {
135 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
138 if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
141 printf("%-*s", (int) max_i, *i);
142 printf(" - - - (activatable) - - ");
143 if (arg_show_machine)
151 if (!arg_unique && (*i)[0] == ':')
154 if (!arg_acquired && (*i)[0] != ':')
157 printf("%-*s", (int) max_i, *i);
159 r = sd_bus_get_name_creds(
161 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
162 SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
163 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
164 SD_BUS_CREDS_DESCRIPTION, &creds);
166 const char *unique, *session, *unit, *cn;
170 r = sd_bus_creds_get_pid(creds, &pid);
172 const char *comm = NULL;
174 sd_bus_creds_get_comm(creds, &comm);
176 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
178 fputs(" - - ", stdout);
180 r = sd_bus_creds_get_euid(creds, &uid);
182 _cleanup_free_ char *u = NULL;
184 u = uid_to_name(uid);
193 fputs(" - ", stdout);
195 r = sd_bus_creds_get_unique_name(creds, &unique);
197 printf(" %-13s", unique);
199 fputs(" - ", stdout);
201 r = sd_bus_creds_get_unit(creds, &unit);
203 _cleanup_free_ char *e;
205 e = ellipsize(unit, 25, 100);
211 fputs(" - ", stdout);
213 r = sd_bus_creds_get_session(creds, &session);
215 printf(" %-10s", session);
217 fputs(" - ", stdout);
219 r = sd_bus_creds_get_description(creds, &cn);
221 printf(" %-19s", cn);
223 fputs(" - ", stdout);
226 printf(" - - - - - - - ");
228 if (arg_show_machine) {
229 r = sd_bus_get_name_machine_id(bus, *i, &mid);
231 char m[SD_ID128_STRING_MAX];
232 printf(" %s\n", sd_id128_to_string(mid, m));
242 static void print_subtree(const char *prefix, const char *path, char **l) {
243 const char *vertical, *space;
246 /* We assume the list is sorted. Let's first skip over the
247 * entry we are looking at. */
252 if (!streq(*l, path))
258 vertical = strjoina(prefix, draw_special_char(DRAW_TREE_VERTICAL));
259 space = strjoina(prefix, draw_special_char(DRAW_TREE_SPACE));
262 bool has_more = false;
264 if (!*l || !path_startswith(*l, path))
269 if (!*n || !path_startswith(*n, path))
272 if (!path_startswith(*n, *l)) {
280 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
282 print_subtree(has_more ? vertical : space, *l, l);
287 static void print_tree(const char *prefix, char **l) {
289 pager_open_if_enabled();
291 prefix = strempty(prefix);
297 printf("%s%s\n", prefix, *i);
301 if (strv_isempty(l)) {
302 printf("No objects discovered.\n");
306 if (streq(l[0], "/") && !l[1]) {
307 printf("Only root object discovered.\n");
311 print_subtree(prefix, "/", l);
314 static int on_path(const char *path, void *userdata) {
315 Set *paths = userdata;
320 r = set_put_strdup(paths, path);
327 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
328 static const XMLIntrospectOps ops = {
332 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
333 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
337 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
340 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
342 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
346 r = sd_bus_message_read(reply, "s", &xml);
348 return bus_log_parse_error(r);
350 return parse_xml_introspect(path, xml, &ops, paths);
353 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
354 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
355 _cleanup_free_ char **l = NULL;
359 paths = set_new(&string_hash_ops);
363 done = set_new(&string_hash_ops);
367 failed = set_new(&string_hash_ops);
375 r = set_put(paths, m);
382 _cleanup_free_ char *p = NULL;
385 p = set_steal_first(paths);
389 if (set_contains(done, p) ||
390 set_contains(failed, p))
393 q = find_nodes(bus, service, p, paths, many);
398 q = set_put(failed, p);
400 q = set_put(done, p);
409 pager_open_if_enabled();
411 l = set_get_strv(done);
416 print_tree(prefix, l);
423 static int tree(sd_bus *bus, char **argv) {
427 if (!arg_unique && !arg_acquired)
430 if (strv_length(argv) <= 1) {
431 _cleanup_strv_free_ char **names = NULL;
432 bool not_first = false;
434 r = sd_bus_list_names(bus, &names, NULL);
436 return log_error_errno(r, "Failed to get name list: %m");
438 pager_open_if_enabled();
440 STRV_FOREACH(i, names) {
443 if (!arg_unique && (*i)[0] == ':')
446 if (!arg_acquired && (*i)[0] == ':')
452 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
454 q = tree_one(bus, *i, NULL, true);
461 STRV_FOREACH(i, argv+1) {
468 pager_open_if_enabled();
469 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
472 q = tree_one(bus, *i, NULL, !!argv[2]);
481 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
485 const char *contents = NULL;
500 r = sd_bus_message_peek_type(m, &type, &contents);
504 if (bus_type_is_container(type) > 0) {
506 r = sd_bus_message_enter_container(m, type, contents);
510 if (type == SD_BUS_TYPE_ARRAY) {
513 /* count array entries */
516 r = sd_bus_message_skip(m, contents);
525 r = sd_bus_message_rewind(m, false);
533 } else if (type == SD_BUS_TYPE_VARIANT) {
538 fprintf(f, "%s", contents);
541 r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT));
545 r = sd_bus_message_exit_container(m);
552 r = sd_bus_message_read_basic(m, type, &basic);
560 case SD_BUS_TYPE_BYTE:
561 fprintf(f, "%u", basic.u8);
564 case SD_BUS_TYPE_BOOLEAN:
565 fputs(true_false(basic.i), f);
568 case SD_BUS_TYPE_INT16:
569 fprintf(f, "%i", basic.s16);
572 case SD_BUS_TYPE_UINT16:
573 fprintf(f, "%u", basic.u16);
576 case SD_BUS_TYPE_INT32:
577 fprintf(f, "%i", basic.s32);
580 case SD_BUS_TYPE_UINT32:
581 fprintf(f, "%u", basic.u32);
584 case SD_BUS_TYPE_INT64:
585 fprintf(f, "%" PRIi64, basic.s64);
588 case SD_BUS_TYPE_UINT64:
589 fprintf(f, "%" PRIu64, basic.u64);
592 case SD_BUS_TYPE_DOUBLE:
593 fprintf(f, "%g", basic.d64);
596 case SD_BUS_TYPE_STRING:
597 case SD_BUS_TYPE_OBJECT_PATH:
598 case SD_BUS_TYPE_SIGNATURE: {
599 _cleanup_free_ char *b = NULL;
601 b = cescape(basic.string);
605 fprintf(f, "\"%s\"", b);
609 case SD_BUS_TYPE_UNIX_FD:
610 fprintf(f, "%i", basic.i);
614 assert_not_reached("Unknown basic type.");
621 typedef struct Member {
632 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
639 ul = string_hash_func(m->type, hash_key);
642 ul ^= string_hash_func(m->name, hash_key);
645 ul ^= string_hash_func(m->interface, hash_key);
650 static int member_compare_func(const void *a, const void *b) {
651 const Member *x = a, *y = b;
659 if (!x->interface && y->interface)
661 if (x->interface && !y->interface)
663 if (x->interface && y->interface) {
664 d = strcmp(x->interface, y->interface);
669 d = strcmp(x->type, y->type);
673 if (!x->name && y->name)
675 if (x->name && !y->name)
677 if (x->name && y->name)
678 return strcmp(x->name, y->name);
683 static int member_compare_funcp(const void *a, const void *b) {
684 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
686 return member_compare_func(*x, *y);
689 static void member_free(Member *m) {
701 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
703 static void member_set_free(Set *s) {
706 while ((m = set_steal_first(s)))
712 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
714 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
715 _cleanup_(member_freep) Member *m;
716 Set *members = userdata;
726 m->type = "interface";
729 r = free_and_strdup(&m->interface, interface);
733 r = set_put(members, m);
735 log_error("Duplicate interface");
743 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
744 _cleanup_(member_freep) Member *m;
745 Set *members = userdata;
758 r = free_and_strdup(&m->interface, interface);
762 r = free_and_strdup(&m->name, name);
766 r = free_and_strdup(&m->signature, signature);
770 r = free_and_strdup(&m->result, result);
774 r = set_put(members, m);
776 log_error("Duplicate method");
784 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
785 _cleanup_(member_freep) Member *m;
786 Set *members = userdata;
799 r = free_and_strdup(&m->interface, interface);
803 r = free_and_strdup(&m->name, name);
807 r = free_and_strdup(&m->signature, signature);
811 r = set_put(members, m);
813 log_error("Duplicate signal");
821 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
822 _cleanup_(member_freep) Member *m;
823 Set *members = userdata;
833 m->type = "property";
835 m->writable = writable;
837 r = free_and_strdup(&m->interface, interface);
841 r = free_and_strdup(&m->name, name);
845 r = free_and_strdup(&m->signature, signature);
849 r = set_put(members, m);
851 log_error("Duplicate property");
859 static const char *strdash(const char *x) {
860 return isempty(x) ? "-" : x;
863 static int introspect(sd_bus *bus, char **argv) {
864 static const struct hash_ops member_hash_ops = {
865 .hash = member_hash_func,
866 .compare = member_compare_func,
869 static const XMLIntrospectOps ops = {
870 .on_interface = on_interface,
871 .on_method = on_method,
872 .on_signal = on_signal,
873 .on_property = on_property,
876 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
877 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
878 _cleanup_(member_set_freep) Set *members = NULL;
883 unsigned name_width, type_width, signature_width, result_width;
884 Member **sorted = NULL;
885 unsigned k = 0, j, n_args;
887 n_args = strv_length(argv);
889 log_error("Requires service and object path argument.");
894 log_error("Too many arguments.");
898 members = set_new(&member_hash_ops);
902 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
904 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
908 r = sd_bus_message_read(reply, "s", &xml);
910 return bus_log_parse_error(r);
912 /* First, get list of all properties */
913 r = parse_xml_introspect(argv[2], xml, &ops, members);
917 /* Second, find the current values for them */
918 SET_FOREACH(m, members, i) {
920 if (!streq(m->type, "property"))
926 if (argv[3] && !streq(argv[3], m->interface))
929 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
931 log_error("%s", bus_error_message(&error, r));
935 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
937 return bus_log_parse_error(r);
941 _cleanup_free_ char *buf = NULL;
942 _cleanup_fclose_ FILE *mf = NULL;
946 r = sd_bus_message_enter_container(reply, 'e', "sv");
948 return bus_log_parse_error(r);
953 r = sd_bus_message_read(reply, "s", &name);
955 return bus_log_parse_error(r);
957 r = sd_bus_message_enter_container(reply, 'v', NULL);
959 return bus_log_parse_error(r);
961 mf = open_memstream(&buf, &sz);
965 r = format_cmdline(reply, mf, false);
967 return bus_log_parse_error(r);
972 z = set_get(members, &((Member) {
974 .interface = m->interface,
975 .name = (char*) name }));
982 r = sd_bus_message_exit_container(reply);
984 return bus_log_parse_error(r);
986 r = sd_bus_message_exit_container(reply);
988 return bus_log_parse_error(r);
991 r = sd_bus_message_exit_container(reply);
993 return bus_log_parse_error(r);
996 pager_open_if_enabled();
998 name_width = strlen("NAME");
999 type_width = strlen("TYPE");
1000 signature_width = strlen("SIGNATURE");
1001 result_width = strlen("RESULT/VALUE");
1003 sorted = newa(Member*, set_size(members));
1005 SET_FOREACH(m, members, i) {
1007 if (argv[3] && !streq(argv[3], m->interface))
1011 name_width = MAX(name_width, strlen(m->interface));
1013 name_width = MAX(name_width, strlen(m->name) + 1);
1015 type_width = MAX(type_width, strlen(m->type));
1017 signature_width = MAX(signature_width, strlen(m->signature));
1019 result_width = MAX(result_width, strlen(m->result));
1021 result_width = MAX(result_width, strlen(m->value));
1026 if (result_width > 40)
1029 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1032 printf("%-*s %-*s %-*s %-*s %s\n",
1033 (int) name_width, "NAME",
1034 (int) type_width, "TYPE",
1035 (int) signature_width, "SIGNATURE",
1036 (int) result_width, "RESULT/VALUE",
1040 for (j = 0; j < k; j++) {
1041 _cleanup_free_ char *ellipsized = NULL;
1047 if (argv[3] && !streq(argv[3], m->interface))
1050 is_interface = streq(m->type, "interface");
1052 if (argv[3] && is_interface)
1056 ellipsized = ellipsize(m->value, result_width, 100);
1062 rv = strdash(m->result);
1064 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1065 is_interface ? ansi_highlight() : "",
1066 is_interface ? "" : ".",
1067 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1068 is_interface ? ansi_highlight_off() : "",
1069 (int) type_width, strdash(m->type),
1070 (int) signature_width, strdash(m->signature),
1071 (int) result_width, rv,
1072 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1073 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1074 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1075 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1076 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1077 m->writable ? " writable" : "");
1083 static int message_dump(sd_bus_message *m, FILE *f) {
1084 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1087 static int message_pcap(sd_bus_message *m, FILE *f) {
1088 return bus_message_pcap_frame(m, arg_snaplen, f);
1091 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1092 bool added_something = false;
1096 STRV_FOREACH(i, argv+1) {
1097 _cleanup_free_ char *m = NULL;
1099 if (!service_name_is_valid(*i)) {
1100 log_error("Invalid service name '%s'", *i);
1104 m = strjoin("sender='", *i, "'", NULL);
1108 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1110 return log_error_errno(r, "Failed to add match: %m");
1112 added_something = true;
1115 STRV_FOREACH(i, arg_matches) {
1116 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1118 return log_error_errno(r, "Failed to add match: %m");
1120 added_something = true;
1123 if (!added_something) {
1124 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1126 return log_error_errno(r, "Failed to add match: %m");
1129 log_info("Monitoring bus message stream.");
1132 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1134 r = sd_bus_process(bus, &m);
1136 return log_error_errno(r, "Failed to process bus: %m");
1141 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1142 log_info("Connection terminated, exiting.");
1152 r = sd_bus_wait(bus, (uint64_t) -1);
1154 return log_error_errno(r, "Failed to wait for bus: %m");
1158 static int capture(sd_bus *bus, char *argv[]) {
1161 if (isatty(fileno(stdout)) > 0) {
1162 log_error("Refusing to write message data to console, please redirect output to a file.");
1166 bus_pcap_header(arg_snaplen, stdout);
1168 r = monitor(bus, argv, message_pcap);
1172 if (ferror(stdout)) {
1173 log_error("Couldn't write capture file.");
1180 static int status(sd_bus *bus, char *argv[]) {
1181 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1187 if (strv_length(argv) > 2) {
1188 log_error("Expects no or one argument.");
1193 r = parse_pid(argv[1], &pid);
1195 r = sd_bus_get_name_creds(
1198 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1201 r = sd_bus_creds_new_from_pid(
1206 const char *scope, *address;
1209 r = sd_bus_get_address(bus, &address);
1211 printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off());
1213 r = sd_bus_get_scope(bus, &scope);
1215 printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off());
1217 r = sd_bus_get_bus_id(bus, &bus_id);
1219 printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off());
1221 r = sd_bus_get_owner_creds(
1223 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1228 return log_error_errno(r, "Failed to get credentials: %m");
1230 bus_creds_dump(creds, NULL, false);
1234 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1254 log_error("Too few parameters for signature.");
1263 case SD_BUS_TYPE_BOOLEAN:
1265 r = parse_boolean(v);
1267 log_error("Failed to parse as boolean: %s", v);
1271 r = sd_bus_message_append_basic(m, t, &r);
1274 case SD_BUS_TYPE_BYTE: {
1277 r = safe_atou8(v, &z);
1279 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1283 r = sd_bus_message_append_basic(m, t, &z);
1287 case SD_BUS_TYPE_INT16: {
1290 r = safe_atoi16(v, &z);
1292 log_error("Failed to parse as signed 16bit integer: %s", v);
1296 r = sd_bus_message_append_basic(m, t, &z);
1300 case SD_BUS_TYPE_UINT16: {
1303 r = safe_atou16(v, &z);
1305 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1309 r = sd_bus_message_append_basic(m, t, &z);
1313 case SD_BUS_TYPE_INT32: {
1316 r = safe_atoi32(v, &z);
1318 log_error("Failed to parse as signed 32bit integer: %s", v);
1322 r = sd_bus_message_append_basic(m, t, &z);
1326 case SD_BUS_TYPE_UINT32: {
1329 r = safe_atou32(v, &z);
1331 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1335 r = sd_bus_message_append_basic(m, t, &z);
1339 case SD_BUS_TYPE_INT64: {
1342 r = safe_atoi64(v, &z);
1344 log_error("Failed to parse as signed 64bit integer: %s", v);
1348 r = sd_bus_message_append_basic(m, t, &z);
1352 case SD_BUS_TYPE_UINT64: {
1355 r = safe_atou64(v, &z);
1357 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1361 r = sd_bus_message_append_basic(m, t, &z);
1366 case SD_BUS_TYPE_DOUBLE: {
1369 r = safe_atod(v, &z);
1371 log_error("Failed to parse as double precision floating point: %s", v);
1375 r = sd_bus_message_append_basic(m, t, &z);
1379 case SD_BUS_TYPE_STRING:
1380 case SD_BUS_TYPE_OBJECT_PATH:
1381 case SD_BUS_TYPE_SIGNATURE:
1383 r = sd_bus_message_append_basic(m, t, v);
1386 case SD_BUS_TYPE_ARRAY: {
1390 r = safe_atou32(v, &n);
1392 log_error("Failed to parse number of array entries: %s", v);
1396 r = signature_element_length(signature, &k);
1398 log_error("Invalid array signature.");
1405 memcpy(s, signature, k);
1408 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1410 return bus_log_create_error(r);
1412 for (i = 0; i < n; i++) {
1413 r = message_append_cmdline(m, s, &p);
1421 r = sd_bus_message_close_container(m);
1425 case SD_BUS_TYPE_VARIANT:
1426 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1428 return bus_log_create_error(r);
1430 r = message_append_cmdline(m, v, &p);
1434 r = sd_bus_message_close_container(m);
1437 case SD_BUS_TYPE_STRUCT_BEGIN:
1438 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1444 r = signature_element_length(signature, &k);
1446 log_error("Invalid struct/dict entry signature.");
1452 memcpy(s, signature + 1, k - 2);
1455 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1457 return bus_log_create_error(r);
1459 r = message_append_cmdline(m, s, &p);
1466 r = sd_bus_message_close_container(m);
1470 case SD_BUS_TYPE_UNIX_FD:
1471 log_error("UNIX file descriptor not supported as type.");
1475 log_error("Unknown signature type %c.", t);
1480 return bus_log_create_error(r);
1487 static int call(sd_bus *bus, char *argv[]) {
1488 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1489 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1494 if (strv_length(argv) < 5) {
1495 log_error("Expects at least four arguments.");
1499 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1501 return bus_log_create_error(r);
1503 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1505 return bus_log_create_error(r);
1507 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1509 return bus_log_create_error(r);
1511 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1513 return bus_log_create_error(r);
1515 if (!isempty(argv[5])) {
1520 r = message_append_cmdline(m, argv[5], &p);
1525 log_error("Too many parameters for signature.");
1530 if (!arg_expect_reply) {
1531 r = sd_bus_send(bus, m, NULL);
1533 log_error("Failed to send message.");
1540 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1542 log_error("%s", bus_error_message(&error, r));
1546 r = sd_bus_message_is_empty(reply);
1548 return bus_log_parse_error(r);
1550 if (r == 0 && !arg_quiet) {
1553 pager_open_if_enabled();
1555 r = bus_message_dump(reply, stdout, 0);
1560 fputs(sd_bus_message_get_signature(reply, true), stdout);
1563 r = format_cmdline(reply, stdout, false);
1565 return bus_log_parse_error(r);
1567 fputc('\n', stdout);
1574 static int get_property(sd_bus *bus, char *argv[]) {
1575 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1582 n = strv_length(argv);
1584 log_error("Expects at least four arguments.");
1588 STRV_FOREACH(i, argv + 4) {
1589 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1590 const char *contents = NULL;
1593 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1595 log_error("%s", bus_error_message(&error, r));
1599 r = sd_bus_message_peek_type(reply, &type, &contents);
1601 return bus_log_parse_error(r);
1603 r = sd_bus_message_enter_container(reply, 'v', contents);
1605 return bus_log_parse_error(r);
1608 pager_open_if_enabled();
1610 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1614 fputs(contents, stdout);
1617 r = format_cmdline(reply, stdout, false);
1619 return bus_log_parse_error(r);
1621 fputc('\n', stdout);
1624 r = sd_bus_message_exit_container(reply);
1626 return bus_log_parse_error(r);
1632 static int set_property(sd_bus *bus, char *argv[]) {
1633 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1634 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1641 n = strv_length(argv);
1643 log_error("Expects at least five arguments.");
1647 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1649 return bus_log_create_error(r);
1651 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1653 return bus_log_create_error(r);
1655 r = sd_bus_message_open_container(m, 'v', argv[5]);
1657 return bus_log_create_error(r);
1660 r = message_append_cmdline(m, argv[5], &p);
1664 r = sd_bus_message_close_container(m);
1666 return bus_log_create_error(r);
1669 log_error("Too many parameters for signature.");
1673 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1675 log_error("%s", bus_error_message(&error, r));
1682 static int help(void) {
1683 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1684 "Introspect the bus.\n\n"
1685 " -h --help Show this help\n"
1686 " --version Show package version\n"
1687 " --no-pager Do not pipe output into a pager\n"
1688 " --no-legend Do not show the headers and footers\n"
1689 " --system Connect to system bus\n"
1690 " --user Connect to user bus\n"
1691 " -H --host=[USER@]HOST Operate on remote host\n"
1692 " -M --machine=CONTAINER Operate on local container\n"
1693 " --address=ADDRESS Connect to bus specified by address\n"
1694 " --show-machine Show machine ID column in list\n"
1695 " --unique Only show unique names\n"
1696 " --acquired Only show acquired names\n"
1697 " --activatable Only show activatable names\n"
1698 " --match=MATCH Only show matching messages\n"
1699 " --list Don't show tree, but simple object path list\n"
1700 " --quiet Don't show method call reply\n"
1701 " --verbose Show result values in long format\n"
1702 " --expect-reply=BOOL Expect a method call reply\n"
1703 " --auto-start=BOOL Auto-start destination service\n"
1704 " --allow-interactive-authorization=BOOL\n"
1705 " Allow interactive authorization for operation\n"
1706 " --timeout=SECS Maximum time to wait for method call completion\n"
1707 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1709 " list List bus names\n"
1710 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1711 " monitor [SERVICE...] Show bus traffic\n"
1712 " capture [SERVICE...] Capture bus traffic as pcap\n"
1713 " tree [SERVICE...] Show object tree of service\n"
1714 " introspect SERVICE OBJECT [INTERFACE]\n"
1715 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1717 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1718 " Get property value\n"
1719 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1720 " Set property value\n"
1721 " help Show this help\n"
1722 , program_invocation_short_name);
1727 static int parse_argv(int argc, char *argv[]) {
1730 ARG_VERSION = 0x100,
1746 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1751 static const struct option options[] = {
1752 { "help", no_argument, NULL, 'h' },
1753 { "version", no_argument, NULL, ARG_VERSION },
1754 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1755 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1756 { "system", no_argument, NULL, ARG_SYSTEM },
1757 { "user", no_argument, NULL, ARG_USER },
1758 { "address", required_argument, NULL, ARG_ADDRESS },
1759 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1760 { "unique", no_argument, NULL, ARG_UNIQUE },
1761 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1762 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1763 { "match", required_argument, NULL, ARG_MATCH },
1764 { "host", required_argument, NULL, 'H' },
1765 { "machine", required_argument, NULL, 'M' },
1766 { "size", required_argument, NULL, ARG_SIZE },
1767 { "list", no_argument, NULL, ARG_LIST },
1768 { "quiet", no_argument, NULL, 'q' },
1769 { "verbose", no_argument, NULL, ARG_VERBOSE },
1770 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1771 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1772 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1773 { "timeout", required_argument, NULL, ARG_TIMEOUT },
1774 { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
1783 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1791 puts(PACKAGE_STRING);
1792 puts(SYSTEMD_FEATURES);
1796 arg_no_pager = true;
1812 arg_address = optarg;
1815 case ARG_SHOW_MACHINE:
1816 arg_show_machine = true;
1824 arg_acquired = true;
1827 case ARG_ACTIVATABLE:
1828 arg_activatable = true;
1832 if (strv_extend(&arg_matches, optarg) < 0)
1839 r = parse_size(optarg, 0, &o);
1841 log_error("Failed to parse size: %s", optarg);
1845 if ((off_t) (size_t) o != o) {
1846 log_error("Size out of range.");
1850 arg_snaplen = (size_t) o;
1859 arg_transport = BUS_TRANSPORT_REMOTE;
1864 arg_transport = BUS_TRANSPORT_MACHINE;
1876 case ARG_EXPECT_REPLY:
1877 r = parse_boolean(optarg);
1879 log_error("Failed to parse --expect-reply= parameter.");
1883 arg_expect_reply = !!r;
1887 case ARG_AUTO_START:
1888 r = parse_boolean(optarg);
1890 log_error("Failed to parse --auto-start= parameter.");
1894 arg_auto_start = !!r;
1898 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1899 r = parse_boolean(optarg);
1901 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1905 arg_allow_interactive_authorization = !!r;
1909 r = parse_sec(optarg, &arg_timeout);
1911 log_error("Failed to parse --timeout= parameter.");
1917 case ARG_AUGMENT_CREDS:
1918 r = parse_boolean(optarg);
1920 log_error("Failed to parse --augment-creds= parameter.");
1924 arg_augment_creds = !!r;
1931 assert_not_reached("Unhandled option");
1937 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1940 if (optind >= argc ||
1941 streq(argv[optind], "list"))
1942 return list_bus_names(bus, argv + optind);
1944 if (streq(argv[optind], "monitor"))
1945 return monitor(bus, argv + optind, message_dump);
1947 if (streq(argv[optind], "capture"))
1948 return capture(bus, argv + optind);
1950 if (streq(argv[optind], "status"))
1951 return status(bus, argv + optind);
1953 if (streq(argv[optind], "tree"))
1954 return tree(bus, argv + optind);
1956 if (streq(argv[optind], "introspect"))
1957 return introspect(bus, argv + optind);
1959 if (streq(argv[optind], "call"))
1960 return call(bus, argv + optind);
1962 if (streq(argv[optind], "get-property"))
1963 return get_property(bus, argv + optind);
1965 if (streq(argv[optind], "set-property"))
1966 return set_property(bus, argv + optind);
1968 if (streq(argv[optind], "help"))
1971 log_error("Unknown command '%s'", argv[optind]);
1975 int main(int argc, char *argv[]) {
1976 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1979 log_parse_environment();
1982 r = parse_argv(argc, argv);
1986 r = sd_bus_new(&bus);
1988 log_error_errno(r, "Failed to allocate bus: %m");
1992 if (streq_ptr(argv[optind], "monitor") ||
1993 streq_ptr(argv[optind], "capture")) {
1995 r = sd_bus_set_monitor(bus, true);
1997 log_error_errno(r, "Failed to set monitor mode: %m");
2001 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
2003 log_error_errno(r, "Failed to enable credentials: %m");
2007 r = sd_bus_negotiate_timestamp(bus, true);
2009 log_error_errno(r, "Failed to enable timestamps: %m");
2013 r = sd_bus_negotiate_fds(bus, true);
2015 log_error_errno(r, "Failed to enable fds: %m");
2021 r = sd_bus_set_address(bus, arg_address);
2023 r = sd_bus_set_bus_client(bus, true);
2025 log_error_errno(r, "Failed to set bus client: %m");
2029 switch (arg_transport) {
2031 case BUS_TRANSPORT_LOCAL:
2033 bus->is_user = true;
2034 r = bus_set_address_user(bus);
2036 bus->is_system = true;
2037 r = bus_set_address_system(bus);
2041 case BUS_TRANSPORT_REMOTE:
2042 r = bus_set_address_system_remote(bus, arg_host);
2045 case BUS_TRANSPORT_MACHINE:
2046 r = bus_set_address_system_machine(bus, arg_host);
2050 assert_not_reached("Hmm, unknown transport type.");
2054 log_error_errno(r, "Failed to set address: %m");
2058 r = sd_bus_start(bus);
2060 log_error_errno(r, "Failed to connect to bus: %m");
2064 r = busctl_main(bus, argc, argv);
2069 strv_free(arg_matches);
2071 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;