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