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