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