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