]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/busctl.c
man: various tweaks for busctl(1) man page
[thirdparty/systemd.git] / src / libsystemd / sd-bus / busctl.c
CommitLineData
de1c301e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
1f849790
LP
22#include <getopt.h>
23
89ffcd2a
LP
24#include "strv.h"
25#include "util.h"
26#include "log.h"
1f849790
LP
27#include "build.h"
28#include "pager.h"
d9130355
LP
29#include "xml.h"
30#include "path-util.h"
89ffcd2a 31
de1c301e 32#include "sd-bus.h"
89ffcd2a
LP
33#include "bus-message.h"
34#include "bus-internal.h"
40ca29a1 35#include "bus-util.h"
2b5c5383 36#include "bus-dump.h"
781fa938 37#include "bus-signature.h"
de1c301e 38
1f849790 39static bool arg_no_pager = false;
17d47d8d 40static bool arg_legend = true;
1f849790 41static char *arg_address = NULL;
56e61788
LP
42static bool arg_unique = false;
43static bool arg_acquired = false;
44static bool arg_activatable = false;
45static bool arg_show_machine = false;
1f849790 46static char **arg_matches = NULL;
d75edbd6
LP
47static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
48static char *arg_host = NULL;
49static bool arg_user = false;
1f70b087 50static size_t arg_snaplen = 4096;
d9130355 51static bool arg_list = false;
781fa938 52static bool arg_quiet = false;
1f849790
LP
53
54static void pager_open_if_enabled(void) {
55
56 /* Cache result before we open the pager */
57 if (arg_no_pager)
58 return;
59
60 pager_open(false);
61}
62
63static int list_bus_names(sd_bus *bus, char **argv) {
71f2ab46 64 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
5e2f14e6
LP
65 _cleanup_free_ char **merged = NULL;
66 _cleanup_hashmap_free_ Hashmap *names = NULL;
de1c301e
LP
67 char **i;
68 int r;
89ffcd2a 69 size_t max_i = 0;
5e2f14e6
LP
70 unsigned n = 0;
71 void *v;
72 char *k;
73 Iterator iterator;
de1c301e 74
1f849790 75 assert(bus);
de1c301e 76
d9130355
LP
77 if (!arg_unique && !arg_acquired && !arg_activatable)
78 arg_unique = arg_acquired = arg_activatable = true;
79
56e61788 80 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
de1c301e
LP
81 if (r < 0) {
82 log_error("Failed to list names: %s", strerror(-r));
1f849790 83 return r;
de1c301e
LP
84 }
85
1f849790
LP
86 pager_open_if_enabled();
87
d5099efc 88 names = hashmap_new(&string_hash_ops);
5e2f14e6
LP
89 if (!names)
90 return log_oom();
89ffcd2a 91
5e2f14e6 92 STRV_FOREACH(i, acquired) {
71f2ab46
LP
93 max_i = MAX(max_i, strlen(*i));
94
5e2f14e6
LP
95 r = hashmap_put(names, *i, INT_TO_PTR(1));
96 if (r < 0) {
97 log_error("Failed to add to hashmap: %s", strerror(-r));
98 return r;
99 }
100 }
101
102 STRV_FOREACH(i, activatable) {
89ffcd2a
LP
103 max_i = MAX(max_i, strlen(*i));
104
5e2f14e6
LP
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));
108 return r;
109 }
110 }
111
112 merged = new(char*, hashmap_size(names) + 1);
113 HASHMAP_FOREACH_KEY(v, k, names, iterator)
114 merged[n++] = k;
115
116 merged[n] = NULL;
117 strv_sort(merged);
118
17d47d8d
TA
119 if (arg_legend) {
120 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
455971c1 121 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
89ffcd2a 122
17d47d8d
TA
123 if (arg_show_machine)
124 puts(" MACHINE");
125 else
126 putchar('\n');
127 }
a4297f08 128
5e2f14e6
LP
129 STRV_FOREACH(i, merged) {
130 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
131 sd_id128_t mid;
71f2ab46 132
5e2f14e6
LP
133 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
134 /* Activatable */
71f2ab46 135
5e2f14e6 136 printf("%-*s", (int) max_i, *i);
56e61788
LP
137 printf(" - - - (activatable) - - ");
138 if (arg_show_machine)
5e2f14e6 139 puts(" -");
56e61788
LP
140 else
141 putchar('\n');
71f2ab46
LP
142 continue;
143
5e2f14e6 144 }
de1c301e 145
56e61788
LP
146 if (!arg_unique && (*i)[0] == ':')
147 continue;
148
149 if (!arg_acquired && (*i)[0] != ':')
1f849790 150 continue;
89ffcd2a
LP
151
152 printf("%-*s", (int) max_i, *i);
de1c301e 153
056f95d0 154 r = sd_bus_get_name_creds(bus, *i,
14008e4e
LP
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|
455971c1 157 SD_BUS_CREDS_DESCRIPTION, &creds);
89ffcd2a 158 if (r >= 0) {
14008e4e 159 const char *unique, *session, *unit, *cn;
5b12334d
LP
160 pid_t pid;
161 uid_t uid;
de1c301e 162
5b12334d
LP
163 r = sd_bus_creds_get_pid(creds, &pid);
164 if (r >= 0) {
165 const char *comm = NULL;
de1c301e 166
5b12334d 167 sd_bus_creds_get_comm(creds, &comm);
89ffcd2a 168
5b12334d
LP
169 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
170 } else
a4297f08 171 fputs(" - - ", stdout);
89ffcd2a 172
5b12334d
LP
173 r = sd_bus_creds_get_uid(creds, &uid);
174 if (r >= 0) {
175 _cleanup_free_ char *u = NULL;
89ffcd2a 176
5b12334d
LP
177 u = uid_to_name(uid);
178 if (!u)
179 return log_oom();
89ffcd2a 180
5b12334d
LP
181 if (strlen(u) > 16)
182 u[16] = 0;
183
184 printf(" %-16s", u);
185 } else
a4297f08 186 fputs(" - ", stdout);
89ffcd2a 187
49b832c5
LP
188 r = sd_bus_creds_get_unique_name(creds, &unique);
189 if (r >= 0)
56e61788
LP
190 printf(" %-13s", unique);
191 else
192 fputs(" - ", stdout);
193
194 r = sd_bus_creds_get_unit(creds, &unit);
195 if (r >= 0) {
196 _cleanup_free_ char *e;
197
198 e = ellipsize(unit, 25, 100);
199 if (!e)
200 return log_oom();
201
202 printf(" %-25s", e);
203 } else
204 fputs(" - ", stdout);
205
206 r = sd_bus_creds_get_session(creds, &session);
207 if (r >= 0)
208 printf(" %-10s", session);
a4297f08 209 else
56e61788 210 fputs(" - ", stdout);
7b0b392f 211
455971c1 212 r = sd_bus_creds_get_description(creds, &cn);
14008e4e
LP
213 if (r >= 0)
214 printf(" %-19s", cn);
215 else
216 fputs(" - ", stdout);
217
7b0b392f 218 } else
14008e4e 219 printf(" - - - - - - - ");
a4297f08 220
56e61788 221 if (arg_show_machine) {
056f95d0 222 r = sd_bus_get_name_machine_id(bus, *i, &mid);
a4297f08
LP
223 if (r >= 0) {
224 char m[SD_ID128_STRING_MAX];
225 printf(" %s\n", sd_id128_to_string(mid, m));
226 } else
227 puts(" -");
56e61788
LP
228 } else
229 putchar('\n');
de1c301e
LP
230 }
231
1f849790
LP
232 return 0;
233}
234
d9130355
LP
235static void print_subtree(const char *prefix, const char *path, char **l) {
236 const char *vertical, *space;
237 char **n;
238
239 /* We assume the list is sorted. Let's first skip over the
240 * entry we are looking at. */
241 for (;;) {
242 if (!*l)
243 return;
244
245 if (!streq(*l, path))
246 break;
247
248 l++;
249 }
250
251 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
252 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
253
254 for (;;) {
255 bool has_more = false;
256
257 if (!*l || !path_startswith(*l, path))
258 break;
259
260 n = l + 1;
261 for (;;) {
262 if (!*n || !path_startswith(*n, path))
263 break;
264
265 if (!path_startswith(*n, *l)) {
266 has_more = true;
267 break;
268 }
269
270 n++;
271 }
272
273 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
274
275 print_subtree(has_more ? vertical : space, *l, l);
276 l = n;
277 }
278}
279
280static void print_tree(const char *prefix, char **l) {
281
282 pager_open_if_enabled();
283
284 prefix = strempty(prefix);
285
286 if (arg_list) {
287 char **i;
288
289 STRV_FOREACH(i, l)
290 printf("%s%s\n", prefix, *i);
291 return;
292 }
293
294 if (!strv_isempty(l))
295 printf("%s/\n", prefix);
296
297 print_subtree(prefix, "/", l);
298}
299
300static int parse_xml_annotation(
301 const char **p,
302 void **xml_state) {
303
304
305 enum {
306 STATE_ANNOTATION,
307 STATE_NAME,
308 STATE_VALUE
309 } state = STATE_ANNOTATION;
310
311 for (;;) {
312 _cleanup_free_ char *name = NULL;
313
314 int t;
315
316 t = xml_tokenize(p, &name, xml_state, NULL);
317 if (t < 0) {
318 log_error("XML parse error.");
319 return t;
320 }
321
322 if (t == XML_END) {
323 log_error("Premature end of XML data.");
324 return -EBADMSG;
325 }
326
327 switch (state) {
328
329 case STATE_ANNOTATION:
330
331 if (t == XML_ATTRIBUTE_NAME) {
332
333 if (streq_ptr(name, "name"))
334 state = STATE_NAME;
335
336 else if (streq_ptr(name, "value"))
337 state = STATE_VALUE;
338
339 else {
340 log_error("Unexpected <annotation> attribute %s.", name);
341 return -EBADMSG;
342 }
343
344 } else if (t == XML_TAG_CLOSE_EMPTY ||
345 (t == XML_TAG_CLOSE && streq_ptr(name, "annotation")))
346
347 return 0;
348
349 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
350 log_error("Unexpected token in <annotation>. (1)");
351 return -EINVAL;
352 }
353
354 break;
355
356 case STATE_NAME:
357
358 if (t == XML_ATTRIBUTE_VALUE)
359 state = STATE_ANNOTATION;
360 else {
361 log_error("Unexpected token in <annotation>. (2)");
362 return -EINVAL;
363 }
364
365 break;
366
367 case STATE_VALUE:
368
369 if (t == XML_ATTRIBUTE_VALUE)
370 state = STATE_ANNOTATION;
371 else {
372 log_error("Unexpected token in <annotation>. (3)");
373 return -EINVAL;
374 }
375
376 break;
377
378 default:
379 assert_not_reached("Bad state");
380 }
381 }
382}
383
384static int parse_xml_node(
385 const char *prefix,
386 Set *paths,
387 const char **p,
388 void **xml_state) {
389
390 enum {
391 STATE_NODE,
392 STATE_NODE_NAME,
393 STATE_INTERFACE,
394 STATE_INTERFACE_NAME,
395 STATE_METHOD,
396 STATE_METHOD_NAME,
397 STATE_METHOD_ARG,
398 STATE_METHOD_ARG_NAME,
399 STATE_METHOD_ARG_TYPE,
400 STATE_METHOD_ARG_DIRECTION,
401 STATE_SIGNAL,
402 STATE_SIGNAL_NAME,
403 STATE_SIGNAL_ARG,
404 STATE_SIGNAL_ARG_NAME,
405 STATE_SIGNAL_ARG_TYPE,
406 STATE_PROPERTY,
407 STATE_PROPERTY_NAME,
408 STATE_PROPERTY_TYPE,
409 STATE_PROPERTY_ACCESS,
410 } state = STATE_NODE;
411
412 _cleanup_free_ char *node_path = NULL;
413 const char *np = prefix;
414 int r;
415
416 for (;;) {
417 _cleanup_free_ char *name = NULL;
418 int t;
419
420 t = xml_tokenize(p, &name, xml_state, NULL);
421 if (t < 0) {
422 log_error("XML parse error.");
423 return t;
424 }
425
426 if (t == XML_END) {
427 log_error("Premature end of XML data.");
428 return -EBADMSG;
429 }
430
431 switch (state) {
432
433 case STATE_NODE:
434 if (t == XML_ATTRIBUTE_NAME) {
435
436 if (streq_ptr(name, "name"))
437 state = STATE_NODE_NAME;
438 else {
439 log_error("Unexpected <node> attribute %s.", name);
440 return -EBADMSG;
441 }
442
443 } else if (t == XML_TAG_OPEN) {
444
445 if (streq_ptr(name, "interface"))
446 state = STATE_INTERFACE;
447
448 else if (streq_ptr(name, "node")) {
449
450 r = parse_xml_node(np, paths, p, xml_state);
451 if (r < 0)
452 return r;
453 } else {
454 log_error("Unexpected <node> tag %s.", name);
455 return -EBADMSG;
456 }
457 } else if (t == XML_TAG_CLOSE_EMPTY ||
458 (t == XML_TAG_CLOSE && streq_ptr(name, "node"))) {
459
460 if (paths) {
461 if (!node_path) {
462 node_path = strdup(np);
463 if (!node_path)
464 return log_oom();
465 }
466
467 r = set_put(paths, node_path);
468 if (r < 0)
469 return log_oom();
470 else if (r > 0)
471 node_path = NULL;
472 }
473
474 return 0;
475
476 } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
477 log_error("Unexpected token in <node>. (1)");
478 return -EINVAL;
479 }
480
481 break;
482
483 case STATE_NODE_NAME:
484
485 if (t == XML_ATTRIBUTE_VALUE) {
486
487 free(node_path);
488
489 if (name[0] == '/') {
490 node_path = name;
491 name = NULL;
492 } else {
493
494 if (endswith(prefix, "/"))
495 node_path = strappend(prefix, name);
496 else
497 node_path = strjoin(prefix, "/", name, NULL);
498 if (!node_path)
499 return log_oom();
500 }
501
502 np = node_path;
503 state = STATE_NODE;
504 } else {
505 log_error("Unexpected token in <node>. (2)");
506 return -EINVAL;
507 }
508
509 break;
510
511 case STATE_INTERFACE:
512
513 if (t == XML_ATTRIBUTE_NAME) {
514 if (streq_ptr(name, "name"))
515 state = STATE_INTERFACE_NAME;
516 else {
517 log_error("Unexpected <interface> attribute %s.", name);
518 return -EBADMSG;
519 }
520
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);
530 if (r < 0)
531 return r;
532 } else {
533 log_error("Unexpected <interface> tag %s.", name);
534 return -EINVAL;
535 }
536 } else if (t == XML_TAG_CLOSE_EMPTY ||
537 (t == XML_TAG_CLOSE && streq_ptr(name, "interface")))
538
539 state = STATE_NODE;
540
541 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
542 log_error("Unexpected token in <interface>. (1)");
543 return -EINVAL;
544 }
545
546 break;
547
548 case STATE_INTERFACE_NAME:
549
550 if (t == XML_ATTRIBUTE_VALUE)
551 state = STATE_INTERFACE;
552 else {
553 log_error("Unexpected token in <interface>. (2)");
554 return -EINVAL;
555 }
556
557 break;
558
559 case STATE_METHOD:
560
561 if (t == XML_ATTRIBUTE_NAME) {
562 if (streq_ptr(name, "name"))
563 state = STATE_METHOD_NAME;
564 else {
565 log_error("Unexpected <method> attribute %s", name);
566 return -EBADMSG;
567 }
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);
573 if (r < 0)
574 return r;
575 } else {
576 log_error("Unexpected <method> tag %s.", name);
577 return -EINVAL;
578 }
579 } else if (t == XML_TAG_CLOSE_EMPTY ||
580 (t == XML_TAG_CLOSE && streq_ptr(name, "method")))
581
582 state = STATE_INTERFACE;
583
584 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
585 log_error("Unexpected token in <method> (1).");
586 return -EINVAL;
587 }
588
589 break;
590
591 case STATE_METHOD_NAME:
592
593 if (t == XML_ATTRIBUTE_VALUE)
594 state = STATE_METHOD;
595 else {
596 log_error("Unexpected token in <method> (2).");
597 return -EINVAL;
598 }
599
600 break;
601
602 case STATE_METHOD_ARG:
603
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;
611 else {
612 log_error("Unexpected method <arg> attribute %s.", name);
613 return -EBADMSG;
614 }
615 } else if (t == XML_TAG_OPEN) {
616 if (streq_ptr(name, "annotation")) {
617 r = parse_xml_annotation(p, xml_state);
618 if (r < 0)
619 return r;
620 } else {
621 log_error("Unexpected method <arg> tag %s.", name);
622 return -EINVAL;
623 }
624 } else if (t == XML_TAG_CLOSE_EMPTY ||
625 (t == XML_TAG_CLOSE && streq_ptr(name, "arg")))
626
627 state = STATE_METHOD;
628
629 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
630 log_error("Unexpected token in method <arg>. (1)");
631 return -EINVAL;
632 }
633
634 break;
635
636 case STATE_METHOD_ARG_NAME:
637
638 if (t == XML_ATTRIBUTE_VALUE)
639 state = STATE_METHOD_ARG;
640 else {
641 log_error("Unexpected token in method <arg>. (2)");
642 return -EINVAL;
643 }
644
645 break;
646
647 case STATE_METHOD_ARG_TYPE:
648
649 if (t == XML_ATTRIBUTE_VALUE)
650 state = STATE_METHOD_ARG;
651 else {
652 log_error("Unexpected token in method <arg>. (3)");
653 return -EINVAL;
654 }
655
656 break;
657
658 case STATE_METHOD_ARG_DIRECTION:
659
660 if (t == XML_ATTRIBUTE_VALUE)
661 state = STATE_METHOD_ARG;
662 else {
663 log_error("Unexpected token in method <arg>. (4)");
664 return -EINVAL;
665 }
666
667 break;
668
669 case STATE_SIGNAL:
670
671 if (t == XML_ATTRIBUTE_NAME) {
672 if (streq_ptr(name, "name"))
673 state = STATE_SIGNAL_NAME;
674 else {
675 log_error("Unexpected <signal> attribute %s.", name);
676 return -EBADMSG;
677 }
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);
683 if (r < 0)
684 return r;
685 } else {
686 log_error("Unexpected <signal> tag %s.", name);
687 return -EINVAL;
688 }
689 } else if (t == XML_TAG_CLOSE_EMPTY ||
690 (t == XML_TAG_CLOSE && streq_ptr(name, "signal")))
691
692 state = STATE_INTERFACE;
693
694 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
695 log_error("Unexpected token in <signal>. (1)");
696 return -EINVAL;
697 }
698
699 break;
700
701 case STATE_SIGNAL_NAME:
702
703 if (t == XML_ATTRIBUTE_VALUE)
704 state = STATE_SIGNAL;
705 else {
706 log_error("Unexpected token in <signal>. (2)");
707 return -EINVAL;
708 }
709
710 break;
711
712
713 case STATE_SIGNAL_ARG:
714
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;
720 else {
721 log_error("Unexpected signal <arg> attribute %s.", name);
722 return -EBADMSG;
723 }
724 } else if (t == XML_TAG_OPEN) {
725 if (streq_ptr(name, "annotation")) {
726 r = parse_xml_annotation(p, xml_state);
727 if (r < 0)
728 return r;
729 } else {
730 log_error("Unexpected signal <arg> tag %s.", name);
731 return -EINVAL;
732 }
733 } else if (t == XML_TAG_CLOSE_EMPTY ||
734 (t == XML_TAG_CLOSE && streq_ptr(name, "arg")))
735
736 state = STATE_SIGNAL;
737
738 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
739 log_error("Unexpected token in signal <arg> (1).");
740 return -EINVAL;
741 }
742
743 break;
744
745 case STATE_SIGNAL_ARG_NAME:
746
747 if (t == XML_ATTRIBUTE_VALUE)
748 state = STATE_SIGNAL_ARG;
749 else {
750 log_error("Unexpected token in signal <arg> (2).");
751 return -EINVAL;
752 }
753
754 break;
755
756 case STATE_SIGNAL_ARG_TYPE:
757
758 if (t == XML_ATTRIBUTE_VALUE)
759 state = STATE_SIGNAL_ARG;
760 else {
761 log_error("Unexpected token in signal <arg> (3).");
762 return -EINVAL;
763 }
764
765 break;
766
767 case STATE_PROPERTY:
768
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;
776 else {
777 log_error("Unexpected <property> attribute %s.", name);
778 return -EBADMSG;
779 }
780 } else if (t == XML_TAG_OPEN) {
781
782 if (streq_ptr(name, "annotation")) {
783 r = parse_xml_annotation(p, xml_state);
784 if (r < 0)
785 return r;
786 } else {
787 log_error("Unexpected <property> tag %s.", name);
788 return -EINVAL;
789 }
790
791 } else if (t == XML_TAG_CLOSE_EMPTY ||
792 (t == XML_TAG_CLOSE && streq_ptr(name, "property")))
793
794 state = STATE_INTERFACE;
795
796 else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
797 log_error("Unexpected token in <property>. (1)");
798 return -EINVAL;
799 }
800
801 break;
802
803 case STATE_PROPERTY_NAME:
804
805 if (t == XML_ATTRIBUTE_VALUE)
806 state = STATE_PROPERTY;
807 else {
808 log_error("Unexpected token in <property>. (2)");
809 return -EINVAL;
810 }
811
812 break;
813
814 case STATE_PROPERTY_TYPE:
815
816 if (t == XML_ATTRIBUTE_VALUE)
817 state = STATE_PROPERTY;
818 else {
819 log_error("Unexpected token in <property>. (3)");
820 return -EINVAL;
821 }
822
823 break;
824
825 case STATE_PROPERTY_ACCESS:
826
827 if (t == XML_ATTRIBUTE_VALUE)
828 state = STATE_PROPERTY;
829 else {
830 log_error("Unexpected token in <property>. (4)");
831 return -EINVAL;
832 }
833
834 break;
835 }
836 }
837}
838
839static 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;
842 const char *xml, *p;
843 void *xml_state = NULL;
844 int r;
845
846 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
847 if (r < 0) {
848 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
849 return r;
850 }
851
852 r = sd_bus_message_read(reply, "s", &xml);
853 if (r < 0)
854 return bus_log_parse_error(r);
855
856 /* fputs(xml, stdout); */
857
858 p = xml;
859 for (;;) {
860 _cleanup_free_ char *name = NULL;
861
862 r = xml_tokenize(&p, &name, &xml_state, NULL);
863 if (r < 0) {
864 log_error("XML parse error");
865 return r;
866 }
867
868 if (r == XML_END)
869 break;
870
871 if (r == XML_TAG_OPEN) {
872
873 if (streq(name, "node")) {
874 r = parse_xml_node(path, paths, &p, &xml_state);
875 if (r < 0)
876 return r;
877 } else {
878 log_error("Unexpected tag '%s' in introspection data.", name);
879 return -EBADMSG;
880 }
881 } else if (r != XML_TEXT || !in_charset(name, WHITESPACE)) {
882 log_error("Unexpected token.");
883 return -EINVAL;
884 }
885 }
886
887 return 0;
888}
889
890static 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;
893 char *m;
894 int r;
895
896 paths = set_new(&string_hash_ops);
897 if (!paths)
898 return log_oom();
899
900 done = set_new(&string_hash_ops);
901 if (!done)
902 return log_oom();
903
904 failed = set_new(&string_hash_ops);
905 if (!failed)
906 return log_oom();
907
908 m = strdup("/");
909 if (!m)
910 return log_oom();
911
912 r = set_put(paths, m);
913 if (r < 0) {
914 free(m);
915 return log_oom();
916 }
917
918 for (;;) {
919 _cleanup_free_ char *p = NULL;
920 int q;
921
922 p = set_steal_first(paths);
923 if (!p)
924 break;
925
926 if (set_contains(done, p) ||
927 set_contains(failed, p))
928 continue;
929
930 q = find_nodes(bus, service, p, paths);
931 if (q < 0) {
932 if (r >= 0)
933 r = q;
934
935 q = set_put(failed, p);
936 } else
937 q = set_put(done, p);
938
939 if (q < 0)
940 return log_oom();
941
942 assert(q != 0);
943 p = NULL;
944 }
945
946 l = set_get_strv(done);
947 if (!l)
948 return log_oom();
949
950 strv_sort(l);
951 print_tree(prefix, l);
952
953 fflush(stdout);
954
955 return r;
956}
957
958static int tree(sd_bus *bus, char **argv) {
959 char **i;
960 int r = 0;
961
962 if (!arg_unique && !arg_acquired)
963 arg_acquired = true;
964
965 if (strv_length(argv) <= 1) {
966 _cleanup_strv_free_ char **names = NULL;
967 bool not_first = true;
968
969 r = sd_bus_list_names(bus, &names, NULL);
970 if (r < 0) {
971 log_error("Failed to get name list: %s", strerror(-r));
972 return r;
973 }
974
975 pager_open_if_enabled();
976
977 STRV_FOREACH(i, names) {
978 int q;
979
980 if (!arg_unique && (*i)[0] == ':')
981 continue;
982
983 if (!arg_acquired && (*i)[0] == ':')
984 continue;
985
986 if (not_first)
987 printf("\n");
988
989 printf("Service %s:\n", *i);
990
991 q = tree_one(bus, *i, "\t");
992 if (q < 0 && r >= 0)
993 r = q;
994
995 not_first = true;
996 }
997 } else {
998 pager_open_if_enabled();
999
1000 STRV_FOREACH(i, argv+1) {
1001 int q;
1002
1003 if (i > argv+1)
1004 printf("\n");
1005
1006 if (argv[2])
1007 printf("Service %s:\n", *i);
1008
1009 q = tree_one(bus, *i, NULL);
1010 if (q < 0 && r >= 0)
1011 r = q;
1012 }
1013 }
1014
1015 return r;
1016}
1017
1f70b087
LP
1018static int message_dump(sd_bus_message *m, FILE *f) {
1019 return bus_message_dump(m, f, true);
1020}
1021
1022static int message_pcap(sd_bus_message *m, FILE *f) {
1023 return bus_message_pcap_frame(m, arg_snaplen, f);
1024}
1025
1026static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
b51f299a 1027 bool added_something = false;
1f849790
LP
1028 char **i;
1029 int r;
1030
1031 STRV_FOREACH(i, argv+1) {
1032 _cleanup_free_ char *m = NULL;
1033
1034 if (!service_name_is_valid(*i)) {
1035 log_error("Invalid service name '%s'", *i);
1036 return -EINVAL;
1037 }
1038
1039 m = strjoin("sender='", *i, "'", NULL);
1040 if (!m)
1041 return log_oom();
1042
19befb2d 1043 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1f849790
LP
1044 if (r < 0) {
1045 log_error("Failed to add match: %s", strerror(-r));
1046 return r;
1047 }
b51f299a
LP
1048
1049 added_something = true;
1f849790
LP
1050 }
1051
1052 STRV_FOREACH(i, arg_matches) {
19befb2d 1053 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1f849790
LP
1054 if (r < 0) {
1055 log_error("Failed to add match: %s", strerror(-r));
1056 return r;
1057 }
b51f299a
LP
1058
1059 added_something = true;
1060 }
1061
1062 if (!added_something) {
19befb2d 1063 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
b51f299a
LP
1064 if (r < 0) {
1065 log_error("Failed to add match: %s", strerror(-r));
1066 return r;
1067 }
1f849790
LP
1068 }
1069
1070 for (;;) {
1071 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1072
1073 r = sd_bus_process(bus, &m);
1074 if (r < 0) {
1075 log_error("Failed to process bus: %s", strerror(-r));
1076 return r;
1077 }
1078
1079 if (m) {
1f70b087 1080 dump(m, stdout);
1f849790
LP
1081 continue;
1082 }
1083
1084 if (r > 0)
1085 continue;
1086
1087 r = sd_bus_wait(bus, (uint64_t) -1);
1088 if (r < 0) {
1089 log_error("Failed to wait for bus: %s", strerror(-r));
1090 return r;
1091 }
1092 }
95c4fe82 1093}
1f849790 1094
1f70b087
LP
1095static int capture(sd_bus *bus, char *argv[]) {
1096 int r;
1097
1098 if (isatty(fileno(stdout)) > 0) {
1099 log_error("Refusing to write message data to console, please redirect output to a file.");
1100 return -EINVAL;
1101 }
1102
1103 bus_pcap_header(arg_snaplen, stdout);
1104
1105 r = monitor(bus, argv, message_pcap);
1106 if (r < 0)
1107 return r;
1108
1109 if (ferror(stdout)) {
1110 log_error("Couldn't write capture file.");
1111 return -EIO;
1112 }
1113
1114 return r;
1115}
1116
95c4fe82
LP
1117static int status(sd_bus *bus, char *argv[]) {
1118 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1119 pid_t pid;
1120 int r;
1121
1122 assert(bus);
1123
1124 if (strv_length(argv) != 2) {
1125 log_error("Expects one argument.");
1126 return -EINVAL;
1127 }
1128
1129 r = parse_pid(argv[1], &pid);
1130 if (r < 0)
056f95d0 1131 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
95c4fe82 1132 else
151b9b96 1133 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
95c4fe82
LP
1134
1135 if (r < 0) {
1136 log_error("Failed to get credentials: %s", strerror(-r));
1137 return r;
1138 }
1139
1140 bus_creds_dump(creds, NULL);
1141 return 0;
1f849790
LP
1142}
1143
781fa938
LP
1144static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1145 char **p;
1146 int r;
1147
1148 assert(m);
1149 assert(signature);
1150 assert(x);
1151
1152 p = *x;
1153
1154 for (;;) {
1155 const char *v;
1156 char t;
1157
1158 t = *signature;
1159 v = *p;
1160
1161 if (t == 0)
1162 break;
1163 if (!v) {
1164 log_error("Too few parameters for signature.");
1165 return -EINVAL;
1166 }
1167
1168 signature++;
1169 p++;
1170
1171 switch (t) {
1172
1173 case SD_BUS_TYPE_BOOLEAN:
1174
1175 r = parse_boolean(v);
1176 if (r < 0) {
1177 log_error("Failed to parse as boolean: %s", v);
1178 return r;
1179 }
1180
1181 r = sd_bus_message_append_basic(m, t, &r);
1182 break;
1183
1184 case SD_BUS_TYPE_BYTE: {
1185 uint8_t z;
1186
1187 r = safe_atou8(v, &z);
1188 if (r < 0) {
1189 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1190 return r;
1191 }
1192
1193 r = sd_bus_message_append_basic(m, t, &z);
1194 break;
1195 }
1196
1197 case SD_BUS_TYPE_INT16: {
1198 int16_t z;
1199
1200 r = safe_atoi16(v, &z);
1201 if (r < 0) {
1202 log_error("Failed to parse as signed 16bit integer: %s", v);
1203 return r;
1204 }
1205
1206 r = sd_bus_message_append_basic(m, t, &z);
1207 break;
1208 }
1209
1210 case SD_BUS_TYPE_UINT16: {
1211 uint16_t z;
1212
1213 r = safe_atou16(v, &z);
1214 if (r < 0) {
1215 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1216 return r;
1217 }
1218
1219 r = sd_bus_message_append_basic(m, t, &z);
1220 break;
1221 }
1222
1223 case SD_BUS_TYPE_INT32: {
1224 int32_t z;
1225
1226 r = safe_atoi32(v, &z);
1227 if (r < 0) {
1228 log_error("Failed to parse as signed 32bit integer: %s", v);
1229 return r;
1230 }
1231
1232 r = sd_bus_message_append_basic(m, t, &z);
1233 break;
1234 }
1235
1236 case SD_BUS_TYPE_UINT32: {
1237 uint32_t z;
1238
1239 r = safe_atou32(v, &z);
1240 if (r < 0) {
1241 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1242 return r;
1243 }
1244
1245 r = sd_bus_message_append_basic(m, t, &z);
1246 break;
1247 }
1248
1249 case SD_BUS_TYPE_INT64: {
1250 int64_t z;
1251
1252 r = safe_atoi64(v, &z);
1253 if (r < 0) {
1254 log_error("Failed to parse as signed 64bit integer: %s", v);
1255 return r;
1256 }
1257
1258 r = sd_bus_message_append_basic(m, t, &z);
1259 break;
1260 }
1261
1262 case SD_BUS_TYPE_UINT64: {
1263 uint64_t z;
1264
1265 r = safe_atou64(v, &z);
1266 if (r < 0) {
1267 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1268 return r;
1269 }
1270
1271 r = sd_bus_message_append_basic(m, t, &z);
1272 break;
1273 }
1274
1275
1276 case SD_BUS_TYPE_DOUBLE: {
1277 double z;
1278
1279 r = safe_atod(v, &z);
1280 if (r < 0) {
1281 log_error("Failed to parse as double precision floating point: %s", v);
1282 return r;
1283 }
1284
1285 r = sd_bus_message_append_basic(m, t, &z);
1286 break;
1287 }
1288
1289 case SD_BUS_TYPE_STRING:
1290 case SD_BUS_TYPE_OBJECT_PATH:
1291 case SD_BUS_TYPE_SIGNATURE:
1292
1293 r = sd_bus_message_append_basic(m, t, v);
1294 break;
1295
1296 case SD_BUS_TYPE_ARRAY: {
1297 uint32_t n;
1298 size_t k;
1299
1300 r = safe_atou32(v, &n);
1301 if (r < 0) {
1302 log_error("Failed to parse number of array entries: %s", v);
1303 return r;
1304 }
1305
1306 r = signature_element_length(signature, &k);
1307 if (r < 0) {
1308 log_error("Invalid array signature.");
1309 return r;
1310 }
1311
1312 {
1313 unsigned i;
1314 char s[k + 1];
1315 memcpy(s, signature, k);
1316 s[k] = 0;
1317
1318 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1319 if (r < 0)
1320 return bus_log_create_error(r);
1321
1322 for (i = 0; i < n; i++) {
1323 r = message_append_cmdline(m, s, &p);
1324 if (r < 0)
1325 return r;
1326 }
1327 }
1328
1329 signature += k;
1330
1331 r = sd_bus_message_close_container(m);
1332 break;
1333 }
1334
1335 case SD_BUS_TYPE_VARIANT:
1336 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1337 if (r < 0)
1338 return bus_log_create_error(r);
1339
1340 r = message_append_cmdline(m, v, &p);
1341 if (r < 0)
1342 return r;
1343
1344 r = sd_bus_message_close_container(m);
1345 break;
1346
1347 case SD_BUS_TYPE_STRUCT_BEGIN:
1348 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1349 size_t k;
1350
1351 signature--;
1352 p--;
1353
1354 r = signature_element_length(signature, &k);
1355 if (r < 0) {
1356 log_error("Invalid struct/dict entry signature.");
1357 return r;
1358 }
1359
1360 {
1361 char s[k-1];
1362 memcpy(s, signature + 1, k - 2);
1363 s[k - 2] = 0;
1364
1365 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1366 if (r < 0)
1367 return bus_log_create_error(r);
1368
1369 r = message_append_cmdline(m, s, &p);
1370 if (r < 0)
1371 return r;
1372 }
1373
1374 signature += k;
1375
1376 r = sd_bus_message_close_container(m);
1377 break;
1378 }
1379
1380 case SD_BUS_TYPE_UNIX_FD:
1381 log_error("UNIX file descriptor not supported as type.");
1382 return -EINVAL;
1383
1384 default:
1385 log_error("Unknown signature type %c.", t);
1386 return -EINVAL;
1387 }
1388
1389 if (r < 0)
1390 return bus_log_create_error(r);
1391 }
1392
1393 *x = p;
1394 return 0;
1395}
1396
1397static 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;
1400 int r;
1401
1402 assert(bus);
1403
1404 if (strv_length(argv) < 5) {
1405 log_error("Expects at least four arguments.");
1406 return -EINVAL;
1407 }
1408
1409 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1410 if (r < 0) {
1411 log_error("Failed to prepare bus message: %s", strerror(-r));
1412 return r;
1413 }
1414
1415 if (!isempty(argv[5])) {
1416 char **p;
1417
1418 p = argv+6;
1419
1420 r = message_append_cmdline(m, argv[5], &p);
1421 if (r < 0)
1422 return r;
1423
1424 if (*p) {
1425 log_error("Too many parameters for signature.");
1426 return -EINVAL;
1427 }
1428 }
1429
1430 r = sd_bus_call(bus, m, 0, &error, &reply);
1431 if (r < 0) {
1432 log_error("%s", bus_error_message(&error, r));
1433 return r;
1434 }
1435
1436 r = sd_bus_message_is_empty(reply);
1437 if (r < 0)
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);
1442 }
1443
1444 return 0;
1445}
1446
1f849790 1447static int help(void) {
1f849790
LP
1448 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1449 "Introspect the bus.\n\n"
d75edbd6
LP
1450 " -h --help Show this help\n"
1451 " --version Show package version\n"
a86a47ce 1452 " --no-pager Do not pipe output into a pager\n"
17d47d8d 1453 " --no-legend Do not show the headers and footers\n"
d75edbd6
LP
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"
56e61788
LP
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"
d9130355 1463 " --match=MATCH Only show matching messages\n"
781fa938
LP
1464 " --list Don't show tree, but simple object path list\n"
1465 " --quiet Don't show method call reply\n\n"
1f849790 1466 "Commands:\n"
d75edbd6 1467 " list List bus names\n"
d9130355 1468 " tree [SERVICE...] Show object tree of service\n"
d94fe1f1 1469 " monitor [SERVICE...] Show bus traffic\n"
1f70b087 1470 " capture [SERVICE...] Capture bus traffic as pcap\n"
781fa938
LP
1471 " status SERVICE Show service name status\n"
1472 " call SERVICE PATH INTERFACE METHOD [SIGNATURE] [ARGUMENTS...]\n"
1473 " Call a method\n"
601185b4
ZJS
1474 " help Show this help\n"
1475 , program_invocation_short_name);
1f849790
LP
1476
1477 return 0;
1478}
1479
1480static int parse_argv(int argc, char *argv[]) {
1481
1482 enum {
1483 ARG_VERSION = 0x100,
1484 ARG_NO_PAGER,
17d47d8d 1485 ARG_NO_LEGEND,
1f849790
LP
1486 ARG_SYSTEM,
1487 ARG_USER,
1488 ARG_ADDRESS,
1489 ARG_MATCH,
56e61788
LP
1490 ARG_SHOW_MACHINE,
1491 ARG_UNIQUE,
1492 ARG_ACQUIRED,
1f70b087
LP
1493 ARG_ACTIVATABLE,
1494 ARG_SIZE,
d9130355 1495 ARG_LIST,
1f849790
LP
1496 };
1497
1498 static const struct option options[] = {
56e61788
LP
1499 { "help", no_argument, NULL, 'h' },
1500 { "version", no_argument, NULL, ARG_VERSION },
1501 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
17d47d8d 1502 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
56e61788
LP
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' },
1f70b087 1513 { "size", required_argument, NULL, ARG_SIZE },
d9130355 1514 { "list", no_argument, NULL, ARG_LIST },
781fa938 1515 { "quiet", no_argument, NULL, 'q' },
eb9da376 1516 {},
1f849790
LP
1517 };
1518
1f70b087 1519 int c, r;
1f849790
LP
1520
1521 assert(argc >= 0);
1522 assert(argv);
1523
781fa938 1524 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1f849790
LP
1525
1526 switch (c) {
1527
1528 case 'h':
1529 return help();
1530
1531 case ARG_VERSION:
1532 puts(PACKAGE_STRING);
1533 puts(SYSTEMD_FEATURES);
1534 return 0;
1535
1536 case ARG_NO_PAGER:
1537 arg_no_pager = true;
1538 break;
1539
17d47d8d
TA
1540 case ARG_NO_LEGEND:
1541 arg_legend = false;
1542 break;
1543
1f849790
LP
1544 case ARG_USER:
1545 arg_user = true;
1546 break;
1547
1548 case ARG_SYSTEM:
1549 arg_user = false;
1550 break;
1551
1552 case ARG_ADDRESS:
1553 arg_address = optarg;
1554 break;
1555
56e61788
LP
1556 case ARG_SHOW_MACHINE:
1557 arg_show_machine = true;
1558 break;
1559
1560 case ARG_UNIQUE:
1561 arg_unique = true;
1f849790
LP
1562 break;
1563
56e61788
LP
1564 case ARG_ACQUIRED:
1565 arg_acquired = true;
1566 break;
1567
1568 case ARG_ACTIVATABLE:
1569 arg_activatable = true;
a4297f08
LP
1570 break;
1571
1f849790
LP
1572 case ARG_MATCH:
1573 if (strv_extend(&arg_matches, optarg) < 0)
1574 return log_oom();
1575 break;
1576
1f70b087
LP
1577 case ARG_SIZE: {
1578 off_t o;
1579
1580 r = parse_size(optarg, 0, &o);
1581 if (r < 0) {
1582 log_error("Failed to parse size: %s", optarg);
1583 return r;
1584 }
1585
1586 if ((off_t) (size_t) o != o) {
1587 log_error("Size out of range.");
1588 return -E2BIG;
1589 }
1590
1591 arg_snaplen = (size_t) o;
1592 break;
1593 }
1594
d9130355
LP
1595 case ARG_LIST:
1596 arg_list = true;
1597 break;
1598
d75edbd6
LP
1599 case 'H':
1600 arg_transport = BUS_TRANSPORT_REMOTE;
1601 arg_host = optarg;
1602 break;
1603
1604 case 'M':
1605 arg_transport = BUS_TRANSPORT_CONTAINER;
1606 arg_host = optarg;
1607 break;
1608
781fa938
LP
1609 case 'q':
1610 arg_quiet = true;
1611 break;
1612
1f849790
LP
1613 case '?':
1614 return -EINVAL;
1615
1616 default:
eb9da376 1617 assert_not_reached("Unhandled option");
1f849790 1618 }
1f849790
LP
1619
1620 return 1;
1621}
1622
1623static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1624 assert(bus);
1625
1626 if (optind >= argc ||
1627 streq(argv[optind], "list"))
1628 return list_bus_names(bus, argv + optind);
1629
1630 if (streq(argv[optind], "monitor"))
1f70b087
LP
1631 return monitor(bus, argv + optind, message_dump);
1632
1633 if (streq(argv[optind], "capture"))
1634 return capture(bus, argv + optind);
1f849790 1635
95c4fe82
LP
1636 if (streq(argv[optind], "status"))
1637 return status(bus, argv + optind);
d9130355
LP
1638
1639 if (streq(argv[optind], "tree"))
1640 return tree(bus, argv + optind);
781fa938
LP
1641
1642 if (streq(argv[optind], "call"))
1643 return call(bus, argv + optind);
95c4fe82 1644
1f849790
LP
1645 if (streq(argv[optind], "help"))
1646 return help();
1647
1648 log_error("Unknown command '%s'", argv[optind]);
1649 return -EINVAL;
1650}
1651
1652int main(int argc, char *argv[]) {
24996861 1653 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1f849790
LP
1654 int r;
1655
1656 log_parse_environment();
1657 log_open();
1658
1659 r = parse_argv(argc, argv);
1660 if (r <= 0)
1661 goto finish;
1662
09365592
LP
1663 r = sd_bus_new(&bus);
1664 if (r < 0) {
1665 log_error("Failed to allocate bus: %s", strerror(-r));
1666 goto finish;
1667 }
1668
1f70b087
LP
1669 if (streq_ptr(argv[optind], "monitor") ||
1670 streq_ptr(argv[optind], "capture")) {
09365592
LP
1671
1672 r = sd_bus_set_monitor(bus, true);
1f849790 1673 if (r < 0) {
09365592 1674 log_error("Failed to set monitor mode: %s", strerror(-r));
1f849790
LP
1675 goto finish;
1676 }
d0ce7734
LP
1677
1678 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1679 if (r < 0) {
1680 log_error("Failed to enable credentials: %s", strerror(-r));
1681 goto finish;
1682 }
1683
1684 r = sd_bus_negotiate_timestamp(bus, true);
1685 if (r < 0) {
1686 log_error("Failed to enable timestamps: %s", strerror(-r));
1687 goto finish;
1688 }
1689
1690 r = sd_bus_negotiate_fds(bus, true);
1691 if (r < 0) {
1692 log_error("Failed to enable fds: %s", strerror(-r));
1693 goto finish;
1694 }
09365592 1695 }
1f849790 1696
09365592 1697 if (arg_address)
1f849790 1698 r = sd_bus_set_address(bus, arg_address);
09365592
LP
1699 else {
1700 switch (arg_transport) {
1f849790 1701
09365592
LP
1702 case BUS_TRANSPORT_LOCAL:
1703 if (arg_user)
1704 r = bus_set_address_user(bus);
1705 else
1706 r = bus_set_address_system(bus);
1707 break;
1708
1709 case BUS_TRANSPORT_REMOTE:
1710 r = bus_set_address_system_remote(bus, arg_host);
1711 break;
1712
1713 case BUS_TRANSPORT_CONTAINER:
1714 r = bus_set_address_system_container(bus, arg_host);
1715 break;
1716
1717 default:
1718 assert_not_reached("Hmm, unknown transport type.");
1f849790 1719 }
09365592
LP
1720 }
1721 if (r < 0) {
1722 log_error("Failed to set address: %s", strerror(-r));
1723 goto finish;
1724 }
1f849790 1725
09365592
LP
1726 r = sd_bus_set_bus_client(bus, true);
1727 if (r < 0) {
1728 log_error("Failed to set bus client: %s", strerror(-r));
1729 goto finish;
1730 }
1f849790 1731
09365592 1732 r = sd_bus_start(bus);
1f849790
LP
1733 if (r < 0) {
1734 log_error("Failed to connect to bus: %s", strerror(-r));
1735 goto finish;
1736 }
1737
1738 r = busctl_main(bus, argc, argv);
1739
1740finish:
1741 pager_close();
d75edbd6 1742
1f849790 1743 strv_free(arg_matches);
de1c301e 1744
de1c301e
LP
1745 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1746}