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