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