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