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