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