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