chiark / gitweb /
busctl: split out introspection parser from tree logic so that we can reuse it for...
[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 "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
55 static void pager_open_if_enabled(void) {
56
57         /* Cache result before we open the pager */
58         if (arg_no_pager)
59                 return;
60
61         pager_open(false);
62 }
63
64 static int list_bus_names(sd_bus *bus, char **argv) {
65         _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
66         _cleanup_free_ char **merged = NULL;
67         _cleanup_hashmap_free_ Hashmap *names = NULL;
68         char **i;
69         int r;
70         size_t max_i = 0;
71         unsigned n = 0;
72         void *v;
73         char *k;
74         Iterator iterator;
75
76         assert(bus);
77
78         if (!arg_unique && !arg_acquired && !arg_activatable)
79                 arg_unique = arg_acquired = arg_activatable = true;
80
81         r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
82         if (r < 0) {
83                 log_error("Failed to list names: %s", strerror(-r));
84                 return r;
85         }
86
87         pager_open_if_enabled();
88
89         names = hashmap_new(&string_hash_ops);
90         if (!names)
91                 return log_oom();
92
93         STRV_FOREACH(i, acquired) {
94                 max_i = MAX(max_i, strlen(*i));
95
96                 r = hashmap_put(names, *i, INT_TO_PTR(1));
97                 if (r < 0) {
98                         log_error("Failed to add to hashmap: %s", strerror(-r));
99                         return r;
100                 }
101         }
102
103         STRV_FOREACH(i, activatable) {
104                 max_i = MAX(max_i, strlen(*i));
105
106                 r = hashmap_put(names, *i, INT_TO_PTR(2));
107                 if (r < 0 && r != -EEXIST) {
108                         log_error("Failed to add to hashmap: %s", strerror(-r));
109                         return r;
110                 }
111         }
112
113         merged = new(char*, hashmap_size(names) + 1);
114         HASHMAP_FOREACH_KEY(v, k, names, iterator)
115                 merged[n++] = k;
116
117         merged[n] = NULL;
118         strv_sort(merged);
119
120         if (arg_legend) {
121                 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
122                        (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
123
124                 if (arg_show_machine)
125                         puts(" MACHINE");
126                 else
127                         putchar('\n');
128         }
129
130         STRV_FOREACH(i, merged) {
131                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
132                 sd_id128_t mid;
133
134                 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
135                         /* Activatable */
136
137                         printf("%-*s", (int) max_i, *i);
138                         printf("          - -               -                (activatable) -                         -         ");
139                         if (arg_show_machine)
140                                 puts(" -");
141                         else
142                                 putchar('\n');
143                         continue;
144
145                 }
146
147                 if (!arg_unique && (*i)[0] == ':')
148                         continue;
149
150                 if (!arg_acquired && (*i)[0] != ':')
151                         continue;
152
153                 printf("%-*s", (int) max_i, *i);
154
155                 r = sd_bus_get_name_creds(bus, *i,
156                                      SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
157                                      SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
158                                      SD_BUS_CREDS_DESCRIPTION, &creds);
159                 if (r >= 0) {
160                         const char *unique, *session, *unit, *cn;
161                         pid_t pid;
162                         uid_t uid;
163
164                         r = sd_bus_creds_get_pid(creds, &pid);
165                         if (r >= 0) {
166                                 const char *comm = NULL;
167
168                                 sd_bus_creds_get_comm(creds, &comm);
169
170                                 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
171                         } else
172                                 fputs("          - -              ", stdout);
173
174                         r = sd_bus_creds_get_uid(creds, &uid);
175                         if (r >= 0) {
176                                 _cleanup_free_ char *u = NULL;
177
178                                 u = uid_to_name(uid);
179                                 if (!u)
180                                         return log_oom();
181
182                                 if (strlen(u) > 16)
183                                         u[16] = 0;
184
185                                 printf(" %-16s", u);
186                         } else
187                                 fputs(" -               ", stdout);
188
189                         r = sd_bus_creds_get_unique_name(creds, &unique);
190                         if (r >= 0)
191                                 printf(" %-13s", unique);
192                         else
193                                 fputs(" -            ", stdout);
194
195                         r = sd_bus_creds_get_unit(creds, &unit);
196                         if (r >= 0) {
197                                 _cleanup_free_ char *e;
198
199                                 e = ellipsize(unit, 25, 100);
200                                 if (!e)
201                                         return log_oom();
202
203                                 printf(" %-25s", e);
204                         } else
205                                 fputs(" -                        ", stdout);
206
207                         r = sd_bus_creds_get_session(creds, &session);
208                         if (r >= 0)
209                                 printf(" %-10s", session);
210                         else
211                                 fputs(" -         ", stdout);
212
213                         r = sd_bus_creds_get_description(creds, &cn);
214                         if (r >= 0)
215                                 printf(" %-19s", cn);
216                         else
217                                 fputs(" -                  ", stdout);
218
219                 } else
220                         printf("          - -               -                -             -                         -          -                  ");
221
222                 if (arg_show_machine) {
223                         r = sd_bus_get_name_machine_id(bus, *i, &mid);
224                         if (r >= 0) {
225                                 char m[SD_ID128_STRING_MAX];
226                                 printf(" %s\n", sd_id128_to_string(mid, m));
227                         } else
228                                 puts(" -");
229                 } else
230                         putchar('\n');
231         }
232
233         return 0;
234 }
235
236 static void print_subtree(const char *prefix, const char *path, char **l) {
237         const char *vertical, *space;
238         char **n;
239
240         /* We assume the list is sorted. Let's first skip over the
241          * entry we are looking at. */
242         for (;;) {
243                 if (!*l)
244                         return;
245
246                 if (!streq(*l, path))
247                         break;
248
249                 l++;
250         }
251
252         vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
253         space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
254
255         for (;;) {
256                 bool has_more = false;
257
258                 if (!*l || !path_startswith(*l, path))
259                         break;
260
261                 n = l + 1;
262                 for (;;) {
263                         if (!*n || !path_startswith(*n, path))
264                                 break;
265
266                         if (!path_startswith(*n, *l)) {
267                                 has_more = true;
268                                 break;
269                         }
270
271                         n++;
272                 }
273
274                 printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
275
276                 print_subtree(has_more ? vertical : space, *l, l);
277                 l = n;
278         }
279 }
280
281 static void print_tree(const char *prefix, char **l) {
282
283         pager_open_if_enabled();
284
285         prefix = strempty(prefix);
286
287         if (arg_list) {
288                 char **i;
289
290                 STRV_FOREACH(i, l)
291                         printf("%s%s\n", prefix, *i);
292                 return;
293         }
294
295         if (strv_isempty(l)) {
296                 printf("No objects discovered.\n");
297                 return;
298         }
299
300         if (streq(l[0], "/") && !l[1]) {
301                 printf("Only root object discovered.\n");
302                 return;
303         }
304
305         print_subtree(prefix, "/", l);
306 }
307
308 static int on_path(const char *path, void *userdata) {
309         Set *paths = userdata;
310         int r;
311
312         assert(paths);
313
314         r = set_put_strdup(paths, path);
315         if (r < 0)
316                 return log_oom();
317
318         return 0;
319 }
320
321 static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths) {
322         const XMLIntrospectOps ops = {
323                 .on_path = on_path,
324         };
325
326         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
327         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
328         const char *xml;
329         int r;
330
331         r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
332         if (r < 0) {
333                 log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
334                 return r;
335         }
336
337         r = sd_bus_message_read(reply, "s", &xml);
338         if (r < 0)
339                 return bus_log_parse_error(r);
340
341         /* fputs(xml, stdout); */
342         return parse_xml_introspect(path, xml, &ops, paths);
343 }
344
345 static int tree_one(sd_bus *bus, const char *service, const char *prefix) {
346         _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
347         _cleanup_free_ char **l = NULL;
348         char *m;
349         int r;
350
351         paths = set_new(&string_hash_ops);
352         if (!paths)
353                 return log_oom();
354
355         done = set_new(&string_hash_ops);
356         if (!done)
357                 return log_oom();
358
359         failed = set_new(&string_hash_ops);
360         if (!failed)
361                 return log_oom();
362
363         m = strdup("/");
364         if (!m)
365                 return log_oom();
366
367         r = set_put(paths, m);
368         if (r < 0) {
369                 free(m);
370                 return log_oom();
371         }
372
373         for (;;) {
374                 _cleanup_free_ char *p = NULL;
375                 int q;
376
377                 p = set_steal_first(paths);
378                 if (!p)
379                         break;
380
381                 if (set_contains(done, p) ||
382                     set_contains(failed, p))
383                         continue;
384
385                 q = find_nodes(bus, service, p, paths);
386                 if (q < 0) {
387                         if (r >= 0)
388                                 r = q;
389
390                         q = set_put(failed, p);
391                 } else
392                         q = set_put(done, p);
393
394                 if (q < 0)
395                         return log_oom();
396
397                 assert(q != 0);
398                 p = NULL;
399         }
400
401         l = set_get_strv(done);
402         if (!l)
403                 return log_oom();
404
405         strv_sort(l);
406         print_tree(prefix, l);
407
408         fflush(stdout);
409
410         return r;
411 }
412
413 static int tree(sd_bus *bus, char **argv) {
414         char **i;
415         int r = 0;
416
417         if (!arg_unique && !arg_acquired)
418                 arg_acquired = true;
419
420         if (strv_length(argv) <= 1) {
421                 _cleanup_strv_free_ char **names = NULL;
422                 bool not_first = false;
423
424                 r = sd_bus_list_names(bus, &names, NULL);
425                 if (r < 0) {
426                         log_error("Failed to get name list: %s", strerror(-r));
427                         return r;
428                 }
429
430                 pager_open_if_enabled();
431
432                 STRV_FOREACH(i, names) {
433                         int q;
434
435                         if (!arg_unique && (*i)[0] == ':')
436                                 continue;
437
438                         if (!arg_acquired && (*i)[0] == ':')
439                                 continue;
440
441                         if (not_first)
442                                 printf("\n");
443
444                         printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
445
446                         q = tree_one(bus, *i, NULL);
447                         if (q < 0 && r >= 0)
448                                 r = q;
449
450                         not_first = true;
451                 }
452         } else {
453                 pager_open_if_enabled();
454
455                 STRV_FOREACH(i, argv+1) {
456                         int q;
457
458                         if (i > argv+1)
459                                 printf("\n");
460
461                         if (argv[2])
462                                 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
463
464                         q = tree_one(bus, *i, NULL);
465                         if (q < 0 && r >= 0)
466                                 r = q;
467                 }
468         }
469
470         return r;
471 }
472
473 static int message_dump(sd_bus_message *m, FILE *f) {
474         return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
475 }
476
477 static int message_pcap(sd_bus_message *m, FILE *f) {
478         return bus_message_pcap_frame(m, arg_snaplen, f);
479 }
480
481 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
482         bool added_something = false;
483         char **i;
484         int r;
485
486         STRV_FOREACH(i, argv+1) {
487                 _cleanup_free_ char *m = NULL;
488
489                 if (!service_name_is_valid(*i)) {
490                         log_error("Invalid service name '%s'", *i);
491                         return -EINVAL;
492                 }
493
494                 m = strjoin("sender='", *i, "'", NULL);
495                 if (!m)
496                         return log_oom();
497
498                 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
499                 if (r < 0) {
500                         log_error("Failed to add match: %s", strerror(-r));
501                         return r;
502                 }
503
504                 added_something = true;
505         }
506
507         STRV_FOREACH(i, arg_matches) {
508                 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
509                 if (r < 0) {
510                         log_error("Failed to add match: %s", strerror(-r));
511                         return r;
512                 }
513
514                 added_something = true;
515         }
516
517         if (!added_something) {
518                 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
519                 if (r < 0) {
520                         log_error("Failed to add match: %s", strerror(-r));
521                         return r;
522                 }
523         }
524
525         for (;;) {
526                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
527
528                 r = sd_bus_process(bus, &m);
529                 if (r < 0) {
530                         log_error("Failed to process bus: %s", strerror(-r));
531                         return r;
532                 }
533
534                 if (m) {
535                         dump(m, stdout);
536                         continue;
537                 }
538
539                 if (r > 0)
540                         continue;
541
542                 r = sd_bus_wait(bus, (uint64_t) -1);
543                 if (r < 0) {
544                         log_error("Failed to wait for bus: %s", strerror(-r));
545                         return r;
546                 }
547         }
548 }
549
550 static int capture(sd_bus *bus, char *argv[]) {
551         int r;
552
553         if (isatty(fileno(stdout)) > 0) {
554                 log_error("Refusing to write message data to console, please redirect output to a file.");
555                 return -EINVAL;
556         }
557
558         bus_pcap_header(arg_snaplen, stdout);
559
560         r = monitor(bus, argv, message_pcap);
561         if (r < 0)
562                 return r;
563
564         if (ferror(stdout)) {
565                 log_error("Couldn't write capture file.");
566                 return -EIO;
567         }
568
569         return r;
570 }
571
572 static int status(sd_bus *bus, char *argv[]) {
573         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
574         pid_t pid;
575         int r;
576
577         assert(bus);
578
579         if (strv_length(argv) != 2) {
580                 log_error("Expects one argument.");
581                 return -EINVAL;
582         }
583
584         r = parse_pid(argv[1], &pid);
585         if (r < 0)
586                 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
587         else
588                 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
589
590         if (r < 0) {
591                 log_error("Failed to get credentials: %s", strerror(-r));
592                 return r;
593         }
594
595         bus_creds_dump(creds, NULL);
596         return 0;
597 }
598
599 static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
600         char **p;
601         int r;
602
603         assert(m);
604         assert(signature);
605         assert(x);
606
607         p = *x;
608
609         for (;;) {
610                 const char *v;
611                 char t;
612
613                 t = *signature;
614                 v = *p;
615
616                 if (t == 0)
617                         break;
618                 if (!v) {
619                         log_error("Too few parameters for signature.");
620                         return -EINVAL;
621                 }
622
623                 signature++;
624                 p++;
625
626                 switch (t) {
627
628                 case SD_BUS_TYPE_BOOLEAN:
629
630                         r = parse_boolean(v);
631                         if (r < 0) {
632                                 log_error("Failed to parse as boolean: %s", v);
633                                 return r;
634                         }
635
636                         r = sd_bus_message_append_basic(m, t, &r);
637                         break;
638
639                 case SD_BUS_TYPE_BYTE: {
640                         uint8_t z;
641
642                         r = safe_atou8(v, &z);
643                         if (r < 0) {
644                                 log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
645                                 return r;
646                         }
647
648                         r = sd_bus_message_append_basic(m, t, &z);
649                         break;
650                 }
651
652                 case SD_BUS_TYPE_INT16: {
653                         int16_t z;
654
655                         r = safe_atoi16(v, &z);
656                         if (r < 0) {
657                                 log_error("Failed to parse as signed 16bit integer: %s", v);
658                                 return r;
659                         }
660
661                         r = sd_bus_message_append_basic(m, t, &z);
662                         break;
663                 }
664
665                 case SD_BUS_TYPE_UINT16: {
666                         uint16_t z;
667
668                         r = safe_atou16(v, &z);
669                         if (r < 0) {
670                                 log_error("Failed to parse as unsigned 16bit integer: %s", v);
671                                 return r;
672                         }
673
674                         r = sd_bus_message_append_basic(m, t, &z);
675                         break;
676                 }
677
678                 case SD_BUS_TYPE_INT32: {
679                         int32_t z;
680
681                         r = safe_atoi32(v, &z);
682                         if (r < 0) {
683                                 log_error("Failed to parse as signed 32bit integer: %s", v);
684                                 return r;
685                         }
686
687                         r = sd_bus_message_append_basic(m, t, &z);
688                         break;
689                 }
690
691                 case SD_BUS_TYPE_UINT32: {
692                         uint32_t z;
693
694                         r = safe_atou32(v, &z);
695                         if (r < 0) {
696                                 log_error("Failed to parse as unsigned 32bit integer: %s", v);
697                                 return r;
698                         }
699
700                         r = sd_bus_message_append_basic(m, t, &z);
701                         break;
702                 }
703
704                 case SD_BUS_TYPE_INT64: {
705                         int64_t z;
706
707                         r = safe_atoi64(v, &z);
708                         if (r < 0) {
709                                 log_error("Failed to parse as signed 64bit integer: %s", v);
710                                 return r;
711                         }
712
713                         r = sd_bus_message_append_basic(m, t, &z);
714                         break;
715                 }
716
717                 case SD_BUS_TYPE_UINT64: {
718                         uint64_t z;
719
720                         r = safe_atou64(v, &z);
721                         if (r < 0) {
722                                 log_error("Failed to parse as unsigned 64bit integer: %s", v);
723                                 return r;
724                         }
725
726                         r = sd_bus_message_append_basic(m, t, &z);
727                         break;
728                 }
729
730
731                 case SD_BUS_TYPE_DOUBLE: {
732                         double z;
733
734                         r = safe_atod(v, &z);
735                         if (r < 0) {
736                                 log_error("Failed to parse as double precision floating point: %s", v);
737                                 return r;
738                         }
739
740                         r = sd_bus_message_append_basic(m, t, &z);
741                         break;
742                 }
743
744                 case SD_BUS_TYPE_STRING:
745                 case SD_BUS_TYPE_OBJECT_PATH:
746                 case SD_BUS_TYPE_SIGNATURE:
747
748                         r = sd_bus_message_append_basic(m, t, v);
749                         break;
750
751                 case SD_BUS_TYPE_ARRAY: {
752                         uint32_t n;
753                         size_t k;
754
755                         r = safe_atou32(v, &n);
756                         if (r < 0) {
757                                 log_error("Failed to parse number of array entries: %s", v);
758                                 return r;
759                         }
760
761                         r = signature_element_length(signature, &k);
762                         if (r < 0) {
763                                 log_error("Invalid array signature.");
764                                 return r;
765                         }
766
767                         {
768                                 unsigned i;
769                                 char s[k + 1];
770                                 memcpy(s, signature, k);
771                                 s[k] = 0;
772
773                                 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
774                                 if (r < 0)
775                                         return bus_log_create_error(r);
776
777                                 for (i = 0; i < n; i++) {
778                                         r = message_append_cmdline(m, s, &p);
779                                         if (r < 0)
780                                                 return r;
781                                 }
782                         }
783
784                         signature += k;
785
786                         r = sd_bus_message_close_container(m);
787                         break;
788                 }
789
790                 case SD_BUS_TYPE_VARIANT:
791                         r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
792                         if (r < 0)
793                                 return bus_log_create_error(r);
794
795                         r = message_append_cmdline(m, v, &p);
796                         if (r < 0)
797                                 return r;
798
799                         r = sd_bus_message_close_container(m);
800                         break;
801
802                 case SD_BUS_TYPE_STRUCT_BEGIN:
803                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
804                         size_t k;
805
806                         signature--;
807                         p--;
808
809                         r = signature_element_length(signature, &k);
810                         if (r < 0) {
811                                 log_error("Invalid struct/dict entry signature.");
812                                 return r;
813                         }
814
815                         {
816                                 char s[k-1];
817                                 memcpy(s, signature + 1, k - 2);
818                                 s[k - 2] = 0;
819
820                                 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
821                                 if (r < 0)
822                                         return bus_log_create_error(r);
823
824                                 r = message_append_cmdline(m, s, &p);
825                                 if (r < 0)
826                                         return r;
827                         }
828
829                         signature += k;
830
831                         r = sd_bus_message_close_container(m);
832                         break;
833                 }
834
835                 case SD_BUS_TYPE_UNIX_FD:
836                         log_error("UNIX file descriptor not supported as type.");
837                         return -EINVAL;
838
839                 default:
840                         log_error("Unknown signature type %c.", t);
841                         return -EINVAL;
842                 }
843
844                 if (r < 0)
845                         return bus_log_create_error(r);
846         }
847
848         *x = p;
849         return 0;
850 }
851
852 static int call(sd_bus *bus, char *argv[]) {
853         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
854         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
855         int r;
856
857         assert(bus);
858
859         if (strv_length(argv) < 5) {
860                 log_error("Expects at least four arguments.");
861                 return -EINVAL;
862         }
863
864         r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
865         if (r < 0) {
866                 log_error("Failed to prepare bus message: %s", strerror(-r));
867                 return r;
868         }
869
870         if (!isempty(argv[5])) {
871                 char **p;
872
873                 p = argv+6;
874
875                 r = message_append_cmdline(m, argv[5], &p);
876                 if (r < 0)
877                         return r;
878
879                 if (*p) {
880                         log_error("Too many parameters for signature.");
881                         return -EINVAL;
882                 }
883         }
884
885         r = sd_bus_call(bus, m, 0, &error, &reply);
886         if (r < 0) {
887                 log_error("%s", bus_error_message(&error, r));
888                 return r;
889         }
890
891         r = sd_bus_message_is_empty(reply);
892         if (r < 0)
893                 return bus_log_parse_error(r);
894         if (r == 0 && !arg_quiet) {
895                 pager_open_if_enabled();
896                 bus_message_dump(reply, stdout, 0);
897         }
898
899         return 0;
900 }
901
902 static int get_property(sd_bus *bus, char *argv[]) {
903         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
904         unsigned n;
905         int r;
906
907         assert(bus);
908
909         n = strv_length(argv);
910         if (n < 3) {
911                 log_error("Expects at least three arguments.");
912                 return -EINVAL;
913         }
914
915         if (n < 5) {
916                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
917                 bool not_first = false;
918
919                 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", strempty(argv[3]));
920                 if (r < 0) {
921                         log_error("%s", bus_error_message(&error, r));
922                         return r;
923                 }
924
925                 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
926                 if (r < 0)
927                         return bus_log_parse_error(r);
928
929                 for (;;) {
930                         const char *name;
931
932                         r = sd_bus_message_enter_container(reply, 'e', "sv");
933                         if (r < 0)
934                                 return bus_log_parse_error(r);
935
936                         if (r == 0)
937                                 break;
938
939                         r = sd_bus_message_read(reply, "s", &name);
940                         if (r < 0)
941                                 return bus_log_parse_error(r);
942
943                         if (not_first)
944                                 printf("\n");
945
946                         printf("Property %s:\n", name);
947
948                         r = sd_bus_message_enter_container(reply, 'v', NULL);
949                         if (r < 0)
950                                 return bus_log_parse_error(r);
951
952                         pager_open_if_enabled();
953                         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
954
955                         r = sd_bus_message_exit_container(reply);
956                         if (r < 0)
957                                 return bus_log_parse_error(r);
958
959                         r = sd_bus_message_exit_container(reply);
960                         if (r < 0)
961                                 return bus_log_parse_error(r);
962
963                         not_first = true;
964                 }
965
966                 r = sd_bus_message_exit_container(reply);
967                 if (r < 0)
968                         return bus_log_parse_error(r);
969         } else {
970                 char **i;
971
972                 STRV_FOREACH(i, argv + 4) {
973                         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
974
975                         r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
976                         if (r < 0) {
977                                 log_error("%s", bus_error_message(&error, r));
978                                 return r;
979                         }
980
981                         r = sd_bus_message_enter_container(reply, 'v', NULL);
982                         if (r < 0)
983                                 return bus_log_parse_error(r);
984
985                         if (i > argv + 4)
986                                 printf("\n");
987
988                         if (argv[5])
989                                 printf("Property %s:\n", *i);
990
991                         pager_open_if_enabled();
992                         bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
993
994                         r = sd_bus_message_exit_container(reply);
995                         if (r < 0)
996                                 return bus_log_parse_error(r);
997                 }
998         }
999
1000         return 0;
1001 }
1002
1003 static int help(void) {
1004         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1005                "Introspect the bus.\n\n"
1006                "  -h --help               Show this help\n"
1007                "     --version            Show package version\n"
1008                "     --no-pager           Do not pipe output into a pager\n"
1009                "     --no-legend          Do not show the headers and footers\n"
1010                "     --system             Connect to system bus\n"
1011                "     --user               Connect to user bus\n"
1012                "  -H --host=[USER@]HOST   Operate on remote host\n"
1013                "  -M --machine=CONTAINER  Operate on local container\n"
1014                "     --address=ADDRESS    Connect to bus specified by address\n"
1015                "     --show-machine       Show machine ID column in list\n"
1016                "     --unique             Only show unique names\n"
1017                "     --acquired           Only show acquired names\n"
1018                "     --activatable        Only show activatable names\n"
1019                "     --match=MATCH        Only show matching messages\n"
1020                "     --list               Don't show tree, but simple object path list\n"
1021                "     --quiet              Don't show method call reply\n\n"
1022                "Commands:\n"
1023                "  list                    List bus names\n"
1024                "  tree [SERVICE...]       Show object tree of service\n"
1025                "  monitor [SERVICE...]    Show bus traffic\n"
1026                "  capture [SERVICE...]    Capture bus traffic as pcap\n"
1027                "  status SERVICE          Show service name status\n"
1028                "  call SERVICE PATH INTERFACE METHOD [SIGNATURE [ARGUMENTS...]]\n"
1029                "                          Call a method\n"
1030                "  get-property SERVICE PATH [INTERFACE [PROPERTY...]]\n"
1031                "                          Get property value\n"
1032                "  help                    Show this help\n"
1033                , program_invocation_short_name);
1034
1035         return 0;
1036 }
1037
1038 static int parse_argv(int argc, char *argv[]) {
1039
1040         enum {
1041                 ARG_VERSION = 0x100,
1042                 ARG_NO_PAGER,
1043                 ARG_NO_LEGEND,
1044                 ARG_SYSTEM,
1045                 ARG_USER,
1046                 ARG_ADDRESS,
1047                 ARG_MATCH,
1048                 ARG_SHOW_MACHINE,
1049                 ARG_UNIQUE,
1050                 ARG_ACQUIRED,
1051                 ARG_ACTIVATABLE,
1052                 ARG_SIZE,
1053                 ARG_LIST,
1054         };
1055
1056         static const struct option options[] = {
1057                 { "help",         no_argument,       NULL, 'h'              },
1058                 { "version",      no_argument,       NULL, ARG_VERSION      },
1059                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
1060                 { "no-legend",    no_argument,       NULL, ARG_NO_LEGEND    },
1061                 { "system",       no_argument,       NULL, ARG_SYSTEM       },
1062                 { "user",         no_argument,       NULL, ARG_USER         },
1063                 { "address",      required_argument, NULL, ARG_ADDRESS      },
1064                 { "show-machine", no_argument,       NULL, ARG_SHOW_MACHINE },
1065                 { "unique",       no_argument,       NULL, ARG_UNIQUE       },
1066                 { "acquired",     no_argument,       NULL, ARG_ACQUIRED     },
1067                 { "activatable",  no_argument,       NULL, ARG_ACTIVATABLE  },
1068                 { "match",        required_argument, NULL, ARG_MATCH        },
1069                 { "host",         required_argument, NULL, 'H'              },
1070                 { "machine",      required_argument, NULL, 'M'              },
1071                 { "size",         required_argument, NULL, ARG_SIZE         },
1072                 { "list",         no_argument,       NULL, ARG_LIST         },
1073                 { "quiet",        no_argument,       NULL, 'q'              },
1074                 {},
1075         };
1076
1077         int c, r;
1078
1079         assert(argc >= 0);
1080         assert(argv);
1081
1082         while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
1083
1084                 switch (c) {
1085
1086                 case 'h':
1087                         return help();
1088
1089                 case ARG_VERSION:
1090                         puts(PACKAGE_STRING);
1091                         puts(SYSTEMD_FEATURES);
1092                         return 0;
1093
1094                 case ARG_NO_PAGER:
1095                         arg_no_pager = true;
1096                         break;
1097
1098                 case ARG_NO_LEGEND:
1099                         arg_legend = false;
1100                         break;
1101
1102                 case ARG_USER:
1103                         arg_user = true;
1104                         break;
1105
1106                 case ARG_SYSTEM:
1107                         arg_user = false;
1108                         break;
1109
1110                 case ARG_ADDRESS:
1111                         arg_address = optarg;
1112                         break;
1113
1114                 case ARG_SHOW_MACHINE:
1115                         arg_show_machine = true;
1116                         break;
1117
1118                 case ARG_UNIQUE:
1119                         arg_unique = true;
1120                         break;
1121
1122                 case ARG_ACQUIRED:
1123                         arg_acquired = true;
1124                         break;
1125
1126                 case ARG_ACTIVATABLE:
1127                         arg_activatable = true;
1128                         break;
1129
1130                 case ARG_MATCH:
1131                         if (strv_extend(&arg_matches, optarg) < 0)
1132                                 return log_oom();
1133                         break;
1134
1135                 case ARG_SIZE: {
1136                         off_t o;
1137
1138                         r = parse_size(optarg, 0, &o);
1139                         if (r < 0) {
1140                                 log_error("Failed to parse size: %s", optarg);
1141                                 return r;
1142                         }
1143
1144                         if ((off_t) (size_t) o !=  o) {
1145                                 log_error("Size out of range.");
1146                                 return -E2BIG;
1147                         }
1148
1149                         arg_snaplen = (size_t) o;
1150                         break;
1151                 }
1152
1153                 case ARG_LIST:
1154                         arg_list = true;
1155                         break;
1156
1157                 case 'H':
1158                         arg_transport = BUS_TRANSPORT_REMOTE;
1159                         arg_host = optarg;
1160                         break;
1161
1162                 case 'M':
1163                         arg_transport = BUS_TRANSPORT_CONTAINER;
1164                         arg_host = optarg;
1165                         break;
1166
1167                 case 'q':
1168                         arg_quiet = true;
1169                         break;
1170
1171                 case '?':
1172                         return -EINVAL;
1173
1174                 default:
1175                         assert_not_reached("Unhandled option");
1176                 }
1177
1178         return 1;
1179 }
1180
1181 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
1182         assert(bus);
1183
1184         if (optind >= argc ||
1185             streq(argv[optind], "list"))
1186                 return list_bus_names(bus, argv + optind);
1187
1188         if (streq(argv[optind], "monitor"))
1189                 return monitor(bus, argv + optind, message_dump);
1190
1191         if (streq(argv[optind], "capture"))
1192                 return capture(bus, argv + optind);
1193
1194         if (streq(argv[optind], "status"))
1195                 return status(bus, argv + optind);
1196
1197         if (streq(argv[optind], "tree"))
1198                 return tree(bus, argv + optind);
1199
1200         if (streq(argv[optind], "call"))
1201                 return call(bus, argv + optind);
1202
1203         if (streq(argv[optind], "get-property"))
1204                 return get_property(bus, argv + optind);
1205
1206         if (streq(argv[optind], "help"))
1207                 return help();
1208
1209         log_error("Unknown command '%s'", argv[optind]);
1210         return -EINVAL;
1211 }
1212
1213 int main(int argc, char *argv[]) {
1214         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1215         int r;
1216
1217         log_parse_environment();
1218         log_open();
1219
1220         r = parse_argv(argc, argv);
1221         if (r <= 0)
1222                 goto finish;
1223
1224         r = sd_bus_new(&bus);
1225         if (r < 0) {
1226                 log_error("Failed to allocate bus: %s", strerror(-r));
1227                 goto finish;
1228         }
1229
1230         if (streq_ptr(argv[optind], "monitor") ||
1231             streq_ptr(argv[optind], "capture")) {
1232
1233                 r = sd_bus_set_monitor(bus, true);
1234                 if (r < 0) {
1235                         log_error("Failed to set monitor mode: %s", strerror(-r));
1236                         goto finish;
1237                 }
1238
1239                 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
1240                 if (r < 0) {
1241                         log_error("Failed to enable credentials: %s", strerror(-r));
1242                         goto finish;
1243                 }
1244
1245                 r = sd_bus_negotiate_timestamp(bus, true);
1246                 if (r < 0) {
1247                         log_error("Failed to enable timestamps: %s", strerror(-r));
1248                         goto finish;
1249                 }
1250
1251                 r = sd_bus_negotiate_fds(bus, true);
1252                 if (r < 0) {
1253                         log_error("Failed to enable fds: %s", strerror(-r));
1254                         goto finish;
1255                 }
1256         }
1257
1258         if (arg_address)
1259                 r = sd_bus_set_address(bus, arg_address);
1260         else {
1261                 switch (arg_transport) {
1262
1263                 case BUS_TRANSPORT_LOCAL:
1264                         if (arg_user)
1265                                 r = bus_set_address_user(bus);
1266                         else
1267                                 r = bus_set_address_system(bus);
1268                         break;
1269
1270                 case BUS_TRANSPORT_REMOTE:
1271                         r = bus_set_address_system_remote(bus, arg_host);
1272                         break;
1273
1274                 case BUS_TRANSPORT_CONTAINER:
1275                         r = bus_set_address_system_container(bus, arg_host);
1276                         break;
1277
1278                 default:
1279                         assert_not_reached("Hmm, unknown transport type.");
1280                 }
1281         }
1282         if (r < 0) {
1283                 log_error("Failed to set address: %s", strerror(-r));
1284                 goto finish;
1285         }
1286
1287         r = sd_bus_set_bus_client(bus, true);
1288         if (r < 0) {
1289                 log_error("Failed to set bus client: %s", strerror(-r));
1290                 goto finish;
1291         }
1292
1293         r = sd_bus_start(bus);
1294         if (r < 0) {
1295                 log_error("Failed to connect to bus: %s", strerror(-r));
1296                 goto finish;
1297         }
1298
1299         r = busctl_main(bus, argc, argv);
1300
1301 finish:
1302         pager_close();
1303
1304         strv_free(arg_matches);
1305
1306         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1307 }