chiark / gitweb /
busctl: when introspecting objects, optionally limit output by interface name
[elogind.git] / src / libsystemd / sd-bus / busctl.c
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
22 #include <getopt.h>
23
24 #include "strv.h"
25 #include "util.h"
26 #include "log.h"
27 #include "build.h"
28 #include "pager.h"
29 #include "xml.h"
30 #include "path-util.h"
31 #include "set.h"
32
33 #include "sd-bus.h"
34 #include "bus-message.h"
35 #include "bus-internal.h"
36 #include "bus-util.h"
37 #include "bus-dump.h"
38 #include "bus-signature.h"
39 #include "bus-type.h"
40 #include "busctl-introspect.h"
41
42 static bool arg_no_pager = false;
43 static bool arg_legend = true;
44 static char *arg_address = NULL;
45 static bool arg_unique = false;
46 static bool arg_acquired = false;
47 static bool arg_activatable = false;
48 static bool arg_show_machine = false;
49 static char **arg_matches = NULL;
50 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
51 static char *arg_host = NULL;
52 static bool arg_user = false;
53 static size_t arg_snaplen = 4096;
54 static bool arg_list = false;
55 static bool arg_quiet = false;
56 static bool arg_verbose = false;
57 static bool arg_expect_reply = true;
58 static bool arg_auto_start = true;
59 static bool arg_allow_interactive_authorization = true;
60 static bool arg_augment_creds = true;
61 static usec_t arg_timeout = 0;
62
63 static void pager_open_if_enabled(void) {
64
65         /* Cache result before we open the pager */
66         if (arg_no_pager)
67                 return;
68
69         pager_open(false);
70 }
71
72 #define NAME_IS_ACQUIRED INT_TO_PTR(1)
73 #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
74
75 static int list_bus_names(sd_bus *bus, char **argv) {
76         _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
77         _cleanup_free_ char **merged = NULL;
78         _cleanup_hashmap_free_ Hashmap *names = NULL;
79         char **i;
80         int r;
81         size_t max_i = 0;
82         unsigned n = 0;
83         void *v;
84         char *k;
85         Iterator iterator;
86
87         assert(bus);
88
89         if (!arg_unique && !arg_acquired && !arg_activatable)
90                 arg_unique = arg_acquired = arg_activatable = true;
91
92         r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
93         if (r < 0)
94                 return log_error_errno(r, "Failed to list names: %m");
95
96         pager_open_if_enabled();
97
98         names = hashmap_new(&string_hash_ops);
99         if (!names)
100                 return log_oom();
101
102         STRV_FOREACH(i, acquired) {
103                 max_i = MAX(max_i, strlen(*i));
104
105                 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
106                 if (r < 0)
107                         return log_error_errno(r, "Failed to add to hashmap: %m");
108         }
109
110         STRV_FOREACH(i, activatable) {
111                 max_i = MAX(max_i, strlen(*i));
112
113                 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
114                 if (r < 0 && r != -EEXIST)
115                         return log_error_errno(r, "Failed to add to hashmap: %m");
116         }
117
118         merged = new(char*, hashmap_size(names) + 1);
119         HASHMAP_FOREACH_KEY(v, k, names, iterator)
120                 merged[n++] = k;
121
122         merged[n] = NULL;
123         strv_sort(merged);
124
125         if (arg_legend) {
126                 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
127                        (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
128
129                 if (arg_show_machine)
130                         puts(" MACHINE");
131                 else
132                         putchar('\n');
133         }
134
135         STRV_FOREACH(i, merged) {
136                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
137                 sd_id128_t mid;
138
139                 if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
140                         /* Activatable */
141
142                         printf("%-*s", (int) max_i, *i);
143                         printf("          - -               -                (activatable) -                         -         ");
144                         if (arg_show_machine)
145                                 puts(" -");
146                         else
147                                 putchar('\n');
148                         continue;
149
150                 }
151
152                 if (!arg_unique && (*i)[0] == ':')
153                         continue;
154
155                 if (!arg_acquired && (*i)[0] != ':')
156                         continue;
157
158                 printf("%-*s", (int) max_i, *i);
159
160                 r = sd_bus_get_name_creds(
161                                 bus, *i,
162                                 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
163                                 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
164                                 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
165                                 SD_BUS_CREDS_DESCRIPTION, &creds);
166                 if (r >= 0) {
167                         const char *unique, *session, *unit, *cn;
168                         pid_t pid;
169                         uid_t uid;
170
171                         r = sd_bus_creds_get_pid(creds, &pid);
172                         if (r >= 0) {
173                                 const char *comm = NULL;
174
175                                 sd_bus_creds_get_comm(creds, &comm);
176
177                                 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
178                         } else
179                                 fputs("          - -              ", stdout);
180
181                         r = sd_bus_creds_get_uid(creds, &uid);
182                         if (r >= 0) {
183                                 _cleanup_free_ char *u = NULL;
184
185                                 u = uid_to_name(uid);
186                                 if (!u)
187                                         return log_oom();
188
189                                 if (strlen(u) > 16)
190                                         u[16] = 0;
191
192                                 printf(" %-16s", u);
193                         } else
194                                 fputs(" -               ", stdout);
195
196                         r = sd_bus_creds_get_unique_name(creds, &unique);
197                         if (r >= 0)
198                                 printf(" %-13s", unique);
199                         else
200                                 fputs(" -            ", stdout);
201
202                         r = sd_bus_creds_get_unit(creds, &unit);
203                         if (r >= 0) {
204                                 _cleanup_free_ char *e;
205
206                                 e = ellipsize(unit, 25, 100);
207                                 if (!e)
208                                         return log_oom();
209
210                                 printf(" %-25s", e);
211                         } else
212                                 fputs(" -                        ", stdout);
213
214                         r = sd_bus_creds_get_session(creds, &session);
215                         if (r >= 0)
216                                 printf(" %-10s", session);
217                         else
218                                 fputs(" -         ", stdout);
219
220                         r = sd_bus_creds_get_description(creds, &cn);
221                         if (r >= 0)
222                                 printf(" %-19s", cn);
223                         else
224                                 fputs(" -                  ", stdout);
225
226                 } else
227                         printf("          - -               -                -             -                         -          -                  ");
228
229                 if (arg_show_machine) {
230                         r = sd_bus_get_name_machine_id(bus, *i, &mid);
231                         if (r >= 0) {
232                                 char m[SD_ID128_STRING_MAX];
233                                 printf(" %s\n", sd_id128_to_string(mid, m));
234                         } else
235                                 puts(" -");
236                 } else
237                         putchar('\n');
238         }
239
240         return 0;
241 }
242
243 static void print_subtree(const char *prefix, const char *path, char **l) {
244         const char *vertical, *space;
245         char **n;
246
247         /* We assume the list is sorted. Let's first skip over the
248          * entry we are looking at. */
249         for (;;) {
250                 if (!*l)
251                         return;
252
253                 if (!streq(*l, path))
254                         break;
255
256                 l++;
257         }
258
259         vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
260         space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
261
262         for (;;) {
263                 bool has_more = false;
264
265                 if (!*l || !path_startswith(*l, path))
266                         break;
267
268                 n = l + 1;
269                 for (;;) {
270                         if (!*n || !path_startswith(*n, path))
271                                 break;
272
273                         if (!path_startswith(*n, *l)) {
274                                 has_more = true;
275                                 break;
276                         }
277
278                         n++;
279                 }
280
281                 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
282
283                 print_subtree(has_more ? vertical : space, *l, l);
284                 l = n;
285         }
286 }
287
288 static void print_tree(const char *prefix, char **l) {
289
290         pager_open_if_enabled();
291
292         prefix = strempty(prefix);
293
294         if (arg_list) {
295                 char **i;
296
297                 STRV_FOREACH(i, l)
298                         printf("%s%s\n", prefix, *i);
299                 return;
300         }
301
302         if (strv_isempty(l)) {
303                 printf("No objects discovered.\n");
304                 return;
305         }
306
307         if (streq(l[0], "/") && !l[1]) {
308                 printf("Only root object discovered.\n");
309                 return;
310         }
311
312         print_subtree(prefix, "/", l);
313 }
314
315 static int on_path(const char *path, void *userdata) {
316         Set *paths = userdata;
317         int r;
318
319         assert(paths);
320
321         r = set_put_strdup(paths, path);
322         if (r < 0)
323                 return log_oom();
324
325         return 0;
326 }
327
328 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
329         static const XMLIntrospectOps ops = {
330                 .on_path = on_path,
331         };
332
333         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
334         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
335         const char *xml;
336         int r;
337
338         r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
339         if (r < 0) {
340                 if (many)
341                         printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
342                 else
343                         log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
344                 return r;
345         }
346
347         r = sd_bus_message_read(reply, "s", &xml);
348         if (r < 0)
349                 return bus_log_parse_error(r);
350
351         return parse_xml_introspect(path, xml, &ops, paths);
352 }
353
354 static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
355         _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
356         _cleanup_free_ char **l = NULL;
357         char *m;
358         int r;
359
360         paths = set_new(&string_hash_ops);
361         if (!paths)
362                 return log_oom();
363
364         done = set_new(&string_hash_ops);
365         if (!done)
366                 return log_oom();
367
368         failed = set_new(&string_hash_ops);
369         if (!failed)
370                 return log_oom();
371
372         m = strdup("/");
373         if (!m)
374                 return log_oom();
375
376         r = set_put(paths, m);
377         if (r < 0) {
378                 free(m);
379                 return log_oom();
380         }
381
382         for (;;) {
383                 _cleanup_free_ char *p = NULL;
384                 int q;
385
386                 p = set_steal_first(paths);
387                 if (!p)
388                         break;
389
390                 if (set_contains(done, p) ||
391                     set_contains(failed, p))
392                         continue;
393
394                 q = find_nodes(bus, service, p, paths, many);
395                 if (q < 0) {
396                         if (r >= 0)
397                                 r = q;
398
399                         q = set_put(failed, p);
400                 } else
401                         q = set_put(done, p);
402
403                 if (q < 0)
404                         return log_oom();
405
406                 assert(q != 0);
407                 p = NULL;
408         }
409
410         pager_open_if_enabled();
411
412         l = set_get_strv(done);
413         if (!l)
414                 return log_oom();
415
416         strv_sort(l);
417         print_tree(prefix, l);
418
419         fflush(stdout);
420
421         return r;
422 }
423
424 static int tree(sd_bus *bus, char **argv) {
425         char **i;
426         int r = 0;
427
428         if (!arg_unique && !arg_acquired)
429                 arg_acquired = true;
430
431         if (strv_length(argv) <= 1) {
432                 _cleanup_strv_free_ char **names = NULL;
433                 bool not_first = false;
434
435                 r = sd_bus_list_names(bus, &names, NULL);
436                 if (r < 0)
437                         return log_error_errno(r, "Failed to get name list: %m");
438
439                 pager_open_if_enabled();
440
441                 STRV_FOREACH(i, names) {
442                         int q;
443
444                         if (!arg_unique && (*i)[0] == ':')
445                                 continue;
446
447                         if (!arg_acquired && (*i)[0] == ':')
448                                 continue;
449
450                         if (not_first)
451                                 printf("\n");
452
453                         printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
454
455                         q = tree_one(bus, *i, NULL, true);
456                         if (q < 0 && r >= 0)
457                                 r = q;
458
459                         not_first = true;
460                 }
461         } else {
462                 STRV_FOREACH(i, argv+1) {
463                         int q;
464
465                         if (i > argv+1)
466                                 printf("\n");
467
468                         if (argv[2]) {
469                                 pager_open_if_enabled();
470                                 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
471                         }
472
473                         q = tree_one(bus, *i, NULL, !!argv[2]);
474                         if (q < 0 && r >= 0)
475                                 r = q;
476                 }
477         }
478
479         return r;
480 }
481
482 static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
483         int r;
484
485         for (;;) {
486                 const char *contents = NULL;
487                 char type;
488                 union {
489                         uint8_t u8;
490                         uint16_t u16;
491                         int16_t s16;
492                         uint32_t u32;
493                         int32_t s32;
494                         uint64_t u64;
495                         int64_t s64;
496                         double d64;
497                         const char *string;
498                         int i;
499                 } basic;
500
501                 r = sd_bus_message_peek_type(m, &type, &contents);
502                 if (r <= 0)
503                         return r;
504
505                 if (bus_type_is_container(type) > 0) {
506
507                         r = sd_bus_message_enter_container(m, type, contents);
508                         if (r < 0)
509                                 return r;
510
511                         if (type == SD_BUS_TYPE_ARRAY) {
512                                 unsigned n = 0;
513
514                                 /* count array entries */
515                                 for (;;) {
516
517                                         r = sd_bus_message_skip(m, contents);
518                                         if (r < 0)
519                                                 return r;
520                                         if (r == 0)
521                                                 break;
522
523                                         n++;
524                                 }
525
526                                 r = sd_bus_message_rewind(m, false);
527                                 if (r < 0)
528                                         return r;
529
530                                 if (needs_space)
531                                         fputc(' ', f);
532
533                                 fprintf(f, "%u", n);
534                         } else if (type == SD_BUS_TYPE_VARIANT) {
535
536                                 if (needs_space)
537                                         fputc(' ', f);
538
539                                 fprintf(f, "%s", contents);
540                         }
541
542                         r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT));
543                         if (r < 0)
544                                 return r;
545
546                         r = sd_bus_message_exit_container(m);
547                         if (r < 0)
548                                 return r;
549
550                         continue;
551                 }
552
553                 r = sd_bus_message_read_basic(m, type, &basic);
554                 if (r < 0)
555                         return r;
556
557                 if (needs_space)
558                         fputc(' ', f);
559
560                 switch (type) {
561                 case SD_BUS_TYPE_BYTE:
562                         fprintf(f, "%u", basic.u8);
563                         break;
564
565                 case SD_BUS_TYPE_BOOLEAN:
566                         fputs(true_false(basic.i), f);
567                         break;
568
569                 case SD_BUS_TYPE_INT16:
570                         fprintf(f, "%i", basic.s16);
571                         break;
572
573                 case SD_BUS_TYPE_UINT16:
574                         fprintf(f, "%u", basic.u16);
575                         break;
576
577                 case SD_BUS_TYPE_INT32:
578                         fprintf(f, "%i", basic.s32);
579                         break;
580
581                 case SD_BUS_TYPE_UINT32:
582                         fprintf(f, "%u", basic.u32);
583                         break;
584
585                 case SD_BUS_TYPE_INT64:
586                         fprintf(f, "%" PRIi64, basic.s64);
587                         break;
588
589                 case SD_BUS_TYPE_UINT64:
590                         fprintf(f, "%" PRIu64, basic.u64);
591                         break;
592
593                 case SD_BUS_TYPE_DOUBLE:
594                         fprintf(f, "%g", basic.d64);
595                         break;
596
597                 case SD_BUS_TYPE_STRING:
598                 case SD_BUS_TYPE_OBJECT_PATH:
599                 case SD_BUS_TYPE_SIGNATURE: {
600                         _cleanup_free_ char *b = NULL;
601
602                         b = cescape(basic.string);
603                         if (!b)
604                                 return -ENOMEM;
605
606                         fprintf(f, "\"%s\"", b);
607                         break;
608                 }
609
610                 case SD_BUS_TYPE_UNIX_FD:
611                         fprintf(f, "%i", basic.i);
612                         break;
613
614                 default:
615                         assert_not_reached("Unknown basic type.");
616                 }
617
618                 needs_space = true;
619         }
620 }
621
622 typedef struct Member {
623         const char *type;
624         char *interface;
625         char *name;
626         char *signature;
627         char *result;
628         char *value;
629         bool writable;
630         uint64_t flags;
631 } Member;
632
633 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
634         const Member *m = p;
635         unsigned long ul;
636
637         assert(m);
638         assert(m->type);
639
640         ul = string_hash_func(m->type, hash_key);
641
642         if (m->name)
643                 ul ^= string_hash_func(m->name, hash_key);
644
645         if (m->interface)
646                 ul ^= string_hash_func(m->interface, hash_key);
647
648         return ul;
649 }
650
651 static int member_compare_func(const void *a, const void *b) {
652         const Member *x = a, *y = b;
653         int d;
654
655         assert(x);
656         assert(y);
657         assert(x->type);
658         assert(y->type);
659
660         if (!x->interface && y->interface)
661                 return -1;
662         if (x->interface && !y->interface)
663                 return 1;
664         if (x->interface && y->interface) {
665                 d = strcmp(x->interface, y->interface);
666                 if (d != 0)
667                         return d;
668         }
669
670         d = strcmp(x->type, y->type);
671         if (d != 0)
672                 return d;
673
674         if (!x->name && y->name)
675                 return -1;
676         if (x->name && !y->name)
677                 return 1;
678         if (x->name && y->name)
679                 return strcmp(x->name, y->name);
680
681         return 0;
682 }
683
684 static int member_compare_funcp(const void *a, const void *b) {
685         const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
686
687         return member_compare_func(*x, *y);
688 }
689
690 static void member_free(Member *m) {
691         if (!m)
692                 return;
693
694         free(m->interface);
695         free(m->name);
696         free(m->signature);
697         free(m->result);
698         free(m->value);
699         free(m);
700 }
701
702 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
703
704 static void member_set_free(Set *s) {
705         Member *m;
706
707         while ((m = set_steal_first(s)))
708                 member_free(m);
709
710         set_free(s);
711 }
712
713 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
714
715 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
716         _cleanup_(member_freep) Member *m;
717         Set *members = userdata;
718         int r;
719
720         assert(interface);
721         assert(members);
722
723         m = new0(Member, 1);
724         if (!m)
725                 return log_oom();
726
727         m->type = "interface";
728         m->flags = flags;
729
730         r = free_and_strdup(&m->interface, interface);
731         if (r < 0)
732                 return log_oom();
733
734         r = set_put(members, m);
735         if (r <= 0) {
736                 log_error("Duplicate interface");
737                 return -EINVAL;
738         }
739
740         m = NULL;
741         return 0;
742 }
743
744 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
745         _cleanup_(member_freep) Member *m;
746         Set *members = userdata;
747         int r;
748
749         assert(interface);
750         assert(name);
751
752         m = new0(Member, 1);
753         if (!m)
754                 return log_oom();
755
756         m->type = "method";
757         m->flags = flags;
758
759         r = free_and_strdup(&m->interface, interface);
760         if (r < 0)
761                 return log_oom();
762
763         r = free_and_strdup(&m->name, name);
764         if (r < 0)
765                 return log_oom();
766
767         r = free_and_strdup(&m->signature, signature);
768         if (r < 0)
769                 return log_oom();
770
771         r = free_and_strdup(&m->result, result);
772         if (r < 0)
773                 return log_oom();
774
775         r = set_put(members, m);
776         if (r <= 0) {
777                 log_error("Duplicate method");
778                 return -EINVAL;
779         }
780
781         m = NULL;
782         return 0;
783 }
784
785 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
786         _cleanup_(member_freep) Member *m;
787         Set *members = userdata;
788         int r;
789
790         assert(interface);
791         assert(name);
792
793         m = new0(Member, 1);
794         if (!m)
795                 return log_oom();
796
797         m->type = "signal";
798         m->flags = flags;
799
800         r = free_and_strdup(&m->interface, interface);
801         if (r < 0)
802                 return log_oom();
803
804         r = free_and_strdup(&m->name, name);
805         if (r < 0)
806                 return log_oom();
807
808         r = free_and_strdup(&m->signature, signature);
809         if (r < 0)
810                 return log_oom();
811
812         r = set_put(members, m);
813         if (r <= 0) {
814                 log_error("Duplicate signal");
815                 return -EINVAL;
816         }
817
818         m = NULL;
819         return 0;
820 }
821
822 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
823         _cleanup_(member_freep) Member *m;
824         Set *members = userdata;
825         int r;
826
827         assert(interface);
828         assert(name);
829
830         m = new0(Member, 1);
831         if (!m)
832                 return log_oom();
833
834         m->type = "property";
835         m->flags = flags;
836         m->writable = writable;
837
838         r = free_and_strdup(&m->interface, interface);
839         if (r < 0)
840                 return log_oom();
841
842         r = free_and_strdup(&m->name, name);
843         if (r < 0)
844                 return log_oom();
845
846         r = free_and_strdup(&m->signature, signature);
847         if (r < 0)
848                 return log_oom();
849
850         r = set_put(members, m);
851         if (r <= 0) {
852                 log_error("Duplicate property");
853                 return -EINVAL;
854         }
855
856         m = NULL;
857         return 0;
858 }
859
860 static const char *strdash(const char *x) {
861         return isempty(x) ? "-" : x;
862 }
863
864 static int introspect(sd_bus *bus, char **argv) {
865         static const struct hash_ops member_hash_ops = {
866                 .hash = member_hash_func,
867                 .compare = member_compare_func,
868         };
869
870         static const XMLIntrospectOps ops = {
871                 .on_interface = on_interface,
872                 .on_method = on_method,
873                 .on_signal = on_signal,
874                 .on_property = on_property,
875         };
876
877         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
878         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
879         _cleanup_(member_set_freep) Set *members = NULL;
880         Iterator i;
881         Member *m;
882         const char *xml;
883         int r;
884         unsigned name_width,  type_width, signature_width, result_width;
885         Member **sorted = NULL;
886         unsigned k = 0, j, n_args;
887
888         n_args = strv_length(argv);
889         if (n_args < 3) {
890                 log_error("Requires service and object path argument.");
891                 return -EINVAL;
892         }
893
894         if (n_args > 4) {
895                 log_error("Too many arguments.");
896                 return -EINVAL;
897         }
898
899         members = set_new(&member_hash_ops);
900         if (!members)
901                 return log_oom();
902
903         r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
904         if (r < 0) {
905                 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
906                 return r;
907         }
908
909         r = sd_bus_message_read(reply, "s", &xml);
910         if (r < 0)
911                 return bus_log_parse_error(r);
912
913         /* First, get list of all properties */
914         r = parse_xml_introspect(argv[2], xml, &ops, members);
915         if (r < 0)
916                 return r;
917
918         /* Second, find the current values for them */
919         SET_FOREACH(m, members, i) {
920
921                 if (!streq(m->type, "property"))
922                         continue;
923
924                 if (m->value)
925                         continue;
926
927                 if (argv[3] && !streq(argv[3], m->interface))
928                         continue;
929
930                 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
931                 if (r < 0) {
932                         log_error("%s", bus_error_message(&error, r));
933                         return r;
934                 }
935
936                 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
937                 if (r < 0)
938                         return bus_log_parse_error(r);
939
940                 for (;;) {
941                         Member *z;
942                         _cleanup_free_ char *buf = NULL;
943                         _cleanup_fclose_ FILE *mf = NULL;
944                         size_t sz = 0;
945                         const char *name;
946
947                         r = sd_bus_message_enter_container(reply, 'e', "sv");
948                         if (r < 0)
949                                 return bus_log_parse_error(r);
950
951                         if (r == 0)
952                                 break;
953
954                         r = sd_bus_message_read(reply, "s", &name);
955                         if (r < 0)
956                                 return bus_log_parse_error(r);
957
958                         r = sd_bus_message_enter_container(reply, 'v', NULL);
959                         if (r < 0)
960                                 return bus_log_parse_error(r);
961
962                         mf = open_memstream(&buf, &sz);
963                         if (!mf)
964                                 return log_oom();
965
966                         r = format_cmdline(reply, mf, false);
967                         if (r < 0)
968                                 return bus_log_parse_error(r);
969
970                         fclose(mf);
971                         mf = NULL;
972
973                         z = set_get(members, &((Member) {
974                                                 .type = "property",
975                                                 .interface = m->interface,
976                                                 .name = (char*) name }));
977                         if (z) {
978                                 free(z->value);
979                                 z->value = buf;
980                                 buf = NULL;
981                         }
982
983                         r = sd_bus_message_exit_container(reply);
984                         if (r < 0)
985                                 return bus_log_parse_error(r);
986
987                         r = sd_bus_message_exit_container(reply);
988                         if (r < 0)
989                                 return bus_log_parse_error(r);
990                 }
991
992                 r = sd_bus_message_exit_container(reply);
993                 if (r < 0)
994                         return bus_log_parse_error(r);
995         }
996
997         pager_open_if_enabled();
998
999         name_width = strlen("NAME");
1000         type_width = strlen("TYPE");
1001         signature_width = strlen("SIGNATURE");
1002         result_width = strlen("RESULT/VALUE");
1003
1004         sorted = newa(Member*, set_size(members));
1005
1006         SET_FOREACH(m, members, i) {
1007
1008                 if (argv[3] && !streq(argv[3], m->interface))
1009                         continue;
1010
1011                 if (m->interface)
1012                         name_width = MAX(name_width, strlen(m->interface));
1013                 if (m->name)
1014                         name_width = MAX(name_width, strlen(m->name) + 1);
1015                 if (m->type)
1016                         type_width = MAX(type_width, strlen(m->type));
1017                 if (m->signature)
1018                         signature_width = MAX(signature_width, strlen(m->signature));
1019                 if (m->result)
1020                         result_width = MAX(result_width, strlen(m->result));
1021                 if (m->value)
1022                         result_width = MAX(result_width, strlen(m->value));
1023
1024                 sorted[k++] = m;
1025         }
1026
1027         if (result_width > 40)
1028                 result_width = 40;
1029
1030         qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1031
1032         if (arg_legend) {
1033                 printf("%-*s %-*s %-*s %-*s %s\n",
1034                        (int) name_width, "NAME",
1035                        (int) type_width, "TYPE",
1036                        (int) signature_width, "SIGNATURE",
1037                        (int) result_width, "RESULT/VALUE",
1038                        "FLAGS");
1039         }
1040
1041         for (j = 0; j < k; j++) {
1042                 _cleanup_free_ char *ellipsized = NULL;
1043                 const char *rv;
1044                 bool is_interface;
1045
1046                 m = sorted[j];
1047
1048                 if (argv[3] && !streq(argv[3], m->interface))
1049                         continue;
1050
1051                 is_interface = streq(m->type, "interface");
1052
1053                 if (argv[3] && is_interface)
1054                         continue;
1055
1056                 if (m->value) {
1057                         ellipsized = ellipsize(m->value, result_width, 100);
1058                         if (!ellipsized)
1059                                 return log_oom();
1060
1061                         rv = ellipsized;
1062                 } else
1063                         rv = strdash(m->result);
1064
1065                 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1066                        is_interface ? ansi_highlight() : "",
1067                        is_interface ? "" : ".",
1068                        - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1069                        is_interface ? ansi_highlight_off() : "",
1070                        (int) type_width, strdash(m->type),
1071                        (int) signature_width, strdash(m->signature),
1072                        (int) result_width, rv,
1073                        (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1074                        (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1075                        (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1076                        (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1077                        (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1078                        m->writable ? " writable" : "");
1079         }
1080
1081         return 0;
1082 }
1083
1084 static int message_dump(sd_bus_message *m, FILE *f) {
1085         return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1086 }
1087
1088 static int message_pcap(sd_bus_message *m, FILE *f) {
1089         return bus_message_pcap_frame(m, arg_snaplen, f);
1090 }
1091
1092 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1093         bool added_something = false;
1094         char **i;
1095         int r;
1096
1097         STRV_FOREACH(i, argv+1) {
1098                 _cleanup_free_ char *m = NULL;
1099
1100                 if (!service_name_is_valid(*i)) {
1101                         log_error("Invalid service name '%s'", *i);
1102                         return -EINVAL;
1103                 }
1104
1105                 m = strjoin("sender='", *i, "'", NULL);
1106                 if (!m)
1107                         return log_oom();
1108
1109                 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1110                 if (r < 0)
1111                         return log_error_errno(r, "Failed to add match: %m");
1112
1113                 added_something = true;
1114         }
1115
1116         STRV_FOREACH(i, arg_matches) {
1117                 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1118                 if (r < 0)
1119                         return log_error_errno(r, "Failed to add match: %m");
1120
1121                 added_something = true;
1122         }
1123
1124         if (!added_something) {
1125                 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1126                 if (r < 0)
1127                         return log_error_errno(r, "Failed to add match: %m");
1128         }
1129
1130         for (;;) {
1131                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1132
1133                 r = sd_bus_process(bus, &m);
1134                 if (r < 0)
1135                         return log_error_errno(r, "Failed to process bus: %m");
1136
1137                 if (m) {
1138                         dump(m, stdout);
1139                         continue;
1140                 }
1141
1142                 if (r > 0)
1143                         continue;
1144
1145                 r = sd_bus_wait(bus, (uint64_t) -1);
1146                 if (r < 0)
1147                         return log_error_errno(r, "Failed to wait for bus: %m");
1148         }
1149 }
1150
1151 static int capture(sd_bus *bus, char *argv[]) {
1152         int r;
1153
1154         if (isatty(fileno(stdout)) > 0) {
1155                 log_error("Refusing to write message data to console, please redirect output to a file.");
1156                 return -EINVAL;
1157         }
1158
1159         bus_pcap_header(arg_snaplen, stdout);
1160
1161         r = monitor(bus, argv, message_pcap);
1162         if (r < 0)
1163                 return r;
1164
1165         if (ferror(stdout)) {
1166                 log_error("Couldn't write capture file.");
1167                 return -EIO;
1168         }
1169
1170         return r;
1171 }
1172
1173 static int status(sd_bus *bus, char *argv[]) {
1174         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1175         pid_t pid;
1176         int r;
1177
1178         assert(bus);
1179
1180         if (strv_length(argv) > 2) {
1181                 log_error("Expects no or one argument.");
1182                 return -EINVAL;
1183         }
1184
1185         if (argv[1]) {
1186                 r = parse_pid(argv[1], &pid);
1187                 if (r < 0)
1188                         r = sd_bus_get_name_creds(
1189                                         bus,
1190                                         argv[1],
1191                                         (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1192                                         &creds);
1193                 else
1194                         r = sd_bus_creds_new_from_pid(
1195                                         &creds,
1196                                         pid,
1197                                         _SD_BUS_CREDS_ALL);
1198         } else {
1199                 const char *scope, *address;
1200                 sd_id128_t bus_id;
1201
1202                 r = sd_bus_get_address(bus, &address);
1203                 if (r >= 0)
1204                         printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off());
1205
1206                 r = sd_bus_get_scope(bus, &scope);
1207                 if (r >= 0)
1208                         printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off());
1209
1210                 r = sd_bus_get_bus_id(bus, &bus_id);
1211                 if (r >= 0)
1212                         printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off());
1213
1214                 r = sd_bus_get_owner_creds(
1215                                 bus,
1216                                 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1217                                 &creds);
1218         }
1219
1220         if (r < 0)
1221                 return log_error_errno(r, "Failed to get credentials: %m");
1222
1223         bus_creds_dump(creds, NULL, false);
1224         return 0;
1225 }
1226
1227 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1228         char **p;
1229         int r;
1230
1231         assert(m);
1232         assert(signature);
1233         assert(x);
1234
1235         p = *x;
1236
1237         for (;;) {
1238                 const char *v;
1239                 char t;
1240
1241                 t = *signature;
1242                 v = *p;
1243
1244                 if (t == 0)
1245                         break;
1246                 if (!v) {
1247                         log_error("Too few parameters for signature.");
1248                         return -EINVAL;
1249                 }
1250
1251                 signature++;
1252                 p++;
1253
1254                 switch (t) {
1255
1256                 case SD_BUS_TYPE_BOOLEAN:
1257
1258                         r = parse_boolean(v);
1259                         if (r < 0) {
1260                                 log_error("Failed to parse as boolean: %s", v);
1261                                 return r;
1262                         }
1263
1264                         r = sd_bus_message_append_basic(m, t, &r);
1265                         break;
1266
1267                 case SD_BUS_TYPE_BYTE: {
1268                         uint8_t z;
1269
1270                         r = safe_atou8(v, &z);
1271                         if (r < 0) {
1272                                 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1273                                 return r;
1274                         }
1275
1276                         r = sd_bus_message_append_basic(m, t, &z);
1277                         break;
1278                 }
1279
1280                 case SD_BUS_TYPE_INT16: {
1281                         int16_t z;
1282
1283                         r = safe_atoi16(v, &z);
1284                         if (r < 0) {
1285                                 log_error("Failed to parse as signed 16bit integer: %s", v);
1286                                 return r;
1287                         }
1288
1289                         r = sd_bus_message_append_basic(m, t, &z);
1290                         break;
1291                 }
1292
1293                 case SD_BUS_TYPE_UINT16: {
1294                         uint16_t z;
1295
1296                         r = safe_atou16(v, &z);
1297                         if (r < 0) {
1298                                 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1299                                 return r;
1300                         }
1301
1302                         r = sd_bus_message_append_basic(m, t, &z);
1303                         break;
1304                 }
1305
1306                 case SD_BUS_TYPE_INT32: {
1307                         int32_t z;
1308
1309                         r = safe_atoi32(v, &z);
1310                         if (r < 0) {
1311                                 log_error("Failed to parse as signed 32bit integer: %s", v);
1312                                 return r;
1313                         }
1314
1315                         r = sd_bus_message_append_basic(m, t, &z);
1316                         break;
1317                 }
1318
1319                 case SD_BUS_TYPE_UINT32: {
1320                         uint32_t z;
1321
1322                         r = safe_atou32(v, &z);
1323                         if (r < 0) {
1324                                 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1325                                 return r;
1326                         }
1327
1328                         r = sd_bus_message_append_basic(m, t, &z);
1329                         break;
1330                 }
1331
1332                 case SD_BUS_TYPE_INT64: {
1333                         int64_t z;
1334
1335                         r = safe_atoi64(v, &z);
1336                         if (r < 0) {
1337                                 log_error("Failed to parse as signed 64bit integer: %s", v);
1338                                 return r;
1339                         }
1340
1341                         r = sd_bus_message_append_basic(m, t, &z);
1342                         break;
1343                 }
1344
1345                 case SD_BUS_TYPE_UINT64: {
1346                         uint64_t z;
1347
1348                         r = safe_atou64(v, &z);
1349                         if (r < 0) {
1350                                 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1351                                 return r;
1352                         }
1353
1354                         r = sd_bus_message_append_basic(m, t, &z);
1355                         break;
1356                 }
1357
1358
1359                 case SD_BUS_TYPE_DOUBLE: {
1360                         double z;
1361
1362                         r = safe_atod(v, &z);
1363                         if (r < 0) {
1364                                 log_error("Failed to parse as double precision floating point: %s", v);
1365                                 return r;
1366                         }
1367
1368                         r = sd_bus_message_append_basic(m, t, &z);
1369                         break;
1370                 }
1371
1372                 case SD_BUS_TYPE_STRING:
1373                 case SD_BUS_TYPE_OBJECT_PATH:
1374                 case SD_BUS_TYPE_SIGNATURE:
1375
1376                         r = sd_bus_message_append_basic(m, t, v);
1377                         break;
1378
1379                 case SD_BUS_TYPE_ARRAY: {
1380                         uint32_t n;
1381                         size_t k;
1382
1383                         r = safe_atou32(v, &n);
1384                         if (r < 0) {
1385                                 log_error("Failed to parse number of array entries: %s", v);
1386                                 return r;
1387                         }
1388
1389                         r = signature_element_length(signature, &k);
1390                         if (r < 0) {
1391                                 log_error("Invalid array signature.");
1392                                 return r;
1393                         }
1394
1395                         {
1396                                 unsigned i;
1397                                 char s[k + 1];
1398                                 memcpy(s, signature, k);
1399                                 s[k] = 0;
1400
1401                                 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1402                                 if (r < 0)
1403                                         return bus_log_create_error(r);
1404
1405                                 for (i = 0; i < n; i++) {
1406                                         r = message_append_cmdline(m, s, &p);
1407                                         if (r < 0)
1408                                                 return r;
1409                                 }
1410                         }
1411
1412                         signature += k;
1413
1414                         r = sd_bus_message_close_container(m);
1415                         break;
1416                 }
1417
1418                 case SD_BUS_TYPE_VARIANT:
1419                         r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1420                         if (r < 0)
1421                                 return bus_log_create_error(r);
1422
1423                         r = message_append_cmdline(m, v, &p);
1424                         if (r < 0)
1425                                 return r;
1426
1427                         r = sd_bus_message_close_container(m);
1428                         break;
1429
1430                 case SD_BUS_TYPE_STRUCT_BEGIN:
1431                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1432                         size_t k;
1433
1434                         signature--;
1435                         p--;
1436
1437                         r = signature_element_length(signature, &k);
1438                         if (r < 0) {
1439                                 log_error("Invalid struct/dict entry signature.");
1440                                 return r;
1441                         }
1442
1443                         {
1444                                 char s[k-1];
1445                                 memcpy(s, signature + 1, k - 2);
1446                                 s[k - 2] = 0;
1447
1448                                 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1449                                 if (r < 0)
1450                                         return bus_log_create_error(r);
1451
1452                                 r = message_append_cmdline(m, s, &p);
1453                                 if (r < 0)
1454                                         return r;
1455                         }
1456
1457                         signature += k;
1458
1459                         r = sd_bus_message_close_container(m);
1460                         break;
1461                 }
1462
1463                 case SD_BUS_TYPE_UNIX_FD:
1464                         log_error("UNIX file descriptor not supported as type.");
1465                         return -EINVAL;
1466
1467                 default:
1468                         log_error("Unknown signature type %c.", t);
1469                         return -EINVAL;
1470                 }
1471
1472                 if (r < 0)
1473                         return bus_log_create_error(r);
1474         }
1475
1476         *x = p;
1477         return 0;
1478 }
1479
1480 static int call(sd_bus *bus, char *argv[]) {
1481         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1482         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1483         int r;
1484
1485         assert(bus);
1486
1487         if (strv_length(argv) < 5) {
1488                 log_error("Expects at least four arguments.");
1489                 return -EINVAL;
1490         }
1491
1492         r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1493         if (r < 0)
1494                 return bus_log_create_error(r);
1495
1496         r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1497         if (r < 0)
1498                 return bus_log_create_error(r);
1499
1500         r = sd_bus_message_set_auto_start(m, arg_auto_start);
1501         if (r < 0)
1502                 return bus_log_create_error(r);
1503
1504         r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1505         if (r < 0)
1506                 return bus_log_create_error(r);
1507
1508         if (!isempty(argv[5])) {
1509                 char **p;
1510
1511                 p = argv+6;
1512
1513                 r = message_append_cmdline(m, argv[5], &p);
1514                 if (r < 0)
1515                         return r;
1516
1517                 if (*p) {
1518                         log_error("Too many parameters for signature.");
1519                         return -EINVAL;
1520                 }
1521         }
1522
1523         if (!arg_expect_reply) {
1524                 r = sd_bus_send(bus, m, NULL);
1525                 if (r < 0) {
1526                         log_error("Failed to send message.");
1527                         return r;
1528                 }
1529
1530                 return 0;
1531         }
1532
1533         r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1534         if (r < 0) {
1535                 log_error("%s", bus_error_message(&error, r));
1536                 return r;
1537         }
1538
1539         r = sd_bus_message_is_empty(reply);
1540         if (r < 0)
1541                 return bus_log_parse_error(r);
1542
1543         if (r == 0 && !arg_quiet) {
1544
1545                 if (arg_verbose) {
1546                         pager_open_if_enabled();
1547
1548                         r = bus_message_dump(reply, stdout, 0);
1549                         if (r < 0)
1550                                 return r;
1551                 } else {
1552
1553                         fputs(sd_bus_message_get_signature(reply, true), stdout);
1554                         fputc(' ', stdout);
1555
1556                         r = format_cmdline(reply, stdout, false);
1557                         if (r < 0)
1558                                 return bus_log_parse_error(r);
1559
1560                         fputc('\n', stdout);
1561                 }
1562         }
1563
1564         return 0;
1565 }
1566
1567 static int get_property(sd_bus *bus, char *argv[]) {
1568         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1569         unsigned n;
1570         char **i;
1571         int r;
1572
1573         assert(bus);
1574
1575         n = strv_length(argv);
1576         if (n < 5) {
1577                 log_error("Expects at least four arguments.");
1578                 return -EINVAL;
1579         }
1580
1581         STRV_FOREACH(i, argv + 4) {
1582                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1583                 const char *contents = NULL;
1584                 char type;
1585
1586                 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1587                 if (r < 0) {
1588                         log_error("%s", bus_error_message(&error, r));
1589                         return r;
1590                 }
1591
1592                 r = sd_bus_message_peek_type(reply, &type, &contents);
1593                 if (r < 0)
1594                         return bus_log_parse_error(r);
1595
1596                 r = sd_bus_message_enter_container(reply, 'v', contents);
1597                 if (r < 0)
1598                         return bus_log_parse_error(r);
1599
1600                 if (arg_verbose)  {
1601                         pager_open_if_enabled();
1602
1603                         r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1604                         if (r < 0)
1605                                 return r;
1606                 } else {
1607                         fputs(contents, stdout);
1608                         fputc(' ', stdout);
1609
1610                         r = format_cmdline(reply, stdout, false);
1611                         if (r < 0)
1612                                 return bus_log_parse_error(r);
1613
1614                         fputc('\n', stdout);
1615                 }
1616
1617                 r = sd_bus_message_exit_container(reply);
1618                 if (r < 0)
1619                         return bus_log_parse_error(r);
1620         }
1621
1622         return 0;
1623 }
1624
1625 static int set_property(sd_bus *bus, char *argv[]) {
1626         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1627         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1628         unsigned n;
1629         char **p;
1630         int r;
1631
1632         assert(bus);
1633
1634         n = strv_length(argv);
1635         if (n < 6) {
1636                 log_error("Expects at least five arguments.");
1637                 return -EINVAL;
1638         }
1639
1640         r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1641         if (r < 0)
1642                 return bus_log_create_error(r);
1643
1644         r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1645         if (r < 0)
1646                 return bus_log_create_error(r);
1647
1648         r = sd_bus_message_open_container(m, 'v', argv[5]);
1649         if (r < 0)
1650                 return bus_log_create_error(r);
1651
1652         p = argv+6;
1653         r = message_append_cmdline(m, argv[5], &p);
1654         if (r < 0)
1655                 return r;
1656
1657         r = sd_bus_message_close_container(m);
1658         if (r < 0)
1659                 return bus_log_create_error(r);
1660
1661         if (*p) {
1662                 log_error("Too many parameters for signature.");
1663                 return -EINVAL;
1664         }
1665
1666         r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1667         if (r < 0) {
1668                 log_error("%s", bus_error_message(&error, r));
1669                 return r;
1670         }
1671
1672         return 0;
1673 }
1674
1675 static int help(void) {
1676         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1677                "Introspect the bus.\n\n"
1678                "  -h --help               Show this help\n"
1679                "     --version            Show package version\n"
1680                "     --no-pager           Do not pipe output into a pager\n"
1681                "     --no-legend          Do not show the headers and footers\n"
1682                "     --system             Connect to system bus\n"
1683                "     --user               Connect to user bus\n"
1684                "  -H --host=[USER@]HOST   Operate on remote host\n"
1685                "  -M --machine=CONTAINER  Operate on local container\n"
1686                "     --address=ADDRESS    Connect to bus specified by address\n"
1687                "     --show-machine       Show machine ID column in list\n"
1688                "     --unique             Only show unique names\n"
1689                "     --acquired           Only show acquired names\n"
1690                "     --activatable        Only show activatable names\n"
1691                "     --match=MATCH        Only show matching messages\n"
1692                "     --list               Don't show tree, but simple object path list\n"
1693                "     --quiet              Don't show method call reply\n"
1694                "     --verbose            Show result values in long format\n"
1695                "     --expect-reply=BOOL  Expect a method call reply\n"
1696                "     --auto-start=BOOL    Auto-start destination service\n"
1697                "     --allow-interactive-authorization=BOOL\n"
1698                "                          Allow interactive authorization for operation\n"
1699                "     --timeout=SECS       Maximum time to wait for method call completion\n"
1700                "     --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1701                "Commands:\n"
1702                "  list                    List bus names\n"
1703                "  status [SERVICE]        Show bus service, process or bus owner credentials\n"
1704                "  monitor [SERVICE...]    Show bus traffic\n"
1705                "  capture [SERVICE...]    Capture bus traffic as pcap\n"
1706                "  tree [SERVICE...]       Show object tree of service\n"
1707                "  introspect SERVICE OBJECT [INTERFACE]\n"
1708                "  call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1709                "                          Call a method\n"
1710                "  get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1711                "                          Get property value\n"
1712                "  set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1713                "                          Set property value\n"
1714                "  help                    Show this help\n"
1715                , program_invocation_short_name);
1716
1717         return 0;
1718 }
1719
1720 static int parse_argv(int argc, char *argv[]) {
1721
1722         enum {
1723                 ARG_VERSION = 0x100,
1724                 ARG_NO_PAGER,
1725                 ARG_NO_LEGEND,
1726                 ARG_SYSTEM,
1727                 ARG_USER,
1728                 ARG_ADDRESS,
1729                 ARG_MATCH,
1730                 ARG_SHOW_MACHINE,
1731                 ARG_UNIQUE,
1732                 ARG_ACQUIRED,
1733                 ARG_ACTIVATABLE,
1734                 ARG_SIZE,
1735                 ARG_LIST,
1736                 ARG_VERBOSE,
1737                 ARG_EXPECT_REPLY,
1738                 ARG_AUTO_START,
1739                 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1740                 ARG_TIMEOUT,
1741                 ARG_AUGMENT_CREDS,
1742         };
1743
1744         static const struct option options[] = {
1745                 { "help",         no_argument,       NULL, 'h'              },
1746                 { "version",      no_argument,       NULL, ARG_VERSION      },
1747                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
1748                 { "no-legend",    no_argument,       NULL, ARG_NO_LEGEND    },
1749                 { "system",       no_argument,       NULL, ARG_SYSTEM       },
1750                 { "user",         no_argument,       NULL, ARG_USER         },
1751                 { "address",      required_argument, NULL, ARG_ADDRESS      },
1752                 { "show-machine", no_argument,       NULL, ARG_SHOW_MACHINE },
1753                 { "unique",       no_argument,       NULL, ARG_UNIQUE       },
1754                 { "acquired",     no_argument,       NULL, ARG_ACQUIRED     },
1755                 { "activatable",  no_argument,       NULL, ARG_ACTIVATABLE  },
1756                 { "match",        required_argument, NULL, ARG_MATCH        },
1757                 { "host",         required_argument, NULL, 'H'              },
1758                 { "machine",      required_argument, NULL, 'M'              },
1759                 { "size",         required_argument, NULL, ARG_SIZE         },
1760                 { "list",         no_argument,       NULL, ARG_LIST         },
1761                 { "quiet",        no_argument,       NULL, 'q'              },
1762                 { "verbose",      no_argument,       NULL, ARG_VERBOSE      },
1763                 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1764                 { "auto-start",   required_argument, NULL, ARG_AUTO_START   },
1765                 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1766                 { "timeout",      required_argument, NULL, ARG_TIMEOUT      },
1767                 { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
1768                 {},
1769         };
1770
1771         int c, r;
1772
1773         assert(argc >= 0);
1774         assert(argv);
1775
1776         while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1777
1778                 switch (c) {
1779
1780                 case 'h':
1781                         return help();
1782
1783                 case ARG_VERSION:
1784                         puts(PACKAGE_STRING);
1785                         puts(SYSTEMD_FEATURES);
1786                         return 0;
1787
1788                 case ARG_NO_PAGER:
1789                         arg_no_pager = true;
1790                         break;
1791
1792                 case ARG_NO_LEGEND:
1793                         arg_legend = false;
1794                         break;
1795
1796                 case ARG_USER:
1797                         arg_user = true;
1798                         break;
1799
1800                 case ARG_SYSTEM:
1801                         arg_user = false;
1802                         break;
1803
1804                 case ARG_ADDRESS:
1805                         arg_address = optarg;
1806                         break;
1807
1808                 case ARG_SHOW_MACHINE:
1809                         arg_show_machine = true;
1810                         break;
1811
1812                 case ARG_UNIQUE:
1813                         arg_unique = true;
1814                         break;
1815
1816                 case ARG_ACQUIRED:
1817                         arg_acquired = true;
1818                         break;
1819
1820                 case ARG_ACTIVATABLE:
1821                         arg_activatable = true;
1822                         break;
1823
1824                 case ARG_MATCH:
1825                         if (strv_extend(&arg_matches, optarg) < 0)
1826                                 return log_oom();
1827                         break;
1828
1829                 case ARG_SIZE: {
1830                         off_t o;
1831
1832                         r = parse_size(optarg, 0, &o);
1833                         if (r < 0) {
1834                                 log_error("Failed to parse size: %s", optarg);
1835                                 return r;
1836                         }
1837
1838                         if ((off_t) (size_t) o !=  o) {
1839                                 log_error("Size out of range.");
1840                                 return -E2BIG;
1841                         }
1842
1843                         arg_snaplen = (size_t) o;
1844                         break;
1845                 }
1846
1847                 case ARG_LIST:
1848                         arg_list = true;
1849                         break;
1850
1851                 case 'H':
1852                         arg_transport = BUS_TRANSPORT_REMOTE;
1853                         arg_host = optarg;
1854                         break;
1855
1856                 case 'M':
1857                         arg_transport = BUS_TRANSPORT_CONTAINER;
1858                         arg_host = optarg;
1859                         break;
1860
1861                 case 'q':
1862                         arg_quiet = true;
1863                         break;
1864
1865                 case ARG_VERBOSE:
1866                         arg_verbose = true;
1867                         break;
1868
1869                 case ARG_EXPECT_REPLY:
1870                         r = parse_boolean(optarg);
1871                         if (r < 0) {
1872                                 log_error("Failed to parse --expect-reply= parameter.");
1873                                 return r;
1874                         }
1875
1876                         arg_expect_reply = !!r;
1877                         break;
1878
1879
1880                 case ARG_AUTO_START:
1881                         r = parse_boolean(optarg);
1882                         if (r < 0) {
1883                                 log_error("Failed to parse --auto-start= parameter.");
1884                                 return r;
1885                         }
1886
1887                         arg_auto_start = !!r;
1888                         break;
1889
1890
1891                 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1892                         r = parse_boolean(optarg);
1893                         if (r < 0) {
1894                                 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1895                                 return r;
1896                         }
1897
1898                         arg_allow_interactive_authorization = !!r;
1899                         break;
1900
1901                 case ARG_TIMEOUT:
1902                         r = parse_sec(optarg, &arg_timeout);
1903                         if (r < 0) {
1904                                 log_error("Failed to parse --timeout= parameter.");
1905                                 return r;
1906                         }
1907
1908                         break;
1909
1910                 case ARG_AUGMENT_CREDS:
1911                         r = parse_boolean(optarg);
1912                         if (r < 0) {
1913                                 log_error("Failed to parse --augment-creds= parameter.");
1914                                 return r;
1915                         }
1916
1917                         arg_augment_creds = !!r;
1918                         break;
1919
1920                 case '?':
1921                         return -EINVAL;
1922
1923                 default:
1924                         assert_not_reached("Unhandled option");
1925                 }
1926
1927         return 1;
1928 }
1929
1930 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1931         assert(bus);
1932
1933         if (optind >= argc ||
1934             streq(argv[optind], "list"))
1935                 return list_bus_names(bus, argv + optind);
1936
1937         if (streq(argv[optind], "monitor"))
1938                 return monitor(bus, argv + optind, message_dump);
1939
1940         if (streq(argv[optind], "capture"))
1941                 return capture(bus, argv + optind);
1942
1943         if (streq(argv[optind], "status"))
1944                 return status(bus, argv + optind);
1945
1946         if (streq(argv[optind], "tree"))
1947                 return tree(bus, argv + optind);
1948
1949         if (streq(argv[optind], "introspect"))
1950                 return introspect(bus, argv + optind);
1951
1952         if (streq(argv[optind], "call"))
1953                 return call(bus, argv + optind);
1954
1955         if (streq(argv[optind], "get-property"))
1956                 return get_property(bus, argv + optind);
1957
1958         if (streq(argv[optind], "set-property"))
1959                 return set_property(bus, argv + optind);
1960
1961         if (streq(argv[optind], "help"))
1962                 return help();
1963
1964         log_error("Unknown command '%s'", argv[optind]);
1965         return -EINVAL;
1966 }
1967
1968 int main(int argc, char *argv[]) {
1969         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1970         int r;
1971
1972         log_parse_environment();
1973         log_open();
1974
1975         r = parse_argv(argc, argv);
1976         if (r <= 0)
1977                 goto finish;
1978
1979         r = sd_bus_new(&bus);
1980         if (r < 0) {
1981                 log_error_errno(r, "Failed to allocate bus: %m");
1982                 goto finish;
1983         }
1984
1985         if (streq_ptr(argv[optind], "monitor") ||
1986             streq_ptr(argv[optind], "capture")) {
1987
1988                 r = sd_bus_set_monitor(bus, true);
1989                 if (r < 0) {
1990                         log_error_errno(r, "Failed to set monitor mode: %m");
1991                         goto finish;
1992                 }
1993
1994                 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
1995                 if (r < 0) {
1996                         log_error_errno(r, "Failed to enable credentials: %m");
1997                         goto finish;
1998                 }
1999
2000                 r = sd_bus_negotiate_timestamp(bus, true);
2001                 if (r < 0) {
2002                         log_error_errno(r, "Failed to enable timestamps: %m");
2003                         goto finish;
2004                 }
2005
2006                 r = sd_bus_negotiate_fds(bus, true);
2007                 if (r < 0) {
2008                         log_error_errno(r, "Failed to enable fds: %m");
2009                         goto finish;
2010                 }
2011         }
2012
2013         if (arg_address)
2014                 r = sd_bus_set_address(bus, arg_address);
2015         else {
2016                 r = sd_bus_set_bus_client(bus, true);
2017                 if (r < 0) {
2018                         log_error_errno(r, "Failed to set bus client: %m");
2019                         goto finish;
2020                 }
2021
2022                 switch (arg_transport) {
2023
2024                 case BUS_TRANSPORT_LOCAL:
2025                         if (arg_user) {
2026                                 bus->is_user = true;
2027                                 r = bus_set_address_user(bus);
2028                         } else {
2029                                 bus->is_system = true;
2030                                 r = bus_set_address_system(bus);
2031                         }
2032                         break;
2033
2034                 case BUS_TRANSPORT_REMOTE:
2035                         r = bus_set_address_system_remote(bus, arg_host);
2036                         break;
2037
2038                 case BUS_TRANSPORT_CONTAINER:
2039                         r = bus_set_address_system_container(bus, arg_host);
2040                         break;
2041
2042                 default:
2043                         assert_not_reached("Hmm, unknown transport type.");
2044                 }
2045         }
2046         if (r < 0) {
2047                 log_error_errno(r, "Failed to set address: %m");
2048                 goto finish;
2049         }
2050
2051         r = sd_bus_start(bus);
2052         if (r < 0) {
2053                 log_error_errno(r, "Failed to connect to bus: %m");
2054                 goto finish;
2055         }
2056
2057         r = busctl_main(bus, argc, argv);
2058
2059 finish:
2060         pager_close();
2061
2062         strv_free(arg_matches);
2063
2064         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2065 }