]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/busctl/busctl.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / busctl / busctl.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1+ */
2/***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <getopt.h>
22
23#include "sd-bus.h"
24
25#include "alloc-util.h"
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 "locale-util.h"
35#include "log.h"
36#include "pager.h"
37#include "parse-util.h"
38#include "path-util.h"
39#include "set.h"
40#include "strv.h"
41#include "terminal-util.h"
42#include "user-util.h"
43#include "util.h"
44
45static bool arg_no_pager = false;
46static bool arg_legend = true;
47static char *arg_address = NULL;
48static bool arg_unique = false;
49static bool arg_acquired = false;
50static bool arg_activatable = false;
51static bool arg_show_machine = false;
52static char **arg_matches = NULL;
53static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
54static char *arg_host = NULL;
55static bool arg_user = false;
56static size_t arg_snaplen = 4096;
57static bool arg_list = false;
58static bool arg_quiet = false;
59static bool arg_verbose = false;
60static bool arg_expect_reply = true;
61static bool arg_auto_start = true;
62static bool arg_allow_interactive_authorization = true;
63static bool arg_augment_creds = true;
64static usec_t arg_timeout = 0;
65
66#define NAME_IS_ACQUIRED INT_TO_PTR(1)
67#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
68
69static int list_bus_names(sd_bus *bus, char **argv) {
70 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
71 _cleanup_free_ char **merged = NULL;
72 _cleanup_hashmap_free_ Hashmap *names = NULL;
73 char **i;
74 int r;
75 size_t max_i = 0;
76 unsigned n = 0;
77 void *v;
78 char *k;
79 Iterator iterator;
80
81 assert(bus);
82
83 if (!arg_unique && !arg_acquired && !arg_activatable)
84 arg_unique = arg_acquired = arg_activatable = true;
85
86 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
87 if (r < 0)
88 return log_error_errno(r, "Failed to list names: %m");
89
90 pager_open(arg_no_pager, false);
91
92 names = hashmap_new(&string_hash_ops);
93 if (!names)
94 return log_oom();
95
96 STRV_FOREACH(i, acquired) {
97 max_i = MAX(max_i, strlen(*i));
98
99 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
100 if (r < 0)
101 return log_error_errno(r, "Failed to add to hashmap: %m");
102 }
103
104 STRV_FOREACH(i, activatable) {
105 max_i = MAX(max_i, strlen(*i));
106
107 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
108 if (r < 0 && r != -EEXIST)
109 return log_error_errno(r, "Failed to add to hashmap: %m");
110 }
111
112 merged = new(char*, hashmap_size(names) + 1);
113 HASHMAP_FOREACH_KEY(v, k, names, iterator)
114 merged[n++] = k;
115
116 merged[n] = NULL;
117 strv_sort(merged);
118
119 if (arg_legend) {
120 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
121 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
122
123 if (arg_show_machine)
124 puts(" MACHINE");
125 else
126 putchar('\n');
127 }
128
129 STRV_FOREACH(i, merged) {
130 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
131 sd_id128_t mid;
132
133 if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
134 /* Activatable */
135
136 printf("%-*s", (int) max_i, *i);
137 printf(" - - - (activatable) - - ");
138 if (arg_show_machine)
139 puts(" -");
140 else
141 putchar('\n');
142 continue;
143
144 }
145
146 if (!arg_unique && (*i)[0] == ':')
147 continue;
148
149 if (!arg_acquired && (*i)[0] != ':')
150 continue;
151
152 printf("%-*s", (int) max_i, *i);
153
154 r = sd_bus_get_name_creds(
155 bus, *i,
156 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
157 SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
158 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
159 SD_BUS_CREDS_DESCRIPTION, &creds);
160 if (r >= 0) {
161 const char *unique, *session, *unit, *cn;
162 pid_t pid;
163 uid_t uid;
164
165 r = sd_bus_creds_get_pid(creds, &pid);
166 if (r >= 0) {
167 const char *comm = NULL;
168
169 sd_bus_creds_get_comm(creds, &comm);
170
171 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
172 } else
173 fputs(" - - ", stdout);
174
175 r = sd_bus_creds_get_euid(creds, &uid);
176 if (r >= 0) {
177 _cleanup_free_ char *u = NULL;
178
179 u = uid_to_name(uid);
180 if (!u)
181 return log_oom();
182
183 if (strlen(u) > 16)
184 u[16] = 0;
185
186 printf(" %-16s", u);
187 } else
188 fputs(" - ", stdout);
189
190 r = sd_bus_creds_get_unique_name(creds, &unique);
191 if (r >= 0)
192 printf(" %-13s", unique);
193 else
194 fputs(" - ", stdout);
195
196 r = sd_bus_creds_get_unit(creds, &unit);
197 if (r >= 0) {
198 _cleanup_free_ char *e;
199
200 e = ellipsize(unit, 25, 100);
201 if (!e)
202 return log_oom();
203
204 printf(" %-25s", e);
205 } else
206 fputs(" - ", stdout);
207
208 r = sd_bus_creds_get_session(creds, &session);
209 if (r >= 0)
210 printf(" %-10s", session);
211 else
212 fputs(" - ", stdout);
213
214 r = sd_bus_creds_get_description(creds, &cn);
215 if (r >= 0)
216 printf(" %-19s", cn);
217 else
218 fputs(" - ", stdout);
219
220 } else
221 printf(" - - - - - - - ");
222
223 if (arg_show_machine) {
224 r = sd_bus_get_name_machine_id(bus, *i, &mid);
225 if (r >= 0) {
226 char m[SD_ID128_STRING_MAX];
227 printf(" %s\n", sd_id128_to_string(mid, m));
228 } else
229 puts(" -");
230 } else
231 putchar('\n');
232 }
233
234 return 0;
235}
236
237static void print_subtree(const char *prefix, const char *path, char **l) {
238 const char *vertical, *space;
239 char **n;
240
241 /* We assume the list is sorted. Let's first skip over the
242 * entry we are looking at. */
243 for (;;) {
244 if (!*l)
245 return;
246
247 if (!streq(*l, path))
248 break;
249
250 l++;
251 }
252
253 vertical = strjoina(prefix, special_glyph(TREE_VERTICAL));
254 space = strjoina(prefix, special_glyph(TREE_SPACE));
255
256 for (;;) {
257 bool has_more = false;
258
259 if (!*l || !path_startswith(*l, path))
260 break;
261
262 n = l + 1;
263 for (;;) {
264 if (!*n || !path_startswith(*n, path))
265 break;
266
267 if (!path_startswith(*n, *l)) {
268 has_more = true;
269 break;
270 }
271
272 n++;
273 }
274
275 printf("%s%s%s\n", prefix, special_glyph(has_more ? TREE_BRANCH : TREE_RIGHT), *l);
276
277 print_subtree(has_more ? vertical : space, *l, l);
278 l = n;
279 }
280}
281
282static void print_tree(const char *prefix, char **l) {
283
284 pager_open(arg_no_pager, false);
285
286 prefix = strempty(prefix);
287
288 if (arg_list) {
289 char **i;
290
291 STRV_FOREACH(i, l)
292 printf("%s%s\n", prefix, *i);
293 return;
294 }
295
296 if (strv_isempty(l)) {
297 printf("No objects discovered.\n");
298 return;
299 }
300
301 if (streq(l[0], "/") && !l[1]) {
302 printf("Only root object discovered.\n");
303 return;
304 }
305
306 print_subtree(prefix, "/", l);
307}
308
309static int on_path(const char *path, void *userdata) {
310 Set *paths = userdata;
311 int r;
312
313 assert(paths);
314
315 r = set_put_strdup(paths, path);
316 if (r < 0)
317 return log_oom();
318
319 return 0;
320}
321
322static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
323 static const XMLIntrospectOps ops = {
324 .on_path = on_path,
325 };
326
327 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
328 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
329 const char *xml;
330 int r;
331
332 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
333 if (r < 0) {
334 if (many)
335 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
336 else
337 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
338 return r;
339 }
340
341 r = sd_bus_message_read(reply, "s", &xml);
342 if (r < 0)
343 return bus_log_parse_error(r);
344
345 return parse_xml_introspect(path, xml, &ops, paths);
346}
347
348static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
349 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
350 _cleanup_free_ char **l = NULL;
351 char *m;
352 int r;
353
354 paths = set_new(&string_hash_ops);
355 if (!paths)
356 return log_oom();
357
358 done = set_new(&string_hash_ops);
359 if (!done)
360 return log_oom();
361
362 failed = set_new(&string_hash_ops);
363 if (!failed)
364 return log_oom();
365
366 m = strdup("/");
367 if (!m)
368 return log_oom();
369
370 r = set_put(paths, m);
371 if (r < 0) {
372 free(m);
373 return log_oom();
374 }
375
376 for (;;) {
377 _cleanup_free_ char *p = NULL;
378 int q;
379
380 p = set_steal_first(paths);
381 if (!p)
382 break;
383
384 if (set_contains(done, p) ||
385 set_contains(failed, p))
386 continue;
387
388 q = find_nodes(bus, service, p, paths, many);
389 if (q < 0) {
390 if (r >= 0)
391 r = q;
392
393 q = set_put(failed, p);
394 } else
395 q = set_put(done, p);
396
397 if (q < 0)
398 return log_oom();
399
400 assert(q != 0);
401 p = NULL;
402 }
403
404 pager_open(arg_no_pager, false);
405
406 l = set_get_strv(done);
407 if (!l)
408 return log_oom();
409
410 strv_sort(l);
411 print_tree(prefix, l);
412
413 fflush(stdout);
414
415 return r;
416}
417
418static int tree(sd_bus *bus, char **argv) {
419 char **i;
420 int r = 0;
421
422 if (!arg_unique && !arg_acquired)
423 arg_acquired = true;
424
425 if (strv_length(argv) <= 1) {
426 _cleanup_strv_free_ char **names = NULL;
427 bool not_first = false;
428
429 r = sd_bus_list_names(bus, &names, NULL);
430 if (r < 0)
431 return log_error_errno(r, "Failed to get name list: %m");
432
433 pager_open(arg_no_pager, false);
434
435 STRV_FOREACH(i, names) {
436 int q;
437
438 if (!arg_unique && (*i)[0] == ':')
439 continue;
440
441 if (!arg_acquired && (*i)[0] == ':')
442 continue;
443
444 if (not_first)
445 printf("\n");
446
447 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
448
449 q = tree_one(bus, *i, NULL, true);
450 if (q < 0 && r >= 0)
451 r = q;
452
453 not_first = true;
454 }
455 } else {
456 STRV_FOREACH(i, argv+1) {
457 int q;
458
459 if (i > argv+1)
460 printf("\n");
461
462 if (argv[2]) {
463 pager_open(arg_no_pager, false);
464 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
465 }
466
467 q = tree_one(bus, *i, NULL, !!argv[2]);
468 if (q < 0 && r >= 0)
469 r = q;
470 }
471 }
472
473 return r;
474}
475
476static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
477 int r;
478
479 for (;;) {
480 const char *contents = NULL;
481 char type;
482 union {
483 uint8_t u8;
484 uint16_t u16;
485 int16_t s16;
486 uint32_t u32;
487 int32_t s32;
488 uint64_t u64;
489 int64_t s64;
490 double d64;
491 const char *string;
492 int i;
493 } basic;
494
495 r = sd_bus_message_peek_type(m, &type, &contents);
496 if (r < 0)
497 return r;
498 if (r == 0)
499 return needs_space;
500
501 if (bus_type_is_container(type) > 0) {
502
503 r = sd_bus_message_enter_container(m, type, contents);
504 if (r < 0)
505 return r;
506
507 if (type == SD_BUS_TYPE_ARRAY) {
508 unsigned n = 0;
509
510 /* count array entries */
511 for (;;) {
512
513 r = sd_bus_message_skip(m, contents);
514 if (r < 0)
515 return r;
516 if (r == 0)
517 break;
518
519 n++;
520 }
521
522 r = sd_bus_message_rewind(m, false);
523 if (r < 0)
524 return r;
525
526 if (needs_space)
527 fputc(' ', f);
528
529 fprintf(f, "%u", n);
530 needs_space = true;
531
532 } else if (type == SD_BUS_TYPE_VARIANT) {
533
534 if (needs_space)
535 fputc(' ', f);
536
537 fprintf(f, "%s", contents);
538 needs_space = true;
539 }
540
541 r = format_cmdline(m, f, needs_space);
542 if (r < 0)
543 return r;
544
545 needs_space = r > 0;
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
623typedef 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
634static 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
654static 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
674static 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
680static 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
692DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
693
694static 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
703DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
704
705static 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
734static 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
775static 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
812static 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
850static const char *strdash(const char *x) {
851 return isempty(x) ? "-" : x;
852}
853
854static 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_(sd_bus_message_unrefp) sd_bus_message *reply_xml = NULL;
868 _cleanup_(sd_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_xml, "");
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_xml, "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 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
911
912 if (!streq(m->type, "property"))
913 continue;
914
915 if (m->value)
916 continue;
917
918 if (argv[3] && !streq(argv[3], m->interface))
919 continue;
920
921 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
922 if (r < 0) {
923 log_error("%s", bus_error_message(&error, r));
924 return r;
925 }
926
927 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
928 if (r < 0)
929 return bus_log_parse_error(r);
930
931 for (;;) {
932 Member *z;
933 _cleanup_free_ char *buf = NULL;
934 _cleanup_fclose_ FILE *mf = NULL;
935 size_t sz = 0;
936 const char *name;
937
938 r = sd_bus_message_enter_container(reply, 'e', "sv");
939 if (r < 0)
940 return bus_log_parse_error(r);
941
942 if (r == 0)
943 break;
944
945 r = sd_bus_message_read(reply, "s", &name);
946 if (r < 0)
947 return bus_log_parse_error(r);
948
949 r = sd_bus_message_enter_container(reply, 'v', NULL);
950 if (r < 0)
951 return bus_log_parse_error(r);
952
953 mf = open_memstream(&buf, &sz);
954 if (!mf)
955 return log_oom();
956
957 r = format_cmdline(reply, mf, false);
958 if (r < 0)
959 return bus_log_parse_error(r);
960
961 fclose(mf);
962 mf = NULL;
963
964 z = set_get(members, &((Member) {
965 .type = "property",
966 .interface = m->interface,
967 .name = (char*) name }));
968 if (z) {
969 free(z->value);
970 z->value = buf;
971 buf = NULL;
972 }
973
974 r = sd_bus_message_exit_container(reply);
975 if (r < 0)
976 return bus_log_parse_error(r);
977
978 r = sd_bus_message_exit_container(reply);
979 if (r < 0)
980 return bus_log_parse_error(r);
981 }
982
983 r = sd_bus_message_exit_container(reply);
984 if (r < 0)
985 return bus_log_parse_error(r);
986 }
987
988 pager_open(arg_no_pager, false);
989
990 name_width = strlen("NAME");
991 type_width = strlen("TYPE");
992 signature_width = strlen("SIGNATURE");
993 result_width = strlen("RESULT/VALUE");
994
995 sorted = newa(Member*, set_size(members));
996
997 SET_FOREACH(m, members, i) {
998
999 if (argv[3] && !streq(argv[3], m->interface))
1000 continue;
1001
1002 if (m->interface)
1003 name_width = MAX(name_width, strlen(m->interface));
1004 if (m->name)
1005 name_width = MAX(name_width, strlen(m->name) + 1);
1006 if (m->type)
1007 type_width = MAX(type_width, strlen(m->type));
1008 if (m->signature)
1009 signature_width = MAX(signature_width, strlen(m->signature));
1010 if (m->result)
1011 result_width = MAX(result_width, strlen(m->result));
1012 if (m->value)
1013 result_width = MAX(result_width, strlen(m->value));
1014
1015 sorted[k++] = m;
1016 }
1017
1018 if (result_width > 40)
1019 result_width = 40;
1020
1021 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1022
1023 if (arg_legend) {
1024 printf("%-*s %-*s %-*s %-*s %s\n",
1025 (int) name_width, "NAME",
1026 (int) type_width, "TYPE",
1027 (int) signature_width, "SIGNATURE",
1028 (int) result_width, "RESULT/VALUE",
1029 "FLAGS");
1030 }
1031
1032 for (j = 0; j < k; j++) {
1033 _cleanup_free_ char *ellipsized = NULL;
1034 const char *rv;
1035 bool is_interface;
1036
1037 m = sorted[j];
1038
1039 if (argv[3] && !streq(argv[3], m->interface))
1040 continue;
1041
1042 is_interface = streq(m->type, "interface");
1043
1044 if (argv[3] && is_interface)
1045 continue;
1046
1047 if (m->value) {
1048 ellipsized = ellipsize(m->value, result_width, 100);
1049 if (!ellipsized)
1050 return log_oom();
1051
1052 rv = ellipsized;
1053 } else
1054 rv = strdash(m->result);
1055
1056 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1057 is_interface ? ansi_highlight() : "",
1058 is_interface ? "" : ".",
1059 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1060 is_interface ? ansi_normal() : "",
1061 (int) type_width, strdash(m->type),
1062 (int) signature_width, strdash(m->signature),
1063 (int) result_width, rv,
1064 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1065 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1066 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1067 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1068 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1069 m->writable ? " writable" : "");
1070 }
1071
1072 return 0;
1073}
1074
1075static int message_dump(sd_bus_message *m, FILE *f) {
1076 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1077}
1078
1079static int message_pcap(sd_bus_message *m, FILE *f) {
1080 return bus_message_pcap_frame(m, arg_snaplen, f);
1081}
1082
1083static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1084 _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
1085 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1086 char **i;
1087 uint32_t flags = 0;
1088 const char *unique_name;
1089 bool is_monitor = false;
1090 int r;
1091
1092 /* upgrade connection; it's not used for anything else after this call */
1093 r = sd_bus_message_new_method_call(bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
1094 if (r < 0)
1095 return bus_log_create_error(r);
1096
1097 r = sd_bus_message_open_container(message, 'a', "s");
1098 if (r < 0)
1099 return bus_log_create_error(r);
1100
1101 STRV_FOREACH(i, argv+1) {
1102 _cleanup_free_ char *m = NULL;
1103
1104 if (!service_name_is_valid(*i)) {
1105 log_error("Invalid service name '%s'", *i);
1106 return -EINVAL;
1107 }
1108
1109 m = strjoin("sender='", *i, "'");
1110 if (!m)
1111 return log_oom();
1112
1113 r = sd_bus_message_append_basic(message, 's', m);
1114 if (r < 0)
1115 return bus_log_create_error(r);
1116
1117 free(m);
1118 m = strjoin("destination='", *i, "'");
1119 if (!m)
1120 return log_oom();
1121
1122 r = sd_bus_message_append_basic(message, 's', m);
1123 if (r < 0)
1124 return bus_log_create_error(r);
1125 }
1126
1127 STRV_FOREACH(i, arg_matches) {
1128 r = sd_bus_message_append_basic(message, 's', *i);
1129 if (r < 0)
1130 return bus_log_create_error(r);
1131 }
1132
1133 r = sd_bus_message_close_container(message);
1134 if (r < 0)
1135 return bus_log_create_error(r);
1136
1137 r = sd_bus_message_append_basic(message, 'u', &flags);
1138 if (r < 0)
1139 return bus_log_create_error(r);
1140
1141 r = sd_bus_call(bus, message, arg_timeout, &error, NULL);
1142 if (r < 0) {
1143 log_error("%s", bus_error_message(&error, r));
1144 return r;
1145 }
1146
1147 r = sd_bus_get_unique_name(bus, &unique_name);
1148 if (r < 0)
1149 return log_error_errno(r, "Failed to get unique name: %m");
1150
1151 log_info("Monitoring bus message stream.");
1152
1153 for (;;) {
1154 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1155
1156 r = sd_bus_process(bus, &m);
1157 if (r < 0)
1158 return log_error_errno(r, "Failed to process bus: %m");
1159
1160 if (!is_monitor) {
1161 const char *name;
1162
1163 /* wait until we lose our unique name */
1164 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameLost") <= 0)
1165 continue;
1166
1167 r = sd_bus_message_read(m, "s", &name);
1168 if (r < 0)
1169 return log_error_errno(r, "Failed to read lost name: %m");
1170
1171 if (streq(name, unique_name))
1172 is_monitor = true;
1173
1174 continue;
1175 }
1176
1177 if (m) {
1178 dump(m, stdout);
1179 fflush(stdout);
1180
1181 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1182 log_info("Connection terminated, exiting.");
1183 return 0;
1184 }
1185
1186 continue;
1187 }
1188
1189 if (r > 0)
1190 continue;
1191
1192 r = sd_bus_wait(bus, (uint64_t) -1);
1193 if (r < 0)
1194 return log_error_errno(r, "Failed to wait for bus: %m");
1195 }
1196}
1197
1198static int capture(sd_bus *bus, char *argv[]) {
1199 int r;
1200
1201 if (isatty(fileno(stdout)) > 0) {
1202 log_error("Refusing to write message data to console, please redirect output to a file.");
1203 return -EINVAL;
1204 }
1205
1206 bus_pcap_header(arg_snaplen, stdout);
1207
1208 r = monitor(bus, argv, message_pcap);
1209 if (r < 0)
1210 return r;
1211
1212 if (ferror(stdout)) {
1213 log_error("Couldn't write capture file.");
1214 return -EIO;
1215 }
1216
1217 return r;
1218}
1219
1220static int status(sd_bus *bus, char *argv[]) {
1221 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
1222 pid_t pid;
1223 int r;
1224
1225 assert(bus);
1226
1227 if (strv_length(argv) > 2) {
1228 log_error("Expects no or one argument.");
1229 return -EINVAL;
1230 }
1231
1232 if (argv[1]) {
1233 r = parse_pid(argv[1], &pid);
1234 if (r < 0)
1235 r = sd_bus_get_name_creds(
1236 bus,
1237 argv[1],
1238 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1239 &creds);
1240 else
1241 r = sd_bus_creds_new_from_pid(
1242 &creds,
1243 pid,
1244 _SD_BUS_CREDS_ALL);
1245 } else {
1246 const char *scope, *address;
1247 sd_id128_t bus_id;
1248
1249 r = sd_bus_get_address(bus, &address);
1250 if (r >= 0)
1251 printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal());
1252
1253 r = sd_bus_get_scope(bus, &scope);
1254 if (r >= 0)
1255 printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal());
1256
1257 r = sd_bus_get_bus_id(bus, &bus_id);
1258 if (r >= 0)
1259 printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal());
1260
1261 r = sd_bus_get_owner_creds(
1262 bus,
1263 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1264 &creds);
1265 }
1266
1267 if (r < 0)
1268 return log_error_errno(r, "Failed to get credentials: %m");
1269
1270 bus_creds_dump(creds, NULL, false);
1271 return 0;
1272}
1273
1274static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1275 char **p;
1276 int r;
1277
1278 assert(m);
1279 assert(signature);
1280 assert(x);
1281
1282 p = *x;
1283
1284 for (;;) {
1285 const char *v;
1286 char t;
1287
1288 t = *signature;
1289 v = *p;
1290
1291 if (t == 0)
1292 break;
1293 if (!v) {
1294 log_error("Too few parameters for signature.");
1295 return -EINVAL;
1296 }
1297
1298 signature++;
1299 p++;
1300
1301 switch (t) {
1302
1303 case SD_BUS_TYPE_BOOLEAN:
1304
1305 r = parse_boolean(v);
1306 if (r < 0) {
1307 log_error("Failed to parse as boolean: %s", v);
1308 return r;
1309 }
1310
1311 r = sd_bus_message_append_basic(m, t, &r);
1312 break;
1313
1314 case SD_BUS_TYPE_BYTE: {
1315 uint8_t z;
1316
1317 r = safe_atou8(v, &z);
1318 if (r < 0) {
1319 log_error("Failed to parse as byte (unsigned 8bit 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_INT16: {
1328 int16_t z;
1329
1330 r = safe_atoi16(v, &z);
1331 if (r < 0) {
1332 log_error("Failed to parse as signed 16bit 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_UINT16: {
1341 uint16_t z;
1342
1343 r = safe_atou16(v, &z);
1344 if (r < 0) {
1345 log_error("Failed to parse as unsigned 16bit 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_INT32: {
1354 int32_t z;
1355
1356 r = safe_atoi32(v, &z);
1357 if (r < 0) {
1358 log_error("Failed to parse as signed 32bit integer: %s", v);
1359 return r;
1360 }
1361
1362 r = sd_bus_message_append_basic(m, t, &z);
1363 break;
1364 }
1365
1366 case SD_BUS_TYPE_UINT32: {
1367 uint32_t z;
1368
1369 r = safe_atou32(v, &z);
1370 if (r < 0) {
1371 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1372 return r;
1373 }
1374
1375 r = sd_bus_message_append_basic(m, t, &z);
1376 break;
1377 }
1378
1379 case SD_BUS_TYPE_INT64: {
1380 int64_t z;
1381
1382 r = safe_atoi64(v, &z);
1383 if (r < 0) {
1384 log_error("Failed to parse as signed 64bit integer: %s", v);
1385 return r;
1386 }
1387
1388 r = sd_bus_message_append_basic(m, t, &z);
1389 break;
1390 }
1391
1392 case SD_BUS_TYPE_UINT64: {
1393 uint64_t z;
1394
1395 r = safe_atou64(v, &z);
1396 if (r < 0) {
1397 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1398 return r;
1399 }
1400
1401 r = sd_bus_message_append_basic(m, t, &z);
1402 break;
1403 }
1404
1405
1406 case SD_BUS_TYPE_DOUBLE: {
1407 double z;
1408
1409 r = safe_atod(v, &z);
1410 if (r < 0) {
1411 log_error("Failed to parse as double precision floating point: %s", v);
1412 return r;
1413 }
1414
1415 r = sd_bus_message_append_basic(m, t, &z);
1416 break;
1417 }
1418
1419 case SD_BUS_TYPE_STRING:
1420 case SD_BUS_TYPE_OBJECT_PATH:
1421 case SD_BUS_TYPE_SIGNATURE:
1422
1423 r = sd_bus_message_append_basic(m, t, v);
1424 break;
1425
1426 case SD_BUS_TYPE_ARRAY: {
1427 uint32_t n;
1428 size_t k;
1429
1430 r = safe_atou32(v, &n);
1431 if (r < 0) {
1432 log_error("Failed to parse number of array entries: %s", v);
1433 return r;
1434 }
1435
1436 r = signature_element_length(signature, &k);
1437 if (r < 0) {
1438 log_error("Invalid array signature.");
1439 return r;
1440 }
1441
1442 {
1443 unsigned i;
1444 char s[k + 1];
1445 memcpy(s, signature, k);
1446 s[k] = 0;
1447
1448 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1449 if (r < 0)
1450 return bus_log_create_error(r);
1451
1452 for (i = 0; i < n; i++) {
1453 r = message_append_cmdline(m, s, &p);
1454 if (r < 0)
1455 return r;
1456 }
1457 }
1458
1459 signature += k;
1460
1461 r = sd_bus_message_close_container(m);
1462 break;
1463 }
1464
1465 case SD_BUS_TYPE_VARIANT:
1466 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1467 if (r < 0)
1468 return bus_log_create_error(r);
1469
1470 r = message_append_cmdline(m, v, &p);
1471 if (r < 0)
1472 return r;
1473
1474 r = sd_bus_message_close_container(m);
1475 break;
1476
1477 case SD_BUS_TYPE_STRUCT_BEGIN:
1478 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1479 size_t k;
1480
1481 signature--;
1482 p--;
1483
1484 r = signature_element_length(signature, &k);
1485 if (r < 0) {
1486 log_error("Invalid struct/dict entry signature.");
1487 return r;
1488 }
1489
1490 {
1491 char s[k-1];
1492 memcpy(s, signature + 1, k - 2);
1493 s[k - 2] = 0;
1494
1495 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1496 if (r < 0)
1497 return bus_log_create_error(r);
1498
1499 r = message_append_cmdline(m, s, &p);
1500 if (r < 0)
1501 return r;
1502 }
1503
1504 signature += k;
1505
1506 r = sd_bus_message_close_container(m);
1507 break;
1508 }
1509
1510 case SD_BUS_TYPE_UNIX_FD:
1511 log_error("UNIX file descriptor not supported as type.");
1512 return -EINVAL;
1513
1514 default:
1515 log_error("Unknown signature type %c.", t);
1516 return -EINVAL;
1517 }
1518
1519 if (r < 0)
1520 return bus_log_create_error(r);
1521 }
1522
1523 *x = p;
1524 return 0;
1525}
1526
1527static int call(sd_bus *bus, char *argv[]) {
1528 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1529 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
1530 int r;
1531
1532 assert(bus);
1533
1534 if (strv_length(argv) < 5) {
1535 log_error("Expects at least four arguments.");
1536 return -EINVAL;
1537 }
1538
1539 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1540 if (r < 0)
1541 return bus_log_create_error(r);
1542
1543 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1544 if (r < 0)
1545 return bus_log_create_error(r);
1546
1547 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1548 if (r < 0)
1549 return bus_log_create_error(r);
1550
1551 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1552 if (r < 0)
1553 return bus_log_create_error(r);
1554
1555 if (!isempty(argv[5])) {
1556 char **p;
1557
1558 p = argv+6;
1559
1560 r = message_append_cmdline(m, argv[5], &p);
1561 if (r < 0)
1562 return r;
1563
1564 if (*p) {
1565 log_error("Too many parameters for signature.");
1566 return -EINVAL;
1567 }
1568 }
1569
1570 if (!arg_expect_reply) {
1571 r = sd_bus_send(bus, m, NULL);
1572 if (r < 0) {
1573 log_error("Failed to send message.");
1574 return r;
1575 }
1576
1577 return 0;
1578 }
1579
1580 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1581 if (r < 0) {
1582 log_error("%s", bus_error_message(&error, r));
1583 return r;
1584 }
1585
1586 r = sd_bus_message_is_empty(reply);
1587 if (r < 0)
1588 return bus_log_parse_error(r);
1589
1590 if (r == 0 && !arg_quiet) {
1591
1592 if (arg_verbose) {
1593 pager_open(arg_no_pager, false);
1594
1595 r = bus_message_dump(reply, stdout, 0);
1596 if (r < 0)
1597 return r;
1598 } else {
1599
1600 fputs(sd_bus_message_get_signature(reply, true), stdout);
1601 fputc(' ', stdout);
1602
1603 r = format_cmdline(reply, stdout, false);
1604 if (r < 0)
1605 return bus_log_parse_error(r);
1606
1607 fputc('\n', stdout);
1608 }
1609 }
1610
1611 return 0;
1612}
1613
1614static int get_property(sd_bus *bus, char *argv[]) {
1615 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1616 unsigned n;
1617 char **i;
1618 int r;
1619
1620 assert(bus);
1621
1622 n = strv_length(argv);
1623 if (n < 5) {
1624 log_error("Expects at least four arguments.");
1625 return -EINVAL;
1626 }
1627
1628 STRV_FOREACH(i, argv + 4) {
1629 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1630 const char *contents = NULL;
1631 char type;
1632
1633 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1634 if (r < 0) {
1635 log_error("%s", bus_error_message(&error, r));
1636 return r;
1637 }
1638
1639 r = sd_bus_message_peek_type(reply, &type, &contents);
1640 if (r < 0)
1641 return bus_log_parse_error(r);
1642
1643 r = sd_bus_message_enter_container(reply, 'v', contents);
1644 if (r < 0)
1645 return bus_log_parse_error(r);
1646
1647 if (arg_verbose) {
1648 pager_open(arg_no_pager, false);
1649
1650 r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1651 if (r < 0)
1652 return r;
1653 } else {
1654 fputs(contents, stdout);
1655 fputc(' ', stdout);
1656
1657 r = format_cmdline(reply, stdout, false);
1658 if (r < 0)
1659 return bus_log_parse_error(r);
1660
1661 fputc('\n', stdout);
1662 }
1663
1664 r = sd_bus_message_exit_container(reply);
1665 if (r < 0)
1666 return bus_log_parse_error(r);
1667 }
1668
1669 return 0;
1670}
1671
1672static int set_property(sd_bus *bus, char *argv[]) {
1673 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1674 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1675 unsigned n;
1676 char **p;
1677 int r;
1678
1679 assert(bus);
1680
1681 n = strv_length(argv);
1682 if (n < 6) {
1683 log_error("Expects at least five arguments.");
1684 return -EINVAL;
1685 }
1686
1687 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1688 if (r < 0)
1689 return bus_log_create_error(r);
1690
1691 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1692 if (r < 0)
1693 return bus_log_create_error(r);
1694
1695 r = sd_bus_message_open_container(m, 'v', argv[5]);
1696 if (r < 0)
1697 return bus_log_create_error(r);
1698
1699 p = argv+6;
1700 r = message_append_cmdline(m, argv[5], &p);
1701 if (r < 0)
1702 return r;
1703
1704 r = sd_bus_message_close_container(m);
1705 if (r < 0)
1706 return bus_log_create_error(r);
1707
1708 if (*p) {
1709 log_error("Too many parameters for signature.");
1710 return -EINVAL;
1711 }
1712
1713 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1714 if (r < 0) {
1715 log_error("%s", bus_error_message(&error, r));
1716 return r;
1717 }
1718
1719 return 0;
1720}
1721
1722static int help(void) {
1723 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1724 "Introspect the bus.\n\n"
1725 " -h --help Show this help\n"
1726 " --version Show package version\n"
1727 " --no-pager Do not pipe output into a pager\n"
1728 " --no-legend Do not show the headers and footers\n"
1729 " --system Connect to system bus\n"
1730 " --user Connect to user bus\n"
1731 " -H --host=[USER@]HOST Operate on remote host\n"
1732 " -M --machine=CONTAINER Operate on local container\n"
1733 " --address=ADDRESS Connect to bus specified by address\n"
1734 " --show-machine Show machine ID column in list\n"
1735 " --unique Only show unique names\n"
1736 " --acquired Only show acquired names\n"
1737 " --activatable Only show activatable names\n"
1738 " --match=MATCH Only show matching messages\n"
1739 " --size=SIZE Maximum length of captured packet\n"
1740 " --list Don't show tree, but simple object path list\n"
1741 " --quiet Don't show method call reply\n"
1742 " --verbose Show result values in long format\n"
1743 " --expect-reply=BOOL Expect a method call reply\n"
1744 " --auto-start=BOOL Auto-start destination service\n"
1745 " --allow-interactive-authorization=BOOL\n"
1746 " Allow interactive authorization for operation\n"
1747 " --timeout=SECS Maximum time to wait for method call completion\n"
1748 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1749 "Commands:\n"
1750 " list List bus names\n"
1751 " status [SERVICE] Show bus service, process or bus owner credentials\n"
1752 " monitor [SERVICE...] Show bus traffic\n"
1753 " capture [SERVICE...] Capture bus traffic as pcap\n"
1754 " tree [SERVICE...] Show object tree of service\n"
1755 " introspect SERVICE OBJECT [INTERFACE]\n"
1756 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1757 " Call a method\n"
1758 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1759 " Get property value\n"
1760 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1761 " Set property value\n"
1762 " help Show this help\n"
1763 , program_invocation_short_name);
1764
1765 return 0;
1766}
1767
1768static int parse_argv(int argc, char *argv[]) {
1769
1770 enum {
1771 ARG_VERSION = 0x100,
1772 ARG_NO_PAGER,
1773 ARG_NO_LEGEND,
1774 ARG_SYSTEM,
1775 ARG_USER,
1776 ARG_ADDRESS,
1777 ARG_MATCH,
1778 ARG_SHOW_MACHINE,
1779 ARG_UNIQUE,
1780 ARG_ACQUIRED,
1781 ARG_ACTIVATABLE,
1782 ARG_SIZE,
1783 ARG_LIST,
1784 ARG_VERBOSE,
1785 ARG_EXPECT_REPLY,
1786 ARG_AUTO_START,
1787 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1788 ARG_TIMEOUT,
1789 ARG_AUGMENT_CREDS,
1790 };
1791
1792 static const struct option options[] = {
1793 { "help", no_argument, NULL, 'h' },
1794 { "version", no_argument, NULL, ARG_VERSION },
1795 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1796 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1797 { "system", no_argument, NULL, ARG_SYSTEM },
1798 { "user", no_argument, NULL, ARG_USER },
1799 { "address", required_argument, NULL, ARG_ADDRESS },
1800 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1801 { "unique", no_argument, NULL, ARG_UNIQUE },
1802 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1803 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1804 { "match", required_argument, NULL, ARG_MATCH },
1805 { "host", required_argument, NULL, 'H' },
1806 { "machine", required_argument, NULL, 'M' },
1807 { "size", required_argument, NULL, ARG_SIZE },
1808 { "list", no_argument, NULL, ARG_LIST },
1809 { "quiet", no_argument, NULL, 'q' },
1810 { "verbose", no_argument, NULL, ARG_VERBOSE },
1811 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1812 { "auto-start", required_argument, NULL, ARG_AUTO_START },
1813 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1814 { "timeout", required_argument, NULL, ARG_TIMEOUT },
1815 { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
1816 {},
1817 };
1818
1819 int c, r;
1820
1821 assert(argc >= 0);
1822 assert(argv);
1823
1824 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1825
1826 switch (c) {
1827
1828 case 'h':
1829 return help();
1830
1831 case ARG_VERSION:
1832 return version();
1833
1834 case ARG_NO_PAGER:
1835 arg_no_pager = true;
1836 break;
1837
1838 case ARG_NO_LEGEND:
1839 arg_legend = false;
1840 break;
1841
1842 case ARG_USER:
1843 arg_user = true;
1844 break;
1845
1846 case ARG_SYSTEM:
1847 arg_user = false;
1848 break;
1849
1850 case ARG_ADDRESS:
1851 arg_address = optarg;
1852 break;
1853
1854 case ARG_SHOW_MACHINE:
1855 arg_show_machine = true;
1856 break;
1857
1858 case ARG_UNIQUE:
1859 arg_unique = true;
1860 break;
1861
1862 case ARG_ACQUIRED:
1863 arg_acquired = true;
1864 break;
1865
1866 case ARG_ACTIVATABLE:
1867 arg_activatable = true;
1868 break;
1869
1870 case ARG_MATCH:
1871 if (strv_extend(&arg_matches, optarg) < 0)
1872 return log_oom();
1873 break;
1874
1875 case ARG_SIZE: {
1876 uint64_t sz;
1877
1878 r = parse_size(optarg, 1024, &sz);
1879 if (r < 0) {
1880 log_error("Failed to parse size: %s", optarg);
1881 return r;
1882 }
1883
1884 if ((uint64_t) (size_t) sz != sz) {
1885 log_error("Size out of range.");
1886 return -E2BIG;
1887 }
1888
1889 arg_snaplen = (size_t) sz;
1890 break;
1891 }
1892
1893 case ARG_LIST:
1894 arg_list = true;
1895 break;
1896
1897 case 'H':
1898 arg_transport = BUS_TRANSPORT_REMOTE;
1899 arg_host = optarg;
1900 break;
1901
1902 case 'M':
1903 arg_transport = BUS_TRANSPORT_MACHINE;
1904 arg_host = optarg;
1905 break;
1906
1907 case 'q':
1908 arg_quiet = true;
1909 break;
1910
1911 case ARG_VERBOSE:
1912 arg_verbose = true;
1913 break;
1914
1915 case ARG_EXPECT_REPLY:
1916 r = parse_boolean(optarg);
1917 if (r < 0) {
1918 log_error("Failed to parse --expect-reply= parameter.");
1919 return r;
1920 }
1921
1922 arg_expect_reply = !!r;
1923 break;
1924
1925
1926 case ARG_AUTO_START:
1927 r = parse_boolean(optarg);
1928 if (r < 0) {
1929 log_error("Failed to parse --auto-start= parameter.");
1930 return r;
1931 }
1932
1933 arg_auto_start = !!r;
1934 break;
1935
1936
1937 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1938 r = parse_boolean(optarg);
1939 if (r < 0) {
1940 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1941 return r;
1942 }
1943
1944 arg_allow_interactive_authorization = !!r;
1945 break;
1946
1947 case ARG_TIMEOUT:
1948 r = parse_sec(optarg, &arg_timeout);
1949 if (r < 0) {
1950 log_error("Failed to parse --timeout= parameter.");
1951 return r;
1952 }
1953
1954 break;
1955
1956 case ARG_AUGMENT_CREDS:
1957 r = parse_boolean(optarg);
1958 if (r < 0) {
1959 log_error("Failed to parse --augment-creds= parameter.");
1960 return r;
1961 }
1962
1963 arg_augment_creds = !!r;
1964 break;
1965
1966 case '?':
1967 return -EINVAL;
1968
1969 default:
1970 assert_not_reached("Unhandled option");
1971 }
1972
1973 return 1;
1974}
1975
1976static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1977 assert(bus);
1978
1979 if (optind >= argc ||
1980 streq(argv[optind], "list"))
1981 return list_bus_names(bus, argv + optind);
1982
1983 if (streq(argv[optind], "monitor"))
1984 return monitor(bus, argv + optind, message_dump);
1985
1986 if (streq(argv[optind], "capture"))
1987 return capture(bus, argv + optind);
1988
1989 if (streq(argv[optind], "status"))
1990 return status(bus, argv + optind);
1991
1992 if (streq(argv[optind], "tree"))
1993 return tree(bus, argv + optind);
1994
1995 if (streq(argv[optind], "introspect"))
1996 return introspect(bus, argv + optind);
1997
1998 if (streq(argv[optind], "call"))
1999 return call(bus, argv + optind);
2000
2001 if (streq(argv[optind], "get-property"))
2002 return get_property(bus, argv + optind);
2003
2004 if (streq(argv[optind], "set-property"))
2005 return set_property(bus, argv + optind);
2006
2007 if (streq(argv[optind], "help"))
2008 return help();
2009
2010 log_error("Unknown command '%s'", argv[optind]);
2011 return -EINVAL;
2012}
2013
2014int main(int argc, char *argv[]) {
2015 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2016 int r;
2017
2018 log_parse_environment();
2019 log_open();
2020
2021 r = parse_argv(argc, argv);
2022 if (r <= 0)
2023 goto finish;
2024
2025 r = sd_bus_new(&bus);
2026 if (r < 0) {
2027 log_error_errno(r, "Failed to allocate bus: %m");
2028 goto finish;
2029 }
2030
2031 if (STRPTR_IN_SET(argv[optind], "monitor", "capture")) {
2032
2033 r = sd_bus_set_monitor(bus, true);
2034 if (r < 0) {
2035 log_error_errno(r, "Failed to set monitor mode: %m");
2036 goto finish;
2037 }
2038
2039 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
2040 if (r < 0) {
2041 log_error_errno(r, "Failed to enable credentials: %m");
2042 goto finish;
2043 }
2044
2045 r = sd_bus_negotiate_timestamp(bus, true);
2046 if (r < 0) {
2047 log_error_errno(r, "Failed to enable timestamps: %m");
2048 goto finish;
2049 }
2050
2051 r = sd_bus_negotiate_fds(bus, true);
2052 if (r < 0) {
2053 log_error_errno(r, "Failed to enable fds: %m");
2054 goto finish;
2055 }
2056 }
2057
2058 r = sd_bus_set_bus_client(bus, true);
2059 if (r < 0) {
2060 log_error_errno(r, "Failed to set bus client: %m");
2061 goto finish;
2062 }
2063
2064 if (arg_address)
2065 r = sd_bus_set_address(bus, arg_address);
2066 else {
2067 switch (arg_transport) {
2068
2069 case BUS_TRANSPORT_LOCAL:
2070 if (arg_user) {
2071 bus->is_user = true;
2072 r = bus_set_address_user(bus);
2073 } else {
2074 bus->is_system = true;
2075 r = bus_set_address_system(bus);
2076 }
2077 break;
2078
2079 case BUS_TRANSPORT_REMOTE:
2080 r = bus_set_address_system_remote(bus, arg_host);
2081 break;
2082
2083 case BUS_TRANSPORT_MACHINE:
2084 r = bus_set_address_system_machine(bus, arg_host);
2085 break;
2086
2087 default:
2088 assert_not_reached("Hmm, unknown transport type.");
2089 }
2090 }
2091 if (r < 0) {
2092 log_error_errno(r, "Failed to set address: %m");
2093 goto finish;
2094 }
2095
2096 r = sd_bus_start(bus);
2097 if (r < 0) {
2098 log_error_errno(r, "Failed to connect to bus: %m");
2099 goto finish;
2100 }
2101
2102 r = busctl_main(bus, argc, argv);
2103
2104finish:
2105 pager_close();
2106
2107 strv_free(arg_matches);
2108
2109 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2110}