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