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