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