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"
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;
55 static void pager_open_if_enabled(void) {
57 /* Cache result before we open the pager */
64 static int list_bus_names(sd_bus *bus, char **argv) {
65 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
66 _cleanup_free_ char **merged = NULL;
67 _cleanup_hashmap_free_ Hashmap *names = NULL;
78 if (!arg_unique && !arg_acquired && !arg_activatable)
79 arg_unique = arg_acquired = arg_activatable = true;
81 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
83 log_error("Failed to list names: %s", strerror(-r));
87 pager_open_if_enabled();
89 names = hashmap_new(&string_hash_ops);
93 STRV_FOREACH(i, acquired) {
94 max_i = MAX(max_i, strlen(*i));
96 r = hashmap_put(names, *i, INT_TO_PTR(1));
98 log_error("Failed to add to hashmap: %s", strerror(-r));
103 STRV_FOREACH(i, activatable) {
104 max_i = MAX(max_i, strlen(*i));
106 r = hashmap_put(names, *i, INT_TO_PTR(2));
107 if (r < 0 && r != -EEXIST) {
108 log_error("Failed to add to hashmap: %s", strerror(-r));
113 merged = new(char*, hashmap_size(names) + 1);
114 HASHMAP_FOREACH_KEY(v, k, names, iterator)
121 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
122 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
124 if (arg_show_machine)
130 STRV_FOREACH(i, merged) {
131 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
134 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
137 printf("%-*s", (int) max_i, *i);
138 printf(" - - - (activatable) - - ");
139 if (arg_show_machine)
147 if (!arg_unique && (*i)[0] == ':')
150 if (!arg_acquired && (*i)[0] != ':')
153 printf("%-*s", (int) max_i, *i);
155 r = sd_bus_get_name_creds(bus, *i,
156 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
157 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
158 SD_BUS_CREDS_DESCRIPTION, &creds);
160 const char *unique, *session, *unit, *cn;
164 r = sd_bus_creds_get_pid(creds, &pid);
166 const char *comm = NULL;
168 sd_bus_creds_get_comm(creds, &comm);
170 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
172 fputs(" - - ", stdout);
174 r = sd_bus_creds_get_uid(creds, &uid);
176 _cleanup_free_ char *u = NULL;
178 u = uid_to_name(uid);
187 fputs(" - ", stdout);
189 r = sd_bus_creds_get_unique_name(creds, &unique);
191 printf(" %-13s", unique);
193 fputs(" - ", stdout);
195 r = sd_bus_creds_get_unit(creds, &unit);
197 _cleanup_free_ char *e;
199 e = ellipsize(unit, 25, 100);
205 fputs(" - ", stdout);
207 r = sd_bus_creds_get_session(creds, &session);
209 printf(" %-10s", session);
211 fputs(" - ", stdout);
213 r = sd_bus_creds_get_description(creds, &cn);
215 printf(" %-19s", cn);
217 fputs(" - ", stdout);
220 printf(" - - - - - - - ");
222 if (arg_show_machine) {
223 r = sd_bus_get_name_machine_id(bus, *i, &mid);
225 char m[SD_ID128_STRING_MAX];
226 printf(" %s\n", sd_id128_to_string(mid, m));
236 static void print_subtree(const char *prefix, const char *path, char **l) {
237 const char *vertical, *space;
240 /* We assume the list is sorted. Let's first skip over the
241 * entry we are looking at. */
246 if (!streq(*l, path))
252 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
253 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
256 bool has_more = false;
258 if (!*l || !path_startswith(*l, path))
263 if (!*n || !path_startswith(*n, path))
266 if (!path_startswith(*n, *l)) {
274 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
276 print_subtree(has_more ? vertical : space, *l, l);
281 static void print_tree(const char *prefix, char **l) {
283 pager_open_if_enabled();
285 prefix = strempty(prefix);
291 printf("%s%s\n", prefix, *i);
295 if (strv_isempty(l)) {
296 printf("No objects discovered.\n");
300 if (streq(l[0], "/") && !l[1]) {
301 printf("Only root object discovered.\n");
305 print_subtree(prefix, "/", l);
308 static int on_path(const char *path, void *userdata) {
309 Set *paths = userdata;
314 r = set_put_strdup(paths, path);
321 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
322 static const XMLIntrospectOps ops = {
326 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
327 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
331 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
334 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
336 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
340 r = sd_bus_message_read(reply, "s", &xml);
342 return bus_log_parse_error(r);
344 return parse_xml_introspect(path, xml, &ops, paths);
347 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
348 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
349 _cleanup_free_ char **l = NULL;
353 paths = set_new(&string_hash_ops);
357 done = set_new(&string_hash_ops);
361 failed = set_new(&string_hash_ops);
369 r = set_put(paths, m);
376 _cleanup_free_ char *p = NULL;
379 p = set_steal_first(paths);
383 if (set_contains(done, p) ||
384 set_contains(failed, p))
387 q = find_nodes(bus, service, p, paths, many);
392 q = set_put(failed, p);
394 q = set_put(done, p);
403 pager_open_if_enabled();
405 l = set_get_strv(done);
410 print_tree(prefix, l);
417 static int tree(sd_bus *bus, char **argv) {
421 if (!arg_unique && !arg_acquired)
424 if (strv_length(argv) <= 1) {
425 _cleanup_strv_free_ char **names = NULL;
426 bool not_first = false;
428 r = sd_bus_list_names(bus, &names, NULL);
430 log_error("Failed to get name list: %s", strerror(-r));
434 pager_open_if_enabled();
436 STRV_FOREACH(i, names) {
439 if (!arg_unique && (*i)[0] == ':')
442 if (!arg_acquired && (*i)[0] == ':')
448 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
450 q = tree_one(bus, *i, NULL, true);
457 STRV_FOREACH(i, argv+1) {
464 pager_open_if_enabled();
465 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
468 q = tree_one(bus, *i, NULL, !!argv[2]);
477 typedef struct Member {
487 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
494 ul = string_hash_func(m->type, hash_key);
497 ul ^= string_hash_func(m->name, hash_key);
500 ul ^= string_hash_func(m->interface, hash_key);
505 static int member_compare_func(const void *a, const void *b) {
506 const Member *x = a, *y = b;
514 if (!x->interface && y->interface)
516 if (x->interface && !y->interface)
518 if (x->interface && y->interface) {
519 d = strcmp(x->interface, y->interface);
524 d = strcmp(x->type, y->type);
528 if (!x->name && y->name)
530 if (x->name && !y->name)
532 if (x->name && y->name)
533 return strcmp(x->name, y->name);
538 static int member_compare_funcp(const void *a, const void *b) {
539 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
541 return member_compare_func(*x, *y);
544 static void member_free(Member *m) {
555 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
557 static void member_set_free(Set *s) {
560 while ((m = set_steal_first(s)))
566 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
568 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
569 _cleanup_(member_freep) Member *m;
570 Set *members = userdata;
580 m->type = "interface";
583 r = free_and_strdup(&m->interface, interface);
587 r = set_put(members, m);
589 log_error("Duplicate interface");
597 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
598 _cleanup_(member_freep) Member *m;
599 Set *members = userdata;
612 r = free_and_strdup(&m->interface, interface);
616 r = free_and_strdup(&m->name, name);
620 r = free_and_strdup(&m->signature, signature);
624 r = free_and_strdup(&m->result, result);
628 r = set_put(members, m);
630 log_error("Duplicate method");
638 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
639 _cleanup_(member_freep) Member *m;
640 Set *members = userdata;
653 r = free_and_strdup(&m->interface, interface);
657 r = free_and_strdup(&m->name, name);
661 r = free_and_strdup(&m->signature, signature);
665 r = set_put(members, m);
667 log_error("Duplicate signal");
675 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
676 _cleanup_(member_freep) Member *m;
677 Set *members = userdata;
687 m->type = "property";
689 m->writable = writable;
691 r = free_and_strdup(&m->interface, interface);
695 r = free_and_strdup(&m->name, name);
699 r = free_and_strdup(&m->signature, signature);
703 r = set_put(members, m);
705 log_error("Duplicate property");
713 static const char *strdash(const char *x) {
714 return isempty(x) ? "-" : x;
717 static int introspect(sd_bus *bus, char **argv) {
718 static const struct hash_ops member_hash_ops = {
719 .hash = member_hash_func,
720 .compare = member_compare_func,
723 static const XMLIntrospectOps ops = {
724 .on_interface = on_interface,
725 .on_method = on_method,
726 .on_signal = on_signal,
727 .on_property = on_property,
730 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
731 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
732 _cleanup_(member_set_freep) Set *members = NULL;
737 unsigned name_width, type_width, signature_width, result_width;
738 Member **sorted = NULL;
741 if (strv_length(argv) != 3) {
742 log_error("Requires service and object path argument.");
746 members = set_new(&member_hash_ops);
750 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
752 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
756 r = sd_bus_message_read(reply, "s", &xml);
758 return bus_log_parse_error(r);
760 r = parse_xml_introspect(argv[2], xml, &ops, members);
764 pager_open_if_enabled();
766 name_width = strlen("NAME");
767 type_width = strlen("TYPE");
768 signature_width = strlen("SIGNATURE");
769 result_width = strlen("RESULT");
771 sorted = newa(Member*, set_size(members));
773 SET_FOREACH(m, members, i) {
775 name_width = MAX(name_width, strlen(m->interface));
777 name_width = MAX(name_width, strlen(m->name) + 1);
779 type_width = MAX(type_width, strlen(m->type));
781 signature_width = MAX(signature_width, strlen(m->signature));
783 result_width = MAX(result_width, strlen(m->result));
788 assert(k == set_size(members));
789 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
791 printf("%-*s %-*s %-*s %-*s %s\n",
792 (int) name_width, "NAME",
793 (int) type_width, "TYPE",
794 (int) signature_width, "SIGNATURE",
795 (int) result_width, "RESULT",
798 for (j = 0; j < k; j++) {
803 is_interface = streq(m->type, "interface");
805 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
806 is_interface ? ansi_highlight() : "",
807 is_interface ? "" : ".",
808 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
809 is_interface ? ansi_highlight_off() : "",
810 (int) type_width, strdash(m->type),
811 (int) signature_width, strdash(m->signature),
812 (int) result_width, strdash(m->result),
813 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
814 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
815 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
816 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
817 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
818 m->writable ? " writable" : "");
824 static int message_dump(sd_bus_message *m, FILE *f) {
825 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
828 static int message_pcap(sd_bus_message *m, FILE *f) {
829 return bus_message_pcap_frame(m, arg_snaplen, f);
832 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
833 bool added_something = false;
837 STRV_FOREACH(i, argv+1) {
838 _cleanup_free_ char *m = NULL;
840 if (!service_name_is_valid(*i)) {
841 log_error("Invalid service name '%s'", *i);
845 m = strjoin("sender='", *i, "'", NULL);
849 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
851 log_error("Failed to add match: %s", strerror(-r));
855 added_something = true;
858 STRV_FOREACH(i, arg_matches) {
859 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
861 log_error("Failed to add match: %s", strerror(-r));
865 added_something = true;
868 if (!added_something) {
869 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
871 log_error("Failed to add match: %s", strerror(-r));
877 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
879 r = sd_bus_process(bus, &m);
881 log_error("Failed to process bus: %s", strerror(-r));
893 r = sd_bus_wait(bus, (uint64_t) -1);
895 log_error("Failed to wait for bus: %s", strerror(-r));
901 static int capture(sd_bus *bus, char *argv[]) {
904 if (isatty(fileno(stdout)) > 0) {
905 log_error("Refusing to write message data to console, please redirect output to a file.");
909 bus_pcap_header(arg_snaplen, stdout);
911 r = monitor(bus, argv, message_pcap);
915 if (ferror(stdout)) {
916 log_error("Couldn't write capture file.");
923 static int status(sd_bus *bus, char *argv[]) {
924 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
930 if (strv_length(argv) != 2) {
931 log_error("Expects one argument.");
935 r = parse_pid(argv[1], &pid);
937 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
939 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
942 log_error("Failed to get credentials: %s", strerror(-r));
946 bus_creds_dump(creds, NULL, false);
950 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
970 log_error("Too few parameters for signature.");
979 case SD_BUS_TYPE_BOOLEAN:
981 r = parse_boolean(v);
983 log_error("Failed to parse as boolean: %s", v);
987 r = sd_bus_message_append_basic(m, t, &r);
990 case SD_BUS_TYPE_BYTE: {
993 r = safe_atou8(v, &z);
995 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
999 r = sd_bus_message_append_basic(m, t, &z);
1003 case SD_BUS_TYPE_INT16: {
1006 r = safe_atoi16(v, &z);
1008 log_error("Failed to parse as signed 16bit integer: %s", v);
1012 r = sd_bus_message_append_basic(m, t, &z);
1016 case SD_BUS_TYPE_UINT16: {
1019 r = safe_atou16(v, &z);
1021 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1025 r = sd_bus_message_append_basic(m, t, &z);
1029 case SD_BUS_TYPE_INT32: {
1032 r = safe_atoi32(v, &z);
1034 log_error("Failed to parse as signed 32bit integer: %s", v);
1038 r = sd_bus_message_append_basic(m, t, &z);
1042 case SD_BUS_TYPE_UINT32: {
1045 r = safe_atou32(v, &z);
1047 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1051 r = sd_bus_message_append_basic(m, t, &z);
1055 case SD_BUS_TYPE_INT64: {
1058 r = safe_atoi64(v, &z);
1060 log_error("Failed to parse as signed 64bit integer: %s", v);
1064 r = sd_bus_message_append_basic(m, t, &z);
1068 case SD_BUS_TYPE_UINT64: {
1071 r = safe_atou64(v, &z);
1073 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1077 r = sd_bus_message_append_basic(m, t, &z);
1082 case SD_BUS_TYPE_DOUBLE: {
1085 r = safe_atod(v, &z);
1087 log_error("Failed to parse as double precision floating point: %s", v);
1091 r = sd_bus_message_append_basic(m, t, &z);
1095 case SD_BUS_TYPE_STRING:
1096 case SD_BUS_TYPE_OBJECT_PATH:
1097 case SD_BUS_TYPE_SIGNATURE:
1099 r = sd_bus_message_append_basic(m, t, v);
1102 case SD_BUS_TYPE_ARRAY: {
1106 r = safe_atou32(v, &n);
1108 log_error("Failed to parse number of array entries: %s", v);
1112 r = signature_element_length(signature, &k);
1114 log_error("Invalid array signature.");
1121 memcpy(s, signature, k);
1124 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1126 return bus_log_create_error(r);
1128 for (i = 0; i < n; i++) {
1129 r = message_append_cmdline(m, s, &p);
1137 r = sd_bus_message_close_container(m);
1141 case SD_BUS_TYPE_VARIANT:
1142 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1144 return bus_log_create_error(r);
1146 r = message_append_cmdline(m, v, &p);
1150 r = sd_bus_message_close_container(m);
1153 case SD_BUS_TYPE_STRUCT_BEGIN:
1154 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1160 r = signature_element_length(signature, &k);
1162 log_error("Invalid struct/dict entry signature.");
1168 memcpy(s, signature + 1, k - 2);
1171 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1173 return bus_log_create_error(r);
1175 r = message_append_cmdline(m, s, &p);
1182 r = sd_bus_message_close_container(m);
1186 case SD_BUS_TYPE_UNIX_FD:
1187 log_error("UNIX file descriptor not supported as type.");
1191 log_error("Unknown signature type %c.", t);
1196 return bus_log_create_error(r);
1203 static int call(sd_bus *bus, char *argv[]) {
1204 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1205 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1210 if (strv_length(argv) < 5) {
1211 log_error("Expects at least four arguments.");
1215 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1217 log_error("Failed to prepare bus message: %s", strerror(-r));
1221 if (!isempty(argv[5])) {
1226 r = message_append_cmdline(m, argv[5], &p);
1231 log_error("Too many parameters for signature.");
1236 r = sd_bus_call(bus, m, 0, &error, &reply);
1238 log_error("%s", bus_error_message(&error, r));
1242 r = sd_bus_message_is_empty(reply);
1244 return bus_log_parse_error(r);
1245 if (r == 0 && !arg_quiet) {
1246 pager_open_if_enabled();
1247 bus_message_dump(reply, stdout, 0);
1253 static int get_property(sd_bus *bus, char *argv[]) {
1254 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1260 n = strv_length(argv);
1262 log_error("Expects at least three arguments.");
1267 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1268 bool not_first = false;
1270 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", strempty(argv[3]));
1272 log_error("%s", bus_error_message(&error, r));
1276 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
1278 return bus_log_parse_error(r);
1283 r = sd_bus_message_enter_container(reply, 'e', "sv");
1285 return bus_log_parse_error(r);
1290 r = sd_bus_message_read(reply, "s", &name);
1292 return bus_log_parse_error(r);
1297 printf("Property %s:\n", name);
1299 r = sd_bus_message_enter_container(reply, 'v', NULL);
1301 return bus_log_parse_error(r);
1303 pager_open_if_enabled();
1304 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1306 r = sd_bus_message_exit_container(reply);
1308 return bus_log_parse_error(r);
1310 r = sd_bus_message_exit_container(reply);
1312 return bus_log_parse_error(r);
1317 r = sd_bus_message_exit_container(reply);
1319 return bus_log_parse_error(r);
1323 STRV_FOREACH(i, argv + 4) {
1324 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1326 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1328 log_error("%s", bus_error_message(&error, r));
1332 r = sd_bus_message_enter_container(reply, 'v', NULL);
1334 return bus_log_parse_error(r);
1340 printf("Property %s:\n", *i);
1342 pager_open_if_enabled();
1343 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1345 r = sd_bus_message_exit_container(reply);
1347 return bus_log_parse_error(r);
1354 static int help(void) {
1355 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1356 "Introspect the bus.\n\n"
1357 " -h --help Show this help\n"
1358 " --version Show package version\n"
1359 " --no-pager Do not pipe output into a pager\n"
1360 " --no-legend Do not show the headers and footers\n"
1361 " --system Connect to system bus\n"
1362 " --user Connect to user bus\n"
1363 " -H --host=[USER@]HOST Operate on remote host\n"
1364 " -M --machine=CONTAINER Operate on local container\n"
1365 " --address=ADDRESS Connect to bus specified by address\n"
1366 " --show-machine Show machine ID column in list\n"
1367 " --unique Only show unique names\n"
1368 " --acquired Only show acquired names\n"
1369 " --activatable Only show activatable names\n"
1370 " --match=MATCH Only show matching messages\n"
1371 " --list Don't show tree, but simple object path list\n"
1372 " --quiet Don't show method call reply\n\n"
1374 " list List bus names\n"
1375 " status SERVICE Show service name status\n"
1376 " monitor [SERVICE...] Show bus traffic\n"
1377 " capture [SERVICE...] Capture bus traffic as pcap\n"
1378 " tree [SERVICE...] Show object tree of service\n"
1379 " introspect SERVICE PATH\n"
1380 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1382 " get-property SERVICE OBJECT [INTERFACE [PROPERTY...]]\n"
1383 " Get property value\n"
1384 " help Show this help\n"
1385 , program_invocation_short_name);
1390 static int parse_argv(int argc, char *argv[]) {
1393 ARG_VERSION = 0x100,
1408 static const struct option options[] = {
1409 { "help", no_argument, NULL, 'h' },
1410 { "version", no_argument, NULL, ARG_VERSION },
1411 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1412 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1413 { "system", no_argument, NULL, ARG_SYSTEM },
1414 { "user", no_argument, NULL, ARG_USER },
1415 { "address", required_argument, NULL, ARG_ADDRESS },
1416 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1417 { "unique", no_argument, NULL, ARG_UNIQUE },
1418 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1419 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1420 { "match", required_argument, NULL, ARG_MATCH },
1421 { "host", required_argument, NULL, 'H' },
1422 { "machine", required_argument, NULL, 'M' },
1423 { "size", required_argument, NULL, ARG_SIZE },
1424 { "list", no_argument, NULL, ARG_LIST },
1425 { "quiet", no_argument, NULL, 'q' },
1434 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1442 puts(PACKAGE_STRING);
1443 puts(SYSTEMD_FEATURES);
1447 arg_no_pager = true;
1463 arg_address = optarg;
1466 case ARG_SHOW_MACHINE:
1467 arg_show_machine = true;
1475 arg_acquired = true;
1478 case ARG_ACTIVATABLE:
1479 arg_activatable = true;
1483 if (strv_extend(&arg_matches, optarg) < 0)
1490 r = parse_size(optarg, 0, &o);
1492 log_error("Failed to parse size: %s", optarg);
1496 if ((off_t) (size_t) o != o) {
1497 log_error("Size out of range.");
1501 arg_snaplen = (size_t) o;
1510 arg_transport = BUS_TRANSPORT_REMOTE;
1515 arg_transport = BUS_TRANSPORT_CONTAINER;
1527 assert_not_reached("Unhandled option");
1533 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1536 if (optind >= argc ||
1537 streq(argv[optind], "list"))
1538 return list_bus_names(bus, argv + optind);
1540 if (streq(argv[optind], "monitor"))
1541 return monitor(bus, argv + optind, message_dump);
1543 if (streq(argv[optind], "capture"))
1544 return capture(bus, argv + optind);
1546 if (streq(argv[optind], "status"))
1547 return status(bus, argv + optind);
1549 if (streq(argv[optind], "tree"))
1550 return tree(bus, argv + optind);
1552 if (streq(argv[optind], "introspect"))
1553 return introspect(bus, argv + optind);
1555 if (streq(argv[optind], "call"))
1556 return call(bus, argv + optind);
1558 if (streq(argv[optind], "get-property"))
1559 return get_property(bus, argv + optind);
1561 if (streq(argv[optind], "help"))
1564 log_error("Unknown command '%s'", argv[optind]);
1568 int main(int argc, char *argv[]) {
1569 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1572 log_parse_environment();
1575 r = parse_argv(argc, argv);
1579 r = sd_bus_new(&bus);
1581 log_error("Failed to allocate bus: %s", strerror(-r));
1585 if (streq_ptr(argv[optind], "monitor") ||
1586 streq_ptr(argv[optind], "capture")) {
1588 r = sd_bus_set_monitor(bus, true);
1590 log_error("Failed to set monitor mode: %s", strerror(-r));
1594 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1596 log_error("Failed to enable credentials: %s", strerror(-r));
1600 r = sd_bus_negotiate_timestamp(bus, true);
1602 log_error("Failed to enable timestamps: %s", strerror(-r));
1606 r = sd_bus_negotiate_fds(bus, true);
1608 log_error("Failed to enable fds: %s", strerror(-r));
1614 r = sd_bus_set_address(bus, arg_address);
1616 switch (arg_transport) {
1618 case BUS_TRANSPORT_LOCAL:
1620 r = bus_set_address_user(bus);
1622 r = bus_set_address_system(bus);
1625 case BUS_TRANSPORT_REMOTE:
1626 r = bus_set_address_system_remote(bus, arg_host);
1629 case BUS_TRANSPORT_CONTAINER:
1630 r = bus_set_address_system_container(bus, arg_host);
1634 assert_not_reached("Hmm, unknown transport type.");
1638 log_error("Failed to set address: %s", strerror(-r));
1642 r = sd_bus_set_bus_client(bus, true);
1644 log_error("Failed to set bus client: %s", strerror(-r));
1648 r = sd_bus_start(bus);
1650 log_error("Failed to connect to bus: %s", strerror(-r));
1654 r = busctl_main(bus, argc, argv);
1659 strv_free(arg_matches);
1661 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;