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