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