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