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