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) {
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, "");
333 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
337 r = sd_bus_message_read(reply, "s", &xml);
339 return bus_log_parse_error(r);
341 return parse_xml_introspect(path, xml, &ops, paths);
344 static int tree_one(sd_bus *bus, const char *service, const char *prefix) {
345 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
346 _cleanup_free_ char **l = NULL;
350 paths = set_new(&string_hash_ops);
354 done = set_new(&string_hash_ops);
358 failed = set_new(&string_hash_ops);
366 r = set_put(paths, m);
373 _cleanup_free_ char *p = NULL;
376 p = set_steal_first(paths);
380 if (set_contains(done, p) ||
381 set_contains(failed, p))
384 q = find_nodes(bus, service, p, paths);
389 q = set_put(failed, p);
391 q = set_put(done, p);
400 l = set_get_strv(done);
405 print_tree(prefix, l);
412 static int tree(sd_bus *bus, char **argv) {
416 if (!arg_unique && !arg_acquired)
419 if (strv_length(argv) <= 1) {
420 _cleanup_strv_free_ char **names = NULL;
421 bool not_first = false;
423 r = sd_bus_list_names(bus, &names, NULL);
425 log_error("Failed to get name list: %s", strerror(-r));
429 pager_open_if_enabled();
431 STRV_FOREACH(i, names) {
434 if (!arg_unique && (*i)[0] == ':')
437 if (!arg_acquired && (*i)[0] == ':')
443 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
445 q = tree_one(bus, *i, NULL);
452 pager_open_if_enabled();
454 STRV_FOREACH(i, argv+1) {
461 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
463 q = tree_one(bus, *i, NULL);
472 typedef struct Member {
482 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
489 ul = string_hash_func(m->type, hash_key);
492 ul ^= string_hash_func(m->name, hash_key);
495 ul ^= string_hash_func(m->interface, hash_key);
500 static int member_compare_func(const void *a, const void *b) {
501 const Member *x = a, *y = b;
509 if (!x->interface && y->interface)
511 if (x->interface && !y->interface)
513 if (x->interface && y->interface) {
514 d = strcmp(x->interface, y->interface);
519 d = strcmp(x->type, y->type);
523 if (!x->name && y->name)
525 if (x->name && !y->name)
527 if (x->name && y->name)
528 return strcmp(x->name, y->name);
533 static int member_compare_funcp(const void *a, const void *b) {
534 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
536 return member_compare_func(*x, *y);
539 static void member_free(Member *m) {
550 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
552 static void member_set_free(Set *s) {
555 while ((m = set_steal_first(s)))
561 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
563 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
564 _cleanup_(member_freep) Member *m;
565 Set *members = userdata;
575 m->type = "interface";
578 r = free_and_strdup(&m->interface, interface);
582 r = set_put(members, m);
584 log_error("Duplicate interface");
592 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
593 _cleanup_(member_freep) Member *m;
594 Set *members = userdata;
607 r = free_and_strdup(&m->interface, interface);
611 r = free_and_strdup(&m->name, name);
615 r = free_and_strdup(&m->signature, signature);
619 r = free_and_strdup(&m->result, result);
623 r = set_put(members, m);
625 log_error("Duplicate method");
633 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
634 _cleanup_(member_freep) Member *m;
635 Set *members = userdata;
648 r = free_and_strdup(&m->interface, interface);
652 r = free_and_strdup(&m->name, name);
656 r = free_and_strdup(&m->signature, signature);
660 r = set_put(members, m);
662 log_error("Duplicate signal");
670 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
671 _cleanup_(member_freep) Member *m;
672 Set *members = userdata;
682 m->type = "property";
684 m->writable = writable;
686 r = free_and_strdup(&m->interface, interface);
690 r = free_and_strdup(&m->name, name);
694 r = free_and_strdup(&m->signature, signature);
698 r = set_put(members, m);
700 log_error("Duplicate property");
708 static const char *strdash(const char *x) {
709 return isempty(x) ? "-" : x;
712 static int introspect(sd_bus *bus, char **argv) {
713 static const struct hash_ops member_hash_ops = {
714 .hash = member_hash_func,
715 .compare = member_compare_func,
718 static const XMLIntrospectOps ops = {
719 .on_interface = on_interface,
720 .on_method = on_method,
721 .on_signal = on_signal,
722 .on_property = on_property,
725 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
726 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
727 _cleanup_(member_set_freep) Set *members = NULL;
732 unsigned name_width, type_width, signature_width, result_width;
733 Member **sorted = NULL;
736 if (strv_length(argv) != 3) {
737 log_error("Requires service and object path argument.");
741 members = set_new(&member_hash_ops);
745 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
747 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
751 r = sd_bus_message_read(reply, "s", &xml);
753 return bus_log_parse_error(r);
755 r = parse_xml_introspect(argv[2], xml, &ops, members);
759 pager_open_if_enabled();
761 name_width = strlen("NAME");
762 type_width = strlen("TYPE");
763 signature_width = strlen("SIGNATURE");
764 result_width = strlen("RESULT");
766 sorted = newa(Member*, set_size(members));
768 SET_FOREACH(m, members, i) {
770 name_width = MAX(name_width, strlen(m->interface));
772 name_width = MAX(name_width, strlen(m->name) + 1);
774 type_width = MAX(type_width, strlen(m->type));
776 signature_width = MAX(signature_width, strlen(m->signature));
778 result_width = MAX(result_width, strlen(m->result));
783 assert(k == set_size(members));
784 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
786 printf("%-*s %-*s %-*s %-*s %s\n",
787 (int) name_width, "NAME",
788 (int) type_width, "TYPE",
789 (int) signature_width, "SIGNATURE",
790 (int) result_width, "RESULT",
793 for (j = 0; j < k; j++) {
798 is_interface = streq(m->type, "interface");
800 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
801 is_interface ? ansi_highlight() : "",
802 is_interface ? "" : ".",
803 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
804 is_interface ? ansi_highlight_off() : "",
805 (int) type_width, strdash(m->type),
806 (int) signature_width, strdash(m->signature),
807 (int) result_width, strdash(m->result),
808 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
809 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
810 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
811 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
812 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
813 m->writable ? " writable" : "");
819 static int message_dump(sd_bus_message *m, FILE *f) {
820 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
823 static int message_pcap(sd_bus_message *m, FILE *f) {
824 return bus_message_pcap_frame(m, arg_snaplen, f);
827 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
828 bool added_something = false;
832 STRV_FOREACH(i, argv+1) {
833 _cleanup_free_ char *m = NULL;
835 if (!service_name_is_valid(*i)) {
836 log_error("Invalid service name '%s'", *i);
840 m = strjoin("sender='", *i, "'", NULL);
844 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
846 log_error("Failed to add match: %s", strerror(-r));
850 added_something = true;
853 STRV_FOREACH(i, arg_matches) {
854 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
856 log_error("Failed to add match: %s", strerror(-r));
860 added_something = true;
863 if (!added_something) {
864 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
866 log_error("Failed to add match: %s", strerror(-r));
872 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
874 r = sd_bus_process(bus, &m);
876 log_error("Failed to process bus: %s", strerror(-r));
888 r = sd_bus_wait(bus, (uint64_t) -1);
890 log_error("Failed to wait for bus: %s", strerror(-r));
896 static int capture(sd_bus *bus, char *argv[]) {
899 if (isatty(fileno(stdout)) > 0) {
900 log_error("Refusing to write message data to console, please redirect output to a file.");
904 bus_pcap_header(arg_snaplen, stdout);
906 r = monitor(bus, argv, message_pcap);
910 if (ferror(stdout)) {
911 log_error("Couldn't write capture file.");
918 static int status(sd_bus *bus, char *argv[]) {
919 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
925 if (strv_length(argv) != 2) {
926 log_error("Expects one argument.");
930 r = parse_pid(argv[1], &pid);
932 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
934 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
937 log_error("Failed to get credentials: %s", strerror(-r));
941 bus_creds_dump(creds, NULL);
945 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
965 log_error("Too few parameters for signature.");
974 case SD_BUS_TYPE_BOOLEAN:
976 r = parse_boolean(v);
978 log_error("Failed to parse as boolean: %s", v);
982 r = sd_bus_message_append_basic(m, t, &r);
985 case SD_BUS_TYPE_BYTE: {
988 r = safe_atou8(v, &z);
990 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
994 r = sd_bus_message_append_basic(m, t, &z);
998 case SD_BUS_TYPE_INT16: {
1001 r = safe_atoi16(v, &z);
1003 log_error("Failed to parse as signed 16bit integer: %s", v);
1007 r = sd_bus_message_append_basic(m, t, &z);
1011 case SD_BUS_TYPE_UINT16: {
1014 r = safe_atou16(v, &z);
1016 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1020 r = sd_bus_message_append_basic(m, t, &z);
1024 case SD_BUS_TYPE_INT32: {
1027 r = safe_atoi32(v, &z);
1029 log_error("Failed to parse as signed 32bit integer: %s", v);
1033 r = sd_bus_message_append_basic(m, t, &z);
1037 case SD_BUS_TYPE_UINT32: {
1040 r = safe_atou32(v, &z);
1042 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1046 r = sd_bus_message_append_basic(m, t, &z);
1050 case SD_BUS_TYPE_INT64: {
1053 r = safe_atoi64(v, &z);
1055 log_error("Failed to parse as signed 64bit integer: %s", v);
1059 r = sd_bus_message_append_basic(m, t, &z);
1063 case SD_BUS_TYPE_UINT64: {
1066 r = safe_atou64(v, &z);
1068 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1072 r = sd_bus_message_append_basic(m, t, &z);
1077 case SD_BUS_TYPE_DOUBLE: {
1080 r = safe_atod(v, &z);
1082 log_error("Failed to parse as double precision floating point: %s", v);
1086 r = sd_bus_message_append_basic(m, t, &z);
1090 case SD_BUS_TYPE_STRING:
1091 case SD_BUS_TYPE_OBJECT_PATH:
1092 case SD_BUS_TYPE_SIGNATURE:
1094 r = sd_bus_message_append_basic(m, t, v);
1097 case SD_BUS_TYPE_ARRAY: {
1101 r = safe_atou32(v, &n);
1103 log_error("Failed to parse number of array entries: %s", v);
1107 r = signature_element_length(signature, &k);
1109 log_error("Invalid array signature.");
1116 memcpy(s, signature, k);
1119 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1121 return bus_log_create_error(r);
1123 for (i = 0; i < n; i++) {
1124 r = message_append_cmdline(m, s, &p);
1132 r = sd_bus_message_close_container(m);
1136 case SD_BUS_TYPE_VARIANT:
1137 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1139 return bus_log_create_error(r);
1141 r = message_append_cmdline(m, v, &p);
1145 r = sd_bus_message_close_container(m);
1148 case SD_BUS_TYPE_STRUCT_BEGIN:
1149 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1155 r = signature_element_length(signature, &k);
1157 log_error("Invalid struct/dict entry signature.");
1163 memcpy(s, signature + 1, k - 2);
1166 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1168 return bus_log_create_error(r);
1170 r = message_append_cmdline(m, s, &p);
1177 r = sd_bus_message_close_container(m);
1181 case SD_BUS_TYPE_UNIX_FD:
1182 log_error("UNIX file descriptor not supported as type.");
1186 log_error("Unknown signature type %c.", t);
1191 return bus_log_create_error(r);
1198 static int call(sd_bus *bus, char *argv[]) {
1199 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1200 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1205 if (strv_length(argv) < 5) {
1206 log_error("Expects at least four arguments.");
1210 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1212 log_error("Failed to prepare bus message: %s", strerror(-r));
1216 if (!isempty(argv[5])) {
1221 r = message_append_cmdline(m, argv[5], &p);
1226 log_error("Too many parameters for signature.");
1231 r = sd_bus_call(bus, m, 0, &error, &reply);
1233 log_error("%s", bus_error_message(&error, r));
1237 r = sd_bus_message_is_empty(reply);
1239 return bus_log_parse_error(r);
1240 if (r == 0 && !arg_quiet) {
1241 pager_open_if_enabled();
1242 bus_message_dump(reply, stdout, 0);
1248 static int get_property(sd_bus *bus, char *argv[]) {
1249 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1255 n = strv_length(argv);
1257 log_error("Expects at least three arguments.");
1262 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1263 bool not_first = false;
1265 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", strempty(argv[3]));
1267 log_error("%s", bus_error_message(&error, r));
1271 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
1273 return bus_log_parse_error(r);
1278 r = sd_bus_message_enter_container(reply, 'e', "sv");
1280 return bus_log_parse_error(r);
1285 r = sd_bus_message_read(reply, "s", &name);
1287 return bus_log_parse_error(r);
1292 printf("Property %s:\n", name);
1294 r = sd_bus_message_enter_container(reply, 'v', NULL);
1296 return bus_log_parse_error(r);
1298 pager_open_if_enabled();
1299 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1301 r = sd_bus_message_exit_container(reply);
1303 return bus_log_parse_error(r);
1305 r = sd_bus_message_exit_container(reply);
1307 return bus_log_parse_error(r);
1312 r = sd_bus_message_exit_container(reply);
1314 return bus_log_parse_error(r);
1318 STRV_FOREACH(i, argv + 4) {
1319 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1321 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1323 log_error("%s", bus_error_message(&error, r));
1327 r = sd_bus_message_enter_container(reply, 'v', NULL);
1329 return bus_log_parse_error(r);
1335 printf("Property %s:\n", *i);
1337 pager_open_if_enabled();
1338 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1340 r = sd_bus_message_exit_container(reply);
1342 return bus_log_parse_error(r);
1349 static int help(void) {
1350 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1351 "Introspect the bus.\n\n"
1352 " -h --help Show this help\n"
1353 " --version Show package version\n"
1354 " --no-pager Do not pipe output into a pager\n"
1355 " --no-legend Do not show the headers and footers\n"
1356 " --system Connect to system bus\n"
1357 " --user Connect to user bus\n"
1358 " -H --host=[USER@]HOST Operate on remote host\n"
1359 " -M --machine=CONTAINER Operate on local container\n"
1360 " --address=ADDRESS Connect to bus specified by address\n"
1361 " --show-machine Show machine ID column in list\n"
1362 " --unique Only show unique names\n"
1363 " --acquired Only show acquired names\n"
1364 " --activatable Only show activatable names\n"
1365 " --match=MATCH Only show matching messages\n"
1366 " --list Don't show tree, but simple object path list\n"
1367 " --quiet Don't show method call reply\n\n"
1369 " list List bus names\n"
1370 " status SERVICE Show service name status\n"
1371 " monitor [SERVICE...] Show bus traffic\n"
1372 " capture [SERVICE...] Capture bus traffic as pcap\n"
1373 " tree [SERVICE...] Show object tree of service\n"
1374 " introspect SERVICE PATH\n"
1375 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1377 " get-property SERVICE OBJECT [INTERFACE [PROPERTY...]]\n"
1378 " Get property value\n"
1379 " help Show this help\n"
1380 , program_invocation_short_name);
1385 static int parse_argv(int argc, char *argv[]) {
1388 ARG_VERSION = 0x100,
1403 static const struct option options[] = {
1404 { "help", no_argument, NULL, 'h' },
1405 { "version", no_argument, NULL, ARG_VERSION },
1406 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1407 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1408 { "system", no_argument, NULL, ARG_SYSTEM },
1409 { "user", no_argument, NULL, ARG_USER },
1410 { "address", required_argument, NULL, ARG_ADDRESS },
1411 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1412 { "unique", no_argument, NULL, ARG_UNIQUE },
1413 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1414 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1415 { "match", required_argument, NULL, ARG_MATCH },
1416 { "host", required_argument, NULL, 'H' },
1417 { "machine", required_argument, NULL, 'M' },
1418 { "size", required_argument, NULL, ARG_SIZE },
1419 { "list", no_argument, NULL, ARG_LIST },
1420 { "quiet", no_argument, NULL, 'q' },
1429 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1437 puts(PACKAGE_STRING);
1438 puts(SYSTEMD_FEATURES);
1442 arg_no_pager = true;
1458 arg_address = optarg;
1461 case ARG_SHOW_MACHINE:
1462 arg_show_machine = true;
1470 arg_acquired = true;
1473 case ARG_ACTIVATABLE:
1474 arg_activatable = true;
1478 if (strv_extend(&arg_matches, optarg) < 0)
1485 r = parse_size(optarg, 0, &o);
1487 log_error("Failed to parse size: %s", optarg);
1491 if ((off_t) (size_t) o != o) {
1492 log_error("Size out of range.");
1496 arg_snaplen = (size_t) o;
1505 arg_transport = BUS_TRANSPORT_REMOTE;
1510 arg_transport = BUS_TRANSPORT_CONTAINER;
1522 assert_not_reached("Unhandled option");
1528 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1531 if (optind >= argc ||
1532 streq(argv[optind], "list"))
1533 return list_bus_names(bus, argv + optind);
1535 if (streq(argv[optind], "monitor"))
1536 return monitor(bus, argv + optind, message_dump);
1538 if (streq(argv[optind], "capture"))
1539 return capture(bus, argv + optind);
1541 if (streq(argv[optind], "status"))
1542 return status(bus, argv + optind);
1544 if (streq(argv[optind], "tree"))
1545 return tree(bus, argv + optind);
1547 if (streq(argv[optind], "introspect"))
1548 return introspect(bus, argv + optind);
1550 if (streq(argv[optind], "call"))
1551 return call(bus, argv + optind);
1553 if (streq(argv[optind], "get-property"))
1554 return get_property(bus, argv + optind);
1556 if (streq(argv[optind], "help"))
1559 log_error("Unknown command '%s'", argv[optind]);
1563 int main(int argc, char *argv[]) {
1564 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1567 log_parse_environment();
1570 r = parse_argv(argc, argv);
1574 r = sd_bus_new(&bus);
1576 log_error("Failed to allocate bus: %s", strerror(-r));
1580 if (streq_ptr(argv[optind], "monitor") ||
1581 streq_ptr(argv[optind], "capture")) {
1583 r = sd_bus_set_monitor(bus, true);
1585 log_error("Failed to set monitor mode: %s", strerror(-r));
1589 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1591 log_error("Failed to enable credentials: %s", strerror(-r));
1595 r = sd_bus_negotiate_timestamp(bus, true);
1597 log_error("Failed to enable timestamps: %s", strerror(-r));
1601 r = sd_bus_negotiate_fds(bus, true);
1603 log_error("Failed to enable fds: %s", strerror(-r));
1609 r = sd_bus_set_address(bus, arg_address);
1611 switch (arg_transport) {
1613 case BUS_TRANSPORT_LOCAL:
1615 r = bus_set_address_user(bus);
1617 r = bus_set_address_system(bus);
1620 case BUS_TRANSPORT_REMOTE:
1621 r = bus_set_address_system_remote(bus, arg_host);
1624 case BUS_TRANSPORT_CONTAINER:
1625 r = bus_set_address_system_container(bus, arg_host);
1629 assert_not_reached("Hmm, unknown transport type.");
1633 log_error("Failed to set address: %s", strerror(-r));
1637 r = sd_bus_set_bus_client(bus, true);
1639 log_error("Failed to set bus client: %s", strerror(-r));
1643 r = sd_bus_start(bus);
1645 log_error("Failed to connect to bus: %s", strerror(-r));
1649 r = busctl_main(bus, argc, argv);
1654 strv_free(arg_matches);
1656 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;