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