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