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