1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "path-util.h"
33 #include "bus-message.h"
34 #include "bus-internal.h"
37 #include "bus-signature.h"
39 #include "busctl-introspect.h"
41 static bool arg_no_pager = false;
42 static bool arg_legend = true;
43 static char *arg_address = NULL;
44 static bool arg_unique = false;
45 static bool arg_acquired = false;
46 static bool arg_activatable = false;
47 static bool arg_show_machine = false;
48 static char **arg_matches = NULL;
49 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
50 static char *arg_host = NULL;
51 static bool arg_user = false;
52 static size_t arg_snaplen = 4096;
53 static bool arg_list = false;
54 static bool arg_quiet = false;
56 static void pager_open_if_enabled(void) {
58 /* Cache result before we open the pager */
65 static int list_bus_names(sd_bus *bus, char **argv) {
66 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
67 _cleanup_free_ char **merged = NULL;
68 _cleanup_hashmap_free_ Hashmap *names = NULL;
79 if (!arg_unique && !arg_acquired && !arg_activatable)
80 arg_unique = arg_acquired = arg_activatable = true;
82 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
84 log_error("Failed to list names: %s", strerror(-r));
88 pager_open_if_enabled();
90 names = hashmap_new(&string_hash_ops);
94 STRV_FOREACH(i, acquired) {
95 max_i = MAX(max_i, strlen(*i));
97 r = hashmap_put(names, *i, INT_TO_PTR(1));
99 log_error("Failed to add to hashmap: %s", strerror(-r));
104 STRV_FOREACH(i, activatable) {
105 max_i = MAX(max_i, strlen(*i));
107 r = hashmap_put(names, *i, INT_TO_PTR(2));
108 if (r < 0 && r != -EEXIST) {
109 log_error("Failed to add to hashmap: %s", strerror(-r));
114 merged = new(char*, hashmap_size(names) + 1);
115 HASHMAP_FOREACH_KEY(v, k, names, iterator)
122 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
123 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
125 if (arg_show_machine)
131 STRV_FOREACH(i, merged) {
132 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
135 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
138 printf("%-*s", (int) max_i, *i);
139 printf(" - - - (activatable) - - ");
140 if (arg_show_machine)
148 if (!arg_unique && (*i)[0] == ':')
151 if (!arg_acquired && (*i)[0] != ':')
154 printf("%-*s", (int) max_i, *i);
156 r = sd_bus_get_name_creds(bus, *i,
157 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
158 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
159 SD_BUS_CREDS_DESCRIPTION, &creds);
161 const char *unique, *session, *unit, *cn;
165 r = sd_bus_creds_get_pid(creds, &pid);
167 const char *comm = NULL;
169 sd_bus_creds_get_comm(creds, &comm);
171 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
173 fputs(" - - ", stdout);
175 r = sd_bus_creds_get_uid(creds, &uid);
177 _cleanup_free_ char *u = NULL;
179 u = uid_to_name(uid);
188 fputs(" - ", stdout);
190 r = sd_bus_creds_get_unique_name(creds, &unique);
192 printf(" %-13s", unique);
194 fputs(" - ", stdout);
196 r = sd_bus_creds_get_unit(creds, &unit);
198 _cleanup_free_ char *e;
200 e = ellipsize(unit, 25, 100);
206 fputs(" - ", stdout);
208 r = sd_bus_creds_get_session(creds, &session);
210 printf(" %-10s", session);
212 fputs(" - ", stdout);
214 r = sd_bus_creds_get_description(creds, &cn);
216 printf(" %-19s", cn);
218 fputs(" - ", stdout);
221 printf(" - - - - - - - ");
223 if (arg_show_machine) {
224 r = sd_bus_get_name_machine_id(bus, *i, &mid);
226 char m[SD_ID128_STRING_MAX];
227 printf(" %s\n", sd_id128_to_string(mid, m));
237 static void print_subtree(const char *prefix, const char *path, char **l) {
238 const char *vertical, *space;
241 /* We assume the list is sorted. Let's first skip over the
242 * entry we are looking at. */
247 if (!streq(*l, path))
253 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
254 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
257 bool has_more = false;
259 if (!*l || !path_startswith(*l, path))
264 if (!*n || !path_startswith(*n, path))
267 if (!path_startswith(*n, *l)) {
275 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
277 print_subtree(has_more ? vertical : space, *l, l);
282 static void print_tree(const char *prefix, char **l) {
284 pager_open_if_enabled();
286 prefix = strempty(prefix);
292 printf("%s%s\n", prefix, *i);
296 if (strv_isempty(l)) {
297 printf("No objects discovered.\n");
301 if (streq(l[0], "/") && !l[1]) {
302 printf("Only root object discovered.\n");
306 print_subtree(prefix, "/", l);
309 static int on_path(const char *path, void *userdata) {
310 Set *paths = userdata;
315 r = set_put_strdup(paths, path);
322 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
323 static const XMLIntrospectOps ops = {
327 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
328 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
332 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
335 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
337 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
341 r = sd_bus_message_read(reply, "s", &xml);
343 return bus_log_parse_error(r);
345 return parse_xml_introspect(path, xml, &ops, paths);
348 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
349 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
350 _cleanup_free_ char **l = NULL;
354 paths = set_new(&string_hash_ops);
358 done = set_new(&string_hash_ops);
362 failed = set_new(&string_hash_ops);
370 r = set_put(paths, m);
377 _cleanup_free_ char *p = NULL;
380 p = set_steal_first(paths);
384 if (set_contains(done, p) ||
385 set_contains(failed, p))
388 q = find_nodes(bus, service, p, paths, many);
393 q = set_put(failed, p);
395 q = set_put(done, p);
404 pager_open_if_enabled();
406 l = set_get_strv(done);
411 print_tree(prefix, l);
418 static int tree(sd_bus *bus, char **argv) {
422 if (!arg_unique && !arg_acquired)
425 if (strv_length(argv) <= 1) {
426 _cleanup_strv_free_ char **names = NULL;
427 bool not_first = false;
429 r = sd_bus_list_names(bus, &names, NULL);
431 log_error("Failed to get name list: %s", strerror(-r));
435 pager_open_if_enabled();
437 STRV_FOREACH(i, names) {
440 if (!arg_unique && (*i)[0] == ':')
443 if (!arg_acquired && (*i)[0] == ':')
449 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
451 q = tree_one(bus, *i, NULL, true);
458 STRV_FOREACH(i, argv+1) {
465 pager_open_if_enabled();
466 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
469 q = tree_one(bus, *i, NULL, !!argv[2]);
478 typedef struct Member {
488 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
495 ul = string_hash_func(m->type, hash_key);
498 ul ^= string_hash_func(m->name, hash_key);
501 ul ^= string_hash_func(m->interface, hash_key);
506 static int member_compare_func(const void *a, const void *b) {
507 const Member *x = a, *y = b;
515 if (!x->interface && y->interface)
517 if (x->interface && !y->interface)
519 if (x->interface && y->interface) {
520 d = strcmp(x->interface, y->interface);
525 d = strcmp(x->type, y->type);
529 if (!x->name && y->name)
531 if (x->name && !y->name)
533 if (x->name && y->name)
534 return strcmp(x->name, y->name);
539 static int member_compare_funcp(const void *a, const void *b) {
540 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
542 return member_compare_func(*x, *y);
545 static void member_free(Member *m) {
556 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
558 static void member_set_free(Set *s) {
561 while ((m = set_steal_first(s)))
567 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
569 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
570 _cleanup_(member_freep) Member *m;
571 Set *members = userdata;
581 m->type = "interface";
584 r = free_and_strdup(&m->interface, interface);
588 r = set_put(members, m);
590 log_error("Duplicate interface");
598 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
599 _cleanup_(member_freep) Member *m;
600 Set *members = userdata;
613 r = free_and_strdup(&m->interface, interface);
617 r = free_and_strdup(&m->name, name);
621 r = free_and_strdup(&m->signature, signature);
625 r = free_and_strdup(&m->result, result);
629 r = set_put(members, m);
631 log_error("Duplicate method");
639 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
640 _cleanup_(member_freep) Member *m;
641 Set *members = userdata;
654 r = free_and_strdup(&m->interface, interface);
658 r = free_and_strdup(&m->name, name);
662 r = free_and_strdup(&m->signature, signature);
666 r = set_put(members, m);
668 log_error("Duplicate signal");
676 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
677 _cleanup_(member_freep) Member *m;
678 Set *members = userdata;
688 m->type = "property";
690 m->writable = writable;
692 r = free_and_strdup(&m->interface, interface);
696 r = free_and_strdup(&m->name, name);
700 r = free_and_strdup(&m->signature, signature);
704 r = set_put(members, m);
706 log_error("Duplicate property");
714 static const char *strdash(const char *x) {
715 return isempty(x) ? "-" : x;
718 static int introspect(sd_bus *bus, char **argv) {
719 static const struct hash_ops member_hash_ops = {
720 .hash = member_hash_func,
721 .compare = member_compare_func,
724 static const XMLIntrospectOps ops = {
725 .on_interface = on_interface,
726 .on_method = on_method,
727 .on_signal = on_signal,
728 .on_property = on_property,
731 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
732 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
733 _cleanup_(member_set_freep) Set *members = NULL;
738 unsigned name_width, type_width, signature_width, result_width;
739 Member **sorted = NULL;
742 if (strv_length(argv) != 3) {
743 log_error("Requires service and object path argument.");
747 members = set_new(&member_hash_ops);
751 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
753 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
757 r = sd_bus_message_read(reply, "s", &xml);
759 return bus_log_parse_error(r);
761 r = parse_xml_introspect(argv[2], xml, &ops, members);
765 pager_open_if_enabled();
767 name_width = strlen("NAME");
768 type_width = strlen("TYPE");
769 signature_width = strlen("SIGNATURE");
770 result_width = strlen("RESULT");
772 sorted = newa(Member*, set_size(members));
774 SET_FOREACH(m, members, i) {
776 name_width = MAX(name_width, strlen(m->interface));
778 name_width = MAX(name_width, strlen(m->name) + 1);
780 type_width = MAX(type_width, strlen(m->type));
782 signature_width = MAX(signature_width, strlen(m->signature));
784 result_width = MAX(result_width, strlen(m->result));
789 assert(k == set_size(members));
790 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
792 printf("%-*s %-*s %-*s %-*s %s\n",
793 (int) name_width, "NAME",
794 (int) type_width, "TYPE",
795 (int) signature_width, "SIGNATURE",
796 (int) result_width, "RESULT",
799 for (j = 0; j < k; j++) {
804 is_interface = streq(m->type, "interface");
806 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
807 is_interface ? ansi_highlight() : "",
808 is_interface ? "" : ".",
809 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
810 is_interface ? ansi_highlight_off() : "",
811 (int) type_width, strdash(m->type),
812 (int) signature_width, strdash(m->signature),
813 (int) result_width, strdash(m->result),
814 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
815 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
816 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
817 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
818 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
819 m->writable ? " writable" : "");
825 static int message_dump(sd_bus_message *m, FILE *f) {
826 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
829 static int message_pcap(sd_bus_message *m, FILE *f) {
830 return bus_message_pcap_frame(m, arg_snaplen, f);
833 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
834 bool added_something = false;
838 STRV_FOREACH(i, argv+1) {
839 _cleanup_free_ char *m = NULL;
841 if (!service_name_is_valid(*i)) {
842 log_error("Invalid service name '%s'", *i);
846 m = strjoin("sender='", *i, "'", NULL);
850 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
852 log_error("Failed to add match: %s", strerror(-r));
856 added_something = true;
859 STRV_FOREACH(i, arg_matches) {
860 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
862 log_error("Failed to add match: %s", strerror(-r));
866 added_something = true;
869 if (!added_something) {
870 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
872 log_error("Failed to add match: %s", strerror(-r));
878 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
880 r = sd_bus_process(bus, &m);
882 log_error("Failed to process bus: %s", strerror(-r));
894 r = sd_bus_wait(bus, (uint64_t) -1);
896 log_error("Failed to wait for bus: %s", strerror(-r));
902 static int capture(sd_bus *bus, char *argv[]) {
905 if (isatty(fileno(stdout)) > 0) {
906 log_error("Refusing to write message data to console, please redirect output to a file.");
910 bus_pcap_header(arg_snaplen, stdout);
912 r = monitor(bus, argv, message_pcap);
916 if (ferror(stdout)) {
917 log_error("Couldn't write capture file.");
924 static int status(sd_bus *bus, char *argv[]) {
925 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
931 if (strv_length(argv) != 2) {
932 log_error("Expects one argument.");
936 r = parse_pid(argv[1], &pid);
938 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
940 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
943 log_error("Failed to get credentials: %s", strerror(-r));
947 bus_creds_dump(creds, NULL, false);
951 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
971 log_error("Too few parameters for signature.");
980 case SD_BUS_TYPE_BOOLEAN:
982 r = parse_boolean(v);
984 log_error("Failed to parse as boolean: %s", v);
988 r = sd_bus_message_append_basic(m, t, &r);
991 case SD_BUS_TYPE_BYTE: {
994 r = safe_atou8(v, &z);
996 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1000 r = sd_bus_message_append_basic(m, t, &z);
1004 case SD_BUS_TYPE_INT16: {
1007 r = safe_atoi16(v, &z);
1009 log_error("Failed to parse as signed 16bit integer: %s", v);
1013 r = sd_bus_message_append_basic(m, t, &z);
1017 case SD_BUS_TYPE_UINT16: {
1020 r = safe_atou16(v, &z);
1022 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1026 r = sd_bus_message_append_basic(m, t, &z);
1030 case SD_BUS_TYPE_INT32: {
1033 r = safe_atoi32(v, &z);
1035 log_error("Failed to parse as signed 32bit integer: %s", v);
1039 r = sd_bus_message_append_basic(m, t, &z);
1043 case SD_BUS_TYPE_UINT32: {
1046 r = safe_atou32(v, &z);
1048 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1052 r = sd_bus_message_append_basic(m, t, &z);
1056 case SD_BUS_TYPE_INT64: {
1059 r = safe_atoi64(v, &z);
1061 log_error("Failed to parse as signed 64bit integer: %s", v);
1065 r = sd_bus_message_append_basic(m, t, &z);
1069 case SD_BUS_TYPE_UINT64: {
1072 r = safe_atou64(v, &z);
1074 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1078 r = sd_bus_message_append_basic(m, t, &z);
1083 case SD_BUS_TYPE_DOUBLE: {
1086 r = safe_atod(v, &z);
1088 log_error("Failed to parse as double precision floating point: %s", v);
1092 r = sd_bus_message_append_basic(m, t, &z);
1096 case SD_BUS_TYPE_STRING:
1097 case SD_BUS_TYPE_OBJECT_PATH:
1098 case SD_BUS_TYPE_SIGNATURE:
1100 r = sd_bus_message_append_basic(m, t, v);
1103 case SD_BUS_TYPE_ARRAY: {
1107 r = safe_atou32(v, &n);
1109 log_error("Failed to parse number of array entries: %s", v);
1113 r = signature_element_length(signature, &k);
1115 log_error("Invalid array signature.");
1122 memcpy(s, signature, k);
1125 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1127 return bus_log_create_error(r);
1129 for (i = 0; i < n; i++) {
1130 r = message_append_cmdline(m, s, &p);
1138 r = sd_bus_message_close_container(m);
1142 case SD_BUS_TYPE_VARIANT:
1143 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1145 return bus_log_create_error(r);
1147 r = message_append_cmdline(m, v, &p);
1151 r = sd_bus_message_close_container(m);
1154 case SD_BUS_TYPE_STRUCT_BEGIN:
1155 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1161 r = signature_element_length(signature, &k);
1163 log_error("Invalid struct/dict entry signature.");
1169 memcpy(s, signature + 1, k - 2);
1172 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1174 return bus_log_create_error(r);
1176 r = message_append_cmdline(m, s, &p);
1183 r = sd_bus_message_close_container(m);
1187 case SD_BUS_TYPE_UNIX_FD:
1188 log_error("UNIX file descriptor not supported as type.");
1192 log_error("Unknown signature type %c.", t);
1197 return bus_log_create_error(r);
1204 static int call(sd_bus *bus, char *argv[]) {
1205 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1206 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1211 if (strv_length(argv) < 5) {
1212 log_error("Expects at least four arguments.");
1216 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1218 return bus_log_create_error(r);
1220 if (!isempty(argv[5])) {
1225 r = message_append_cmdline(m, argv[5], &p);
1230 log_error("Too many parameters for signature.");
1235 r = sd_bus_call(bus, m, 0, &error, &reply);
1237 log_error("%s", bus_error_message(&error, r));
1241 r = sd_bus_message_is_empty(reply);
1243 return bus_log_parse_error(r);
1244 if (r == 0 && !arg_quiet) {
1245 pager_open_if_enabled();
1246 bus_message_dump(reply, stdout, 0);
1252 static int get_property(sd_bus *bus, char *argv[]) {
1253 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1259 n = strv_length(argv);
1261 log_error("Expects at least three arguments.");
1266 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1267 bool not_first = false;
1269 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", strempty(argv[3]));
1271 log_error("%s", bus_error_message(&error, r));
1275 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
1277 return bus_log_parse_error(r);
1282 r = sd_bus_message_enter_container(reply, 'e', "sv");
1284 return bus_log_parse_error(r);
1289 r = sd_bus_message_read(reply, "s", &name);
1291 return bus_log_parse_error(r);
1296 printf("Property %s:\n", name);
1298 r = sd_bus_message_enter_container(reply, 'v', NULL);
1300 return bus_log_parse_error(r);
1302 pager_open_if_enabled();
1303 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1305 r = sd_bus_message_exit_container(reply);
1307 return bus_log_parse_error(r);
1309 r = sd_bus_message_exit_container(reply);
1311 return bus_log_parse_error(r);
1316 r = sd_bus_message_exit_container(reply);
1318 return bus_log_parse_error(r);
1322 STRV_FOREACH(i, argv + 4) {
1323 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1325 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1327 log_error("%s", bus_error_message(&error, r));
1331 r = sd_bus_message_enter_container(reply, 'v', NULL);
1333 return bus_log_parse_error(r);
1339 printf("Property %s:\n", *i);
1341 pager_open_if_enabled();
1342 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1344 r = sd_bus_message_exit_container(reply);
1346 return bus_log_parse_error(r);
1353 static int help(void) {
1354 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1355 "Introspect the bus.\n\n"
1356 " -h --help Show this help\n"
1357 " --version Show package version\n"
1358 " --no-pager Do not pipe output into a pager\n"
1359 " --no-legend Do not show the headers and footers\n"
1360 " --system Connect to system bus\n"
1361 " --user Connect to user bus\n"
1362 " -H --host=[USER@]HOST Operate on remote host\n"
1363 " -M --machine=CONTAINER Operate on local container\n"
1364 " --address=ADDRESS Connect to bus specified by address\n"
1365 " --show-machine Show machine ID column in list\n"
1366 " --unique Only show unique names\n"
1367 " --acquired Only show acquired names\n"
1368 " --activatable Only show activatable names\n"
1369 " --match=MATCH Only show matching messages\n"
1370 " --list Don't show tree, but simple object path list\n"
1371 " --quiet Don't show method call reply\n\n"
1373 " list List bus names\n"
1374 " status SERVICE Show service name status\n"
1375 " monitor [SERVICE...] Show bus traffic\n"
1376 " capture [SERVICE...] Capture bus traffic as pcap\n"
1377 " tree [SERVICE...] Show object tree of service\n"
1378 " introspect SERVICE PATH\n"
1379 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1381 " get-property SERVICE OBJECT [INTERFACE [PROPERTY...]]\n"
1382 " Get property value\n"
1383 " help Show this help\n"
1384 , program_invocation_short_name);
1389 static int parse_argv(int argc, char *argv[]) {
1392 ARG_VERSION = 0x100,
1407 static const struct option options[] = {
1408 { "help", no_argument, NULL, 'h' },
1409 { "version", no_argument, NULL, ARG_VERSION },
1410 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1411 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1412 { "system", no_argument, NULL, ARG_SYSTEM },
1413 { "user", no_argument, NULL, ARG_USER },
1414 { "address", required_argument, NULL, ARG_ADDRESS },
1415 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1416 { "unique", no_argument, NULL, ARG_UNIQUE },
1417 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1418 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1419 { "match", required_argument, NULL, ARG_MATCH },
1420 { "host", required_argument, NULL, 'H' },
1421 { "machine", required_argument, NULL, 'M' },
1422 { "size", required_argument, NULL, ARG_SIZE },
1423 { "list", no_argument, NULL, ARG_LIST },
1424 { "quiet", no_argument, NULL, 'q' },
1433 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1441 puts(PACKAGE_STRING);
1442 puts(SYSTEMD_FEATURES);
1446 arg_no_pager = true;
1462 arg_address = optarg;
1465 case ARG_SHOW_MACHINE:
1466 arg_show_machine = true;
1474 arg_acquired = true;
1477 case ARG_ACTIVATABLE:
1478 arg_activatable = true;
1482 if (strv_extend(&arg_matches, optarg) < 0)
1489 r = parse_size(optarg, 0, &o);
1491 log_error("Failed to parse size: %s", optarg);
1495 if ((off_t) (size_t) o != o) {
1496 log_error("Size out of range.");
1500 arg_snaplen = (size_t) o;
1509 arg_transport = BUS_TRANSPORT_REMOTE;
1514 arg_transport = BUS_TRANSPORT_CONTAINER;
1526 assert_not_reached("Unhandled option");
1532 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1535 if (optind >= argc ||
1536 streq(argv[optind], "list"))
1537 return list_bus_names(bus, argv + optind);
1539 if (streq(argv[optind], "monitor"))
1540 return monitor(bus, argv + optind, message_dump);
1542 if (streq(argv[optind], "capture"))
1543 return capture(bus, argv + optind);
1545 if (streq(argv[optind], "status"))
1546 return status(bus, argv + optind);
1548 if (streq(argv[optind], "tree"))
1549 return tree(bus, argv + optind);
1551 if (streq(argv[optind], "introspect"))
1552 return introspect(bus, argv + optind);
1554 if (streq(argv[optind], "call"))
1555 return call(bus, argv + optind);
1557 if (streq(argv[optind], "get-property"))
1558 return get_property(bus, argv + optind);
1560 if (streq(argv[optind], "help"))
1563 log_error("Unknown command '%s'", argv[optind]);
1567 int main(int argc, char *argv[]) {
1568 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1571 log_parse_environment();
1574 r = parse_argv(argc, argv);
1578 r = sd_bus_new(&bus);
1580 log_error("Failed to allocate bus: %s", strerror(-r));
1584 if (streq_ptr(argv[optind], "monitor") ||
1585 streq_ptr(argv[optind], "capture")) {
1587 r = sd_bus_set_monitor(bus, true);
1589 log_error("Failed to set monitor mode: %s", strerror(-r));
1593 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1595 log_error("Failed to enable credentials: %s", strerror(-r));
1599 r = sd_bus_negotiate_timestamp(bus, true);
1601 log_error("Failed to enable timestamps: %s", strerror(-r));
1605 r = sd_bus_negotiate_fds(bus, true);
1607 log_error("Failed to enable fds: %s", strerror(-r));
1613 r = sd_bus_set_address(bus, arg_address);
1615 switch (arg_transport) {
1617 case BUS_TRANSPORT_LOCAL:
1619 r = bus_set_address_user(bus);
1621 r = bus_set_address_system(bus);
1624 case BUS_TRANSPORT_REMOTE:
1625 r = bus_set_address_system_remote(bus, arg_host);
1628 case BUS_TRANSPORT_CONTAINER:
1629 r = bus_set_address_system_container(bus, arg_host);
1633 assert_not_reached("Hmm, unknown transport type.");
1637 log_error("Failed to set address: %s", strerror(-r));
1641 r = sd_bus_set_bus_client(bus, true);
1643 log_error("Failed to set bus client: %s", strerror(-r));
1647 r = sd_bus_start(bus);
1649 log_error("Failed to connect to bus: %s", strerror(-r));
1653 r = busctl_main(bus, argc, argv);
1658 strv_free(arg_matches);
1660 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;