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