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 static bool arg_no_pager = false;
40 static bool arg_legend = true;
41 static char *arg_address = NULL;
42 static bool arg_unique = false;
43 static bool arg_acquired = false;
44 static bool arg_activatable = false;
45 static bool arg_show_machine = false;
46 static char **arg_matches = NULL;
47 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
48 static char *arg_host = NULL;
49 static bool arg_user = false;
50 static size_t arg_snaplen = 4096;
51 static bool arg_list = false;
52 static bool arg_quiet = false;
54 static void pager_open_if_enabled(void) {
56 /* Cache result before we open the pager */
63 static int list_bus_names(sd_bus *bus, char **argv) {
64 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
65 _cleanup_free_ char **merged = NULL;
66 _cleanup_hashmap_free_ Hashmap *names = NULL;
77 if (!arg_unique && !arg_acquired && !arg_activatable)
78 arg_unique = arg_acquired = arg_activatable = true;
80 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
82 log_error("Failed to list names: %s", strerror(-r));
86 pager_open_if_enabled();
88 names = hashmap_new(&string_hash_ops);
92 STRV_FOREACH(i, acquired) {
93 max_i = MAX(max_i, strlen(*i));
95 r = hashmap_put(names, *i, INT_TO_PTR(1));
97 log_error("Failed to add to hashmap: %s", strerror(-r));
102 STRV_FOREACH(i, activatable) {
103 max_i = MAX(max_i, strlen(*i));
105 r = hashmap_put(names, *i, INT_TO_PTR(2));
106 if (r < 0 && r != -EEXIST) {
107 log_error("Failed to add to hashmap: %s", strerror(-r));
112 merged = new(char*, hashmap_size(names) + 1);
113 HASHMAP_FOREACH_KEY(v, k, names, iterator)
120 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
121 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
123 if (arg_show_machine)
129 STRV_FOREACH(i, merged) {
130 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
133 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
136 printf("%-*s", (int) max_i, *i);
137 printf(" - - - (activatable) - - ");
138 if (arg_show_machine)
146 if (!arg_unique && (*i)[0] == ':')
149 if (!arg_acquired && (*i)[0] != ':')
152 printf("%-*s", (int) max_i, *i);
154 r = sd_bus_get_name_creds(bus, *i,
155 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
156 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
157 SD_BUS_CREDS_DESCRIPTION, &creds);
159 const char *unique, *session, *unit, *cn;
163 r = sd_bus_creds_get_pid(creds, &pid);
165 const char *comm = NULL;
167 sd_bus_creds_get_comm(creds, &comm);
169 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
171 fputs(" - - ", stdout);
173 r = sd_bus_creds_get_uid(creds, &uid);
175 _cleanup_free_ char *u = NULL;
177 u = uid_to_name(uid);
186 fputs(" - ", stdout);
188 r = sd_bus_creds_get_unique_name(creds, &unique);
190 printf(" %-13s", unique);
192 fputs(" - ", stdout);
194 r = sd_bus_creds_get_unit(creds, &unit);
196 _cleanup_free_ char *e;
198 e = ellipsize(unit, 25, 100);
204 fputs(" - ", stdout);
206 r = sd_bus_creds_get_session(creds, &session);
208 printf(" %-10s", session);
210 fputs(" - ", stdout);
212 r = sd_bus_creds_get_description(creds, &cn);
214 printf(" %-19s", cn);
216 fputs(" - ", stdout);
219 printf(" - - - - - - - ");
221 if (arg_show_machine) {
222 r = sd_bus_get_name_machine_id(bus, *i, &mid);
224 char m[SD_ID128_STRING_MAX];
225 printf(" %s\n", sd_id128_to_string(mid, m));
235 static void print_subtree(const char *prefix, const char *path, char **l) {
236 const char *vertical, *space;
239 /* We assume the list is sorted. Let's first skip over the
240 * entry we are looking at. */
245 if (!streq(*l, path))
251 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
252 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
255 bool has_more = false;
257 if (!*l || !path_startswith(*l, path))
262 if (!*n || !path_startswith(*n, path))
265 if (!path_startswith(*n, *l)) {
273 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
275 print_subtree(has_more ? vertical : space, *l, l);
280 static void print_tree(const char *prefix, char **l) {
282 pager_open_if_enabled();
284 prefix = strempty(prefix);
290 printf("%s%s\n", prefix, *i);
294 if (!strv_isempty(l))
295 printf("%s/\n", prefix);
297 print_subtree(prefix, "/", l);
300 static int parse_xml_annotation(
309 } state = STATE_ANNOTATION;
312 _cleanup_free_ char *name = NULL;
316 t = xml_tokenize(p, &name, xml_state, NULL);
318 log_error("XML parse error.");
323 log_error("Premature end of XML data.");
329 case STATE_ANNOTATION:
331 if (t == XML_ATTRIBUTE_NAME) {
333 if (streq_ptr(name, "name"))
336 else if (streq_ptr(name, "value"))
340 log_error("Unexpected <annotation> attribute %s.", name);
344 } else if (t == XML_TAG_CLOSE_EMPTY ||
345 (t == XML_TAG_CLOSE && streq_ptr(name, "annotation")))
349 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
350 log_error("Unexpected token in <annotation>. (1)");
358 if (t == XML_ATTRIBUTE_VALUE)
359 state = STATE_ANNOTATION;
361 log_error("Unexpected token in <annotation>. (2)");
369 if (t == XML_ATTRIBUTE_VALUE)
370 state = STATE_ANNOTATION;
372 log_error("Unexpected token in <annotation>. (3)");
379 assert_not_reached("Bad state");
384 static int parse_xml_node(
394 STATE_INTERFACE_NAME,
398 STATE_METHOD_ARG_NAME,
399 STATE_METHOD_ARG_TYPE,
400 STATE_METHOD_ARG_DIRECTION,
404 STATE_SIGNAL_ARG_NAME,
405 STATE_SIGNAL_ARG_TYPE,
409 STATE_PROPERTY_ACCESS,
410 } state = STATE_NODE;
412 _cleanup_free_ char *node_path = NULL;
413 const char *np = prefix;
417 _cleanup_free_ char *name = NULL;
420 t = xml_tokenize(p, &name, xml_state, NULL);
422 log_error("XML parse error.");
427 log_error("Premature end of XML data.");
434 if (t == XML_ATTRIBUTE_NAME) {
436 if (streq_ptr(name, "name"))
437 state = STATE_NODE_NAME;
439 log_error("Unexpected <node> attribute %s.", name);
443 } else if (t == XML_TAG_OPEN) {
445 if (streq_ptr(name, "interface"))
446 state = STATE_INTERFACE;
448 else if (streq_ptr(name, "node")) {
450 r = parse_xml_node(np, paths, p, xml_state);
454 log_error("Unexpected <node> tag %s.", name);
457 } else if (t == XML_TAG_CLOSE_EMPTY ||
458 (t == XML_TAG_CLOSE && streq_ptr(name, "node"))) {
462 node_path = strdup(np);
467 r = set_put(paths, node_path);
476 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
477 log_error("Unexpected token in <node>. (1)");
483 case STATE_NODE_NAME:
485 if (t == XML_ATTRIBUTE_VALUE) {
489 if (name[0] == '/') {
494 if (endswith(prefix, "/"))
495 node_path = strappend(prefix, name);
497 node_path = strjoin(prefix, "/", name, NULL);
505 log_error("Unexpected token in <node>. (2)");
511 case STATE_INTERFACE:
513 if (t == XML_ATTRIBUTE_NAME) {
514 if (streq_ptr(name, "name"))
515 state = STATE_INTERFACE_NAME;
517 log_error("Unexpected <interface> attribute %s.", name);
521 } else if (t == XML_TAG_OPEN) {
522 if (streq_ptr(name, "method"))
523 state = STATE_METHOD;
524 else if (streq_ptr(name, "signal"))
525 state = STATE_SIGNAL;
526 else if (streq_ptr(name, "property"))
527 state = STATE_PROPERTY;
528 else if (streq_ptr(name, "annotation")) {
529 r = parse_xml_annotation(p, xml_state);
533 log_error("Unexpected <interface> tag %s.", name);
536 } else if (t == XML_TAG_CLOSE_EMPTY ||
537 (t == XML_TAG_CLOSE && streq_ptr(name, "interface")))
541 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
542 log_error("Unexpected token in <interface>. (1)");
548 case STATE_INTERFACE_NAME:
550 if (t == XML_ATTRIBUTE_VALUE)
551 state = STATE_INTERFACE;
553 log_error("Unexpected token in <interface>. (2)");
561 if (t == XML_ATTRIBUTE_NAME) {
562 if (streq_ptr(name, "name"))
563 state = STATE_METHOD_NAME;
565 log_error("Unexpected <method> attribute %s", name);
568 } else if (t == XML_TAG_OPEN) {
569 if (streq_ptr(name, "arg"))
570 state = STATE_METHOD_ARG;
571 else if (streq_ptr(name, "annotation")) {
572 r = parse_xml_annotation(p, xml_state);
576 log_error("Unexpected <method> tag %s.", name);
579 } else if (t == XML_TAG_CLOSE_EMPTY ||
580 (t == XML_TAG_CLOSE && streq_ptr(name, "method")))
582 state = STATE_INTERFACE;
584 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
585 log_error("Unexpected token in <method> (1).");
591 case STATE_METHOD_NAME:
593 if (t == XML_ATTRIBUTE_VALUE)
594 state = STATE_METHOD;
596 log_error("Unexpected token in <method> (2).");
602 case STATE_METHOD_ARG:
604 if (t == XML_ATTRIBUTE_NAME) {
605 if (streq_ptr(name, "name"))
606 state = STATE_METHOD_ARG_NAME;
607 else if (streq_ptr(name, "type"))
608 state = STATE_METHOD_ARG_TYPE;
609 else if (streq_ptr(name, "direction"))
610 state = STATE_METHOD_ARG_DIRECTION;
612 log_error("Unexpected method <arg> attribute %s.", name);
615 } else if (t == XML_TAG_OPEN) {
616 if (streq_ptr(name, "annotation")) {
617 r = parse_xml_annotation(p, xml_state);
621 log_error("Unexpected method <arg> tag %s.", name);
624 } else if (t == XML_TAG_CLOSE_EMPTY ||
625 (t == XML_TAG_CLOSE && streq_ptr(name, "arg")))
627 state = STATE_METHOD;
629 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
630 log_error("Unexpected token in method <arg>. (1)");
636 case STATE_METHOD_ARG_NAME:
638 if (t == XML_ATTRIBUTE_VALUE)
639 state = STATE_METHOD_ARG;
641 log_error("Unexpected token in method <arg>. (2)");
647 case STATE_METHOD_ARG_TYPE:
649 if (t == XML_ATTRIBUTE_VALUE)
650 state = STATE_METHOD_ARG;
652 log_error("Unexpected token in method <arg>. (3)");
658 case STATE_METHOD_ARG_DIRECTION:
660 if (t == XML_ATTRIBUTE_VALUE)
661 state = STATE_METHOD_ARG;
663 log_error("Unexpected token in method <arg>. (4)");
671 if (t == XML_ATTRIBUTE_NAME) {
672 if (streq_ptr(name, "name"))
673 state = STATE_SIGNAL_NAME;
675 log_error("Unexpected <signal> attribute %s.", name);
678 } else if (t == XML_TAG_OPEN) {
679 if (streq_ptr(name, "arg"))
680 state = STATE_SIGNAL_ARG;
681 else if (streq_ptr(name, "annotation")) {
682 r = parse_xml_annotation(p, xml_state);
686 log_error("Unexpected <signal> tag %s.", name);
689 } else if (t == XML_TAG_CLOSE_EMPTY ||
690 (t == XML_TAG_CLOSE && streq_ptr(name, "signal")))
692 state = STATE_INTERFACE;
694 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
695 log_error("Unexpected token in <signal>. (1)");
701 case STATE_SIGNAL_NAME:
703 if (t == XML_ATTRIBUTE_VALUE)
704 state = STATE_SIGNAL;
706 log_error("Unexpected token in <signal>. (2)");
713 case STATE_SIGNAL_ARG:
715 if (t == XML_ATTRIBUTE_NAME) {
716 if (streq_ptr(name, "name"))
717 state = STATE_SIGNAL_ARG_NAME;
718 else if (streq_ptr(name, "type"))
719 state = STATE_SIGNAL_ARG_TYPE;
721 log_error("Unexpected signal <arg> attribute %s.", name);
724 } else if (t == XML_TAG_OPEN) {
725 if (streq_ptr(name, "annotation")) {
726 r = parse_xml_annotation(p, xml_state);
730 log_error("Unexpected signal <arg> tag %s.", name);
733 } else if (t == XML_TAG_CLOSE_EMPTY ||
734 (t == XML_TAG_CLOSE && streq_ptr(name, "arg")))
736 state = STATE_SIGNAL;
738 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
739 log_error("Unexpected token in signal <arg> (1).");
745 case STATE_SIGNAL_ARG_NAME:
747 if (t == XML_ATTRIBUTE_VALUE)
748 state = STATE_SIGNAL_ARG;
750 log_error("Unexpected token in signal <arg> (2).");
756 case STATE_SIGNAL_ARG_TYPE:
758 if (t == XML_ATTRIBUTE_VALUE)
759 state = STATE_SIGNAL_ARG;
761 log_error("Unexpected token in signal <arg> (3).");
769 if (t == XML_ATTRIBUTE_NAME) {
770 if (streq_ptr(name, "name"))
771 state = STATE_PROPERTY_NAME;
772 else if (streq_ptr(name, "type"))
773 state = STATE_PROPERTY_TYPE;
774 else if (streq_ptr(name, "access"))
775 state = STATE_PROPERTY_ACCESS;
777 log_error("Unexpected <property> attribute %s.", name);
780 } else if (t == XML_TAG_OPEN) {
782 if (streq_ptr(name, "annotation")) {
783 r = parse_xml_annotation(p, xml_state);
787 log_error("Unexpected <property> tag %s.", name);
791 } else if (t == XML_TAG_CLOSE_EMPTY ||
792 (t == XML_TAG_CLOSE && streq_ptr(name, "property")))
794 state = STATE_INTERFACE;
796 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
797 log_error("Unexpected token in <property>. (1)");
803 case STATE_PROPERTY_NAME:
805 if (t == XML_ATTRIBUTE_VALUE)
806 state = STATE_PROPERTY;
808 log_error("Unexpected token in <property>. (2)");
814 case STATE_PROPERTY_TYPE:
816 if (t == XML_ATTRIBUTE_VALUE)
817 state = STATE_PROPERTY;
819 log_error("Unexpected token in <property>. (3)");
825 case STATE_PROPERTY_ACCESS:
827 if (t == XML_ATTRIBUTE_VALUE)
828 state = STATE_PROPERTY;
830 log_error("Unexpected token in <property>. (4)");
839 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths) {
840 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
841 _cleanup_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
843 void *xml_state = NULL;
846 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
848 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
852 r = sd_bus_message_read(reply, "s", &xml);
854 return bus_log_parse_error(r);
856 /* fputs(xml, stdout); */
860 _cleanup_free_ char *name = NULL;
862 r = xml_tokenize(&p, &name, &xml_state, NULL);
864 log_error("XML parse error");
871 if (r == XML_TAG_OPEN) {
873 if (streq(name, "node")) {
874 r = parse_xml_node(path, paths, &p, &xml_state);
878 log_error("Unexpected tag '%s' in introspection data.", name);
881 } else if (r != XML_TEXT || !in_charset(name, WHITESPACE)) {
882 log_error("Unexpected token.");
890 static int tree_one(sd_bus *bus, const char *service, const char *prefix) {
891 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
892 _cleanup_free_ char **l = NULL;
896 paths = set_new(&string_hash_ops);
900 done = set_new(&string_hash_ops);
904 failed = set_new(&string_hash_ops);
912 r = set_put(paths, m);
919 _cleanup_free_ char *p = NULL;
922 p = set_steal_first(paths);
926 if (set_contains(done, p) ||
927 set_contains(failed, p))
930 q = find_nodes(bus, service, p, paths);
935 q = set_put(failed, p);
937 q = set_put(done, p);
946 l = set_get_strv(done);
951 print_tree(prefix, l);
958 static int tree(sd_bus *bus, char **argv) {
962 if (!arg_unique && !arg_acquired)
965 if (strv_length(argv) <= 1) {
966 _cleanup_strv_free_ char **names = NULL;
967 bool not_first = true;
969 r = sd_bus_list_names(bus, &names, NULL);
971 log_error("Failed to get name list: %s", strerror(-r));
975 pager_open_if_enabled();
977 STRV_FOREACH(i, names) {
980 if (!arg_unique && (*i)[0] == ':')
983 if (!arg_acquired && (*i)[0] == ':')
989 printf("Service %s:\n", *i);
991 q = tree_one(bus, *i, "\t");
998 pager_open_if_enabled();
1000 STRV_FOREACH(i, argv+1) {
1007 printf("Service %s:\n", *i);
1009 q = tree_one(bus, *i, NULL);
1010 if (q < 0 && r >= 0)
1018 static int message_dump(sd_bus_message *m, FILE *f) {
1019 return bus_message_dump(m, f, true);
1022 static int message_pcap(sd_bus_message *m, FILE *f) {
1023 return bus_message_pcap_frame(m, arg_snaplen, f);
1026 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1027 bool added_something = false;
1031 STRV_FOREACH(i, argv+1) {
1032 _cleanup_free_ char *m = NULL;
1034 if (!service_name_is_valid(*i)) {
1035 log_error("Invalid service name '%s'", *i);
1039 m = strjoin("sender='", *i, "'", NULL);
1043 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1045 log_error("Failed to add match: %s", strerror(-r));
1049 added_something = true;
1052 STRV_FOREACH(i, arg_matches) {
1053 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1055 log_error("Failed to add match: %s", strerror(-r));
1059 added_something = true;
1062 if (!added_something) {
1063 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1065 log_error("Failed to add match: %s", strerror(-r));
1071 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1073 r = sd_bus_process(bus, &m);
1075 log_error("Failed to process bus: %s", strerror(-r));
1087 r = sd_bus_wait(bus, (uint64_t) -1);
1089 log_error("Failed to wait for bus: %s", strerror(-r));
1095 static int capture(sd_bus *bus, char *argv[]) {
1098 if (isatty(fileno(stdout)) > 0) {
1099 log_error("Refusing to write message data to console, please redirect output to a file.");
1103 bus_pcap_header(arg_snaplen, stdout);
1105 r = monitor(bus, argv, message_pcap);
1109 if (ferror(stdout)) {
1110 log_error("Couldn't write capture file.");
1117 static int status(sd_bus *bus, char *argv[]) {
1118 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1124 if (strv_length(argv) != 2) {
1125 log_error("Expects one argument.");
1129 r = parse_pid(argv[1], &pid);
1131 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
1133 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
1136 log_error("Failed to get credentials: %s", strerror(-r));
1140 bus_creds_dump(creds, NULL);
1144 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1164 log_error("Too few parameters for signature.");
1173 case SD_BUS_TYPE_BOOLEAN:
1175 r = parse_boolean(v);
1177 log_error("Failed to parse as boolean: %s", v);
1181 r = sd_bus_message_append_basic(m, t, &r);
1184 case SD_BUS_TYPE_BYTE: {
1187 r = safe_atou8(v, &z);
1189 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1193 r = sd_bus_message_append_basic(m, t, &z);
1197 case SD_BUS_TYPE_INT16: {
1200 r = safe_atoi16(v, &z);
1202 log_error("Failed to parse as signed 16bit integer: %s", v);
1206 r = sd_bus_message_append_basic(m, t, &z);
1210 case SD_BUS_TYPE_UINT16: {
1213 r = safe_atou16(v, &z);
1215 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1219 r = sd_bus_message_append_basic(m, t, &z);
1223 case SD_BUS_TYPE_INT32: {
1226 r = safe_atoi32(v, &z);
1228 log_error("Failed to parse as signed 32bit integer: %s", v);
1232 r = sd_bus_message_append_basic(m, t, &z);
1236 case SD_BUS_TYPE_UINT32: {
1239 r = safe_atou32(v, &z);
1241 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1245 r = sd_bus_message_append_basic(m, t, &z);
1249 case SD_BUS_TYPE_INT64: {
1252 r = safe_atoi64(v, &z);
1254 log_error("Failed to parse as signed 64bit integer: %s", v);
1258 r = sd_bus_message_append_basic(m, t, &z);
1262 case SD_BUS_TYPE_UINT64: {
1265 r = safe_atou64(v, &z);
1267 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1271 r = sd_bus_message_append_basic(m, t, &z);
1276 case SD_BUS_TYPE_DOUBLE: {
1279 r = safe_atod(v, &z);
1281 log_error("Failed to parse as double precision floating point: %s", v);
1285 r = sd_bus_message_append_basic(m, t, &z);
1289 case SD_BUS_TYPE_STRING:
1290 case SD_BUS_TYPE_OBJECT_PATH:
1291 case SD_BUS_TYPE_SIGNATURE:
1293 r = sd_bus_message_append_basic(m, t, v);
1296 case SD_BUS_TYPE_ARRAY: {
1300 r = safe_atou32(v, &n);
1302 log_error("Failed to parse number of array entries: %s", v);
1306 r = signature_element_length(signature, &k);
1308 log_error("Invalid array signature.");
1315 memcpy(s, signature, k);
1318 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1320 return bus_log_create_error(r);
1322 for (i = 0; i < n; i++) {
1323 r = message_append_cmdline(m, s, &p);
1331 r = sd_bus_message_close_container(m);
1335 case SD_BUS_TYPE_VARIANT:
1336 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1338 return bus_log_create_error(r);
1340 r = message_append_cmdline(m, v, &p);
1344 r = sd_bus_message_close_container(m);
1347 case SD_BUS_TYPE_STRUCT_BEGIN:
1348 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1354 r = signature_element_length(signature, &k);
1356 log_error("Invalid struct/dict entry signature.");
1362 memcpy(s, signature + 1, k - 2);
1365 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1367 return bus_log_create_error(r);
1369 r = message_append_cmdline(m, s, &p);
1376 r = sd_bus_message_close_container(m);
1380 case SD_BUS_TYPE_UNIX_FD:
1381 log_error("UNIX file descriptor not supported as type.");
1385 log_error("Unknown signature type %c.", t);
1390 return bus_log_create_error(r);
1397 static int call(sd_bus *bus, char *argv[]) {
1398 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1399 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1404 if (strv_length(argv) < 5) {
1405 log_error("Expects at least four arguments.");
1409 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1411 log_error("Failed to prepare bus message: %s", strerror(-r));
1415 if (!isempty(argv[5])) {
1420 r = message_append_cmdline(m, argv[5], &p);
1425 log_error("Too many parameters for signature.");
1430 r = sd_bus_call(bus, m, 0, &error, &reply);
1432 log_error("%s", bus_error_message(&error, r));
1436 r = sd_bus_message_is_empty(reply);
1438 return bus_log_parse_error(r);
1439 if (r == 0 && !arg_quiet) {
1440 pager_open_if_enabled();
1441 bus_message_dump(reply, stdout, false);
1447 static int help(void) {
1448 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1449 "Introspect the bus.\n\n"
1450 " -h --help Show this help\n"
1451 " --version Show package version\n"
1452 " --no-pager Do not pipe output into a pager\n"
1453 " --no-legend Do not show the headers and footers\n"
1454 " --system Connect to system bus\n"
1455 " --user Connect to user bus\n"
1456 " -H --host=[USER@]HOST Operate on remote host\n"
1457 " -M --machine=CONTAINER Operate on local container\n"
1458 " --address=ADDRESS Connect to bus specified by address\n"
1459 " --show-machine Show machine ID column in list\n"
1460 " --unique Only show unique names\n"
1461 " --acquired Only show acquired names\n"
1462 " --activatable Only show activatable names\n"
1463 " --match=MATCH Only show matching messages\n"
1464 " --list Don't show tree, but simple object path list\n"
1465 " --quiet Don't show method call reply\n\n"
1467 " list List bus names\n"
1468 " tree [SERVICE...] Show object tree of service\n"
1469 " monitor [SERVICE...] Show bus traffic\n"
1470 " capture [SERVICE...] Capture bus traffic as pcap\n"
1471 " status SERVICE Show service name status\n"
1472 " call SERVICE PATH INTERFACE METHOD [SIGNATURE] [ARGUMENTS...]\n"
1474 " help Show this help\n"
1475 , program_invocation_short_name);
1480 static int parse_argv(int argc, char *argv[]) {
1483 ARG_VERSION = 0x100,
1498 static const struct option options[] = {
1499 { "help", no_argument, NULL, 'h' },
1500 { "version", no_argument, NULL, ARG_VERSION },
1501 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1502 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1503 { "system", no_argument, NULL, ARG_SYSTEM },
1504 { "user", no_argument, NULL, ARG_USER },
1505 { "address", required_argument, NULL, ARG_ADDRESS },
1506 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1507 { "unique", no_argument, NULL, ARG_UNIQUE },
1508 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1509 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1510 { "match", required_argument, NULL, ARG_MATCH },
1511 { "host", required_argument, NULL, 'H' },
1512 { "machine", required_argument, NULL, 'M' },
1513 { "size", required_argument, NULL, ARG_SIZE },
1514 { "list", no_argument, NULL, ARG_LIST },
1515 { "quiet", no_argument, NULL, 'q' },
1524 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1532 puts(PACKAGE_STRING);
1533 puts(SYSTEMD_FEATURES);
1537 arg_no_pager = true;
1553 arg_address = optarg;
1556 case ARG_SHOW_MACHINE:
1557 arg_show_machine = true;
1565 arg_acquired = true;
1568 case ARG_ACTIVATABLE:
1569 arg_activatable = true;
1573 if (strv_extend(&arg_matches, optarg) < 0)
1580 r = parse_size(optarg, 0, &o);
1582 log_error("Failed to parse size: %s", optarg);
1586 if ((off_t) (size_t) o != o) {
1587 log_error("Size out of range.");
1591 arg_snaplen = (size_t) o;
1600 arg_transport = BUS_TRANSPORT_REMOTE;
1605 arg_transport = BUS_TRANSPORT_CONTAINER;
1617 assert_not_reached("Unhandled option");
1623 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1626 if (optind >= argc ||
1627 streq(argv[optind], "list"))
1628 return list_bus_names(bus, argv + optind);
1630 if (streq(argv[optind], "monitor"))
1631 return monitor(bus, argv + optind, message_dump);
1633 if (streq(argv[optind], "capture"))
1634 return capture(bus, argv + optind);
1636 if (streq(argv[optind], "status"))
1637 return status(bus, argv + optind);
1639 if (streq(argv[optind], "tree"))
1640 return tree(bus, argv + optind);
1642 if (streq(argv[optind], "call"))
1643 return call(bus, argv + optind);
1645 if (streq(argv[optind], "help"))
1648 log_error("Unknown command '%s'", argv[optind]);
1652 int main(int argc, char *argv[]) {
1653 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1656 log_parse_environment();
1659 r = parse_argv(argc, argv);
1663 r = sd_bus_new(&bus);
1665 log_error("Failed to allocate bus: %s", strerror(-r));
1669 if (streq_ptr(argv[optind], "monitor") ||
1670 streq_ptr(argv[optind], "capture")) {
1672 r = sd_bus_set_monitor(bus, true);
1674 log_error("Failed to set monitor mode: %s", strerror(-r));
1678 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1680 log_error("Failed to enable credentials: %s", strerror(-r));
1684 r = sd_bus_negotiate_timestamp(bus, true);
1686 log_error("Failed to enable timestamps: %s", strerror(-r));
1690 r = sd_bus_negotiate_fds(bus, true);
1692 log_error("Failed to enable fds: %s", strerror(-r));
1698 r = sd_bus_set_address(bus, arg_address);
1700 switch (arg_transport) {
1702 case BUS_TRANSPORT_LOCAL:
1704 r = bus_set_address_user(bus);
1706 r = bus_set_address_system(bus);
1709 case BUS_TRANSPORT_REMOTE:
1710 r = bus_set_address_system_remote(bus, arg_host);
1713 case BUS_TRANSPORT_CONTAINER:
1714 r = bus_set_address_system_container(bus, arg_host);
1718 assert_not_reached("Hmm, unknown transport type.");
1722 log_error("Failed to set address: %s", strerror(-r));
1726 r = sd_bus_set_bus_client(bus, true);
1728 log_error("Failed to set bus client: %s", strerror(-r));
1732 r = sd_bus_start(bus);
1734 log_error("Failed to connect to bus: %s", strerror(-r));
1738 r = busctl_main(bus, argc, argv);
1743 strv_free(arg_matches);
1745 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;