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