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