]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/busctl/busctl.c
coccinelle: make use of SYNTHETIC_ERRNO
[thirdparty/systemd.git] / src / busctl / busctl.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <getopt.h>
4 #include <stdio_ext.h>
5
6 #include "sd-bus.h"
7
8 #include "alloc-util.h"
9 #include "bus-dump.h"
10 #include "bus-internal.h"
11 #include "bus-signature.h"
12 #include "bus-type.h"
13 #include "bus-util.h"
14 #include "busctl-introspect.h"
15 #include "escape.h"
16 #include "fd-util.h"
17 #include "fileio.h"
18 #include "json.h"
19 #include "locale-util.h"
20 #include "log.h"
21 #include "main-func.h"
22 #include "pager.h"
23 #include "parse-util.h"
24 #include "path-util.h"
25 #include "pretty-print.h"
26 #include "set.h"
27 #include "strv.h"
28 #include "terminal-util.h"
29 #include "user-util.h"
30 #include "util.h"
31 #include "verbs.h"
32
33 static enum {
34 JSON_OFF,
35 JSON_SHORT,
36 JSON_PRETTY,
37 } arg_json = JSON_OFF;
38 static PagerFlags arg_pager_flags = 0;
39 static bool arg_legend = true;
40 static const 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 const char *arg_host = NULL;
48 static bool arg_user = false;
49 static size_t arg_snaplen = 4096;
50 static bool arg_list = false;
51 static bool arg_quiet = false;
52 static bool arg_verbose = false;
53 static bool arg_expect_reply = true;
54 static bool arg_auto_start = true;
55 static bool arg_allow_interactive_authorization = true;
56 static bool arg_augment_creds = true;
57 static bool arg_watch_bind = false;
58 static usec_t arg_timeout = 0;
59
60 STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
61
62 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
63 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
64
65 static int acquire_bus(bool set_monitor, sd_bus **ret) {
66 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
67 int r;
68
69 r = sd_bus_new(&bus);
70 if (r < 0)
71 return log_error_errno(r, "Failed to allocate bus: %m");
72
73 if (set_monitor) {
74 r = sd_bus_set_monitor(bus, true);
75 if (r < 0)
76 return log_error_errno(r, "Failed to set monitor mode: %m");
77
78 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
79 if (r < 0)
80 return log_error_errno(r, "Failed to enable credentials: %m");
81
82 r = sd_bus_negotiate_timestamp(bus, true);
83 if (r < 0)
84 return log_error_errno(r, "Failed to enable timestamps: %m");
85
86 r = sd_bus_negotiate_fds(bus, true);
87 if (r < 0)
88 return log_error_errno(r, "Failed to enable fds: %m");
89 }
90
91 r = sd_bus_set_bus_client(bus, true);
92 if (r < 0)
93 return log_error_errno(r, "Failed to set bus client: %m");
94
95 r = sd_bus_set_watch_bind(bus, arg_watch_bind);
96 if (r < 0)
97 return log_error_errno(r, "Failed to set watch-bind setting to '%s': %m", yes_no(arg_watch_bind));
98
99 if (arg_address)
100 r = sd_bus_set_address(bus, arg_address);
101 else {
102 switch (arg_transport) {
103
104 case BUS_TRANSPORT_LOCAL:
105 if (arg_user) {
106 bus->is_user = true;
107 r = bus_set_address_user(bus);
108 } else {
109 bus->is_system = true;
110 r = bus_set_address_system(bus);
111 }
112 break;
113
114 case BUS_TRANSPORT_REMOTE:
115 r = bus_set_address_system_remote(bus, arg_host);
116 break;
117
118 case BUS_TRANSPORT_MACHINE:
119 r = bus_set_address_system_machine(bus, arg_host);
120 break;
121
122 default:
123 assert_not_reached("Hmm, unknown transport type.");
124 }
125 }
126 if (r < 0)
127 return log_error_errno(r, "Failed to set address: %m");
128
129 r = sd_bus_start(bus);
130 if (r < 0)
131 return log_error_errno(r, "Failed to connect to bus: %m");
132
133 *ret = TAKE_PTR(bus);
134
135 return 0;
136 }
137
138 static int list_bus_names(int argc, char **argv, void *userdata) {
139 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
140 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
141 _cleanup_free_ char **merged = NULL;
142 _cleanup_hashmap_free_ Hashmap *names = NULL;
143 char **i;
144 int r;
145 size_t max_i = 0;
146 unsigned n = 0;
147 void *v;
148 char *k;
149 Iterator iterator;
150
151 if (!arg_unique && !arg_acquired && !arg_activatable)
152 arg_unique = arg_acquired = arg_activatable = true;
153
154 r = acquire_bus(false, &bus);
155 if (r < 0)
156 return r;
157
158 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
159 if (r < 0)
160 return log_error_errno(r, "Failed to list names: %m");
161
162 (void) pager_open(arg_pager_flags);
163
164 names = hashmap_new(&string_hash_ops);
165 if (!names)
166 return log_oom();
167
168 STRV_FOREACH(i, acquired) {
169 max_i = MAX(max_i, strlen(*i));
170
171 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
172 if (r < 0)
173 return log_error_errno(r, "Failed to add to hashmap: %m");
174 }
175
176 STRV_FOREACH(i, activatable) {
177 max_i = MAX(max_i, strlen(*i));
178
179 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
180 if (r < 0 && r != -EEXIST)
181 return log_error_errno(r, "Failed to add to hashmap: %m");
182 }
183
184 merged = new(char*, hashmap_size(names) + 1);
185 if (!merged)
186 return log_oom();
187
188 HASHMAP_FOREACH_KEY(v, k, names, iterator)
189 merged[n++] = k;
190
191 merged[n] = NULL;
192 strv_sort(merged);
193
194 if (arg_legend) {
195 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
196 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
197
198 if (arg_show_machine)
199 puts(" MACHINE");
200 else
201 putchar('\n');
202 }
203
204 STRV_FOREACH(i, merged) {
205 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
206 sd_id128_t mid;
207
208 if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
209 /* Activatable */
210
211 printf("%-*s", (int) max_i, *i);
212 printf(" - - - (activatable) - - ");
213 if (arg_show_machine)
214 puts(" -");
215 else
216 putchar('\n');
217 continue;
218
219 }
220
221 if (!arg_unique && (*i)[0] == ':')
222 continue;
223
224 if (!arg_acquired && (*i)[0] != ':')
225 continue;
226
227 printf("%-*s", (int) max_i, *i);
228
229 r = sd_bus_get_name_creds(
230 bus, *i,
231 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
232 SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
233 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
234 SD_BUS_CREDS_DESCRIPTION, &creds);
235 if (r >= 0) {
236 const char *unique, *session, *unit, *cn;
237 pid_t pid;
238 uid_t uid;
239
240 r = sd_bus_creds_get_pid(creds, &pid);
241 if (r >= 0) {
242 const char *comm = NULL;
243
244 sd_bus_creds_get_comm(creds, &comm);
245
246 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
247 } else
248 fputs(" - - ", stdout);
249
250 r = sd_bus_creds_get_euid(creds, &uid);
251 if (r >= 0) {
252 _cleanup_free_ char *u = NULL;
253
254 u = uid_to_name(uid);
255 if (!u)
256 return log_oom();
257
258 if (strlen(u) > 16)
259 u[16] = 0;
260
261 printf(" %-16s", u);
262 } else
263 fputs(" - ", stdout);
264
265 r = sd_bus_creds_get_unique_name(creds, &unique);
266 if (r >= 0)
267 printf(" %-13s", unique);
268 else
269 fputs(" - ", stdout);
270
271 r = sd_bus_creds_get_unit(creds, &unit);
272 if (r >= 0) {
273 _cleanup_free_ char *e;
274
275 e = ellipsize(unit, 25, 100);
276 if (!e)
277 return log_oom();
278
279 printf(" %-25s", e);
280 } else
281 fputs(" - ", stdout);
282
283 r = sd_bus_creds_get_session(creds, &session);
284 if (r >= 0)
285 printf(" %-10s", session);
286 else
287 fputs(" - ", stdout);
288
289 r = sd_bus_creds_get_description(creds, &cn);
290 if (r >= 0)
291 printf(" %-19s", cn);
292 else
293 fputs(" - ", stdout);
294
295 } else
296 printf(" - - - - - - - ");
297
298 if (arg_show_machine) {
299 r = sd_bus_get_name_machine_id(bus, *i, &mid);
300 if (r >= 0) {
301 char m[SD_ID128_STRING_MAX];
302 printf(" %s\n", sd_id128_to_string(mid, m));
303 } else
304 puts(" -");
305 } else
306 putchar('\n');
307 }
308
309 return 0;
310 }
311
312 static void print_subtree(const char *prefix, const char *path, char **l) {
313 const char *vertical, *space;
314 char **n;
315
316 /* We assume the list is sorted. Let's first skip over the
317 * entry we are looking at. */
318 for (;;) {
319 if (!*l)
320 return;
321
322 if (!streq(*l, path))
323 break;
324
325 l++;
326 }
327
328 vertical = strjoina(prefix, special_glyph(TREE_VERTICAL));
329 space = strjoina(prefix, special_glyph(TREE_SPACE));
330
331 for (;;) {
332 bool has_more = false;
333
334 if (!*l || !path_startswith(*l, path))
335 break;
336
337 n = l + 1;
338 for (;;) {
339 if (!*n || !path_startswith(*n, path))
340 break;
341
342 if (!path_startswith(*n, *l)) {
343 has_more = true;
344 break;
345 }
346
347 n++;
348 }
349
350 printf("%s%s%s\n", prefix, special_glyph(has_more ? TREE_BRANCH : TREE_RIGHT), *l);
351
352 print_subtree(has_more ? vertical : space, *l, l);
353 l = n;
354 }
355 }
356
357 static void print_tree(const char *prefix, char **l) {
358
359 prefix = strempty(prefix);
360
361 if (arg_list) {
362 char **i;
363
364 STRV_FOREACH(i, l)
365 printf("%s%s\n", prefix, *i);
366 return;
367 }
368
369 if (strv_isempty(l)) {
370 printf("No objects discovered.\n");
371 return;
372 }
373
374 if (streq(l[0], "/") && !l[1]) {
375 printf("Only root object discovered.\n");
376 return;
377 }
378
379 print_subtree(prefix, "/", l);
380 }
381
382 static int on_path(const char *path, void *userdata) {
383 Set *paths = userdata;
384 int r;
385
386 assert(paths);
387
388 r = set_put_strdup(paths, path);
389 if (r < 0)
390 return log_oom();
391
392 return 0;
393 }
394
395 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
396 static const XMLIntrospectOps ops = {
397 .on_path = on_path,
398 };
399
400 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
401 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
402 const char *xml;
403 int r;
404
405 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
406 if (r < 0) {
407 if (many)
408 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
409 else
410 log_error_errno(r, "Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
411 return r;
412 }
413
414 r = sd_bus_message_read(reply, "s", &xml);
415 if (r < 0)
416 return bus_log_parse_error(r);
417
418 return parse_xml_introspect(path, xml, &ops, paths);
419 }
420
421 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
422 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
423 _cleanup_free_ char **l = NULL;
424 char *m;
425 int r;
426
427 paths = set_new(&string_hash_ops);
428 if (!paths)
429 return log_oom();
430
431 done = set_new(&string_hash_ops);
432 if (!done)
433 return log_oom();
434
435 failed = set_new(&string_hash_ops);
436 if (!failed)
437 return log_oom();
438
439 m = strdup("/");
440 if (!m)
441 return log_oom();
442
443 r = set_put(paths, m);
444 if (r < 0) {
445 free(m);
446 return log_oom();
447 }
448
449 for (;;) {
450 _cleanup_free_ char *p = NULL;
451 int q;
452
453 p = set_steal_first(paths);
454 if (!p)
455 break;
456
457 if (set_contains(done, p) ||
458 set_contains(failed, p))
459 continue;
460
461 q = find_nodes(bus, service, p, paths, many);
462 if (q < 0) {
463 if (r >= 0)
464 r = q;
465
466 q = set_put(failed, p);
467 } else
468 q = set_put(done, p);
469
470 if (q < 0)
471 return log_oom();
472
473 assert(q != 0);
474 p = NULL;
475 }
476
477 (void) pager_open(arg_pager_flags);
478
479 l = set_get_strv(done);
480 if (!l)
481 return log_oom();
482
483 strv_sort(l);
484 print_tree(prefix, l);
485
486 fflush(stdout);
487
488 return r;
489 }
490
491 static int tree(int argc, char **argv, void *userdata) {
492 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
493 char **i;
494 int r = 0;
495
496 if (!arg_unique && !arg_acquired)
497 arg_acquired = true;
498
499 r = acquire_bus(false, &bus);
500 if (r < 0)
501 return r;
502
503 if (argc <= 1) {
504 _cleanup_strv_free_ char **names = NULL;
505 bool not_first = false;
506
507 r = sd_bus_list_names(bus, &names, NULL);
508 if (r < 0)
509 return log_error_errno(r, "Failed to get name list: %m");
510
511 (void) pager_open(arg_pager_flags);
512
513 STRV_FOREACH(i, names) {
514 int q;
515
516 if (!arg_unique && (*i)[0] == ':')
517 continue;
518
519 if (!arg_acquired && (*i)[0] == ':')
520 continue;
521
522 if (not_first)
523 printf("\n");
524
525 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
526
527 q = tree_one(bus, *i, NULL, true);
528 if (q < 0 && r >= 0)
529 r = q;
530
531 not_first = true;
532 }
533 } else {
534 STRV_FOREACH(i, argv+1) {
535 int q;
536
537 if (i > argv+1)
538 printf("\n");
539
540 if (argv[2]) {
541 (void) pager_open(arg_pager_flags);
542 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
543 }
544
545 q = tree_one(bus, *i, NULL, !!argv[2]);
546 if (q < 0 && r >= 0)
547 r = q;
548 }
549 }
550
551 return r;
552 }
553
554 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
555 int r;
556
557 for (;;) {
558 const char *contents = NULL;
559 char type;
560 union {
561 uint8_t u8;
562 uint16_t u16;
563 int16_t s16;
564 uint32_t u32;
565 int32_t s32;
566 uint64_t u64;
567 int64_t s64;
568 double d64;
569 const char *string;
570 int i;
571 } basic;
572
573 r = sd_bus_message_peek_type(m, &type, &contents);
574 if (r < 0)
575 return r;
576 if (r == 0)
577 return needs_space;
578
579 if (bus_type_is_container(type) > 0) {
580
581 r = sd_bus_message_enter_container(m, type, contents);
582 if (r < 0)
583 return r;
584
585 if (type == SD_BUS_TYPE_ARRAY) {
586 unsigned n = 0;
587
588 /* count array entries */
589 for (;;) {
590
591 r = sd_bus_message_skip(m, contents);
592 if (r < 0)
593 return r;
594 if (r == 0)
595 break;
596
597 n++;
598 }
599
600 r = sd_bus_message_rewind(m, false);
601 if (r < 0)
602 return r;
603
604 if (needs_space)
605 fputc(' ', f);
606
607 fprintf(f, "%u", n);
608 needs_space = true;
609
610 } else if (type == SD_BUS_TYPE_VARIANT) {
611
612 if (needs_space)
613 fputc(' ', f);
614
615 fprintf(f, "%s", contents);
616 needs_space = true;
617 }
618
619 r = format_cmdline(m, f, needs_space);
620 if (r < 0)
621 return r;
622
623 needs_space = r > 0;
624
625 r = sd_bus_message_exit_container(m);
626 if (r < 0)
627 return r;
628
629 continue;
630 }
631
632 r = sd_bus_message_read_basic(m, type, &basic);
633 if (r < 0)
634 return r;
635
636 if (needs_space)
637 fputc(' ', f);
638
639 switch (type) {
640 case SD_BUS_TYPE_BYTE:
641 fprintf(f, "%u", basic.u8);
642 break;
643
644 case SD_BUS_TYPE_BOOLEAN:
645 fputs(true_false(basic.i), f);
646 break;
647
648 case SD_BUS_TYPE_INT16:
649 fprintf(f, "%i", basic.s16);
650 break;
651
652 case SD_BUS_TYPE_UINT16:
653 fprintf(f, "%u", basic.u16);
654 break;
655
656 case SD_BUS_TYPE_INT32:
657 fprintf(f, "%i", basic.s32);
658 break;
659
660 case SD_BUS_TYPE_UINT32:
661 fprintf(f, "%u", basic.u32);
662 break;
663
664 case SD_BUS_TYPE_INT64:
665 fprintf(f, "%" PRIi64, basic.s64);
666 break;
667
668 case SD_BUS_TYPE_UINT64:
669 fprintf(f, "%" PRIu64, basic.u64);
670 break;
671
672 case SD_BUS_TYPE_DOUBLE:
673 fprintf(f, "%g", basic.d64);
674 break;
675
676 case SD_BUS_TYPE_STRING:
677 case SD_BUS_TYPE_OBJECT_PATH:
678 case SD_BUS_TYPE_SIGNATURE: {
679 _cleanup_free_ char *b = NULL;
680
681 b = cescape(basic.string);
682 if (!b)
683 return -ENOMEM;
684
685 fprintf(f, "\"%s\"", b);
686 break;
687 }
688
689 case SD_BUS_TYPE_UNIX_FD:
690 fprintf(f, "%i", basic.i);
691 break;
692
693 default:
694 assert_not_reached("Unknown basic type.");
695 }
696
697 needs_space = true;
698 }
699 }
700
701 typedef struct Member {
702 const char *type;
703 char *interface;
704 char *name;
705 char *signature;
706 char *result;
707 char *value;
708 bool writable;
709 uint64_t flags;
710 } Member;
711
712 static void member_hash_func(const void *p, struct siphash *state) {
713 const Member *m = p;
714 uint64_t arity = 1;
715
716 assert(m);
717 assert(m->type);
718
719 string_hash_func(m->type, state);
720
721 arity += !!m->name + !!m->interface;
722
723 uint64_hash_func(&arity, state);
724
725 if (m->name)
726 string_hash_func(m->name, state);
727
728 if (m->interface)
729 string_hash_func(m->interface, state);
730 }
731
732 static int member_compare_func(const Member *x, const Member *y) {
733 int d;
734
735 assert(x);
736 assert(y);
737 assert(x->type);
738 assert(y->type);
739
740 d = strcmp_ptr(x->interface, y->interface);
741 if (d != 0)
742 return d;
743
744 d = strcmp(x->type, y->type);
745 if (d != 0)
746 return d;
747
748 return strcmp_ptr(x->name, y->name);
749 }
750
751 static int member_compare_funcp(Member * const *a, Member * const *b) {
752 return member_compare_func(*a, *b);
753 }
754
755 static void member_free(Member *m) {
756 if (!m)
757 return;
758
759 free(m->interface);
760 free(m->name);
761 free(m->signature);
762 free(m->result);
763 free(m->value);
764 free(m);
765 }
766
767 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
768
769 static void member_set_free(Set *s) {
770 set_free_with_destructor(s, member_free);
771 }
772
773 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
774
775 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
776 _cleanup_(member_freep) Member *m;
777 Set *members = userdata;
778 int r;
779
780 assert(interface);
781 assert(members);
782
783 m = new0(Member, 1);
784 if (!m)
785 return log_oom();
786
787 m->type = "interface";
788 m->flags = flags;
789
790 r = free_and_strdup(&m->interface, interface);
791 if (r < 0)
792 return log_oom();
793
794 r = set_put(members, m);
795 if (r <= 0) {
796 log_error("Duplicate interface");
797 return -EINVAL;
798 }
799
800 m = NULL;
801 return 0;
802 }
803
804 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
805 _cleanup_(member_freep) Member *m;
806 Set *members = userdata;
807 int r;
808
809 assert(interface);
810 assert(name);
811
812 m = new0(Member, 1);
813 if (!m)
814 return log_oom();
815
816 m->type = "method";
817 m->flags = flags;
818
819 r = free_and_strdup(&m->interface, interface);
820 if (r < 0)
821 return log_oom();
822
823 r = free_and_strdup(&m->name, name);
824 if (r < 0)
825 return log_oom();
826
827 r = free_and_strdup(&m->signature, signature);
828 if (r < 0)
829 return log_oom();
830
831 r = free_and_strdup(&m->result, result);
832 if (r < 0)
833 return log_oom();
834
835 r = set_put(members, m);
836 if (r <= 0) {
837 log_error("Duplicate method");
838 return -EINVAL;
839 }
840
841 m = NULL;
842 return 0;
843 }
844
845 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
846 _cleanup_(member_freep) Member *m;
847 Set *members = userdata;
848 int r;
849
850 assert(interface);
851 assert(name);
852
853 m = new0(Member, 1);
854 if (!m)
855 return log_oom();
856
857 m->type = "signal";
858 m->flags = flags;
859
860 r = free_and_strdup(&m->interface, interface);
861 if (r < 0)
862 return log_oom();
863
864 r = free_and_strdup(&m->name, name);
865 if (r < 0)
866 return log_oom();
867
868 r = free_and_strdup(&m->signature, signature);
869 if (r < 0)
870 return log_oom();
871
872 r = set_put(members, m);
873 if (r <= 0) {
874 log_error("Duplicate signal");
875 return -EINVAL;
876 }
877
878 m = NULL;
879 return 0;
880 }
881
882 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
883 _cleanup_(member_freep) Member *m;
884 Set *members = userdata;
885 int r;
886
887 assert(interface);
888 assert(name);
889
890 m = new0(Member, 1);
891 if (!m)
892 return log_oom();
893
894 m->type = "property";
895 m->flags = flags;
896 m->writable = writable;
897
898 r = free_and_strdup(&m->interface, interface);
899 if (r < 0)
900 return log_oom();
901
902 r = free_and_strdup(&m->name, name);
903 if (r < 0)
904 return log_oom();
905
906 r = free_and_strdup(&m->signature, signature);
907 if (r < 0)
908 return log_oom();
909
910 r = set_put(members, m);
911 if (r <= 0) {
912 log_error("Duplicate property");
913 return -EINVAL;
914 }
915
916 m = NULL;
917 return 0;
918 }
919
920 static int introspect(int argc, char **argv, void *userdata) {
921 static const struct hash_ops member_hash_ops = {
922 .hash = member_hash_func,
923 .compare = (__compar_fn_t) member_compare_func,
924 };
925
926 static const XMLIntrospectOps ops = {
927 .on_interface = on_interface,
928 .on_method = on_method,
929 .on_signal = on_signal,
930 .on_property = on_property,
931 };
932
933 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
934 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_xml = NULL;
935 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
936 _cleanup_(member_set_freep) Set *members = NULL;
937 unsigned name_width, type_width, signature_width, result_width, j, k = 0;
938 Member *m, **sorted = NULL;
939 Iterator i;
940 const char *xml;
941 int r;
942
943 r = acquire_bus(false, &bus);
944 if (r < 0)
945 return r;
946
947 members = set_new(&member_hash_ops);
948 if (!members)
949 return log_oom();
950
951 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply_xml, "");
952 if (r < 0)
953 return log_error_errno(r, "Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
954
955 r = sd_bus_message_read(reply_xml, "s", &xml);
956 if (r < 0)
957 return bus_log_parse_error(r);
958
959 /* First, get list of all properties */
960 r = parse_xml_introspect(argv[2], xml, &ops, members);
961 if (r < 0)
962 return r;
963
964 /* Second, find the current values for them */
965 SET_FOREACH(m, members, i) {
966 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
967
968 if (!streq(m->type, "property"))
969 continue;
970
971 if (m->value)
972 continue;
973
974 if (argv[3] && !streq(argv[3], m->interface))
975 continue;
976
977 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
978 if (r < 0)
979 return log_error_errno(r, "%s", bus_error_message(&error, r));
980
981 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
982 if (r < 0)
983 return bus_log_parse_error(r);
984
985 for (;;) {
986 Member *z;
987 _cleanup_free_ char *buf = NULL;
988 _cleanup_fclose_ FILE *mf = NULL;
989 size_t sz = 0;
990 const char *name;
991
992 r = sd_bus_message_enter_container(reply, 'e', "sv");
993 if (r < 0)
994 return bus_log_parse_error(r);
995
996 if (r == 0)
997 break;
998
999 r = sd_bus_message_read(reply, "s", &name);
1000 if (r < 0)
1001 return bus_log_parse_error(r);
1002
1003 r = sd_bus_message_enter_container(reply, 'v', NULL);
1004 if (r < 0)
1005 return bus_log_parse_error(r);
1006
1007 mf = open_memstream(&buf, &sz);
1008 if (!mf)
1009 return log_oom();
1010
1011 (void) __fsetlocking(mf, FSETLOCKING_BYCALLER);
1012
1013 r = format_cmdline(reply, mf, false);
1014 if (r < 0)
1015 return bus_log_parse_error(r);
1016
1017 mf = safe_fclose(mf);
1018
1019 z = set_get(members, &((Member) {
1020 .type = "property",
1021 .interface = m->interface,
1022 .name = (char*) name }));
1023 if (z)
1024 free_and_replace(z->value, buf);
1025
1026 r = sd_bus_message_exit_container(reply);
1027 if (r < 0)
1028 return bus_log_parse_error(r);
1029
1030 r = sd_bus_message_exit_container(reply);
1031 if (r < 0)
1032 return bus_log_parse_error(r);
1033 }
1034
1035 r = sd_bus_message_exit_container(reply);
1036 if (r < 0)
1037 return bus_log_parse_error(r);
1038 }
1039
1040 (void) pager_open(arg_pager_flags);
1041
1042 name_width = STRLEN("NAME");
1043 type_width = STRLEN("TYPE");
1044 signature_width = STRLEN("SIGNATURE");
1045 result_width = STRLEN("RESULT/VALUE");
1046
1047 sorted = newa(Member*, set_size(members));
1048
1049 SET_FOREACH(m, members, i) {
1050
1051 if (argv[3] && !streq(argv[3], m->interface))
1052 continue;
1053
1054 if (m->interface)
1055 name_width = MAX(name_width, strlen(m->interface));
1056 if (m->name)
1057 name_width = MAX(name_width, strlen(m->name) + 1);
1058 if (m->type)
1059 type_width = MAX(type_width, strlen(m->type));
1060 if (m->signature)
1061 signature_width = MAX(signature_width, strlen(m->signature));
1062 if (m->result)
1063 result_width = MAX(result_width, strlen(m->result));
1064 if (m->value)
1065 result_width = MAX(result_width, strlen(m->value));
1066
1067 sorted[k++] = m;
1068 }
1069
1070 if (result_width > 40)
1071 result_width = 40;
1072
1073 typesafe_qsort(sorted, k, member_compare_funcp);
1074
1075 if (arg_legend) {
1076 printf("%-*s %-*s %-*s %-*s %s\n",
1077 (int) name_width, "NAME",
1078 (int) type_width, "TYPE",
1079 (int) signature_width, "SIGNATURE",
1080 (int) result_width, "RESULT/VALUE",
1081 "FLAGS");
1082 }
1083
1084 for (j = 0; j < k; j++) {
1085 _cleanup_free_ char *ellipsized = NULL;
1086 const char *rv;
1087 bool is_interface;
1088
1089 m = sorted[j];
1090
1091 if (argv[3] && !streq(argv[3], m->interface))
1092 continue;
1093
1094 is_interface = streq(m->type, "interface");
1095
1096 if (argv[3] && is_interface)
1097 continue;
1098
1099 if (m->value) {
1100 ellipsized = ellipsize(m->value, result_width, 100);
1101 if (!ellipsized)
1102 return log_oom();
1103
1104 rv = ellipsized;
1105 } else
1106 rv = empty_to_dash(m->result);
1107
1108 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1109 is_interface ? ansi_highlight() : "",
1110 is_interface ? "" : ".",
1111 - !is_interface + (int) name_width, empty_to_dash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1112 is_interface ? ansi_normal() : "",
1113 (int) type_width, empty_to_dash(m->type),
1114 (int) signature_width, empty_to_dash(m->signature),
1115 (int) result_width, rv,
1116 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1117 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1118 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1119 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1120 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1121 m->writable ? " writable" : "");
1122 }
1123
1124 return 0;
1125 }
1126
1127 static int message_dump(sd_bus_message *m, FILE *f) {
1128 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1129 }
1130
1131 static int message_pcap(sd_bus_message *m, FILE *f) {
1132 return bus_message_pcap_frame(m, arg_snaplen, f);
1133 }
1134
1135 static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f)) {
1136 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1137 _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
1138 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1139 char **i;
1140 uint32_t flags = 0;
1141 const char *unique_name;
1142 bool is_monitor = false;
1143 int r;
1144
1145 r = acquire_bus(true, &bus);
1146 if (r < 0)
1147 return r;
1148
1149 /* upgrade connection; it's not used for anything else after this call */
1150 r = sd_bus_message_new_method_call(bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
1151 if (r < 0)
1152 return bus_log_create_error(r);
1153
1154 r = sd_bus_message_open_container(message, 'a', "s");
1155 if (r < 0)
1156 return bus_log_create_error(r);
1157
1158 STRV_FOREACH(i, argv+1) {
1159 _cleanup_free_ char *m = NULL;
1160
1161 if (!service_name_is_valid(*i)) {
1162 log_error("Invalid service name '%s'", *i);
1163 return -EINVAL;
1164 }
1165
1166 m = strjoin("sender='", *i, "'");
1167 if (!m)
1168 return log_oom();
1169
1170 r = sd_bus_message_append_basic(message, 's', m);
1171 if (r < 0)
1172 return bus_log_create_error(r);
1173
1174 free(m);
1175 m = strjoin("destination='", *i, "'");
1176 if (!m)
1177 return log_oom();
1178
1179 r = sd_bus_message_append_basic(message, 's', m);
1180 if (r < 0)
1181 return bus_log_create_error(r);
1182 }
1183
1184 STRV_FOREACH(i, arg_matches) {
1185 r = sd_bus_message_append_basic(message, 's', *i);
1186 if (r < 0)
1187 return bus_log_create_error(r);
1188 }
1189
1190 r = sd_bus_message_close_container(message);
1191 if (r < 0)
1192 return bus_log_create_error(r);
1193
1194 r = sd_bus_message_append_basic(message, 'u', &flags);
1195 if (r < 0)
1196 return bus_log_create_error(r);
1197
1198 r = sd_bus_call(bus, message, arg_timeout, &error, NULL);
1199 if (r < 0)
1200 return log_error_errno(r, "%s", bus_error_message(&error, r));
1201
1202 r = sd_bus_get_unique_name(bus, &unique_name);
1203 if (r < 0)
1204 return log_error_errno(r, "Failed to get unique name: %m");
1205
1206 log_info("Monitoring bus message stream.");
1207
1208 for (;;) {
1209 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1210
1211 r = sd_bus_process(bus, &m);
1212 if (r < 0)
1213 return log_error_errno(r, "Failed to process bus: %m");
1214
1215 if (!is_monitor) {
1216 const char *name;
1217
1218 /* wait until we lose our unique name */
1219 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameLost") <= 0)
1220 continue;
1221
1222 r = sd_bus_message_read(m, "s", &name);
1223 if (r < 0)
1224 return log_error_errno(r, "Failed to read lost name: %m");
1225
1226 if (streq(name, unique_name))
1227 is_monitor = true;
1228
1229 continue;
1230 }
1231
1232 if (m) {
1233 dump(m, stdout);
1234 fflush(stdout);
1235
1236 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1237 log_info("Connection terminated, exiting.");
1238 return 0;
1239 }
1240
1241 continue;
1242 }
1243
1244 if (r > 0)
1245 continue;
1246
1247 r = sd_bus_wait(bus, (uint64_t) -1);
1248 if (r < 0)
1249 return log_error_errno(r, "Failed to wait for bus: %m");
1250 }
1251 }
1252
1253 static int verb_monitor(int argc, char **argv, void *userdata) {
1254 return monitor(argc, argv, message_dump);
1255 }
1256
1257 static int verb_capture(int argc, char **argv, void *userdata) {
1258 int r;
1259
1260 if (isatty(fileno(stdout)) > 0)
1261 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1262 "Refusing to write message data to console, please redirect output to a file.");
1263
1264 bus_pcap_header(arg_snaplen, stdout);
1265
1266 r = monitor(argc, argv, message_pcap);
1267 if (r < 0)
1268 return r;
1269
1270 r = fflush_and_check(stdout);
1271 if (r < 0)
1272 return log_error_errno(r, "Couldn't write capture file: %m");
1273
1274 return r;
1275 }
1276
1277 static int status(int argc, char **argv, void *userdata) {
1278 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1279 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
1280 pid_t pid;
1281 int r;
1282
1283 r = acquire_bus(false, &bus);
1284 if (r < 0)
1285 return r;
1286
1287 if (!isempty(argv[1])) {
1288 r = parse_pid(argv[1], &pid);
1289 if (r < 0)
1290 r = sd_bus_get_name_creds(
1291 bus,
1292 argv[1],
1293 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1294 &creds);
1295 else
1296 r = sd_bus_creds_new_from_pid(
1297 &creds,
1298 pid,
1299 _SD_BUS_CREDS_ALL);
1300 } else {
1301 const char *scope, *address;
1302 sd_id128_t bus_id;
1303
1304 r = sd_bus_get_address(bus, &address);
1305 if (r >= 0)
1306 printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal());
1307
1308 r = sd_bus_get_scope(bus, &scope);
1309 if (r >= 0)
1310 printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal());
1311
1312 r = sd_bus_get_bus_id(bus, &bus_id);
1313 if (r >= 0)
1314 printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal());
1315
1316 r = sd_bus_get_owner_creds(
1317 bus,
1318 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1319 &creds);
1320 }
1321
1322 if (r < 0)
1323 return log_error_errno(r, "Failed to get credentials: %m");
1324
1325 bus_creds_dump(creds, NULL, false);
1326 return 0;
1327 }
1328
1329 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1330 char **p;
1331 int r;
1332
1333 assert(m);
1334 assert(signature);
1335 assert(x);
1336
1337 p = *x;
1338
1339 for (;;) {
1340 const char *v;
1341 char t;
1342
1343 t = *signature;
1344 v = *p;
1345
1346 if (t == 0)
1347 break;
1348 if (!v)
1349 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1350 "Too few parameters for signature.");
1351
1352 signature++;
1353 p++;
1354
1355 switch (t) {
1356
1357 case SD_BUS_TYPE_BOOLEAN:
1358
1359 r = parse_boolean(v);
1360 if (r < 0)
1361 return log_error_errno(r, "Failed to parse '%s' as boolean: %m", v);
1362
1363 r = sd_bus_message_append_basic(m, t, &r);
1364 break;
1365
1366 case SD_BUS_TYPE_BYTE: {
1367 uint8_t z;
1368
1369 r = safe_atou8(v, &z);
1370 if (r < 0)
1371 return log_error_errno(r, "Failed to parse '%s' as byte (unsigned 8bit integer): %m", v);
1372
1373 r = sd_bus_message_append_basic(m, t, &z);
1374 break;
1375 }
1376
1377 case SD_BUS_TYPE_INT16: {
1378 int16_t z;
1379
1380 r = safe_atoi16(v, &z);
1381 if (r < 0)
1382 return log_error_errno(r, "Failed to parse '%s' as signed 16bit integer: %m", v);
1383
1384 r = sd_bus_message_append_basic(m, t, &z);
1385 break;
1386 }
1387
1388 case SD_BUS_TYPE_UINT16: {
1389 uint16_t z;
1390
1391 r = safe_atou16(v, &z);
1392 if (r < 0)
1393 return log_error_errno(r, "Failed to parse '%s' as unsigned 16bit integer: %m", v);
1394
1395 r = sd_bus_message_append_basic(m, t, &z);
1396 break;
1397 }
1398
1399 case SD_BUS_TYPE_INT32: {
1400 int32_t z;
1401
1402 r = safe_atoi32(v, &z);
1403 if (r < 0)
1404 return log_error_errno(r, "Failed to parse '%s' as signed 32bit integer: %m", v);
1405
1406 r = sd_bus_message_append_basic(m, t, &z);
1407 break;
1408 }
1409
1410 case SD_BUS_TYPE_UINT32: {
1411 uint32_t z;
1412
1413 r = safe_atou32(v, &z);
1414 if (r < 0)
1415 return log_error_errno(r, "Failed to parse '%s' as unsigned 32bit integer: %m", v);
1416
1417 r = sd_bus_message_append_basic(m, t, &z);
1418 break;
1419 }
1420
1421 case SD_BUS_TYPE_INT64: {
1422 int64_t z;
1423
1424 r = safe_atoi64(v, &z);
1425 if (r < 0)
1426 return log_error_errno(r, "Failed to parse '%s' as signed 64bit integer: %m", v);
1427
1428 r = sd_bus_message_append_basic(m, t, &z);
1429 break;
1430 }
1431
1432 case SD_BUS_TYPE_UINT64: {
1433 uint64_t z;
1434
1435 r = safe_atou64(v, &z);
1436 if (r < 0)
1437 return log_error_errno(r, "Failed to parse '%s' as unsigned 64bit integer: %m", v);
1438
1439 r = sd_bus_message_append_basic(m, t, &z);
1440 break;
1441 }
1442
1443 case SD_BUS_TYPE_DOUBLE: {
1444 double z;
1445
1446 r = safe_atod(v, &z);
1447 if (r < 0)
1448 return log_error_errno(r, "Failed to parse '%s' as double precision floating point: %m", v);
1449
1450 r = sd_bus_message_append_basic(m, t, &z);
1451 break;
1452 }
1453
1454 case SD_BUS_TYPE_STRING:
1455 case SD_BUS_TYPE_OBJECT_PATH:
1456 case SD_BUS_TYPE_SIGNATURE:
1457
1458 r = sd_bus_message_append_basic(m, t, v);
1459 break;
1460
1461 case SD_BUS_TYPE_ARRAY: {
1462 uint32_t n;
1463 size_t k;
1464
1465 r = safe_atou32(v, &n);
1466 if (r < 0)
1467 return log_error_errno(r, "Failed to parse '%s' number of array entries: %m", v);
1468
1469 r = signature_element_length(signature, &k);
1470 if (r < 0)
1471 return log_error_errno(r, "Invalid array signature: %m");
1472
1473 {
1474 unsigned i;
1475 char s[k + 1];
1476 memcpy(s, signature, k);
1477 s[k] = 0;
1478
1479 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1480 if (r < 0)
1481 return bus_log_create_error(r);
1482
1483 for (i = 0; i < n; i++) {
1484 r = message_append_cmdline(m, s, &p);
1485 if (r < 0)
1486 return r;
1487 }
1488 }
1489
1490 signature += k;
1491
1492 r = sd_bus_message_close_container(m);
1493 break;
1494 }
1495
1496 case SD_BUS_TYPE_VARIANT:
1497 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1498 if (r < 0)
1499 return bus_log_create_error(r);
1500
1501 r = message_append_cmdline(m, v, &p);
1502 if (r < 0)
1503 return r;
1504
1505 r = sd_bus_message_close_container(m);
1506 break;
1507
1508 case SD_BUS_TYPE_STRUCT_BEGIN:
1509 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1510 size_t k;
1511
1512 signature--;
1513 p--;
1514
1515 r = signature_element_length(signature, &k);
1516 if (r < 0)
1517 return log_error_errno(r, "Invalid struct/dict entry signature: %m");
1518
1519 {
1520 char s[k-1];
1521 memcpy(s, signature + 1, k - 2);
1522 s[k - 2] = 0;
1523
1524 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1525 if (r < 0)
1526 return bus_log_create_error(r);
1527
1528 r = message_append_cmdline(m, s, &p);
1529 if (r < 0)
1530 return r;
1531 }
1532
1533 signature += k;
1534
1535 r = sd_bus_message_close_container(m);
1536 break;
1537 }
1538
1539 case SD_BUS_TYPE_UNIX_FD:
1540 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1541 "UNIX file descriptor not supported as type.");
1542
1543 default:
1544 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1545 "Unknown signature type %c.", t);
1546 }
1547
1548 if (r < 0)
1549 return bus_log_create_error(r);
1550 }
1551
1552 *x = p;
1553 return 0;
1554 }
1555
1556 static int json_transform_one(sd_bus_message *m, JsonVariant **ret);
1557
1558 static int json_transform_array_or_struct(sd_bus_message *m, JsonVariant **ret) {
1559 size_t n_elements = 0, n_allocated = 0;
1560 JsonVariant **elements = NULL;
1561 int r;
1562
1563 assert(m);
1564 assert(ret);
1565
1566 for (;;) {
1567 r = sd_bus_message_at_end(m, false);
1568 if (r < 0) {
1569 bus_log_parse_error(r);
1570 goto finish;
1571 }
1572 if (r > 0)
1573 break;
1574
1575 if (!GREEDY_REALLOC(elements, n_allocated, n_elements + 1)) {
1576 r = log_oom();
1577 goto finish;
1578 }
1579
1580 r = json_transform_one(m, elements + n_elements);
1581 if (r < 0)
1582 goto finish;
1583
1584 n_elements++;
1585 }
1586
1587 r = json_variant_new_array(ret, elements, n_elements);
1588
1589 finish:
1590 json_variant_unref_many(elements, n_elements);
1591 free(elements);
1592
1593 return r;
1594 }
1595
1596 static int json_transform_variant(sd_bus_message *m, const char *contents, JsonVariant **ret) {
1597 _cleanup_(json_variant_unrefp) JsonVariant *value = NULL;
1598 int r;
1599
1600 assert(m);
1601 assert(contents);
1602 assert(ret);
1603
1604 r = json_transform_one(m, &value);
1605 if (r < 0)
1606 return r;
1607
1608 r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(contents)),
1609 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(value))));
1610 if (r < 0)
1611 return log_oom();
1612
1613 return r;
1614 }
1615
1616 static int json_transform_dict_array(sd_bus_message *m, JsonVariant **ret) {
1617 size_t n_elements = 0, n_allocated = 0;
1618 JsonVariant **elements = NULL;
1619 int r;
1620
1621 assert(m);
1622 assert(ret);
1623
1624 for (;;) {
1625 const char *contents;
1626 char type;
1627
1628 r = sd_bus_message_at_end(m, false);
1629 if (r < 0) {
1630 bus_log_parse_error(r);
1631 goto finish;
1632 }
1633 if (r > 0)
1634 break;
1635
1636 r = sd_bus_message_peek_type(m, &type, &contents);
1637 if (r < 0)
1638 return r;
1639
1640 assert(type == 'e');
1641
1642 if (!GREEDY_REALLOC(elements, n_allocated, n_elements + 2)) {
1643 r = log_oom();
1644 goto finish;
1645 }
1646
1647 r = sd_bus_message_enter_container(m, type, contents);
1648 if (r < 0) {
1649 bus_log_parse_error(r);
1650 goto finish;
1651 }
1652
1653 r = json_transform_one(m, elements + n_elements);
1654 if (r < 0)
1655 goto finish;
1656
1657 n_elements++;
1658
1659 r = json_transform_one(m, elements + n_elements);
1660 if (r < 0)
1661 goto finish;
1662
1663 n_elements++;
1664
1665 r = sd_bus_message_exit_container(m);
1666 if (r < 0) {
1667 bus_log_parse_error(r);
1668 goto finish;
1669 }
1670 }
1671
1672 r = json_variant_new_object(ret, elements, n_elements);
1673
1674 finish:
1675 json_variant_unref_many(elements, n_elements);
1676 free(elements);
1677
1678 return r;
1679 }
1680
1681 static int json_transform_one(sd_bus_message *m, JsonVariant **ret) {
1682 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1683 const char *contents;
1684 char type;
1685 int r;
1686
1687 assert(m);
1688 assert(ret);
1689
1690 r = sd_bus_message_peek_type(m, &type, &contents);
1691 if (r < 0)
1692 return bus_log_parse_error(r);
1693
1694 switch (type) {
1695
1696 case SD_BUS_TYPE_BYTE: {
1697 uint8_t b;
1698
1699 r = sd_bus_message_read_basic(m, type, &b);
1700 if (r < 0)
1701 return bus_log_parse_error(r);
1702
1703 r = json_variant_new_unsigned(&v, b);
1704 if (r < 0)
1705 return log_error_errno(r, "Failed to transform byte: %m");
1706
1707 break;
1708 }
1709
1710 case SD_BUS_TYPE_BOOLEAN: {
1711 int b;
1712
1713 r = sd_bus_message_read_basic(m, type, &b);
1714 if (r < 0)
1715 return bus_log_parse_error(r);
1716
1717 r = json_variant_new_boolean(&v, b);
1718 if (r < 0)
1719 return log_error_errno(r, "Failed to transform boolean: %m");
1720
1721 break;
1722 }
1723
1724 case SD_BUS_TYPE_INT16: {
1725 int16_t b;
1726
1727 r = sd_bus_message_read_basic(m, type, &b);
1728 if (r < 0)
1729 return bus_log_parse_error(r);
1730
1731 r = json_variant_new_integer(&v, b);
1732 if (r < 0)
1733 return log_error_errno(r, "Failed to transform int16: %m");
1734
1735 break;
1736 }
1737
1738 case SD_BUS_TYPE_UINT16: {
1739 uint16_t b;
1740
1741 r = sd_bus_message_read_basic(m, type, &b);
1742 if (r < 0)
1743 return bus_log_parse_error(r);
1744
1745 r = json_variant_new_unsigned(&v, b);
1746 if (r < 0)
1747 return log_error_errno(r, "Failed to transform uint16: %m");
1748
1749 break;
1750 }
1751
1752 case SD_BUS_TYPE_INT32: {
1753 int32_t b;
1754
1755 r = sd_bus_message_read_basic(m, type, &b);
1756 if (r < 0)
1757 return bus_log_parse_error(r);
1758
1759 r = json_variant_new_integer(&v, b);
1760 if (r < 0)
1761 return log_error_errno(r, "Failed to transform int32: %m");
1762
1763 break;
1764 }
1765
1766 case SD_BUS_TYPE_UINT32: {
1767 uint32_t b;
1768
1769 r = sd_bus_message_read_basic(m, type, &b);
1770 if (r < 0)
1771 return bus_log_parse_error(r);
1772
1773 r = json_variant_new_unsigned(&v, b);
1774 if (r < 0)
1775 return log_error_errno(r, "Failed to transform uint32: %m");
1776
1777 break;
1778 }
1779
1780 case SD_BUS_TYPE_INT64: {
1781 int64_t b;
1782
1783 r = sd_bus_message_read_basic(m, type, &b);
1784 if (r < 0)
1785 return bus_log_parse_error(r);
1786
1787 r = json_variant_new_integer(&v, b);
1788 if (r < 0)
1789 return log_error_errno(r, "Failed to transform int64: %m");
1790
1791 break;
1792 }
1793
1794 case SD_BUS_TYPE_UINT64: {
1795 uint64_t b;
1796
1797 r = sd_bus_message_read_basic(m, type, &b);
1798 if (r < 0)
1799 return bus_log_parse_error(r);
1800
1801 r = json_variant_new_unsigned(&v, b);
1802 if (r < 0)
1803 return log_error_errno(r, "Failed to transform uint64: %m");
1804
1805 break;
1806 }
1807
1808 case SD_BUS_TYPE_DOUBLE: {
1809 double d;
1810
1811 r = sd_bus_message_read_basic(m, type, &d);
1812 if (r < 0)
1813 return bus_log_parse_error(r);
1814
1815 r = json_variant_new_real(&v, d);
1816 if (r < 0)
1817 return log_error_errno(r, "Failed to transform double: %m");
1818
1819 break;
1820 }
1821
1822 case SD_BUS_TYPE_STRING:
1823 case SD_BUS_TYPE_OBJECT_PATH:
1824 case SD_BUS_TYPE_SIGNATURE: {
1825 const char *s;
1826
1827 r = sd_bus_message_read_basic(m, type, &s);
1828 if (r < 0)
1829 return bus_log_parse_error(r);
1830
1831 r = json_variant_new_string(&v, s);
1832 if (r < 0)
1833 return log_error_errno(r, "Failed to transform double: %m");
1834
1835 break;
1836 }
1837
1838 case SD_BUS_TYPE_UNIX_FD:
1839 r = sd_bus_message_read_basic(m, type, NULL);
1840 if (r < 0)
1841 return bus_log_parse_error(r);
1842
1843 r = json_variant_new_null(&v);
1844 if (r < 0)
1845 return log_error_errno(r, "Failed to transform fd: %m");
1846
1847 break;
1848
1849 case SD_BUS_TYPE_ARRAY:
1850 case SD_BUS_TYPE_VARIANT:
1851 case SD_BUS_TYPE_STRUCT:
1852 r = sd_bus_message_enter_container(m, type, contents);
1853 if (r < 0)
1854 return bus_log_parse_error(r);
1855
1856 if (type == SD_BUS_TYPE_VARIANT)
1857 r = json_transform_variant(m, contents, &v);
1858 else if (type == SD_BUS_TYPE_ARRAY && contents[0] == '{')
1859 r = json_transform_dict_array(m, &v);
1860 else
1861 r = json_transform_array_or_struct(m, &v);
1862 if (r < 0)
1863 return r;
1864
1865 r = sd_bus_message_exit_container(m);
1866 if (r < 0)
1867 return bus_log_parse_error(r);
1868
1869 break;
1870
1871 default:
1872 assert_not_reached("Unexpected element type");
1873 }
1874
1875 *ret = TAKE_PTR(v);
1876 return 0;
1877 }
1878
1879 static int json_transform_message(sd_bus_message *m, JsonVariant **ret) {
1880 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1881 const char *type;
1882 int r;
1883
1884 assert(m);
1885 assert(ret);
1886
1887 assert_se(type = sd_bus_message_get_signature(m, false));
1888
1889 r = json_transform_array_or_struct(m, &v);
1890 if (r < 0)
1891 return r;
1892
1893 r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(type)),
1894 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(v))));
1895 if (r < 0)
1896 return log_oom();
1897
1898 return 0;
1899 }
1900
1901 static void json_dump_with_flags(JsonVariant *v, FILE *f) {
1902
1903 json_variant_dump(v,
1904 (arg_json == JSON_PRETTY ? JSON_FORMAT_PRETTY : JSON_FORMAT_NEWLINE) |
1905 colors_enabled() * JSON_FORMAT_COLOR,
1906 f, NULL);
1907 }
1908
1909 static int call(int argc, char **argv, void *userdata) {
1910 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1911 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1912 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
1913 int r;
1914
1915 r = acquire_bus(false, &bus);
1916 if (r < 0)
1917 return r;
1918
1919 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1920 if (r < 0)
1921 return bus_log_create_error(r);
1922
1923 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1924 if (r < 0)
1925 return bus_log_create_error(r);
1926
1927 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1928 if (r < 0)
1929 return bus_log_create_error(r);
1930
1931 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1932 if (r < 0)
1933 return bus_log_create_error(r);
1934
1935 if (!isempty(argv[5])) {
1936 char **p;
1937
1938 p = argv+6;
1939
1940 r = message_append_cmdline(m, argv[5], &p);
1941 if (r < 0)
1942 return r;
1943
1944 if (*p) {
1945 log_error("Too many parameters for signature.");
1946 return -EINVAL;
1947 }
1948 }
1949
1950 if (!arg_expect_reply) {
1951 r = sd_bus_send(bus, m, NULL);
1952 if (r < 0)
1953 return log_error_errno(r, "Failed to send message: %m");
1954
1955 return 0;
1956 }
1957
1958 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1959 if (r < 0)
1960 return log_error_errno(r, "%s", bus_error_message(&error, r));
1961
1962 r = sd_bus_message_is_empty(reply);
1963 if (r < 0)
1964 return bus_log_parse_error(r);
1965
1966 if (r == 0 && !arg_quiet) {
1967
1968 if (arg_json != JSON_OFF) {
1969 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1970
1971 if (arg_json != JSON_SHORT)
1972 (void) pager_open(arg_pager_flags);
1973
1974 r = json_transform_message(reply, &v);
1975 if (r < 0)
1976 return r;
1977
1978 json_dump_with_flags(v, stdout);
1979
1980 } else if (arg_verbose) {
1981 (void) pager_open(arg_pager_flags);
1982
1983 r = bus_message_dump(reply, stdout, 0);
1984 if (r < 0)
1985 return r;
1986 } else {
1987
1988 fputs(sd_bus_message_get_signature(reply, true), stdout);
1989 fputc(' ', stdout);
1990
1991 r = format_cmdline(reply, stdout, false);
1992 if (r < 0)
1993 return bus_log_parse_error(r);
1994
1995 fputc('\n', stdout);
1996 }
1997 }
1998
1999 return 0;
2000 }
2001
2002 static int get_property(int argc, char **argv, void *userdata) {
2003 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2004 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2005 char **i;
2006 int r;
2007
2008 r = acquire_bus(false, &bus);
2009 if (r < 0)
2010 return r;
2011
2012 STRV_FOREACH(i, argv + 4) {
2013 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2014 const char *contents = NULL;
2015 char type;
2016
2017 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
2018 if (r < 0)
2019 return log_error_errno(r, "%s", bus_error_message(&error, r));
2020
2021 r = sd_bus_message_peek_type(reply, &type, &contents);
2022 if (r < 0)
2023 return bus_log_parse_error(r);
2024
2025 r = sd_bus_message_enter_container(reply, 'v', contents);
2026 if (r < 0)
2027 return bus_log_parse_error(r);
2028
2029 if (arg_json != JSON_OFF) {
2030 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
2031
2032 if (arg_json != JSON_SHORT)
2033 (void) pager_open(arg_pager_flags);
2034
2035 r = json_transform_variant(reply, contents, &v);
2036 if (r < 0)
2037 return r;
2038
2039 json_dump_with_flags(v, stdout);
2040
2041 } else if (arg_verbose) {
2042 (void) pager_open(arg_pager_flags);
2043
2044 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
2045 if (r < 0)
2046 return r;
2047 } else {
2048 fputs(contents, stdout);
2049 fputc(' ', stdout);
2050
2051 r = format_cmdline(reply, stdout, false);
2052 if (r < 0)
2053 return bus_log_parse_error(r);
2054
2055 fputc('\n', stdout);
2056 }
2057
2058 r = sd_bus_message_exit_container(reply);
2059 if (r < 0)
2060 return bus_log_parse_error(r);
2061 }
2062
2063 return 0;
2064 }
2065
2066 static int set_property(int argc, char **argv, void *userdata) {
2067 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2068 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2069 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2070 char **p;
2071 int r;
2072
2073 r = acquire_bus(false, &bus);
2074 if (r < 0)
2075 return r;
2076
2077 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
2078 if (r < 0)
2079 return bus_log_create_error(r);
2080
2081 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
2082 if (r < 0)
2083 return bus_log_create_error(r);
2084
2085 r = sd_bus_message_open_container(m, 'v', argv[5]);
2086 if (r < 0)
2087 return bus_log_create_error(r);
2088
2089 p = argv + 6;
2090 r = message_append_cmdline(m, argv[5], &p);
2091 if (r < 0)
2092 return r;
2093
2094 r = sd_bus_message_close_container(m);
2095 if (r < 0)
2096 return bus_log_create_error(r);
2097
2098 if (*p) {
2099 log_error("Too many parameters for signature.");
2100 return -EINVAL;
2101 }
2102
2103 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
2104 if (r < 0)
2105 return log_error_errno(r, "%s", bus_error_message(&error, r));
2106
2107 return 0;
2108 }
2109
2110 static int help(void) {
2111 _cleanup_free_ char *link = NULL;
2112 int r;
2113
2114 r = terminal_urlify_man("busctl", "1", &link);
2115 if (r < 0)
2116 return log_oom();
2117
2118 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
2119 "Introspect the bus.\n\n"
2120 " -h --help Show this help\n"
2121 " --version Show package version\n"
2122 " --no-pager Do not pipe output into a pager\n"
2123 " --no-legend Do not show the headers and footers\n"
2124 " --system Connect to system bus\n"
2125 " --user Connect to user bus\n"
2126 " -H --host=[USER@]HOST Operate on remote host\n"
2127 " -M --machine=CONTAINER Operate on local container\n"
2128 " --address=ADDRESS Connect to bus specified by address\n"
2129 " --show-machine Show machine ID column in list\n"
2130 " --unique Only show unique names\n"
2131 " --acquired Only show acquired names\n"
2132 " --activatable Only show activatable names\n"
2133 " --match=MATCH Only show matching messages\n"
2134 " --size=SIZE Maximum length of captured packet\n"
2135 " --list Don't show tree, but simple object path list\n"
2136 " -q --quiet Don't show method call reply\n"
2137 " --verbose Show result values in long format\n"
2138 " --json=MODE Output as JSON\n"
2139 " -j Same as --json=pretty on tty, --json=short otherwise\n"
2140 " --expect-reply=BOOL Expect a method call reply\n"
2141 " --auto-start=BOOL Auto-start destination service\n"
2142 " --allow-interactive-authorization=BOOL\n"
2143 " Allow interactive authorization for operation\n"
2144 " --timeout=SECS Maximum time to wait for method call completion\n"
2145 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
2146 " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n"
2147 " system\n\n"
2148 "Commands:\n"
2149 " list List bus names\n"
2150 " status [SERVICE] Show bus service, process or bus owner credentials\n"
2151 " monitor [SERVICE...] Show bus traffic\n"
2152 " capture [SERVICE...] Capture bus traffic as pcap\n"
2153 " tree [SERVICE...] Show object tree of service\n"
2154 " introspect SERVICE OBJECT [INTERFACE]\n"
2155 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
2156 " Call a method\n"
2157 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
2158 " Get property value\n"
2159 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
2160 " Set property value\n"
2161 " help Show this help\n"
2162 "\nSee the %s for details.\n"
2163 , program_invocation_short_name
2164 , link
2165 );
2166
2167 return 0;
2168 }
2169
2170 static int verb_help(int argc, char **argv, void *userdata) {
2171 return help();
2172 }
2173
2174 static int parse_argv(int argc, char *argv[]) {
2175
2176 enum {
2177 ARG_VERSION = 0x100,
2178 ARG_NO_PAGER,
2179 ARG_NO_LEGEND,
2180 ARG_SYSTEM,
2181 ARG_USER,
2182 ARG_ADDRESS,
2183 ARG_MATCH,
2184 ARG_SHOW_MACHINE,
2185 ARG_UNIQUE,
2186 ARG_ACQUIRED,
2187 ARG_ACTIVATABLE,
2188 ARG_SIZE,
2189 ARG_LIST,
2190 ARG_VERBOSE,
2191 ARG_EXPECT_REPLY,
2192 ARG_AUTO_START,
2193 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
2194 ARG_TIMEOUT,
2195 ARG_AUGMENT_CREDS,
2196 ARG_WATCH_BIND,
2197 ARG_JSON,
2198 };
2199
2200 static const struct option options[] = {
2201 { "help", no_argument, NULL, 'h' },
2202 { "version", no_argument, NULL, ARG_VERSION },
2203 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
2204 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
2205 { "system", no_argument, NULL, ARG_SYSTEM },
2206 { "user", no_argument, NULL, ARG_USER },
2207 { "address", required_argument, NULL, ARG_ADDRESS },
2208 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
2209 { "unique", no_argument, NULL, ARG_UNIQUE },
2210 { "acquired", no_argument, NULL, ARG_ACQUIRED },
2211 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
2212 { "match", required_argument, NULL, ARG_MATCH },
2213 { "host", required_argument, NULL, 'H' },
2214 { "machine", required_argument, NULL, 'M' },
2215 { "size", required_argument, NULL, ARG_SIZE },
2216 { "list", no_argument, NULL, ARG_LIST },
2217 { "quiet", no_argument, NULL, 'q' },
2218 { "verbose", no_argument, NULL, ARG_VERBOSE },
2219 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
2220 { "auto-start", required_argument, NULL, ARG_AUTO_START },
2221 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
2222 { "timeout", required_argument, NULL, ARG_TIMEOUT },
2223 { "augment-creds", required_argument, NULL, ARG_AUGMENT_CREDS },
2224 { "watch-bind", required_argument, NULL, ARG_WATCH_BIND },
2225 { "json", required_argument, NULL, ARG_JSON },
2226 {},
2227 };
2228
2229 int c, r;
2230
2231 assert(argc >= 0);
2232 assert(argv);
2233
2234 while ((c = getopt_long(argc, argv, "hH:M:qj", options, NULL)) >= 0)
2235
2236 switch (c) {
2237
2238 case 'h':
2239 return help();
2240
2241 case ARG_VERSION:
2242 return version();
2243
2244 case ARG_NO_PAGER:
2245 arg_pager_flags |= PAGER_DISABLE;
2246 break;
2247
2248 case ARG_NO_LEGEND:
2249 arg_legend = false;
2250 break;
2251
2252 case ARG_USER:
2253 arg_user = true;
2254 break;
2255
2256 case ARG_SYSTEM:
2257 arg_user = false;
2258 break;
2259
2260 case ARG_ADDRESS:
2261 arg_address = optarg;
2262 break;
2263
2264 case ARG_SHOW_MACHINE:
2265 arg_show_machine = true;
2266 break;
2267
2268 case ARG_UNIQUE:
2269 arg_unique = true;
2270 break;
2271
2272 case ARG_ACQUIRED:
2273 arg_acquired = true;
2274 break;
2275
2276 case ARG_ACTIVATABLE:
2277 arg_activatable = true;
2278 break;
2279
2280 case ARG_MATCH:
2281 if (strv_extend(&arg_matches, optarg) < 0)
2282 return log_oom();
2283 break;
2284
2285 case ARG_SIZE: {
2286 uint64_t sz;
2287
2288 r = parse_size(optarg, 1024, &sz);
2289 if (r < 0)
2290 return log_error_errno(r, "Failed to parse size '%s': %m", optarg);
2291
2292 if ((uint64_t) (size_t) sz != sz)
2293 return log_error_errno(SYNTHETIC_ERRNO(E2BIG),
2294 "Size out of range.");
2295
2296 arg_snaplen = (size_t) sz;
2297 break;
2298 }
2299
2300 case ARG_LIST:
2301 arg_list = true;
2302 break;
2303
2304 case 'H':
2305 arg_transport = BUS_TRANSPORT_REMOTE;
2306 arg_host = optarg;
2307 break;
2308
2309 case 'M':
2310 arg_transport = BUS_TRANSPORT_MACHINE;
2311 arg_host = optarg;
2312 break;
2313
2314 case 'q':
2315 arg_quiet = true;
2316 break;
2317
2318 case ARG_VERBOSE:
2319 arg_verbose = true;
2320 break;
2321
2322 case ARG_EXPECT_REPLY:
2323 r = parse_boolean(optarg);
2324 if (r < 0)
2325 return log_error_errno(r, "Failed to parse --expect-reply= parameter '%s': %m", optarg);
2326
2327 arg_expect_reply = r;
2328 break;
2329
2330 case ARG_AUTO_START:
2331 r = parse_boolean(optarg);
2332 if (r < 0)
2333 return log_error_errno(r, "Failed to parse --auto-start= parameter '%s': %m", optarg);
2334
2335 arg_auto_start = r;
2336 break;
2337
2338 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
2339 r = parse_boolean(optarg);
2340 if (r < 0)
2341 return log_error_errno(r, "Failed to parse --allow-interactive-authorization= parameter '%s': %m", optarg);
2342
2343 arg_allow_interactive_authorization = r;
2344 break;
2345
2346 case ARG_TIMEOUT:
2347 r = parse_sec(optarg, &arg_timeout);
2348 if (r < 0)
2349 return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", optarg);
2350
2351 break;
2352
2353 case ARG_AUGMENT_CREDS:
2354 r = parse_boolean(optarg);
2355 if (r < 0)
2356 return log_error_errno(r, "Failed to parse --augment-creds= parameter '%s': %m", optarg);
2357
2358 arg_augment_creds = r;
2359 break;
2360
2361 case ARG_WATCH_BIND:
2362 r = parse_boolean(optarg);
2363 if (r < 0)
2364 return log_error_errno(r, "Failed to parse --watch-bind= parameter '%s': %m", optarg);
2365
2366 arg_watch_bind = r;
2367 break;
2368
2369 case 'j':
2370 if (on_tty())
2371 arg_json = JSON_PRETTY;
2372 else
2373 arg_json = JSON_SHORT;
2374 break;
2375
2376 case ARG_JSON:
2377 if (streq(optarg, "short"))
2378 arg_json = JSON_SHORT;
2379 else if (streq(optarg, "pretty"))
2380 arg_json = JSON_PRETTY;
2381 else if (streq(optarg, "help")) {
2382 fputs("short\n"
2383 "pretty\n", stdout);
2384 return 0;
2385 } else
2386 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2387 "Unknown JSON out mode: %s",
2388 optarg);
2389
2390 break;
2391
2392 case '?':
2393 return -EINVAL;
2394
2395 default:
2396 assert_not_reached("Unhandled option");
2397 }
2398
2399 return 1;
2400 }
2401
2402 static int busctl_main(int argc, char *argv[]) {
2403
2404 static const Verb verbs[] = {
2405 { "list", VERB_ANY, 1, VERB_DEFAULT, list_bus_names },
2406 { "status", VERB_ANY, 2, 0, status },
2407 { "monitor", VERB_ANY, VERB_ANY, 0, verb_monitor },
2408 { "capture", VERB_ANY, VERB_ANY, 0, verb_capture },
2409 { "tree", VERB_ANY, VERB_ANY, 0, tree },
2410 { "introspect", 3, 4, 0, introspect },
2411 { "call", 5, VERB_ANY, 0, call },
2412 { "get-property", 5, VERB_ANY, 0, get_property },
2413 { "set-property", 6, VERB_ANY, 0, set_property },
2414 { "help", VERB_ANY, VERB_ANY, 0, verb_help },
2415 {}
2416 };
2417
2418 return dispatch_verb(argc, argv, verbs, NULL);
2419 }
2420
2421 static int run(int argc, char *argv[]) {
2422 int r;
2423
2424 log_parse_environment();
2425 log_open();
2426
2427 r = parse_argv(argc, argv);
2428 if (r <= 0)
2429 return r;
2430
2431 return busctl_main(argc, argv);
2432 }
2433
2434 DEFINE_MAIN_FUNCTION(run);