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