]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/busctl.c
util-lib: split out user/group/uid/gid calls into user-util.[ch]
[thirdparty/systemd.git] / src / libsystemd / sd-bus / busctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <getopt.h>
23
24 #include "sd-bus.h"
25
26 #include "bus-dump.h"
27 #include "bus-internal.h"
28 #include "bus-signature.h"
29 #include "bus-type.h"
30 #include "bus-util.h"
31 #include "busctl-introspect.h"
32 #include "escape.h"
33 #include "fd-util.h"
34 #include "log.h"
35 #include "pager.h"
36 #include "path-util.h"
37 #include "set.h"
38 #include "strv.h"
39 #include "terminal-util.h"
40 #include "user-util.h"
41 #include "util.h"
42
43 static bool arg_no_pager = false;
44 static bool arg_legend = true;
45 static char *arg_address = NULL;
46 static bool arg_unique = false;
47 static bool arg_acquired = false;
48 static bool arg_activatable = false;
49 static bool arg_show_machine = false;
50 static char **arg_matches = NULL;
51 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
52 static char *arg_host = NULL;
53 static bool arg_user = false;
54 static size_t arg_snaplen = 4096;
55 static bool arg_list = false;
56 static bool arg_quiet = false;
57 static bool arg_verbose = false;
58 static bool arg_expect_reply = true;
59 static bool arg_auto_start = true;
60 static bool arg_allow_interactive_authorization = true;
61 static bool arg_augment_creds = true;
62 static usec_t arg_timeout = 0;
63
64 static void pager_open_if_enabled(void) {
65
66 /* Cache result before we open the pager */
67 if (arg_no_pager)
68 return;
69
70 pager_open(false);
71 }
72
73 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
74 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
75
76 static int list_bus_names(sd_bus *bus, char **argv) {
77 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
78 _cleanup_free_ char **merged = NULL;
79 _cleanup_hashmap_free_ Hashmap *names = NULL;
80 char **i;
81 int r;
82 size_t max_i = 0;
83 unsigned n = 0;
84 void *v;
85 char *k;
86 Iterator iterator;
87
88 assert(bus);
89
90 if (!arg_unique && !arg_acquired && !arg_activatable)
91 arg_unique = arg_acquired = arg_activatable = true;
92
93 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
94 if (r < 0)
95 return log_error_errno(r, "Failed to list names: %m");
96
97 pager_open_if_enabled();
98
99 names = hashmap_new(&string_hash_ops);
100 if (!names)
101 return log_oom();
102
103 STRV_FOREACH(i, acquired) {
104 max_i = MAX(max_i, strlen(*i));
105
106 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
107 if (r < 0)
108 return log_error_errno(r, "Failed to add to hashmap: %m");
109 }
110
111 STRV_FOREACH(i, activatable) {
112 max_i = MAX(max_i, strlen(*i));
113
114 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
115 if (r < 0 && r != -EEXIST)
116 return log_error_errno(r, "Failed to add to hashmap: %m");
117 }
118
119 merged = new(char*, hashmap_size(names) + 1);
120 HASHMAP_FOREACH_KEY(v, k, names, iterator)
121 merged[n++] = k;
122
123 merged[n] = NULL;
124 strv_sort(merged);
125
126 if (arg_legend) {
127 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
128 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
129
130 if (arg_show_machine)
131 puts(" MACHINE");
132 else
133 putchar('\n');
134 }
135
136 STRV_FOREACH(i, merged) {
137 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
138 sd_id128_t mid;
139
140 if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
141 /* Activatable */
142
143 printf("%-*s", (int) max_i, *i);
144 printf(" - - - (activatable) - - ");
145 if (arg_show_machine)
146 puts(" -");
147 else
148 putchar('\n');
149 continue;
150
151 }
152
153 if (!arg_unique && (*i)[0] == ':')
154 continue;
155
156 if (!arg_acquired && (*i)[0] != ':')
157 continue;
158
159 printf("%-*s", (int) max_i, *i);
160
161 r = sd_bus_get_name_creds(
162 bus, *i,
163 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
164 SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
165 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
166 SD_BUS_CREDS_DESCRIPTION, &creds);
167 if (r >= 0) {
168 const char *unique, *session, *unit, *cn;
169 pid_t pid;
170 uid_t uid;
171
172 r = sd_bus_creds_get_pid(creds, &pid);
173 if (r >= 0) {
174 const char *comm = NULL;
175
176 sd_bus_creds_get_comm(creds, &comm);
177
178 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
179 } else
180 fputs(" - - ", stdout);
181
182 r = sd_bus_creds_get_euid(creds, &uid);
183 if (r >= 0) {
184 _cleanup_free_ char *u = NULL;
185
186 u = uid_to_name(uid);
187 if (!u)
188 return log_oom();
189
190 if (strlen(u) > 16)
191 u[16] = 0;
192
193 printf(" %-16s", u);
194 } else
195 fputs(" - ", stdout);
196
197 r = sd_bus_creds_get_unique_name(creds, &unique);
198 if (r >= 0)
199 printf(" %-13s", unique);
200 else
201 fputs(" - ", stdout);
202
203 r = sd_bus_creds_get_unit(creds, &unit);
204 if (r >= 0) {
205 _cleanup_free_ char *e;
206
207 e = ellipsize(unit, 25, 100);
208 if (!e)
209 return log_oom();
210
211 printf(" %-25s", e);
212 } else
213 fputs(" - ", stdout);
214
215 r = sd_bus_creds_get_session(creds, &session);
216 if (r >= 0)
217 printf(" %-10s", session);
218 else
219 fputs(" - ", stdout);
220
221 r = sd_bus_creds_get_description(creds, &cn);
222 if (r >= 0)
223 printf(" %-19s", cn);
224 else
225 fputs(" - ", stdout);
226
227 } else
228 printf(" - - - - - - - ");
229
230 if (arg_show_machine) {
231 r = sd_bus_get_name_machine_id(bus, *i, &mid);
232 if (r >= 0) {
233 char m[SD_ID128_STRING_MAX];
234 printf(" %s\n", sd_id128_to_string(mid, m));
235 } else
236 puts(" -");
237 } else
238 putchar('\n');
239 }
240
241 return 0;
242 }
243
244 static void print_subtree(const char *prefix, const char *path, char **l) {
245 const char *vertical, *space;
246 char **n;
247
248 /* We assume the list is sorted. Let's first skip over the
249 * entry we are looking at. */
250 for (;;) {
251 if (!*l)
252 return;
253
254 if (!streq(*l, path))
255 break;
256
257 l++;
258 }
259
260 vertical = strjoina(prefix, draw_special_char(DRAW_TREE_VERTICAL));
261 space = strjoina(prefix, draw_special_char(DRAW_TREE_SPACE));
262
263 for (;;) {
264 bool has_more = false;
265
266 if (!*l || !path_startswith(*l, path))
267 break;
268
269 n = l + 1;
270 for (;;) {
271 if (!*n || !path_startswith(*n, path))
272 break;
273
274 if (!path_startswith(*n, *l)) {
275 has_more = true;
276 break;
277 }
278
279 n++;
280 }
281
282 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
283
284 print_subtree(has_more ? vertical : space, *l, l);
285 l = n;
286 }
287 }
288
289 static void print_tree(const char *prefix, char **l) {
290
291 pager_open_if_enabled();
292
293 prefix = strempty(prefix);
294
295 if (arg_list) {
296 char **i;
297
298 STRV_FOREACH(i, l)
299 printf("%s%s\n", prefix, *i);
300 return;
301 }
302
303 if (strv_isempty(l)) {
304 printf("No objects discovered.\n");
305 return;
306 }
307
308 if (streq(l[0], "/") && !l[1]) {
309 printf("Only root object discovered.\n");
310 return;
311 }
312
313 print_subtree(prefix, "/", l);
314 }
315
316 static int on_path(const char *path, void *userdata) {
317 Set *paths = userdata;
318 int r;
319
320 assert(paths);
321
322 r = set_put_strdup(paths, path);
323 if (r < 0)
324 return log_oom();
325
326 return 0;
327 }
328
329 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
330 static const XMLIntrospectOps ops = {
331 .on_path = on_path,
332 };
333
334 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
335 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
336 const char *xml;
337 int r;
338
339 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
340 if (r < 0) {
341 if (many)
342 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
343 else
344 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
345 return r;
346 }
347
348 r = sd_bus_message_read(reply, "s", &xml);
349 if (r < 0)
350 return bus_log_parse_error(r);
351
352 return parse_xml_introspect(path, xml, &ops, paths);
353 }
354
355 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
356 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
357 _cleanup_free_ char **l = NULL;
358 char *m;
359 int r;
360
361 paths = set_new(&string_hash_ops);
362 if (!paths)
363 return log_oom();
364
365 done = set_new(&string_hash_ops);
366 if (!done)
367 return log_oom();
368
369 failed = set_new(&string_hash_ops);
370 if (!failed)
371 return log_oom();
372
373 m = strdup("/");
374 if (!m)
375 return log_oom();
376
377 r = set_put(paths, m);
378 if (r < 0) {
379 free(m);
380 return log_oom();
381 }
382
383 for (;;) {
384 _cleanup_free_ char *p = NULL;
385 int q;
386
387 p = set_steal_first(paths);
388 if (!p)
389 break;
390
391 if (set_contains(done, p) ||
392 set_contains(failed, p))
393 continue;
394
395 q = find_nodes(bus, service, p, paths, many);
396 if (q < 0) {
397 if (r >= 0)
398 r = q;
399
400 q = set_put(failed, p);
401 } else
402 q = set_put(done, p);
403
404 if (q < 0)
405 return log_oom();
406
407 assert(q != 0);
408 p = NULL;
409 }
410
411 pager_open_if_enabled();
412
413 l = set_get_strv(done);
414 if (!l)
415 return log_oom();
416
417 strv_sort(l);
418 print_tree(prefix, l);
419
420 fflush(stdout);
421
422 return r;
423 }
424
425 static int tree(sd_bus *bus, char **argv) {
426 char **i;
427 int r = 0;
428
429 if (!arg_unique && !arg_acquired)
430 arg_acquired = true;
431
432 if (strv_length(argv) <= 1) {
433 _cleanup_strv_free_ char **names = NULL;
434 bool not_first = false;
435
436 r = sd_bus_list_names(bus, &names, NULL);
437 if (r < 0)
438 return log_error_errno(r, "Failed to get name list: %m");
439
440 pager_open_if_enabled();
441
442 STRV_FOREACH(i, names) {
443 int q;
444
445 if (!arg_unique && (*i)[0] == ':')
446 continue;
447
448 if (!arg_acquired && (*i)[0] == ':')
449 continue;
450
451 if (not_first)
452 printf("\n");
453
454 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
455
456 q = tree_one(bus, *i, NULL, true);
457 if (q < 0 && r >= 0)
458 r = q;
459
460 not_first = true;
461 }
462 } else {
463 STRV_FOREACH(i, argv+1) {
464 int q;
465
466 if (i > argv+1)
467 printf("\n");
468
469 if (argv[2]) {
470 pager_open_if_enabled();
471 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
472 }
473
474 q = tree_one(bus, *i, NULL, !!argv[2]);
475 if (q < 0 && r >= 0)
476 r = q;
477 }
478 }
479
480 return r;
481 }
482
483 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
484 int r;
485
486 for (;;) {
487 const char *contents = NULL;
488 char type;
489 union {
490 uint8_t u8;
491 uint16_t u16;
492 int16_t s16;
493 uint32_t u32;
494 int32_t s32;
495 uint64_t u64;
496 int64_t s64;
497 double d64;
498 const char *string;
499 int i;
500 } basic;
501
502 r = sd_bus_message_peek_type(m, &type, &contents);
503 if (r <= 0)
504 return r;
505
506 if (bus_type_is_container(type) > 0) {
507
508 r = sd_bus_message_enter_container(m, type, contents);
509 if (r < 0)
510 return r;
511
512 if (type == SD_BUS_TYPE_ARRAY) {
513 unsigned n = 0;
514
515 /* count array entries */
516 for (;;) {
517
518 r = sd_bus_message_skip(m, contents);
519 if (r < 0)
520 return r;
521 if (r == 0)
522 break;
523
524 n++;
525 }
526
527 r = sd_bus_message_rewind(m, false);
528 if (r < 0)
529 return r;
530
531 if (needs_space)
532 fputc(' ', f);
533
534 fprintf(f, "%u", n);
535 } else if (type == SD_BUS_TYPE_VARIANT) {
536
537 if (needs_space)
538 fputc(' ', f);
539
540 fprintf(f, "%s", contents);
541 }
542
543 r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT));
544 if (r < 0)
545 return r;
546
547 r = sd_bus_message_exit_container(m);
548 if (r < 0)
549 return r;
550
551 continue;
552 }
553
554 r = sd_bus_message_read_basic(m, type, &basic);
555 if (r < 0)
556 return r;
557
558 if (needs_space)
559 fputc(' ', f);
560
561 switch (type) {
562 case SD_BUS_TYPE_BYTE:
563 fprintf(f, "%u", basic.u8);
564 break;
565
566 case SD_BUS_TYPE_BOOLEAN:
567 fputs(true_false(basic.i), f);
568 break;
569
570 case SD_BUS_TYPE_INT16:
571 fprintf(f, "%i", basic.s16);
572 break;
573
574 case SD_BUS_TYPE_UINT16:
575 fprintf(f, "%u", basic.u16);
576 break;
577
578 case SD_BUS_TYPE_INT32:
579 fprintf(f, "%i", basic.s32);
580 break;
581
582 case SD_BUS_TYPE_UINT32:
583 fprintf(f, "%u", basic.u32);
584 break;
585
586 case SD_BUS_TYPE_INT64:
587 fprintf(f, "%" PRIi64, basic.s64);
588 break;
589
590 case SD_BUS_TYPE_UINT64:
591 fprintf(f, "%" PRIu64, basic.u64);
592 break;
593
594 case SD_BUS_TYPE_DOUBLE:
595 fprintf(f, "%g", basic.d64);
596 break;
597
598 case SD_BUS_TYPE_STRING:
599 case SD_BUS_TYPE_OBJECT_PATH:
600 case SD_BUS_TYPE_SIGNATURE: {
601 _cleanup_free_ char *b = NULL;
602
603 b = cescape(basic.string);
604 if (!b)
605 return -ENOMEM;
606
607 fprintf(f, "\"%s\"", b);
608 break;
609 }
610
611 case SD_BUS_TYPE_UNIX_FD:
612 fprintf(f, "%i", basic.i);
613 break;
614
615 default:
616 assert_not_reached("Unknown basic type.");
617 }
618
619 needs_space = true;
620 }
621 }
622
623 typedef struct Member {
624 const char *type;
625 char *interface;
626 char *name;
627 char *signature;
628 char *result;
629 char *value;
630 bool writable;
631 uint64_t flags;
632 } Member;
633
634 static void member_hash_func(const void *p, struct siphash *state) {
635 const Member *m = p;
636 uint64_t arity = 1;
637
638 assert(m);
639 assert(m->type);
640
641 string_hash_func(m->type, state);
642
643 arity += !!m->name + !!m->interface;
644
645 uint64_hash_func(&arity, state);
646
647 if (m->name)
648 string_hash_func(m->name, state);
649
650 if (m->interface)
651 string_hash_func(m->interface, state);
652 }
653
654 static int member_compare_func(const void *a, const void *b) {
655 const Member *x = a, *y = b;
656 int d;
657
658 assert(x);
659 assert(y);
660 assert(x->type);
661 assert(y->type);
662
663 d = strcmp_ptr(x->interface, y->interface);
664 if (d != 0)
665 return d;
666
667 d = strcmp(x->type, y->type);
668 if (d != 0)
669 return d;
670
671 return strcmp_ptr(x->name, y->name);
672 }
673
674 static int member_compare_funcp(const void *a, const void *b) {
675 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
676
677 return member_compare_func(*x, *y);
678 }
679
680 static void member_free(Member *m) {
681 if (!m)
682 return;
683
684 free(m->interface);
685 free(m->name);
686 free(m->signature);
687 free(m->result);
688 free(m->value);
689 free(m);
690 }
691
692 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
693
694 static void member_set_free(Set *s) {
695 Member *m;
696
697 while ((m = set_steal_first(s)))
698 member_free(m);
699
700 set_free(s);
701 }
702
703 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
704
705 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
706 _cleanup_(member_freep) Member *m;
707 Set *members = userdata;
708 int r;
709
710 assert(interface);
711 assert(members);
712
713 m = new0(Member, 1);
714 if (!m)
715 return log_oom();
716
717 m->type = "interface";
718 m->flags = flags;
719
720 r = free_and_strdup(&m->interface, interface);
721 if (r < 0)
722 return log_oom();
723
724 r = set_put(members, m);
725 if (r <= 0) {
726 log_error("Duplicate interface");
727 return -EINVAL;
728 }
729
730 m = NULL;
731 return 0;
732 }
733
734 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
735 _cleanup_(member_freep) Member *m;
736 Set *members = userdata;
737 int r;
738
739 assert(interface);
740 assert(name);
741
742 m = new0(Member, 1);
743 if (!m)
744 return log_oom();
745
746 m->type = "method";
747 m->flags = flags;
748
749 r = free_and_strdup(&m->interface, interface);
750 if (r < 0)
751 return log_oom();
752
753 r = free_and_strdup(&m->name, name);
754 if (r < 0)
755 return log_oom();
756
757 r = free_and_strdup(&m->signature, signature);
758 if (r < 0)
759 return log_oom();
760
761 r = free_and_strdup(&m->result, result);
762 if (r < 0)
763 return log_oom();
764
765 r = set_put(members, m);
766 if (r <= 0) {
767 log_error("Duplicate method");
768 return -EINVAL;
769 }
770
771 m = NULL;
772 return 0;
773 }
774
775 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
776 _cleanup_(member_freep) Member *m;
777 Set *members = userdata;
778 int r;
779
780 assert(interface);
781 assert(name);
782
783 m = new0(Member, 1);
784 if (!m)
785 return log_oom();
786
787 m->type = "signal";
788 m->flags = flags;
789
790 r = free_and_strdup(&m->interface, interface);
791 if (r < 0)
792 return log_oom();
793
794 r = free_and_strdup(&m->name, name);
795 if (r < 0)
796 return log_oom();
797
798 r = free_and_strdup(&m->signature, signature);
799 if (r < 0)
800 return log_oom();
801
802 r = set_put(members, m);
803 if (r <= 0) {
804 log_error("Duplicate signal");
805 return -EINVAL;
806 }
807
808 m = NULL;
809 return 0;
810 }
811
812 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
813 _cleanup_(member_freep) Member *m;
814 Set *members = userdata;
815 int r;
816
817 assert(interface);
818 assert(name);
819
820 m = new0(Member, 1);
821 if (!m)
822 return log_oom();
823
824 m->type = "property";
825 m->flags = flags;
826 m->writable = writable;
827
828 r = free_and_strdup(&m->interface, interface);
829 if (r < 0)
830 return log_oom();
831
832 r = free_and_strdup(&m->name, name);
833 if (r < 0)
834 return log_oom();
835
836 r = free_and_strdup(&m->signature, signature);
837 if (r < 0)
838 return log_oom();
839
840 r = set_put(members, m);
841 if (r <= 0) {
842 log_error("Duplicate property");
843 return -EINVAL;
844 }
845
846 m = NULL;
847 return 0;
848 }
849
850 static const char *strdash(const char *x) {
851 return isempty(x) ? "-" : x;
852 }
853
854 static int introspect(sd_bus *bus, char **argv) {
855 static const struct hash_ops member_hash_ops = {
856 .hash = member_hash_func,
857 .compare = member_compare_func,
858 };
859
860 static const XMLIntrospectOps ops = {
861 .on_interface = on_interface,
862 .on_method = on_method,
863 .on_signal = on_signal,
864 .on_property = on_property,
865 };
866
867 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
868 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
869 _cleanup_(member_set_freep) Set *members = NULL;
870 Iterator i;
871 Member *m;
872 const char *xml;
873 int r;
874 unsigned name_width, type_width, signature_width, result_width;
875 Member **sorted = NULL;
876 unsigned k = 0, j, n_args;
877
878 n_args = strv_length(argv);
879 if (n_args < 3) {
880 log_error("Requires service and object path argument.");
881 return -EINVAL;
882 }
883
884 if (n_args > 4) {
885 log_error("Too many arguments.");
886 return -EINVAL;
887 }
888
889 members = set_new(&member_hash_ops);
890 if (!members)
891 return log_oom();
892
893 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
894 if (r < 0) {
895 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
896 return r;
897 }
898
899 r = sd_bus_message_read(reply, "s", &xml);
900 if (r < 0)
901 return bus_log_parse_error(r);
902
903 /* First, get list of all properties */
904 r = parse_xml_introspect(argv[2], xml, &ops, members);
905 if (r < 0)
906 return r;
907
908 /* Second, find the current values for them */
909 SET_FOREACH(m, members, i) {
910
911 if (!streq(m->type, "property"))
912 continue;
913
914 if (m->value)
915 continue;
916
917 if (argv[3] && !streq(argv[3], m->interface))
918 continue;
919
920 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
921 if (r < 0) {
922 log_error("%s", bus_error_message(&error, r));
923 return r;
924 }
925
926 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
927 if (r < 0)
928 return bus_log_parse_error(r);
929
930 for (;;) {
931 Member *z;
932 _cleanup_free_ char *buf = NULL;
933 _cleanup_fclose_ FILE *mf = NULL;
934 size_t sz = 0;
935 const char *name;
936
937 r = sd_bus_message_enter_container(reply, 'e', "sv");
938 if (r < 0)
939 return bus_log_parse_error(r);
940
941 if (r == 0)
942 break;
943
944 r = sd_bus_message_read(reply, "s", &name);
945 if (r < 0)
946 return bus_log_parse_error(r);
947
948 r = sd_bus_message_enter_container(reply, 'v', NULL);
949 if (r < 0)
950 return bus_log_parse_error(r);
951
952 mf = open_memstream(&buf, &sz);
953 if (!mf)
954 return log_oom();
955
956 r = format_cmdline(reply, mf, false);
957 if (r < 0)
958 return bus_log_parse_error(r);
959
960 fclose(mf);
961 mf = NULL;
962
963 z = set_get(members, &((Member) {
964 .type = "property",
965 .interface = m->interface,
966 .name = (char*) name }));
967 if (z) {
968 free(z->value);
969 z->value = buf;
970 buf = NULL;
971 }
972
973 r = sd_bus_message_exit_container(reply);
974 if (r < 0)
975 return bus_log_parse_error(r);
976
977 r = sd_bus_message_exit_container(reply);
978 if (r < 0)
979 return bus_log_parse_error(r);
980 }
981
982 r = sd_bus_message_exit_container(reply);
983 if (r < 0)
984 return bus_log_parse_error(r);
985 }
986
987 pager_open_if_enabled();
988
989 name_width = strlen("NAME");
990 type_width = strlen("TYPE");
991 signature_width = strlen("SIGNATURE");
992 result_width = strlen("RESULT/VALUE");
993
994 sorted = newa(Member*, set_size(members));
995
996 SET_FOREACH(m, members, i) {
997
998 if (argv[3] && !streq(argv[3], m->interface))
999 continue;
1000
1001 if (m->interface)
1002 name_width = MAX(name_width, strlen(m->interface));
1003 if (m->name)
1004 name_width = MAX(name_width, strlen(m->name) + 1);
1005 if (m->type)
1006 type_width = MAX(type_width, strlen(m->type));
1007 if (m->signature)
1008 signature_width = MAX(signature_width, strlen(m->signature));
1009 if (m->result)
1010 result_width = MAX(result_width, strlen(m->result));
1011 if (m->value)
1012 result_width = MAX(result_width, strlen(m->value));
1013
1014 sorted[k++] = m;
1015 }
1016
1017 if (result_width > 40)
1018 result_width = 40;
1019
1020 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1021
1022 if (arg_legend) {
1023 printf("%-*s %-*s %-*s %-*s %s\n",
1024 (int) name_width, "NAME",
1025 (int) type_width, "TYPE",
1026 (int) signature_width, "SIGNATURE",
1027 (int) result_width, "RESULT/VALUE",
1028 "FLAGS");
1029 }
1030
1031 for (j = 0; j < k; j++) {
1032 _cleanup_free_ char *ellipsized = NULL;
1033 const char *rv;
1034 bool is_interface;
1035
1036 m = sorted[j];
1037
1038 if (argv[3] && !streq(argv[3], m->interface))
1039 continue;
1040
1041 is_interface = streq(m->type, "interface");
1042
1043 if (argv[3] && is_interface)
1044 continue;
1045
1046 if (m->value) {
1047 ellipsized = ellipsize(m->value, result_width, 100);
1048 if (!ellipsized)
1049 return log_oom();
1050
1051 rv = ellipsized;
1052 } else
1053 rv = strdash(m->result);
1054
1055 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1056 is_interface ? ansi_highlight() : "",
1057 is_interface ? "" : ".",
1058 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1059 is_interface ? ansi_normal() : "",
1060 (int) type_width, strdash(m->type),
1061 (int) signature_width, strdash(m->signature),
1062 (int) result_width, rv,
1063 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1064 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1065 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1066 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1067 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1068 m->writable ? " writable" : "");
1069 }
1070
1071 return 0;
1072 }
1073
1074 static int message_dump(sd_bus_message *m, FILE *f) {
1075 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1076 }
1077
1078 static int message_pcap(sd_bus_message *m, FILE *f) {
1079 return bus_message_pcap_frame(m, arg_snaplen, f);
1080 }
1081
1082 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1083 bool added_something = false;
1084 char **i;
1085 int r;
1086
1087 STRV_FOREACH(i, argv+1) {
1088 _cleanup_free_ char *m = NULL;
1089
1090 if (!service_name_is_valid(*i)) {
1091 log_error("Invalid service name '%s'", *i);
1092 return -EINVAL;
1093 }
1094
1095 m = strjoin("sender='", *i, "'", NULL);
1096 if (!m)
1097 return log_oom();
1098
1099 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1100 if (r < 0)
1101 return log_error_errno(r, "Failed to add match: %m");
1102
1103 free(m);
1104 m = strjoin("destination='", *i, "'", NULL);
1105 if (!m)
1106 return log_oom();
1107
1108 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1109 if (r < 0)
1110 return log_error_errno(r, "Failed to add match: %m");
1111
1112 added_something = true;
1113 }
1114
1115 STRV_FOREACH(i, arg_matches) {
1116 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1117 if (r < 0)
1118 return log_error_errno(r, "Failed to add match: %m");
1119
1120 added_something = true;
1121 }
1122
1123 if (!added_something) {
1124 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1125 if (r < 0)
1126 return log_error_errno(r, "Failed to add match: %m");
1127 }
1128
1129 log_info("Monitoring bus message stream.");
1130
1131 for (;;) {
1132 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1133
1134 r = sd_bus_process(bus, &m);
1135 if (r < 0)
1136 return log_error_errno(r, "Failed to process bus: %m");
1137
1138 if (m) {
1139 dump(m, stdout);
1140 fflush(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_normal());
1213
1214 r = sd_bus_get_scope(bus, &scope);
1215 if (r >= 0)
1216 printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal());
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_normal());
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 " --size=SIZE Maximum length of captured packet\n"
1701 " --list Don't show tree, but simple object path list\n"
1702 " --quiet Don't show method call reply\n"
1703 " --verbose Show result values in long format\n"
1704 " --expect-reply=BOOL Expect a method call reply\n"
1705 " --auto-start=BOOL Auto-start destination service\n"
1706 " --allow-interactive-authorization=BOOL\n"
1707 " Allow interactive authorization for operation\n"
1708 " --timeout=SECS Maximum time to wait for method call completion\n"
1709 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1710 "Commands:\n"
1711 " list List bus names\n"
1712 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1713 " monitor [SERVICE...] Show bus traffic\n"
1714 " capture [SERVICE...] Capture bus traffic as pcap\n"
1715 " tree [SERVICE...] Show object tree of service\n"
1716 " introspect SERVICE OBJECT [INTERFACE]\n"
1717 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1718 " Call a method\n"
1719 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1720 " Get property value\n"
1721 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1722 " Set property value\n"
1723 " help Show this help\n"
1724 , program_invocation_short_name);
1725
1726 return 0;
1727 }
1728
1729 static int parse_argv(int argc, char *argv[]) {
1730
1731 enum {
1732 ARG_VERSION = 0x100,
1733 ARG_NO_PAGER,
1734 ARG_NO_LEGEND,
1735 ARG_SYSTEM,
1736 ARG_USER,
1737 ARG_ADDRESS,
1738 ARG_MATCH,
1739 ARG_SHOW_MACHINE,
1740 ARG_UNIQUE,
1741 ARG_ACQUIRED,
1742 ARG_ACTIVATABLE,
1743 ARG_SIZE,
1744 ARG_LIST,
1745 ARG_VERBOSE,
1746 ARG_EXPECT_REPLY,
1747 ARG_AUTO_START,
1748 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1749 ARG_TIMEOUT,
1750 ARG_AUGMENT_CREDS,
1751 };
1752
1753 static const struct option options[] = {
1754 { "help", no_argument, NULL, 'h' },
1755 { "version", no_argument, NULL, ARG_VERSION },
1756 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1757 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1758 { "system", no_argument, NULL, ARG_SYSTEM },
1759 { "user", no_argument, NULL, ARG_USER },
1760 { "address", required_argument, NULL, ARG_ADDRESS },
1761 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1762 { "unique", no_argument, NULL, ARG_UNIQUE },
1763 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1764 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1765 { "match", required_argument, NULL, ARG_MATCH },
1766 { "host", required_argument, NULL, 'H' },
1767 { "machine", required_argument, NULL, 'M' },
1768 { "size", required_argument, NULL, ARG_SIZE },
1769 { "list", no_argument, NULL, ARG_LIST },
1770 { "quiet", no_argument, NULL, 'q' },
1771 { "verbose", no_argument, NULL, ARG_VERBOSE },
1772 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1773 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1774 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1775 { "timeout", required_argument, NULL, ARG_TIMEOUT },
1776 { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
1777 {},
1778 };
1779
1780 int c, r;
1781
1782 assert(argc >= 0);
1783 assert(argv);
1784
1785 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1786
1787 switch (c) {
1788
1789 case 'h':
1790 return help();
1791
1792 case ARG_VERSION:
1793 return version();
1794
1795 case ARG_NO_PAGER:
1796 arg_no_pager = true;
1797 break;
1798
1799 case ARG_NO_LEGEND:
1800 arg_legend = false;
1801 break;
1802
1803 case ARG_USER:
1804 arg_user = true;
1805 break;
1806
1807 case ARG_SYSTEM:
1808 arg_user = false;
1809 break;
1810
1811 case ARG_ADDRESS:
1812 arg_address = optarg;
1813 break;
1814
1815 case ARG_SHOW_MACHINE:
1816 arg_show_machine = true;
1817 break;
1818
1819 case ARG_UNIQUE:
1820 arg_unique = true;
1821 break;
1822
1823 case ARG_ACQUIRED:
1824 arg_acquired = true;
1825 break;
1826
1827 case ARG_ACTIVATABLE:
1828 arg_activatable = true;
1829 break;
1830
1831 case ARG_MATCH:
1832 if (strv_extend(&arg_matches, optarg) < 0)
1833 return log_oom();
1834 break;
1835
1836 case ARG_SIZE: {
1837 uint64_t sz;
1838
1839 r = parse_size(optarg, 1024, &sz);
1840 if (r < 0) {
1841 log_error("Failed to parse size: %s", optarg);
1842 return r;
1843 }
1844
1845 if ((uint64_t) (size_t) sz != sz) {
1846 log_error("Size out of range.");
1847 return -E2BIG;
1848 }
1849
1850 arg_snaplen = (size_t) sz;
1851 break;
1852 }
1853
1854 case ARG_LIST:
1855 arg_list = true;
1856 break;
1857
1858 case 'H':
1859 arg_transport = BUS_TRANSPORT_REMOTE;
1860 arg_host = optarg;
1861 break;
1862
1863 case 'M':
1864 arg_transport = BUS_TRANSPORT_MACHINE;
1865 arg_host = optarg;
1866 break;
1867
1868 case 'q':
1869 arg_quiet = true;
1870 break;
1871
1872 case ARG_VERBOSE:
1873 arg_verbose = true;
1874 break;
1875
1876 case ARG_EXPECT_REPLY:
1877 r = parse_boolean(optarg);
1878 if (r < 0) {
1879 log_error("Failed to parse --expect-reply= parameter.");
1880 return r;
1881 }
1882
1883 arg_expect_reply = !!r;
1884 break;
1885
1886
1887 case ARG_AUTO_START:
1888 r = parse_boolean(optarg);
1889 if (r < 0) {
1890 log_error("Failed to parse --auto-start= parameter.");
1891 return r;
1892 }
1893
1894 arg_auto_start = !!r;
1895 break;
1896
1897
1898 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1899 r = parse_boolean(optarg);
1900 if (r < 0) {
1901 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1902 return r;
1903 }
1904
1905 arg_allow_interactive_authorization = !!r;
1906 break;
1907
1908 case ARG_TIMEOUT:
1909 r = parse_sec(optarg, &arg_timeout);
1910 if (r < 0) {
1911 log_error("Failed to parse --timeout= parameter.");
1912 return r;
1913 }
1914
1915 break;
1916
1917 case ARG_AUGMENT_CREDS:
1918 r = parse_boolean(optarg);
1919 if (r < 0) {
1920 log_error("Failed to parse --augment-creds= parameter.");
1921 return r;
1922 }
1923
1924 arg_augment_creds = !!r;
1925 break;
1926
1927 case '?':
1928 return -EINVAL;
1929
1930 default:
1931 assert_not_reached("Unhandled option");
1932 }
1933
1934 return 1;
1935 }
1936
1937 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1938 assert(bus);
1939
1940 if (optind >= argc ||
1941 streq(argv[optind], "list"))
1942 return list_bus_names(bus, argv + optind);
1943
1944 if (streq(argv[optind], "monitor"))
1945 return monitor(bus, argv + optind, message_dump);
1946
1947 if (streq(argv[optind], "capture"))
1948 return capture(bus, argv + optind);
1949
1950 if (streq(argv[optind], "status"))
1951 return status(bus, argv + optind);
1952
1953 if (streq(argv[optind], "tree"))
1954 return tree(bus, argv + optind);
1955
1956 if (streq(argv[optind], "introspect"))
1957 return introspect(bus, argv + optind);
1958
1959 if (streq(argv[optind], "call"))
1960 return call(bus, argv + optind);
1961
1962 if (streq(argv[optind], "get-property"))
1963 return get_property(bus, argv + optind);
1964
1965 if (streq(argv[optind], "set-property"))
1966 return set_property(bus, argv + optind);
1967
1968 if (streq(argv[optind], "help"))
1969 return help();
1970
1971 log_error("Unknown command '%s'", argv[optind]);
1972 return -EINVAL;
1973 }
1974
1975 int main(int argc, char *argv[]) {
1976 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
1977 int r;
1978
1979 log_parse_environment();
1980 log_open();
1981
1982 r = parse_argv(argc, argv);
1983 if (r <= 0)
1984 goto finish;
1985
1986 r = sd_bus_new(&bus);
1987 if (r < 0) {
1988 log_error_errno(r, "Failed to allocate bus: %m");
1989 goto finish;
1990 }
1991
1992 if (streq_ptr(argv[optind], "monitor") ||
1993 streq_ptr(argv[optind], "capture")) {
1994
1995 r = sd_bus_set_monitor(bus, true);
1996 if (r < 0) {
1997 log_error_errno(r, "Failed to set monitor mode: %m");
1998 goto finish;
1999 }
2000
2001 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
2002 if (r < 0) {
2003 log_error_errno(r, "Failed to enable credentials: %m");
2004 goto finish;
2005 }
2006
2007 r = sd_bus_negotiate_timestamp(bus, true);
2008 if (r < 0) {
2009 log_error_errno(r, "Failed to enable timestamps: %m");
2010 goto finish;
2011 }
2012
2013 r = sd_bus_negotiate_fds(bus, true);
2014 if (r < 0) {
2015 log_error_errno(r, "Failed to enable fds: %m");
2016 goto finish;
2017 }
2018 }
2019
2020 r = sd_bus_set_bus_client(bus, true);
2021 if (r < 0) {
2022 log_error_errno(r, "Failed to set bus client: %m");
2023 goto finish;
2024 }
2025
2026 if (arg_address)
2027 r = sd_bus_set_address(bus, arg_address);
2028 else {
2029 switch (arg_transport) {
2030
2031 case BUS_TRANSPORT_LOCAL:
2032 if (arg_user) {
2033 bus->is_user = true;
2034 r = bus_set_address_user(bus);
2035 } else {
2036 bus->is_system = true;
2037 r = bus_set_address_system(bus);
2038 }
2039 break;
2040
2041 case BUS_TRANSPORT_REMOTE:
2042 r = bus_set_address_system_remote(bus, arg_host);
2043 break;
2044
2045 case BUS_TRANSPORT_MACHINE:
2046 r = bus_set_address_system_machine(bus, arg_host);
2047 break;
2048
2049 default:
2050 assert_not_reached("Hmm, unknown transport type.");
2051 }
2052 }
2053 if (r < 0) {
2054 log_error_errno(r, "Failed to set address: %m");
2055 goto finish;
2056 }
2057
2058 r = sd_bus_start(bus);
2059 if (r < 0) {
2060 log_error_errno(r, "Failed to connect to bus: %m");
2061 goto finish;
2062 }
2063
2064 r = busctl_main(bus, argc, argv);
2065
2066 finish:
2067 pager_close();
2068
2069 strv_free(arg_matches);
2070
2071 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2072 }