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