chiark / gitweb /
util: introduce our own gperf based capability list
[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, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT));
542                         if (r < 0)
543                                 return r;
544
545                         r = sd_bus_message_exit_container(m);
546                         if (r < 0)
547                                 return r;
548
549                         continue;
550                 }
551
552                 r = sd_bus_message_read_basic(m, type, &basic);
553                 if (r < 0)
554                         return r;
555
556                 if (needs_space)
557                         fputc(' ', f);
558
559                 switch (type) {
560                 case SD_BUS_TYPE_BYTE:
561                         fprintf(f, "%u", basic.u8);
562                         break;
563
564                 case SD_BUS_TYPE_BOOLEAN:
565                         fputs(true_false(basic.i), f);
566                         break;
567
568                 case SD_BUS_TYPE_INT16:
569                         fprintf(f, "%i", basic.s16);
570                         break;
571
572                 case SD_BUS_TYPE_UINT16:
573                         fprintf(f, "%u", basic.u16);
574                         break;
575
576                 case SD_BUS_TYPE_INT32:
577                         fprintf(f, "%i", basic.s32);
578                         break;
579
580                 case SD_BUS_TYPE_UINT32:
581                         fprintf(f, "%u", basic.u32);
582                         break;
583
584                 case SD_BUS_TYPE_INT64:
585                         fprintf(f, "%" PRIi64, basic.s64);
586                         break;
587
588                 case SD_BUS_TYPE_UINT64:
589                         fprintf(f, "%" PRIu64, basic.u64);
590                         break;
591
592                 case SD_BUS_TYPE_DOUBLE:
593                         fprintf(f, "%g", basic.d64);
594                         break;
595
596                 case SD_BUS_TYPE_STRING:
597                 case SD_BUS_TYPE_OBJECT_PATH:
598                 case SD_BUS_TYPE_SIGNATURE: {
599                         _cleanup_free_ char *b = NULL;
600
601                         b = cescape(basic.string);
602                         if (!b)
603                                 return -ENOMEM;
604
605                         fprintf(f, "\"%s\"", b);
606                         break;
607                 }
608
609                 case SD_BUS_TYPE_UNIX_FD:
610                         fprintf(f, "%i", basic.i);
611                         break;
612
613                 default:
614                         assert_not_reached("Unknown basic type.");
615                 }
616
617                 needs_space = true;
618         }
619 }
620
621 typedef struct Member {
622         const char *type;
623         char *interface;
624         char *name;
625         char *signature;
626         char *result;
627         char *value;
628         bool writable;
629         uint64_t flags;
630 } Member;
631
632 static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
633         const Member *m = p;
634         unsigned long ul;
635
636         assert(m);
637         assert(m->type);
638
639         ul = string_hash_func(m->type, hash_key);
640
641         if (m->name)
642                 ul ^= string_hash_func(m->name, hash_key);
643
644         if (m->interface)
645                 ul ^= string_hash_func(m->interface, hash_key);
646
647         return ul;
648 }
649
650 static int member_compare_func(const void *a, const void *b) {
651         const Member *x = a, *y = b;
652         int d;
653
654         assert(x);
655         assert(y);
656         assert(x->type);
657         assert(y->type);
658
659         if (!x->interface && y->interface)
660                 return -1;
661         if (x->interface && !y->interface)
662                 return 1;
663         if (x->interface && y->interface) {
664                 d = strcmp(x->interface, y->interface);
665                 if (d != 0)
666                         return d;
667         }
668
669         d = strcmp(x->type, y->type);
670         if (d != 0)
671                 return d;
672
673         if (!x->name && y->name)
674                 return -1;
675         if (x->name && !y->name)
676                 return 1;
677         if (x->name && y->name)
678                 return strcmp(x->name, y->name);
679
680         return 0;
681 }
682
683 static int member_compare_funcp(const void *a, const void *b) {
684         const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
685
686         return member_compare_func(*x, *y);
687 }
688
689 static void member_free(Member *m) {
690         if (!m)
691                 return;
692
693         free(m->interface);
694         free(m->name);
695         free(m->signature);
696         free(m->result);
697         free(m->value);
698         free(m);
699 }
700
701 DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
702
703 static void member_set_free(Set *s) {
704         Member *m;
705
706         while ((m = set_steal_first(s)))
707                 member_free(m);
708
709         set_free(s);
710 }
711
712 DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
713
714 static int on_interface(const char *interface, uint64_t flags, void *userdata) {
715         _cleanup_(member_freep) Member *m;
716         Set *members = userdata;
717         int r;
718
719         assert(interface);
720         assert(members);
721
722         m = new0(Member, 1);
723         if (!m)
724                 return log_oom();
725
726         m->type = "interface";
727         m->flags = flags;
728
729         r = free_and_strdup(&m->interface, interface);
730         if (r < 0)
731                 return log_oom();
732
733         r = set_put(members, m);
734         if (r <= 0) {
735                 log_error("Duplicate interface");
736                 return -EINVAL;
737         }
738
739         m = NULL;
740         return 0;
741 }
742
743 static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
744         _cleanup_(member_freep) Member *m;
745         Set *members = userdata;
746         int r;
747
748         assert(interface);
749         assert(name);
750
751         m = new0(Member, 1);
752         if (!m)
753                 return log_oom();
754
755         m->type = "method";
756         m->flags = flags;
757
758         r = free_and_strdup(&m->interface, interface);
759         if (r < 0)
760                 return log_oom();
761
762         r = free_and_strdup(&m->name, name);
763         if (r < 0)
764                 return log_oom();
765
766         r = free_and_strdup(&m->signature, signature);
767         if (r < 0)
768                 return log_oom();
769
770         r = free_and_strdup(&m->result, result);
771         if (r < 0)
772                 return log_oom();
773
774         r = set_put(members, m);
775         if (r <= 0) {
776                 log_error("Duplicate method");
777                 return -EINVAL;
778         }
779
780         m = NULL;
781         return 0;
782 }
783
784 static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
785         _cleanup_(member_freep) Member *m;
786         Set *members = userdata;
787         int r;
788
789         assert(interface);
790         assert(name);
791
792         m = new0(Member, 1);
793         if (!m)
794                 return log_oom();
795
796         m->type = "signal";
797         m->flags = flags;
798
799         r = free_and_strdup(&m->interface, interface);
800         if (r < 0)
801                 return log_oom();
802
803         r = free_and_strdup(&m->name, name);
804         if (r < 0)
805                 return log_oom();
806
807         r = free_and_strdup(&m->signature, signature);
808         if (r < 0)
809                 return log_oom();
810
811         r = set_put(members, m);
812         if (r <= 0) {
813                 log_error("Duplicate signal");
814                 return -EINVAL;
815         }
816
817         m = NULL;
818         return 0;
819 }
820
821 static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
822         _cleanup_(member_freep) Member *m;
823         Set *members = userdata;
824         int r;
825
826         assert(interface);
827         assert(name);
828
829         m = new0(Member, 1);
830         if (!m)
831                 return log_oom();
832
833         m->type = "property";
834         m->flags = flags;
835         m->writable = writable;
836
837         r = free_and_strdup(&m->interface, interface);
838         if (r < 0)
839                 return log_oom();
840
841         r = free_and_strdup(&m->name, name);
842         if (r < 0)
843                 return log_oom();
844
845         r = free_and_strdup(&m->signature, signature);
846         if (r < 0)
847                 return log_oom();
848
849         r = set_put(members, m);
850         if (r <= 0) {
851                 log_error("Duplicate property");
852                 return -EINVAL;
853         }
854
855         m = NULL;
856         return 0;
857 }
858
859 static const char *strdash(const char *x) {
860         return isempty(x) ? "-" : x;
861 }
862
863 static int introspect(sd_bus *bus, char **argv) {
864         static const struct hash_ops member_hash_ops = {
865                 .hash = member_hash_func,
866                 .compare = member_compare_func,
867         };
868
869         static const XMLIntrospectOps ops = {
870                 .on_interface = on_interface,
871                 .on_method = on_method,
872                 .on_signal = on_signal,
873                 .on_property = on_property,
874         };
875
876         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
877         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
878         _cleanup_(member_set_freep) Set *members = NULL;
879         Iterator i;
880         Member *m;
881         const char *xml;
882         int r;
883         unsigned name_width,  type_width, signature_width, result_width;
884         Member **sorted = NULL;
885         unsigned k = 0, j;
886
887         if (strv_length(argv) != 3) {
888                 log_error("Requires service and object path argument.");
889                 return -EINVAL;
890         }
891
892         members = set_new(&member_hash_ops);
893         if (!members)
894                 return log_oom();
895
896         r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
897         if (r < 0) {
898                 log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
899                 return r;
900         }
901
902         r = sd_bus_message_read(reply, "s", &xml);
903         if (r < 0)
904                 return bus_log_parse_error(r);
905
906         /* First, get list of all properties */
907         r = parse_xml_introspect(argv[2], xml, &ops, members);
908         if (r < 0)
909                 return r;
910
911         /* Second, find the current values for them */
912         SET_FOREACH(m, members, i) {
913
914                 if (!streq(m->type, "property"))
915                         continue;
916
917                 if (m->value)
918                         continue;
919
920                 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
921                 if (r < 0) {
922                         log_error("%s", bus_error_message(&error, r));
923                         return r;
924                 }
925
926                 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
927                 if (r < 0)
928                         return bus_log_parse_error(r);
929
930                 for (;;) {
931                         Member *z;
932                         _cleanup_free_ char *buf = NULL;
933                         _cleanup_fclose_ FILE *mf = NULL;
934                         size_t sz = 0;
935                         const char *name;
936
937                         r = sd_bus_message_enter_container(reply, 'e', "sv");
938                         if (r < 0)
939                                 return bus_log_parse_error(r);
940
941                         if (r == 0)
942                                 break;
943
944                         r = sd_bus_message_read(reply, "s", &name);
945                         if (r < 0)
946                                 return bus_log_parse_error(r);
947
948                         r = sd_bus_message_enter_container(reply, 'v', NULL);
949                         if (r < 0)
950                                 return bus_log_parse_error(r);
951
952                         mf = open_memstream(&buf, &sz);
953                         if (!mf)
954                                 return log_oom();
955
956                         r = format_cmdline(reply, mf, false);
957                         if (r < 0)
958                                 return bus_log_parse_error(r);
959
960                         fclose(mf);
961                         mf = NULL;
962
963                         z = set_get(members, &((Member) {
964                                                 .type = "property",
965                                                 .interface = m->interface,
966                                                 .name = (char*) name }));
967                         if (z) {
968                                 free(z->value);
969                                 z->value = buf;
970                                 buf = NULL;
971                         }
972
973                         r = sd_bus_message_exit_container(reply);
974                         if (r < 0)
975                                 return bus_log_parse_error(r);
976
977                         r = sd_bus_message_exit_container(reply);
978                         if (r < 0)
979                                 return bus_log_parse_error(r);
980                 }
981
982                 r = sd_bus_message_exit_container(reply);
983                 if (r < 0)
984                         return bus_log_parse_error(r);
985         }
986
987         pager_open_if_enabled();
988
989         name_width = strlen("NAME");
990         type_width = strlen("TYPE");
991         signature_width = strlen("SIGNATURE");
992         result_width = strlen("RESULT/VALUE");
993
994         sorted = newa(Member*, set_size(members));
995
996         SET_FOREACH(m, members, i) {
997                 if (m->interface)
998                         name_width = MAX(name_width, strlen(m->interface));
999                 if (m->name)
1000                         name_width = MAX(name_width, strlen(m->name) + 1);
1001                 if (m->type)
1002                         type_width = MAX(type_width, strlen(m->type));
1003                 if (m->signature)
1004                         signature_width = MAX(signature_width, strlen(m->signature));
1005                 if (m->result)
1006                         result_width = MAX(result_width, strlen(m->result));
1007                 if (m->value)
1008                         result_width = MAX(result_width, strlen(m->value));
1009
1010                 sorted[k++] = m;
1011         }
1012
1013         if (result_width > 40)
1014                 result_width = 40;
1015
1016         assert(k == set_size(members));
1017         qsort(sorted, k, sizeof(Member*), member_compare_funcp);
1018
1019         if (arg_legend) {
1020                 printf("%-*s %-*s %-*s %-*s %s\n",
1021                        (int) name_width, "NAME",
1022                        (int) type_width, "TYPE",
1023                        (int) signature_width, "SIGNATURE",
1024                        (int) result_width, "RESULT/VALUE",
1025                        "FLAGS");
1026         }
1027
1028         for (j = 0; j < k; j++) {
1029                 _cleanup_free_ char *ellipsized = NULL;
1030                 const char *rv;
1031                 bool is_interface;
1032
1033                 m = sorted[j];
1034
1035                 is_interface = streq(m->type, "interface");
1036
1037                 if (m->value) {
1038                         ellipsized = ellipsize(m->value, result_width, 100);
1039                         if (!ellipsized)
1040                                 return log_oom();
1041
1042                         rv = ellipsized;
1043                 } else
1044                         rv = strdash(m->result);
1045
1046                 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1047                        is_interface ? ansi_highlight() : "",
1048                        is_interface ? "" : ".",
1049                        - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
1050                        is_interface ? ansi_highlight_off() : "",
1051                        (int) type_width, strdash(m->type),
1052                        (int) signature_width, strdash(m->signature),
1053                        (int) result_width, rv,
1054                        (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
1055                        (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
1056                        (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
1057                        (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
1058                        (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
1059                        m->writable ? " writable" : "");
1060         }
1061
1062         return 0;
1063 }
1064
1065 static int message_dump(sd_bus_message *m, FILE *f) {
1066         return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
1067 }
1068
1069 static int message_pcap(sd_bus_message *m, FILE *f) {
1070         return bus_message_pcap_frame(m, arg_snaplen, f);
1071 }
1072
1073 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
1074         bool added_something = false;
1075         char **i;
1076         int r;
1077
1078         STRV_FOREACH(i, argv+1) {
1079                 _cleanup_free_ char *m = NULL;
1080
1081                 if (!service_name_is_valid(*i)) {
1082                         log_error("Invalid service name '%s'", *i);
1083                         return -EINVAL;
1084                 }
1085
1086                 m = strjoin("sender='", *i, "'", NULL);
1087                 if (!m)
1088                         return log_oom();
1089
1090                 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1091                 if (r < 0)
1092                         return log_error_errno(r, "Failed to add match: %m");
1093
1094                 added_something = true;
1095         }
1096
1097         STRV_FOREACH(i, arg_matches) {
1098                 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1099                 if (r < 0)
1100                         return log_error_errno(r, "Failed to add match: %m");
1101
1102                 added_something = true;
1103         }
1104
1105         if (!added_something) {
1106                 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
1107                 if (r < 0)
1108                         return log_error_errno(r, "Failed to add match: %m");
1109         }
1110
1111         for (;;) {
1112                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1113
1114                 r = sd_bus_process(bus, &m);
1115                 if (r < 0)
1116                         return log_error_errno(r, "Failed to process bus: %m");
1117
1118                 if (m) {
1119                         dump(m, stdout);
1120                         continue;
1121                 }
1122
1123                 if (r > 0)
1124                         continue;
1125
1126                 r = sd_bus_wait(bus, (uint64_t) -1);
1127                 if (r < 0)
1128                         return log_error_errno(r, "Failed to wait for bus: %m");
1129         }
1130 }
1131
1132 static int capture(sd_bus *bus, char *argv[]) {
1133         int r;
1134
1135         if (isatty(fileno(stdout)) > 0) {
1136                 log_error("Refusing to write message data to console, please redirect output to a file.");
1137                 return -EINVAL;
1138         }
1139
1140         bus_pcap_header(arg_snaplen, stdout);
1141
1142         r = monitor(bus, argv, message_pcap);
1143         if (r < 0)
1144                 return r;
1145
1146         if (ferror(stdout)) {
1147                 log_error("Couldn't write capture file.");
1148                 return -EIO;
1149         }
1150
1151         return r;
1152 }
1153
1154 static int status(sd_bus *bus, char *argv[]) {
1155         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
1156         pid_t pid;
1157         int r;
1158
1159         assert(bus);
1160
1161         if (strv_length(argv) > 2) {
1162                 log_error("Expects no or one argument.");
1163                 return -EINVAL;
1164         }
1165
1166         if (argv[1]) {
1167                 r = parse_pid(argv[1], &pid);
1168                 if (r < 0)
1169                         r = sd_bus_get_name_creds(
1170                                         bus,
1171                                         argv[1],
1172                                         (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1173                                         &creds);
1174                 else
1175                         r = sd_bus_creds_new_from_pid(
1176                                         &creds,
1177                                         pid,
1178                                         _SD_BUS_CREDS_ALL);
1179         } else {
1180                 const char *scope, *address;
1181                 sd_id128_t bus_id;
1182
1183                 r = sd_bus_get_address(bus, &address);
1184                 if (r >= 0)
1185                         printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off());
1186
1187                 r = sd_bus_get_scope(bus, &scope);
1188                 if (r >= 0)
1189                         printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off());
1190
1191                 r = sd_bus_get_bus_id(bus, &bus_id);
1192                 if (r >= 0)
1193                         printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off());
1194
1195                 r = sd_bus_get_owner_creds(
1196                                 bus,
1197                                 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
1198                                 &creds);
1199         }
1200
1201         if (r < 0)
1202                 return log_error_errno(r, "Failed to get credentials: %m");
1203
1204         bus_creds_dump(creds, NULL, false);
1205         return 0;
1206 }
1207
1208 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
1209         char **p;
1210         int r;
1211
1212         assert(m);
1213         assert(signature);
1214         assert(x);
1215
1216         p = *x;
1217
1218         for (;;) {
1219                 const char *v;
1220                 char t;
1221
1222                 t = *signature;
1223                 v = *p;
1224
1225                 if (t == 0)
1226                         break;
1227                 if (!v) {
1228                         log_error("Too few parameters for signature.");
1229                         return -EINVAL;
1230                 }
1231
1232                 signature++;
1233                 p++;
1234
1235                 switch (t) {
1236
1237                 case SD_BUS_TYPE_BOOLEAN:
1238
1239                         r = parse_boolean(v);
1240                         if (r < 0) {
1241                                 log_error("Failed to parse as boolean: %s", v);
1242                                 return r;
1243                         }
1244
1245                         r = sd_bus_message_append_basic(m, t, &r);
1246                         break;
1247
1248                 case SD_BUS_TYPE_BYTE: {
1249                         uint8_t z;
1250
1251                         r = safe_atou8(v, &z);
1252                         if (r < 0) {
1253                                 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
1254                                 return r;
1255                         }
1256
1257                         r = sd_bus_message_append_basic(m, t, &z);
1258                         break;
1259                 }
1260
1261                 case SD_BUS_TYPE_INT16: {
1262                         int16_t z;
1263
1264                         r = safe_atoi16(v, &z);
1265                         if (r < 0) {
1266                                 log_error("Failed to parse as signed 16bit integer: %s", v);
1267                                 return r;
1268                         }
1269
1270                         r = sd_bus_message_append_basic(m, t, &z);
1271                         break;
1272                 }
1273
1274                 case SD_BUS_TYPE_UINT16: {
1275                         uint16_t z;
1276
1277                         r = safe_atou16(v, &z);
1278                         if (r < 0) {
1279                                 log_error("Failed to parse as unsigned 16bit integer: %s", v);
1280                                 return r;
1281                         }
1282
1283                         r = sd_bus_message_append_basic(m, t, &z);
1284                         break;
1285                 }
1286
1287                 case SD_BUS_TYPE_INT32: {
1288                         int32_t z;
1289
1290                         r = safe_atoi32(v, &z);
1291                         if (r < 0) {
1292                                 log_error("Failed to parse as signed 32bit integer: %s", v);
1293                                 return r;
1294                         }
1295
1296                         r = sd_bus_message_append_basic(m, t, &z);
1297                         break;
1298                 }
1299
1300                 case SD_BUS_TYPE_UINT32: {
1301                         uint32_t z;
1302
1303                         r = safe_atou32(v, &z);
1304                         if (r < 0) {
1305                                 log_error("Failed to parse as unsigned 32bit integer: %s", v);
1306                                 return r;
1307                         }
1308
1309                         r = sd_bus_message_append_basic(m, t, &z);
1310                         break;
1311                 }
1312
1313                 case SD_BUS_TYPE_INT64: {
1314                         int64_t z;
1315
1316                         r = safe_atoi64(v, &z);
1317                         if (r < 0) {
1318                                 log_error("Failed to parse as signed 64bit integer: %s", v);
1319                                 return r;
1320                         }
1321
1322                         r = sd_bus_message_append_basic(m, t, &z);
1323                         break;
1324                 }
1325
1326                 case SD_BUS_TYPE_UINT64: {
1327                         uint64_t z;
1328
1329                         r = safe_atou64(v, &z);
1330                         if (r < 0) {
1331                                 log_error("Failed to parse as unsigned 64bit integer: %s", v);
1332                                 return r;
1333                         }
1334
1335                         r = sd_bus_message_append_basic(m, t, &z);
1336                         break;
1337                 }
1338
1339
1340                 case SD_BUS_TYPE_DOUBLE: {
1341                         double z;
1342
1343                         r = safe_atod(v, &z);
1344                         if (r < 0) {
1345                                 log_error("Failed to parse as double precision floating point: %s", v);
1346                                 return r;
1347                         }
1348
1349                         r = sd_bus_message_append_basic(m, t, &z);
1350                         break;
1351                 }
1352
1353                 case SD_BUS_TYPE_STRING:
1354                 case SD_BUS_TYPE_OBJECT_PATH:
1355                 case SD_BUS_TYPE_SIGNATURE:
1356
1357                         r = sd_bus_message_append_basic(m, t, v);
1358                         break;
1359
1360                 case SD_BUS_TYPE_ARRAY: {
1361                         uint32_t n;
1362                         size_t k;
1363
1364                         r = safe_atou32(v, &n);
1365                         if (r < 0) {
1366                                 log_error("Failed to parse number of array entries: %s", v);
1367                                 return r;
1368                         }
1369
1370                         r = signature_element_length(signature, &k);
1371                         if (r < 0) {
1372                                 log_error("Invalid array signature.");
1373                                 return r;
1374                         }
1375
1376                         {
1377                                 unsigned i;
1378                                 char s[k + 1];
1379                                 memcpy(s, signature, k);
1380                                 s[k] = 0;
1381
1382                                 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
1383                                 if (r < 0)
1384                                         return bus_log_create_error(r);
1385
1386                                 for (i = 0; i < n; i++) {
1387                                         r = message_append_cmdline(m, s, &p);
1388                                         if (r < 0)
1389                                                 return r;
1390                                 }
1391                         }
1392
1393                         signature += k;
1394
1395                         r = sd_bus_message_close_container(m);
1396                         break;
1397                 }
1398
1399                 case SD_BUS_TYPE_VARIANT:
1400                         r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
1401                         if (r < 0)
1402                                 return bus_log_create_error(r);
1403
1404                         r = message_append_cmdline(m, v, &p);
1405                         if (r < 0)
1406                                 return r;
1407
1408                         r = sd_bus_message_close_container(m);
1409                         break;
1410
1411                 case SD_BUS_TYPE_STRUCT_BEGIN:
1412                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1413                         size_t k;
1414
1415                         signature--;
1416                         p--;
1417
1418                         r = signature_element_length(signature, &k);
1419                         if (r < 0) {
1420                                 log_error("Invalid struct/dict entry signature.");
1421                                 return r;
1422                         }
1423
1424                         {
1425                                 char s[k-1];
1426                                 memcpy(s, signature + 1, k - 2);
1427                                 s[k - 2] = 0;
1428
1429                                 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
1430                                 if (r < 0)
1431                                         return bus_log_create_error(r);
1432
1433                                 r = message_append_cmdline(m, s, &p);
1434                                 if (r < 0)
1435                                         return r;
1436                         }
1437
1438                         signature += k;
1439
1440                         r = sd_bus_message_close_container(m);
1441                         break;
1442                 }
1443
1444                 case SD_BUS_TYPE_UNIX_FD:
1445                         log_error("UNIX file descriptor not supported as type.");
1446                         return -EINVAL;
1447
1448                 default:
1449                         log_error("Unknown signature type %c.", t);
1450                         return -EINVAL;
1451                 }
1452
1453                 if (r < 0)
1454                         return bus_log_create_error(r);
1455         }
1456
1457         *x = p;
1458         return 0;
1459 }
1460
1461 static int call(sd_bus *bus, char *argv[]) {
1462         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1463         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1464         int r;
1465
1466         assert(bus);
1467
1468         if (strv_length(argv) < 5) {
1469                 log_error("Expects at least four arguments.");
1470                 return -EINVAL;
1471         }
1472
1473         r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1474         if (r < 0)
1475                 return bus_log_create_error(r);
1476
1477         r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1478         if (r < 0)
1479                 return bus_log_create_error(r);
1480
1481         r = sd_bus_message_set_auto_start(m, arg_auto_start);
1482         if (r < 0)
1483                 return bus_log_create_error(r);
1484
1485         r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1486         if (r < 0)
1487                 return bus_log_create_error(r);
1488
1489         if (!isempty(argv[5])) {
1490                 char **p;
1491
1492                 p = argv+6;
1493
1494                 r = message_append_cmdline(m, argv[5], &p);
1495                 if (r < 0)
1496                         return r;
1497
1498                 if (*p) {
1499                         log_error("Too many parameters for signature.");
1500                         return -EINVAL;
1501                 }
1502         }
1503
1504         if (!arg_expect_reply) {
1505                 r = sd_bus_send(bus, m, NULL);
1506                 if (r < 0) {
1507                         log_error("Failed to send message.");
1508                         return r;
1509                 }
1510
1511                 return 0;
1512         }
1513
1514         r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1515         if (r < 0) {
1516                 log_error("%s", bus_error_message(&error, r));
1517                 return r;
1518         }
1519
1520         r = sd_bus_message_is_empty(reply);
1521         if (r < 0)
1522                 return bus_log_parse_error(r);
1523
1524         if (r == 0 && !arg_quiet) {
1525
1526                 if (arg_verbose) {
1527                         pager_open_if_enabled();
1528
1529                         r = bus_message_dump(reply, stdout, 0);
1530                         if (r < 0)
1531                                 return r;
1532                 } else {
1533
1534                         fputs(sd_bus_message_get_signature(reply, true), stdout);
1535                         fputc(' ', stdout);
1536
1537                         r = format_cmdline(reply, stdout, false);
1538                         if (r < 0)
1539                                 return bus_log_parse_error(r);
1540
1541                         fputc('\n', stdout);
1542                 }
1543         }
1544
1545         return 0;
1546 }
1547
1548 static int get_property(sd_bus *bus, char *argv[]) {
1549         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1550         unsigned n;
1551         char **i;
1552         int r;
1553
1554         assert(bus);
1555
1556         n = strv_length(argv);
1557         if (n < 5) {
1558                 log_error("Expects at least four arguments.");
1559                 return -EINVAL;
1560         }
1561
1562         STRV_FOREACH(i, argv + 4) {
1563                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1564                 const char *contents = NULL;
1565                 char type;
1566
1567                 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
1568                 if (r < 0) {
1569                         log_error("%s", bus_error_message(&error, r));
1570                         return r;
1571                 }
1572
1573                 r = sd_bus_message_peek_type(reply, &type, &contents);
1574                 if (r < 0)
1575                         return bus_log_parse_error(r);
1576
1577                 r = sd_bus_message_enter_container(reply, 'v', contents);
1578                 if (r < 0)
1579                         return bus_log_parse_error(r);
1580
1581                 if (arg_verbose)  {
1582                         pager_open_if_enabled();
1583
1584                         r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
1585                         if (r < 0)
1586                                 return r;
1587                 } else {
1588                         fputs(contents, stdout);
1589                         fputc(' ', stdout);
1590
1591                         r = format_cmdline(reply, stdout, false);
1592                         if (r < 0)
1593                                 return bus_log_parse_error(r);
1594
1595                         fputc('\n', stdout);
1596                 }
1597
1598                 r = sd_bus_message_exit_container(reply);
1599                 if (r < 0)
1600                         return bus_log_parse_error(r);
1601         }
1602
1603         return 0;
1604 }
1605
1606 static int set_property(sd_bus *bus, char *argv[]) {
1607         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1608         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1609         unsigned n;
1610         char **p;
1611         int r;
1612
1613         assert(bus);
1614
1615         n = strv_length(argv);
1616         if (n < 6) {
1617                 log_error("Expects at least five arguments.");
1618                 return -EINVAL;
1619         }
1620
1621         r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
1622         if (r < 0)
1623                 return bus_log_create_error(r);
1624
1625         r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
1626         if (r < 0)
1627                 return bus_log_create_error(r);
1628
1629         r = sd_bus_message_open_container(m, 'v', argv[5]);
1630         if (r < 0)
1631                 return bus_log_create_error(r);
1632
1633         p = argv+6;
1634         r = message_append_cmdline(m, argv[5], &p);
1635         if (r < 0)
1636                 return r;
1637
1638         r = sd_bus_message_close_container(m);
1639         if (r < 0)
1640                 return bus_log_create_error(r);
1641
1642         if (*p) {
1643                 log_error("Too many parameters for signature.");
1644                 return -EINVAL;
1645         }
1646
1647         r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
1648         if (r < 0) {
1649                 log_error("%s", bus_error_message(&error, r));
1650                 return r;
1651         }
1652
1653         return 0;
1654 }
1655
1656 static int help(void) {
1657         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1658                "Introspect the bus.\n\n"
1659                "  -h --help               Show this help\n"
1660                "     --version            Show package version\n"
1661                "     --no-pager           Do not pipe output into a pager\n"
1662                "     --no-legend          Do not show the headers and footers\n"
1663                "     --system             Connect to system bus\n"
1664                "     --user               Connect to user bus\n"
1665                "  -H --host=[USER@]HOST   Operate on remote host\n"
1666                "  -M --machine=CONTAINER  Operate on local container\n"
1667                "     --address=ADDRESS    Connect to bus specified by address\n"
1668                "     --show-machine       Show machine ID column in list\n"
1669                "     --unique             Only show unique names\n"
1670                "     --acquired           Only show acquired names\n"
1671                "     --activatable        Only show activatable names\n"
1672                "     --match=MATCH        Only show matching messages\n"
1673                "     --list               Don't show tree, but simple object path list\n"
1674                "     --quiet              Don't show method call reply\n"
1675                "     --verbose            Show result values in long format\n"
1676                "     --expect-reply=BOOL  Expect a method call reply\n"
1677                "     --auto-start=BOOL    Auto-start destination service\n"
1678                "     --allow-interactive-authorization=BOOL\n"
1679                "                          Allow interactive authorization for operation\n"
1680                "     --timeout=SECS       Maximum time to wait for method call completion\n"
1681                "     --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
1682                "Commands:\n"
1683                "  list                    List bus names\n"
1684                "  status [SERVICE]        Show bus service, process or bus owner credentials\n"
1685                "  monitor [SERVICE...]    Show bus traffic\n"
1686                "  capture [SERVICE...]    Capture bus traffic as pcap\n"
1687                "  tree [SERVICE...]       Show object tree of service\n"
1688                "  introspect SERVICE OBJECT\n"
1689                "  call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
1690                "                          Call a method\n"
1691                "  get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
1692                "                          Get property value\n"
1693                "  set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
1694                "                          Set property value\n"
1695                "  help                    Show this help\n"
1696                , program_invocation_short_name);
1697
1698         return 0;
1699 }
1700
1701 static int parse_argv(int argc, char *argv[]) {
1702
1703         enum {
1704                 ARG_VERSION = 0x100,
1705                 ARG_NO_PAGER,
1706                 ARG_NO_LEGEND,
1707                 ARG_SYSTEM,
1708                 ARG_USER,
1709                 ARG_ADDRESS,
1710                 ARG_MATCH,
1711                 ARG_SHOW_MACHINE,
1712                 ARG_UNIQUE,
1713                 ARG_ACQUIRED,
1714                 ARG_ACTIVATABLE,
1715                 ARG_SIZE,
1716                 ARG_LIST,
1717                 ARG_VERBOSE,
1718                 ARG_EXPECT_REPLY,
1719                 ARG_AUTO_START,
1720                 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
1721                 ARG_TIMEOUT,
1722                 ARG_AUGMENT_CREDS,
1723         };
1724
1725         static const struct option options[] = {
1726                 { "help",         no_argument,       NULL, 'h'              },
1727                 { "version",      no_argument,       NULL, ARG_VERSION      },
1728                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
1729                 { "no-legend",    no_argument,       NULL, ARG_NO_LEGEND    },
1730                 { "system",       no_argument,       NULL, ARG_SYSTEM       },
1731                 { "user",         no_argument,       NULL, ARG_USER         },
1732                 { "address",      required_argument, NULL, ARG_ADDRESS      },
1733                 { "show-machine", no_argument,       NULL, ARG_SHOW_MACHINE },
1734                 { "unique",       no_argument,       NULL, ARG_UNIQUE       },
1735                 { "acquired",     no_argument,       NULL, ARG_ACQUIRED     },
1736                 { "activatable",  no_argument,       NULL, ARG_ACTIVATABLE  },
1737                 { "match",        required_argument, NULL, ARG_MATCH        },
1738                 { "host",         required_argument, NULL, 'H'              },
1739                 { "machine",      required_argument, NULL, 'M'              },
1740                 { "size",         required_argument, NULL, ARG_SIZE         },
1741                 { "list",         no_argument,       NULL, ARG_LIST         },
1742                 { "quiet",        no_argument,       NULL, 'q'              },
1743                 { "verbose",      no_argument,       NULL, ARG_VERBOSE      },
1744                 { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
1745                 { "auto-start",   required_argument, NULL, ARG_AUTO_START   },
1746                 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
1747                 { "timeout",      required_argument, NULL, ARG_TIMEOUT      },
1748                 { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
1749                 {},
1750         };
1751
1752         int c, r;
1753
1754         assert(argc >= 0);
1755         assert(argv);
1756
1757         while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1758
1759                 switch (c) {
1760
1761                 case 'h':
1762                         return help();
1763
1764                 case ARG_VERSION:
1765                         puts(PACKAGE_STRING);
1766                         puts(SYSTEMD_FEATURES);
1767                         return 0;
1768
1769                 case ARG_NO_PAGER:
1770                         arg_no_pager = true;
1771                         break;
1772
1773                 case ARG_NO_LEGEND:
1774                         arg_legend = false;
1775                         break;
1776
1777                 case ARG_USER:
1778                         arg_user = true;
1779                         break;
1780
1781                 case ARG_SYSTEM:
1782                         arg_user = false;
1783                         break;
1784
1785                 case ARG_ADDRESS:
1786                         arg_address = optarg;
1787                         break;
1788
1789                 case ARG_SHOW_MACHINE:
1790                         arg_show_machine = true;
1791                         break;
1792
1793                 case ARG_UNIQUE:
1794                         arg_unique = true;
1795                         break;
1796
1797                 case ARG_ACQUIRED:
1798                         arg_acquired = true;
1799                         break;
1800
1801                 case ARG_ACTIVATABLE:
1802                         arg_activatable = true;
1803                         break;
1804
1805                 case ARG_MATCH:
1806                         if (strv_extend(&arg_matches, optarg) < 0)
1807                                 return log_oom();
1808                         break;
1809
1810                 case ARG_SIZE: {
1811                         off_t o;
1812
1813                         r = parse_size(optarg, 0, &o);
1814                         if (r < 0) {
1815                                 log_error("Failed to parse size: %s", optarg);
1816                                 return r;
1817                         }
1818
1819                         if ((off_t) (size_t) o !=  o) {
1820                                 log_error("Size out of range.");
1821                                 return -E2BIG;
1822                         }
1823
1824                         arg_snaplen = (size_t) o;
1825                         break;
1826                 }
1827
1828                 case ARG_LIST:
1829                         arg_list = true;
1830                         break;
1831
1832                 case 'H':
1833                         arg_transport = BUS_TRANSPORT_REMOTE;
1834                         arg_host = optarg;
1835                         break;
1836
1837                 case 'M':
1838                         arg_transport = BUS_TRANSPORT_CONTAINER;
1839                         arg_host = optarg;
1840                         break;
1841
1842                 case 'q':
1843                         arg_quiet = true;
1844                         break;
1845
1846                 case ARG_VERBOSE:
1847                         arg_verbose = true;
1848                         break;
1849
1850                 case ARG_EXPECT_REPLY:
1851                         r = parse_boolean(optarg);
1852                         if (r < 0) {
1853                                 log_error("Failed to parse --expect-reply= parameter.");
1854                                 return r;
1855                         }
1856
1857                         arg_expect_reply = !!r;
1858                         break;
1859
1860
1861                 case ARG_AUTO_START:
1862                         r = parse_boolean(optarg);
1863                         if (r < 0) {
1864                                 log_error("Failed to parse --auto-start= parameter.");
1865                                 return r;
1866                         }
1867
1868                         arg_auto_start = !!r;
1869                         break;
1870
1871
1872                 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1873                         r = parse_boolean(optarg);
1874                         if (r < 0) {
1875                                 log_error("Failed to parse --allow-interactive-authorization= parameter.");
1876                                 return r;
1877                         }
1878
1879                         arg_allow_interactive_authorization = !!r;
1880                         break;
1881
1882                 case ARG_TIMEOUT:
1883                         r = parse_sec(optarg, &arg_timeout);
1884                         if (r < 0) {
1885                                 log_error("Failed to parse --timeout= parameter.");
1886                                 return r;
1887                         }
1888
1889                         break;
1890
1891                 case ARG_AUGMENT_CREDS:
1892                         r = parse_boolean(optarg);
1893                         if (r < 0) {
1894                                 log_error("Failed to parse --augment-creds= parameter.");
1895                                 return r;
1896                         }
1897
1898                         arg_augment_creds = !!r;
1899                         break;
1900
1901                 case '?':
1902                         return -EINVAL;
1903
1904                 default:
1905                         assert_not_reached("Unhandled option");
1906                 }
1907
1908         return 1;
1909 }
1910
1911 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1912         assert(bus);
1913
1914         if (optind >= argc ||
1915             streq(argv[optind], "list"))
1916                 return list_bus_names(bus, argv + optind);
1917
1918         if (streq(argv[optind], "monitor"))
1919                 return monitor(bus, argv + optind, message_dump);
1920
1921         if (streq(argv[optind], "capture"))
1922                 return capture(bus, argv + optind);
1923
1924         if (streq(argv[optind], "status"))
1925                 return status(bus, argv + optind);
1926
1927         if (streq(argv[optind], "tree"))
1928                 return tree(bus, argv + optind);
1929
1930         if (streq(argv[optind], "introspect"))
1931                 return introspect(bus, argv + optind);
1932
1933         if (streq(argv[optind], "call"))
1934                 return call(bus, argv + optind);
1935
1936         if (streq(argv[optind], "get-property"))
1937                 return get_property(bus, argv + optind);
1938
1939         if (streq(argv[optind], "set-property"))
1940                 return set_property(bus, argv + optind);
1941
1942         if (streq(argv[optind], "help"))
1943                 return help();
1944
1945         log_error("Unknown command '%s'", argv[optind]);
1946         return -EINVAL;
1947 }
1948
1949 int main(int argc, char *argv[]) {
1950         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1951         int r;
1952
1953         log_parse_environment();
1954         log_open();
1955
1956         r = parse_argv(argc, argv);
1957         if (r <= 0)
1958                 goto finish;
1959
1960         r = sd_bus_new(&bus);
1961         if (r < 0) {
1962                 log_error_errno(r, "Failed to allocate bus: %m");
1963                 goto finish;
1964         }
1965
1966         if (streq_ptr(argv[optind], "monitor") ||
1967             streq_ptr(argv[optind], "capture")) {
1968
1969                 r = sd_bus_set_monitor(bus, true);
1970                 if (r < 0) {
1971                         log_error_errno(r, "Failed to set monitor mode: %m");
1972                         goto finish;
1973                 }
1974
1975                 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
1976                 if (r < 0) {
1977                         log_error_errno(r, "Failed to enable credentials: %m");
1978                         goto finish;
1979                 }
1980
1981                 r = sd_bus_negotiate_timestamp(bus, true);
1982                 if (r < 0) {
1983                         log_error_errno(r, "Failed to enable timestamps: %m");
1984                         goto finish;
1985                 }
1986
1987                 r = sd_bus_negotiate_fds(bus, true);
1988                 if (r < 0) {
1989                         log_error_errno(r, "Failed to enable fds: %m");
1990                         goto finish;
1991                 }
1992         }
1993
1994         if (arg_address)
1995                 r = sd_bus_set_address(bus, arg_address);
1996         else {
1997                 r = sd_bus_set_bus_client(bus, true);
1998                 if (r < 0) {
1999                         log_error_errno(r, "Failed to set bus client: %m");
2000                         goto finish;
2001                 }
2002
2003                 switch (arg_transport) {
2004
2005                 case BUS_TRANSPORT_LOCAL:
2006                         if (arg_user) {
2007                                 bus->is_user = true;
2008                                 r = bus_set_address_user(bus);
2009                         } else {
2010                                 bus->is_system = true;
2011                                 r = bus_set_address_system(bus);
2012                         }
2013                         break;
2014
2015                 case BUS_TRANSPORT_REMOTE:
2016                         r = bus_set_address_system_remote(bus, arg_host);
2017                         break;
2018
2019                 case BUS_TRANSPORT_CONTAINER:
2020                         r = bus_set_address_system_container(bus, arg_host);
2021                         break;
2022
2023                 default:
2024                         assert_not_reached("Hmm, unknown transport type.");
2025                 }
2026         }
2027         if (r < 0) {
2028                 log_error_errno(r, "Failed to set address: %m");
2029                 goto finish;
2030         }
2031
2032         r = sd_bus_start(bus);
2033         if (r < 0) {
2034                 log_error_errno(r, "Failed to connect to bus: %m");
2035                 goto finish;
2036         }
2037
2038         r = busctl_main(bus, argc, argv);
2039
2040 finish:
2041         pager_close();
2042
2043         strv_free(arg_matches);
2044
2045         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2046 }