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