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"
38 static bool arg_no_pager = false;
39 static bool arg_legend = true;
40 static char *arg_address = NULL;
41 static bool arg_unique = false;
42 static bool arg_acquired = false;
43 static bool arg_activatable = false;
44 static bool arg_show_machine = false;
45 static char **arg_matches = NULL;
46 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
47 static char *arg_host = NULL;
48 static bool arg_user = false;
49 static size_t arg_snaplen = 4096;
50 static bool arg_list = false;
52 static void pager_open_if_enabled(void) {
54 /* Cache result before we open the pager */
61 static int list_bus_names(sd_bus *bus, char **argv) {
62 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
63 _cleanup_free_ char **merged = NULL;
64 _cleanup_hashmap_free_ Hashmap *names = NULL;
75 if (!arg_unique && !arg_acquired && !arg_activatable)
76 arg_unique = arg_acquired = arg_activatable = true;
78 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
80 log_error("Failed to list names: %s", strerror(-r));
84 pager_open_if_enabled();
86 names = hashmap_new(&string_hash_ops);
90 STRV_FOREACH(i, acquired) {
91 max_i = MAX(max_i, strlen(*i));
93 r = hashmap_put(names, *i, INT_TO_PTR(1));
95 log_error("Failed to add to hashmap: %s", strerror(-r));
100 STRV_FOREACH(i, activatable) {
101 max_i = MAX(max_i, strlen(*i));
103 r = hashmap_put(names, *i, INT_TO_PTR(2));
104 if (r < 0 && r != -EEXIST) {
105 log_error("Failed to add to hashmap: %s", strerror(-r));
110 merged = new(char*, hashmap_size(names) + 1);
111 HASHMAP_FOREACH_KEY(v, k, names, iterator)
118 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
119 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
121 if (arg_show_machine)
127 STRV_FOREACH(i, merged) {
128 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
131 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
134 printf("%-*s", (int) max_i, *i);
135 printf(" - - - (activatable) - - ");
136 if (arg_show_machine)
144 if (!arg_unique && (*i)[0] == ':')
147 if (!arg_acquired && (*i)[0] != ':')
150 printf("%-*s", (int) max_i, *i);
152 r = sd_bus_get_name_creds(bus, *i,
153 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
154 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
155 SD_BUS_CREDS_DESCRIPTION, &creds);
157 const char *unique, *session, *unit, *cn;
161 r = sd_bus_creds_get_pid(creds, &pid);
163 const char *comm = NULL;
165 sd_bus_creds_get_comm(creds, &comm);
167 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
169 fputs(" - - ", stdout);
171 r = sd_bus_creds_get_uid(creds, &uid);
173 _cleanup_free_ char *u = NULL;
175 u = uid_to_name(uid);
184 fputs(" - ", stdout);
186 r = sd_bus_creds_get_unique_name(creds, &unique);
188 printf(" %-13s", unique);
190 fputs(" - ", stdout);
192 r = sd_bus_creds_get_unit(creds, &unit);
194 _cleanup_free_ char *e;
196 e = ellipsize(unit, 25, 100);
202 fputs(" - ", stdout);
204 r = sd_bus_creds_get_session(creds, &session);
206 printf(" %-10s", session);
208 fputs(" - ", stdout);
210 r = sd_bus_creds_get_description(creds, &cn);
212 printf(" %-19s", cn);
214 fputs(" - ", stdout);
217 printf(" - - - - - - - ");
219 if (arg_show_machine) {
220 r = sd_bus_get_name_machine_id(bus, *i, &mid);
222 char m[SD_ID128_STRING_MAX];
223 printf(" %s\n", sd_id128_to_string(mid, m));
233 static void print_subtree(const char *prefix, const char *path, char **l) {
234 const char *vertical, *space;
237 /* We assume the list is sorted. Let's first skip over the
238 * entry we are looking at. */
243 if (!streq(*l, path))
249 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
250 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
253 bool has_more = false;
255 if (!*l || !path_startswith(*l, path))
260 if (!*n || !path_startswith(*n, path))
263 if (!path_startswith(*n, *l)) {
271 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
273 print_subtree(has_more ? vertical : space, *l, l);
278 static void print_tree(const char *prefix, char **l) {
280 pager_open_if_enabled();
282 prefix = strempty(prefix);
288 printf("%s%s\n", prefix, *i);
292 if (!strv_isempty(l))
293 printf("%s/\n", prefix);
295 print_subtree(prefix, "/", l);
298 static int parse_xml_annotation(
307 } state = STATE_ANNOTATION;
310 _cleanup_free_ char *name = NULL;
314 t = xml_tokenize(p, &name, xml_state, NULL);
316 log_error("XML parse error.");
321 log_error("Premature end of XML data.");
327 case STATE_ANNOTATION:
329 if (t == XML_ATTRIBUTE_NAME) {
331 if (streq_ptr(name, "name"))
334 else if (streq_ptr(name, "value"))
338 log_error("Unexpected <annotation> attribute %s.", name);
342 } else if (t == XML_TAG_CLOSE_EMPTY ||
343 (t == XML_TAG_CLOSE && streq_ptr(name, "annotation")))
347 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
348 log_error("Unexpected token in <annotation>. (1)");
356 if (t == XML_ATTRIBUTE_VALUE)
357 state = STATE_ANNOTATION;
359 log_error("Unexpected token in <annotation>. (2)");
367 if (t == XML_ATTRIBUTE_VALUE)
368 state = STATE_ANNOTATION;
370 log_error("Unexpected token in <annotation>. (3)");
377 assert_not_reached("Bad state");
382 static int parse_xml_node(
392 STATE_INTERFACE_NAME,
396 STATE_METHOD_ARG_NAME,
397 STATE_METHOD_ARG_TYPE,
398 STATE_METHOD_ARG_DIRECTION,
402 STATE_SIGNAL_ARG_NAME,
403 STATE_SIGNAL_ARG_TYPE,
407 STATE_PROPERTY_ACCESS,
408 } state = STATE_NODE;
410 _cleanup_free_ char *node_path = NULL;
411 const char *np = prefix;
415 _cleanup_free_ char *name = NULL;
418 t = xml_tokenize(p, &name, xml_state, NULL);
420 log_error("XML parse error.");
425 log_error("Premature end of XML data.");
432 if (t == XML_ATTRIBUTE_NAME) {
434 if (streq_ptr(name, "name"))
435 state = STATE_NODE_NAME;
437 log_error("Unexpected <node> attribute %s.", name);
441 } else if (t == XML_TAG_OPEN) {
443 if (streq_ptr(name, "interface"))
444 state = STATE_INTERFACE;
446 else if (streq_ptr(name, "node")) {
448 r = parse_xml_node(np, paths, p, xml_state);
452 log_error("Unexpected <node> tag %s.", name);
455 } else if (t == XML_TAG_CLOSE_EMPTY ||
456 (t == XML_TAG_CLOSE && streq_ptr(name, "node"))) {
460 node_path = strdup(np);
465 r = set_put(paths, node_path);
474 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
475 log_error("Unexpected token in <node>. (1)");
481 case STATE_NODE_NAME:
483 if (t == XML_ATTRIBUTE_VALUE) {
487 if (name[0] == '/') {
492 if (endswith(prefix, "/"))
493 node_path = strappend(prefix, name);
495 node_path = strjoin(prefix, "/", name, NULL);
503 log_error("Unexpected token in <node>. (2)");
509 case STATE_INTERFACE:
511 if (t == XML_ATTRIBUTE_NAME) {
512 if (streq_ptr(name, "name"))
513 state = STATE_INTERFACE_NAME;
515 log_error("Unexpected <interface> attribute %s.", name);
519 } else if (t == XML_TAG_OPEN) {
520 if (streq_ptr(name, "method"))
521 state = STATE_METHOD;
522 else if (streq_ptr(name, "signal"))
523 state = STATE_SIGNAL;
524 else if (streq_ptr(name, "property"))
525 state = STATE_PROPERTY;
526 else if (streq_ptr(name, "annotation")) {
527 r = parse_xml_annotation(p, xml_state);
531 log_error("Unexpected <interface> tag %s.", name);
534 } else if (t == XML_TAG_CLOSE_EMPTY ||
535 (t == XML_TAG_CLOSE && streq_ptr(name, "interface")))
539 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
540 log_error("Unexpected token in <interface>. (1)");
546 case STATE_INTERFACE_NAME:
548 if (t == XML_ATTRIBUTE_VALUE)
549 state = STATE_INTERFACE;
551 log_error("Unexpected token in <interface>. (2)");
559 if (t == XML_ATTRIBUTE_NAME) {
560 if (streq_ptr(name, "name"))
561 state = STATE_METHOD_NAME;
563 log_error("Unexpected <method> attribute %s", name);
566 } else if (t == XML_TAG_OPEN) {
567 if (streq_ptr(name, "arg"))
568 state = STATE_METHOD_ARG;
569 else if (streq_ptr(name, "annotation")) {
570 r = parse_xml_annotation(p, xml_state);
574 log_error("Unexpected <method> tag %s.", name);
577 } else if (t == XML_TAG_CLOSE_EMPTY ||
578 (t == XML_TAG_CLOSE && streq_ptr(name, "method")))
580 state = STATE_INTERFACE;
582 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
583 log_error("Unexpected token in <method> (1).");
589 case STATE_METHOD_NAME:
591 if (t == XML_ATTRIBUTE_VALUE)
592 state = STATE_METHOD;
594 log_error("Unexpected token in <method> (2).");
600 case STATE_METHOD_ARG:
602 if (t == XML_ATTRIBUTE_NAME) {
603 if (streq_ptr(name, "name"))
604 state = STATE_METHOD_ARG_NAME;
605 else if (streq_ptr(name, "type"))
606 state = STATE_METHOD_ARG_TYPE;
607 else if (streq_ptr(name, "direction"))
608 state = STATE_METHOD_ARG_DIRECTION;
610 log_error("Unexpected method <arg> attribute %s.", name);
613 } else if (t == XML_TAG_OPEN) {
614 if (streq_ptr(name, "annotation")) {
615 r = parse_xml_annotation(p, xml_state);
619 log_error("Unexpected method <arg> tag %s.", name);
622 } else if (t == XML_TAG_CLOSE_EMPTY ||
623 (t == XML_TAG_CLOSE && streq_ptr(name, "arg")))
625 state = STATE_METHOD;
627 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
628 log_error("Unexpected token in method <arg>. (1)");
634 case STATE_METHOD_ARG_NAME:
636 if (t == XML_ATTRIBUTE_VALUE)
637 state = STATE_METHOD_ARG;
639 log_error("Unexpected token in method <arg>. (2)");
645 case STATE_METHOD_ARG_TYPE:
647 if (t == XML_ATTRIBUTE_VALUE)
648 state = STATE_METHOD_ARG;
650 log_error("Unexpected token in method <arg>. (3)");
656 case STATE_METHOD_ARG_DIRECTION:
658 if (t == XML_ATTRIBUTE_VALUE)
659 state = STATE_METHOD_ARG;
661 log_error("Unexpected token in method <arg>. (4)");
669 if (t == XML_ATTRIBUTE_NAME) {
670 if (streq_ptr(name, "name"))
671 state = STATE_SIGNAL_NAME;
673 log_error("Unexpected <signal> attribute %s.", name);
676 } else if (t == XML_TAG_OPEN) {
677 if (streq_ptr(name, "arg"))
678 state = STATE_SIGNAL_ARG;
679 else if (streq_ptr(name, "annotation")) {
680 r = parse_xml_annotation(p, xml_state);
684 log_error("Unexpected <signal> tag %s.", name);
687 } else if (t == XML_TAG_CLOSE_EMPTY ||
688 (t == XML_TAG_CLOSE && streq_ptr(name, "signal")))
690 state = STATE_INTERFACE;
692 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
693 log_error("Unexpected token in <signal>. (1)");
699 case STATE_SIGNAL_NAME:
701 if (t == XML_ATTRIBUTE_VALUE)
702 state = STATE_SIGNAL;
704 log_error("Unexpected token in <signal>. (2)");
711 case STATE_SIGNAL_ARG:
713 if (t == XML_ATTRIBUTE_NAME) {
714 if (streq_ptr(name, "name"))
715 state = STATE_SIGNAL_ARG_NAME;
716 else if (streq_ptr(name, "type"))
717 state = STATE_SIGNAL_ARG_TYPE;
719 log_error("Unexpected signal <arg> attribute %s.", name);
722 } else if (t == XML_TAG_OPEN) {
723 if (streq_ptr(name, "annotation")) {
724 r = parse_xml_annotation(p, xml_state);
728 log_error("Unexpected signal <arg> tag %s.", name);
731 } else if (t == XML_TAG_CLOSE_EMPTY ||
732 (t == XML_TAG_CLOSE && streq_ptr(name, "arg")))
734 state = STATE_SIGNAL;
736 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
737 log_error("Unexpected token in signal <arg> (1).");
743 case STATE_SIGNAL_ARG_NAME:
745 if (t == XML_ATTRIBUTE_VALUE)
746 state = STATE_SIGNAL_ARG;
748 log_error("Unexpected token in signal <arg> (2).");
754 case STATE_SIGNAL_ARG_TYPE:
756 if (t == XML_ATTRIBUTE_VALUE)
757 state = STATE_SIGNAL_ARG;
759 log_error("Unexpected token in signal <arg> (3).");
767 if (t == XML_ATTRIBUTE_NAME) {
768 if (streq_ptr(name, "name"))
769 state = STATE_PROPERTY_NAME;
770 else if (streq_ptr(name, "type"))
771 state = STATE_PROPERTY_TYPE;
772 else if (streq_ptr(name, "access"))
773 state = STATE_PROPERTY_ACCESS;
775 log_error("Unexpected <property> attribute %s.", name);
778 } else if (t == XML_TAG_OPEN) {
780 if (streq_ptr(name, "annotation")) {
781 r = parse_xml_annotation(p, xml_state);
785 log_error("Unexpected <property> tag %s.", name);
789 } else if (t == XML_TAG_CLOSE_EMPTY ||
790 (t == XML_TAG_CLOSE && streq_ptr(name, "property")))
792 state = STATE_INTERFACE;
794 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
795 log_error("Unexpected token in <property>. (1)");
801 case STATE_PROPERTY_NAME:
803 if (t == XML_ATTRIBUTE_VALUE)
804 state = STATE_PROPERTY;
806 log_error("Unexpected token in <property>. (2)");
812 case STATE_PROPERTY_TYPE:
814 if (t == XML_ATTRIBUTE_VALUE)
815 state = STATE_PROPERTY;
817 log_error("Unexpected token in <property>. (3)");
823 case STATE_PROPERTY_ACCESS:
825 if (t == XML_ATTRIBUTE_VALUE)
826 state = STATE_PROPERTY;
828 log_error("Unexpected token in <property>. (4)");
837 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths) {
838 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
839 _cleanup_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
841 void *xml_state = NULL;
844 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
846 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
850 r = sd_bus_message_read(reply, "s", &xml);
852 return bus_log_parse_error(r);
854 /* fputs(xml, stdout); */
858 _cleanup_free_ char *name = NULL;
860 r = xml_tokenize(&p, &name, &xml_state, NULL);
862 log_error("XML parse error");
869 if (r == XML_TAG_OPEN) {
871 if (streq(name, "node")) {
872 r = parse_xml_node(path, paths, &p, &xml_state);
876 log_error("Unexpected tag '%s' in introspection data.", name);
879 } else if (r != XML_TEXT || !in_charset(name, WHITESPACE)) {
880 log_error("Unexpected token.");
888 static int tree_one(sd_bus *bus, const char *service, const char *prefix) {
889 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
890 _cleanup_free_ char **l = NULL;
894 paths = set_new(&string_hash_ops);
898 done = set_new(&string_hash_ops);
902 failed = set_new(&string_hash_ops);
910 r = set_put(paths, m);
917 _cleanup_free_ char *p = NULL;
920 p = set_steal_first(paths);
924 if (set_contains(done, p) ||
925 set_contains(failed, p))
928 q = find_nodes(bus, service, p, paths);
933 q = set_put(failed, p);
935 q = set_put(done, p);
944 l = set_get_strv(done);
949 print_tree(prefix, l);
956 static int tree(sd_bus *bus, char **argv) {
960 if (!arg_unique && !arg_acquired)
963 if (strv_length(argv) <= 1) {
964 _cleanup_strv_free_ char **names = NULL;
965 bool not_first = true;
967 r = sd_bus_list_names(bus, &names, NULL);
969 log_error("Failed to get name list: %s", strerror(-r));
973 pager_open_if_enabled();
975 STRV_FOREACH(i, names) {
978 if (!arg_unique && (*i)[0] == ':')
981 if (!arg_acquired && (*i)[0] == ':')
987 printf("Service %s:\n", *i);
989 q = tree_one(bus, *i, "\t");
996 pager_open_if_enabled();
998 STRV_FOREACH(i, argv+1) {
1005 printf("Service %s:\n", *i);
1007 q = tree_one(bus, *i, NULL);
1008 if (q < 0 && r >= 0)
1016 static int message_dump(sd_bus_message *m, FILE *f) {
1017 return bus_message_dump(m, f, true);
1020 static int message_pcap(sd_bus_message *m, FILE *f) {
1021 return bus_message_pcap_frame(m, arg_snaplen, f);
1024 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1025 bool added_something = false;
1029 STRV_FOREACH(i, argv+1) {
1030 _cleanup_free_ char *m = NULL;
1032 if (!service_name_is_valid(*i)) {
1033 log_error("Invalid service name '%s'", *i);
1037 m = strjoin("sender='", *i, "'", NULL);
1041 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1043 log_error("Failed to add match: %s", strerror(-r));
1047 added_something = true;
1050 STRV_FOREACH(i, arg_matches) {
1051 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1053 log_error("Failed to add match: %s", strerror(-r));
1057 added_something = true;
1060 if (!added_something) {
1061 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1063 log_error("Failed to add match: %s", strerror(-r));
1069 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1071 r = sd_bus_process(bus, &m);
1073 log_error("Failed to process bus: %s", strerror(-r));
1085 r = sd_bus_wait(bus, (uint64_t) -1);
1087 log_error("Failed to wait for bus: %s", strerror(-r));
1093 static int capture(sd_bus *bus, char *argv[]) {
1096 if (isatty(fileno(stdout)) > 0) {
1097 log_error("Refusing to write message data to console, please redirect output to a file.");
1101 bus_pcap_header(arg_snaplen, stdout);
1103 r = monitor(bus, argv, message_pcap);
1107 if (ferror(stdout)) {
1108 log_error("Couldn't write capture file.");
1115 static int status(sd_bus *bus, char *argv[]) {
1116 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1122 if (strv_length(argv) != 2) {
1123 log_error("Expects one argument.");
1127 r = parse_pid(argv[1], &pid);
1129 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
1131 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
1134 log_error("Failed to get credentials: %s", strerror(-r));
1138 bus_creds_dump(creds, NULL);
1142 static int help(void) {
1143 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1144 "Introspect the bus.\n\n"
1145 " -h --help Show this help\n"
1146 " --version Show package version\n"
1147 " --no-pager Do not pipe output into a pager\n"
1148 " --no-legend Do not show the headers and footers\n"
1149 " --system Connect to system bus\n"
1150 " --user Connect to user bus\n"
1151 " -H --host=[USER@]HOST Operate on remote host\n"
1152 " -M --machine=CONTAINER Operate on local container\n"
1153 " --address=ADDRESS Connect to bus specified by address\n"
1154 " --show-machine Show machine ID column in list\n"
1155 " --unique Only show unique names\n"
1156 " --acquired Only show acquired names\n"
1157 " --activatable Only show activatable names\n"
1158 " --match=MATCH Only show matching messages\n"
1159 " --list Don't show tree, but simple object path list\n\n"
1161 " list List bus names\n"
1162 " tree [SERVICE...] Show object tree of service\n"
1163 " monitor [SERVICE...] Show bus traffic\n"
1164 " capture [SERVICE...] Capture bus traffic as pcap\n"
1165 " status NAME Show name status\n"
1166 " help Show this help\n"
1167 , program_invocation_short_name);
1172 static int parse_argv(int argc, char *argv[]) {
1175 ARG_VERSION = 0x100,
1190 static const struct option options[] = {
1191 { "help", no_argument, NULL, 'h' },
1192 { "version", no_argument, NULL, ARG_VERSION },
1193 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1194 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1195 { "system", no_argument, NULL, ARG_SYSTEM },
1196 { "user", no_argument, NULL, ARG_USER },
1197 { "address", required_argument, NULL, ARG_ADDRESS },
1198 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1199 { "unique", no_argument, NULL, ARG_UNIQUE },
1200 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1201 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1202 { "match", required_argument, NULL, ARG_MATCH },
1203 { "host", required_argument, NULL, 'H' },
1204 { "machine", required_argument, NULL, 'M' },
1205 { "size", required_argument, NULL, ARG_SIZE },
1206 { "list", no_argument, NULL, ARG_LIST },
1215 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
1223 puts(PACKAGE_STRING);
1224 puts(SYSTEMD_FEATURES);
1228 arg_no_pager = true;
1244 arg_address = optarg;
1247 case ARG_SHOW_MACHINE:
1248 arg_show_machine = true;
1256 arg_acquired = true;
1259 case ARG_ACTIVATABLE:
1260 arg_activatable = true;
1264 if (strv_extend(&arg_matches, optarg) < 0)
1271 r = parse_size(optarg, 0, &o);
1273 log_error("Failed to parse size: %s", optarg);
1277 if ((off_t) (size_t) o != o) {
1278 log_error("Size out of range.");
1282 arg_snaplen = (size_t) o;
1291 arg_transport = BUS_TRANSPORT_REMOTE;
1296 arg_transport = BUS_TRANSPORT_CONTAINER;
1304 assert_not_reached("Unhandled option");
1310 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1313 if (optind >= argc ||
1314 streq(argv[optind], "list"))
1315 return list_bus_names(bus, argv + optind);
1317 if (streq(argv[optind], "monitor"))
1318 return monitor(bus, argv + optind, message_dump);
1320 if (streq(argv[optind], "capture"))
1321 return capture(bus, argv + optind);
1323 if (streq(argv[optind], "status"))
1324 return status(bus, argv + optind);
1326 if (streq(argv[optind], "tree"))
1327 return tree(bus, argv + optind);
1329 if (streq(argv[optind], "help"))
1332 log_error("Unknown command '%s'", argv[optind]);
1336 int main(int argc, char *argv[]) {
1337 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1340 log_parse_environment();
1343 r = parse_argv(argc, argv);
1347 r = sd_bus_new(&bus);
1349 log_error("Failed to allocate bus: %s", strerror(-r));
1353 if (streq_ptr(argv[optind], "monitor") ||
1354 streq_ptr(argv[optind], "capture")) {
1356 r = sd_bus_set_monitor(bus, true);
1358 log_error("Failed to set monitor mode: %s", strerror(-r));
1362 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1364 log_error("Failed to enable credentials: %s", strerror(-r));
1368 r = sd_bus_negotiate_timestamp(bus, true);
1370 log_error("Failed to enable timestamps: %s", strerror(-r));
1374 r = sd_bus_negotiate_fds(bus, true);
1376 log_error("Failed to enable fds: %s", strerror(-r));
1382 r = sd_bus_set_address(bus, arg_address);
1384 switch (arg_transport) {
1386 case BUS_TRANSPORT_LOCAL:
1388 r = bus_set_address_user(bus);
1390 r = bus_set_address_system(bus);
1393 case BUS_TRANSPORT_REMOTE:
1394 r = bus_set_address_system_remote(bus, arg_host);
1397 case BUS_TRANSPORT_CONTAINER:
1398 r = bus_set_address_system_container(bus, arg_host);
1402 assert_not_reached("Hmm, unknown transport type.");
1406 log_error("Failed to set address: %s", strerror(-r));
1410 r = sd_bus_set_bus_client(bus, true);
1412 log_error("Failed to set bus client: %s", strerror(-r));
1416 r = sd_bus_start(bus);
1418 log_error("Failed to connect to bus: %s", strerror(-r));
1422 r = busctl_main(bus, argc, argv);
1427 strv_free(arg_matches);
1429 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;