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