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