]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/busctl/busctl.c
Make pager_open() return void
[thirdparty/systemd.git] / src / busctl / busctl.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <getopt.h>
4
5 #include "sd-bus.h"
6
7 #include "alloc-util.h"
8 #include "bus-dump.h"
9 #include "bus-internal.h"
10 #include "bus-message.h"
11 #include "bus-signature.h"
12 #include "bus-type.h"
13 #include "bus-util.h"
14 #include "busctl-introspect.h"
15 #include "escape.h"
16 #include "fd-util.h"
17 #include "fileio.h"
18 #include "format-table.h"
19 #include "glyph-util.h"
20 #include "json.h"
21 #include "log.h"
22 #include "main-func.h"
23 #include "pager.h"
24 #include "parse-argument.h"
25 #include "parse-util.h"
26 #include "path-util.h"
27 #include "pretty-print.h"
28 #include "set.h"
29 #include "sort-util.h"
30 #include "strv.h"
31 #include "terminal-util.h"
32 #include "user-util.h"
33 #include "verbs.h"
34
35 static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
36 static PagerFlags arg_pager_flags = 0;
37 static bool arg_legend = true;
38 static bool arg_full = false;
39 static const char *arg_address = NULL;
40 static bool arg_unique = false;
41 static bool arg_acquired = false;
42 static bool arg_activatable = false;
43 static bool arg_show_machine = false;
44 static char **arg_matches = NULL;
45 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
46 static const char *arg_host = NULL;
47 static bool arg_user = false;
48 static size_t arg_snaplen = 4096;
49 static bool arg_list = false;
50 static bool arg_quiet = false;
51 static bool arg_verbose = false;
52 static bool arg_xml_interface = false;
53 static bool arg_expect_reply = true;
54 static bool arg_auto_start = true;
55 static bool arg_allow_interactive_authorization = true;
56 static bool arg_augment_creds = true;
57 static bool arg_watch_bind = false;
58 static usec_t arg_timeout = 0;
59 static const char *arg_destination = NULL;
60
61 STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
62
63 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
64 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
65
66 static int json_transform_message(sd_bus_message *m, JsonVariant **ret);
67
68 static int acquire_bus(bool set_monitor, sd_bus **ret) {
69 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
70 int r;
71
72 r = sd_bus_new(&bus);
73 if (r < 0)
74 return log_error_errno(r, "Failed to allocate bus: %m");
75
76 if (set_monitor) {
77 r = sd_bus_set_monitor(bus, true);
78 if (r < 0)
79 return log_error_errno(r, "Failed to set monitor mode: %m");
80
81 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
82 if (r < 0)
83 return log_error_errno(r, "Failed to enable credentials: %m");
84
85 r = sd_bus_negotiate_timestamp(bus, true);
86 if (r < 0)
87 return log_error_errno(r, "Failed to enable timestamps: %m");
88
89 r = sd_bus_negotiate_fds(bus, true);
90 if (r < 0)
91 return log_error_errno(r, "Failed to enable fds: %m");
92 }
93
94 r = sd_bus_set_bus_client(bus, true);
95 if (r < 0)
96 return log_error_errno(r, "Failed to set bus client: %m");
97
98 r = sd_bus_set_watch_bind(bus, arg_watch_bind);
99 if (r < 0)
100 return log_error_errno(r, "Failed to set watch-bind setting to '%s': %m",
101 yes_no(arg_watch_bind));
102
103 if (arg_address)
104 r = sd_bus_set_address(bus, arg_address);
105 else {
106 switch (arg_transport) {
107
108 case BUS_TRANSPORT_LOCAL:
109 if (arg_user)
110 r = bus_set_address_user(bus);
111 else
112 r = bus_set_address_system(bus);
113 break;
114
115 case BUS_TRANSPORT_REMOTE:
116 r = bus_set_address_system_remote(bus, arg_host);
117 break;
118
119 case BUS_TRANSPORT_MACHINE:
120 r = bus_set_address_machine(bus, arg_user, arg_host);
121 break;
122
123 default:
124 assert_not_reached();
125 }
126 }
127 if (r < 0)
128 return bus_log_address_error(r);
129
130 r = sd_bus_start(bus);
131 if (r < 0)
132 return bus_log_connect_error(r);
133
134 *ret = TAKE_PTR(bus);
135
136 return 0;
137 }
138
139 static int list_bus_names(int argc, char **argv, void *userdata) {
140 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
141 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
142 _cleanup_hashmap_free_ Hashmap *names = NULL;
143 _cleanup_(table_unrefp) Table *table = NULL;
144 char **i, *k;
145 void *v;
146 int r;
147
148 enum {
149 COLUMN_ACTIVATABLE,
150 COLUMN_NAME,
151 COLUMN_PID,
152 COLUMN_PROCESS,
153 COLUMN_USER,
154 COLUMN_CONNECTION,
155 COLUMN_UNIT,
156 COLUMN_SESSION,
157 COLUMN_DESCRIPTION,
158 COLUMN_MACHINE,
159 };
160
161 if (!arg_unique && !arg_acquired && !arg_activatable)
162 arg_unique = arg_acquired = arg_activatable = true;
163
164 r = acquire_bus(false, &bus);
165 if (r < 0)
166 return r;
167
168 r = sd_bus_list_names(bus,
169 (arg_acquired || arg_unique) ? &acquired : NULL,
170 arg_activatable ? &activatable : NULL);
171 if (r < 0)
172 return log_error_errno(r, "Failed to list names: %m");
173
174 names = hashmap_new(&string_hash_ops);
175 if (!names)
176 return log_oom();
177
178 STRV_FOREACH(i, acquired) {
179 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
180 if (r < 0)
181 return log_error_errno(r, "Failed to add to hashmap: %m");
182 }
183
184 STRV_FOREACH(i, activatable) {
185 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
186 if (r < 0 && r != -EEXIST)
187 return log_error_errno(r, "Failed to add to hashmap: %m");
188 }
189
190 table = table_new("activatable",
191 "name",
192 "pid",
193 "process",
194 "user",
195 "connection",
196 "unit",
197 "session",
198 "description",
199 "machine");
200 if (!table)
201 return log_oom();
202
203 if (arg_full)
204 table_set_width(table, 0);
205
206 r = table_set_align_percent(table, table_get_cell(table, 0, COLUMN_PID), 100);
207 if (r < 0)
208 return log_error_errno(r, "Failed to set alignment: %m");
209
210 r = table_set_empty_string(table, "-");
211 if (r < 0)
212 return log_error_errno(r, "Failed to set empty string: %m");
213
214 r = table_set_sort(table, (size_t) COLUMN_NAME);
215 if (r < 0)
216 return log_error_errno(r, "Failed to set sort column: %m");
217
218 if (arg_show_machine)
219 r = table_set_display(table, (size_t) COLUMN_NAME,
220 (size_t) COLUMN_PID,
221 (size_t) COLUMN_PROCESS,
222 (size_t) COLUMN_USER,
223 (size_t) COLUMN_CONNECTION,
224 (size_t) COLUMN_UNIT,
225 (size_t) COLUMN_SESSION,
226 (size_t) COLUMN_DESCRIPTION,
227 (size_t) COLUMN_MACHINE);
228 else
229 r = table_set_display(table, (size_t) COLUMN_NAME,
230 (size_t) COLUMN_PID,
231 (size_t) COLUMN_PROCESS,
232 (size_t) COLUMN_USER,
233 (size_t) COLUMN_CONNECTION,
234 (size_t) COLUMN_UNIT,
235 (size_t) COLUMN_SESSION,
236 (size_t) COLUMN_DESCRIPTION);
237
238 if (r < 0)
239 return log_error_errno(r, "Failed to set columns to display: %m");
240
241 HASHMAP_FOREACH_KEY(v, k, names) {
242 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
243
244 if (v == NAME_IS_ACTIVATABLE) {
245 r = table_add_many(
246 table,
247 TABLE_INT, PTR_TO_INT(v),
248 TABLE_STRING, k,
249 TABLE_EMPTY,
250 TABLE_EMPTY,
251 TABLE_EMPTY,
252 TABLE_STRING, "(activatable)", TABLE_SET_COLOR, ansi_grey(),
253 TABLE_EMPTY,
254 TABLE_EMPTY,
255 TABLE_EMPTY,
256 TABLE_EMPTY);
257 if (r < 0)
258 return table_log_add_error(r);
259
260 continue;
261 }
262
263 assert(v == NAME_IS_ACQUIRED);
264
265 if (!arg_unique && k[0] == ':')
266 continue;
267
268 if (!arg_acquired && k[0] != ':')
269 continue;
270
271 r = table_add_many(table,
272 TABLE_INT, PTR_TO_INT(v),
273 TABLE_STRING, k);
274 if (r < 0)
275 return table_log_add_error(r);
276
277 r = sd_bus_get_name_creds(
278 bus, k,
279 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
280 SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
281 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
282 SD_BUS_CREDS_DESCRIPTION, &creds);
283 if (r < 0) {
284 log_debug_errno(r, "Failed to acquire credentials of service %s, ignoring: %m", k);
285
286 r = table_fill_empty(table, COLUMN_MACHINE);
287 } else {
288 const char *unique = NULL, *session = NULL, *unit = NULL, *cn = NULL;
289 pid_t pid;
290 uid_t uid;
291
292 r = sd_bus_creds_get_pid(creds, &pid);
293 if (r >= 0) {
294 const char *comm = NULL;
295
296 (void) sd_bus_creds_get_comm(creds, &comm);
297
298 r = table_add_many(table,
299 TABLE_PID, pid,
300 TABLE_STRING, strna(comm));
301 } else
302 r = table_add_many(table, TABLE_EMPTY, TABLE_EMPTY);
303 if (r < 0)
304 return table_log_add_error(r);
305
306 r = sd_bus_creds_get_euid(creds, &uid);
307 if (r >= 0) {
308 _cleanup_free_ char *u = NULL;
309
310 u = uid_to_name(uid);
311 if (!u)
312 return log_oom();
313
314 r = table_add_cell(table, NULL, TABLE_STRING, u);
315 } else
316 r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
317 if (r < 0)
318 return table_log_add_error(r);
319
320 (void) sd_bus_creds_get_unique_name(creds, &unique);
321 (void) sd_bus_creds_get_unit(creds, &unit);
322 (void) sd_bus_creds_get_session(creds, &session);
323 (void) sd_bus_creds_get_description(creds, &cn);
324
325 r = table_add_many(
326 table,
327 TABLE_STRING, unique,
328 TABLE_STRING, unit,
329 TABLE_STRING, session,
330 TABLE_STRING, cn);
331 }
332 if (r < 0)
333 return table_log_add_error(r);
334
335 if (arg_show_machine) {
336 sd_id128_t mid;
337
338 r = sd_bus_get_name_machine_id(bus, k, &mid);
339 if (r < 0)
340 log_debug_errno(r, "Failed to acquire credentials of service %s, ignoring: %m", k);
341 else {
342 r = table_add_cell(table, NULL, TABLE_ID128, &mid);
343 if (r < 0)
344 return table_log_add_error(r);
345
346 continue; /* line fully filled, no need to fill the remainder below */
347 }
348 }
349
350 r = table_fill_empty(table, 0);
351 if (r < 0)
352 return log_error_errno(r, "Failed to fill line: %m");
353 }
354
355 return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
356 }
357
358 static void print_subtree(const char *prefix, const char *path, char **l) {
359 const char *vertical, *space;
360 char **n;
361
362 /* We assume the list is sorted. Let's first skip over the
363 * entry we are looking at. */
364 for (;;) {
365 if (!*l)
366 return;
367
368 if (!streq(*l, path))
369 break;
370
371 l++;
372 }
373
374 vertical = strjoina(prefix, special_glyph(SPECIAL_GLYPH_TREE_VERTICAL));
375 space = strjoina(prefix, special_glyph(SPECIAL_GLYPH_TREE_SPACE));
376
377 for (;;) {
378 bool has_more = false;
379
380 if (!*l || !path_startswith(*l, path))
381 break;
382
383 n = l + 1;
384 for (;;) {
385 if (!*n || !path_startswith(*n, path))
386 break;
387
388 if (!path_startswith(*n, *l)) {
389 has_more = true;
390 break;
391 }
392
393 n++;
394 }
395
396 printf("%s%s%s\n",
397 prefix,
398 special_glyph(has_more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT),
399 *l);
400
401 print_subtree(has_more ? vertical : space, *l, l);
402 l = n;
403 }
404 }
405
406 static void print_tree(char **l) {
407 if (arg_list)
408 strv_print(l);
409 else if (strv_isempty(l))
410 printf("No objects discovered.\n");
411 else if (streq(l[0], "/") && !l[1])
412 printf("Only root object discovered.\n");
413 else
414 print_subtree("", "/", l);
415 }
416
417 static int on_path(const char *path, void *userdata) {
418 Set *paths = userdata;
419 int r;
420
421 assert(paths);
422
423 r = set_put_strdup(&paths, path);
424 if (r < 0)
425 return log_oom();
426
427 return 0;
428 }
429
430 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths) {
431 static const XMLIntrospectOps ops = {
432 .on_path = on_path,
433 };
434
435 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
436 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
437 const char *xml;
438 int r;
439
440 r = sd_bus_call_method(bus, service, path,
441 "org.freedesktop.DBus.Introspectable", "Introspect",
442 &error, &reply, NULL);
443 if (r < 0) {
444 printf("%sFailed to introspect object %s of service %s: %s%s\n",
445 ansi_highlight_red(),
446 path, service, bus_error_message(&error, r),
447 ansi_normal());
448 return r;
449 }
450
451 r = sd_bus_message_read(reply, "s", &xml);
452 if (r < 0)
453 return bus_log_parse_error(r);
454
455 return parse_xml_introspect(path, xml, &ops, paths);
456 }
457
458 static int tree_one(sd_bus *bus, const char *service) {
459 _cleanup_set_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
460 _cleanup_free_ char **l = NULL;
461 int r;
462
463 r = set_put_strdup(&paths, "/");
464 if (r < 0)
465 return log_oom();
466
467 for (;;) {
468 _cleanup_free_ char *p = NULL;
469 int q;
470
471 p = set_steal_first(paths);
472 if (!p)
473 break;
474
475 if (set_contains(done, p) ||
476 set_contains(failed, p))
477 continue;
478
479 q = find_nodes(bus, service, p, paths);
480 if (q < 0 && r >= 0)
481 r = q;
482
483 q = set_ensure_consume(q < 0 ? &failed : &done, &string_hash_ops_free, TAKE_PTR(p));
484 assert(q != 0);
485 if (q < 0)
486 return log_oom();
487 }
488
489 pager_open(arg_pager_flags);
490
491 l = set_get_strv(done);
492 if (!l)
493 return log_oom();
494
495 strv_sort(l);
496 print_tree(l);
497
498 fflush(stdout);
499
500 return r;
501 }
502
503 static int tree(int argc, char **argv, void *userdata) {
504 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
505 char **i;
506 int r;
507
508 /* Do superficial verification of arguments before even opening the bus */
509 STRV_FOREACH(i, strv_skip(argv, 1))
510 if (!sd_bus_service_name_is_valid(*i))
511 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
512 "Invalid bus service name: %s", *i);
513
514 if (!arg_unique && !arg_acquired)
515 arg_acquired = true;
516
517 r = acquire_bus(false, &bus);
518 if (r < 0)
519 return r;
520
521 if (argc <= 1) {
522 _cleanup_strv_free_ char **names = NULL;
523 bool not_first = false;
524
525 r = sd_bus_list_names(bus, &names, NULL);
526 if (r < 0)
527 return log_error_errno(r, "Failed to get name list: %m");
528
529 pager_open(arg_pager_flags);
530
531 STRV_FOREACH(i, names) {
532 int q;
533
534 if (!arg_unique && (*i)[0] == ':')
535 continue;
536
537 if (!arg_acquired && (*i)[0] == ':')
538 continue;
539
540 if (not_first)
541 printf("\n");
542
543 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
544
545 q = tree_one(bus, *i);
546 if (q < 0 && r >= 0)
547 r = q;
548
549 not_first = true;
550 }
551 } else
552 STRV_FOREACH(i, strv_skip(argv, 1)) {
553 int q;
554
555 if (i > argv+1)
556 printf("\n");
557
558 if (argv[2]) {
559 pager_open(arg_pager_flags);
560 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
561 }
562
563 q = tree_one(bus, *i);
564 if (q < 0 && r >= 0)
565 r = q;
566 }
567
568 return r;
569 }
570
571 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
572 int r;
573
574 for (;;) {
575 const char *contents = NULL;
576 char type;
577 union {
578 uint8_t u8;
579 uint16_t u16;
580 int16_t s16;
581 uint32_t u32;
582 int32_t s32;
583 uint64_t u64;
584 int64_t s64;
585 double d64;
586 const char *string;
587 int i;
588 } basic;
589
590 r = sd_bus_message_peek_type(m, &type, &contents);
591 if (r < 0)
592 return r;
593 if (r == 0)
594 return needs_space;
595
596 if (bus_type_is_container(type) > 0) {
597
598 r = sd_bus_message_enter_container(m, type, contents);
599 if (r < 0)
600 return r;
601
602 if (type == SD_BUS_TYPE_ARRAY) {
603 unsigned n = 0;
604
605 /* count array entries */
606 for (;;) {
607
608 r = sd_bus_message_skip(m, contents);
609 if (r < 0)
610 return r;
611 if (r == 0)
612 break;
613
614 n++;
615 }
616
617 r = sd_bus_message_rewind(m, false);
618 if (r < 0)
619 return r;
620
621 if (needs_space)
622 fputc(' ', f);
623
624 fprintf(f, "%u", n);
625 needs_space = true;
626
627 } else if (type == SD_BUS_TYPE_VARIANT) {
628
629 if (needs_space)
630 fputc(' ', f);
631
632 fprintf(f, "%s", contents);
633 needs_space = true;
634 }
635
636 r = format_cmdline(m, f, needs_space);
637 if (r < 0)
638 return r;
639
640 needs_space = r > 0;
641
642 r = sd_bus_message_exit_container(m);
643 if (r < 0)
644 return r;
645
646 continue;
647 }
648
649 r = sd_bus_message_read_basic(m, type, &basic);
650 if (r < 0)
651 return r;
652
653 if (needs_space)
654 fputc(' ', f);
655
656 switch (type) {
657 case SD_BUS_TYPE_BYTE:
658 fprintf(f, "%u", basic.u8);
659 break;
660
661 case SD_BUS_TYPE_BOOLEAN:
662 fputs(true_false(basic.i), f);
663 break;
664
665 case SD_BUS_TYPE_INT16:
666 fprintf(f, "%i", basic.s16);
667 break;
668
669 case SD_BUS_TYPE_UINT16:
670 fprintf(f, "%u", basic.u16);
671 break;
672
673 case SD_BUS_TYPE_INT32:
674 fprintf(f, "%i", basic.s32);
675 break;
676
677 case SD_BUS_TYPE_UINT32:
678 fprintf(f, "%u", basic.u32);
679 break;
680
681 case SD_BUS_TYPE_INT64:
682 fprintf(f, "%" PRIi64, basic.s64);
683 break;
684
685 case SD_BUS_TYPE_UINT64:
686 fprintf(f, "%" PRIu64, basic.u64);
687 break;
688
689 case SD_BUS_TYPE_DOUBLE:
690 fprintf(f, "%g", basic.d64);
691 break;
692
693 case SD_BUS_TYPE_STRING:
694 case SD_BUS_TYPE_OBJECT_PATH:
695 case SD_BUS_TYPE_SIGNATURE: {
696 _cleanup_free_ char *b = NULL;
697
698 b = cescape(basic.string);
699 if (!b)
700 return -ENOMEM;
701
702 fprintf(f, "\"%s\"", b);
703 break;
704 }
705
706 case SD_BUS_TYPE_UNIX_FD:
707 fprintf(f, "%i", basic.i);
708 break;
709
710 default:
711 assert_not_reached();
712 }
713
714 needs_space = true;
715 }
716 }
717
718 typedef struct Member {
719 const char *type;
720 char *interface;
721 char *name;
722 char *signature;
723 char *result;
724 char *value;
725 bool writable;
726 uint64_t flags;
727 } Member;
728
729 static void member_hash_func(const Member *m, struct siphash *state) {
730 uint64_t arity = 1;
731
732 assert(m);
733 assert(m->type);
734
735 string_hash_func(m->type, state);
736
737 arity += !!m->name + !!m->interface;
738
739 uint64_hash_func(&arity, state);
740
741 if (m->name)
742 string_hash_func(m->name, state);
743
744 if (m->interface)
745 string_hash_func(m->interface, state);
746 }
747
748 static int member_compare_func(const Member *x, const Member *y) {
749 int d;
750
751 assert(x);
752 assert(y);
753 assert(x->type);
754 assert(y->type);
755
756 d = strcmp_ptr(x->interface, y->interface);
757 if (d != 0)
758 return d;
759
760 d = strcmp(x->type, y->type);
761 if (d != 0)
762 return d;
763
764 return strcmp_ptr(x->name, y->name);
765 }
766
767 static int member_compare_funcp(Member * const *a, Member * const *b) {
768 return member_compare_func(*a, *b);
769 }
770
771 static Member* member_free(Member *m) {
772 if (!m)
773 return NULL;
774
775 free(m->interface);
776 free(m->name);
777 free(m->signature);
778 free(m->result);
779 free(m->value);
780 return mfree(m);
781 }
782 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
783
784 static Set* member_set_free(Set *s) {
785 return set_free_with_destructor(s, member_free);
786 }
787 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
788
789 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
790 _cleanup_(member_freep) Member *m = NULL;
791 Set *members = userdata;
792 int r;
793
794 assert(interface);
795 assert(members);
796
797 m = new(Member, 1);
798 if (!m)
799 return log_oom();
800
801 *m = (Member) {
802 .type = "interface",
803 .flags = flags,
804 };
805
806 r = free_and_strdup(&m->interface, interface);
807 if (r < 0)
808 return log_oom();
809
810 r = set_put(members, m);
811 if (r == -EEXIST)
812 return log_error_errno(r, "Invalid introspection data: duplicate interface '%s'.", interface);
813 if (r < 0)
814 return log_oom();
815
816 m = NULL;
817 return 0;
818 }
819
820 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
821 _cleanup_(member_freep) Member *m = NULL;
822 Set *members = userdata;
823 int r;
824
825 assert(interface);
826 assert(name);
827
828 m = new(Member, 1);
829 if (!m)
830 return log_oom();
831
832 *m = (Member) {
833 .type = "method",
834 .flags = flags,
835 };
836
837 r = free_and_strdup(&m->interface, interface);
838 if (r < 0)
839 return log_oom();
840
841 r = free_and_strdup(&m->name, name);
842 if (r < 0)
843 return log_oom();
844
845 r = free_and_strdup(&m->signature, signature);
846 if (r < 0)
847 return log_oom();
848
849 r = free_and_strdup(&m->result, result);
850 if (r < 0)
851 return log_oom();
852
853 r = set_put(members, m);
854 if (r == -EEXIST)
855 return log_error_errno(r, "Invalid introspection data: duplicate method '%s' on interface '%s'.", name, interface);
856 if (r < 0)
857 return log_oom();
858
859 m = NULL;
860 return 0;
861 }
862
863 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
864 _cleanup_(member_freep) Member *m = NULL;
865 Set *members = userdata;
866 int r;
867
868 assert(interface);
869 assert(name);
870
871 m = new(Member, 1);
872 if (!m)
873 return log_oom();
874
875 *m = (Member) {
876 .type = "signal",
877 .flags = flags,
878 };
879
880 r = free_and_strdup(&m->interface, interface);
881 if (r < 0)
882 return log_oom();
883
884 r = free_and_strdup(&m->name, name);
885 if (r < 0)
886 return log_oom();
887
888 r = free_and_strdup(&m->signature, signature);
889 if (r < 0)
890 return log_oom();
891
892 r = set_put(members, m);
893 if (r == -EEXIST)
894 return log_error_errno(r, "Invalid introspection data: duplicate signal '%s' on interface '%s'.", name, interface);
895 if (r < 0)
896 return log_oom();
897
898 m = NULL;
899 return 0;
900 }
901
902 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
903 _cleanup_(member_freep) Member *m = NULL;
904 Set *members = userdata;
905 int r;
906
907 assert(interface);
908 assert(name);
909
910 m = new(Member, 1);
911 if (!m)
912 return log_oom();
913
914 *m = (Member) {
915 .type = "property",
916 .flags = flags,
917 .writable = writable,
918 };
919
920 r = free_and_strdup(&m->interface, interface);
921 if (r < 0)
922 return log_oom();
923
924 r = free_and_strdup(&m->name, name);
925 if (r < 0)
926 return log_oom();
927
928 r = free_and_strdup(&m->signature, signature);
929 if (r < 0)
930 return log_oom();
931
932 r = set_put(members, m);
933 if (r == -EEXIST)
934 return log_error_errno(r, "Invalid introspection data: duplicate property '%s' on interface '%s'.", name, interface);
935 if (r < 0)
936 return log_oom();
937
938 m = NULL;
939 return 0;
940 }
941
942 DEFINE_PRIVATE_HASH_OPS(member_hash_ops, Member, member_hash_func, member_compare_func);
943
944 static int introspect(int argc, char **argv, void *userdata) {
945 static const XMLIntrospectOps ops = {
946 .on_interface = on_interface,
947 .on_method = on_method,
948 .on_signal = on_signal,
949 .on_property = on_property,
950 };
951
952 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
953 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_xml = NULL;
954 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
955 _cleanup_(member_set_freep) Set *members = NULL;
956 unsigned name_width, type_width, signature_width, result_width, j, k = 0;
957 Member *m, **sorted = NULL;
958 const char *xml;
959 int r;
960
961 r = acquire_bus(false, &bus);
962 if (r < 0)
963 return r;
964
965 members = set_new(&member_hash_ops);
966 if (!members)
967 return log_oom();
968
969 r = sd_bus_call_method(bus, argv[1], argv[2],
970 "org.freedesktop.DBus.Introspectable", "Introspect",
971 &error, &reply_xml, NULL);
972 if (r < 0)
973 return log_error_errno(r, "Failed to introspect object %s of service %s: %s",
974 argv[2], argv[1], bus_error_message(&error, r));
975
976 r = sd_bus_message_read(reply_xml, "s", &xml);
977 if (r < 0)
978 return bus_log_parse_error(r);
979
980 if (arg_xml_interface) {
981 /* Just dump the received XML and finish */
982 pager_open(arg_pager_flags);
983 puts(xml);
984 return 0;
985 }
986
987 /* First, get list of all properties */
988 r = parse_xml_introspect(argv[2], xml, &ops, members);
989 if (r < 0)
990 return r;
991
992 /* Second, find the current values for them */
993 SET_FOREACH(m, members) {
994 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
995
996 if (!streq(m->type, "property"))
997 continue;
998
999 if (m->value)
1000 continue;
1001
1002 if (argv[3] && !streq(argv[3], m->interface))
1003 continue;
1004
1005 r = sd_bus_call_method(bus, argv[1], argv[2],
1006 "org.freedesktop.DBus.Properties", "GetAll",
1007 &error, &reply, "s", m->interface);
1008 if (r < 0)
1009 return log_error_errno(r, "Failed to get all properties on interface %s: %s",
1010 m->interface, bus_error_message(&error, r));
1011
1012 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
1013 if (r < 0)
1014 return bus_log_parse_error(r);
1015
1016 for (;;) {
1017 Member *z;
1018 _cleanup_free_ char *buf = NULL;
1019 _cleanup_fclose_ FILE *mf = NULL;
1020 size_t sz = 0;
1021 const char *name;
1022
1023 r = sd_bus_message_enter_container(reply, 'e', "sv");
1024 if (r < 0)
1025 return bus_log_parse_error(r);
1026
1027 if (r == 0)
1028 break;
1029
1030 r = sd_bus_message_read(reply, "s", &name);
1031 if (r < 0)
1032 return bus_log_parse_error(r);
1033
1034 r = sd_bus_message_enter_container(reply, 'v', NULL);
1035 if (r < 0)
1036 return bus_log_parse_error(r);
1037
1038 mf = open_memstream_unlocked(&buf, &sz);
1039 if (!mf)
1040 return log_oom();
1041
1042 r = format_cmdline(reply, mf, false);
1043 if (r < 0)
1044 return bus_log_parse_error(r);
1045
1046 mf = safe_fclose(mf);
1047
1048 z = set_get(members, &((Member) {
1049 .type = "property",
1050 .interface = m->interface,
1051 .name = (char*) name }));
1052 if (z)
1053 free_and_replace(z->value, buf);
1054
1055 r = sd_bus_message_exit_container(reply);
1056 if (r < 0)
1057 return bus_log_parse_error(r);
1058
1059 r = sd_bus_message_exit_container(reply);
1060 if (r < 0)
1061 return bus_log_parse_error(r);
1062 }
1063
1064 r = sd_bus_message_exit_container(reply);
1065 if (r < 0)
1066 return bus_log_parse_error(r);
1067 }
1068
1069 name_width = strlen("NAME");
1070 type_width = strlen("TYPE");
1071 signature_width = strlen("SIGNATURE");
1072 result_width = strlen("RESULT/VALUE");
1073
1074 sorted = newa(Member*, set_size(members));
1075
1076 SET_FOREACH(m, members) {
1077 if (argv[3] && !streq(argv[3], m->interface))
1078 continue;
1079
1080 if (m->interface)
1081 name_width = MAX(name_width, strlen(m->interface));
1082 if (m->name)
1083 name_width = MAX(name_width, strlen(m->name) + 1);
1084 if (m->type)
1085 type_width = MAX(type_width, strlen(m->type));
1086 if (m->signature)
1087 signature_width = MAX(signature_width, strlen(m->signature));
1088 if (m->result)
1089 result_width = MAX(result_width, strlen(m->result));
1090 if (m->value)
1091 result_width = MAX(result_width, strlen(m->value));
1092
1093 sorted[k++] = m;
1094 }
1095
1096 if (result_width > 40)
1097 result_width = 40;
1098
1099 typesafe_qsort(sorted, k, member_compare_funcp);
1100
1101 pager_open(arg_pager_flags);
1102
1103 if (arg_legend)
1104 printf("%-*s %-*s %-*s %-*s %s\n",
1105 (int) name_width, "NAME",
1106 (int) type_width, "TYPE",
1107 (int) signature_width, "SIGNATURE",
1108 (int) result_width, "RESULT/VALUE",
1109 "FLAGS");
1110
1111 for (j = 0; j < k; j++) {
1112 _cleanup_free_ char *ellipsized = NULL;
1113 const char *rv;
1114 bool is_interface;
1115
1116 m = sorted[j];
1117
1118 if (argv[3] && !streq(argv[3], m->interface))
1119 continue;
1120
1121 is_interface = streq(m->type, "interface");
1122
1123 if (argv[3] && is_interface)
1124 continue;
1125
1126 if (m->value) {
1127 ellipsized = ellipsize(m->value, result_width, 100);
1128 if (!ellipsized)
1129 return log_oom();
1130
1131 rv = ellipsized;
1132 } else
1133 rv = empty_to_dash(m->result);
1134
1135 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1136 is_interface ? ansi_highlight() : "",
1137 is_interface ? "" : ".",
1138 - !is_interface + (int) name_width,
1139 empty_to_dash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1140 is_interface ? ansi_normal() : "",
1141 (int) type_width, empty_to_dash(m->type),
1142 (int) signature_width, empty_to_dash(m->signature),
1143 (int) result_width, rv,
1144 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1145 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1146 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1147 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1148 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1149 m->writable ? " writable" : "");
1150 }
1151
1152 return 0;
1153 }
1154
1155 static int message_dump(sd_bus_message *m, FILE *f) {
1156 return sd_bus_message_dump(m, f, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
1157 }
1158
1159 static int message_pcap(sd_bus_message *m, FILE *f) {
1160 return bus_message_pcap_frame(m, arg_snaplen, f);
1161 }
1162
1163 static int message_json(sd_bus_message *m, FILE *f) {
1164 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
1165 char e[2];
1166 int r;
1167 usec_t ts;
1168
1169 r = json_transform_message(m, &v);
1170 if (r < 0)
1171 return r;
1172
1173 e[0] = m->header->endian;
1174 e[1] = 0;
1175
1176 ts = m->realtime;
1177 if (ts == 0)
1178 ts = now(CLOCK_REALTIME);
1179
1180 r = json_build(&w, JSON_BUILD_OBJECT(
1181 JSON_BUILD_PAIR("type", JSON_BUILD_STRING(bus_message_type_to_string(m->header->type))),
1182 JSON_BUILD_PAIR("endian", JSON_BUILD_STRING(e)),
1183 JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(m->header->flags)),
1184 JSON_BUILD_PAIR("version", JSON_BUILD_INTEGER(m->header->version)),
1185 JSON_BUILD_PAIR("cookie", JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m))),
1186 JSON_BUILD_PAIR_CONDITION(m->reply_cookie != 0, "reply_cookie", JSON_BUILD_INTEGER(m->reply_cookie)),
1187 JSON_BUILD_PAIR("timestamp-realtime", JSON_BUILD_UNSIGNED(ts)),
1188 JSON_BUILD_PAIR_CONDITION(m->sender, "sender", JSON_BUILD_STRING(m->sender)),
1189 JSON_BUILD_PAIR_CONDITION(m->destination, "destination", JSON_BUILD_STRING(m->destination)),
1190 JSON_BUILD_PAIR_CONDITION(m->path, "path", JSON_BUILD_STRING(m->path)),
1191 JSON_BUILD_PAIR_CONDITION(m->interface, "interface", JSON_BUILD_STRING(m->interface)),
1192 JSON_BUILD_PAIR_CONDITION(m->member, "member", JSON_BUILD_STRING(m->member)),
1193 JSON_BUILD_PAIR_CONDITION(m->monotonic != 0, "monotonic", JSON_BUILD_INTEGER(m->monotonic)),
1194 JSON_BUILD_PAIR_CONDITION(m->realtime != 0, "realtime", JSON_BUILD_INTEGER(m->realtime)),
1195 JSON_BUILD_PAIR_CONDITION(m->seqnum != 0, "seqnum", JSON_BUILD_INTEGER(m->seqnum)),
1196 JSON_BUILD_PAIR_CONDITION(m->error.name, "error_name", JSON_BUILD_STRING(m->error.name)),
1197 JSON_BUILD_PAIR("payload", JSON_BUILD_VARIANT(v))));
1198 if (r < 0)
1199 return log_error_errno(r, "Failed to build JSON object: %m");
1200
1201 json_variant_dump(w, arg_json_format_flags, f, NULL);
1202 return 0;
1203 }
1204
1205 static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f)) {
1206 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1207 _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
1208 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1209 char **i;
1210 uint32_t flags = 0;
1211 const char *unique_name;
1212 bool is_monitor = false;
1213 int r;
1214
1215 r = acquire_bus(true, &bus);
1216 if (r < 0)
1217 return r;
1218
1219 /* upgrade connection; it's not used for anything else after this call */
1220 r = sd_bus_message_new_method_call(bus,
1221 &message,
1222 "org.freedesktop.DBus",
1223 "/org/freedesktop/DBus",
1224 "org.freedesktop.DBus.Monitoring",
1225 "BecomeMonitor");
1226 if (r < 0)
1227 return bus_log_create_error(r);
1228
1229 r = sd_bus_message_open_container(message, 'a', "s");
1230 if (r < 0)
1231 return bus_log_create_error(r);
1232
1233 STRV_FOREACH(i, argv+1) {
1234 _cleanup_free_ char *m = NULL;
1235
1236 if (!sd_bus_service_name_is_valid(*i))
1237 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name '%s'", *i);
1238
1239 m = strjoin("sender='", *i, "'");
1240 if (!m)
1241 return log_oom();
1242
1243 r = sd_bus_message_append_basic(message, 's', m);
1244 if (r < 0)
1245 return bus_log_create_error(r);
1246
1247 free(m);
1248 m = strjoin("destination='", *i, "'");
1249 if (!m)
1250 return log_oom();
1251
1252 r = sd_bus_message_append_basic(message, 's', m);
1253 if (r < 0)
1254 return bus_log_create_error(r);
1255 }
1256
1257 STRV_FOREACH(i, arg_matches) {
1258 r = sd_bus_message_append_basic(message, 's', *i);
1259 if (r < 0)
1260 return bus_log_create_error(r);
1261 }
1262
1263 r = sd_bus_message_close_container(message);
1264 if (r < 0)
1265 return bus_log_create_error(r);
1266
1267 r = sd_bus_message_append_basic(message, 'u', &flags);
1268 if (r < 0)
1269 return bus_log_create_error(r);
1270
1271 r = sd_bus_call(bus, message, arg_timeout, &error, NULL);
1272 if (r < 0)
1273 return log_error_errno(r, "Call to org.freedesktop.DBus.Monitoring.BecomeMonitor failed: %s",
1274 bus_error_message(&error, r));
1275
1276 r = sd_bus_get_unique_name(bus, &unique_name);
1277 if (r < 0)
1278 return log_error_errno(r, "Failed to get unique name: %m");
1279
1280 log_info("Monitoring bus message stream.");
1281
1282 for (;;) {
1283 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1284
1285 r = sd_bus_process(bus, &m);
1286 if (r < 0)
1287 return log_error_errno(r, "Failed to process bus: %m");
1288
1289 if (!is_monitor) {
1290 const char *name;
1291
1292 /* wait until we lose our unique name */
1293 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameLost") <= 0)
1294 continue;
1295
1296 r = sd_bus_message_read(m, "s", &name);
1297 if (r < 0)
1298 return bus_log_parse_error(r);
1299
1300 if (streq(name, unique_name))
1301 is_monitor = true;
1302
1303 continue;
1304 }
1305
1306 if (m) {
1307 dump(m, stdout);
1308 fflush(stdout);
1309
1310 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
1311 log_info("Connection terminated, exiting.");
1312 return 0;
1313 }
1314
1315 continue;
1316 }
1317
1318 if (r > 0)
1319 continue;
1320
1321 r = sd_bus_wait(bus, UINT64_MAX);
1322 if (r < 0)
1323 return log_error_errno(r, "Failed to wait for bus: %m");
1324 }
1325 }
1326
1327 static int verb_monitor(int argc, char **argv, void *userdata) {
1328 return monitor(argc, argv, (arg_json_format_flags & JSON_FORMAT_OFF) ? message_dump : message_json);
1329 }
1330
1331 static int verb_capture(int argc, char **argv, void *userdata) {
1332 int r;
1333
1334 if (isatty(fileno(stdout)) > 0)
1335 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1336 "Refusing to write message data to console, please redirect output to a file.");
1337
1338 bus_pcap_header(arg_snaplen, stdout);
1339
1340 r = monitor(argc, argv, message_pcap);
1341 if (r < 0)
1342 return r;
1343
1344 r = fflush_and_check(stdout);
1345 if (r < 0)
1346 return log_error_errno(r, "Couldn't write capture file: %m");
1347
1348 return r;
1349 }
1350
1351 static int status(int argc, char **argv, void *userdata) {
1352 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1353 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
1354 pid_t pid;
1355 int r;
1356
1357 r = acquire_bus(false, &bus);
1358 if (r < 0)
1359 return r;
1360
1361 pager_open(arg_pager_flags);
1362
1363 if (!isempty(argv[1])) {
1364 r = parse_pid(argv[1], &pid);
1365 if (r < 0)
1366 r = sd_bus_get_name_creds(
1367 bus,
1368 argv[1],
1369 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1370 &creds);
1371 else
1372 r = sd_bus_creds_new_from_pid(
1373 &creds,
1374 pid,
1375 _SD_BUS_CREDS_ALL);
1376 } else {
1377 const char *scope, *address;
1378 sd_id128_t bus_id;
1379
1380 r = sd_bus_get_address(bus, &address);
1381 if (r >= 0)
1382 printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal());
1383
1384 r = sd_bus_get_scope(bus, &scope);
1385 if (r >= 0)
1386 printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal());
1387
1388 r = sd_bus_get_bus_id(bus, &bus_id);
1389 if (r >= 0)
1390 printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n",
1391 ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal());
1392
1393 r = sd_bus_get_owner_creds(
1394 bus,
1395 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1396 &creds);
1397 }
1398
1399 if (r < 0)
1400 return log_error_errno(r, "Failed to get credentials: %m");
1401
1402 bus_creds_dump(creds, NULL, false);
1403 return 0;
1404 }
1405
1406 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1407 char **p;
1408 int r;
1409
1410 assert(m);
1411 assert(signature);
1412 assert(x);
1413
1414 p = *x;
1415
1416 for (;;) {
1417 const char *v;
1418 char t;
1419
1420 t = *signature;
1421 v = *p;
1422
1423 if (t == 0)
1424 break;
1425 if (!v)
1426 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1427 "Too few parameters for signature.");
1428
1429 signature++;
1430 p++;
1431
1432 switch (t) {
1433
1434 case SD_BUS_TYPE_BOOLEAN:
1435
1436 r = parse_boolean(v);
1437 if (r < 0)
1438 return log_error_errno(r, "Failed to parse '%s' as boolean: %m", v);
1439
1440 r = sd_bus_message_append_basic(m, t, &r);
1441 break;
1442
1443 case SD_BUS_TYPE_BYTE: {
1444 uint8_t z;
1445
1446 r = safe_atou8(v, &z);
1447 if (r < 0)
1448 return log_error_errno(r, "Failed to parse '%s' as byte (unsigned 8bit integer): %m", v);
1449
1450 r = sd_bus_message_append_basic(m, t, &z);
1451 break;
1452 }
1453
1454 case SD_BUS_TYPE_INT16: {
1455 int16_t z;
1456
1457 r = safe_atoi16(v, &z);
1458 if (r < 0)
1459 return log_error_errno(r, "Failed to parse '%s' as signed 16bit integer: %m", v);
1460
1461 r = sd_bus_message_append_basic(m, t, &z);
1462 break;
1463 }
1464
1465 case SD_BUS_TYPE_UINT16: {
1466 uint16_t z;
1467
1468 r = safe_atou16(v, &z);
1469 if (r < 0)
1470 return log_error_errno(r, "Failed to parse '%s' as unsigned 16bit integer: %m", v);
1471
1472 r = sd_bus_message_append_basic(m, t, &z);
1473 break;
1474 }
1475
1476 case SD_BUS_TYPE_INT32: {
1477 int32_t z;
1478
1479 r = safe_atoi32(v, &z);
1480 if (r < 0)
1481 return log_error_errno(r, "Failed to parse '%s' as signed 32bit integer: %m", v);
1482
1483 r = sd_bus_message_append_basic(m, t, &z);
1484 break;
1485 }
1486
1487 case SD_BUS_TYPE_UINT32: {
1488 uint32_t z;
1489
1490 r = safe_atou32(v, &z);
1491 if (r < 0)
1492 return log_error_errno(r, "Failed to parse '%s' as unsigned 32bit integer: %m", v);
1493
1494 r = sd_bus_message_append_basic(m, t, &z);
1495 break;
1496 }
1497
1498 case SD_BUS_TYPE_INT64: {
1499 int64_t z;
1500
1501 r = safe_atoi64(v, &z);
1502 if (r < 0)
1503 return log_error_errno(r, "Failed to parse '%s' as signed 64bit integer: %m", v);
1504
1505 r = sd_bus_message_append_basic(m, t, &z);
1506 break;
1507 }
1508
1509 case SD_BUS_TYPE_UINT64: {
1510 uint64_t z;
1511
1512 r = safe_atou64(v, &z);
1513 if (r < 0)
1514 return log_error_errno(r, "Failed to parse '%s' as unsigned 64bit integer: %m", v);
1515
1516 r = sd_bus_message_append_basic(m, t, &z);
1517 break;
1518 }
1519
1520 case SD_BUS_TYPE_DOUBLE: {
1521 double z;
1522
1523 r = safe_atod(v, &z);
1524 if (r < 0)
1525 return log_error_errno(r, "Failed to parse '%s' as double precision floating point: %m", v);
1526
1527 r = sd_bus_message_append_basic(m, t, &z);
1528 break;
1529 }
1530
1531 case SD_BUS_TYPE_STRING:
1532 case SD_BUS_TYPE_OBJECT_PATH:
1533 case SD_BUS_TYPE_SIGNATURE:
1534
1535 r = sd_bus_message_append_basic(m, t, v);
1536 break;
1537
1538 case SD_BUS_TYPE_ARRAY: {
1539 uint32_t n;
1540 size_t k;
1541
1542 r = safe_atou32(v, &n);
1543 if (r < 0)
1544 return log_error_errno(r, "Failed to parse '%s' number of array entries: %m", v);
1545
1546 r = signature_element_length(signature, &k);
1547 if (r < 0)
1548 return log_error_errno(r, "Invalid array signature: %m");
1549
1550 {
1551 char s[k + 1];
1552 memcpy(s, signature, k);
1553 s[k] = 0;
1554
1555 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1556 if (r < 0)
1557 return bus_log_create_error(r);
1558
1559 for (unsigned i = 0; i < n; i++) {
1560 r = message_append_cmdline(m, s, &p);
1561 if (r < 0)
1562 return r;
1563 }
1564 }
1565
1566 signature += k;
1567
1568 r = sd_bus_message_close_container(m);
1569 break;
1570 }
1571
1572 case SD_BUS_TYPE_VARIANT:
1573 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1574 if (r < 0)
1575 return bus_log_create_error(r);
1576
1577 r = message_append_cmdline(m, v, &p);
1578 if (r < 0)
1579 return r;
1580
1581 r = sd_bus_message_close_container(m);
1582 break;
1583
1584 case SD_BUS_TYPE_STRUCT_BEGIN:
1585 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1586 size_t k;
1587
1588 signature--;
1589 p--;
1590
1591 r = signature_element_length(signature, &k);
1592 if (r < 0)
1593 return log_error_errno(r, "Invalid struct/dict entry signature: %m");
1594
1595 {
1596 char s[k-1];
1597 memcpy(s, signature + 1, k - 2);
1598 s[k - 2] = 0;
1599
1600 const char ctype = t == SD_BUS_TYPE_STRUCT_BEGIN ?
1601 SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
1602 r = sd_bus_message_open_container(m, ctype, s);
1603 if (r < 0)
1604 return bus_log_create_error(r);
1605
1606 r = message_append_cmdline(m, s, &p);
1607 if (r < 0)
1608 return r;
1609 }
1610
1611 signature += k;
1612
1613 r = sd_bus_message_close_container(m);
1614 break;
1615 }
1616
1617 case SD_BUS_TYPE_UNIX_FD:
1618 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1619 "UNIX file descriptor not supported as type.");
1620
1621 default:
1622 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1623 "Unknown signature type %c.", t);
1624 }
1625
1626 if (r < 0)
1627 return bus_log_create_error(r);
1628 }
1629
1630 *x = p;
1631 return 0;
1632 }
1633
1634 static int json_transform_one(sd_bus_message *m, JsonVariant **ret);
1635
1636 static int json_transform_array_or_struct(sd_bus_message *m, JsonVariant **ret) {
1637 JsonVariant **elements = NULL;
1638 size_t n_elements = 0;
1639 int r;
1640
1641 assert(m);
1642 assert(ret);
1643
1644 for (;;) {
1645 r = sd_bus_message_at_end(m, false);
1646 if (r < 0) {
1647 bus_log_parse_error(r);
1648 goto finish;
1649 }
1650 if (r > 0)
1651 break;
1652
1653 if (!GREEDY_REALLOC(elements, n_elements + 1)) {
1654 r = log_oom();
1655 goto finish;
1656 }
1657
1658 r = json_transform_one(m, elements + n_elements);
1659 if (r < 0)
1660 goto finish;
1661
1662 n_elements++;
1663 }
1664
1665 r = json_variant_new_array(ret, elements, n_elements);
1666
1667 finish:
1668 json_variant_unref_many(elements, n_elements);
1669 free(elements);
1670
1671 return r;
1672 }
1673
1674 static int json_transform_variant(sd_bus_message *m, const char *contents, JsonVariant **ret) {
1675 _cleanup_(json_variant_unrefp) JsonVariant *value = NULL;
1676 int r;
1677
1678 assert(m);
1679 assert(contents);
1680 assert(ret);
1681
1682 r = json_transform_one(m, &value);
1683 if (r < 0)
1684 return r;
1685
1686 r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(contents)),
1687 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(value))));
1688 if (r < 0)
1689 return log_oom();
1690
1691 return r;
1692 }
1693
1694 static int json_transform_dict_array(sd_bus_message *m, JsonVariant **ret) {
1695 JsonVariant **elements = NULL;
1696 size_t n_elements = 0;
1697 int r;
1698
1699 assert(m);
1700 assert(ret);
1701
1702 for (;;) {
1703 const char *contents;
1704 char type;
1705
1706 r = sd_bus_message_at_end(m, false);
1707 if (r < 0) {
1708 bus_log_parse_error(r);
1709 goto finish;
1710 }
1711 if (r > 0)
1712 break;
1713
1714 r = sd_bus_message_peek_type(m, &type, &contents);
1715 if (r < 0)
1716 return r;
1717
1718 assert(type == 'e');
1719
1720 if (!GREEDY_REALLOC(elements, n_elements + 2)) {
1721 r = log_oom();
1722 goto finish;
1723 }
1724
1725 r = sd_bus_message_enter_container(m, type, contents);
1726 if (r < 0) {
1727 bus_log_parse_error(r);
1728 goto finish;
1729 }
1730
1731 r = json_transform_one(m, elements + n_elements);
1732 if (r < 0)
1733 goto finish;
1734
1735 n_elements++;
1736
1737 r = json_transform_one(m, elements + n_elements);
1738 if (r < 0)
1739 goto finish;
1740
1741 n_elements++;
1742
1743 r = sd_bus_message_exit_container(m);
1744 if (r < 0) {
1745 bus_log_parse_error(r);
1746 goto finish;
1747 }
1748 }
1749
1750 r = json_variant_new_object(ret, elements, n_elements);
1751
1752 finish:
1753 json_variant_unref_many(elements, n_elements);
1754 free(elements);
1755
1756 return r;
1757 }
1758
1759 static int json_transform_one(sd_bus_message *m, JsonVariant **ret) {
1760 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1761 const char *contents;
1762 char type;
1763 int r;
1764
1765 assert(m);
1766 assert(ret);
1767
1768 r = sd_bus_message_peek_type(m, &type, &contents);
1769 if (r < 0)
1770 return bus_log_parse_error(r);
1771
1772 switch (type) {
1773
1774 case SD_BUS_TYPE_BYTE: {
1775 uint8_t b;
1776
1777 r = sd_bus_message_read_basic(m, type, &b);
1778 if (r < 0)
1779 return bus_log_parse_error(r);
1780
1781 r = json_variant_new_unsigned(&v, b);
1782 if (r < 0)
1783 return log_error_errno(r, "Failed to transform byte: %m");
1784
1785 break;
1786 }
1787
1788 case SD_BUS_TYPE_BOOLEAN: {
1789 int b;
1790
1791 r = sd_bus_message_read_basic(m, type, &b);
1792 if (r < 0)
1793 return bus_log_parse_error(r);
1794
1795 r = json_variant_new_boolean(&v, b);
1796 if (r < 0)
1797 return log_error_errno(r, "Failed to transform boolean: %m");
1798
1799 break;
1800 }
1801
1802 case SD_BUS_TYPE_INT16: {
1803 int16_t b;
1804
1805 r = sd_bus_message_read_basic(m, type, &b);
1806 if (r < 0)
1807 return bus_log_parse_error(r);
1808
1809 r = json_variant_new_integer(&v, b);
1810 if (r < 0)
1811 return log_error_errno(r, "Failed to transform int16: %m");
1812
1813 break;
1814 }
1815
1816 case SD_BUS_TYPE_UINT16: {
1817 uint16_t b;
1818
1819 r = sd_bus_message_read_basic(m, type, &b);
1820 if (r < 0)
1821 return bus_log_parse_error(r);
1822
1823 r = json_variant_new_unsigned(&v, b);
1824 if (r < 0)
1825 return log_error_errno(r, "Failed to transform uint16: %m");
1826
1827 break;
1828 }
1829
1830 case SD_BUS_TYPE_INT32: {
1831 int32_t b;
1832
1833 r = sd_bus_message_read_basic(m, type, &b);
1834 if (r < 0)
1835 return bus_log_parse_error(r);
1836
1837 r = json_variant_new_integer(&v, b);
1838 if (r < 0)
1839 return log_error_errno(r, "Failed to transform int32: %m");
1840
1841 break;
1842 }
1843
1844 case SD_BUS_TYPE_UINT32: {
1845 uint32_t b;
1846
1847 r = sd_bus_message_read_basic(m, type, &b);
1848 if (r < 0)
1849 return bus_log_parse_error(r);
1850
1851 r = json_variant_new_unsigned(&v, b);
1852 if (r < 0)
1853 return log_error_errno(r, "Failed to transform uint32: %m");
1854
1855 break;
1856 }
1857
1858 case SD_BUS_TYPE_INT64: {
1859 int64_t b;
1860
1861 r = sd_bus_message_read_basic(m, type, &b);
1862 if (r < 0)
1863 return bus_log_parse_error(r);
1864
1865 r = json_variant_new_integer(&v, b);
1866 if (r < 0)
1867 return log_error_errno(r, "Failed to transform int64: %m");
1868
1869 break;
1870 }
1871
1872 case SD_BUS_TYPE_UINT64: {
1873 uint64_t b;
1874
1875 r = sd_bus_message_read_basic(m, type, &b);
1876 if (r < 0)
1877 return bus_log_parse_error(r);
1878
1879 r = json_variant_new_unsigned(&v, b);
1880 if (r < 0)
1881 return log_error_errno(r, "Failed to transform uint64: %m");
1882
1883 break;
1884 }
1885
1886 case SD_BUS_TYPE_DOUBLE: {
1887 double d;
1888
1889 r = sd_bus_message_read_basic(m, type, &d);
1890 if (r < 0)
1891 return bus_log_parse_error(r);
1892
1893 r = json_variant_new_real(&v, d);
1894 if (r < 0)
1895 return log_error_errno(r, "Failed to transform double: %m");
1896
1897 break;
1898 }
1899
1900 case SD_BUS_TYPE_STRING:
1901 case SD_BUS_TYPE_OBJECT_PATH:
1902 case SD_BUS_TYPE_SIGNATURE: {
1903 const char *s;
1904
1905 r = sd_bus_message_read_basic(m, type, &s);
1906 if (r < 0)
1907 return bus_log_parse_error(r);
1908
1909 r = json_variant_new_string(&v, s);
1910 if (r < 0)
1911 return log_error_errno(r, "Failed to transform double: %m");
1912
1913 break;
1914 }
1915
1916 case SD_BUS_TYPE_UNIX_FD:
1917 r = sd_bus_message_read_basic(m, type, NULL);
1918 if (r < 0)
1919 return bus_log_parse_error(r);
1920
1921 r = json_variant_new_null(&v);
1922 if (r < 0)
1923 return log_error_errno(r, "Failed to transform fd: %m");
1924
1925 break;
1926
1927 case SD_BUS_TYPE_ARRAY:
1928 case SD_BUS_TYPE_VARIANT:
1929 case SD_BUS_TYPE_STRUCT:
1930 r = sd_bus_message_enter_container(m, type, contents);
1931 if (r < 0)
1932 return bus_log_parse_error(r);
1933
1934 if (type == SD_BUS_TYPE_VARIANT)
1935 r = json_transform_variant(m, contents, &v);
1936 else if (type == SD_BUS_TYPE_ARRAY && contents[0] == '{')
1937 r = json_transform_dict_array(m, &v);
1938 else
1939 r = json_transform_array_or_struct(m, &v);
1940 if (r < 0)
1941 return r;
1942
1943 r = sd_bus_message_exit_container(m);
1944 if (r < 0)
1945 return bus_log_parse_error(r);
1946
1947 break;
1948
1949 default:
1950 assert_not_reached();
1951 }
1952
1953 *ret = TAKE_PTR(v);
1954 return 0;
1955 }
1956
1957 static int json_transform_message(sd_bus_message *m, JsonVariant **ret) {
1958 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1959 const char *type;
1960 int r;
1961
1962 assert(m);
1963 assert(ret);
1964
1965 assert_se(type = sd_bus_message_get_signature(m, false));
1966
1967 r = json_transform_array_or_struct(m, &v);
1968 if (r < 0)
1969 return r;
1970
1971 r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(type)),
1972 JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(v))));
1973 if (r < 0)
1974 return log_oom();
1975
1976 return 0;
1977 }
1978
1979 static int call(int argc, char **argv, void *userdata) {
1980 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1981 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1982 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
1983 int r;
1984
1985 r = acquire_bus(false, &bus);
1986 if (r < 0)
1987 return r;
1988
1989 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1990 if (r < 0)
1991 return bus_log_create_error(r);
1992
1993 r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1994 if (r < 0)
1995 return bus_log_create_error(r);
1996
1997 r = sd_bus_message_set_auto_start(m, arg_auto_start);
1998 if (r < 0)
1999 return bus_log_create_error(r);
2000
2001 r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
2002 if (r < 0)
2003 return bus_log_create_error(r);
2004
2005 if (!isempty(argv[5])) {
2006 char **p;
2007
2008 p = argv+6;
2009
2010 r = message_append_cmdline(m, argv[5], &p);
2011 if (r < 0)
2012 return r;
2013
2014 if (*p)
2015 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2016 "Too many parameters for signature.");
2017 }
2018
2019 if (!arg_expect_reply) {
2020 r = sd_bus_send(bus, m, NULL);
2021 if (r < 0)
2022 return log_error_errno(r, "Failed to send message: %m");
2023
2024 return 0;
2025 }
2026
2027 r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
2028 if (r < 0)
2029 return log_error_errno(r, "Call failed: %s", bus_error_message(&error, r));
2030
2031 r = sd_bus_message_is_empty(reply);
2032 if (r < 0)
2033 return bus_log_parse_error(r);
2034
2035 if (r == 0 && !arg_quiet) {
2036
2037 if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
2038 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
2039
2040 if (arg_json_format_flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
2041 pager_open(arg_pager_flags);
2042
2043 r = json_transform_message(reply, &v);
2044 if (r < 0)
2045 return r;
2046
2047 json_variant_dump(v, arg_json_format_flags, NULL, NULL);
2048
2049 } else if (arg_verbose) {
2050 pager_open(arg_pager_flags);
2051
2052 r = sd_bus_message_dump(reply, stdout, 0);
2053 if (r < 0)
2054 return r;
2055 } else {
2056
2057 fputs(sd_bus_message_get_signature(reply, true), stdout);
2058 fputc(' ', stdout);
2059
2060 r = format_cmdline(reply, stdout, false);
2061 if (r < 0)
2062 return bus_log_parse_error(r);
2063
2064 fputc('\n', stdout);
2065 }
2066 }
2067
2068 return 0;
2069 }
2070
2071 static int emit_signal(int argc, char **argv, void *userdata) {
2072 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2073 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2074 int r;
2075
2076 r = acquire_bus(false, &bus);
2077 if (r < 0)
2078 return r;
2079
2080 r = sd_bus_message_new_signal(bus, &m, argv[1], argv[2], argv[3]);
2081 if (r < 0)
2082 return bus_log_create_error(r);
2083
2084 if (arg_destination) {
2085 r = sd_bus_message_set_destination(m, arg_destination);
2086 if (r < 0)
2087 return bus_log_create_error(r);
2088 }
2089
2090 r = sd_bus_message_set_auto_start(m, arg_auto_start);
2091 if (r < 0)
2092 return bus_log_create_error(r);
2093
2094 if (!isempty(argv[4])) {
2095 char **p;
2096
2097 p = argv+5;
2098
2099 r = message_append_cmdline(m, argv[4], &p);
2100 if (r < 0)
2101 return r;
2102
2103 if (*p)
2104 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2105 "Too many parameters for signature.");
2106 }
2107
2108 r = sd_bus_send(bus, m, NULL);
2109 if (r < 0)
2110 return log_error_errno(r, "Failed to send signal: %m");
2111
2112 return 0;
2113 }
2114
2115 static int get_property(int argc, char **argv, void *userdata) {
2116 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2117 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2118 char **i;
2119 int r;
2120
2121 r = acquire_bus(false, &bus);
2122 if (r < 0)
2123 return r;
2124
2125 STRV_FOREACH(i, argv + 4) {
2126 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2127 const char *contents = NULL;
2128 char type;
2129
2130 r = sd_bus_call_method(bus, argv[1], argv[2],
2131 "org.freedesktop.DBus.Properties", "Get",
2132 &error, &reply, "ss", argv[3], *i);
2133 if (r < 0)
2134 return log_error_errno(r, "Failed to get property %s on interface %s: %s",
2135 *i, argv[3],
2136 bus_error_message(&error, r));
2137
2138 r = sd_bus_message_peek_type(reply, &type, &contents);
2139 if (r < 0)
2140 return bus_log_parse_error(r);
2141
2142 r = sd_bus_message_enter_container(reply, 'v', contents);
2143 if (r < 0)
2144 return bus_log_parse_error(r);
2145
2146 if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
2147 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
2148
2149 if (arg_json_format_flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
2150 pager_open(arg_pager_flags);
2151
2152 r = json_transform_variant(reply, contents, &v);
2153 if (r < 0)
2154 return r;
2155
2156 json_variant_dump(v, arg_json_format_flags, NULL, NULL);
2157
2158 } else if (arg_verbose) {
2159 pager_open(arg_pager_flags);
2160
2161 r = sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY);
2162 if (r < 0)
2163 return r;
2164 } else {
2165 fputs(contents, stdout);
2166 fputc(' ', stdout);
2167
2168 r = format_cmdline(reply, stdout, false);
2169 if (r < 0)
2170 return bus_log_parse_error(r);
2171
2172 fputc('\n', stdout);
2173 }
2174
2175 r = sd_bus_message_exit_container(reply);
2176 if (r < 0)
2177 return bus_log_parse_error(r);
2178 }
2179
2180 return 0;
2181 }
2182
2183 static int set_property(int argc, char **argv, void *userdata) {
2184 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2185 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2186 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2187 char **p;
2188 int r;
2189
2190 r = acquire_bus(false, &bus);
2191 if (r < 0)
2192 return r;
2193
2194 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2],
2195 "org.freedesktop.DBus.Properties", "Set");
2196 if (r < 0)
2197 return bus_log_create_error(r);
2198
2199 r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
2200 if (r < 0)
2201 return bus_log_create_error(r);
2202
2203 r = sd_bus_message_open_container(m, 'v', argv[5]);
2204 if (r < 0)
2205 return bus_log_create_error(r);
2206
2207 p = argv + 6;
2208 r = message_append_cmdline(m, argv[5], &p);
2209 if (r < 0)
2210 return r;
2211
2212 r = sd_bus_message_close_container(m);
2213 if (r < 0)
2214 return bus_log_create_error(r);
2215
2216 if (*p)
2217 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
2218
2219 r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
2220 if (r < 0)
2221 return log_error_errno(r, "Failed to set property %s on interface %s: %s",
2222 argv[4], argv[3],
2223 bus_error_message(&error, r));
2224
2225 return 0;
2226 }
2227
2228 static int help(void) {
2229 _cleanup_free_ char *link = NULL;
2230 int r;
2231
2232 r = terminal_urlify_man("busctl", "1", &link);
2233 if (r < 0)
2234 return log_oom();
2235
2236 pager_open(arg_pager_flags);
2237
2238 printf("%s [OPTIONS...] COMMAND ...\n\n"
2239 "%sIntrospect the D-Bus IPC bus.%s\n"
2240 "\nCommands:\n"
2241 " list List bus names\n"
2242 " status [SERVICE] Show bus service, process or bus owner credentials\n"
2243 " monitor [SERVICE...] Show bus traffic\n"
2244 " capture [SERVICE...] Capture bus traffic as pcap\n"
2245 " tree [SERVICE...] Show object tree of service\n"
2246 " introspect SERVICE OBJECT [INTERFACE]\n"
2247 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
2248 " Call a method\n"
2249 " emit OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT...]]\n"
2250 " Emit a signal\n"
2251 " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
2252 " Get property value\n"
2253 " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
2254 " Set property value\n"
2255 " help Show this help\n"
2256 "\nOptions:\n"
2257 " -h --help Show this help\n"
2258 " --version Show package version\n"
2259 " --no-pager Do not pipe output into a pager\n"
2260 " --no-legend Do not show the headers and footers\n"
2261 " -l --full Do not ellipsize output\n"
2262 " --system Connect to system bus\n"
2263 " --user Connect to user bus\n"
2264 " -H --host=[USER@]HOST Operate on remote host\n"
2265 " -M --machine=CONTAINER Operate on local container\n"
2266 " --address=ADDRESS Connect to bus specified by address\n"
2267 " --show-machine Show machine ID column in list\n"
2268 " --unique Only show unique names\n"
2269 " --acquired Only show acquired names\n"
2270 " --activatable Only show activatable names\n"
2271 " --match=MATCH Only show matching messages\n"
2272 " --size=SIZE Maximum length of captured packet\n"
2273 " --list Don't show tree, but simple object path list\n"
2274 " -q --quiet Don't show method call reply\n"
2275 " --verbose Show result values in long format\n"
2276 " --json=MODE Output as JSON\n"
2277 " -j Same as --json=pretty on tty, --json=short otherwise\n"
2278 " --expect-reply=BOOL Expect a method call reply\n"
2279 " --auto-start=BOOL Auto-start destination service\n"
2280 " --allow-interactive-authorization=BOOL\n"
2281 " Allow interactive authorization for operation\n"
2282 " --timeout=SECS Maximum time to wait for method call completion\n"
2283 " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
2284 " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n"
2285 " system\n"
2286 " --destination=SERVICE Destination service of a signal\n"
2287 "\nSee the %s for details.\n",
2288 program_invocation_short_name,
2289 ansi_highlight(),
2290 ansi_normal(),
2291 link);
2292
2293 return 0;
2294 }
2295
2296 static int verb_help(int argc, char **argv, void *userdata) {
2297 return help();
2298 }
2299
2300 static int parse_argv(int argc, char *argv[]) {
2301
2302 enum {
2303 ARG_VERSION = 0x100,
2304 ARG_NO_PAGER,
2305 ARG_NO_LEGEND,
2306 ARG_SYSTEM,
2307 ARG_USER,
2308 ARG_ADDRESS,
2309 ARG_MATCH,
2310 ARG_SHOW_MACHINE,
2311 ARG_UNIQUE,
2312 ARG_ACQUIRED,
2313 ARG_ACTIVATABLE,
2314 ARG_SIZE,
2315 ARG_LIST,
2316 ARG_VERBOSE,
2317 ARG_XML_INTERFACE,
2318 ARG_EXPECT_REPLY,
2319 ARG_AUTO_START,
2320 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
2321 ARG_TIMEOUT,
2322 ARG_AUGMENT_CREDS,
2323 ARG_WATCH_BIND,
2324 ARG_JSON,
2325 ARG_DESTINATION,
2326 };
2327
2328 static const struct option options[] = {
2329 { "help", no_argument, NULL, 'h' },
2330 { "version", no_argument, NULL, ARG_VERSION },
2331 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
2332 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
2333 { "full", no_argument, NULL, 'l' },
2334 { "system", no_argument, NULL, ARG_SYSTEM },
2335 { "user", no_argument, NULL, ARG_USER },
2336 { "address", required_argument, NULL, ARG_ADDRESS },
2337 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
2338 { "unique", no_argument, NULL, ARG_UNIQUE },
2339 { "acquired", no_argument, NULL, ARG_ACQUIRED },
2340 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
2341 { "match", required_argument, NULL, ARG_MATCH },
2342 { "host", required_argument, NULL, 'H' },
2343 { "machine", required_argument, NULL, 'M' },
2344 { "size", required_argument, NULL, ARG_SIZE },
2345 { "list", no_argument, NULL, ARG_LIST },
2346 { "quiet", no_argument, NULL, 'q' },
2347 { "verbose", no_argument, NULL, ARG_VERBOSE },
2348 { "xml-interface", no_argument, NULL, ARG_XML_INTERFACE },
2349 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
2350 { "auto-start", required_argument, NULL, ARG_AUTO_START },
2351 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
2352 { "timeout", required_argument, NULL, ARG_TIMEOUT },
2353 { "augment-creds", required_argument, NULL, ARG_AUGMENT_CREDS },
2354 { "watch-bind", required_argument, NULL, ARG_WATCH_BIND },
2355 { "json", required_argument, NULL, ARG_JSON },
2356 { "destination", required_argument, NULL, ARG_DESTINATION },
2357 {},
2358 };
2359
2360 int c, r;
2361
2362 assert(argc >= 0);
2363 assert(argv);
2364
2365 while ((c = getopt_long(argc, argv, "hH:M:qjl", options, NULL)) >= 0)
2366
2367 switch (c) {
2368
2369 case 'h':
2370 return help();
2371
2372 case ARG_VERSION:
2373 return version();
2374
2375 case ARG_NO_PAGER:
2376 arg_pager_flags |= PAGER_DISABLE;
2377 break;
2378
2379 case ARG_NO_LEGEND:
2380 arg_legend = false;
2381 break;
2382
2383 case 'l':
2384 arg_full = true;
2385 break;
2386
2387 case ARG_USER:
2388 arg_user = true;
2389 break;
2390
2391 case ARG_SYSTEM:
2392 arg_user = false;
2393 break;
2394
2395 case ARG_ADDRESS:
2396 arg_address = optarg;
2397 break;
2398
2399 case ARG_SHOW_MACHINE:
2400 arg_show_machine = true;
2401 break;
2402
2403 case ARG_UNIQUE:
2404 arg_unique = true;
2405 break;
2406
2407 case ARG_ACQUIRED:
2408 arg_acquired = true;
2409 break;
2410
2411 case ARG_ACTIVATABLE:
2412 arg_activatable = true;
2413 break;
2414
2415 case ARG_MATCH:
2416 if (strv_extend(&arg_matches, optarg) < 0)
2417 return log_oom();
2418 break;
2419
2420 case ARG_SIZE: {
2421 uint64_t sz;
2422
2423 r = parse_size(optarg, 1024, &sz);
2424 if (r < 0)
2425 return log_error_errno(r, "Failed to parse size '%s': %m", optarg);
2426
2427 if ((uint64_t) (size_t) sz != sz)
2428 return log_error_errno(SYNTHETIC_ERRNO(E2BIG),
2429 "Size out of range.");
2430
2431 arg_snaplen = (size_t) sz;
2432 break;
2433 }
2434
2435 case ARG_LIST:
2436 arg_list = true;
2437 break;
2438
2439 case 'H':
2440 arg_transport = BUS_TRANSPORT_REMOTE;
2441 arg_host = optarg;
2442 break;
2443
2444 case 'M':
2445 arg_transport = BUS_TRANSPORT_MACHINE;
2446 arg_host = optarg;
2447 break;
2448
2449 case 'q':
2450 arg_quiet = true;
2451 break;
2452
2453 case ARG_VERBOSE:
2454 arg_verbose = true;
2455 break;
2456
2457 case ARG_XML_INTERFACE:
2458 arg_xml_interface = true;
2459 break;
2460
2461 case ARG_EXPECT_REPLY:
2462 r = parse_boolean_argument("--expect-reply=", optarg, &arg_expect_reply);
2463 if (r < 0)
2464 return r;
2465 break;
2466
2467 case ARG_AUTO_START:
2468 r = parse_boolean_argument("--auto-start=", optarg, &arg_auto_start);
2469 if (r < 0)
2470 return r;
2471 break;
2472
2473 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
2474 r = parse_boolean_argument("--allow-interactive-authorization=", optarg,
2475 &arg_allow_interactive_authorization);
2476 if (r < 0)
2477 return r;
2478 break;
2479
2480 case ARG_TIMEOUT:
2481 r = parse_sec(optarg, &arg_timeout);
2482 if (r < 0)
2483 return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", optarg);
2484
2485 break;
2486
2487 case ARG_AUGMENT_CREDS:
2488 r = parse_boolean_argument("--augment-creds=", optarg, &arg_augment_creds);
2489 if (r < 0)
2490 return r;
2491 break;
2492
2493 case ARG_WATCH_BIND:
2494 r = parse_boolean_argument("--watch-bind=", optarg, &arg_watch_bind);
2495 if (r < 0)
2496 return r;
2497 break;
2498
2499 case 'j':
2500 arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO;
2501 break;
2502
2503 case ARG_JSON:
2504 r = parse_json_argument(optarg, &arg_json_format_flags);
2505 if (r <= 0)
2506 return r;
2507
2508 break;
2509
2510 case ARG_DESTINATION:
2511 arg_destination = optarg;
2512 break;
2513
2514 case '?':
2515 return -EINVAL;
2516
2517 default:
2518 assert_not_reached();
2519 }
2520
2521 return 1;
2522 }
2523
2524 static int busctl_main(int argc, char *argv[]) {
2525 static const Verb verbs[] = {
2526 { "list", VERB_ANY, 1, VERB_DEFAULT, list_bus_names },
2527 { "status", VERB_ANY, 2, 0, status },
2528 { "monitor", VERB_ANY, VERB_ANY, 0, verb_monitor },
2529 { "capture", VERB_ANY, VERB_ANY, 0, verb_capture },
2530 { "tree", VERB_ANY, VERB_ANY, 0, tree },
2531 { "introspect", 3, 4, 0, introspect },
2532 { "call", 5, VERB_ANY, 0, call },
2533 { "emit", 4, VERB_ANY, 0, emit_signal },
2534 { "get-property", 5, VERB_ANY, 0, get_property },
2535 { "set-property", 6, VERB_ANY, 0, set_property },
2536 { "help", VERB_ANY, VERB_ANY, 0, verb_help },
2537 {}
2538 };
2539
2540 return dispatch_verb(argc, argv, verbs, NULL);
2541 }
2542
2543 static int run(int argc, char *argv[]) {
2544 int r;
2545
2546 log_setup();
2547
2548 r = parse_argv(argc, argv);
2549 if (r <= 0)
2550 return r;
2551
2552 return busctl_main(argc, argv);
2553 }
2554
2555 DEFINE_MAIN_FUNCTION(run);