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