Branch data 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 : 16 : 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 : 12 : static int help(void) {
2226 : 12 : _cleanup_free_ char *link = NULL;
2227 : : int r;
2228 : :
2229 : 12 : r = terminal_urlify_man("busctl", "1", &link);
2230 [ - + ]: 12 : if (r < 0)
2231 : 0 : return log_oom();
2232 : :
2233 : 12 : 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 : 12 : return 0;
2286 : : }
2287 : :
2288 : 0 : static int verb_help(int argc, char **argv, void *userdata) {
2289 : 0 : return help();
2290 : : }
2291 : :
2292 : 16 : 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 [ - + ]: 16 : assert(argc >= 0);
2354 [ - + ]: 16 : assert(argv);
2355 : :
2356 [ + - ]: 16 : while ((c = getopt_long(argc, argv, "hH:M:qj", options, NULL)) >= 0)
2357 : :
2358 [ + - - - : 16 : switch (c) {
- - - - -
- - - - -
- - - - -
- - - - -
- - - - +
- ]
2359 : :
2360 : 12 : case 'h':
2361 : 12 : 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 : 4 : case '?':
2523 : 4 : 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 : 16 : static int run(int argc, char *argv[]) {
2553 : : int r;
2554 : :
2555 : 16 : log_show_color(true);
2556 : 16 : log_parse_environment();
2557 : 16 : log_open();
2558 : :
2559 : 16 : r = parse_argv(argc, argv);
2560 [ + - ]: 16 : if (r <= 0)
2561 : 16 : return r;
2562 : :
2563 : 0 : return busctl_main(argc, argv);
2564 : : }
2565 : :
2566 : 16 : DEFINE_MAIN_FUNCTION(run);
|