]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/busctl.c
busctl: when --address is specified do not assume we connect to a full bus
[thirdparty/systemd.git] / src / libsystemd / sd-bus / busctl.c
CommitLineData
de1c301e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
1f849790
LP
22#include <getopt.h>
23
89ffcd2a
LP
24#include "strv.h"
25#include "util.h"
26#include "log.h"
1f849790
LP
27#include "build.h"
28#include "pager.h"
d9130355
LP
29#include "xml.h"
30#include "path-util.h"
89ffcd2a 31
de1c301e 32#include "sd-bus.h"
89ffcd2a
LP
33#include "bus-message.h"
34#include "bus-internal.h"
40ca29a1 35#include "bus-util.h"
2b5c5383 36#include "bus-dump.h"
781fa938 37#include "bus-signature.h"
79f34de9 38#include "bus-type.h"
a1ad3767 39#include "busctl-introspect.h"
de1c301e 40
1f849790 41static bool arg_no_pager = false;
17d47d8d 42static bool arg_legend = true;
1f849790 43static char *arg_address = NULL;
56e61788
LP
44static bool arg_unique = false;
45static bool arg_acquired = false;
46static bool arg_activatable = false;
47static bool arg_show_machine = false;
1f849790 48static char **arg_matches = NULL;
d75edbd6
LP
49static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
50static char *arg_host = NULL;
51static bool arg_user = false;
1f70b087 52static size_t arg_snaplen = 4096;
d9130355 53static bool arg_list = false;
781fa938 54static bool arg_quiet = false;
1f849790
LP
55
56static void pager_open_if_enabled(void) {
57
58 /* Cache result before we open the pager */
59 if (arg_no_pager)
60 return;
61
62 pager_open(false);
63}
64
65static int list_bus_names(sd_bus *bus, char **argv) {
71f2ab46 66 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
5e2f14e6
LP
67 _cleanup_free_ char **merged = NULL;
68 _cleanup_hashmap_free_ Hashmap *names = NULL;
de1c301e
LP
69 char **i;
70 int r;
89ffcd2a 71 size_t max_i = 0;
5e2f14e6
LP
72 unsigned n = 0;
73 void *v;
74 char *k;
75 Iterator iterator;
de1c301e 76
1f849790 77 assert(bus);
de1c301e 78
d9130355
LP
79 if (!arg_unique && !arg_acquired && !arg_activatable)
80 arg_unique = arg_acquired = arg_activatable = true;
81
56e61788 82 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
de1c301e
LP
83 if (r < 0) {
84 log_error("Failed to list names: %s", strerror(-r));
1f849790 85 return r;
de1c301e
LP
86 }
87
1f849790
LP
88 pager_open_if_enabled();
89
d5099efc 90 names = hashmap_new(&string_hash_ops);
5e2f14e6
LP
91 if (!names)
92 return log_oom();
89ffcd2a 93
5e2f14e6 94 STRV_FOREACH(i, acquired) {
71f2ab46
LP
95 max_i = MAX(max_i, strlen(*i));
96
5e2f14e6
LP
97 r = hashmap_put(names, *i, INT_TO_PTR(1));
98 if (r < 0) {
99 log_error("Failed to add to hashmap: %s", strerror(-r));
100 return r;
101 }
102 }
103
104 STRV_FOREACH(i, activatable) {
89ffcd2a
LP
105 max_i = MAX(max_i, strlen(*i));
106
5e2f14e6
LP
107 r = hashmap_put(names, *i, INT_TO_PTR(2));
108 if (r < 0 && r != -EEXIST) {
109 log_error("Failed to add to hashmap: %s", strerror(-r));
110 return r;
111 }
112 }
113
114 merged = new(char*, hashmap_size(names) + 1);
115 HASHMAP_FOREACH_KEY(v, k, names, iterator)
116 merged[n++] = k;
117
118 merged[n] = NULL;
119 strv_sort(merged);
120
17d47d8d
TA
121 if (arg_legend) {
122 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
455971c1 123 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
89ffcd2a 124
17d47d8d
TA
125 if (arg_show_machine)
126 puts(" MACHINE");
127 else
128 putchar('\n');
129 }
a4297f08 130
5e2f14e6
LP
131 STRV_FOREACH(i, merged) {
132 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
133 sd_id128_t mid;
71f2ab46 134
5e2f14e6
LP
135 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
136 /* Activatable */
71f2ab46 137
5e2f14e6 138 printf("%-*s", (int) max_i, *i);
56e61788
LP
139 printf(" - - - (activatable) - - ");
140 if (arg_show_machine)
5e2f14e6 141 puts(" -");
56e61788
LP
142 else
143 putchar('\n');
71f2ab46
LP
144 continue;
145
5e2f14e6 146 }
de1c301e 147
56e61788
LP
148 if (!arg_unique && (*i)[0] == ':')
149 continue;
150
151 if (!arg_acquired && (*i)[0] != ':')
1f849790 152 continue;
89ffcd2a
LP
153
154 printf("%-*s", (int) max_i, *i);
de1c301e 155
056f95d0 156 r = sd_bus_get_name_creds(bus, *i,
14008e4e
LP
157 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
158 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
455971c1 159 SD_BUS_CREDS_DESCRIPTION, &creds);
89ffcd2a 160 if (r >= 0) {
14008e4e 161 const char *unique, *session, *unit, *cn;
5b12334d
LP
162 pid_t pid;
163 uid_t uid;
de1c301e 164
5b12334d
LP
165 r = sd_bus_creds_get_pid(creds, &pid);
166 if (r >= 0) {
167 const char *comm = NULL;
de1c301e 168
5b12334d 169 sd_bus_creds_get_comm(creds, &comm);
89ffcd2a 170
5b12334d
LP
171 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
172 } else
a4297f08 173 fputs(" - - ", stdout);
89ffcd2a 174
5b12334d
LP
175 r = sd_bus_creds_get_uid(creds, &uid);
176 if (r >= 0) {
177 _cleanup_free_ char *u = NULL;
89ffcd2a 178
5b12334d
LP
179 u = uid_to_name(uid);
180 if (!u)
181 return log_oom();
89ffcd2a 182
5b12334d
LP
183 if (strlen(u) > 16)
184 u[16] = 0;
185
186 printf(" %-16s", u);
187 } else
a4297f08 188 fputs(" - ", stdout);
89ffcd2a 189
49b832c5
LP
190 r = sd_bus_creds_get_unique_name(creds, &unique);
191 if (r >= 0)
56e61788
LP
192 printf(" %-13s", unique);
193 else
194 fputs(" - ", stdout);
195
196 r = sd_bus_creds_get_unit(creds, &unit);
197 if (r >= 0) {
198 _cleanup_free_ char *e;
199
200 e = ellipsize(unit, 25, 100);
201 if (!e)
202 return log_oom();
203
204 printf(" %-25s", e);
205 } else
206 fputs(" - ", stdout);
207
208 r = sd_bus_creds_get_session(creds, &session);
209 if (r >= 0)
210 printf(" %-10s", session);
a4297f08 211 else
56e61788 212 fputs(" - ", stdout);
7b0b392f 213
455971c1 214 r = sd_bus_creds_get_description(creds, &cn);
14008e4e
LP
215 if (r >= 0)
216 printf(" %-19s", cn);
217 else
218 fputs(" - ", stdout);
219
7b0b392f 220 } else
14008e4e 221 printf(" - - - - - - - ");
a4297f08 222
56e61788 223 if (arg_show_machine) {
056f95d0 224 r = sd_bus_get_name_machine_id(bus, *i, &mid);
a4297f08
LP
225 if (r >= 0) {
226 char m[SD_ID128_STRING_MAX];
227 printf(" %s\n", sd_id128_to_string(mid, m));
228 } else
229 puts(" -");
56e61788
LP
230 } else
231 putchar('\n');
de1c301e
LP
232 }
233
1f849790
LP
234 return 0;
235}
236
d9130355
LP
237static void print_subtree(const char *prefix, const char *path, char **l) {
238 const char *vertical, *space;
239 char **n;
240
241 /* We assume the list is sorted. Let's first skip over the
242 * entry we are looking at. */
243 for (;;) {
244 if (!*l)
245 return;
246
247 if (!streq(*l, path))
248 break;
249
250 l++;
251 }
252
253 vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
254 space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
255
256 for (;;) {
257 bool has_more = false;
258
259 if (!*l || !path_startswith(*l, path))
260 break;
261
262 n = l + 1;
263 for (;;) {
264 if (!*n || !path_startswith(*n, path))
265 break;
266
267 if (!path_startswith(*n, *l)) {
268 has_more = true;
269 break;
270 }
271
272 n++;
273 }
274
275 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
276
277 print_subtree(has_more ? vertical : space, *l, l);
278 l = n;
279 }
280}
281
282static void print_tree(const char *prefix, char **l) {
283
284 pager_open_if_enabled();
285
286 prefix = strempty(prefix);
287
288 if (arg_list) {
289 char **i;
290
291 STRV_FOREACH(i, l)
292 printf("%s%s\n", prefix, *i);
293 return;
294 }
295
56c8b52d
LP
296 if (strv_isempty(l)) {
297 printf("No objects discovered.\n");
298 return;
299 }
300
301 if (streq(l[0], "/") && !l[1]) {
302 printf("Only root object discovered.\n");
303 return;
304 }
d9130355
LP
305
306 print_subtree(prefix, "/", l);
307}
308
a1ad3767
LP
309static int on_path(const char *path, void *userdata) {
310 Set *paths = userdata;
d9130355
LP
311 int r;
312
a1ad3767 313 assert(paths);
d9130355 314
a1ad3767
LP
315 r = set_put_strdup(paths, path);
316 if (r < 0)
317 return log_oom();
d9130355 318
a1ad3767 319 return 0;
d9130355
LP
320}
321
73fc23c0 322static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
0171da06 323 static const XMLIntrospectOps ops = {
a1ad3767
LP
324 .on_path = on_path,
325 };
326
d9130355 327 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
a1ad3767
LP
328 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
329 const char *xml;
d9130355
LP
330 int r;
331
332 r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
333 if (r < 0) {
73fc23c0
LP
334 if (many)
335 printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
336 else
337 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
d9130355
LP
338 return r;
339 }
340
341 r = sd_bus_message_read(reply, "s", &xml);
342 if (r < 0)
343 return bus_log_parse_error(r);
344
a1ad3767 345 return parse_xml_introspect(path, xml, &ops, paths);
d9130355
LP
346}
347
73fc23c0 348static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
d9130355
LP
349 _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
350 _cleanup_free_ char **l = NULL;
351 char *m;
352 int r;
353
354 paths = set_new(&string_hash_ops);
355 if (!paths)
356 return log_oom();
357
358 done = set_new(&string_hash_ops);
359 if (!done)
360 return log_oom();
361
362 failed = set_new(&string_hash_ops);
363 if (!failed)
364 return log_oom();
365
366 m = strdup("/");
367 if (!m)
368 return log_oom();
369
370 r = set_put(paths, m);
371 if (r < 0) {
372 free(m);
373 return log_oom();
374 }
375
376 for (;;) {
377 _cleanup_free_ char *p = NULL;
378 int q;
379
380 p = set_steal_first(paths);
381 if (!p)
382 break;
383
384 if (set_contains(done, p) ||
385 set_contains(failed, p))
386 continue;
387
73fc23c0 388 q = find_nodes(bus, service, p, paths, many);
d9130355
LP
389 if (q < 0) {
390 if (r >= 0)
391 r = q;
392
393 q = set_put(failed, p);
394 } else
395 q = set_put(done, p);
396
397 if (q < 0)
398 return log_oom();
399
400 assert(q != 0);
401 p = NULL;
402 }
403
73fc23c0
LP
404 pager_open_if_enabled();
405
d9130355
LP
406 l = set_get_strv(done);
407 if (!l)
408 return log_oom();
409
410 strv_sort(l);
411 print_tree(prefix, l);
412
413 fflush(stdout);
414
415 return r;
416}
417
418static int tree(sd_bus *bus, char **argv) {
419 char **i;
420 int r = 0;
421
422 if (!arg_unique && !arg_acquired)
423 arg_acquired = true;
424
425 if (strv_length(argv) <= 1) {
426 _cleanup_strv_free_ char **names = NULL;
56c8b52d 427 bool not_first = false;
d9130355
LP
428
429 r = sd_bus_list_names(bus, &names, NULL);
430 if (r < 0) {
431 log_error("Failed to get name list: %s", strerror(-r));
432 return r;
433 }
434
435 pager_open_if_enabled();
436
437 STRV_FOREACH(i, names) {
438 int q;
439
440 if (!arg_unique && (*i)[0] == ':')
441 continue;
442
443 if (!arg_acquired && (*i)[0] == ':')
444 continue;
445
446 if (not_first)
447 printf("\n");
448
56c8b52d 449 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
d9130355 450
73fc23c0 451 q = tree_one(bus, *i, NULL, true);
d9130355
LP
452 if (q < 0 && r >= 0)
453 r = q;
454
455 not_first = true;
456 }
457 } else {
d9130355
LP
458 STRV_FOREACH(i, argv+1) {
459 int q;
460
461 if (i > argv+1)
462 printf("\n");
463
73fc23c0
LP
464 if (argv[2]) {
465 pager_open_if_enabled();
56c8b52d 466 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
73fc23c0 467 }
d9130355 468
73fc23c0 469 q = tree_one(bus, *i, NULL, !!argv[2]);
d9130355
LP
470 if (q < 0 && r >= 0)
471 r = q;
472 }
473 }
474
475 return r;
476}
477
0171da06
LP
478typedef struct Member {
479 const char *type;
480 char *interface;
481 char *name;
482 char *signature;
483 char *result;
484 bool writable;
485 uint64_t flags;
486} Member;
487
488static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
489 const Member *m = p;
490 unsigned long ul;
491
492 assert(m);
493 assert(m->type);
494
495 ul = string_hash_func(m->type, hash_key);
496
497 if (m->name)
498 ul ^= string_hash_func(m->name, hash_key);
499
500 if (m->interface)
501 ul ^= string_hash_func(m->interface, hash_key);
502
503 return ul;
504}
505
506static int member_compare_func(const void *a, const void *b) {
507 const Member *x = a, *y = b;
508 int d;
509
510 assert(x);
511 assert(y);
512 assert(x->type);
513 assert(y->type);
514
515 if (!x->interface && y->interface)
516 return -1;
517 if (x->interface && !y->interface)
518 return 1;
519 if (x->interface && y->interface) {
520 d = strcmp(x->interface, y->interface);
521 if (d != 0)
522 return d;
523 }
524
525 d = strcmp(x->type, y->type);
526 if (d != 0)
527 return d;
528
529 if (!x->name && y->name)
530 return -1;
531 if (x->name && !y->name)
532 return 1;
533 if (x->name && y->name)
534 return strcmp(x->name, y->name);
535
536 return 0;
537}
538
539static int member_compare_funcp(const void *a, const void *b) {
540 const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
541
542 return member_compare_func(*x, *y);
543}
544
545static void member_free(Member *m) {
546 if (!m)
547 return;
548
549 free(m->interface);
550 free(m->name);
551 free(m->signature);
552 free(m->result);
553 free(m);
554}
555
556DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
557
558static void member_set_free(Set *s) {
559 Member *m;
560
561 while ((m = set_steal_first(s)))
562 member_free(m);
563
564 set_free(s);
565}
566
567DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
568
569static int on_interface(const char *interface, uint64_t flags, void *userdata) {
570 _cleanup_(member_freep) Member *m;
571 Set *members = userdata;
572 int r;
573
574 assert(interface);
575 assert(members);
576
577 m = new0(Member, 1);
578 if (!m)
579 return log_oom();
580
581 m->type = "interface";
582 m->flags = flags;
583
584 r = free_and_strdup(&m->interface, interface);
585 if (r < 0)
586 return log_oom();
587
588 r = set_put(members, m);
589 if (r <= 0) {
590 log_error("Duplicate interface");
591 return -EINVAL;
592 }
593
594 m = NULL;
595 return 0;
596}
597
598static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
599 _cleanup_(member_freep) Member *m;
600 Set *members = userdata;
601 int r;
602
603 assert(interface);
604 assert(name);
605
606 m = new0(Member, 1);
607 if (!m)
608 return log_oom();
609
610 m->type = "method";
611 m->flags = flags;
612
613 r = free_and_strdup(&m->interface, interface);
614 if (r < 0)
615 return log_oom();
616
617 r = free_and_strdup(&m->name, name);
618 if (r < 0)
619 return log_oom();
620
621 r = free_and_strdup(&m->signature, signature);
622 if (r < 0)
623 return log_oom();
624
625 r = free_and_strdup(&m->result, result);
626 if (r < 0)
627 return log_oom();
628
629 r = set_put(members, m);
630 if (r <= 0) {
631 log_error("Duplicate method");
632 return -EINVAL;
633 }
634
635 m = NULL;
636 return 0;
637}
638
639static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
640 _cleanup_(member_freep) Member *m;
641 Set *members = userdata;
642 int r;
643
644 assert(interface);
645 assert(name);
646
647 m = new0(Member, 1);
648 if (!m)
649 return log_oom();
650
651 m->type = "signal";
652 m->flags = flags;
653
654 r = free_and_strdup(&m->interface, interface);
655 if (r < 0)
656 return log_oom();
657
658 r = free_and_strdup(&m->name, name);
659 if (r < 0)
660 return log_oom();
661
662 r = free_and_strdup(&m->signature, signature);
663 if (r < 0)
664 return log_oom();
665
666 r = set_put(members, m);
667 if (r <= 0) {
668 log_error("Duplicate signal");
669 return -EINVAL;
670 }
671
672 m = NULL;
673 return 0;
674}
675
676static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
677 _cleanup_(member_freep) Member *m;
678 Set *members = userdata;
679 int r;
680
681 assert(interface);
682 assert(name);
683
684 m = new0(Member, 1);
685 if (!m)
686 return log_oom();
687
688 m->type = "property";
689 m->flags = flags;
690 m->writable = writable;
691
692 r = free_and_strdup(&m->interface, interface);
693 if (r < 0)
694 return log_oom();
695
696 r = free_and_strdup(&m->name, name);
697 if (r < 0)
698 return log_oom();
699
700 r = free_and_strdup(&m->signature, signature);
701 if (r < 0)
702 return log_oom();
703
704 r = set_put(members, m);
705 if (r <= 0) {
706 log_error("Duplicate property");
707 return -EINVAL;
708 }
709
710 m = NULL;
711 return 0;
712}
713
714static const char *strdash(const char *x) {
715 return isempty(x) ? "-" : x;
716}
717
718static int introspect(sd_bus *bus, char **argv) {
719 static const struct hash_ops member_hash_ops = {
720 .hash = member_hash_func,
721 .compare = member_compare_func,
722 };
723
724 static const XMLIntrospectOps ops = {
725 .on_interface = on_interface,
726 .on_method = on_method,
727 .on_signal = on_signal,
728 .on_property = on_property,
729 };
730
731 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
732 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
733 _cleanup_(member_set_freep) Set *members = NULL;
734 Iterator i;
735 Member *m;
736 const char *xml;
737 int r;
738 unsigned name_width, type_width, signature_width, result_width;
739 Member **sorted = NULL;
740 unsigned k = 0, j;
741
742 if (strv_length(argv) != 3) {
743 log_error("Requires service and object path argument.");
744 return -EINVAL;
745 }
746
747 members = set_new(&member_hash_ops);
748 if (!members)
749 return log_oom();
750
751 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
752 if (r < 0) {
753 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
754 return r;
755 }
756
757 r = sd_bus_message_read(reply, "s", &xml);
758 if (r < 0)
759 return bus_log_parse_error(r);
760
761 r = parse_xml_introspect(argv[2], xml, &ops, members);
762 if (r < 0)
763 return r;
764
765 pager_open_if_enabled();
766
767 name_width = strlen("NAME");
768 type_width = strlen("TYPE");
769 signature_width = strlen("SIGNATURE");
770 result_width = strlen("RESULT");
771
772 sorted = newa(Member*, set_size(members));
773
774 SET_FOREACH(m, members, i) {
775 if (m->interface)
776 name_width = MAX(name_width, strlen(m->interface));
777 if (m->name)
778 name_width = MAX(name_width, strlen(m->name) + 1);
779 if (m->type)
780 type_width = MAX(type_width, strlen(m->type));
781 if (m->signature)
782 signature_width = MAX(signature_width, strlen(m->signature));
783 if (m->result)
784 result_width = MAX(result_width, strlen(m->result));
785
786 sorted[k++] = m;
787 }
788
789 assert(k == set_size(members));
790 qsort(sorted, k, sizeof(Member*), member_compare_funcp);
791
792 printf("%-*s %-*s %-*s %-*s %s\n",
793 (int) name_width, "NAME",
794 (int) type_width, "TYPE",
795 (int) signature_width, "SIGNATURE",
796 (int) result_width, "RESULT",
797 "FLAGS");
798
799 for (j = 0; j < k; j++) {
800 bool is_interface;
801
802 m = sorted[j];
803
804 is_interface = streq(m->type, "interface");
805
806 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
807 is_interface ? ansi_highlight() : "",
808 is_interface ? "" : ".",
809 - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
810 is_interface ? ansi_highlight_off() : "",
811 (int) type_width, strdash(m->type),
812 (int) signature_width, strdash(m->signature),
813 (int) result_width, strdash(m->result),
814 (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
815 (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
816 (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
817 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
818 (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
819 m->writable ? " writable" : "");
820 }
821
822 return 0;
823}
824
1f70b087 825static int message_dump(sd_bus_message *m, FILE *f) {
d55192ad 826 return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1f70b087
LP
827}
828
829static int message_pcap(sd_bus_message *m, FILE *f) {
830 return bus_message_pcap_frame(m, arg_snaplen, f);
831}
832
833static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
b51f299a 834 bool added_something = false;
1f849790
LP
835 char **i;
836 int r;
837
838 STRV_FOREACH(i, argv+1) {
839 _cleanup_free_ char *m = NULL;
840
841 if (!service_name_is_valid(*i)) {
842 log_error("Invalid service name '%s'", *i);
843 return -EINVAL;
844 }
845
846 m = strjoin("sender='", *i, "'", NULL);
847 if (!m)
848 return log_oom();
849
19befb2d 850 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1f849790
LP
851 if (r < 0) {
852 log_error("Failed to add match: %s", strerror(-r));
853 return r;
854 }
b51f299a
LP
855
856 added_something = true;
1f849790
LP
857 }
858
859 STRV_FOREACH(i, arg_matches) {
19befb2d 860 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1f849790
LP
861 if (r < 0) {
862 log_error("Failed to add match: %s", strerror(-r));
863 return r;
864 }
b51f299a
LP
865
866 added_something = true;
867 }
868
869 if (!added_something) {
19befb2d 870 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
b51f299a
LP
871 if (r < 0) {
872 log_error("Failed to add match: %s", strerror(-r));
873 return r;
874 }
1f849790
LP
875 }
876
877 for (;;) {
878 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
879
880 r = sd_bus_process(bus, &m);
881 if (r < 0) {
882 log_error("Failed to process bus: %s", strerror(-r));
883 return r;
884 }
885
886 if (m) {
1f70b087 887 dump(m, stdout);
1f849790
LP
888 continue;
889 }
890
891 if (r > 0)
892 continue;
893
894 r = sd_bus_wait(bus, (uint64_t) -1);
895 if (r < 0) {
896 log_error("Failed to wait for bus: %s", strerror(-r));
897 return r;
898 }
899 }
95c4fe82 900}
1f849790 901
1f70b087
LP
902static int capture(sd_bus *bus, char *argv[]) {
903 int r;
904
905 if (isatty(fileno(stdout)) > 0) {
906 log_error("Refusing to write message data to console, please redirect output to a file.");
907 return -EINVAL;
908 }
909
910 bus_pcap_header(arg_snaplen, stdout);
911
912 r = monitor(bus, argv, message_pcap);
913 if (r < 0)
914 return r;
915
916 if (ferror(stdout)) {
917 log_error("Couldn't write capture file.");
918 return -EIO;
919 }
920
921 return r;
922}
923
95c4fe82
LP
924static int status(sd_bus *bus, char *argv[]) {
925 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
926 pid_t pid;
927 int r;
928
929 assert(bus);
930
931 if (strv_length(argv) != 2) {
932 log_error("Expects one argument.");
933 return -EINVAL;
934 }
935
936 r = parse_pid(argv[1], &pid);
937 if (r < 0)
056f95d0 938 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
95c4fe82 939 else
151b9b96 940 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
95c4fe82
LP
941
942 if (r < 0) {
943 log_error("Failed to get credentials: %s", strerror(-r));
944 return r;
945 }
946
d0b2babf 947 bus_creds_dump(creds, NULL, false);
95c4fe82 948 return 0;
1f849790
LP
949}
950
781fa938
LP
951static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
952 char **p;
953 int r;
954
955 assert(m);
956 assert(signature);
957 assert(x);
958
959 p = *x;
960
961 for (;;) {
962 const char *v;
963 char t;
964
965 t = *signature;
966 v = *p;
967
968 if (t == 0)
969 break;
970 if (!v) {
971 log_error("Too few parameters for signature.");
972 return -EINVAL;
973 }
974
975 signature++;
976 p++;
977
978 switch (t) {
979
980 case SD_BUS_TYPE_BOOLEAN:
981
982 r = parse_boolean(v);
983 if (r < 0) {
984 log_error("Failed to parse as boolean: %s", v);
985 return r;
986 }
987
988 r = sd_bus_message_append_basic(m, t, &r);
989 break;
990
991 case SD_BUS_TYPE_BYTE: {
992 uint8_t z;
993
994 r = safe_atou8(v, &z);
995 if (r < 0) {
996 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
997 return r;
998 }
999
1000 r = sd_bus_message_append_basic(m, t, &z);
1001 break;
1002 }
1003
1004 case SD_BUS_TYPE_INT16: {
1005 int16_t z;
1006
1007 r = safe_atoi16(v, &z);
1008 if (r < 0) {
1009 log_error("Failed to parse as signed 16bit integer: %s", v);
1010 return r;
1011 }
1012
1013 r = sd_bus_message_append_basic(m, t, &z);
1014 break;
1015 }
1016
1017 case SD_BUS_TYPE_UINT16: {
1018 uint16_t z;
1019
1020 r = safe_atou16(v, &z);
1021 if (r < 0) {
1022 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1023 return r;
1024 }
1025
1026 r = sd_bus_message_append_basic(m, t, &z);
1027 break;
1028 }
1029
1030 case SD_BUS_TYPE_INT32: {
1031 int32_t z;
1032
1033 r = safe_atoi32(v, &z);
1034 if (r < 0) {
1035 log_error("Failed to parse as signed 32bit integer: %s", v);
1036 return r;
1037 }
1038
1039 r = sd_bus_message_append_basic(m, t, &z);
1040 break;
1041 }
1042
1043 case SD_BUS_TYPE_UINT32: {
1044 uint32_t z;
1045
1046 r = safe_atou32(v, &z);
1047 if (r < 0) {
1048 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1049 return r;
1050 }
1051
1052 r = sd_bus_message_append_basic(m, t, &z);
1053 break;
1054 }
1055
1056 case SD_BUS_TYPE_INT64: {
1057 int64_t z;
1058
1059 r = safe_atoi64(v, &z);
1060 if (r < 0) {
1061 log_error("Failed to parse as signed 64bit integer: %s", v);
1062 return r;
1063 }
1064
1065 r = sd_bus_message_append_basic(m, t, &z);
1066 break;
1067 }
1068
1069 case SD_BUS_TYPE_UINT64: {
1070 uint64_t z;
1071
1072 r = safe_atou64(v, &z);
1073 if (r < 0) {
1074 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1075 return r;
1076 }
1077
1078 r = sd_bus_message_append_basic(m, t, &z);
1079 break;
1080 }
1081
1082
1083 case SD_BUS_TYPE_DOUBLE: {
1084 double z;
1085
1086 r = safe_atod(v, &z);
1087 if (r < 0) {
1088 log_error("Failed to parse as double precision floating point: %s", v);
1089 return r;
1090 }
1091
1092 r = sd_bus_message_append_basic(m, t, &z);
1093 break;
1094 }
1095
1096 case SD_BUS_TYPE_STRING:
1097 case SD_BUS_TYPE_OBJECT_PATH:
1098 case SD_BUS_TYPE_SIGNATURE:
1099
1100 r = sd_bus_message_append_basic(m, t, v);
1101 break;
1102
1103 case SD_BUS_TYPE_ARRAY: {
1104 uint32_t n;
1105 size_t k;
1106
1107 r = safe_atou32(v, &n);
1108 if (r < 0) {
1109 log_error("Failed to parse number of array entries: %s", v);
1110 return r;
1111 }
1112
1113 r = signature_element_length(signature, &k);
1114 if (r < 0) {
1115 log_error("Invalid array signature.");
1116 return r;
1117 }
1118
1119 {
1120 unsigned i;
1121 char s[k + 1];
1122 memcpy(s, signature, k);
1123 s[k] = 0;
1124
1125 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1126 if (r < 0)
1127 return bus_log_create_error(r);
1128
1129 for (i = 0; i < n; i++) {
1130 r = message_append_cmdline(m, s, &p);
1131 if (r < 0)
1132 return r;
1133 }
1134 }
1135
1136 signature += k;
1137
1138 r = sd_bus_message_close_container(m);
1139 break;
1140 }
1141
1142 case SD_BUS_TYPE_VARIANT:
1143 r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1144 if (r < 0)
1145 return bus_log_create_error(r);
1146
1147 r = message_append_cmdline(m, v, &p);
1148 if (r < 0)
1149 return r;
1150
1151 r = sd_bus_message_close_container(m);
1152 break;
1153
1154 case SD_BUS_TYPE_STRUCT_BEGIN:
1155 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1156 size_t k;
1157
1158 signature--;
1159 p--;
1160
1161 r = signature_element_length(signature, &k);
1162 if (r < 0) {
1163 log_error("Invalid struct/dict entry signature.");
1164 return r;
1165 }
1166
1167 {
1168 char s[k-1];
1169 memcpy(s, signature + 1, k - 2);
1170 s[k - 2] = 0;
1171
1172 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1173 if (r < 0)
1174 return bus_log_create_error(r);
1175
1176 r = message_append_cmdline(m, s, &p);
1177 if (r < 0)
1178 return r;
1179 }
1180
1181 signature += k;
1182
1183 r = sd_bus_message_close_container(m);
1184 break;
1185 }
1186
1187 case SD_BUS_TYPE_UNIX_FD:
1188 log_error("UNIX file descriptor not supported as type.");
1189 return -EINVAL;
1190
1191 default:
1192 log_error("Unknown signature type %c.", t);
1193 return -EINVAL;
1194 }
1195
1196 if (r < 0)
1197 return bus_log_create_error(r);
1198 }
1199
1200 *x = p;
1201 return 0;
1202}
1203
1204static int call(sd_bus *bus, char *argv[]) {
1205 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1206 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1207 int r;
1208
1209 assert(bus);
1210
1211 if (strv_length(argv) < 5) {
1212 log_error("Expects at least four arguments.");
1213 return -EINVAL;
1214 }
1215
1216 r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
79f34de9
LP
1217 if (r < 0)
1218 return bus_log_create_error(r);
781fa938
LP
1219
1220 if (!isempty(argv[5])) {
1221 char **p;
1222
1223 p = argv+6;
1224
1225 r = message_append_cmdline(m, argv[5], &p);
1226 if (r < 0)
1227 return r;
1228
1229 if (*p) {
1230 log_error("Too many parameters for signature.");
1231 return -EINVAL;
1232 }
1233 }
1234
1235 r = sd_bus_call(bus, m, 0, &error, &reply);
1236 if (r < 0) {
1237 log_error("%s", bus_error_message(&error, r));
1238 return r;
1239 }
1240
1241 r = sd_bus_message_is_empty(reply);
1242 if (r < 0)
1243 return bus_log_parse_error(r);
1244 if (r == 0 && !arg_quiet) {
1245 pager_open_if_enabled();
d55192ad
LP
1246 bus_message_dump(reply, stdout, 0);
1247 }
1248
1249 return 0;
1250}
1251
1252static int get_property(sd_bus *bus, char *argv[]) {
1253 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1254 unsigned n;
1255 int r;
1256
1257 assert(bus);
1258
1259 n = strv_length(argv);
1260 if (n < 3) {
1261 log_error("Expects at least three arguments.");
1262 return -EINVAL;
1263 }
1264
1265 if (n < 5) {
1266 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1267 bool not_first = false;
1268
1269 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", strempty(argv[3]));
1270 if (r < 0) {
1271 log_error("%s", bus_error_message(&error, r));
1272 return r;
1273 }
1274
1275 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
1276 if (r < 0)
1277 return bus_log_parse_error(r);
1278
1279 for (;;) {
1280 const char *name;
1281
1282 r = sd_bus_message_enter_container(reply, 'e', "sv");
1283 if (r < 0)
1284 return bus_log_parse_error(r);
1285
1286 if (r == 0)
1287 break;
1288
1289 r = sd_bus_message_read(reply, "s", &name);
1290 if (r < 0)
1291 return bus_log_parse_error(r);
1292
1293 if (not_first)
1294 printf("\n");
1295
1296 printf("Property %s:\n", name);
1297
1298 r = sd_bus_message_enter_container(reply, 'v', NULL);
1299 if (r < 0)
1300 return bus_log_parse_error(r);
1301
1302 pager_open_if_enabled();
1303 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1304
1305 r = sd_bus_message_exit_container(reply);
1306 if (r < 0)
1307 return bus_log_parse_error(r);
1308
1309 r = sd_bus_message_exit_container(reply);
1310 if (r < 0)
1311 return bus_log_parse_error(r);
1312
1313 not_first = true;
1314 }
1315
1316 r = sd_bus_message_exit_container(reply);
1317 if (r < 0)
1318 return bus_log_parse_error(r);
1319 } else {
1320 char **i;
1321
1322 STRV_FOREACH(i, argv + 4) {
1323 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1324
1325 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1326 if (r < 0) {
1327 log_error("%s", bus_error_message(&error, r));
1328 return r;
1329 }
1330
1331 r = sd_bus_message_enter_container(reply, 'v', NULL);
1332 if (r < 0)
1333 return bus_log_parse_error(r);
1334
1335 if (i > argv + 4)
1336 printf("\n");
1337
1338 if (argv[5])
1339 printf("Property %s:\n", *i);
1340
1341 pager_open_if_enabled();
1342 bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1343
1344 r = sd_bus_message_exit_container(reply);
1345 if (r < 0)
1346 return bus_log_parse_error(r);
1347 }
781fa938
LP
1348 }
1349
1350 return 0;
1351}
1352
1f849790 1353static int help(void) {
1f849790
LP
1354 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1355 "Introspect the bus.\n\n"
d75edbd6
LP
1356 " -h --help Show this help\n"
1357 " --version Show package version\n"
a86a47ce 1358 " --no-pager Do not pipe output into a pager\n"
17d47d8d 1359 " --no-legend Do not show the headers and footers\n"
d75edbd6
LP
1360 " --system Connect to system bus\n"
1361 " --user Connect to user bus\n"
1362 " -H --host=[USER@]HOST Operate on remote host\n"
1363 " -M --machine=CONTAINER Operate on local container\n"
1364 " --address=ADDRESS Connect to bus specified by address\n"
56e61788
LP
1365 " --show-machine Show machine ID column in list\n"
1366 " --unique Only show unique names\n"
1367 " --acquired Only show acquired names\n"
1368 " --activatable Only show activatable names\n"
d9130355 1369 " --match=MATCH Only show matching messages\n"
781fa938
LP
1370 " --list Don't show tree, but simple object path list\n"
1371 " --quiet Don't show method call reply\n\n"
1f849790 1372 "Commands:\n"
d75edbd6 1373 " list List bus names\n"
0171da06 1374 " status SERVICE Show service name status\n"
d94fe1f1 1375 " monitor [SERVICE...] Show bus traffic\n"
1f70b087 1376 " capture [SERVICE...] Capture bus traffic as pcap\n"
0171da06
LP
1377 " tree [SERVICE...] Show object tree of service\n"
1378 " introspect SERVICE PATH\n"
1379 " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
781fa938 1380 " Call a method\n"
0171da06 1381 " get-property SERVICE OBJECT [INTERFACE [PROPERTY...]]\n"
d55192ad 1382 " Get property value\n"
601185b4
ZJS
1383 " help Show this help\n"
1384 , program_invocation_short_name);
1f849790
LP
1385
1386 return 0;
1387}
1388
1389static int parse_argv(int argc, char *argv[]) {
1390
1391 enum {
1392 ARG_VERSION = 0x100,
1393 ARG_NO_PAGER,
17d47d8d 1394 ARG_NO_LEGEND,
1f849790
LP
1395 ARG_SYSTEM,
1396 ARG_USER,
1397 ARG_ADDRESS,
1398 ARG_MATCH,
56e61788
LP
1399 ARG_SHOW_MACHINE,
1400 ARG_UNIQUE,
1401 ARG_ACQUIRED,
1f70b087
LP
1402 ARG_ACTIVATABLE,
1403 ARG_SIZE,
d9130355 1404 ARG_LIST,
1f849790
LP
1405 };
1406
1407 static const struct option options[] = {
56e61788
LP
1408 { "help", no_argument, NULL, 'h' },
1409 { "version", no_argument, NULL, ARG_VERSION },
1410 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
17d47d8d 1411 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
56e61788
LP
1412 { "system", no_argument, NULL, ARG_SYSTEM },
1413 { "user", no_argument, NULL, ARG_USER },
1414 { "address", required_argument, NULL, ARG_ADDRESS },
1415 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
1416 { "unique", no_argument, NULL, ARG_UNIQUE },
1417 { "acquired", no_argument, NULL, ARG_ACQUIRED },
1418 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
1419 { "match", required_argument, NULL, ARG_MATCH },
1420 { "host", required_argument, NULL, 'H' },
1421 { "machine", required_argument, NULL, 'M' },
1f70b087 1422 { "size", required_argument, NULL, ARG_SIZE },
d9130355 1423 { "list", no_argument, NULL, ARG_LIST },
781fa938 1424 { "quiet", no_argument, NULL, 'q' },
eb9da376 1425 {},
1f849790
LP
1426 };
1427
1f70b087 1428 int c, r;
1f849790
LP
1429
1430 assert(argc >= 0);
1431 assert(argv);
1432
781fa938 1433 while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1f849790
LP
1434
1435 switch (c) {
1436
1437 case 'h':
1438 return help();
1439
1440 case ARG_VERSION:
1441 puts(PACKAGE_STRING);
1442 puts(SYSTEMD_FEATURES);
1443 return 0;
1444
1445 case ARG_NO_PAGER:
1446 arg_no_pager = true;
1447 break;
1448
17d47d8d
TA
1449 case ARG_NO_LEGEND:
1450 arg_legend = false;
1451 break;
1452
1f849790
LP
1453 case ARG_USER:
1454 arg_user = true;
1455 break;
1456
1457 case ARG_SYSTEM:
1458 arg_user = false;
1459 break;
1460
1461 case ARG_ADDRESS:
1462 arg_address = optarg;
1463 break;
1464
56e61788
LP
1465 case ARG_SHOW_MACHINE:
1466 arg_show_machine = true;
1467 break;
1468
1469 case ARG_UNIQUE:
1470 arg_unique = true;
1f849790
LP
1471 break;
1472
56e61788
LP
1473 case ARG_ACQUIRED:
1474 arg_acquired = true;
1475 break;
1476
1477 case ARG_ACTIVATABLE:
1478 arg_activatable = true;
a4297f08
LP
1479 break;
1480
1f849790
LP
1481 case ARG_MATCH:
1482 if (strv_extend(&arg_matches, optarg) < 0)
1483 return log_oom();
1484 break;
1485
1f70b087
LP
1486 case ARG_SIZE: {
1487 off_t o;
1488
1489 r = parse_size(optarg, 0, &o);
1490 if (r < 0) {
1491 log_error("Failed to parse size: %s", optarg);
1492 return r;
1493 }
1494
1495 if ((off_t) (size_t) o != o) {
1496 log_error("Size out of range.");
1497 return -E2BIG;
1498 }
1499
1500 arg_snaplen = (size_t) o;
1501 break;
1502 }
1503
d9130355
LP
1504 case ARG_LIST:
1505 arg_list = true;
1506 break;
1507
d75edbd6
LP
1508 case 'H':
1509 arg_transport = BUS_TRANSPORT_REMOTE;
1510 arg_host = optarg;
1511 break;
1512
1513 case 'M':
1514 arg_transport = BUS_TRANSPORT_CONTAINER;
1515 arg_host = optarg;
1516 break;
1517
781fa938
LP
1518 case 'q':
1519 arg_quiet = true;
1520 break;
1521
1f849790
LP
1522 case '?':
1523 return -EINVAL;
1524
1525 default:
eb9da376 1526 assert_not_reached("Unhandled option");
1f849790 1527 }
1f849790
LP
1528
1529 return 1;
1530}
1531
1532static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1533 assert(bus);
1534
1535 if (optind >= argc ||
1536 streq(argv[optind], "list"))
1537 return list_bus_names(bus, argv + optind);
1538
1539 if (streq(argv[optind], "monitor"))
1f70b087
LP
1540 return monitor(bus, argv + optind, message_dump);
1541
1542 if (streq(argv[optind], "capture"))
1543 return capture(bus, argv + optind);
1f849790 1544
95c4fe82
LP
1545 if (streq(argv[optind], "status"))
1546 return status(bus, argv + optind);
d9130355
LP
1547
1548 if (streq(argv[optind], "tree"))
1549 return tree(bus, argv + optind);
781fa938 1550
0171da06
LP
1551 if (streq(argv[optind], "introspect"))
1552 return introspect(bus, argv + optind);
1553
781fa938
LP
1554 if (streq(argv[optind], "call"))
1555 return call(bus, argv + optind);
d55192ad
LP
1556
1557 if (streq(argv[optind], "get-property"))
1558 return get_property(bus, argv + optind);
95c4fe82 1559
1f849790
LP
1560 if (streq(argv[optind], "help"))
1561 return help();
1562
1563 log_error("Unknown command '%s'", argv[optind]);
1564 return -EINVAL;
1565}
1566
1567int main(int argc, char *argv[]) {
24996861 1568 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1f849790
LP
1569 int r;
1570
1571 log_parse_environment();
1572 log_open();
1573
1574 r = parse_argv(argc, argv);
1575 if (r <= 0)
1576 goto finish;
1577
09365592
LP
1578 r = sd_bus_new(&bus);
1579 if (r < 0) {
1580 log_error("Failed to allocate bus: %s", strerror(-r));
1581 goto finish;
1582 }
1583
1f70b087
LP
1584 if (streq_ptr(argv[optind], "monitor") ||
1585 streq_ptr(argv[optind], "capture")) {
09365592
LP
1586
1587 r = sd_bus_set_monitor(bus, true);
1f849790 1588 if (r < 0) {
09365592 1589 log_error("Failed to set monitor mode: %s", strerror(-r));
1f849790
LP
1590 goto finish;
1591 }
d0ce7734
LP
1592
1593 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1594 if (r < 0) {
1595 log_error("Failed to enable credentials: %s", strerror(-r));
1596 goto finish;
1597 }
1598
1599 r = sd_bus_negotiate_timestamp(bus, true);
1600 if (r < 0) {
1601 log_error("Failed to enable timestamps: %s", strerror(-r));
1602 goto finish;
1603 }
1604
1605 r = sd_bus_negotiate_fds(bus, true);
1606 if (r < 0) {
1607 log_error("Failed to enable fds: %s", strerror(-r));
1608 goto finish;
1609 }
09365592 1610 }
1f849790 1611
09365592 1612 if (arg_address)
1f849790 1613 r = sd_bus_set_address(bus, arg_address);
09365592 1614 else {
b18ec7e2
LP
1615 r = sd_bus_set_bus_client(bus, true);
1616 if (r < 0) {
1617 log_error("Failed to set bus client: %s", strerror(-r));
1618 goto finish;
1619 }
1620
09365592 1621 switch (arg_transport) {
1f849790 1622
09365592
LP
1623 case BUS_TRANSPORT_LOCAL:
1624 if (arg_user)
1625 r = bus_set_address_user(bus);
1626 else
1627 r = bus_set_address_system(bus);
1628 break;
1629
1630 case BUS_TRANSPORT_REMOTE:
1631 r = bus_set_address_system_remote(bus, arg_host);
1632 break;
1633
1634 case BUS_TRANSPORT_CONTAINER:
1635 r = bus_set_address_system_container(bus, arg_host);
1636 break;
1637
1638 default:
1639 assert_not_reached("Hmm, unknown transport type.");
1f849790 1640 }
09365592
LP
1641 }
1642 if (r < 0) {
1643 log_error("Failed to set address: %s", strerror(-r));
1644 goto finish;
1645 }
1f849790 1646
09365592 1647 r = sd_bus_start(bus);
1f849790
LP
1648 if (r < 0) {
1649 log_error("Failed to connect to bus: %s", strerror(-r));
1650 goto finish;
1651 }
1652
1653 r = busctl_main(bus, argc, argv);
1654
1655finish:
1656 pager_close();
d75edbd6 1657
1f849790 1658 strv_free(arg_matches);
de1c301e 1659
de1c301e
LP
1660 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1661}