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