]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/busctl.c
sd-bus: rename sd_bus_get_owner_id() → sd_bus_get_bus_id()
[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
32 #include "sd-bus.h"
33 #include "bus-message.h"
34 #include "bus-internal.h"
35 #include "bus-util.h"
36 #include "bus-dump.h"
37 #include "bus-signature.h"
38 #include "bus-type.h"
39 #include "busctl-introspect.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_UID|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_uid(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 = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
259 space = strappenda(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_highlight_off());
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_highlight_off());
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, true);
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 }
618 }
619
620 typedef struct Member {
621 const char *type;
622 char *interface;
623 char *name;
624 char *signature;
625 char *result;
626 char *value;
627 bool writable;
628 uint64_t flags;
629 } Member;
630
631 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
632 const Member *m = p;
633 unsigned long ul;
634
635 assert(m);
636 assert(m->type);
637
638 ul = string_hash_func(m->type, hash_key);
639
640 if (m->name)
641 ul ^= string_hash_func(m->name, hash_key);
642
643 if (m->interface)
644 ul ^= string_hash_func(m->interface, hash_key);
645
646 return ul;
647 }
648
649 static int member_compare_func(const void *a, const void *b) {
650 const Member *x = a, *y = b;
651 int d;
652
653 assert(x);
654 assert(y);
655 assert(x->type);
656 assert(y->type);
657
658 if (!x->interface && y->interface)
659 return -1;
660 if (x->interface && !y->interface)
661 return 1;
662 if (x->interface && y->interface) {
663 d = strcmp(x->interface, y->interface);
664 if (d != 0)
665 return d;
666 }
667
668 d = strcmp(x->type, y->type);
669 if (d != 0)
670 return d;
671
672 if (!x->name && y->name)
673 return -1;
674 if (x->name && !y->name)
675 return 1;
676 if (x->name && y->name)
677 return strcmp(x->name, y->name);
678
679 return 0;
680 }
681
682 static int member_compare_funcp(const void *a, const void *b) {
683 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
684
685 return member_compare_func(*x, *y);
686 }
687
688 static void member_free(Member *m) {
689 if (!m)
690 return;
691
692 free(m->interface);
693 free(m->name);
694 free(m->signature);
695 free(m->result);
696 free(m->value);
697 free(m);
698 }
699
700 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
701
702 static void member_set_free(Set *s) {
703 Member *m;
704
705 while ((m = set_steal_first(s)))
706 member_free(m);
707
708 set_free(s);
709 }
710
711 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
712
713 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
714 _cleanup_(member_freep) Member *m;
715 Set *members = userdata;
716 int r;
717
718 assert(interface);
719 assert(members);
720
721 m = new0(Member, 1);
722 if (!m)
723 return log_oom();
724
725 m->type = "interface";
726 m->flags = flags;
727
728 r = free_and_strdup(&m->interface, interface);
729 if (r < 0)
730 return log_oom();
731
732 r = set_put(members, m);
733 if (r <= 0) {
734 log_error("Duplicate interface");
735 return -EINVAL;
736 }
737
738 m = NULL;
739 return 0;
740 }
741
742 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
743 _cleanup_(member_freep) Member *m;
744 Set *members = userdata;
745 int r;
746
747 assert(interface);
748 assert(name);
749
750 m = new0(Member, 1);
751 if (!m)
752 return log_oom();
753
754 m->type = "method";
755 m->flags = flags;
756
757 r = free_and_strdup(&m->interface, interface);
758 if (r < 0)
759 return log_oom();
760
761 r = free_and_strdup(&m->name, name);
762 if (r < 0)
763 return log_oom();
764
765 r = free_and_strdup(&m->signature, signature);
766 if (r < 0)
767 return log_oom();
768
769 r = free_and_strdup(&m->result, result);
770 if (r < 0)
771 return log_oom();
772
773 r = set_put(members, m);
774 if (r <= 0) {
775 log_error("Duplicate method");
776 return -EINVAL;
777 }
778
779 m = NULL;
780 return 0;
781 }
782
783 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
784 _cleanup_(member_freep) Member *m;
785 Set *members = userdata;
786 int r;
787
788 assert(interface);
789 assert(name);
790
791 m = new0(Member, 1);
792 if (!m)
793 return log_oom();
794
795 m->type = "signal";
796 m->flags = flags;
797
798 r = free_and_strdup(&m->interface, interface);
799 if (r < 0)
800 return log_oom();
801
802 r = free_and_strdup(&m->name, name);
803 if (r < 0)
804 return log_oom();
805
806 r = free_and_strdup(&m->signature, signature);
807 if (r < 0)
808 return log_oom();
809
810 r = set_put(members, m);
811 if (r <= 0) {
812 log_error("Duplicate signal");
813 return -EINVAL;
814 }
815
816 m = NULL;
817 return 0;
818 }
819
820 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
821 _cleanup_(member_freep) Member *m;
822 Set *members = userdata;
823 int r;
824
825 assert(interface);
826 assert(name);
827
828 m = new0(Member, 1);
829 if (!m)
830 return log_oom();
831
832 m->type = "property";
833 m->flags = flags;
834 m->writable = writable;
835
836 r = free_and_strdup(&m->interface, interface);
837 if (r < 0)
838 return log_oom();
839
840 r = free_and_strdup(&m->name, name);
841 if (r < 0)
842 return log_oom();
843
844 r = free_and_strdup(&m->signature, signature);
845 if (r < 0)
846 return log_oom();
847
848 r = set_put(members, m);
849 if (r <= 0) {
850 log_error("Duplicate property");
851 return -EINVAL;
852 }
853
854 m = NULL;
855 return 0;
856 }
857
858 static const char *strdash(const char *x) {
859 return isempty(x) ? "-" : x;
860 }
861
862 static int introspect(sd_bus *bus, char **argv) {
863 static const struct hash_ops member_hash_ops = {
864 .hash = member_hash_func,
865 .compare = member_compare_func,
866 };
867
868 static const XMLIntrospectOps ops = {
869 .on_interface = on_interface,
870 .on_method = on_method,
871 .on_signal = on_signal,
872 .on_property = on_property,
873 };
874
875 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
876 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
877 _cleanup_(member_set_freep) Set *members = NULL;
878 Iterator i;
879 Member *m;
880 const char *xml;
881 int r;
882 unsigned name_width, type_width, signature_width, result_width;
883 Member **sorted = NULL;
884 unsigned k = 0, j;
885
886 if (strv_length(argv) != 3) {
887 log_error("Requires service and object path argument.");
888 return -EINVAL;
889 }
890
891 members = set_new(&member_hash_ops);
892 if (!members)
893 return log_oom();
894
895 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
896 if (r < 0) {
897 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
898 return r;
899 }
900
901 r = sd_bus_message_read(reply, "s", &xml);
902 if (r < 0)
903 return bus_log_parse_error(r);
904
905 /* First, get list of all properties */
906 r = parse_xml_introspect(argv[2], xml, &ops, members);
907 if (r < 0)
908 return r;
909
910 /* Second, find the current values for them */
911 SET_FOREACH(m, members, i) {
912
913 if (!streq(m->type, "property"))
914 continue;
915
916 if (m->value)
917 continue;
918
919 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
920 if (r < 0) {
921 log_error("%s", bus_error_message(&error, r));
922 return r;
923 }
924
925 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
926 if (r < 0)
927 return bus_log_parse_error(r);
928
929 for (;;) {
930 Member *z;
931 _cleanup_free_ char *buf = NULL;
932 _cleanup_fclose_ FILE *mf = NULL;
933 size_t sz = 0;
934 const char *name;
935
936 r = sd_bus_message_enter_container(reply, 'e', "sv");
937 if (r < 0)
938 return bus_log_parse_error(r);
939
940 if (r == 0)
941 break;
942
943 r = sd_bus_message_read(reply, "s", &name);
944 if (r < 0)
945 return bus_log_parse_error(r);
946
947 r = sd_bus_message_enter_container(reply, 'v', NULL);
948 if (r < 0)
949 return bus_log_parse_error(r);
950
951 mf = open_memstream(&buf, &sz);
952 if (!mf)
953 return log_oom();
954
955 r = format_cmdline(reply, mf, false);
956 if (r < 0)
957 return bus_log_parse_error(r);
958
959 fclose(mf);
960 mf = NULL;
961
962 z = set_get(members, &((Member) {
963 .type = "property",
964 .interface = m->interface,
965 .name = (char*) name }));
966 if (z) {
967 free(z->value);
968 z->value = buf;
969 buf = NULL;
970 }
971
972 r = sd_bus_message_exit_container(reply);
973 if (r < 0)
974 return bus_log_parse_error(r);
975
976 r = sd_bus_message_exit_container(reply);
977 if (r < 0)
978 return bus_log_parse_error(r);
979 }
980
981 r = sd_bus_message_exit_container(reply);
982 if (r < 0)
983 return bus_log_parse_error(r);
984 }
985
986 pager_open_if_enabled();
987
988 name_width = strlen("NAME");
989 type_width = strlen("TYPE");
990 signature_width = strlen("SIGNATURE");
991 result_width = strlen("RESULT/VALUE");
992
993 sorted = newa(Member*, set_size(members));
994
995 SET_FOREACH(m, members, i) {
996 if (m->interface)
997 name_width = MAX(name_width, strlen(m->interface));
998 if (m->name)
999 name_width = MAX(name_width, strlen(m->name) + 1);
1000 if (m->type)
1001 type_width = MAX(type_width, strlen(m->type));
1002 if (m->signature)
1003 signature_width = MAX(signature_width, strlen(m->signature));
1004 if (m->result)
1005 result_width = MAX(result_width, strlen(m->result));
1006 if (m->value)
1007 result_width = MAX(result_width, strlen(m->value));
1008
1009 sorted[k++] = m;
1010 }
1011
1012 if (result_width > 40)
1013 result_width = 40;
1014
1015 assert(k == set_size(members));
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 is_interface = streq(m->type, "interface");
1035
1036 if (m->value) {
1037 ellipsized = ellipsize(m->value, result_width, 100);
1038 if (!ellipsized)
1039 return log_oom();
1040
1041 rv = ellipsized;
1042 } else
1043 rv = strdash(m->result);
1044
1045 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1046 is_interface ? ansi_highlight() : "",
1047 is_interface ? "" : ".",
1048 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1049 is_interface ? ansi_highlight_off() : "",
1050 (int) type_width, strdash(m->type),
1051 (int) signature_width, strdash(m->signature),
1052 (int) result_width, rv,
1053 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1054 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1055 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1056 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1057 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1058 m->writable ? " writable" : "");
1059 }
1060
1061 return 0;
1062 }
1063
1064 static int message_dump(sd_bus_message *m, FILE *f) {
1065 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1066 }
1067
1068 static int message_pcap(sd_bus_message *m, FILE *f) {
1069 return bus_message_pcap_frame(m, arg_snaplen, f);
1070 }
1071
1072 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1073 bool added_something = false;
1074 char **i;
1075 int r;
1076
1077 STRV_FOREACH(i, argv+1) {
1078 _cleanup_free_ char *m = NULL;
1079
1080 if (!service_name_is_valid(*i)) {
1081 log_error("Invalid service name '%s'", *i);
1082 return -EINVAL;
1083 }
1084
1085 m = strjoin("sender='", *i, "'", NULL);
1086 if (!m)
1087 return log_oom();
1088
1089 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1090 if (r < 0)
1091 return log_error_errno(r, "Failed to add match: %m");
1092
1093 added_something = true;
1094 }
1095
1096 STRV_FOREACH(i, arg_matches) {
1097 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1098 if (r < 0)
1099 return log_error_errno(r, "Failed to add match: %m");
1100
1101 added_something = true;
1102 }
1103
1104 if (!added_something) {
1105 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1106 if (r < 0)
1107 return log_error_errno(r, "Failed to add match: %m");
1108 }
1109
1110 for (;;) {
1111 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1112
1113 r = sd_bus_process(bus, &m);
1114 if (r < 0)
1115 return log_error_errno(r, "Failed to process bus: %m");
1116
1117 if (m) {
1118 dump(m, stdout);
1119 continue;
1120 }
1121
1122 if (r > 0)
1123 continue;
1124
1125 r = sd_bus_wait(bus, (uint64_t) -1);
1126 if (r < 0)
1127 return log_error_errno(r, "Failed to wait for bus: %m");
1128 }
1129 }
1130
1131 static int capture(sd_bus *bus, char *argv[]) {
1132 int r;
1133
1134 if (isatty(fileno(stdout)) > 0) {
1135 log_error("Refusing to write message data to console, please redirect output to a file.");
1136 return -EINVAL;
1137 }
1138
1139 bus_pcap_header(arg_snaplen, stdout);
1140
1141 r = monitor(bus, argv, message_pcap);
1142 if (r < 0)
1143 return r;
1144
1145 if (ferror(stdout)) {
1146 log_error("Couldn't write capture file.");
1147 return -EIO;
1148 }
1149
1150 return r;
1151 }
1152
1153 static int status(sd_bus *bus, char *argv[]) {
1154 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1155 pid_t pid;
1156 int r;
1157
1158 assert(bus);
1159
1160 if (strv_length(argv) > 2) {
1161 log_error("Expects no or one argument.");
1162 return -EINVAL;
1163 }
1164
1165 if (argv[1]) {
1166 r = parse_pid(argv[1], &pid);
1167 if (r < 0)
1168 r = sd_bus_get_name_creds(
1169 bus,
1170 argv[1],
1171 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1172 &creds);
1173 else
1174 r = sd_bus_creds_new_from_pid(
1175 &creds,
1176 pid,
1177 _SD_BUS_CREDS_ALL);
1178 } else {
1179 const char *scope;
1180 sd_id128_t bus_id;
1181
1182 r = sd_bus_get_scope(bus, &scope);
1183 if (r >= 0)
1184 printf("Scope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off());
1185
1186 r = sd_bus_get_bus_id(bus, &bus_id);
1187 if (r >= 0)
1188 printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off());
1189
1190 r = sd_bus_get_owner_creds(
1191 bus,
1192 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1193 &creds);
1194 }
1195
1196 if (r < 0)
1197 return log_error_errno(r, "Failed to get credentials: %m");
1198
1199 bus_creds_dump(creds, NULL, false);
1200 return 0;
1201 }
1202
1203 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1204 char **p;
1205 int r;
1206
1207 assert(m);
1208 assert(signature);
1209 assert(x);
1210
1211 p = *x;
1212
1213 for (;;) {
1214 const char *v;
1215 char t;
1216
1217 t = *signature;
1218 v = *p;
1219
1220 if (t == 0)
1221 break;
1222 if (!v) {
1223 log_error("Too few parameters for signature.");
1224 return -EINVAL;
1225 }
1226
1227 signature++;
1228 p++;
1229
1230 switch (t) {
1231
1232 case SD_BUS_TYPE_BOOLEAN:
1233
1234 r = parse_boolean(v);
1235 if (r < 0) {
1236 log_error("Failed to parse as boolean: %s", v);
1237 return r;
1238 }
1239
1240 r = sd_bus_message_append_basic(m, t, &r);
1241 break;
1242
1243 case SD_BUS_TYPE_BYTE: {
1244 uint8_t z;
1245
1246 r = safe_atou8(v, &z);
1247 if (r < 0) {
1248 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1249 return r;
1250 }
1251
1252 r = sd_bus_message_append_basic(m, t, &z);
1253 break;
1254 }
1255
1256 case SD_BUS_TYPE_INT16: {
1257 int16_t z;
1258
1259 r = safe_atoi16(v, &z);
1260 if (r < 0) {
1261 log_error("Failed to parse as signed 16bit integer: %s", v);
1262 return r;
1263 }
1264
1265 r = sd_bus_message_append_basic(m, t, &z);
1266 break;
1267 }
1268
1269 case SD_BUS_TYPE_UINT16: {
1270 uint16_t z;
1271
1272 r = safe_atou16(v, &z);
1273 if (r < 0) {
1274 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1275 return r;
1276 }
1277
1278 r = sd_bus_message_append_basic(m, t, &z);
1279 break;
1280 }
1281
1282 case SD_BUS_TYPE_INT32: {
1283 int32_t z;
1284
1285 r = safe_atoi32(v, &z);
1286 if (r < 0) {
1287 log_error("Failed to parse as signed 32bit integer: %s", v);
1288 return r;
1289 }
1290
1291 r = sd_bus_message_append_basic(m, t, &z);
1292 break;
1293 }
1294
1295 case SD_BUS_TYPE_UINT32: {
1296 uint32_t z;
1297
1298 r = safe_atou32(v, &z);
1299 if (r < 0) {
1300 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1301 return r;
1302 }
1303
1304 r = sd_bus_message_append_basic(m, t, &z);
1305 break;
1306 }
1307
1308 case SD_BUS_TYPE_INT64: {
1309 int64_t z;
1310
1311 r = safe_atoi64(v, &z);
1312 if (r < 0) {
1313 log_error("Failed to parse as signed 64bit integer: %s", v);
1314 return r;
1315 }
1316
1317 r = sd_bus_message_append_basic(m, t, &z);
1318 break;
1319 }
1320
1321 case SD_BUS_TYPE_UINT64: {
1322 uint64_t z;
1323
1324 r = safe_atou64(v, &z);
1325 if (r < 0) {
1326 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1327 return r;
1328 }
1329
1330 r = sd_bus_message_append_basic(m, t, &z);
1331 break;
1332 }
1333
1334
1335 case SD_BUS_TYPE_DOUBLE: {
1336 double z;
1337
1338 r = safe_atod(v, &z);
1339 if (r < 0) {
1340 log_error("Failed to parse as double precision floating point: %s", v);
1341 return r;
1342 }
1343
1344 r = sd_bus_message_append_basic(m, t, &z);
1345 break;
1346 }
1347
1348 case SD_BUS_TYPE_STRING:
1349 case SD_BUS_TYPE_OBJECT_PATH:
1350 case SD_BUS_TYPE_SIGNATURE:
1351
1352 r = sd_bus_message_append_basic(m, t, v);
1353 break;
1354
1355 case SD_BUS_TYPE_ARRAY: {
1356 uint32_t n;
1357 size_t k;
1358
1359 r = safe_atou32(v, &n);
1360 if (r < 0) {
1361 log_error("Failed to parse number of array entries: %s", v);
1362 return r;
1363 }
1364
1365 r = signature_element_length(signature, &k);
1366 if (r < 0) {
1367 log_error("Invalid array signature.");
1368 return r;
1369 }
1370
1371 {
1372 unsigned i;
1373 char s[k + 1];
1374 memcpy(s, signature, k);
1375 s[k] = 0;
1376
1377 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1378 if (r < 0)
1379 return bus_log_create_error(r);
1380
1381 for (i = 0; i < n; i++) {
1382 r = message_append_cmdline(m, s, &p);
1383 if (r < 0)
1384 return r;
1385 }
1386 }
1387
1388 signature += k;
1389
1390 r = sd_bus_message_close_container(m);
1391 break;
1392 }
1393
1394 case SD_BUS_TYPE_VARIANT:
1395 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1396 if (r < 0)
1397 return bus_log_create_error(r);
1398
1399 r = message_append_cmdline(m, v, &p);
1400 if (r < 0)
1401 return r;
1402
1403 r = sd_bus_message_close_container(m);
1404 break;
1405
1406 case SD_BUS_TYPE_STRUCT_BEGIN:
1407 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1408 size_t k;
1409
1410 signature--;
1411 p--;
1412
1413 r = signature_element_length(signature, &k);
1414 if (r < 0) {
1415 log_error("Invalid struct/dict entry signature.");
1416 return r;
1417 }
1418
1419 {
1420 char s[k-1];
1421 memcpy(s, signature + 1, k - 2);
1422 s[k - 2] = 0;
1423
1424 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1425 if (r < 0)
1426 return bus_log_create_error(r);
1427
1428 r = message_append_cmdline(m, s, &p);
1429 if (r < 0)
1430 return r;
1431 }
1432
1433 signature += k;
1434
1435 r = sd_bus_message_close_container(m);
1436 break;
1437 }
1438
1439 case SD_BUS_TYPE_UNIX_FD:
1440 log_error("UNIX file descriptor not supported as type.");
1441 return -EINVAL;
1442
1443 default:
1444 log_error("Unknown signature type %c.", t);
1445 return -EINVAL;
1446 }
1447
1448 if (r < 0)
1449 return bus_log_create_error(r);
1450 }
1451
1452 *x = p;
1453 return 0;
1454 }
1455
1456 static int call(sd_bus *bus, char *argv[]) {
1457 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1458 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1459 int r;
1460
1461 assert(bus);
1462
1463 if (strv_length(argv) < 5) {
1464 log_error("Expects at least four arguments.");
1465 return -EINVAL;
1466 }
1467
1468 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1469 if (r < 0)
1470 return bus_log_create_error(r);
1471
1472 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1473 if (r < 0)
1474 return bus_log_create_error(r);
1475
1476 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1477 if (r < 0)
1478 return bus_log_create_error(r);
1479
1480 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1481 if (r < 0)
1482 return bus_log_create_error(r);
1483
1484 if (!isempty(argv[5])) {
1485 char **p;
1486
1487 p = argv+6;
1488
1489 r = message_append_cmdline(m, argv[5], &p);
1490 if (r < 0)
1491 return r;
1492
1493 if (*p) {
1494 log_error("Too many parameters for signature.");
1495 return -EINVAL;
1496 }
1497 }
1498
1499 if (!arg_expect_reply) {
1500 r = sd_bus_send(bus, m, NULL);
1501 if (r < 0) {
1502 log_error("Failed to send message.");
1503 return r;
1504 }
1505
1506 return 0;
1507 }
1508
1509 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1510 if (r < 0) {
1511 log_error("%s", bus_error_message(&error, r));
1512 return r;
1513 }
1514
1515 r = sd_bus_message_is_empty(reply);
1516 if (r < 0)
1517 return bus_log_parse_error(r);
1518
1519 if (r == 0 && !arg_quiet) {
1520
1521 if (arg_verbose) {
1522 pager_open_if_enabled();
1523
1524 r = bus_message_dump(reply, stdout, 0);
1525 if (r < 0)
1526 return r;
1527 } else {
1528
1529 fputs(sd_bus_message_get_signature(reply, true), stdout);
1530 fputc(' ', stdout);
1531
1532 r = format_cmdline(reply, stdout, false);
1533 if (r < 0)
1534 return bus_log_parse_error(r);
1535
1536 fputc('\n', stdout);
1537 }
1538 }
1539
1540 return 0;
1541 }
1542
1543 static int get_property(sd_bus *bus, char *argv[]) {
1544 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1545 unsigned n;
1546 char **i;
1547 int r;
1548
1549 assert(bus);
1550
1551 n = strv_length(argv);
1552 if (n < 5) {
1553 log_error("Expects at least four arguments.");
1554 return -EINVAL;
1555 }
1556
1557 STRV_FOREACH(i, argv + 4) {
1558 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1559 const char *contents = NULL;
1560 char type;
1561
1562 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1563 if (r < 0) {
1564 log_error("%s", bus_error_message(&error, r));
1565 return r;
1566 }
1567
1568 r = sd_bus_message_peek_type(reply, &type, &contents);
1569 if (r < 0)
1570 return bus_log_parse_error(r);
1571
1572 r = sd_bus_message_enter_container(reply, 'v', contents);
1573 if (r < 0)
1574 return bus_log_parse_error(r);
1575
1576 if (arg_verbose) {
1577 pager_open_if_enabled();
1578
1579 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1580 if (r < 0)
1581 return r;
1582 } else {
1583 fputs(contents, stdout);
1584 fputc(' ', stdout);
1585
1586 r = format_cmdline(reply, stdout, false);
1587 if (r < 0)
1588 return bus_log_parse_error(r);
1589
1590 fputc('\n', stdout);
1591 }
1592
1593 r = sd_bus_message_exit_container(reply);
1594 if (r < 0)
1595 return bus_log_parse_error(r);
1596 }
1597
1598 return 0;
1599 }
1600
1601 static int set_property(sd_bus *bus, char *argv[]) {
1602 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1603 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1604 unsigned n;
1605 char **p;
1606 int r;
1607
1608 assert(bus);
1609
1610 n = strv_length(argv);
1611 if (n < 6) {
1612 log_error("Expects at least five arguments.");
1613 return -EINVAL;
1614 }
1615
1616 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1617 if (r < 0)
1618 return bus_log_create_error(r);
1619
1620 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1621 if (r < 0)
1622 return bus_log_create_error(r);
1623
1624 r = sd_bus_message_open_container(m, 'v', argv[5]);
1625 if (r < 0)
1626 return bus_log_create_error(r);
1627
1628 p = argv+6;
1629 r = message_append_cmdline(m, argv[5], &p);
1630 if (r < 0)
1631 return r;
1632
1633 r = sd_bus_message_close_container(m);
1634 if (r < 0)
1635 return bus_log_create_error(r);
1636
1637 if (*p) {
1638 log_error("Too many parameters for signature.");
1639 return -EINVAL;
1640 }
1641
1642 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1643 if (r < 0) {
1644 log_error("%s", bus_error_message(&error, r));
1645 return r;
1646 }
1647
1648 return 0;
1649 }
1650
1651 static int help(void) {
1652 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1653 "Introspect the bus.\n\n"
1654 " -h --help Show this help\n"
1655 " --version Show package version\n"
1656 " --no-pager Do not pipe output into a pager\n"
1657 " --no-legend Do not show the headers and footers\n"
1658 " --system Connect to system bus\n"
1659 " --user Connect to user bus\n"
1660 " -H --host=[USER@]HOST Operate on remote host\n"
1661 " -M --machine=CONTAINER Operate on local container\n"
1662 " --address=ADDRESS Connect to bus specified by address\n"
1663 " --show-machine Show machine ID column in list\n"
1664 " --unique Only show unique names\n"
1665 " --acquired Only show acquired names\n"
1666 " --activatable Only show activatable names\n"
1667 " --match=MATCH Only show matching messages\n"
1668 " --list Don't show tree, but simple object path list\n"
1669 " --quiet Don't show method call reply\n"
1670 " --verbose Show result values in long format\n"
1671 " --expect-reply=BOOL Expect a method call reply\n"
1672 " --auto-start=BOOL Auto-start destination service\n"
1673 " --allow-interactive-authorization=BOOL\n"
1674 " Allow interactive authorization for operation\n"
1675 " --timeout=SECS Maximum time to wait for method call completion\n"
1676 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1677 "Commands:\n"
1678 " list List bus names\n"
1679 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1680 " monitor [SERVICE...] Show bus traffic\n"
1681 " capture [SERVICE...] Capture bus traffic as pcap\n"
1682 " tree [SERVICE...] Show object tree of service\n"
1683 " introspect SERVICE OBJECT\n"
1684 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1685 " Call a method\n"
1686 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1687 " Get property value\n"
1688 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1689 " Set property value\n"
1690 " help Show this help\n"
1691 , program_invocation_short_name);
1692
1693 return 0;
1694 }
1695
1696 static int parse_argv(int argc, char *argv[]) {
1697
1698 enum {
1699 ARG_VERSION = 0x100,
1700 ARG_NO_PAGER,
1701 ARG_NO_LEGEND,
1702 ARG_SYSTEM,
1703 ARG_USER,
1704 ARG_ADDRESS,
1705 ARG_MATCH,
1706 ARG_SHOW_MACHINE,
1707 ARG_UNIQUE,
1708 ARG_ACQUIRED,
1709 ARG_ACTIVATABLE,
1710 ARG_SIZE,
1711 ARG_LIST,
1712 ARG_VERBOSE,
1713 ARG_EXPECT_REPLY,
1714 ARG_AUTO_START,
1715 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1716 ARG_TIMEOUT,
1717 ARG_AUGMENT_CREDS,
1718 };
1719
1720 static const struct option options[] = {
1721 { "help", no_argument, NULL, 'h' },
1722 { "version", no_argument, NULL, ARG_VERSION },
1723 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1724 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1725 { "system", no_argument, NULL, ARG_SYSTEM },
1726 { "user", no_argument, NULL, ARG_USER },
1727 { "address", required_argument, NULL, ARG_ADDRESS },
1728 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1729 { "unique", no_argument, NULL, ARG_UNIQUE },
1730 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1731 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1732 { "match", required_argument, NULL, ARG_MATCH },
1733 { "host", required_argument, NULL, 'H' },
1734 { "machine", required_argument, NULL, 'M' },
1735 { "size", required_argument, NULL, ARG_SIZE },
1736 { "list", no_argument, NULL, ARG_LIST },
1737 { "quiet", no_argument, NULL, 'q' },
1738 { "verbose", no_argument, NULL, ARG_VERBOSE },
1739 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1740 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1741 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1742 { "timeout", required_argument, NULL, ARG_TIMEOUT },
1743 { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
1744 {},
1745 };
1746
1747 int c, r;
1748
1749 assert(argc >= 0);
1750 assert(argv);
1751
1752 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1753
1754 switch (c) {
1755
1756 case 'h':
1757 return help();
1758
1759 case ARG_VERSION:
1760 puts(PACKAGE_STRING);
1761 puts(SYSTEMD_FEATURES);
1762 return 0;
1763
1764 case ARG_NO_PAGER:
1765 arg_no_pager = true;
1766 break;
1767
1768 case ARG_NO_LEGEND:
1769 arg_legend = false;
1770 break;
1771
1772 case ARG_USER:
1773 arg_user = true;
1774 break;
1775
1776 case ARG_SYSTEM:
1777 arg_user = false;
1778 break;
1779
1780 case ARG_ADDRESS:
1781 arg_address = optarg;
1782 break;
1783
1784 case ARG_SHOW_MACHINE:
1785 arg_show_machine = true;
1786 break;
1787
1788 case ARG_UNIQUE:
1789 arg_unique = true;
1790 break;
1791
1792 case ARG_ACQUIRED:
1793 arg_acquired = true;
1794 break;
1795
1796 case ARG_ACTIVATABLE:
1797 arg_activatable = true;
1798 break;
1799
1800 case ARG_MATCH:
1801 if (strv_extend(&arg_matches, optarg) < 0)
1802 return log_oom();
1803 break;
1804
1805 case ARG_SIZE: {
1806 off_t o;
1807
1808 r = parse_size(optarg, 0, &o);
1809 if (r < 0) {
1810 log_error("Failed to parse size: %s", optarg);
1811 return r;
1812 }
1813
1814 if ((off_t) (size_t) o != o) {
1815 log_error("Size out of range.");
1816 return -E2BIG;
1817 }
1818
1819 arg_snaplen = (size_t) o;
1820 break;
1821 }
1822
1823 case ARG_LIST:
1824 arg_list = true;
1825 break;
1826
1827 case 'H':
1828 arg_transport = BUS_TRANSPORT_REMOTE;
1829 arg_host = optarg;
1830 break;
1831
1832 case 'M':
1833 arg_transport = BUS_TRANSPORT_CONTAINER;
1834 arg_host = optarg;
1835 break;
1836
1837 case 'q':
1838 arg_quiet = true;
1839 break;
1840
1841 case ARG_VERBOSE:
1842 arg_verbose = true;
1843 break;
1844
1845 case ARG_EXPECT_REPLY:
1846 r = parse_boolean(optarg);
1847 if (r < 0) {
1848 log_error("Failed to parse --expect-reply= parameter.");
1849 return r;
1850 }
1851
1852 arg_expect_reply = !!r;
1853 break;
1854
1855
1856 case ARG_AUTO_START:
1857 r = parse_boolean(optarg);
1858 if (r < 0) {
1859 log_error("Failed to parse --auto-start= parameter.");
1860 return r;
1861 }
1862
1863 arg_auto_start = !!r;
1864 break;
1865
1866
1867 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1868 r = parse_boolean(optarg);
1869 if (r < 0) {
1870 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1871 return r;
1872 }
1873
1874 arg_allow_interactive_authorization = !!r;
1875 break;
1876
1877 case ARG_TIMEOUT:
1878 r = parse_sec(optarg, &arg_timeout);
1879 if (r < 0) {
1880 log_error("Failed to parse --timeout= parameter.");
1881 return r;
1882 }
1883
1884 break;
1885
1886 case ARG_AUGMENT_CREDS:
1887 r = parse_boolean(optarg);
1888 if (r < 0) {
1889 log_error("Failed to parse --augment-creds= parameter.");
1890 return r;
1891 }
1892
1893 arg_augment_creds = !!r;
1894 break;
1895
1896 case '?':
1897 return -EINVAL;
1898
1899 default:
1900 assert_not_reached("Unhandled option");
1901 }
1902
1903 return 1;
1904 }
1905
1906 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1907 assert(bus);
1908
1909 if (optind >= argc ||
1910 streq(argv[optind], "list"))
1911 return list_bus_names(bus, argv + optind);
1912
1913 if (streq(argv[optind], "monitor"))
1914 return monitor(bus, argv + optind, message_dump);
1915
1916 if (streq(argv[optind], "capture"))
1917 return capture(bus, argv + optind);
1918
1919 if (streq(argv[optind], "status"))
1920 return status(bus, argv + optind);
1921
1922 if (streq(argv[optind], "tree"))
1923 return tree(bus, argv + optind);
1924
1925 if (streq(argv[optind], "introspect"))
1926 return introspect(bus, argv + optind);
1927
1928 if (streq(argv[optind], "call"))
1929 return call(bus, argv + optind);
1930
1931 if (streq(argv[optind], "get-property"))
1932 return get_property(bus, argv + optind);
1933
1934 if (streq(argv[optind], "set-property"))
1935 return set_property(bus, argv + optind);
1936
1937 if (streq(argv[optind], "help"))
1938 return help();
1939
1940 log_error("Unknown command '%s'", argv[optind]);
1941 return -EINVAL;
1942 }
1943
1944 int main(int argc, char *argv[]) {
1945 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1946 int r;
1947
1948 log_parse_environment();
1949 log_open();
1950
1951 r = parse_argv(argc, argv);
1952 if (r <= 0)
1953 goto finish;
1954
1955 r = sd_bus_new(&bus);
1956 if (r < 0) {
1957 log_error_errno(r, "Failed to allocate bus: %m");
1958 goto finish;
1959 }
1960
1961 if (streq_ptr(argv[optind], "monitor") ||
1962 streq_ptr(argv[optind], "capture")) {
1963
1964 r = sd_bus_set_monitor(bus, true);
1965 if (r < 0) {
1966 log_error_errno(r, "Failed to set monitor mode: %m");
1967 goto finish;
1968 }
1969
1970 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
1971 if (r < 0) {
1972 log_error_errno(r, "Failed to enable credentials: %m");
1973 goto finish;
1974 }
1975
1976 r = sd_bus_negotiate_timestamp(bus, true);
1977 if (r < 0) {
1978 log_error_errno(r, "Failed to enable timestamps: %m");
1979 goto finish;
1980 }
1981
1982 r = sd_bus_negotiate_fds(bus, true);
1983 if (r < 0) {
1984 log_error_errno(r, "Failed to enable fds: %m");
1985 goto finish;
1986 }
1987 }
1988
1989 if (arg_address)
1990 r = sd_bus_set_address(bus, arg_address);
1991 else {
1992 r = sd_bus_set_bus_client(bus, true);
1993 if (r < 0) {
1994 log_error_errno(r, "Failed to set bus client: %m");
1995 goto finish;
1996 }
1997
1998 switch (arg_transport) {
1999
2000 case BUS_TRANSPORT_LOCAL:
2001 if (arg_user) {
2002 bus->is_user = true;
2003 r = bus_set_address_user(bus);
2004 } else {
2005 bus->is_system = true;
2006 r = bus_set_address_system(bus);
2007 }
2008 break;
2009
2010 case BUS_TRANSPORT_REMOTE:
2011 r = bus_set_address_system_remote(bus, arg_host);
2012 break;
2013
2014 case BUS_TRANSPORT_CONTAINER:
2015 r = bus_set_address_system_container(bus, arg_host);
2016 break;
2017
2018 default:
2019 assert_not_reached("Hmm, unknown transport type.");
2020 }
2021 }
2022 if (r < 0) {
2023 log_error_errno(r, "Failed to set address: %m");
2024 goto finish;
2025 }
2026
2027 r = sd_bus_start(bus);
2028 if (r < 0) {
2029 log_error_errno(r, "Failed to connect to bus: %m");
2030 goto finish;
2031 }
2032
2033 r = busctl_main(bus, argc, argv);
2034
2035 finish:
2036 pager_close();
2037
2038 strv_free(arg_matches);
2039
2040 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2041 }