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