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