LCOV - code coverage report
Current view: top level - busctl - busctl.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 24 1406 1.7 %
Date: 2019-08-22 15:41:25 Functions: 5 46 10.9 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <getopt.h>
       4             : 
       5             : #include "sd-bus.h"
       6             : 
       7             : #include "alloc-util.h"
       8             : #include "bus-dump.h"
       9             : #include "bus-internal.h"
      10             : #include "bus-message.h"
      11             : #include "bus-signature.h"
      12             : #include "bus-type.h"
      13             : #include "bus-util.h"
      14             : #include "busctl-introspect.h"
      15             : #include "escape.h"
      16             : #include "fd-util.h"
      17             : #include "fileio.h"
      18             : #include "format-table.h"
      19             : #include "json.h"
      20             : #include "locale-util.h"
      21             : #include "log.h"
      22             : #include "main-func.h"
      23             : #include "pager.h"
      24             : #include "parse-util.h"
      25             : #include "path-util.h"
      26             : #include "pretty-print.h"
      27             : #include "set.h"
      28             : #include "sort-util.h"
      29             : #include "strv.h"
      30             : #include "terminal-util.h"
      31             : #include "user-util.h"
      32             : #include "verbs.h"
      33             : 
      34             : static enum {
      35             :         JSON_OFF,
      36             :         JSON_SHORT,
      37             :         JSON_PRETTY,
      38             : } arg_json = JSON_OFF;
      39             : static PagerFlags arg_pager_flags = 0;
      40             : static bool arg_legend = true;
      41             : static const 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 const 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             : static bool arg_verbose = false;
      54             : static bool arg_xml_interface = false;
      55             : static bool arg_expect_reply = true;
      56             : static bool arg_auto_start = true;
      57             : static bool arg_allow_interactive_authorization = true;
      58             : static bool arg_augment_creds = true;
      59             : static bool arg_watch_bind = false;
      60             : static usec_t arg_timeout = 0;
      61             : static const char *arg_destination = NULL;
      62             : 
      63           4 : STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
      64             : 
      65             : #define NAME_IS_ACQUIRED INT_TO_PTR(1)
      66             : #define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
      67             : 
      68             : static int json_transform_message(sd_bus_message *m, JsonVariant **ret);
      69             : static void json_dump_with_flags(JsonVariant *v, FILE *f);
      70             : 
      71           0 : static int acquire_bus(bool set_monitor, sd_bus **ret) {
      72           0 :         _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
      73             :         int r;
      74             : 
      75           0 :         r = sd_bus_new(&bus);
      76           0 :         if (r < 0)
      77           0 :                 return log_error_errno(r, "Failed to allocate bus: %m");
      78             : 
      79           0 :         if (set_monitor) {
      80           0 :                 r = sd_bus_set_monitor(bus, true);
      81           0 :                 if (r < 0)
      82           0 :                         return log_error_errno(r, "Failed to set monitor mode: %m");
      83             : 
      84           0 :                 r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
      85           0 :                 if (r < 0)
      86           0 :                         return log_error_errno(r, "Failed to enable credentials: %m");
      87             : 
      88           0 :                 r = sd_bus_negotiate_timestamp(bus, true);
      89           0 :                 if (r < 0)
      90           0 :                         return log_error_errno(r, "Failed to enable timestamps: %m");
      91             : 
      92           0 :                 r = sd_bus_negotiate_fds(bus, true);
      93           0 :                 if (r < 0)
      94           0 :                         return log_error_errno(r, "Failed to enable fds: %m");
      95             :         }
      96             : 
      97           0 :         r = sd_bus_set_bus_client(bus, true);
      98           0 :         if (r < 0)
      99           0 :                 return log_error_errno(r, "Failed to set bus client: %m");
     100             : 
     101           0 :         r = sd_bus_set_watch_bind(bus, arg_watch_bind);
     102           0 :         if (r < 0)
     103           0 :                 return log_error_errno(r, "Failed to set watch-bind setting to '%s': %m", yes_no(arg_watch_bind));
     104             : 
     105           0 :         if (arg_address)
     106           0 :                 r = sd_bus_set_address(bus, arg_address);
     107             :         else {
     108           0 :                 switch (arg_transport) {
     109             : 
     110           0 :                 case BUS_TRANSPORT_LOCAL:
     111           0 :                         if (arg_user) {
     112           0 :                                 bus->is_user = true;
     113           0 :                                 r = bus_set_address_user(bus);
     114             :                         } else {
     115           0 :                                 bus->is_system = true;
     116           0 :                                 r = bus_set_address_system(bus);
     117             :                         }
     118           0 :                         break;
     119             : 
     120           0 :                 case BUS_TRANSPORT_REMOTE:
     121           0 :                         r = bus_set_address_system_remote(bus, arg_host);
     122           0 :                         break;
     123             : 
     124           0 :                 case BUS_TRANSPORT_MACHINE:
     125           0 :                         r = bus_set_address_system_machine(bus, arg_host);
     126           0 :                         break;
     127             : 
     128           0 :                 default:
     129           0 :                         assert_not_reached("Hmm, unknown transport type.");
     130             :                 }
     131             :         }
     132           0 :         if (r < 0)
     133           0 :                 return log_error_errno(r, "Failed to set address: %m");
     134             : 
     135           0 :         r = sd_bus_start(bus);
     136           0 :         if (r < 0)
     137           0 :                 return log_error_errno(r, "Failed to connect to bus: %m");
     138             : 
     139           0 :         *ret = TAKE_PTR(bus);
     140             : 
     141           0 :         return 0;
     142             : }
     143             : 
     144           0 : static int list_bus_names(int argc, char **argv, void *userdata) {
     145           0 :         _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
     146           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     147           0 :         _cleanup_hashmap_free_ Hashmap *names = NULL;
     148           0 :         _cleanup_(table_unrefp) Table *table = NULL;
     149             :         Iterator iterator;
     150             :         char **i, *k;
     151             :         void *v;
     152             :         int r;
     153             : 
     154             :         enum {
     155             :                 COLUMN_ACTIVATABLE,
     156             :                 COLUMN_NAME,
     157             :                 COLUMN_PID,
     158             :                 COLUMN_PROCESS,
     159             :                 COLUMN_USER,
     160             :                 COLUMN_CONNECTION,
     161             :                 COLUMN_UNIT,
     162             :                 COLUMN_SESSION,
     163             :                 COLUMN_DESCRIPTION,
     164             :                 COLUMN_MACHINE,
     165             :         };
     166             : 
     167           0 :         if (!arg_unique && !arg_acquired && !arg_activatable)
     168           0 :                 arg_unique = arg_acquired = arg_activatable = true;
     169             : 
     170           0 :         r = acquire_bus(false, &bus);
     171           0 :         if (r < 0)
     172           0 :                 return r;
     173             : 
     174           0 :         r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
     175           0 :         if (r < 0)
     176           0 :                 return log_error_errno(r, "Failed to list names: %m");
     177             : 
     178           0 :         names = hashmap_new(&string_hash_ops);
     179           0 :         if (!names)
     180           0 :                 return log_oom();
     181             : 
     182           0 :         STRV_FOREACH(i, acquired) {
     183           0 :                 r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
     184           0 :                 if (r < 0)
     185           0 :                         return log_error_errno(r, "Failed to add to hashmap: %m");
     186             :         }
     187             : 
     188           0 :         STRV_FOREACH(i, activatable) {
     189           0 :                 r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
     190           0 :                 if (r < 0 && r != -EEXIST)
     191           0 :                         return log_error_errno(r, "Failed to add to hashmap: %m");
     192             :         }
     193             : 
     194           0 :         table = table_new("activatable", "name", "pid", "process", "user", "connection", "unit", "session", "description", "machine");
     195           0 :         if (!table)
     196           0 :                 return log_oom();
     197             : 
     198           0 :         r = table_set_align_percent(table, table_get_cell(table, 0, COLUMN_PID), 100);
     199           0 :         if (r < 0)
     200           0 :                 return log_error_errno(r, "Failed to set alignment: %m");
     201             : 
     202           0 :         r = table_set_empty_string(table, "-");
     203           0 :         if (r < 0)
     204           0 :                 return log_error_errno(r, "Failed to set empty string: %m");
     205             : 
     206           0 :         r = table_set_sort(table, COLUMN_NAME, (size_t) -1);
     207           0 :         if (r < 0)
     208           0 :                 return log_error_errno(r, "Failed to set sort column: %m");
     209             : 
     210           0 :         if (arg_show_machine)
     211           0 :                 r = table_set_display(table, COLUMN_NAME, COLUMN_PID, COLUMN_PROCESS, COLUMN_USER, COLUMN_CONNECTION, COLUMN_UNIT, COLUMN_SESSION, COLUMN_DESCRIPTION, COLUMN_MACHINE, (size_t) -1);
     212             :         else
     213           0 :                 r = table_set_display(table, COLUMN_NAME, COLUMN_PID, COLUMN_PROCESS, COLUMN_USER, COLUMN_CONNECTION, COLUMN_UNIT, COLUMN_SESSION, COLUMN_DESCRIPTION, (size_t) -1);
     214           0 :         if (r < 0)
     215           0 :                 return log_error_errno(r, "Failed to set columns to display: %m");
     216             : 
     217           0 :         table_set_header(table, arg_legend);
     218             : 
     219           0 :         HASHMAP_FOREACH_KEY(v, k, names, iterator) {
     220           0 :                 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
     221             : 
     222           0 :                 if (v == NAME_IS_ACTIVATABLE) {
     223           0 :                         r = table_add_many(
     224             :                                         table,
     225             :                                         TABLE_INT, PTR_TO_INT(v),
     226             :                                         TABLE_STRING, k,
     227             :                                         TABLE_EMPTY,
     228             :                                         TABLE_EMPTY,
     229             :                                         TABLE_EMPTY,
     230             :                                         TABLE_STRING, "(activatable)", TABLE_SET_COLOR, ansi_grey(),
     231             :                                         TABLE_EMPTY,
     232             :                                         TABLE_EMPTY,
     233             :                                         TABLE_EMPTY,
     234             :                                         TABLE_EMPTY);
     235           0 :                         if (r < 0)
     236           0 :                                 return log_error_errno(r, "Failed to fill line: %m");
     237             : 
     238           0 :                         continue;
     239             :                 }
     240             : 
     241           0 :                 assert(v == NAME_IS_ACQUIRED);
     242             : 
     243           0 :                 if (!arg_unique && k[0] == ':')
     244           0 :                         continue;
     245             : 
     246           0 :                 if (!arg_acquired && k[0] != ':')
     247           0 :                         continue;
     248             : 
     249           0 :                 r = table_add_many(table,
     250             :                                    TABLE_INT, PTR_TO_INT(v),
     251             :                                    TABLE_STRING, k);
     252           0 :                 if (r < 0)
     253           0 :                         return log_error_errno(r, "Failed to add name %s to table: %m", k);
     254             : 
     255           0 :                 r = sd_bus_get_name_creds(
     256             :                                 bus, k,
     257           0 :                                 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
     258             :                                 SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
     259             :                                 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
     260             :                                 SD_BUS_CREDS_DESCRIPTION, &creds);
     261           0 :                 if (r < 0) {
     262           0 :                         log_debug_errno(r, "Failed to acquire credentials of service %s, ignoring: %m", k);
     263             : 
     264           0 :                         r = table_fill_empty(table, COLUMN_MACHINE);
     265             :                 } else {
     266           0 :                         const char *unique = NULL, *session = NULL, *unit = NULL, *cn = NULL;
     267             :                         pid_t pid;
     268             :                         uid_t uid;
     269             : 
     270           0 :                         r = sd_bus_creds_get_pid(creds, &pid);
     271           0 :                         if (r >= 0) {
     272           0 :                                 const char *comm = NULL;
     273             : 
     274           0 :                                 (void) sd_bus_creds_get_comm(creds, &comm);
     275             : 
     276           0 :                                 r = table_add_many(table,
     277             :                                                    TABLE_PID, pid,
     278             :                                                    TABLE_STRING, strna(comm));
     279             :                         } else
     280           0 :                                 r = table_add_many(table, TABLE_EMPTY, TABLE_EMPTY);
     281           0 :                         if (r < 0)
     282           0 :                                 return log_error_errno(r, "Failed to add fields to table: %m");
     283             : 
     284           0 :                         r = sd_bus_creds_get_euid(creds, &uid);
     285           0 :                         if (r >= 0) {
     286           0 :                                 _cleanup_free_ char *u = NULL;
     287             : 
     288           0 :                                 u = uid_to_name(uid);
     289           0 :                                 if (!u)
     290           0 :                                         return log_oom();
     291             : 
     292           0 :                                 r = table_add_cell(table, NULL, TABLE_STRING, u);
     293             :                         } else
     294           0 :                                 r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
     295           0 :                         if (r < 0)
     296           0 :                                 return log_error_errno(r, "Failed to add field to table: %m");
     297             : 
     298           0 :                         (void) sd_bus_creds_get_unique_name(creds, &unique);
     299           0 :                         (void) sd_bus_creds_get_unit(creds, &unit);
     300           0 :                         (void) sd_bus_creds_get_session(creds, &session);
     301           0 :                         (void) sd_bus_creds_get_description(creds, &cn);
     302             : 
     303           0 :                         r = table_add_many(
     304             :                                         table,
     305             :                                         TABLE_STRING, unique,
     306             :                                         TABLE_STRING, unit,
     307             :                                         TABLE_STRING, session,
     308             :                                         TABLE_STRING, cn);
     309             :                 }
     310           0 :                 if (r < 0)
     311           0 :                         return log_error_errno(r, "Failed to add fields to table: %m");
     312             : 
     313           0 :                 if (arg_show_machine) {
     314             :                         sd_id128_t mid;
     315             : 
     316           0 :                         r = sd_bus_get_name_machine_id(bus, k, &mid);
     317           0 :                         if (r < 0)
     318           0 :                                 log_debug_errno(r, "Failed to acquire credentials of service %s, ignoring: %m", k);
     319             :                         else {
     320             :                                 char m[SD_ID128_STRING_MAX];
     321             : 
     322           0 :                                 r = table_add_cell(table, NULL, TABLE_STRING, sd_id128_to_string(mid, m));
     323           0 :                                 if (r < 0)
     324           0 :                                         return log_error_errno(r, "Failed to add field to table: %m");
     325             : 
     326           0 :                                 continue; /* line fully filled, no need to fill the remainder below */
     327             :                         }
     328             :                 }
     329             : 
     330           0 :                 r = table_fill_empty(table, 0);
     331           0 :                 if (r < 0)
     332           0 :                         return log_error_errno(r, "Failed to fill line: %m");
     333             :         }
     334             : 
     335           0 :         if (IN_SET(arg_json, JSON_OFF, JSON_PRETTY))
     336           0 :                 (void) pager_open(arg_pager_flags);
     337             : 
     338           0 :         if (arg_json)
     339           0 :                 r = table_print_json(table, stdout, (arg_json == JSON_PRETTY ? JSON_FORMAT_PRETTY : JSON_FORMAT_NEWLINE) | JSON_FORMAT_COLOR_AUTO);
     340             :         else
     341           0 :                 r = table_print(table, stdout);
     342           0 :         if (r < 0)
     343           0 :                 return log_error_errno(r, "Failed to show table: %m");
     344             : 
     345             : 
     346             : 
     347           0 :         return 0;
     348             : }
     349             : 
     350           0 : static void print_subtree(const char *prefix, const char *path, char **l) {
     351             :         const char *vertical, *space;
     352             :         char **n;
     353             : 
     354             :         /* We assume the list is sorted. Let's first skip over the
     355             :          * entry we are looking at. */
     356             :         for (;;) {
     357           0 :                 if (!*l)
     358           0 :                         return;
     359             : 
     360           0 :                 if (!streq(*l, path))
     361           0 :                         break;
     362             : 
     363           0 :                 l++;
     364             :         }
     365             : 
     366           0 :         vertical = strjoina(prefix, special_glyph(SPECIAL_GLYPH_TREE_VERTICAL));
     367           0 :         space = strjoina(prefix, special_glyph(SPECIAL_GLYPH_TREE_SPACE));
     368             : 
     369           0 :         for (;;) {
     370           0 :                 bool has_more = false;
     371             : 
     372           0 :                 if (!*l || !path_startswith(*l, path))
     373             :                         break;
     374             : 
     375           0 :                 n = l + 1;
     376             :                 for (;;) {
     377           0 :                         if (!*n || !path_startswith(*n, path))
     378             :                                 break;
     379             : 
     380           0 :                         if (!path_startswith(*n, *l)) {
     381           0 :                                 has_more = true;
     382           0 :                                 break;
     383             :                         }
     384             : 
     385           0 :                         n++;
     386             :                 }
     387             : 
     388           0 :                 printf("%s%s%s\n", prefix, special_glyph(has_more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT), *l);
     389             : 
     390           0 :                 print_subtree(has_more ? vertical : space, *l, l);
     391           0 :                 l = n;
     392             :         }
     393             : }
     394             : 
     395           0 : static void print_tree(const char *prefix, char **l) {
     396             : 
     397           0 :         prefix = strempty(prefix);
     398             : 
     399           0 :         if (arg_list) {
     400             :                 char **i;
     401             : 
     402           0 :                 STRV_FOREACH(i, l)
     403           0 :                         printf("%s%s\n", prefix, *i);
     404           0 :                 return;
     405             :         }
     406             : 
     407           0 :         if (strv_isempty(l)) {
     408           0 :                 printf("No objects discovered.\n");
     409           0 :                 return;
     410             :         }
     411             : 
     412           0 :         if (streq(l[0], "/") && !l[1]) {
     413           0 :                 printf("Only root object discovered.\n");
     414           0 :                 return;
     415             :         }
     416             : 
     417           0 :         print_subtree(prefix, "/", l);
     418             : }
     419             : 
     420           0 : static int on_path(const char *path, void *userdata) {
     421           0 :         Set *paths = userdata;
     422             :         int r;
     423             : 
     424           0 :         assert(paths);
     425             : 
     426           0 :         r = set_put_strdup(paths, path);
     427           0 :         if (r < 0)
     428           0 :                 return log_oom();
     429             : 
     430           0 :         return 0;
     431             : }
     432             : 
     433           0 : static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
     434             :         static const XMLIntrospectOps ops = {
     435             :                 .on_path = on_path,
     436             :         };
     437             : 
     438           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     439           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     440             :         const char *xml;
     441             :         int r;
     442             : 
     443           0 :         r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
     444           0 :         if (r < 0) {
     445           0 :                 if (many)
     446           0 :                         printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
     447             :                 else
     448           0 :                         log_error_errno(r, "Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
     449           0 :                 return r;
     450             :         }
     451             : 
     452           0 :         r = sd_bus_message_read(reply, "s", &xml);
     453           0 :         if (r < 0)
     454           0 :                 return bus_log_parse_error(r);
     455             : 
     456           0 :         return parse_xml_introspect(path, xml, &ops, paths);
     457             : }
     458             : 
     459           0 : static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
     460           0 :         _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
     461           0 :         _cleanup_free_ char **l = NULL;
     462             :         char *m;
     463             :         int r;
     464             : 
     465           0 :         paths = set_new(&string_hash_ops);
     466           0 :         if (!paths)
     467           0 :                 return log_oom();
     468             : 
     469           0 :         done = set_new(&string_hash_ops);
     470           0 :         if (!done)
     471           0 :                 return log_oom();
     472             : 
     473           0 :         failed = set_new(&string_hash_ops);
     474           0 :         if (!failed)
     475           0 :                 return log_oom();
     476             : 
     477           0 :         m = strdup("/");
     478           0 :         if (!m)
     479           0 :                 return log_oom();
     480             : 
     481           0 :         r = set_put(paths, m);
     482           0 :         if (r < 0) {
     483           0 :                 free(m);
     484           0 :                 return log_oom();
     485             :         }
     486             : 
     487           0 :         for (;;) {
     488           0 :                 _cleanup_free_ char *p = NULL;
     489             :                 int q;
     490             : 
     491           0 :                 p = set_steal_first(paths);
     492           0 :                 if (!p)
     493           0 :                         break;
     494             : 
     495           0 :                 if (set_contains(done, p) ||
     496           0 :                     set_contains(failed, p))
     497           0 :                         continue;
     498             : 
     499           0 :                 q = find_nodes(bus, service, p, paths, many);
     500           0 :                 if (q < 0) {
     501           0 :                         if (r >= 0)
     502           0 :                                 r = q;
     503             : 
     504           0 :                         q = set_put(failed, p);
     505             :                 } else
     506           0 :                         q = set_put(done, p);
     507             : 
     508           0 :                 if (q < 0)
     509           0 :                         return log_oom();
     510             : 
     511           0 :                 assert(q != 0);
     512           0 :                 p = NULL;
     513             :         }
     514             : 
     515           0 :         (void) pager_open(arg_pager_flags);
     516             : 
     517           0 :         l = set_get_strv(done);
     518           0 :         if (!l)
     519           0 :                 return log_oom();
     520             : 
     521           0 :         strv_sort(l);
     522           0 :         print_tree(prefix, l);
     523             : 
     524           0 :         fflush(stdout);
     525             : 
     526           0 :         return r;
     527             : }
     528             : 
     529           0 : static int tree(int argc, char **argv, void *userdata) {
     530           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     531             :         char **i;
     532           0 :         int r = 0;
     533             : 
     534           0 :         if (!arg_unique && !arg_acquired)
     535           0 :                 arg_acquired = true;
     536             : 
     537           0 :         r = acquire_bus(false, &bus);
     538           0 :         if (r < 0)
     539           0 :                 return r;
     540             : 
     541           0 :         if (argc <= 1) {
     542           0 :                 _cleanup_strv_free_ char **names = NULL;
     543           0 :                 bool not_first = false;
     544             : 
     545           0 :                 r = sd_bus_list_names(bus, &names, NULL);
     546           0 :                 if (r < 0)
     547           0 :                         return log_error_errno(r, "Failed to get name list: %m");
     548             : 
     549           0 :                 (void) pager_open(arg_pager_flags);
     550             : 
     551           0 :                 STRV_FOREACH(i, names) {
     552             :                         int q;
     553             : 
     554           0 :                         if (!arg_unique && (*i)[0] == ':')
     555           0 :                                 continue;
     556             : 
     557           0 :                         if (!arg_acquired && (*i)[0] == ':')
     558           0 :                                 continue;
     559             : 
     560           0 :                         if (not_first)
     561           0 :                                 printf("\n");
     562             : 
     563           0 :                         printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
     564             : 
     565           0 :                         q = tree_one(bus, *i, NULL, true);
     566           0 :                         if (q < 0 && r >= 0)
     567           0 :                                 r = q;
     568             : 
     569           0 :                         not_first = true;
     570             :                 }
     571             :         } else {
     572           0 :                 STRV_FOREACH(i, argv+1) {
     573             :                         int q;
     574             : 
     575           0 :                         if (i > argv+1)
     576           0 :                                 printf("\n");
     577             : 
     578           0 :                         if (argv[2]) {
     579           0 :                                 (void) pager_open(arg_pager_flags);
     580           0 :                                 printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
     581             :                         }
     582             : 
     583           0 :                         q = tree_one(bus, *i, NULL, !!argv[2]);
     584           0 :                         if (q < 0 && r >= 0)
     585           0 :                                 r = q;
     586             :                 }
     587             :         }
     588             : 
     589           0 :         return r;
     590             : }
     591             : 
     592           0 : static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
     593             :         int r;
     594             : 
     595           0 :         for (;;) {
     596           0 :                 const char *contents = NULL;
     597             :                 char type;
     598             :                 union {
     599             :                         uint8_t u8;
     600             :                         uint16_t u16;
     601             :                         int16_t s16;
     602             :                         uint32_t u32;
     603             :                         int32_t s32;
     604             :                         uint64_t u64;
     605             :                         int64_t s64;
     606             :                         double d64;
     607             :                         const char *string;
     608             :                         int i;
     609             :                 } basic;
     610             : 
     611           0 :                 r = sd_bus_message_peek_type(m, &type, &contents);
     612           0 :                 if (r < 0)
     613           0 :                         return r;
     614           0 :                 if (r == 0)
     615           0 :                         return needs_space;
     616             : 
     617           0 :                 if (bus_type_is_container(type) > 0) {
     618             : 
     619           0 :                         r = sd_bus_message_enter_container(m, type, contents);
     620           0 :                         if (r < 0)
     621           0 :                                 return r;
     622             : 
     623           0 :                         if (type == SD_BUS_TYPE_ARRAY) {
     624           0 :                                 unsigned n = 0;
     625             : 
     626             :                                 /* count array entries */
     627             :                                 for (;;) {
     628             : 
     629           0 :                                         r = sd_bus_message_skip(m, contents);
     630           0 :                                         if (r < 0)
     631           0 :                                                 return r;
     632           0 :                                         if (r == 0)
     633           0 :                                                 break;
     634             : 
     635           0 :                                         n++;
     636             :                                 }
     637             : 
     638           0 :                                 r = sd_bus_message_rewind(m, false);
     639           0 :                                 if (r < 0)
     640           0 :                                         return r;
     641             : 
     642           0 :                                 if (needs_space)
     643           0 :                                         fputc(' ', f);
     644             : 
     645           0 :                                 fprintf(f, "%u", n);
     646           0 :                                 needs_space = true;
     647             : 
     648           0 :                         } else if (type == SD_BUS_TYPE_VARIANT) {
     649             : 
     650           0 :                                 if (needs_space)
     651           0 :                                         fputc(' ', f);
     652             : 
     653           0 :                                 fprintf(f, "%s", contents);
     654           0 :                                 needs_space = true;
     655             :                         }
     656             : 
     657           0 :                         r = format_cmdline(m, f, needs_space);
     658           0 :                         if (r < 0)
     659           0 :                                 return r;
     660             : 
     661           0 :                         needs_space = r > 0;
     662             : 
     663           0 :                         r = sd_bus_message_exit_container(m);
     664           0 :                         if (r < 0)
     665           0 :                                 return r;
     666             : 
     667           0 :                         continue;
     668             :                 }
     669             : 
     670           0 :                 r = sd_bus_message_read_basic(m, type, &basic);
     671           0 :                 if (r < 0)
     672           0 :                         return r;
     673             : 
     674           0 :                 if (needs_space)
     675           0 :                         fputc(' ', f);
     676             : 
     677           0 :                 switch (type) {
     678           0 :                 case SD_BUS_TYPE_BYTE:
     679           0 :                         fprintf(f, "%u", basic.u8);
     680           0 :                         break;
     681             : 
     682           0 :                 case SD_BUS_TYPE_BOOLEAN:
     683           0 :                         fputs(true_false(basic.i), f);
     684           0 :                         break;
     685             : 
     686           0 :                 case SD_BUS_TYPE_INT16:
     687           0 :                         fprintf(f, "%i", basic.s16);
     688           0 :                         break;
     689             : 
     690           0 :                 case SD_BUS_TYPE_UINT16:
     691           0 :                         fprintf(f, "%u", basic.u16);
     692           0 :                         break;
     693             : 
     694           0 :                 case SD_BUS_TYPE_INT32:
     695           0 :                         fprintf(f, "%i", basic.s32);
     696           0 :                         break;
     697             : 
     698           0 :                 case SD_BUS_TYPE_UINT32:
     699           0 :                         fprintf(f, "%u", basic.u32);
     700           0 :                         break;
     701             : 
     702           0 :                 case SD_BUS_TYPE_INT64:
     703           0 :                         fprintf(f, "%" PRIi64, basic.s64);
     704           0 :                         break;
     705             : 
     706           0 :                 case SD_BUS_TYPE_UINT64:
     707           0 :                         fprintf(f, "%" PRIu64, basic.u64);
     708           0 :                         break;
     709             : 
     710           0 :                 case SD_BUS_TYPE_DOUBLE:
     711           0 :                         fprintf(f, "%g", basic.d64);
     712           0 :                         break;
     713             : 
     714           0 :                 case SD_BUS_TYPE_STRING:
     715             :                 case SD_BUS_TYPE_OBJECT_PATH:
     716             :                 case SD_BUS_TYPE_SIGNATURE: {
     717           0 :                         _cleanup_free_ char *b = NULL;
     718             : 
     719           0 :                         b = cescape(basic.string);
     720           0 :                         if (!b)
     721           0 :                                 return -ENOMEM;
     722             : 
     723           0 :                         fprintf(f, "\"%s\"", b);
     724           0 :                         break;
     725             :                 }
     726             : 
     727           0 :                 case SD_BUS_TYPE_UNIX_FD:
     728           0 :                         fprintf(f, "%i", basic.i);
     729           0 :                         break;
     730             : 
     731           0 :                 default:
     732           0 :                         assert_not_reached("Unknown basic type.");
     733             :                 }
     734             : 
     735           0 :                 needs_space = true;
     736             :         }
     737             : }
     738             : 
     739             : typedef struct Member {
     740             :         const char *type;
     741             :         char *interface;
     742             :         char *name;
     743             :         char *signature;
     744             :         char *result;
     745             :         char *value;
     746             :         bool writable;
     747             :         uint64_t flags;
     748             : } Member;
     749             : 
     750           0 : static void member_hash_func(const Member *m, struct siphash *state) {
     751           0 :         uint64_t arity = 1;
     752             : 
     753           0 :         assert(m);
     754           0 :         assert(m->type);
     755             : 
     756           0 :         string_hash_func(m->type, state);
     757             : 
     758           0 :         arity += !!m->name + !!m->interface;
     759             : 
     760           0 :         uint64_hash_func(&arity, state);
     761             : 
     762           0 :         if (m->name)
     763           0 :                 string_hash_func(m->name, state);
     764             : 
     765           0 :         if (m->interface)
     766           0 :                 string_hash_func(m->interface, state);
     767           0 : }
     768             : 
     769           0 : static int member_compare_func(const Member *x, const Member *y) {
     770             :         int d;
     771             : 
     772           0 :         assert(x);
     773           0 :         assert(y);
     774           0 :         assert(x->type);
     775           0 :         assert(y->type);
     776             : 
     777           0 :         d = strcmp_ptr(x->interface, y->interface);
     778           0 :         if (d != 0)
     779           0 :                 return d;
     780             : 
     781           0 :         d = strcmp(x->type, y->type);
     782           0 :         if (d != 0)
     783           0 :                 return d;
     784             : 
     785           0 :         return strcmp_ptr(x->name, y->name);
     786             : }
     787             : 
     788           0 : static int member_compare_funcp(Member * const *a, Member * const *b) {
     789           0 :         return member_compare_func(*a, *b);
     790             : }
     791             : 
     792           0 : static void member_free(Member *m) {
     793           0 :         if (!m)
     794           0 :                 return;
     795             : 
     796           0 :         free(m->interface);
     797           0 :         free(m->name);
     798           0 :         free(m->signature);
     799           0 :         free(m->result);
     800           0 :         free(m->value);
     801           0 :         free(m);
     802             : }
     803             : 
     804           0 : DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
     805             : 
     806           0 : static void member_set_free(Set *s) {
     807           0 :         set_free_with_destructor(s, member_free);
     808           0 : }
     809             : 
     810           0 : DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
     811             : 
     812           0 : static int on_interface(const char *interface, uint64_t flags, void *userdata) {
     813           0 :         _cleanup_(member_freep) Member *m;
     814           0 :         Set *members = userdata;
     815             :         int r;
     816             : 
     817           0 :         assert(interface);
     818           0 :         assert(members);
     819             : 
     820           0 :         m = new0(Member, 1);
     821           0 :         if (!m)
     822           0 :                 return log_oom();
     823             : 
     824           0 :         m->type = "interface";
     825           0 :         m->flags = flags;
     826             : 
     827           0 :         r = free_and_strdup(&m->interface, interface);
     828           0 :         if (r < 0)
     829           0 :                 return log_oom();
     830             : 
     831           0 :         r = set_put(members, m);
     832           0 :         if (r <= 0)
     833           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate interface");
     834             : 
     835           0 :         m = NULL;
     836           0 :         return 0;
     837             : }
     838             : 
     839           0 : static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
     840           0 :         _cleanup_(member_freep) Member *m;
     841           0 :         Set *members = userdata;
     842             :         int r;
     843             : 
     844           0 :         assert(interface);
     845           0 :         assert(name);
     846             : 
     847           0 :         m = new0(Member, 1);
     848           0 :         if (!m)
     849           0 :                 return log_oom();
     850             : 
     851           0 :         m->type = "method";
     852           0 :         m->flags = flags;
     853             : 
     854           0 :         r = free_and_strdup(&m->interface, interface);
     855           0 :         if (r < 0)
     856           0 :                 return log_oom();
     857             : 
     858           0 :         r = free_and_strdup(&m->name, name);
     859           0 :         if (r < 0)
     860           0 :                 return log_oom();
     861             : 
     862           0 :         r = free_and_strdup(&m->signature, signature);
     863           0 :         if (r < 0)
     864           0 :                 return log_oom();
     865             : 
     866           0 :         r = free_and_strdup(&m->result, result);
     867           0 :         if (r < 0)
     868           0 :                 return log_oom();
     869             : 
     870           0 :         r = set_put(members, m);
     871           0 :         if (r <= 0)
     872           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate method");
     873             : 
     874           0 :         m = NULL;
     875           0 :         return 0;
     876             : }
     877             : 
     878           0 : static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
     879           0 :         _cleanup_(member_freep) Member *m;
     880           0 :         Set *members = userdata;
     881             :         int r;
     882             : 
     883           0 :         assert(interface);
     884           0 :         assert(name);
     885             : 
     886           0 :         m = new0(Member, 1);
     887           0 :         if (!m)
     888           0 :                 return log_oom();
     889             : 
     890           0 :         m->type = "signal";
     891           0 :         m->flags = flags;
     892             : 
     893           0 :         r = free_and_strdup(&m->interface, interface);
     894           0 :         if (r < 0)
     895           0 :                 return log_oom();
     896             : 
     897           0 :         r = free_and_strdup(&m->name, name);
     898           0 :         if (r < 0)
     899           0 :                 return log_oom();
     900             : 
     901           0 :         r = free_and_strdup(&m->signature, signature);
     902           0 :         if (r < 0)
     903           0 :                 return log_oom();
     904             : 
     905           0 :         r = set_put(members, m);
     906           0 :         if (r <= 0)
     907           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate signal");
     908             : 
     909           0 :         m = NULL;
     910           0 :         return 0;
     911             : }
     912             : 
     913           0 : static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
     914           0 :         _cleanup_(member_freep) Member *m;
     915           0 :         Set *members = userdata;
     916             :         int r;
     917             : 
     918           0 :         assert(interface);
     919           0 :         assert(name);
     920             : 
     921           0 :         m = new0(Member, 1);
     922           0 :         if (!m)
     923           0 :                 return log_oom();
     924             : 
     925           0 :         m->type = "property";
     926           0 :         m->flags = flags;
     927           0 :         m->writable = writable;
     928             : 
     929           0 :         r = free_and_strdup(&m->interface, interface);
     930           0 :         if (r < 0)
     931           0 :                 return log_oom();
     932             : 
     933           0 :         r = free_and_strdup(&m->name, name);
     934           0 :         if (r < 0)
     935           0 :                 return log_oom();
     936             : 
     937           0 :         r = free_and_strdup(&m->signature, signature);
     938           0 :         if (r < 0)
     939           0 :                 return log_oom();
     940             : 
     941           0 :         r = set_put(members, m);
     942           0 :         if (r <= 0)
     943           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate property");
     944             : 
     945           0 :         m = NULL;
     946           0 :         return 0;
     947             : }
     948             : 
     949             : DEFINE_PRIVATE_HASH_OPS(member_hash_ops, Member, member_hash_func, member_compare_func);
     950             : 
     951           0 : static int introspect(int argc, char **argv, void *userdata) {
     952             :         static const XMLIntrospectOps ops = {
     953             :                 .on_interface = on_interface,
     954             :                 .on_method = on_method,
     955             :                 .on_signal = on_signal,
     956             :                 .on_property = on_property,
     957             :         };
     958             : 
     959           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     960           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_xml = NULL;
     961           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     962           0 :         _cleanup_(member_set_freep) Set *members = NULL;
     963           0 :         unsigned name_width, type_width, signature_width, result_width, j, k = 0;
     964           0 :         Member *m, **sorted = NULL;
     965             :         Iterator i;
     966             :         const char *xml;
     967             :         int r;
     968             : 
     969           0 :         r = acquire_bus(false, &bus);
     970           0 :         if (r < 0)
     971           0 :                 return r;
     972             : 
     973           0 :         members = set_new(&member_hash_ops);
     974           0 :         if (!members)
     975           0 :                 return log_oom();
     976             : 
     977           0 :         r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply_xml, "");
     978           0 :         if (r < 0)
     979           0 :                 return log_error_errno(r, "Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
     980             : 
     981           0 :         r = sd_bus_message_read(reply_xml, "s", &xml);
     982           0 :         if (r < 0)
     983           0 :                 return bus_log_parse_error(r);
     984             : 
     985           0 :         if (arg_xml_interface) {
     986             :                 /* Just dump the received XML and finish */
     987           0 :                 puts(xml);
     988           0 :                 return 0;
     989             :         }
     990             : 
     991             :         /* First, get list of all properties */
     992           0 :         r = parse_xml_introspect(argv[2], xml, &ops, members);
     993           0 :         if (r < 0)
     994           0 :                 return r;
     995             : 
     996             :         /* Second, find the current values for them */
     997           0 :         SET_FOREACH(m, members, i) {
     998           0 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     999             : 
    1000           0 :                 if (!streq(m->type, "property"))
    1001           0 :                         continue;
    1002             : 
    1003           0 :                 if (m->value)
    1004           0 :                         continue;
    1005             : 
    1006           0 :                 if (argv[3] && !streq(argv[3], m->interface))
    1007           0 :                         continue;
    1008             : 
    1009           0 :                 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
    1010           0 :                 if (r < 0)
    1011           0 :                         return log_error_errno(r, "Failed to get all properties on interface %s: %s",
    1012             :                                                m->interface, bus_error_message(&error, r));
    1013             : 
    1014           0 :                 r = sd_bus_message_enter_container(reply, 'a', "{sv}");
    1015           0 :                 if (r < 0)
    1016           0 :                         return bus_log_parse_error(r);
    1017             : 
    1018           0 :                 for (;;) {
    1019             :                         Member *z;
    1020           0 :                         _cleanup_free_ char *buf = NULL;
    1021           0 :                         _cleanup_fclose_ FILE *mf = NULL;
    1022           0 :                         size_t sz = 0;
    1023             :                         const char *name;
    1024             : 
    1025           0 :                         r = sd_bus_message_enter_container(reply, 'e', "sv");
    1026           0 :                         if (r < 0)
    1027           0 :                                 return bus_log_parse_error(r);
    1028             : 
    1029           0 :                         if (r == 0)
    1030           0 :                                 break;
    1031             : 
    1032           0 :                         r = sd_bus_message_read(reply, "s", &name);
    1033           0 :                         if (r < 0)
    1034           0 :                                 return bus_log_parse_error(r);
    1035             : 
    1036           0 :                         r = sd_bus_message_enter_container(reply, 'v', NULL);
    1037           0 :                         if (r < 0)
    1038           0 :                                 return bus_log_parse_error(r);
    1039             : 
    1040           0 :                         mf = open_memstream_unlocked(&buf, &sz);
    1041           0 :                         if (!mf)
    1042           0 :                                 return log_oom();
    1043             : 
    1044           0 :                         r = format_cmdline(reply, mf, false);
    1045           0 :                         if (r < 0)
    1046           0 :                                 return bus_log_parse_error(r);
    1047             : 
    1048           0 :                         mf = safe_fclose(mf);
    1049             : 
    1050           0 :                         z = set_get(members, &((Member) {
    1051             :                                                 .type = "property",
    1052           0 :                                                 .interface = m->interface,
    1053             :                                                 .name = (char*) name }));
    1054           0 :                         if (z)
    1055           0 :                                 free_and_replace(z->value, buf);
    1056             : 
    1057           0 :                         r = sd_bus_message_exit_container(reply);
    1058           0 :                         if (r < 0)
    1059           0 :                                 return bus_log_parse_error(r);
    1060             : 
    1061           0 :                         r = sd_bus_message_exit_container(reply);
    1062           0 :                         if (r < 0)
    1063           0 :                                 return bus_log_parse_error(r);
    1064             :                 }
    1065             : 
    1066           0 :                 r = sd_bus_message_exit_container(reply);
    1067           0 :                 if (r < 0)
    1068           0 :                         return bus_log_parse_error(r);
    1069             :         }
    1070             : 
    1071           0 :         (void) pager_open(arg_pager_flags);
    1072             : 
    1073           0 :         name_width = STRLEN("NAME");
    1074           0 :         type_width = STRLEN("TYPE");
    1075           0 :         signature_width = STRLEN("SIGNATURE");
    1076           0 :         result_width = STRLEN("RESULT/VALUE");
    1077             : 
    1078           0 :         sorted = newa(Member*, set_size(members));
    1079             : 
    1080           0 :         SET_FOREACH(m, members, i) {
    1081             : 
    1082           0 :                 if (argv[3] && !streq(argv[3], m->interface))
    1083           0 :                         continue;
    1084             : 
    1085           0 :                 if (m->interface)
    1086           0 :                         name_width = MAX(name_width, strlen(m->interface));
    1087           0 :                 if (m->name)
    1088           0 :                         name_width = MAX(name_width, strlen(m->name) + 1);
    1089           0 :                 if (m->type)
    1090           0 :                         type_width = MAX(type_width, strlen(m->type));
    1091           0 :                 if (m->signature)
    1092           0 :                         signature_width = MAX(signature_width, strlen(m->signature));
    1093           0 :                 if (m->result)
    1094           0 :                         result_width = MAX(result_width, strlen(m->result));
    1095           0 :                 if (m->value)
    1096           0 :                         result_width = MAX(result_width, strlen(m->value));
    1097             : 
    1098           0 :                 sorted[k++] = m;
    1099             :         }
    1100             : 
    1101           0 :         if (result_width > 40)
    1102           0 :                 result_width = 40;
    1103             : 
    1104           0 :         typesafe_qsort(sorted, k, member_compare_funcp);
    1105             : 
    1106           0 :         if (arg_legend) {
    1107           0 :                 printf("%-*s %-*s %-*s %-*s %s\n",
    1108             :                        (int) name_width, "NAME",
    1109             :                        (int) type_width, "TYPE",
    1110             :                        (int) signature_width, "SIGNATURE",
    1111             :                        (int) result_width, "RESULT/VALUE",
    1112             :                        "FLAGS");
    1113             :         }
    1114             : 
    1115           0 :         for (j = 0; j < k; j++) {
    1116           0 :                 _cleanup_free_ char *ellipsized = NULL;
    1117             :                 const char *rv;
    1118             :                 bool is_interface;
    1119             : 
    1120           0 :                 m = sorted[j];
    1121             : 
    1122           0 :                 if (argv[3] && !streq(argv[3], m->interface))
    1123           0 :                         continue;
    1124             : 
    1125           0 :                 is_interface = streq(m->type, "interface");
    1126             : 
    1127           0 :                 if (argv[3] && is_interface)
    1128           0 :                         continue;
    1129             : 
    1130           0 :                 if (m->value) {
    1131           0 :                         ellipsized = ellipsize(m->value, result_width, 100);
    1132           0 :                         if (!ellipsized)
    1133           0 :                                 return log_oom();
    1134             : 
    1135           0 :                         rv = ellipsized;
    1136             :                 } else
    1137           0 :                         rv = empty_to_dash(m->result);
    1138             : 
    1139           0 :                 printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
    1140           0 :                        is_interface ? ansi_highlight() : "",
    1141             :                        is_interface ? "" : ".",
    1142           0 :                        - !is_interface + (int) name_width, empty_to_dash(streq_ptr(m->type, "interface") ? m->interface : m->name),
    1143           0 :                        is_interface ? ansi_normal() : "",
    1144           0 :                        (int) type_width, empty_to_dash(m->type),
    1145           0 :                        (int) signature_width, empty_to_dash(m->signature),
    1146             :                        (int) result_width, rv,
    1147           0 :                        (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
    1148           0 :                        (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
    1149           0 :                        (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
    1150           0 :                        (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
    1151           0 :                        (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
    1152           0 :                        m->writable ? " writable" : "");
    1153             :         }
    1154             : 
    1155           0 :         return 0;
    1156             : }
    1157             : 
    1158           0 : static int message_dump(sd_bus_message *m, FILE *f) {
    1159           0 :         return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
    1160             : }
    1161             : 
    1162           0 : static int message_pcap(sd_bus_message *m, FILE *f) {
    1163           0 :         return bus_message_pcap_frame(m, arg_snaplen, f);
    1164             : }
    1165             : 
    1166           0 : static int message_json(sd_bus_message *m, FILE *f) {
    1167           0 :         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
    1168             :         char e[2];
    1169             :         int r;
    1170             : 
    1171           0 :         r = json_transform_message(m, &v);
    1172           0 :         if (r < 0)
    1173           0 :                 return r;
    1174             : 
    1175           0 :         e[0] = m->header->endian;
    1176           0 :         e[1] = 0;
    1177             : 
    1178           0 :         r = json_build(&w, JSON_BUILD_OBJECT(
    1179             :                                        JSON_BUILD_PAIR("type", JSON_BUILD_STRING(bus_message_type_to_string(m->header->type))),
    1180             :                                        JSON_BUILD_PAIR("endian", JSON_BUILD_STRING(e)),
    1181             :                                        JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(m->header->flags)),
    1182             :                                        JSON_BUILD_PAIR("version", JSON_BUILD_INTEGER(m->header->version)),
    1183             :                                        JSON_BUILD_PAIR_CONDITION(m->priority != 0, "priority", JSON_BUILD_INTEGER(m->priority)),
    1184             :                                        JSON_BUILD_PAIR("cookie", JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m))),
    1185             :                                        JSON_BUILD_PAIR_CONDITION(m->reply_cookie != 0, "reply_cookie", JSON_BUILD_INTEGER(m->reply_cookie)),
    1186             :                                        JSON_BUILD_PAIR_CONDITION(m->sender, "sender", JSON_BUILD_STRING(m->sender)),
    1187             :                                        JSON_BUILD_PAIR_CONDITION(m->destination, "destination", JSON_BUILD_STRING(m->destination)),
    1188             :                                        JSON_BUILD_PAIR_CONDITION(m->path, "path", JSON_BUILD_STRING(m->path)),
    1189             :                                        JSON_BUILD_PAIR_CONDITION(m->interface, "interface", JSON_BUILD_STRING(m->interface)),
    1190             :                                        JSON_BUILD_PAIR_CONDITION(m->member, "member", JSON_BUILD_STRING(m->member)),
    1191             :                                        JSON_BUILD_PAIR_CONDITION(m->monotonic != 0, "monotonic", JSON_BUILD_INTEGER(m->monotonic)),
    1192             :                                        JSON_BUILD_PAIR_CONDITION(m->realtime != 0, "realtime", JSON_BUILD_INTEGER(m->realtime)),
    1193             :                                        JSON_BUILD_PAIR_CONDITION(m->seqnum != 0, "seqnum", JSON_BUILD_INTEGER(m->seqnum)),
    1194             :                                        JSON_BUILD_PAIR_CONDITION(m->error.name, "error_name", JSON_BUILD_STRING(m->error.name)),
    1195             :                                        JSON_BUILD_PAIR("payload", JSON_BUILD_VARIANT(v))));
    1196           0 :         if (r < 0)
    1197           0 :                 return log_error_errno(r, "Failed to build JSON object: %m");
    1198             : 
    1199           0 :         json_dump_with_flags(w, f);
    1200           0 :         return 0;
    1201             : }
    1202             : 
    1203           0 : static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f)) {
    1204           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1205           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
    1206           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1207             :         char **i;
    1208           0 :         uint32_t flags = 0;
    1209             :         const char *unique_name;
    1210           0 :         bool is_monitor = false;
    1211             :         int r;
    1212             : 
    1213           0 :         r = acquire_bus(true, &bus);
    1214           0 :         if (r < 0)
    1215           0 :                 return r;
    1216             : 
    1217             :         /* upgrade connection; it's not used for anything else after this call */
    1218           0 :         r = sd_bus_message_new_method_call(bus,
    1219             :                                            &message,
    1220             :                                            "org.freedesktop.DBus",
    1221             :                                            "/org/freedesktop/DBus",
    1222             :                                            "org.freedesktop.DBus.Monitoring",
    1223             :                                            "BecomeMonitor");
    1224           0 :         if (r < 0)
    1225           0 :                 return bus_log_create_error(r);
    1226             : 
    1227           0 :         r = sd_bus_message_open_container(message, 'a', "s");
    1228           0 :         if (r < 0)
    1229           0 :                 return bus_log_create_error(r);
    1230             : 
    1231           0 :         STRV_FOREACH(i, argv+1) {
    1232           0 :                 _cleanup_free_ char *m = NULL;
    1233             : 
    1234           0 :                 if (!service_name_is_valid(*i))
    1235           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name '%s'", *i);
    1236             : 
    1237           0 :                 m = strjoin("sender='", *i, "'");
    1238           0 :                 if (!m)
    1239           0 :                         return log_oom();
    1240             : 
    1241           0 :                 r = sd_bus_message_append_basic(message, 's', m);
    1242           0 :                 if (r < 0)
    1243           0 :                         return bus_log_create_error(r);
    1244             : 
    1245           0 :                 free(m);
    1246           0 :                 m = strjoin("destination='", *i, "'");
    1247           0 :                 if (!m)
    1248           0 :                         return log_oom();
    1249             : 
    1250           0 :                 r = sd_bus_message_append_basic(message, 's', m);
    1251           0 :                 if (r < 0)
    1252           0 :                         return bus_log_create_error(r);
    1253             :         }
    1254             : 
    1255           0 :         STRV_FOREACH(i, arg_matches) {
    1256           0 :                 r = sd_bus_message_append_basic(message, 's', *i);
    1257           0 :                 if (r < 0)
    1258           0 :                         return bus_log_create_error(r);
    1259             :         }
    1260             : 
    1261           0 :         r = sd_bus_message_close_container(message);
    1262           0 :         if (r < 0)
    1263           0 :                 return bus_log_create_error(r);
    1264             : 
    1265           0 :         r = sd_bus_message_append_basic(message, 'u', &flags);
    1266           0 :         if (r < 0)
    1267           0 :                 return bus_log_create_error(r);
    1268             : 
    1269           0 :         r = sd_bus_call(bus, message, arg_timeout, &error, NULL);
    1270           0 :         if (r < 0)
    1271           0 :                 return log_error_errno(r, "Call to org.freedesktop.DBus.Monitoring.BecomeMonitor failed: %s",
    1272             :                                        bus_error_message(&error, r));
    1273             : 
    1274           0 :         r = sd_bus_get_unique_name(bus, &unique_name);
    1275           0 :         if (r < 0)
    1276           0 :                 return log_error_errno(r, "Failed to get unique name: %m");
    1277             : 
    1278           0 :         log_info("Monitoring bus message stream.");
    1279             : 
    1280           0 :         for (;;) {
    1281           0 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
    1282             : 
    1283           0 :                 r = sd_bus_process(bus, &m);
    1284           0 :                 if (r < 0)
    1285           0 :                         return log_error_errno(r, "Failed to process bus: %m");
    1286             : 
    1287           0 :                 if (!is_monitor) {
    1288             :                         const char *name;
    1289             : 
    1290             :                         /* wait until we lose our unique name */
    1291           0 :                         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameLost") <= 0)
    1292           0 :                                 continue;
    1293             : 
    1294           0 :                         r = sd_bus_message_read(m, "s", &name);
    1295           0 :                         if (r < 0)
    1296           0 :                                 return log_error_errno(r, "Failed to read lost name: %m");
    1297             : 
    1298           0 :                         if (streq(name, unique_name))
    1299           0 :                                 is_monitor = true;
    1300             : 
    1301           0 :                         continue;
    1302             :                 }
    1303             : 
    1304           0 :                 if (m) {
    1305           0 :                         dump(m, stdout);
    1306           0 :                         fflush(stdout);
    1307             : 
    1308           0 :                         if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
    1309           0 :                                 log_info("Connection terminated, exiting.");
    1310           0 :                                 return 0;
    1311             :                         }
    1312             : 
    1313           0 :                         continue;
    1314             :                 }
    1315             : 
    1316           0 :                 if (r > 0)
    1317           0 :                         continue;
    1318             : 
    1319           0 :                 r = sd_bus_wait(bus, (uint64_t) -1);
    1320           0 :                 if (r < 0)
    1321           0 :                         return log_error_errno(r, "Failed to wait for bus: %m");
    1322             :         }
    1323             : }
    1324             : 
    1325           0 : static int verb_monitor(int argc, char **argv, void *userdata) {
    1326           0 :         return monitor(argc, argv, arg_json != JSON_OFF ? message_json : message_dump);
    1327             : }
    1328             : 
    1329           0 : static int verb_capture(int argc, char **argv, void *userdata) {
    1330             :         int r;
    1331             : 
    1332           0 :         if (isatty(fileno(stdout)) > 0)
    1333           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1334             :                                        "Refusing to write message data to console, please redirect output to a file.");
    1335             : 
    1336           0 :         bus_pcap_header(arg_snaplen, stdout);
    1337             : 
    1338           0 :         r = monitor(argc, argv, message_pcap);
    1339           0 :         if (r < 0)
    1340           0 :                 return r;
    1341             : 
    1342           0 :         r = fflush_and_check(stdout);
    1343           0 :         if (r < 0)
    1344           0 :                 return log_error_errno(r, "Couldn't write capture file: %m");
    1345             : 
    1346           0 :         return r;
    1347             : }
    1348             : 
    1349           0 : static int status(int argc, char **argv, void *userdata) {
    1350           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1351           0 :         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
    1352             :         pid_t pid;
    1353             :         int r;
    1354             : 
    1355           0 :         r = acquire_bus(false, &bus);
    1356           0 :         if (r < 0)
    1357           0 :                 return r;
    1358             : 
    1359           0 :         if (!isempty(argv[1])) {
    1360           0 :                 r = parse_pid(argv[1], &pid);
    1361           0 :                 if (r < 0)
    1362           0 :                         r = sd_bus_get_name_creds(
    1363             :                                         bus,
    1364           0 :                                         argv[1],
    1365           0 :                                         (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
    1366             :                                         &creds);
    1367             :                 else
    1368           0 :                         r = sd_bus_creds_new_from_pid(
    1369             :                                         &creds,
    1370             :                                         pid,
    1371             :                                         _SD_BUS_CREDS_ALL);
    1372             :         } else {
    1373             :                 const char *scope, *address;
    1374             :                 sd_id128_t bus_id;
    1375             : 
    1376           0 :                 r = sd_bus_get_address(bus, &address);
    1377           0 :                 if (r >= 0)
    1378           0 :                         printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal());
    1379             : 
    1380           0 :                 r = sd_bus_get_scope(bus, &scope);
    1381           0 :                 if (r >= 0)
    1382           0 :                         printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal());
    1383             : 
    1384           0 :                 r = sd_bus_get_bus_id(bus, &bus_id);
    1385           0 :                 if (r >= 0)
    1386           0 :                         printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal());
    1387             : 
    1388           0 :                 r = sd_bus_get_owner_creds(
    1389             :                                 bus,
    1390           0 :                                 (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
    1391             :                                 &creds);
    1392             :         }
    1393             : 
    1394           0 :         if (r < 0)
    1395           0 :                 return log_error_errno(r, "Failed to get credentials: %m");
    1396             : 
    1397           0 :         bus_creds_dump(creds, NULL, false);
    1398           0 :         return 0;
    1399             : }
    1400             : 
    1401           0 : static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
    1402             :         char **p;
    1403             :         int r;
    1404             : 
    1405           0 :         assert(m);
    1406           0 :         assert(signature);
    1407           0 :         assert(x);
    1408             : 
    1409           0 :         p = *x;
    1410             : 
    1411           0 :         for (;;) {
    1412             :                 const char *v;
    1413             :                 char t;
    1414             : 
    1415           0 :                 t = *signature;
    1416           0 :                 v = *p;
    1417             : 
    1418           0 :                 if (t == 0)
    1419           0 :                         break;
    1420           0 :                 if (!v)
    1421           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1422             :                                                "Too few parameters for signature.");
    1423             : 
    1424           0 :                 signature++;
    1425           0 :                 p++;
    1426             : 
    1427           0 :                 switch (t) {
    1428             : 
    1429           0 :                 case SD_BUS_TYPE_BOOLEAN:
    1430             : 
    1431           0 :                         r = parse_boolean(v);
    1432           0 :                         if (r < 0)
    1433           0 :                                 return log_error_errno(r, "Failed to parse '%s' as boolean: %m", v);
    1434             : 
    1435           0 :                         r = sd_bus_message_append_basic(m, t, &r);
    1436           0 :                         break;
    1437             : 
    1438           0 :                 case SD_BUS_TYPE_BYTE: {
    1439             :                         uint8_t z;
    1440             : 
    1441           0 :                         r = safe_atou8(v, &z);
    1442           0 :                         if (r < 0)
    1443           0 :                                 return log_error_errno(r, "Failed to parse '%s' as byte (unsigned 8bit integer): %m", v);
    1444             : 
    1445           0 :                         r = sd_bus_message_append_basic(m, t, &z);
    1446           0 :                         break;
    1447             :                 }
    1448             : 
    1449           0 :                 case SD_BUS_TYPE_INT16: {
    1450             :                         int16_t z;
    1451             : 
    1452           0 :                         r = safe_atoi16(v, &z);
    1453           0 :                         if (r < 0)
    1454           0 :                                 return log_error_errno(r, "Failed to parse '%s' as signed 16bit integer: %m", v);
    1455             : 
    1456           0 :                         r = sd_bus_message_append_basic(m, t, &z);
    1457           0 :                         break;
    1458             :                 }
    1459             : 
    1460           0 :                 case SD_BUS_TYPE_UINT16: {
    1461             :                         uint16_t z;
    1462             : 
    1463           0 :                         r = safe_atou16(v, &z);
    1464           0 :                         if (r < 0)
    1465           0 :                                 return log_error_errno(r, "Failed to parse '%s' as unsigned 16bit integer: %m", v);
    1466             : 
    1467           0 :                         r = sd_bus_message_append_basic(m, t, &z);
    1468           0 :                         break;
    1469             :                 }
    1470             : 
    1471           0 :                 case SD_BUS_TYPE_INT32: {
    1472             :                         int32_t z;
    1473             : 
    1474           0 :                         r = safe_atoi32(v, &z);
    1475           0 :                         if (r < 0)
    1476           0 :                                 return log_error_errno(r, "Failed to parse '%s' as signed 32bit integer: %m", v);
    1477             : 
    1478           0 :                         r = sd_bus_message_append_basic(m, t, &z);
    1479           0 :                         break;
    1480             :                 }
    1481             : 
    1482           0 :                 case SD_BUS_TYPE_UINT32: {
    1483             :                         uint32_t z;
    1484             : 
    1485           0 :                         r = safe_atou32(v, &z);
    1486           0 :                         if (r < 0)
    1487           0 :                                 return log_error_errno(r, "Failed to parse '%s' as unsigned 32bit integer: %m", v);
    1488             : 
    1489           0 :                         r = sd_bus_message_append_basic(m, t, &z);
    1490           0 :                         break;
    1491             :                 }
    1492             : 
    1493           0 :                 case SD_BUS_TYPE_INT64: {
    1494             :                         int64_t z;
    1495             : 
    1496           0 :                         r = safe_atoi64(v, &z);
    1497           0 :                         if (r < 0)
    1498           0 :                                 return log_error_errno(r, "Failed to parse '%s' as signed 64bit integer: %m", v);
    1499             : 
    1500           0 :                         r = sd_bus_message_append_basic(m, t, &z);
    1501           0 :                         break;
    1502             :                 }
    1503             : 
    1504           0 :                 case SD_BUS_TYPE_UINT64: {
    1505             :                         uint64_t z;
    1506             : 
    1507           0 :                         r = safe_atou64(v, &z);
    1508           0 :                         if (r < 0)
    1509           0 :                                 return log_error_errno(r, "Failed to parse '%s' as unsigned 64bit integer: %m", v);
    1510             : 
    1511           0 :                         r = sd_bus_message_append_basic(m, t, &z);
    1512           0 :                         break;
    1513             :                 }
    1514             : 
    1515           0 :                 case SD_BUS_TYPE_DOUBLE: {
    1516             :                         double z;
    1517             : 
    1518           0 :                         r = safe_atod(v, &z);
    1519           0 :                         if (r < 0)
    1520           0 :                                 return log_error_errno(r, "Failed to parse '%s' as double precision floating point: %m", v);
    1521             : 
    1522           0 :                         r = sd_bus_message_append_basic(m, t, &z);
    1523           0 :                         break;
    1524             :                 }
    1525             : 
    1526           0 :                 case SD_BUS_TYPE_STRING:
    1527             :                 case SD_BUS_TYPE_OBJECT_PATH:
    1528             :                 case SD_BUS_TYPE_SIGNATURE:
    1529             : 
    1530           0 :                         r = sd_bus_message_append_basic(m, t, v);
    1531           0 :                         break;
    1532             : 
    1533           0 :                 case SD_BUS_TYPE_ARRAY: {
    1534             :                         uint32_t n;
    1535             :                         size_t k;
    1536             : 
    1537           0 :                         r = safe_atou32(v, &n);
    1538           0 :                         if (r < 0)
    1539           0 :                                 return log_error_errno(r, "Failed to parse '%s' number of array entries: %m", v);
    1540             : 
    1541           0 :                         r = signature_element_length(signature, &k);
    1542           0 :                         if (r < 0)
    1543           0 :                                 return log_error_errno(r, "Invalid array signature: %m");
    1544             : 
    1545           0 :                         {
    1546             :                                 unsigned i;
    1547           0 :                                 char s[k + 1];
    1548           0 :                                 memcpy(s, signature, k);
    1549           0 :                                 s[k] = 0;
    1550             : 
    1551           0 :                                 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
    1552           0 :                                 if (r < 0)
    1553           0 :                                         return bus_log_create_error(r);
    1554             : 
    1555           0 :                                 for (i = 0; i < n; i++) {
    1556           0 :                                         r = message_append_cmdline(m, s, &p);
    1557           0 :                                         if (r < 0)
    1558           0 :                                                 return r;
    1559             :                                 }
    1560             :                         }
    1561             : 
    1562           0 :                         signature += k;
    1563             : 
    1564           0 :                         r = sd_bus_message_close_container(m);
    1565           0 :                         break;
    1566             :                 }
    1567             : 
    1568           0 :                 case SD_BUS_TYPE_VARIANT:
    1569           0 :                         r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
    1570           0 :                         if (r < 0)
    1571           0 :                                 return bus_log_create_error(r);
    1572             : 
    1573           0 :                         r = message_append_cmdline(m, v, &p);
    1574           0 :                         if (r < 0)
    1575           0 :                                 return r;
    1576             : 
    1577           0 :                         r = sd_bus_message_close_container(m);
    1578           0 :                         break;
    1579             : 
    1580           0 :                 case SD_BUS_TYPE_STRUCT_BEGIN:
    1581             :                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
    1582             :                         size_t k;
    1583             : 
    1584           0 :                         signature--;
    1585           0 :                         p--;
    1586             : 
    1587           0 :                         r = signature_element_length(signature, &k);
    1588           0 :                         if (r < 0)
    1589           0 :                                 return log_error_errno(r, "Invalid struct/dict entry signature: %m");
    1590             : 
    1591           0 :                         {
    1592           0 :                                 char s[k-1];
    1593           0 :                                 memcpy(s, signature + 1, k - 2);
    1594           0 :                                 s[k - 2] = 0;
    1595             : 
    1596           0 :                                 r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
    1597           0 :                                 if (r < 0)
    1598           0 :                                         return bus_log_create_error(r);
    1599             : 
    1600           0 :                                 r = message_append_cmdline(m, s, &p);
    1601           0 :                                 if (r < 0)
    1602           0 :                                         return r;
    1603             :                         }
    1604             : 
    1605           0 :                         signature += k;
    1606             : 
    1607           0 :                         r = sd_bus_message_close_container(m);
    1608           0 :                         break;
    1609             :                 }
    1610             : 
    1611           0 :                 case SD_BUS_TYPE_UNIX_FD:
    1612           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1613             :                                                "UNIX file descriptor not supported as type.");
    1614             : 
    1615           0 :                 default:
    1616           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1617             :                                                "Unknown signature type %c.", t);
    1618             :                 }
    1619             : 
    1620           0 :                 if (r < 0)
    1621           0 :                         return bus_log_create_error(r);
    1622             :         }
    1623             : 
    1624           0 :         *x = p;
    1625           0 :         return 0;
    1626             : }
    1627             : 
    1628             : static int json_transform_one(sd_bus_message *m, JsonVariant **ret);
    1629             : 
    1630           0 : static int json_transform_array_or_struct(sd_bus_message *m, JsonVariant **ret) {
    1631           0 :         size_t n_elements = 0, n_allocated = 0;
    1632           0 :         JsonVariant **elements = NULL;
    1633             :         int r;
    1634             : 
    1635           0 :         assert(m);
    1636           0 :         assert(ret);
    1637             : 
    1638             :         for (;;) {
    1639           0 :                 r = sd_bus_message_at_end(m, false);
    1640           0 :                 if (r < 0) {
    1641           0 :                         bus_log_parse_error(r);
    1642           0 :                         goto finish;
    1643             :                 }
    1644           0 :                 if (r > 0)
    1645           0 :                         break;
    1646             : 
    1647           0 :                 if (!GREEDY_REALLOC(elements, n_allocated, n_elements + 1)) {
    1648           0 :                         r = log_oom();
    1649           0 :                         goto finish;
    1650             :                 }
    1651             : 
    1652           0 :                 r = json_transform_one(m, elements + n_elements);
    1653           0 :                 if (r < 0)
    1654           0 :                         goto finish;
    1655             : 
    1656           0 :                 n_elements++;
    1657             :         }
    1658             : 
    1659           0 :         r = json_variant_new_array(ret, elements, n_elements);
    1660             : 
    1661           0 : finish:
    1662           0 :         json_variant_unref_many(elements, n_elements);
    1663           0 :         free(elements);
    1664             : 
    1665           0 :         return r;
    1666             : }
    1667             : 
    1668           0 : static int json_transform_variant(sd_bus_message *m, const char *contents, JsonVariant **ret) {
    1669           0 :         _cleanup_(json_variant_unrefp) JsonVariant *value = NULL;
    1670             :         int r;
    1671             : 
    1672           0 :         assert(m);
    1673           0 :         assert(contents);
    1674           0 :         assert(ret);
    1675             : 
    1676           0 :         r = json_transform_one(m, &value);
    1677           0 :         if (r < 0)
    1678           0 :                 return r;
    1679             : 
    1680           0 :         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type", JSON_BUILD_STRING(contents)),
    1681             :                                               JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(value))));
    1682           0 :         if (r < 0)
    1683           0 :                 return log_oom();
    1684             : 
    1685           0 :         return r;
    1686             : }
    1687             : 
    1688           0 : static int json_transform_dict_array(sd_bus_message *m, JsonVariant **ret) {
    1689           0 :         size_t n_elements = 0, n_allocated = 0;
    1690           0 :         JsonVariant **elements = NULL;
    1691             :         int r;
    1692             : 
    1693           0 :         assert(m);
    1694           0 :         assert(ret);
    1695             : 
    1696           0 :         for (;;) {
    1697             :                 const char *contents;
    1698             :                 char type;
    1699             : 
    1700           0 :                 r = sd_bus_message_at_end(m, false);
    1701           0 :                 if (r < 0) {
    1702           0 :                         bus_log_parse_error(r);
    1703           0 :                         goto finish;
    1704             :                 }
    1705           0 :                 if (r > 0)
    1706           0 :                         break;
    1707             : 
    1708           0 :                 r = sd_bus_message_peek_type(m, &type, &contents);
    1709           0 :                 if (r < 0)
    1710           0 :                         return r;
    1711             : 
    1712           0 :                 assert(type == 'e');
    1713             : 
    1714           0 :                 if (!GREEDY_REALLOC(elements, n_allocated, n_elements + 2)) {
    1715           0 :                         r = log_oom();
    1716           0 :                         goto finish;
    1717             :                 }
    1718             : 
    1719           0 :                 r = sd_bus_message_enter_container(m, type, contents);
    1720           0 :                 if (r < 0) {
    1721           0 :                         bus_log_parse_error(r);
    1722           0 :                         goto finish;
    1723             :                 }
    1724             : 
    1725           0 :                 r = json_transform_one(m, elements + n_elements);
    1726           0 :                 if (r < 0)
    1727           0 :                         goto finish;
    1728             : 
    1729           0 :                 n_elements++;
    1730             : 
    1731           0 :                 r = json_transform_one(m, elements + n_elements);
    1732           0 :                 if (r < 0)
    1733           0 :                         goto finish;
    1734             : 
    1735           0 :                 n_elements++;
    1736             : 
    1737           0 :                 r = sd_bus_message_exit_container(m);
    1738           0 :                 if (r < 0) {
    1739           0 :                         bus_log_parse_error(r);
    1740           0 :                         goto finish;
    1741             :                 }
    1742             :         }
    1743             : 
    1744           0 :         r = json_variant_new_object(ret, elements, n_elements);
    1745             : 
    1746           0 : finish:
    1747           0 :         json_variant_unref_many(elements, n_elements);
    1748           0 :         free(elements);
    1749             : 
    1750           0 :         return r;
    1751             : }
    1752             : 
    1753           0 : static int json_transform_one(sd_bus_message *m, JsonVariant **ret) {
    1754           0 :         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
    1755             :         const char *contents;
    1756             :         char type;
    1757             :         int r;
    1758             : 
    1759           0 :         assert(m);
    1760           0 :         assert(ret);
    1761             : 
    1762           0 :         r = sd_bus_message_peek_type(m, &type, &contents);
    1763           0 :         if (r < 0)
    1764           0 :                 return bus_log_parse_error(r);
    1765             : 
    1766           0 :         switch (type) {
    1767             : 
    1768           0 :         case SD_BUS_TYPE_BYTE: {
    1769             :                 uint8_t b;
    1770             : 
    1771           0 :                 r = sd_bus_message_read_basic(m, type, &b);
    1772           0 :                 if (r < 0)
    1773           0 :                         return bus_log_parse_error(r);
    1774             : 
    1775           0 :                 r = json_variant_new_unsigned(&v, b);
    1776           0 :                 if (r < 0)
    1777           0 :                         return log_error_errno(r, "Failed to transform byte: %m");
    1778             : 
    1779           0 :                 break;
    1780             :         }
    1781             : 
    1782           0 :         case SD_BUS_TYPE_BOOLEAN: {
    1783             :                 int b;
    1784             : 
    1785           0 :                 r = sd_bus_message_read_basic(m, type, &b);
    1786           0 :                 if (r < 0)
    1787           0 :                         return bus_log_parse_error(r);
    1788             : 
    1789           0 :                 r = json_variant_new_boolean(&v, b);
    1790           0 :                 if (r < 0)
    1791           0 :                         return log_error_errno(r, "Failed to transform boolean: %m");
    1792             : 
    1793           0 :                 break;
    1794             :         }
    1795             : 
    1796           0 :         case SD_BUS_TYPE_INT16: {
    1797             :                 int16_t b;
    1798             : 
    1799           0 :                 r = sd_bus_message_read_basic(m, type, &b);
    1800           0 :                 if (r < 0)
    1801           0 :                         return bus_log_parse_error(r);
    1802             : 
    1803           0 :                 r = json_variant_new_integer(&v, b);
    1804           0 :                 if (r < 0)
    1805           0 :                         return log_error_errno(r, "Failed to transform int16: %m");
    1806             : 
    1807           0 :                 break;
    1808             :         }
    1809             : 
    1810           0 :         case SD_BUS_TYPE_UINT16: {
    1811             :                 uint16_t b;
    1812             : 
    1813           0 :                 r = sd_bus_message_read_basic(m, type, &b);
    1814           0 :                 if (r < 0)
    1815           0 :                         return bus_log_parse_error(r);
    1816             : 
    1817           0 :                 r = json_variant_new_unsigned(&v, b);
    1818           0 :                 if (r < 0)
    1819           0 :                         return log_error_errno(r, "Failed to transform uint16: %m");
    1820             : 
    1821           0 :                 break;
    1822             :         }
    1823             : 
    1824           0 :         case SD_BUS_TYPE_INT32: {
    1825             :                 int32_t b;
    1826             : 
    1827           0 :                 r = sd_bus_message_read_basic(m, type, &b);
    1828           0 :                 if (r < 0)
    1829           0 :                         return bus_log_parse_error(r);
    1830             : 
    1831           0 :                 r = json_variant_new_integer(&v, b);
    1832           0 :                 if (r < 0)
    1833           0 :                         return log_error_errno(r, "Failed to transform int32: %m");
    1834             : 
    1835           0 :                 break;
    1836             :         }
    1837             : 
    1838           0 :         case SD_BUS_TYPE_UINT32: {
    1839             :                 uint32_t b;
    1840             : 
    1841           0 :                 r = sd_bus_message_read_basic(m, type, &b);
    1842           0 :                 if (r < 0)
    1843           0 :                         return bus_log_parse_error(r);
    1844             : 
    1845           0 :                 r = json_variant_new_unsigned(&v, b);
    1846           0 :                 if (r < 0)
    1847           0 :                         return log_error_errno(r, "Failed to transform uint32: %m");
    1848             : 
    1849           0 :                 break;
    1850             :         }
    1851             : 
    1852           0 :         case SD_BUS_TYPE_INT64: {
    1853             :                 int64_t b;
    1854             : 
    1855           0 :                 r = sd_bus_message_read_basic(m, type, &b);
    1856           0 :                 if (r < 0)
    1857           0 :                         return bus_log_parse_error(r);
    1858             : 
    1859           0 :                 r = json_variant_new_integer(&v, b);
    1860           0 :                 if (r < 0)
    1861           0 :                         return log_error_errno(r, "Failed to transform int64: %m");
    1862             : 
    1863           0 :                 break;
    1864             :         }
    1865             : 
    1866           0 :         case SD_BUS_TYPE_UINT64: {
    1867             :                 uint64_t b;
    1868             : 
    1869           0 :                 r = sd_bus_message_read_basic(m, type, &b);
    1870           0 :                 if (r < 0)
    1871           0 :                         return bus_log_parse_error(r);
    1872             : 
    1873           0 :                 r = json_variant_new_unsigned(&v, b);
    1874           0 :                 if (r < 0)
    1875           0 :                         return log_error_errno(r, "Failed to transform uint64: %m");
    1876             : 
    1877           0 :                 break;
    1878             :         }
    1879             : 
    1880           0 :         case SD_BUS_TYPE_DOUBLE: {
    1881             :                 double d;
    1882             : 
    1883           0 :                 r = sd_bus_message_read_basic(m, type, &d);
    1884           0 :                 if (r < 0)
    1885           0 :                         return bus_log_parse_error(r);
    1886             : 
    1887           0 :                 r = json_variant_new_real(&v, d);
    1888           0 :                 if (r < 0)
    1889           0 :                         return log_error_errno(r, "Failed to transform double: %m");
    1890             : 
    1891           0 :                 break;
    1892             :         }
    1893             : 
    1894           0 :         case SD_BUS_TYPE_STRING:
    1895             :         case SD_BUS_TYPE_OBJECT_PATH:
    1896             :         case SD_BUS_TYPE_SIGNATURE: {
    1897             :                 const char *s;
    1898             : 
    1899           0 :                 r = sd_bus_message_read_basic(m, type, &s);
    1900           0 :                 if (r < 0)
    1901           0 :                         return bus_log_parse_error(r);
    1902             : 
    1903           0 :                 r = json_variant_new_string(&v, s);
    1904           0 :                 if (r < 0)
    1905           0 :                         return log_error_errno(r, "Failed to transform double: %m");
    1906             : 
    1907           0 :                 break;
    1908             :         }
    1909             : 
    1910           0 :         case SD_BUS_TYPE_UNIX_FD:
    1911           0 :                 r = sd_bus_message_read_basic(m, type, NULL);
    1912           0 :                 if (r < 0)
    1913           0 :                         return bus_log_parse_error(r);
    1914             : 
    1915           0 :                 r = json_variant_new_null(&v);
    1916           0 :                 if (r < 0)
    1917           0 :                         return log_error_errno(r, "Failed to transform fd: %m");
    1918             : 
    1919           0 :                 break;
    1920             : 
    1921           0 :         case SD_BUS_TYPE_ARRAY:
    1922             :         case SD_BUS_TYPE_VARIANT:
    1923             :         case SD_BUS_TYPE_STRUCT:
    1924           0 :                 r = sd_bus_message_enter_container(m, type, contents);
    1925           0 :                 if (r < 0)
    1926           0 :                         return bus_log_parse_error(r);
    1927             : 
    1928           0 :                 if (type == SD_BUS_TYPE_VARIANT)
    1929           0 :                         r = json_transform_variant(m, contents, &v);
    1930           0 :                 else if (type == SD_BUS_TYPE_ARRAY && contents[0] == '{')
    1931           0 :                         r = json_transform_dict_array(m, &v);
    1932             :                 else
    1933           0 :                         r = json_transform_array_or_struct(m, &v);
    1934           0 :                 if (r < 0)
    1935           0 :                         return r;
    1936             : 
    1937           0 :                 r = sd_bus_message_exit_container(m);
    1938           0 :                 if (r < 0)
    1939           0 :                         return bus_log_parse_error(r);
    1940             : 
    1941           0 :                 break;
    1942             : 
    1943           0 :         default:
    1944           0 :                 assert_not_reached("Unexpected element type");
    1945             :         }
    1946             : 
    1947           0 :         *ret = TAKE_PTR(v);
    1948           0 :         return 0;
    1949             : }
    1950             : 
    1951           0 : static int json_transform_message(sd_bus_message *m, JsonVariant **ret) {
    1952           0 :         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
    1953             :         const char *type;
    1954             :         int r;
    1955             : 
    1956           0 :         assert(m);
    1957           0 :         assert(ret);
    1958             : 
    1959           0 :         assert_se(type = sd_bus_message_get_signature(m, false));
    1960             : 
    1961           0 :         r = json_transform_array_or_struct(m, &v);
    1962           0 :         if (r < 0)
    1963           0 :                 return r;
    1964             : 
    1965           0 :         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("type",  JSON_BUILD_STRING(type)),
    1966             :                                               JSON_BUILD_PAIR("data", JSON_BUILD_VARIANT(v))));
    1967           0 :         if (r < 0)
    1968           0 :                 return log_oom();
    1969             : 
    1970           0 :         return 0;
    1971             : }
    1972             : 
    1973           0 : static void json_dump_with_flags(JsonVariant *v, FILE *f) {
    1974             : 
    1975           0 :         json_variant_dump(v,
    1976           0 :                           (arg_json == JSON_PRETTY ? JSON_FORMAT_PRETTY : JSON_FORMAT_NEWLINE) |
    1977             :                           JSON_FORMAT_COLOR_AUTO,
    1978             :                           f, NULL);
    1979           0 : }
    1980             : 
    1981           0 : static int call(int argc, char **argv, void *userdata) {
    1982           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1983           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1984           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
    1985             :         int r;
    1986             : 
    1987           0 :         r = acquire_bus(false, &bus);
    1988           0 :         if (r < 0)
    1989           0 :                 return r;
    1990             : 
    1991           0 :         r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
    1992           0 :         if (r < 0)
    1993           0 :                 return bus_log_create_error(r);
    1994             : 
    1995           0 :         r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
    1996           0 :         if (r < 0)
    1997           0 :                 return bus_log_create_error(r);
    1998             : 
    1999           0 :         r = sd_bus_message_set_auto_start(m, arg_auto_start);
    2000           0 :         if (r < 0)
    2001           0 :                 return bus_log_create_error(r);
    2002             : 
    2003           0 :         r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
    2004           0 :         if (r < 0)
    2005           0 :                 return bus_log_create_error(r);
    2006             : 
    2007           0 :         if (!isempty(argv[5])) {
    2008             :                 char **p;
    2009             : 
    2010           0 :                 p = argv+6;
    2011             : 
    2012           0 :                 r = message_append_cmdline(m, argv[5], &p);
    2013           0 :                 if (r < 0)
    2014           0 :                         return r;
    2015             : 
    2016           0 :                 if (*p)
    2017           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
    2018             :         }
    2019             : 
    2020           0 :         if (!arg_expect_reply) {
    2021           0 :                 r = sd_bus_send(bus, m, NULL);
    2022           0 :                 if (r < 0)
    2023           0 :                         return log_error_errno(r, "Failed to send message: %m");
    2024             : 
    2025           0 :                 return 0;
    2026             :         }
    2027             : 
    2028           0 :         r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
    2029           0 :         if (r < 0)
    2030           0 :                 return log_error_errno(r, "Call failed: %s", bus_error_message(&error, r));
    2031             : 
    2032           0 :         r = sd_bus_message_is_empty(reply);
    2033           0 :         if (r < 0)
    2034           0 :                 return bus_log_parse_error(r);
    2035             : 
    2036           0 :         if (r == 0 && !arg_quiet) {
    2037             : 
    2038           0 :                 if (arg_json != JSON_OFF) {
    2039           0 :                         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
    2040             : 
    2041           0 :                         if (arg_json != JSON_SHORT)
    2042           0 :                                 (void) pager_open(arg_pager_flags);
    2043             : 
    2044           0 :                         r = json_transform_message(reply, &v);
    2045           0 :                         if (r < 0)
    2046           0 :                                 return r;
    2047             : 
    2048           0 :                         json_dump_with_flags(v, stdout);
    2049             : 
    2050           0 :                 } else if (arg_verbose) {
    2051           0 :                         (void) pager_open(arg_pager_flags);
    2052             : 
    2053           0 :                         r = bus_message_dump(reply, stdout, 0);
    2054           0 :                         if (r < 0)
    2055           0 :                                 return r;
    2056             :                 } else {
    2057             : 
    2058           0 :                         fputs(sd_bus_message_get_signature(reply, true), stdout);
    2059           0 :                         fputc(' ', stdout);
    2060             : 
    2061           0 :                         r = format_cmdline(reply, stdout, false);
    2062           0 :                         if (r < 0)
    2063           0 :                                 return bus_log_parse_error(r);
    2064             : 
    2065           0 :                         fputc('\n', stdout);
    2066             :                 }
    2067             :         }
    2068             : 
    2069           0 :         return 0;
    2070             : }
    2071             : 
    2072           0 : static int emit_signal(int argc, char **argv, void *userdata) {
    2073           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    2074           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
    2075             :         int r;
    2076             : 
    2077           0 :         r = acquire_bus(false, &bus);
    2078           0 :         if (r < 0)
    2079           0 :                 return r;
    2080             : 
    2081           0 :         r = sd_bus_message_new_signal(bus, &m, argv[1], argv[2], argv[3]);
    2082           0 :         if (r < 0)
    2083           0 :                 return bus_log_create_error(r);
    2084             : 
    2085           0 :         if (arg_destination) {
    2086           0 :                 r = sd_bus_message_set_destination(m, arg_destination);
    2087           0 :                 if (r < 0)
    2088           0 :                         return bus_log_create_error(r);
    2089             :         }
    2090             : 
    2091           0 :         r = sd_bus_message_set_auto_start(m, arg_auto_start);
    2092           0 :         if (r < 0)
    2093           0 :                 return bus_log_create_error(r);
    2094             : 
    2095           0 :         if (!isempty(argv[4])) {
    2096             :                 char **p;
    2097             : 
    2098           0 :                 p = argv+5;
    2099             : 
    2100           0 :                 r = message_append_cmdline(m, argv[4], &p);
    2101           0 :                 if (r < 0)
    2102           0 :                         return r;
    2103             : 
    2104           0 :                 if (*p)
    2105           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
    2106             :         }
    2107             : 
    2108           0 :         r = sd_bus_send(bus, m, NULL);
    2109           0 :         if (r < 0)
    2110           0 :                 return log_error_errno(r, "Failed to send signal: %m");
    2111             : 
    2112           0 :         return 0;
    2113             : }
    2114             : 
    2115           0 : static int get_property(int argc, char **argv, void *userdata) {
    2116           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    2117           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    2118             :         char **i;
    2119             :         int r;
    2120             : 
    2121           0 :         r = acquire_bus(false, &bus);
    2122           0 :         if (r < 0)
    2123           0 :                 return r;
    2124             : 
    2125           0 :         STRV_FOREACH(i, argv + 4) {
    2126           0 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
    2127           0 :                 const char *contents = NULL;
    2128             :                 char type;
    2129             : 
    2130           0 :                 r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
    2131           0 :                 if (r < 0)
    2132           0 :                         return log_error_errno(r, "Failed to get property %s on interface %s: %s",
    2133             :                                                *i, argv[3],
    2134             :                                                bus_error_message(&error, r));
    2135             : 
    2136           0 :                 r = sd_bus_message_peek_type(reply, &type, &contents);
    2137           0 :                 if (r < 0)
    2138           0 :                         return bus_log_parse_error(r);
    2139             : 
    2140           0 :                 r = sd_bus_message_enter_container(reply, 'v', contents);
    2141           0 :                 if (r < 0)
    2142           0 :                         return bus_log_parse_error(r);
    2143             : 
    2144           0 :                 if (arg_json != JSON_OFF) {
    2145           0 :                         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
    2146             : 
    2147           0 :                         if (arg_json != JSON_SHORT)
    2148           0 :                                 (void) pager_open(arg_pager_flags);
    2149             : 
    2150           0 :                         r = json_transform_variant(reply, contents, &v);
    2151           0 :                         if (r < 0)
    2152           0 :                                 return r;
    2153             : 
    2154           0 :                         json_dump_with_flags(v, stdout);
    2155             : 
    2156           0 :                 } else if (arg_verbose) {
    2157           0 :                         (void) pager_open(arg_pager_flags);
    2158             : 
    2159           0 :                         r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
    2160           0 :                         if (r < 0)
    2161           0 :                                 return r;
    2162             :                 } else {
    2163           0 :                         fputs(contents, stdout);
    2164           0 :                         fputc(' ', stdout);
    2165             : 
    2166           0 :                         r = format_cmdline(reply, stdout, false);
    2167           0 :                         if (r < 0)
    2168           0 :                                 return bus_log_parse_error(r);
    2169             : 
    2170           0 :                         fputc('\n', stdout);
    2171             :                 }
    2172             : 
    2173           0 :                 r = sd_bus_message_exit_container(reply);
    2174           0 :                 if (r < 0)
    2175           0 :                         return bus_log_parse_error(r);
    2176             :         }
    2177             : 
    2178           0 :         return 0;
    2179             : }
    2180             : 
    2181           0 : static int set_property(int argc, char **argv, void *userdata) {
    2182           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    2183           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
    2184           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    2185             :         char **p;
    2186             :         int r;
    2187             : 
    2188           0 :         r = acquire_bus(false, &bus);
    2189           0 :         if (r < 0)
    2190           0 :                 return r;
    2191             : 
    2192           0 :         r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
    2193           0 :         if (r < 0)
    2194           0 :                 return bus_log_create_error(r);
    2195             : 
    2196           0 :         r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
    2197           0 :         if (r < 0)
    2198           0 :                 return bus_log_create_error(r);
    2199             : 
    2200           0 :         r = sd_bus_message_open_container(m, 'v', argv[5]);
    2201           0 :         if (r < 0)
    2202           0 :                 return bus_log_create_error(r);
    2203             : 
    2204           0 :         p = argv + 6;
    2205           0 :         r = message_append_cmdline(m, argv[5], &p);
    2206           0 :         if (r < 0)
    2207           0 :                 return r;
    2208             : 
    2209           0 :         r = sd_bus_message_close_container(m);
    2210           0 :         if (r < 0)
    2211           0 :                 return bus_log_create_error(r);
    2212             : 
    2213           0 :         if (*p)
    2214           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
    2215             : 
    2216           0 :         r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
    2217           0 :         if (r < 0)
    2218           0 :                 return log_error_errno(r, "Failed to set property %s on interface %s: %s",
    2219             :                                        argv[4], argv[3],
    2220             :                                        bus_error_message(&error, r));
    2221             : 
    2222           0 :         return 0;
    2223             : }
    2224             : 
    2225           3 : static int help(void) {
    2226           3 :         _cleanup_free_ char *link = NULL;
    2227             :         int r;
    2228             : 
    2229           3 :         r = terminal_urlify_man("busctl", "1", &link);
    2230           3 :         if (r < 0)
    2231           0 :                 return log_oom();
    2232             : 
    2233           3 :         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
    2234             :                "Introspect the bus.\n\n"
    2235             :                "  -h --help                Show this help\n"
    2236             :                "     --version             Show package version\n"
    2237             :                "     --no-pager            Do not pipe output into a pager\n"
    2238             :                "     --no-legend           Do not show the headers and footers\n"
    2239             :                "     --system              Connect to system bus\n"
    2240             :                "     --user                Connect to user bus\n"
    2241             :                "  -H --host=[USER@]HOST    Operate on remote host\n"
    2242             :                "  -M --machine=CONTAINER   Operate on local container\n"
    2243             :                "     --address=ADDRESS     Connect to bus specified by address\n"
    2244             :                "     --show-machine        Show machine ID column in list\n"
    2245             :                "     --unique              Only show unique names\n"
    2246             :                "     --acquired            Only show acquired names\n"
    2247             :                "     --activatable         Only show activatable names\n"
    2248             :                "     --match=MATCH         Only show matching messages\n"
    2249             :                "     --size=SIZE           Maximum length of captured packet\n"
    2250             :                "     --list                Don't show tree, but simple object path list\n"
    2251             :                "  -q --quiet               Don't show method call reply\n"
    2252             :                "     --verbose             Show result values in long format\n"
    2253             :                "     --json=MODE           Output as JSON\n"
    2254             :                "  -j                       Same as --json=pretty on tty, --json=short otherwise\n"
    2255             :                "     --expect-reply=BOOL   Expect a method call reply\n"
    2256             :                "     --auto-start=BOOL     Auto-start destination service\n"
    2257             :                "     --allow-interactive-authorization=BOOL\n"
    2258             :                "                           Allow interactive authorization for operation\n"
    2259             :                "     --timeout=SECS        Maximum time to wait for method call completion\n"
    2260             :                "     --augment-creds=BOOL  Extend credential data with data read from /proc/$PID\n"
    2261             :                "     --watch-bind=BOOL     Wait for bus AF_UNIX socket to be bound in the file\n"
    2262             :                "                           system\n"
    2263             :                "     --destination=SERVICE Destination service of a signal\n"
    2264             :                "\nCommands:\n"
    2265             :                "  list                     List bus names\n"
    2266             :                "  status [SERVICE]         Show bus service, process or bus owner credentials\n"
    2267             :                "  monitor [SERVICE...]     Show bus traffic\n"
    2268             :                "  capture [SERVICE...]     Capture bus traffic as pcap\n"
    2269             :                "  tree [SERVICE...]        Show object tree of service\n"
    2270             :                "  introspect SERVICE OBJECT [INTERFACE]\n"
    2271             :                "  call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
    2272             :                "                           Call a method\n"
    2273             :                "  emit OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT...]]\n"
    2274             :                "                           Emit a signal\n"
    2275             :                "  get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
    2276             :                "                           Get property value\n"
    2277             :                "  set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
    2278             :                "                           Set property value\n"
    2279             :                "  help                     Show this help\n"
    2280             :                "\nSee the %s for details.\n"
    2281             :                , program_invocation_short_name
    2282             :                , link
    2283             :         );
    2284             : 
    2285           3 :         return 0;
    2286             : }
    2287             : 
    2288           0 : static int verb_help(int argc, char **argv, void *userdata) {
    2289           0 :         return help();
    2290             : }
    2291             : 
    2292           4 : static int parse_argv(int argc, char *argv[]) {
    2293             : 
    2294             :         enum {
    2295             :                 ARG_VERSION = 0x100,
    2296             :                 ARG_NO_PAGER,
    2297             :                 ARG_NO_LEGEND,
    2298             :                 ARG_SYSTEM,
    2299             :                 ARG_USER,
    2300             :                 ARG_ADDRESS,
    2301             :                 ARG_MATCH,
    2302             :                 ARG_SHOW_MACHINE,
    2303             :                 ARG_UNIQUE,
    2304             :                 ARG_ACQUIRED,
    2305             :                 ARG_ACTIVATABLE,
    2306             :                 ARG_SIZE,
    2307             :                 ARG_LIST,
    2308             :                 ARG_VERBOSE,
    2309             :                 ARG_XML_INTERFACE,
    2310             :                 ARG_EXPECT_REPLY,
    2311             :                 ARG_AUTO_START,
    2312             :                 ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
    2313             :                 ARG_TIMEOUT,
    2314             :                 ARG_AUGMENT_CREDS,
    2315             :                 ARG_WATCH_BIND,
    2316             :                 ARG_JSON,
    2317             :                 ARG_DESTINATION,
    2318             :         };
    2319             : 
    2320             :         static const struct option options[] = {
    2321             :                 { "help",                            no_argument,       NULL, 'h'                                 },
    2322             :                 { "version",                         no_argument,       NULL, ARG_VERSION                         },
    2323             :                 { "no-pager",                        no_argument,       NULL, ARG_NO_PAGER                        },
    2324             :                 { "no-legend",                       no_argument,       NULL, ARG_NO_LEGEND                       },
    2325             :                 { "system",                          no_argument,       NULL, ARG_SYSTEM                          },
    2326             :                 { "user",                            no_argument,       NULL, ARG_USER                            },
    2327             :                 { "address",                         required_argument, NULL, ARG_ADDRESS                         },
    2328             :                 { "show-machine",                    no_argument,       NULL, ARG_SHOW_MACHINE                    },
    2329             :                 { "unique",                          no_argument,       NULL, ARG_UNIQUE                          },
    2330             :                 { "acquired",                        no_argument,       NULL, ARG_ACQUIRED                        },
    2331             :                 { "activatable",                     no_argument,       NULL, ARG_ACTIVATABLE                     },
    2332             :                 { "match",                           required_argument, NULL, ARG_MATCH                           },
    2333             :                 { "host",                            required_argument, NULL, 'H'                                 },
    2334             :                 { "machine",                         required_argument, NULL, 'M'                                 },
    2335             :                 { "size",                            required_argument, NULL, ARG_SIZE                            },
    2336             :                 { "list",                            no_argument,       NULL, ARG_LIST                            },
    2337             :                 { "quiet",                           no_argument,       NULL, 'q'                                 },
    2338             :                 { "verbose",                         no_argument,       NULL, ARG_VERBOSE                         },
    2339             :                 { "xml-interface",                   no_argument,       NULL, ARG_XML_INTERFACE                   },
    2340             :                 { "expect-reply",                    required_argument, NULL, ARG_EXPECT_REPLY                    },
    2341             :                 { "auto-start",                      required_argument, NULL, ARG_AUTO_START                      },
    2342             :                 { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
    2343             :                 { "timeout",                         required_argument, NULL, ARG_TIMEOUT                         },
    2344             :                 { "augment-creds",                   required_argument, NULL, ARG_AUGMENT_CREDS                   },
    2345             :                 { "watch-bind",                      required_argument, NULL, ARG_WATCH_BIND                      },
    2346             :                 { "json",                            required_argument, NULL, ARG_JSON                            },
    2347             :                 { "destination",                     required_argument, NULL, ARG_DESTINATION                     },
    2348             :                 {},
    2349             :         };
    2350             : 
    2351             :         int c, r;
    2352             : 
    2353           4 :         assert(argc >= 0);
    2354           4 :         assert(argv);
    2355             : 
    2356           4 :         while ((c = getopt_long(argc, argv, "hH:M:qj", options, NULL)) >= 0)
    2357             : 
    2358           4 :                 switch (c) {
    2359             : 
    2360           3 :                 case 'h':
    2361           3 :                         return help();
    2362             : 
    2363           0 :                 case ARG_VERSION:
    2364           0 :                         return version();
    2365             : 
    2366           0 :                 case ARG_NO_PAGER:
    2367           0 :                         arg_pager_flags |= PAGER_DISABLE;
    2368           0 :                         break;
    2369             : 
    2370           0 :                 case ARG_NO_LEGEND:
    2371           0 :                         arg_legend = false;
    2372           0 :                         break;
    2373             : 
    2374           0 :                 case ARG_USER:
    2375           0 :                         arg_user = true;
    2376           0 :                         break;
    2377             : 
    2378           0 :                 case ARG_SYSTEM:
    2379           0 :                         arg_user = false;
    2380           0 :                         break;
    2381             : 
    2382           0 :                 case ARG_ADDRESS:
    2383           0 :                         arg_address = optarg;
    2384           0 :                         break;
    2385             : 
    2386           0 :                 case ARG_SHOW_MACHINE:
    2387           0 :                         arg_show_machine = true;
    2388           0 :                         break;
    2389             : 
    2390           0 :                 case ARG_UNIQUE:
    2391           0 :                         arg_unique = true;
    2392           0 :                         break;
    2393             : 
    2394           0 :                 case ARG_ACQUIRED:
    2395           0 :                         arg_acquired = true;
    2396           0 :                         break;
    2397             : 
    2398           0 :                 case ARG_ACTIVATABLE:
    2399           0 :                         arg_activatable = true;
    2400           0 :                         break;
    2401             : 
    2402           0 :                 case ARG_MATCH:
    2403           0 :                         if (strv_extend(&arg_matches, optarg) < 0)
    2404           0 :                                 return log_oom();
    2405           0 :                         break;
    2406             : 
    2407           0 :                 case ARG_SIZE: {
    2408             :                         uint64_t sz;
    2409             : 
    2410           0 :                         r = parse_size(optarg, 1024, &sz);
    2411           0 :                         if (r < 0)
    2412           0 :                                 return log_error_errno(r, "Failed to parse size '%s': %m", optarg);
    2413             : 
    2414             :                         if ((uint64_t) (size_t) sz !=  sz)
    2415             :                                 return log_error_errno(SYNTHETIC_ERRNO(E2BIG),
    2416             :                                                        "Size out of range.");
    2417             : 
    2418           0 :                         arg_snaplen = (size_t) sz;
    2419           0 :                         break;
    2420             :                 }
    2421             : 
    2422           0 :                 case ARG_LIST:
    2423           0 :                         arg_list = true;
    2424           0 :                         break;
    2425             : 
    2426           0 :                 case 'H':
    2427           0 :                         arg_transport = BUS_TRANSPORT_REMOTE;
    2428           0 :                         arg_host = optarg;
    2429           0 :                         break;
    2430             : 
    2431           0 :                 case 'M':
    2432           0 :                         arg_transport = BUS_TRANSPORT_MACHINE;
    2433           0 :                         arg_host = optarg;
    2434           0 :                         break;
    2435             : 
    2436           0 :                 case 'q':
    2437           0 :                         arg_quiet = true;
    2438           0 :                         break;
    2439             : 
    2440           0 :                 case ARG_VERBOSE:
    2441           0 :                         arg_verbose = true;
    2442           0 :                         break;
    2443             : 
    2444           0 :                 case ARG_XML_INTERFACE:
    2445           0 :                         arg_xml_interface = true;
    2446           0 :                         break;
    2447             : 
    2448           0 :                 case ARG_EXPECT_REPLY:
    2449           0 :                         r = parse_boolean(optarg);
    2450           0 :                         if (r < 0)
    2451           0 :                                 return log_error_errno(r, "Failed to parse --expect-reply= parameter '%s': %m", optarg);
    2452             : 
    2453           0 :                         arg_expect_reply = r;
    2454           0 :                         break;
    2455             : 
    2456           0 :                 case ARG_AUTO_START:
    2457           0 :                         r = parse_boolean(optarg);
    2458           0 :                         if (r < 0)
    2459           0 :                                 return log_error_errno(r, "Failed to parse --auto-start= parameter '%s': %m", optarg);
    2460             : 
    2461           0 :                         arg_auto_start = r;
    2462           0 :                         break;
    2463             : 
    2464           0 :                 case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
    2465           0 :                         r = parse_boolean(optarg);
    2466           0 :                         if (r < 0)
    2467           0 :                                 return log_error_errno(r, "Failed to parse --allow-interactive-authorization= parameter '%s': %m", optarg);
    2468             : 
    2469           0 :                         arg_allow_interactive_authorization = r;
    2470           0 :                         break;
    2471             : 
    2472           0 :                 case ARG_TIMEOUT:
    2473           0 :                         r = parse_sec(optarg, &arg_timeout);
    2474           0 :                         if (r < 0)
    2475           0 :                                 return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", optarg);
    2476             : 
    2477           0 :                         break;
    2478             : 
    2479           0 :                 case ARG_AUGMENT_CREDS:
    2480           0 :                         r = parse_boolean(optarg);
    2481           0 :                         if (r < 0)
    2482           0 :                                 return log_error_errno(r, "Failed to parse --augment-creds= parameter '%s': %m", optarg);
    2483             : 
    2484           0 :                         arg_augment_creds = r;
    2485           0 :                         break;
    2486             : 
    2487           0 :                 case ARG_WATCH_BIND:
    2488           0 :                         r = parse_boolean(optarg);
    2489           0 :                         if (r < 0)
    2490           0 :                                 return log_error_errno(r, "Failed to parse --watch-bind= parameter '%s': %m", optarg);
    2491             : 
    2492           0 :                         arg_watch_bind = r;
    2493           0 :                         break;
    2494             : 
    2495           0 :                 case 'j':
    2496           0 :                         if (on_tty())
    2497           0 :                                 arg_json = JSON_PRETTY;
    2498             :                         else
    2499           0 :                                 arg_json = JSON_SHORT;
    2500           0 :                         break;
    2501             : 
    2502           0 :                 case ARG_JSON:
    2503           0 :                         if (streq(optarg, "short"))
    2504           0 :                                 arg_json = JSON_SHORT;
    2505           0 :                         else if (streq(optarg, "pretty"))
    2506           0 :                                 arg_json = JSON_PRETTY;
    2507           0 :                         else if (streq(optarg, "help")) {
    2508           0 :                                 fputs("short\n"
    2509             :                                       "pretty\n", stdout);
    2510           0 :                                 return 0;
    2511             :                         } else
    2512           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    2513             :                                                        "Unknown JSON out mode: %s",
    2514             :                                                        optarg);
    2515             : 
    2516           0 :                         break;
    2517             : 
    2518           0 :                 case ARG_DESTINATION:
    2519           0 :                         arg_destination = optarg;
    2520           0 :                         break;
    2521             : 
    2522           1 :                 case '?':
    2523           1 :                         return -EINVAL;
    2524             : 
    2525           0 :                 default:
    2526           0 :                         assert_not_reached("Unhandled option");
    2527             :                 }
    2528             : 
    2529           0 :         return 1;
    2530             : }
    2531             : 
    2532           0 : static int busctl_main(int argc, char *argv[]) {
    2533             : 
    2534             :         static const Verb verbs[] = {
    2535             :                 { "list",         VERB_ANY, 1,        VERB_DEFAULT, list_bus_names },
    2536             :                 { "status",       VERB_ANY, 2,        0,            status         },
    2537             :                 { "monitor",      VERB_ANY, VERB_ANY, 0,            verb_monitor   },
    2538             :                 { "capture",      VERB_ANY, VERB_ANY, 0,            verb_capture   },
    2539             :                 { "tree",         VERB_ANY, VERB_ANY, 0,            tree           },
    2540             :                 { "introspect",   3,        4,        0,            introspect     },
    2541             :                 { "call",         5,        VERB_ANY, 0,            call           },
    2542             :                 { "emit",         4,        VERB_ANY, 0,            emit_signal    },
    2543             :                 { "get-property", 5,        VERB_ANY, 0,            get_property   },
    2544             :                 { "set-property", 6,        VERB_ANY, 0,            set_property   },
    2545             :                 { "help",         VERB_ANY, VERB_ANY, 0,            verb_help      },
    2546             :                 {}
    2547             :         };
    2548             : 
    2549           0 :         return dispatch_verb(argc, argv, verbs, NULL);
    2550             : }
    2551             : 
    2552           4 : static int run(int argc, char *argv[]) {
    2553             :         int r;
    2554             : 
    2555           4 :         log_show_color(true);
    2556           4 :         log_parse_environment();
    2557           4 :         log_open();
    2558             : 
    2559           4 :         r = parse_argv(argc, argv);
    2560           4 :         if (r <= 0)
    2561           4 :                 return r;
    2562             : 
    2563           0 :         return busctl_main(argc, argv);
    2564             : }
    2565             : 
    2566           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14