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