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