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