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