• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14766779411

30 Apr 2025 04:55PM UTC coverage: 72.225% (-0.06%) from 72.282%
14766779411

push

github

web-flow
wait-online: handle varlink connection errors while waiting for DNS (#37283)

Currently, if systemd-networkd-wait-online is started with --dns, and
systemd-resolved is not running, it will exit with an error right away.
Similarly, if systemd-resolved is restarted while waiting for DNS
configuration, systemd-networkd-wait-online will not attempt to
re-connect, and will potentially never see subsequent DNS
configurations.

Improve this by adding socket units for the systemd-resolved varlink
servers, and re-establish the connection in systemd-networkd-wait-online
when we receive `SD_VARLINK_ERROR_DISCONNECTED`.

8 of 16 new or added lines in 2 files covered. (50.0%)

5825 existing lines in 217 files now uncovered.

297168 of 411450 relevant lines covered (72.22%)

695892.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.57
/src/busctl/busctl.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <getopt.h>
4

5
#include "sd-bus.h"
6
#include "sd-json.h"
7

8
#include "alloc-util.h"
9
#include "bitfield.h"
10
#include "build.h"
11
#include "bus-dump.h"
12
#include "bus-internal.h"
13
#include "bus-message.h"
14
#include "bus-signature.h"
15
#include "bus-type.h"
16
#include "bus-util.h"
17
#include "busctl-introspect.h"
18
#include "capsule-util.h"
19
#include "escape.h"
20
#include "fd-util.h"
21
#include "fdset.h"
22
#include "fileio.h"
23
#include "format-table.h"
24
#include "glyph-util.h"
25
#include "json-util.h"
26
#include "log.h"
27
#include "logarithm.h"
28
#include "main-func.h"
29
#include "memstream-util.h"
30
#include "os-util.h"
31
#include "pager.h"
32
#include "parse-argument.h"
33
#include "parse-util.h"
34
#include "path-util.h"
35
#include "pretty-print.h"
36
#include "runtime-scope.h"
37
#include "set.h"
38
#include "sort-util.h"
39
#include "strv.h"
40
#include "terminal-util.h"
41
#include "user-util.h"
42
#include "verbs.h"
43
#include "version.h"
44

45
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
46
static PagerFlags arg_pager_flags = 0;
47
static bool arg_legend = true;
48
static int arg_full = -1;
49
static const char *arg_address = NULL;
50
static bool arg_unique = false;
51
static bool arg_acquired = false;
52
static bool arg_activatable = false;
53
static bool arg_show_machine = false;
54
static char **arg_matches = NULL;
55
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
56
static const char *arg_host = NULL;
57
static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
58
static size_t arg_snaplen = 4096;
59
static bool arg_list = false;
60
static bool arg_quiet = false;
61
static bool arg_verbose = false;
62
static bool arg_xml_interface = false;
63
static bool arg_expect_reply = true;
64
static bool arg_auto_start = true;
65
static bool arg_allow_interactive_authorization = true;
66
static bool arg_augment_creds = true;
67
static bool arg_watch_bind = false;
68
static usec_t arg_timeout = 0;
69
static const char *arg_destination = NULL;
70
static uint64_t arg_limit_messages = UINT64_MAX;
71

72
STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
1,156✔
73

74
#define NAME_IS_ACQUIRED INT_TO_PTR(1)
75
#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
76

77
static int acquire_bus(bool set_monitor, sd_bus **ret) {
1,149✔
78
        _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
1,149✔
79
        _cleanup_close_ int pin_fd = -EBADF;
1,149✔
80
        int r;
1,149✔
81

82
        r = sd_bus_new(&bus);
1,149✔
83
        if (r < 0)
1,149✔
UNCOV
84
                return log_error_errno(r, "Failed to allocate bus: %m");
×
85

86
        (void) sd_bus_set_description(bus, "busctl");
1,149✔
87

88
        if (set_monitor) {
1,149✔
89
                r = sd_bus_set_monitor(bus, true);
2✔
90
                if (r < 0)
2✔
UNCOV
91
                        return log_error_errno(r, "Failed to set monitor mode: %m");
×
92

93
                r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
2✔
94
                if (r < 0)
2✔
UNCOV
95
                        return log_error_errno(r, "Failed to enable credentials: %m");
×
96

97
                r = sd_bus_negotiate_timestamp(bus, true);
2✔
98
                if (r < 0)
2✔
UNCOV
99
                        return log_error_errno(r, "Failed to enable timestamps: %m");
×
100

101
                r = sd_bus_negotiate_fds(bus, true);
2✔
102
                if (r < 0)
2✔
UNCOV
103
                        return log_error_errno(r, "Failed to enable fds: %m");
×
104
        }
105

106
        r = sd_bus_set_bus_client(bus, true);
1,149✔
107
        if (r < 0)
1,149✔
UNCOV
108
                return log_error_errno(r, "Failed to set bus client: %m");
×
109

110
        r = sd_bus_set_watch_bind(bus, arg_watch_bind);
1,149✔
111
        if (r < 0)
1,149✔
UNCOV
112
                return log_error_errno(r, "Failed to set watch-bind setting to '%s': %m",
×
113
                                       yes_no(arg_watch_bind));
114

115
        if (arg_address)
1,149✔
UNCOV
116
                r = sd_bus_set_address(bus, arg_address);
×
117
        else
118
                switch (arg_transport) {
1,149✔
119

120
                case BUS_TRANSPORT_LOCAL:
1,146✔
121

122
                        switch (arg_runtime_scope) {
1,146✔
123

UNCOV
124
                        case RUNTIME_SCOPE_USER:
×
UNCOV
125
                                r = bus_set_address_user(bus);
×
126
                                break;
127

128
                        case RUNTIME_SCOPE_SYSTEM:
1,146✔
129
                                r = bus_set_address_system(bus);
1,146✔
130
                                break;
131

UNCOV
132
                        default:
×
UNCOV
133
                                assert_not_reached();
×
134
                        }
135

136
                        break;
137

UNCOV
138
                case BUS_TRANSPORT_REMOTE:
×
UNCOV
139
                        r = bus_set_address_system_remote(bus, arg_host);
×
140
                        break;
141

142
                case BUS_TRANSPORT_MACHINE:
2✔
143
                        r = bus_set_address_machine(bus, arg_runtime_scope, arg_host);
2✔
144
                        break;
145

146
                case BUS_TRANSPORT_CAPSULE:
1✔
147
                        r = bus_set_address_capsule_bus(bus, arg_host, &pin_fd);
1✔
148
                        break;
149

UNCOV
150
                default:
×
UNCOV
151
                        assert_not_reached();
×
152
                }
153
        if (r < 0)
1,149✔
UNCOV
154
                return bus_log_address_error(r, arg_transport);
×
155

156
        r = sd_bus_start(bus);
1,149✔
157
        if (r < 0)
1,149✔
158
                return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
1,149✔
159

160
        *ret = TAKE_PTR(bus);
1,149✔
161

162
        return 0;
1,149✔
163
}
164

165
static void notify_bus_error(const sd_bus_error *error) {
1,013✔
166

167
        if (!sd_bus_error_is_set(error))
1,013✔
168
                return;
169

170
        (void) sd_notifyf(/* unset_environment= */ false, "BUSERROR=%s", error->name);
1,013✔
171
}
172

173
static int list_bus_names(int argc, char **argv, void *userdata) {
6✔
174
        _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
6✔
175
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
6✔
176
        _cleanup_hashmap_free_ Hashmap *names = NULL;
6✔
177
        _cleanup_(table_unrefp) Table *table = NULL;
6✔
178
        char *k;
6✔
179
        void *v;
6✔
180
        int r;
6✔
181

182
        enum {
6✔
183
                COLUMN_ACTIVATABLE,
184
                COLUMN_NAME,
185
                COLUMN_PID,
186
                COLUMN_PROCESS,
187
                COLUMN_USER,
188
                COLUMN_CONNECTION,
189
                COLUMN_UNIT,
190
                COLUMN_SESSION,
191
                COLUMN_DESCRIPTION,
192
                COLUMN_MACHINE,
193
        };
194

195
        if (!arg_unique && !arg_acquired && !arg_activatable)
6✔
196
                arg_unique = arg_acquired = arg_activatable = true;
4✔
197

198
        r = acquire_bus(false, &bus);
6✔
199
        if (r < 0)
6✔
200
                return r;
201

202
        r = sd_bus_list_names(bus,
6✔
203
                              (arg_acquired || arg_unique) ? &acquired : NULL,
6✔
204
                              arg_activatable ? &activatable : NULL);
6✔
205
        if (r < 0)
6✔
UNCOV
206
                return log_error_errno(r, "Failed to list names: %m");
×
207

208
        names = hashmap_new(&string_hash_ops);
6✔
209
        if (!names)
6✔
UNCOV
210
                return log_oom();
×
211

212
        STRV_FOREACH(i, acquired) {
79✔
213
                r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
73✔
214
                if (r < 0)
73✔
UNCOV
215
                        return log_error_errno(r, "Failed to add to hashmap: %m");
×
216
        }
217

218
        STRV_FOREACH(i, activatable) {
72✔
219
                r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
66✔
220
                if (r < 0 && r != -EEXIST)
66✔
UNCOV
221
                        return log_error_errno(r, "Failed to add to hashmap: %m");
×
222
        }
223

224
        table = table_new("activatable",
6✔
225
                          "name",
226
                          "pid",
227
                          "process",
228
                          "user",
229
                          "connection",
230
                          "unit",
231
                          "session",
232
                          "description",
233
                          "machine");
234
        if (!table)
6✔
UNCOV
235
                return log_oom();
×
236

237
        if (arg_full > 0)
6✔
238
                table_set_width(table, 0);
6✔
239

240
        r = table_set_align_percent(table, table_get_cell(table, 0, COLUMN_PID), 100);
6✔
241
        if (r < 0)
6✔
UNCOV
242
                return log_error_errno(r, "Failed to set alignment: %m");
×
243

244
        table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
6✔
245

246
        r = table_set_sort(table, (size_t) COLUMN_NAME);
6✔
247
        if (r < 0)
6✔
UNCOV
248
                return log_error_errno(r, "Failed to set sort column: %m");
×
249

250
        if (arg_show_machine)
6✔
251
                r = table_set_display(table, (size_t) COLUMN_NAME,
1✔
252
                                             (size_t) COLUMN_PID,
253
                                             (size_t) COLUMN_PROCESS,
254
                                             (size_t) COLUMN_USER,
255
                                             (size_t) COLUMN_CONNECTION,
256
                                             (size_t) COLUMN_UNIT,
257
                                             (size_t) COLUMN_SESSION,
258
                                             (size_t) COLUMN_DESCRIPTION,
259
                                             (size_t) COLUMN_MACHINE);
260
        else
261
                r = table_set_display(table, (size_t) COLUMN_NAME,
5✔
262
                                             (size_t) COLUMN_PID,
263
                                             (size_t) COLUMN_PROCESS,
264
                                             (size_t) COLUMN_USER,
265
                                             (size_t) COLUMN_CONNECTION,
266
                                             (size_t) COLUMN_UNIT,
267
                                             (size_t) COLUMN_SESSION,
268
                                             (size_t) COLUMN_DESCRIPTION);
269

270
        if (r < 0)
6✔
UNCOV
271
                return log_error_errno(r, "Failed to set columns to display: %m");
×
272

273
        HASHMAP_FOREACH_KEY(v, k, names) {
120✔
274
                _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
114✔
275

276
                if (v == NAME_IS_ACTIVATABLE) {
114✔
277
                        r = table_add_many(
41✔
278
                                        table,
279
                                        TABLE_INT, PTR_TO_INT(v),
280
                                        TABLE_STRING, k,
281
                                        TABLE_EMPTY,
282
                                        TABLE_EMPTY,
283
                                        TABLE_EMPTY,
284
                                        TABLE_STRING, "(activatable)", TABLE_SET_COLOR, ansi_grey(),
285
                                        TABLE_EMPTY,
286
                                        TABLE_EMPTY,
287
                                        TABLE_EMPTY,
288
                                        TABLE_EMPTY);
289
                        if (r < 0)
41✔
UNCOV
290
                                return table_log_add_error(r);
×
291

292
                        continue;
41✔
293
                }
294

295
                assert(v == NAME_IS_ACQUIRED);
73✔
296

297
                if (!arg_unique && k[0] == ':')
73✔
298
                        continue;
8✔
299

300
                if (!arg_acquired && k[0] != ':')
65✔
301
                        continue;
6✔
302

303
                r = table_add_many(table,
59✔
304
                                   TABLE_INT, PTR_TO_INT(v),
305
                                   TABLE_STRING, k);
306
                if (r < 0)
59✔
UNCOV
307
                        return table_log_add_error(r);
×
308

309
                r = sd_bus_get_name_creds(
59✔
310
                                bus, k,
311
                                (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
59✔
312
                                SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
313
                                SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
314
                                SD_BUS_CREDS_DESCRIPTION, &creds);
315
                if (r < 0) {
59✔
UNCOV
316
                        log_debug_errno(r, "Failed to acquire credentials of service %s, ignoring: %m", k);
×
317

318
                        r = table_fill_empty(table, COLUMN_MACHINE);
×
319
                } else {
320
                        const char *unique = NULL, *session = NULL, *unit = NULL, *cn = NULL;
59✔
321
                        pid_t pid;
59✔
322
                        uid_t uid;
59✔
323

324
                        r = sd_bus_creds_get_pid(creds, &pid);
59✔
325
                        if (r >= 0) {
59✔
326
                                const char *comm = NULL;
59✔
327

328
                                (void) sd_bus_creds_get_comm(creds, &comm);
59✔
329

330
                                r = table_add_many(table,
60✔
331
                                                   TABLE_PID, pid,
332
                                                   TABLE_STRING, strna(comm));
333
                        } else
UNCOV
334
                                r = table_add_many(table, TABLE_EMPTY, TABLE_EMPTY);
×
335
                        if (r < 0)
59✔
336
                                return table_log_add_error(r);
×
337

338
                        r = sd_bus_creds_get_euid(creds, &uid);
59✔
339
                        if (r >= 0) {
59✔
340
                                _cleanup_free_ char *u = NULL;
59✔
341

342
                                u = uid_to_name(uid);
59✔
343
                                if (!u)
59✔
UNCOV
344
                                        return log_oom();
×
345

346
                                r = table_add_cell(table, NULL, TABLE_STRING, u);
59✔
347
                        } else
UNCOV
348
                                r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
×
349
                        if (r < 0)
59✔
350
                                return table_log_add_error(r);
×
351

352
                        (void) sd_bus_creds_get_unique_name(creds, &unique);
59✔
353
                        (void) sd_bus_creds_get_unit(creds, &unit);
59✔
354
                        (void) sd_bus_creds_get_session(creds, &session);
59✔
355
                        (void) sd_bus_creds_get_description(creds, &cn);
59✔
356

357
                        r = table_add_many(
59✔
358
                                        table,
359
                                        TABLE_STRING, unique,
360
                                        TABLE_STRING, unit,
361
                                        TABLE_STRING, session,
362
                                        TABLE_STRING, cn);
363
                }
364
                if (r < 0)
59✔
UNCOV
365
                        return table_log_add_error(r);
×
366

367
                if (arg_show_machine) {
59✔
368
                        sd_id128_t mid;
8✔
369

370
                        r = sd_bus_get_name_machine_id(bus, k, &mid);
8✔
371
                        if (r < 0)
8✔
372
                                log_debug_errno(r, "Failed to acquire credentials of service %s, ignoring: %m", k);
2✔
373
                        else {
374
                                r = table_add_cell(table, NULL, TABLE_ID128, &mid);
6✔
375
                                if (r < 0)
6✔
UNCOV
376
                                        return table_log_add_error(r);
×
377

378
                                continue; /* line fully filled, no need to fill the remainder below */
6✔
379
                        }
380
                }
381

382
                r = table_fill_empty(table, 0);
53✔
383
                if (r < 0)
53✔
UNCOV
384
                        return log_error_errno(r, "Failed to fill line: %m");
×
385
        }
386

387
        return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
6✔
388
}
389

390
static void print_subtree(const char *prefix, const char *path, char **l) {
333✔
391
        /* We assume the list is sorted. Let's first skip over the
392
         * entry we are looking at. */
393
        for (;;) {
999✔
394
                if (!*l)
666✔
395
                        return;
396

397
                if (!streq(*l, path))
653✔
398
                        break;
399

400
                l++;
333✔
401
        }
402

403
        const char
320✔
404
                *vertical = strjoina(prefix, glyph(GLYPH_TREE_VERTICAL)),
1,600✔
405
                *space = strjoina(prefix, glyph(GLYPH_TREE_SPACE));
1,600✔
406

407
        for (;;) {
320✔
408
                bool has_more = false;
640✔
409
                char **n;
640✔
410

411
                if (!*l || !path_startswith(*l, path))
640✔
412
                        break;
413

414
                n = l + 1;
320✔
415
                for (;;) {
2,570✔
416
                        if (!*n || !path_startswith(*n, path))
1,445✔
417
                                break;
418

419
                        if (!path_startswith(*n, *l)) {
1,382✔
420
                                has_more = true;
421
                                break;
422
                        }
423

424
                        n++;
1,125✔
425
                }
426

427
                printf("%s%s %s\n",
640✔
428
                       prefix,
429
                       glyph(has_more ? GLYPH_TREE_BRANCH : GLYPH_TREE_RIGHT),
430
                       *l);
431

432
                print_subtree(has_more ? vertical : space, *l, l);
320✔
433
                l = n;
320✔
434
        }
435
}
436

437
static void print_tree(char **l) {
15✔
438
        if (arg_list)
15✔
439
                strv_print(l);
1✔
440
        else if (strv_isempty(l))
14✔
441
                printf("No objects discovered.\n");
1✔
442
        else if (streq(l[0], "/") && !l[1])
13✔
UNCOV
443
                printf("Only root object discovered.\n");
×
444
        else
445
                print_subtree("", "/", l);
13✔
446
}
15✔
447

448
static int on_path(const char *path, void *userdata) {
674✔
449
        Set *paths = ASSERT_PTR(userdata);
674✔
450
        int r;
674✔
451

452
        r = set_put_strdup(&paths, path);
674✔
453
        if (r < 0)
674✔
UNCOV
454
                return log_oom();
×
455

456
        return 0;
457
}
458

459
static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths) {
345✔
460
        static const XMLIntrospectOps ops = {
345✔
461
                .on_path = on_path,
462
        };
463

464
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
345✔
465
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
345✔
466
        const char *xml;
345✔
467
        int r;
345✔
468

469
        r = sd_bus_call_method(bus, service, path,
345✔
470
                               "org.freedesktop.DBus.Introspectable", "Introspect",
471
                               &error, &reply, NULL);
472
        if (r < 0) {
345✔
473
                notify_bus_error(&error);
1✔
474
                printf("%sFailed to introspect object %s of service %s: %s%s\n",
2✔
475
                       ansi_highlight_red(),
476
                       path, service, bus_error_message(&error, r),
1✔
477
                       ansi_normal());
478
                return r;
1✔
479
        }
480

481
        r = sd_bus_message_read(reply, "s", &xml);
344✔
482
        if (r < 0)
344✔
UNCOV
483
                return bus_log_parse_error(r);
×
484

485
        return parse_xml_introspect(path, xml, &ops, paths);
344✔
486
}
487

488
static int tree_one(sd_bus *bus, const char *service) {
15✔
489
        _cleanup_set_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
15✔
490
        _cleanup_free_ char **l = NULL;
15✔
491
        int r;
15✔
492

493
        r = set_put_strdup(&paths, "/");
15✔
494
        if (r < 0)
15✔
UNCOV
495
                return log_oom();
×
496

497
        for (;;) {
704✔
498
                _cleanup_free_ char *p = NULL;
344✔
499
                int q;
704✔
500

501
                p = set_steal_first(paths);
704✔
502
                if (!p)
704✔
503
                        break;
504

505
                if (set_contains(done, p) ||
689✔
506
                    set_contains(failed, p))
345✔
507
                        continue;
344✔
508

509
                q = find_nodes(bus, service, p, paths);
345✔
510
                if (q < 0 && r >= 0)
345✔
511
                        r = q;
512

513
                q = set_ensure_consume(q < 0 ? &failed : &done, &string_hash_ops_free, TAKE_PTR(p));
689✔
514
                assert(q != 0);
345✔
515
                if (q < 0)
345✔
UNCOV
516
                        return log_oom();
×
517
        }
518

519
        pager_open(arg_pager_flags);
15✔
520

521
        l = set_get_strv(done);
15✔
522
        if (!l)
15✔
UNCOV
523
                return log_oom();
×
524

525
        strv_sort(l);
15✔
526
        print_tree(l);
15✔
527

528
        fflush(stdout);
15✔
529

530
        return r;
531
}
532

533
static int tree(int argc, char **argv, void *userdata) {
10✔
534
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
10✔
535
        int r;
10✔
536

537
        /* Do superficial verification of arguments before even opening the bus */
538
        STRV_FOREACH(i, strv_skip(argv, 1))
19✔
539
                if (!sd_bus_service_name_is_valid(*i))
9✔
UNCOV
540
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
541
                                               "Invalid bus service name: %s", *i);
542

543
        if (!arg_unique && !arg_acquired)
10✔
544
                arg_acquired = true;
10✔
545

546
        r = acquire_bus(false, &bus);
10✔
547
        if (r < 0)
10✔
548
                return r;
549

550
        char **args = strv_skip(argv, 1);
10✔
551
        if (args)
10✔
552
                STRV_FOREACH(arg, args) {
18✔
553
                        if (arg != args)
9✔
UNCOV
554
                                puts("");
×
555

556
                        if (args[1]) {
9✔
UNCOV
557
                                pager_open(arg_pager_flags);
×
UNCOV
558
                                printf("Service %s%s%s:\n", ansi_highlight(), *arg, ansi_normal());
×
559
                        }
560

561
                        RET_GATHER(r, tree_one(bus, *arg));
9✔
562
                }
563
        else {
564
                _cleanup_strv_free_ char **names = NULL;
1✔
565

566
                r = sd_bus_list_names(bus, &names, NULL);
1✔
567
                if (r < 0)
1✔
UNCOV
568
                        return log_error_errno(r, "Failed to get name list: %m");
×
569

570
                pager_open(arg_pager_flags);
1✔
571

572
                STRV_FOREACH(name, names) {
15✔
573
                        if (!arg_unique && (*name)[0] == ':')
14✔
574
                                continue;
8✔
575

576
                        if (!arg_acquired && (*name)[0] == ':')
6✔
UNCOV
577
                                continue;
×
578

579
                        if (name != names)
6✔
580
                                puts("");
5✔
581

582
                        printf("Service %s%s%s:\n", ansi_highlight(), *name, ansi_normal());
18✔
583

584
                        RET_GATHER(r, tree_one(bus, *name));
6✔
585
                }
586
        }
587

588
        return r;
589
}
590

591
static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
355✔
592
        int r;
790✔
593

594
        for (;;) {
790✔
595
                const char *contents = NULL;
790✔
596
                char type;
790✔
597
                union {
790✔
598
                        uint8_t u8;
599
                        uint16_t u16;
600
                        int16_t s16;
601
                        uint32_t u32;
602
                        int32_t s32;
603
                        uint64_t u64;
604
                        int64_t s64;
605
                        double d64;
606
                        const char *string;
607
                        int i;
608
                } basic;
609

610
                r = sd_bus_message_peek_type(m, &type, &contents);
790✔
611
                if (r < 0)
790✔
612
                        return r;
355✔
613
                if (r == 0)
790✔
614
                        return needs_space;
355✔
615

616
                if (bus_type_is_container(type) > 0) {
435✔
617

618
                        r = sd_bus_message_enter_container(m, type, contents);
15✔
619
                        if (r < 0)
15✔
620
                                return r;
621

622
                        if (type == SD_BUS_TYPE_ARRAY) {
15✔
623
                                unsigned n = 0;
624

625
                                /* count array entries */
626
                                for (;;) {
107✔
627

628
                                        r = sd_bus_message_skip(m, contents);
58✔
629
                                        if (r < 0)
58✔
630
                                                return r;
631
                                        if (r == 0)
58✔
632
                                                break;
633

634
                                        n++;
49✔
635
                                }
636

637
                                r = sd_bus_message_rewind(m, false);
9✔
638
                                if (r < 0)
9✔
639
                                        return r;
640

641
                                if (needs_space)
9✔
642
                                        fputc(' ', f);
1✔
643

644
                                fprintf(f, "%u", n);
9✔
645
                                needs_space = true;
646

647
                        } else if (type == SD_BUS_TYPE_VARIANT) {
6✔
648

UNCOV
649
                                if (needs_space)
×
UNCOV
650
                                        fputc(' ', f);
×
651

652
                                fprintf(f, "%s", contents);
×
653
                                needs_space = true;
654
                        }
655

656
                        r = format_cmdline(m, f, needs_space);
15✔
657
                        if (r < 0)
15✔
658
                                return r;
659

660
                        needs_space = r > 0;
15✔
661

662
                        r = sd_bus_message_exit_container(m);
15✔
663
                        if (r < 0)
15✔
664
                                return r;
665

666
                        continue;
15✔
667
                }
668

669
                r = sd_bus_message_read_basic(m, type, &basic);
420✔
670
                if (r < 0)
420✔
671
                        return r;
672

673
                if (needs_space)
420✔
674
                        fputc(' ', f);
88✔
675

676
                switch (type) {
420✔
677
                case SD_BUS_TYPE_BYTE:
6✔
678
                        fprintf(f, "%u", basic.u8);
6✔
679
                        break;
680

681
                case SD_BUS_TYPE_BOOLEAN:
21✔
682
                        fputs(true_false(basic.i), f);
32✔
683
                        break;
684

UNCOV
685
                case SD_BUS_TYPE_INT16:
×
UNCOV
686
                        fprintf(f, "%i", basic.s16);
×
687
                        break;
688

UNCOV
689
                case SD_BUS_TYPE_UINT16:
×
UNCOV
690
                        fprintf(f, "%u", basic.u16);
×
691
                        break;
692

693
                case SD_BUS_TYPE_INT32:
35✔
694
                        fprintf(f, "%i", basic.s32);
35✔
695
                        break;
696

697
                case SD_BUS_TYPE_UINT32:
15✔
698
                        fprintf(f, "%u", basic.u32);
15✔
699
                        break;
700

UNCOV
701
                case SD_BUS_TYPE_INT64:
×
UNCOV
702
                        fprintf(f, "%" PRIi64, basic.s64);
×
703
                        break;
704

705
                case SD_BUS_TYPE_UINT64:
177✔
706
                        fprintf(f, "%" PRIu64, basic.u64);
177✔
707
                        break;
708

709
                case SD_BUS_TYPE_DOUBLE:
2✔
710
                        fprintf(f, "%g", basic.d64);
2✔
711
                        break;
712

713
                case SD_BUS_TYPE_STRING:
164✔
714
                case SD_BUS_TYPE_OBJECT_PATH:
715
                case SD_BUS_TYPE_SIGNATURE: {
716
                        _cleanup_free_ char *b = NULL;
164✔
717

718
                        b = cescape(basic.string);
164✔
719
                        if (!b)
164✔
UNCOV
720
                                return -ENOMEM;
×
721

722
                        fprintf(f, "\"%s\"", b);
164✔
723
                        break;
164✔
724
                }
725

UNCOV
726
                case SD_BUS_TYPE_UNIX_FD:
×
UNCOV
727
                        fprintf(f, "%i", basic.i);
×
728
                        break;
729

UNCOV
730
                default:
×
UNCOV
731
                        assert_not_reached();
×
732
                }
733

734
                needs_space = true;
420✔
735
        }
736
}
737

738
typedef struct Member {
739
        const char *type;
740
        char *interface;
741
        char *name;
742
        char *signature;
743
        char *result;
744
        char *value;
745
        bool writable;
746
        uint64_t flags;
747
} Member;
748

749
static void member_hash_func(const Member *m, struct siphash *state) {
1,436✔
750
        uint64_t arity = 1;
1,436✔
751

752
        assert(m);
1,436✔
753
        assert(m->type);
1,436✔
754

755
        string_hash_func(m->type, state);
1,436✔
756

757
        arity += !!m->name + !!m->interface;
1,436✔
758

759
        uint64_hash_func(&arity, state);
1,436✔
760

761
        if (m->name)
1,436✔
762
                string_hash_func(m->name, state);
1,394✔
763

764
        if (m->signature)
1,436✔
765
                string_hash_func(m->signature, state);
1,298✔
766

767
        if (m->interface)
1,436✔
768
                string_hash_func(m->interface, state);
1,436✔
769
}
1,436✔
770

771
static int member_compare_func(const Member *x, const Member *y) {
3,596✔
772
        int d;
3,596✔
773

774
        assert(x);
3,596✔
775
        assert(y);
3,596✔
776
        assert(x->type);
3,596✔
777
        assert(y->type);
3,596✔
778

779
        d = strcmp_ptr(x->interface, y->interface);
3,596✔
780
        if (d != 0)
3,596✔
781
                return d;
782

783
        d = strcmp(x->type, y->type);
3,426✔
784
        if (d != 0)
3,426✔
785
                return d;
786

787
        d = strcmp_ptr(x->name, y->name);
2,817✔
788
        if (d != 0)
2,817✔
789
                return d;
790

791
        return strcmp_ptr(x->signature, y->signature);
250✔
792
}
793

794
static Member* member_free(Member *m) {
462✔
795
        if (!m)
462✔
796
                return NULL;
797

798
        free(m->interface);
462✔
799
        free(m->name);
462✔
800
        free(m->signature);
462✔
801
        free(m->result);
462✔
802
        free(m->value);
462✔
803
        return mfree(m);
462✔
804
}
805
DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
462✔
806

807
static int on_interface(const char *interface, uint64_t flags, void *userdata) {
8✔
808
        _cleanup_(member_freep) Member *m = NULL;
8✔
809
        Set *members = ASSERT_PTR(userdata);
8✔
810
        int r;
8✔
811

812
        assert(interface);
8✔
813

814
        m = new(Member, 1);
8✔
815
        if (!m)
8✔
UNCOV
816
                return log_oom();
×
817

818
        *m = (Member) {
8✔
819
                .type = "interface",
820
                .flags = flags,
821
        };
822

823
        r = strdup_to(&m->interface, interface);
8✔
824
        if (r < 0)
8✔
UNCOV
825
                return log_oom();
×
826

827
        r = set_consume(members, TAKE_PTR(m));
8✔
828
        if (r < 0)
8✔
UNCOV
829
                return log_oom();
×
830
        if (r == 0)
8✔
831
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
832
                                       "Invalid introspection data: duplicate interface '%s'.", interface);
833

834
        return 0;
835
}
836

837
static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
188✔
838
        _cleanup_(member_freep) Member *m = NULL;
188✔
839
        Set *members = userdata;
188✔
840
        int r;
188✔
841

842
        assert(interface);
188✔
843
        assert(name);
188✔
844

845
        m = new(Member, 1);
188✔
846
        if (!m)
188✔
UNCOV
847
                return log_oom();
×
848

849
        *m = (Member) {
188✔
850
                .type = "method",
851
                .flags = flags,
852
        };
853

854
        r = strdup_to(&m->interface, interface);
188✔
855
        if (r < 0)
188✔
UNCOV
856
                return log_oom();
×
857

858
        r = strdup_to(&m->name, name);
188✔
859
        if (r < 0)
188✔
UNCOV
860
                return log_oom();
×
861

862
        r = strdup_to(&m->signature, signature);
188✔
863
        if (r < 0)
188✔
UNCOV
864
                return log_oom();
×
865

866
        r = strdup_to(&m->result, result);
188✔
867
        if (r < 0)
188✔
UNCOV
868
                return log_oom();
×
869

870
        r = set_consume(members, TAKE_PTR(m));
188✔
871
        if (r < 0)
188✔
UNCOV
872
                return log_oom();
×
873
        if (r == 0)
188✔
874
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
875
                                       "Invalid introspection data: duplicate method '%s' on interface '%s'.", name, interface);
876

877
        return 0;
878
}
879

880
static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
16✔
881
        _cleanup_(member_freep) Member *m = NULL;
16✔
882
        Set *members = userdata;
16✔
883
        int r;
16✔
884

885
        assert(interface);
16✔
886
        assert(name);
16✔
887

888
        m = new(Member, 1);
16✔
889
        if (!m)
16✔
UNCOV
890
                return log_oom();
×
891

892
        *m = (Member) {
16✔
893
                .type = "signal",
894
                .flags = flags,
895
        };
896

897
        r = strdup_to(&m->interface, interface);
16✔
898
        if (r < 0)
16✔
UNCOV
899
                return log_oom();
×
900

901
        r = strdup_to(&m->name, name);
16✔
902
        if (r < 0)
16✔
UNCOV
903
                return log_oom();
×
904

905
        r = strdup_to(&m->signature, signature);
16✔
906
        if (r < 0)
16✔
UNCOV
907
                return log_oom();
×
908

909
        r = set_consume(members, TAKE_PTR(m));
16✔
910
        if (r < 0)
16✔
UNCOV
911
                return log_oom();
×
912
        if (r == 0)
16✔
913
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
914
                                       "Invalid introspection data: duplicate signal '%s' on interface '%s'.", name, interface);
915

916
        return 0;
917
}
918

919
static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
250✔
920
        _cleanup_(member_freep) Member *m = NULL;
250✔
921
        Set *members = userdata;
250✔
922
        int r;
250✔
923

924
        assert(interface);
250✔
925
        assert(name);
250✔
926

927
        m = new(Member, 1);
250✔
928
        if (!m)
250✔
UNCOV
929
                return log_oom();
×
930

931
        *m = (Member) {
250✔
932
                .type = "property",
933
                .flags = flags,
934
                .writable = writable,
935
        };
936

937
        r = strdup_to(&m->interface, interface);
250✔
938
        if (r < 0)
250✔
UNCOV
939
                return log_oom();
×
940

941
        r = strdup_to(&m->name, name);
250✔
942
        if (r < 0)
250✔
UNCOV
943
                return log_oom();
×
944

945
        r = strdup_to(&m->signature, signature);
250✔
946
        if (r < 0)
250✔
UNCOV
947
                return log_oom();
×
948

949
        r = set_consume(members, TAKE_PTR(m));
250✔
950
        if (r < 0)
250✔
UNCOV
951
                return log_oom();
×
952
        if (r == 0)
250✔
953
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
954
                                       "Invalid introspection data: duplicate property '%s' on interface '%s'.", name, interface);
955

956
        return 0;
957
}
958

959
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
462✔
960
                member_hash_ops,
961
                Member,
962
                member_hash_func,
963
                member_compare_func,
964
                member_free);
965

966
static int members_flags_to_string(const Member *m, char **ret) {
451✔
967
        static const char *map[] = {
451✔
968
                [LOG2U(SD_BUS_VTABLE_DEPRECATED)]                  = "deprecated",
969
                [LOG2U(SD_BUS_VTABLE_METHOD_NO_REPLY)]             = "no-reply",
970
                [LOG2U(SD_BUS_VTABLE_PROPERTY_CONST)]              = "const",
971
                [LOG2U(SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)]       = "emits-change",
972
                [LOG2U(SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)] = "emits-invalidation",
973
        };
974

975
        assert(m);
451✔
976
        assert(ret);
451✔
977

978
        _cleanup_free_ char *str = NULL;
451✔
979
        for (size_t i = 0; i < ELEMENTSOF(map); i++)
3,608✔
980
                if (BIT_SET(m->flags, i) && map[i])
3,157✔
981
                        if (!strextend_with_separator(&str, " ", map[i]))
204✔
982
                                return -ENOMEM;
983

984
        if (m->writable)
451✔
985
                if (!strextend_with_separator(&str, " ", "writable"))
16✔
986
                        return -ENOMEM;
987

988
        *ret = TAKE_PTR(str);
451✔
989
        return 0;
451✔
990
}
991

992
static int introspect(int argc, char **argv, void *userdata) {
6✔
993
        static const XMLIntrospectOps ops = {
6✔
994
                .on_interface = on_interface,
995
                .on_method = on_method,
996
                .on_signal = on_signal,
997
                .on_property = on_property,
998
        };
999

1000
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
6✔
1001
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_xml = NULL;
6✔
1002
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6✔
1003
        _cleanup_set_free_ Set *members = NULL;
6✔
1004
        Member *m;
6✔
1005
        const char *xml;
6✔
1006
        int r;
6✔
1007

1008
        r = acquire_bus(false, &bus);
6✔
1009
        if (r < 0)
6✔
1010
                return r;
1011

1012
        members = set_new(&member_hash_ops);
6✔
1013
        if (!members)
6✔
UNCOV
1014
                return log_oom();
×
1015

1016
        r = sd_bus_call_method(bus, argv[1], argv[2],
6✔
1017
                               "org.freedesktop.DBus.Introspectable", "Introspect",
1018
                               &error, &reply_xml, NULL);
1019
        if (r < 0) {
6✔
1020
                notify_bus_error(&error);
3✔
1021
                return log_error_errno(r, "Failed to introspect object %s of service %s: %s",
3✔
1022
                                       argv[2], argv[1], bus_error_message(&error, r));
1023
        }
1024

1025
        r = sd_bus_message_read(reply_xml, "s", &xml);
3✔
1026
        if (r < 0)
3✔
UNCOV
1027
                return bus_log_parse_error(r);
×
1028

1029
        if (arg_xml_interface) {
3✔
1030
                /* Just dump the received XML and finish */
1031
                pager_open(arg_pager_flags);
1✔
1032
                puts(xml);
1✔
1033
                return 0;
1034
        }
1035

1036
        /* First, get list of all properties */
1037
        r = parse_xml_introspect(argv[2], xml, &ops, members);
2✔
1038
        if (r < 0)
2✔
1039
                return r;
1040

1041
        /* Second, find the current values for them */
1042
        SET_FOREACH(m, members) {
464✔
1043
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
462✔
1044

1045
                if (!streq(m->type, "property"))
462✔
1046
                        continue;
212✔
1047

1048
                if (m->value)
250✔
1049
                        continue;
248✔
1050

1051
                if (argv[3] && !streq(argv[3], m->interface))
2✔
UNCOV
1052
                        continue;
×
1053

1054
                r = sd_bus_call_method(bus, argv[1], argv[2],
2✔
1055
                                       "org.freedesktop.DBus.Properties", "GetAll",
1056
                                       &error, &reply, "s", m->interface);
1057
                if (r < 0) {
2✔
UNCOV
1058
                        notify_bus_error(&error);
×
UNCOV
1059
                        return log_error_errno(r, "Failed to get all properties on interface %s: %s",
×
1060
                                               m->interface, bus_error_message(&error, r));
1061
                }
1062

1063
                r = sd_bus_message_enter_container(reply, 'a', "{sv}");
2✔
1064
                if (r < 0)
2✔
UNCOV
1065
                        return bus_log_parse_error(r);
×
1066

1067
                for (;;) {
250✔
UNCOV
1068
                        _cleanup_(memstream_done) MemStream ms = {};
×
1069
                        _cleanup_free_ char *buf = NULL;
252✔
1070
                        const char *name, *contents;
252✔
1071
                        Member *z;
252✔
1072
                        char type;
252✔
1073
                        FILE *mf;
252✔
1074

1075
                        r = sd_bus_message_enter_container(reply, 'e', "sv");
252✔
1076
                        if (r < 0)
252✔
UNCOV
1077
                                return bus_log_parse_error(r);
×
1078
                        if (r == 0)
252✔
1079
                                break;
1080

1081
                        r = sd_bus_message_read(reply, "s", &name);
250✔
1082
                        if (r < 0)
250✔
UNCOV
1083
                                return bus_log_parse_error(r);
×
1084

1085
                        r = sd_bus_message_peek_type(reply, &type, &contents);
250✔
1086
                        if (r < 0)
250✔
UNCOV
1087
                                return bus_log_parse_error(r);
×
1088
                        if (type != 'v')
250✔
1089
                                return bus_log_parse_error(EINVAL);
×
1090

1091
                        r = sd_bus_message_enter_container(reply, 'v', contents);
250✔
1092
                        if (r < 0)
250✔
UNCOV
1093
                                return bus_log_parse_error(r);
×
1094

1095
                        mf = memstream_init(&ms);
250✔
1096
                        if (!mf)
250✔
UNCOV
1097
                                return log_oom();
×
1098

1099
                        r = format_cmdline(reply, mf, false);
250✔
1100
                        if (r < 0)
250✔
UNCOV
1101
                                return bus_log_parse_error(r);
×
1102

1103
                        r = memstream_finalize(&ms, &buf, NULL);
250✔
1104
                        if (r < 0)
250✔
UNCOV
1105
                                return log_error_errno(r, "Failed to flush and close memstream: %m");
×
1106

1107
                        z = set_get(members, &((Member) {
500✔
1108
                                                .type = "property",
1109
                                                .interface = m->interface,
250✔
1110
                                                .signature = (char*) contents,
1111
                                                .name = (char*) name }));
1112
                        if (z)
250✔
1113
                                free_and_replace(z->value, buf);
250✔
1114

1115
                        r = sd_bus_message_exit_container(reply);
250✔
1116
                        if (r < 0)
250✔
UNCOV
1117
                                return bus_log_parse_error(r);
×
1118

1119
                        r = sd_bus_message_exit_container(reply);
250✔
1120
                        if (r < 0)
250✔
UNCOV
1121
                                return bus_log_parse_error(r);
×
1122
                }
1123

1124
                r = sd_bus_message_exit_container(reply);
2✔
1125
                if (r < 0)
2✔
UNCOV
1126
                        return bus_log_parse_error(r);
×
1127
        }
1128

1129
        size_t n;
2✔
1130
        _cleanup_free_ Member **sorted = NULL;
2✔
1131
        r = set_dump_sorted(members, (void***) &sorted, &n);
2✔
1132
        if (r < 0)
2✔
UNCOV
1133
                return log_oom();
×
1134

1135
        _cleanup_(table_unrefp) Table *table = table_new("name", "type", "signature", "result/value", "flags");
4✔
1136
        if (!table)
2✔
UNCOV
1137
                return log_oom();
×
1138

1139
        if (arg_full)
2✔
1140
                table_set_width(table, 0);
2✔
1141
        (void) table_set_maximum_width(table, table_get_cell(table, 0, 3), arg_full ? 100 : 40);
2✔
1142
        table_set_header(table, arg_legend);
2✔
1143
        table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
2✔
1144

1145
        FOREACH_ARRAY(p, sorted, n) {
464✔
1146
                bool is_interface;
462✔
1147

1148
                m = *p;
462✔
1149

1150
                if (argv[3] && !streq(argv[3], m->interface))
462✔
1151
                        continue;
11✔
1152

1153
                is_interface = streq(m->type, "interface");
452✔
1154

1155
                if (argv[3] && is_interface)
452✔
1156
                        continue;
1✔
1157

1158
                if (is_interface)
231✔
1159
                        r = table_add_many(
8✔
1160
                                        table,
1161
                                        TABLE_STRING, m->interface,
1162
                                        TABLE_SET_COLOR, ansi_highlight());
1163
                else
1164
                        r = table_add_cell_stringf(
447✔
1165
                                        table, /* ret_cell = */ NULL, ".%s", m->name);
1166
                if (r < 0)
451✔
UNCOV
1167
                        return table_log_add_error(r);
×
1168

1169
                _cleanup_free_ char *flags = NULL;
451✔
1170
                r = members_flags_to_string(m, &flags);
451✔
1171
                if (r < 0)
451✔
UNCOV
1172
                        return log_oom();
×
1173

1174
                r = table_add_many(
451✔
1175
                                table,
1176
                                TABLE_STRING, m->type,
1177
                                TABLE_STRING, m->signature,
1178
                                TABLE_STRING, m->value ?: m->result,
1179
                                TABLE_STRING, flags);
1180
                if (r < 0)
451✔
UNCOV
1181
                        return table_log_add_error(r);
×
1182
        }
1183

1184
        pager_open(arg_pager_flags);
2✔
1185

1186
        r = table_print(table, NULL);
2✔
1187
        if (r < 0)
2✔
UNCOV
1188
                return table_log_print_error(r);
×
1189

1190
        return 0;
1191
}
1192

UNCOV
1193
static int message_dump(sd_bus_message *m, FILE *f) {
×
UNCOV
1194
        int r;
×
1195

1196
        assert(m);
×
1197

UNCOV
1198
        r = sd_bus_message_dump(m, f, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
×
1199
        if (r < 0)
×
1200
                return log_error_errno(r, "Failed to dump DBus message: %m");
×
1201

1202
        return 0;
1203
}
1204

1205
static int message_pcap(sd_bus_message *m, FILE *f) {
×
1206
        int r;
×
1207

UNCOV
1208
        assert(m);
×
1209

1210
        r = bus_message_pcap_frame(m, arg_snaplen, f);
×
UNCOV
1211
        if (r < 0)
×
UNCOV
1212
                return log_error_errno(r, "Failed to dump DBus message in PCAP format: %m");
×
1213

1214
        return 0;
1215
}
1216

1217
static int message_json(sd_bus_message *m, FILE *f) {
×
1218
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
×
UNCOV
1219
        int r;
×
1220

UNCOV
1221
        assert(m);
×
1222

UNCOV
1223
        r = sd_bus_message_dump_json(m, SD_BUS_MESSAGE_DUMP_WITH_HEADER, &v);
×
UNCOV
1224
        if (r < 0)
×
UNCOV
1225
                return log_error_errno(r, "Failed to build JSON object from DBus message: %m");
×
1226

UNCOV
1227
        r = sd_json_variant_dump(v, arg_json_format_flags, f, NULL);
×
UNCOV
1228
        if (r < 0)
×
UNCOV
1229
                return log_error_errno(r, "Failed to show JSON object: %m");
×
1230

1231
        return 0;
1232
}
1233

1234
static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f)) {
2✔
1235
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2✔
1236
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
2✔
1237
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2✔
1238
        uint32_t flags = 0;
2✔
1239
        const char *unique_name;
2✔
1240
        bool is_monitor = false;
2✔
1241
        int r;
2✔
1242

1243
        r = acquire_bus(true, &bus);
2✔
1244
        if (r < 0)
2✔
1245
                return r;
1246

1247
        usec_t end = arg_timeout > 0 ?
2✔
1248
                usec_add(now(CLOCK_MONOTONIC), arg_timeout) : USEC_INFINITY;
2✔
1249

1250
        /* upgrade connection; it's not used for anything else after this call */
1251
        r = sd_bus_message_new_method_call(bus,
2✔
1252
                                           &message,
1253
                                           "org.freedesktop.DBus",
1254
                                           "/org/freedesktop/DBus",
1255
                                           "org.freedesktop.DBus.Monitoring",
1256
                                           "BecomeMonitor");
1257
        if (r < 0)
2✔
UNCOV
1258
                return bus_log_create_error(r);
×
1259

1260
        r = sd_bus_message_open_container(message, 'a', "s");
2✔
1261
        if (r < 0)
2✔
UNCOV
1262
                return bus_log_create_error(r);
×
1263

1264
        STRV_FOREACH(i, argv+1) {
2✔
UNCOV
1265
                _cleanup_free_ char *m = NULL;
×
1266

UNCOV
1267
                if (!sd_bus_service_name_is_valid(*i))
×
UNCOV
1268
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name '%s'", *i);
×
1269

UNCOV
1270
                m = strjoin("sender='", *i, "'");
×
UNCOV
1271
                if (!m)
×
UNCOV
1272
                        return log_oom();
×
1273

UNCOV
1274
                r = sd_bus_message_append_basic(message, 's', m);
×
UNCOV
1275
                if (r < 0)
×
1276
                        return bus_log_create_error(r);
×
1277

1278
                free(m);
×
1279
                m = strjoin("destination='", *i, "'");
×
UNCOV
1280
                if (!m)
×
1281
                        return log_oom();
×
1282

1283
                r = sd_bus_message_append_basic(message, 's', m);
×
UNCOV
1284
                if (r < 0)
×
1285
                        return bus_log_create_error(r);
×
1286
        }
1287

1288
        STRV_FOREACH(i, arg_matches) {
4✔
1289
                r = sd_bus_message_append_basic(message, 's', *i);
2✔
1290
                if (r < 0)
2✔
1291
                        return bus_log_create_error(r);
×
1292
        }
1293

1294
        r = sd_bus_message_close_container(message);
2✔
1295
        if (r < 0)
2✔
1296
                return bus_log_create_error(r);
×
1297

1298
        r = sd_bus_message_append_basic(message, 'u', &flags);
2✔
1299
        if (r < 0)
2✔
UNCOV
1300
                return bus_log_create_error(r);
×
1301

1302
        r = sd_bus_call(bus, message, arg_timeout, &error, NULL);
2✔
1303
        if (r < 0) {
2✔
UNCOV
1304
                notify_bus_error(&error);
×
UNCOV
1305
                return log_error_errno(r, "Call to org.freedesktop.DBus.Monitoring.BecomeMonitor failed: %s",
×
1306
                                       bus_error_message(&error, r));
1307
        }
1308

1309
        r = sd_bus_get_unique_name(bus, &unique_name);
2✔
1310
        if (r < 0)
2✔
1311
                return log_error_errno(r, "Failed to get unique name: %m");
×
1312

1313
        if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
2✔
UNCOV
1314
                log_info("Monitoring bus message stream.");
×
1315

1316
        (void) sd_notify(/* unset_environment=false */ false, "READY=1");
2✔
1317

1318
        for (;;) {
6✔
1319
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
6✔
1320

1321
                r = sd_bus_process(bus, &m);
6✔
1322
                if (r < 0)
6✔
UNCOV
1323
                        return log_error_errno(r, "Failed to process bus: %m");
×
1324

1325
                if (m) {
6✔
1326
                        if (!is_monitor) {
4✔
1327
                                const char *name;
4✔
1328

1329
                                /* wait until we lose our unique name */
1330
                                if (sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameLost") <= 0)
4✔
1331
                                        continue;
4✔
1332

1333
                                r = sd_bus_message_read(m, "s", &name);
2✔
1334
                                if (r < 0)
2✔
UNCOV
1335
                                        return bus_log_parse_error(r);
×
1336

1337
                                if (streq(name, unique_name))
2✔
1338
                                        is_monitor = true;
2✔
1339

1340
                                continue;
2✔
1341
                        }
1342

UNCOV
1343
                        dump(m, stdout);
×
UNCOV
1344
                        fflush(stdout);
×
1345

1346
                        if (arg_limit_messages != UINT64_MAX) {
×
UNCOV
1347
                                arg_limit_messages--;
×
1348

UNCOV
1349
                                if (arg_limit_messages == 0) {
×
UNCOV
1350
                                        if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
×
UNCOV
1351
                                                log_info("Received requested maximum number of messages, exiting.");
×
UNCOV
1352
                                        return 0;
×
1353
                                }
1354
                        }
1355

UNCOV
1356
                        if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
×
1357
                                if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
×
1358
                                        log_info("Connection terminated, exiting.");
×
UNCOV
1359
                                return 0;
×
1360
                        }
1361

1362
                        continue;
×
1363
                }
1364

1365
                if (r > 0)
2✔
UNCOV
1366
                        continue;
×
1367

1368
                r = sd_bus_wait(bus, arg_timeout > 0 ? usec_sub_unsigned(end, now(CLOCK_MONOTONIC)) : UINT64_MAX);
4✔
1369
                if (r == 0 && arg_timeout > 0 && now(CLOCK_MONOTONIC) >= end) {
2✔
1370
                        if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
2✔
UNCOV
1371
                                log_info("Timed out waiting for messages, exiting.");
×
1372
                        return 0;
2✔
1373
                }
UNCOV
1374
                if (r < 0)
×
UNCOV
1375
                        return log_error_errno(r, "Failed to wait for bus: %m");
×
1376
        }
1377
}
1378

1379
static int verb_monitor(int argc, char **argv, void *userdata) {
2✔
1380
        return monitor(argc, argv, sd_json_format_enabled(arg_json_format_flags) ? message_json : message_dump);
4✔
1381
}
1382

UNCOV
1383
static int verb_capture(int argc, char **argv, void *userdata) {
×
UNCOV
1384
        _cleanup_free_ char *osname = NULL;
×
1385
        static const char info[] =
×
1386
                "busctl (systemd) " PROJECT_VERSION_FULL " (Git " GIT_VERSION ")";
UNCOV
1387
        int r;
×
1388

UNCOV
1389
        if (isatty_safe(STDOUT_FILENO))
×
UNCOV
1390
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1391
                                       "Refusing to write message data to console, please redirect output to a file.");
1392

UNCOV
1393
        r = parse_os_release(NULL, "PRETTY_NAME", &osname);
×
1394
        if (r < 0)
×
1395
                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_INFO, r,
×
1396
                               "Failed to read os-release file, ignoring: %m");
UNCOV
1397
        bus_pcap_header(arg_snaplen, osname, info, stdout);
×
1398

UNCOV
1399
        r = monitor(argc, argv, message_pcap);
×
1400
        if (r < 0)
×
1401
                return r;
1402

UNCOV
1403
        r = fflush_and_check(stdout);
×
1404
        if (r < 0)
×
1405
                return log_error_errno(r, "Couldn't write capture file: %m");
×
1406

1407
        return r;
1408
}
1409

1410
static int status(int argc, char **argv, void *userdata) {
5✔
1411
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
5✔
1412
        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
5✔
1413
        pid_t pid;
5✔
1414
        int r;
5✔
1415

1416
        r = acquire_bus(false, &bus);
5✔
1417
        if (r < 0)
5✔
1418
                return r;
1419

1420
        pager_open(arg_pager_flags);
5✔
1421

1422
        if (!isempty(argv[1])) {
5✔
1423
                r = parse_pid(argv[1], &pid);
2✔
1424
                if (r < 0)
2✔
1425
                        r = sd_bus_get_name_creds(
2✔
1426
                                        bus,
1427
                                        argv[1],
1428
                                        (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
2✔
1429
                                        &creds);
1430
                else
UNCOV
1431
                        r = sd_bus_creds_new_from_pid(
×
1432
                                        &creds,
1433
                                        pid,
1434
                                        _SD_BUS_CREDS_ALL);
1435
        } else {
1436
                const char *scope, *address;
3✔
1437
                sd_id128_t bus_id;
3✔
1438

1439
                r = sd_bus_get_address(bus, &address);
3✔
1440
                if (r >= 0)
3✔
1441
                        printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal());
9✔
1442

1443
                r = sd_bus_get_scope(bus, &scope);
3✔
1444
                if (r >= 0)
3✔
1445
                        printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal());
3✔
1446

1447
                r = sd_bus_get_bus_id(bus, &bus_id);
3✔
1448
                if (r >= 0)
3✔
1449
                        printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n",
6✔
1450
                               ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal());
3✔
1451

1452
                r = sd_bus_get_owner_creds(
3✔
1453
                                bus,
1454
                                (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
3✔
1455
                                &creds);
1456
        }
1457

1458
        if (r < 0)
5✔
1459
                return log_error_errno(r, "Failed to get credentials: %m");
1✔
1460

1461
        bus_creds_dump(creds, NULL, false);
4✔
1462
        return 0;
1463
}
1464

1465
static int message_append_cmdline(sd_bus_message *m, const char *signature, FDSet **passed_fdset, char ***x) {
1,149✔
1466
        char **p;
1,149✔
1467
        int r;
1,149✔
1468

1469
        assert(m);
1,149✔
1470
        assert(signature);
1,149✔
1471
        assert(passed_fdset);
1,149✔
1472
        assert(x);
1,149✔
1473

1474
        p = *x;
1,149✔
1475

1476
        for (;;) {
2,363✔
1477
                const char *v;
2,363✔
1478
                char t;
2,363✔
1479

1480
                t = *signature;
2,363✔
1481
                v = *p;
2,363✔
1482

1483
                if (t == 0)
2,363✔
1484
                        break;
1485
                if (!v)
1,219✔
1486
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1✔
1487
                                               "Too few parameters for signature.");
1488

1489
                signature++;
1,218✔
1490
                p++;
1,218✔
1491

1492
                switch (t) {
1,218✔
1493

1494
                case SD_BUS_TYPE_BOOLEAN:
12✔
1495

1496
                        r = parse_boolean(v);
12✔
1497
                        if (r < 0)
12✔
UNCOV
1498
                                return log_error_errno(r, "Failed to parse '%s' as boolean: %m", v);
×
1499

1500
                        r = sd_bus_message_append_basic(m, t, &r);
12✔
1501
                        break;
12✔
1502

1503
                case SD_BUS_TYPE_BYTE: {
UNCOV
1504
                        uint8_t z;
×
1505

UNCOV
1506
                        r = safe_atou8(v, &z);
×
UNCOV
1507
                        if (r < 0)
×
UNCOV
1508
                                return log_error_errno(r, "Failed to parse '%s' as byte (unsigned 8-bit integer): %m", v);
×
1509

UNCOV
1510
                        r = sd_bus_message_append_basic(m, t, &z);
×
UNCOV
1511
                        break;
×
1512
                }
1513

UNCOV
1514
                case SD_BUS_TYPE_INT16: {
×
1515
                        int16_t z;
×
1516

1517
                        r = safe_atoi16(v, &z);
×
1518
                        if (r < 0)
×
1519
                                return log_error_errno(r, "Failed to parse '%s' as signed 16-bit integer: %m", v);
×
1520

1521
                        r = sd_bus_message_append_basic(m, t, &z);
×
1522
                        break;
×
1523
                }
1524

1525
                case SD_BUS_TYPE_UINT16: {
1526
                        uint16_t z;
×
1527

1528
                        r = safe_atou16(v, &z);
×
1529
                        if (r < 0)
×
1530
                                return log_error_errno(r, "Failed to parse '%s' as unsigned 16-bit integer: %m", v);
×
1531

1532
                        r = sd_bus_message_append_basic(m, t, &z);
×
1533
                        break;
×
1534
                }
1535

1536
                case SD_BUS_TYPE_INT32: {
1537
                        int32_t z;
2✔
1538

1539
                        r = safe_atoi32(v, &z);
2✔
1540
                        if (r < 0)
2✔
1541
                                return log_error_errno(r, "Failed to parse '%s' as signed 32-bit integer: %m", v);
×
1542

1543
                        r = sd_bus_message_append_basic(m, t, &z);
2✔
1544
                        break;
2✔
1545
                }
1546

1547
                case SD_BUS_TYPE_UINT32: {
1548
                        uint32_t z;
1,003✔
1549

1550
                        r = safe_atou32(v, &z);
1,003✔
1551
                        if (r < 0)
1,003✔
1552
                                return log_error_errno(r, "Failed to parse '%s' as unsigned 32-bit integer: %m", v);
1✔
1553

1554
                        r = sd_bus_message_append_basic(m, t, &z);
1,002✔
1555
                        break;
1,002✔
1556
                }
1557

1558
                case SD_BUS_TYPE_INT64: {
UNCOV
1559
                        int64_t z;
×
1560

UNCOV
1561
                        r = safe_atoi64(v, &z);
×
UNCOV
1562
                        if (r < 0)
×
UNCOV
1563
                                return log_error_errno(r, "Failed to parse '%s' as signed 64-bit integer: %m", v);
×
1564

UNCOV
1565
                        r = sd_bus_message_append_basic(m, t, &z);
×
UNCOV
1566
                        break;
×
1567
                }
1568

1569
                case SD_BUS_TYPE_UINT64: {
1570
                        uint64_t z;
8✔
1571

1572
                        r = safe_atou64(v, &z);
8✔
1573
                        if (r < 0)
8✔
1574
                                return log_error_errno(r, "Failed to parse '%s' as unsigned 64-bit integer: %m", v);
1✔
1575

1576
                        r = sd_bus_message_append_basic(m, t, &z);
7✔
1577
                        break;
7✔
1578
                }
1579

UNCOV
1580
                case SD_BUS_TYPE_DOUBLE: {
×
UNCOV
1581
                        double z;
×
1582

UNCOV
1583
                        r = safe_atod(v, &z);
×
UNCOV
1584
                        if (r < 0)
×
UNCOV
1585
                                return log_error_errno(r, "Failed to parse '%s' as double precision floating point: %m", v);
×
1586

UNCOV
1587
                        r = sd_bus_message_append_basic(m, t, &z);
×
UNCOV
1588
                        break;
×
1589
                }
1590

1591
                case SD_BUS_TYPE_STRING:
113✔
1592
                case SD_BUS_TYPE_OBJECT_PATH:
1593
                case SD_BUS_TYPE_SIGNATURE:
1594

1595
                        r = sd_bus_message_append_basic(m, t, v);
113✔
1596
                        break;
113✔
1597

1598
                case SD_BUS_TYPE_ARRAY: {
1599
                        uint32_t n;
38✔
1600
                        size_t k;
38✔
1601

1602
                        r = safe_atou32(v, &n);
38✔
1603
                        if (r < 0)
38✔
1604
                                return log_error_errno(r, "Failed to parse '%s' number of array entries: %m", v);
2✔
1605

1606
                        r = signature_element_length(signature, &k);
37✔
1607
                        if (r < 0)
37✔
UNCOV
1608
                                return log_error_errno(r, "Invalid array signature: %m");
×
1609

1610
                        {
37✔
1611
                                char s[k + 1];
37✔
1612
                                memcpy(s, signature, k);
37✔
1613
                                s[k] = 0;
37✔
1614

1615
                                r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
37✔
1616
                                if (r < 0)
37✔
1617
                                        return bus_log_create_error(r);
1✔
1618

1619
                                for (unsigned i = 0; i < n; i++) {
82✔
1620
                                        r = message_append_cmdline(m, s, passed_fdset, &p);
46✔
1621
                                        if (r < 0)
46✔
1622
                                                return r;
1623
                                }
1624
                        }
1625

1626
                        signature += k;
36✔
1627

1628
                        r = sd_bus_message_close_container(m);
36✔
1629
                        break;
36✔
1630
                }
1631

1632
                case SD_BUS_TYPE_VARIANT:
16✔
1633
                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
16✔
1634
                        if (r < 0)
16✔
UNCOV
1635
                                return bus_log_create_error(r);
×
1636

1637
                        r = message_append_cmdline(m, v, passed_fdset, &p);
16✔
1638
                        if (r < 0)
16✔
1639
                                return r;
1640

1641
                        r = sd_bus_message_close_container(m);
16✔
1642
                        break;
16✔
1643

1644
                case SD_BUS_TYPE_STRUCT_BEGIN:
24✔
1645
                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1646
                        size_t k;
24✔
1647

1648
                        signature--;
24✔
1649
                        p--;
24✔
1650

1651
                        r = signature_element_length(signature, &k);
24✔
1652
                        if (r < 0 || k < 2) {
24✔
UNCOV
1653
                                if (r >= 0 && k < 2)
×
UNCOV
1654
                                        r = -ERANGE;
×
UNCOV
1655
                                return log_error_errno(r, "Invalid struct/dict entry signature: %m");
×
1656
                        }
1657

1658
                        {
24✔
1659
                                char s[k-1];
24✔
1660
                                memcpy(s, signature + 1, k - 2);
24✔
1661
                                s[k - 2] = 0;
24✔
1662

1663
                                const char ctype = t == SD_BUS_TYPE_STRUCT_BEGIN ?
24✔
1664
                                        SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
1665
                                r = sd_bus_message_open_container(m, ctype, s);
24✔
1666
                                if (r < 0)
24✔
UNCOV
1667
                                        return bus_log_create_error(r);
×
1668

1669
                                r = message_append_cmdline(m, s, passed_fdset, &p);
24✔
1670
                                if (r < 0)
24✔
1671
                                        return r;
1672
                        }
1673

1674
                        signature += k;
24✔
1675

1676
                        r = sd_bus_message_close_container(m);
24✔
1677
                        break;
24✔
1678
                }
1679

1680
                case SD_BUS_TYPE_UNIX_FD: {
2✔
1681
                        int fd;
2✔
1682

1683
                        fd = parse_fd(v);
2✔
1684
                        if (fd < 0)
2✔
UNCOV
1685
                                return log_error_errno(fd, "Failed to parse '%s' as a file descriptor: %m", v);
×
1686

1687
                        if (!*passed_fdset) {
2✔
1688
                                r = fdset_new_fill(/* filter_cloexec= */ 0, passed_fdset);
1✔
1689
                                if (r < 0)
1✔
UNCOV
1690
                                        return log_error_errno(r, "Failed to create fd set: %m");
×
1691
                        }
1692

1693
                        if (!fdset_contains(*passed_fdset, fd))
2✔
UNCOV
1694
                                return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Failed to find file descriptor '%s' among passed file descriptors.", v);
×
1695

1696
                        r = sd_bus_message_append_basic(m, t, &fd);
2✔
1697
                        break;
2✔
1698
                }
1699

1700
                default:
1701
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1702
                                               "Unknown signature type %c.", t);
1703
                }
1704

1705
                if (r < 0)
1,214✔
UNCOV
1706
                        return bus_log_create_error(r);
×
1707
        }
1708

1709
        *x = p;
1,144✔
1710
        return 0;
1,144✔
1711
}
1712

1713
static int bus_message_dump(sd_bus_message *m, uint64_t flags) {
113✔
1714
        const char *contents;
113✔
1715
        int r;
113✔
1716

1717
        assert(m);
113✔
1718

1719
        r = sd_bus_message_rewind(m, !FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY));
113✔
1720
        if (r < 0)
113✔
1721
                return log_error_errno(r, "Failed to rewind: %m");
113✔
1722

1723
        if (FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
113✔
1724
                r = sd_bus_message_peek_type(m, /* ret_type = */ NULL, &contents);
55✔
1725
                if (r < 0)
55✔
UNCOV
1726
                        return bus_log_parse_error(r);
×
1727

1728
                r = sd_bus_message_enter_container(m, 'v', contents);
55✔
1729
                if (r < 0)
55✔
UNCOV
1730
                        return bus_log_parse_error(r);
×
1731
        } else {
1732
                r = sd_bus_message_is_empty(m);
58✔
1733
                if (r < 0)
58✔
UNCOV
1734
                        return bus_log_parse_error(r);
×
1735
                if (r > 0 || arg_quiet)
58✔
1736
                        return 0;
1737
        }
1738

1739
        if (sd_json_format_enabled(arg_json_format_flags)) {
112✔
1740
                _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
17✔
1741

1742
                if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
17✔
1743
                        pager_open(arg_pager_flags);
8✔
1744

1745
                r = sd_bus_message_dump_json(m, flags, &v);
17✔
1746
                if (r < 0)
17✔
UNCOV
1747
                        return log_error_errno(r, "Failed to dump DBus message to JSON object: %m");
×
1748

1749
                r = sd_json_variant_dump(v, arg_json_format_flags, NULL, NULL);
17✔
1750
                if (r < 0)
17✔
UNCOV
1751
                        return log_error_errno(r, "Failed to dump JSON object: %m");
×
1752

1753
        } else if (arg_verbose) {
95✔
1754
                pager_open(arg_pager_flags);
5✔
1755

1756
                r = sd_bus_message_dump(m, NULL, flags);
5✔
1757
                if (r < 0)
5✔
1758
                        return log_error_errno(r, "Failed to dump DBus message: %m");
×
1759
        } else {
1760

1761
                fputs(FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY) ? contents : sd_bus_message_get_signature(m, true), stdout);
90✔
1762
                fputc(' ', stdout);
90✔
1763

1764
                r = format_cmdline(m, stdout, /* needs_space = */ false);
90✔
1765
                if (r < 0)
90✔
UNCOV
1766
                        return bus_log_parse_error(r);
×
1767

1768
                fputc('\n', stdout);
90✔
1769
        }
1770

1771
        if (FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
112✔
1772
                r = sd_bus_message_exit_container(m);
55✔
1773
                if (r < 0)
55✔
UNCOV
1774
                        return bus_log_parse_error(r);
×
1775
        }
1776

1777
        return 0;
1778
}
1779

1780
static int call(int argc, char **argv, void *userdata) {
1,065✔
1781
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1,065✔
UNCOV
1782
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
1783
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
2,130✔
1784
        _cleanup_fdset_free_ FDSet *passed_fdset = NULL;
1,065✔
1785
        int r;
1,065✔
1786

1787
        r = acquire_bus(false, &bus);
1,065✔
1788
        if (r < 0)
1,065✔
1789
                return r;
1790

1791
        if (!service_name_is_valid(argv[1]))
1,065✔
UNCOV
1792
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]);
×
1793
        if (!object_path_is_valid(argv[2]))
1,065✔
UNCOV
1794
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]);
×
1795
        if (!interface_name_is_valid(argv[3]))
1,065✔
UNCOV
1796
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]);
×
1797
        if (!member_name_is_valid(argv[4]))
1,065✔
UNCOV
1798
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid member name: %s", argv[4]);
×
1799

1800
        r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1,065✔
1801
        if (r < 0)
1,065✔
UNCOV
1802
                return bus_log_create_error(r);
×
1803

1804
        r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1,065✔
1805
        if (r < 0)
1,065✔
UNCOV
1806
                return bus_log_create_error(r);
×
1807

1808
        r = sd_bus_message_set_auto_start(m, arg_auto_start);
1,065✔
1809
        if (r < 0)
1,065✔
UNCOV
1810
                return bus_log_create_error(r);
×
1811

1812
        r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1,065✔
1813
        if (r < 0)
1,065✔
1814
                return bus_log_create_error(r);
×
1815

1816
        if (!isempty(argv[5])) {
1,065✔
1817
                char **p;
1,056✔
1818

1819
                p = argv+6;
1,056✔
1820

1821
                r = message_append_cmdline(m, argv[5], &passed_fdset, &p);
1,056✔
1822
                if (r < 0)
1,056✔
1823
                        return r;
3✔
1824

1825
                if (*p)
1,053✔
UNCOV
1826
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1827
                                               "Too many parameters for signature.");
1828
        }
1829

1830
        if (!arg_expect_reply) {
1,062✔
UNCOV
1831
                r = sd_bus_send(bus, m, NULL);
×
UNCOV
1832
                if (r < 0)
×
UNCOV
1833
                        return log_error_errno(r, "Failed to send message: %m");
×
1834

1835
                return 0;
1836
        }
1837

1838
        r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1,062✔
1839
        if (r < 0) {
1,062✔
1840
                notify_bus_error(&error);
1,005✔
1841
                return log_error_errno(r, "Call failed: %s", bus_error_message(&error, r));
1,005✔
1842
        }
1843

1844
        return bus_message_dump(reply, /* flags = */ 0);
57✔
1845
}
1846

1847
static int emit_signal(int argc, char **argv, void *userdata) {
3✔
1848
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
3✔
1849
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
3✔
1850
        _cleanup_fdset_free_ FDSet *passed_fdset = NULL;
3✔
1851
        int r;
3✔
1852

1853
        r = acquire_bus(false, &bus);
3✔
1854
        if (r < 0)
3✔
1855
                return r;
1856

1857
        r = sd_bus_message_new_signal(bus, &m, argv[1], argv[2], argv[3]);
3✔
1858
        if (r < 0)
3✔
UNCOV
1859
                return bus_log_create_error(r);
×
1860

1861
        if (arg_destination) {
3✔
1862
                r = sd_bus_message_set_destination(m, arg_destination);
1✔
1863
                if (r < 0)
1✔
UNCOV
1864
                        return bus_log_create_error(r);
×
1865
        }
1866

1867
        r = sd_bus_message_set_auto_start(m, arg_auto_start);
3✔
1868
        if (r < 0)
3✔
1869
                return bus_log_create_error(r);
×
1870

1871
        if (!isempty(argv[4])) {
3✔
1872
                char **p;
3✔
1873

1874
                p = argv+5;
3✔
1875

1876
                r = message_append_cmdline(m, argv[4], &passed_fdset, &p);
3✔
1877
                if (r < 0)
3✔
UNCOV
1878
                        return r;
×
1879

1880
                if (*p)
3✔
UNCOV
1881
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1882
                                               "Too many parameters for signature.");
1883
        }
1884

1885
        r = sd_bus_send(bus, m, NULL);
3✔
1886
        if (r < 0)
3✔
1887
                return log_error_errno(r, "Failed to send signal: %m");
×
1888

1889
        return 0;
1890
}
1891

1892
static int get_property(int argc, char **argv, void *userdata) {
50✔
1893
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
50✔
1894
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
50✔
1895
        int r;
50✔
1896

1897
        if (!service_name_is_valid(argv[1]))
50✔
1898
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]);
1✔
1899
        if (!object_path_is_valid(argv[2]))
49✔
1900
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]);
1✔
1901
        if (!interface_name_is_valid(argv[3]))
48✔
1902
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]);
1✔
1903

1904
        r = acquire_bus(false, &bus);
47✔
1905
        if (r < 0)
47✔
1906
                return r;
1907

1908
        STRV_FOREACH(i, argv + 4) {
102✔
1909
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
57✔
1910

1911
                r = sd_bus_call_method(bus, argv[1], argv[2],
57✔
1912
                                       "org.freedesktop.DBus.Properties", "Get",
1913
                                       &error, &reply, "ss", argv[3], *i);
1914
                if (r < 0) {
57✔
1915
                        notify_bus_error(&error);
2✔
1916
                        return log_error_errno(r, "Failed to get property %s on interface %s: %s",
2✔
1917
                                               *i, argv[3],
1918
                                               bus_error_message(&error, r));
1919
                }
1920

1921
                r = bus_message_dump(reply, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY);
55✔
1922
                if (r < 0)
55✔
1923
                        return r;
1924
        }
1925

1926
        return 0;
1927
}
1928

1929
static int on_bus_signal(sd_bus_message *msg, void *userdata, sd_bus_error *ret_error) {
1✔
1930
        return sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(ASSERT_PTR(msg))),
1✔
1931
                             bus_message_dump(msg, /* flags = */ 0));
1932
}
1933

1934
static int wait_signal(int argc, char **argv, void *userdata) {
1✔
1935
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1✔
1936
        _cleanup_(sd_event_unrefp) sd_event *e = NULL;
1✔
1937
        _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
1✔
1938
        int argn = 1, r;
1✔
1939

1940
        const char *sender = argc == 5 ? argv[argn++] : NULL;
1✔
1941
        const char *path = argv[argn++];
1✔
1942
        const char *interface = argv[argn++];
1✔
1943
        const char *member = argv[argn++];
1✔
1944

1945
        if (sender && !service_name_is_valid(sender))
1✔
UNCOV
1946
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", sender);
×
1947
        if (!object_path_is_valid(path))
1✔
1948
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", path);
×
1949
        if (!interface_name_is_valid(interface))
1✔
UNCOV
1950
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", interface);
×
1951
        if (!member_name_is_valid(member))
1✔
1952
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid member name: %s", member);
×
1953

1954
        r = acquire_bus(/* set_monitor= */ false, &bus);
1✔
1955
        if (r < 0)
1✔
1956
                return r;
1957

1958
        r = sd_bus_match_signal(bus, NULL, sender, path, interface, member, on_bus_signal, NULL);
1✔
1959
        if (r < 0)
1✔
UNCOV
1960
                return log_error_errno(r, "Failed to match signal %s on interface %s: %m", member, interface);
×
1961

1962
        r = sd_event_new(&e);
1✔
1963
        if (r < 0)
1✔
UNCOV
1964
                return log_error_errno(r, "Failed to allocate event loop: %m\n");
×
1965

1966
        r = sd_bus_attach_event(bus, e, SD_EVENT_PRIORITY_NORMAL);
1✔
1967
        if (r < 0)
1✔
UNCOV
1968
                return log_error_errno(r, "Failed to attach bus event: %m\n");
×
1969

1970
        if (arg_timeout) {
1✔
1971
                r = sd_event_add_time_relative(e, &timer, CLOCK_MONOTONIC, arg_timeout, 0, NULL, NULL);
1✔
1972
                if (r < 0)
1✔
UNCOV
1973
                        return log_error_errno(r, "Failed to schedule timeout: %m\n");
×
1974
        }
1975

1976
        /* The match is installed and we're ready to observe the signal */
1977
        sd_notify(/* unset_environment= */ false, "READY=1");
1✔
1978

1979
        return sd_event_loop(e);
1✔
1980
}
1981

1982
static int set_property(int argc, char **argv, void *userdata) {
4✔
1983
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
4✔
1984
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
4✔
1985
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4✔
1986
        _cleanup_fdset_free_ FDSet *passed_fdset = NULL;
4✔
1987
        char **p;
4✔
1988
        int r;
4✔
1989

1990
        if (!service_name_is_valid(argv[1]))
4✔
UNCOV
1991
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]);
×
1992
        if (!object_path_is_valid(argv[2]))
4✔
UNCOV
1993
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]);
×
1994
        if (!interface_name_is_valid(argv[3]))
4✔
UNCOV
1995
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]);
×
1996

1997
        r = acquire_bus(false, &bus);
4✔
1998
        if (r < 0)
4✔
1999
                return r;
2000

2001
        r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2],
4✔
2002
                                           "org.freedesktop.DBus.Properties", "Set");
2003
        if (r < 0)
4✔
UNCOV
2004
                return bus_log_create_error(r);
×
2005

2006
        r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
4✔
2007
        if (r < 0)
4✔
UNCOV
2008
                return bus_log_create_error(r);
×
2009

2010
        r = sd_bus_message_open_container(m, 'v', argv[5]);
4✔
2011
        if (r < 0)
4✔
UNCOV
2012
                return bus_log_create_error(r);
×
2013

2014
        p = argv + 6;
4✔
2015
        r = message_append_cmdline(m, argv[5], &passed_fdset, &p);
4✔
2016
        if (r < 0)
4✔
2017
                return r;
2018

2019
        r = sd_bus_message_close_container(m);
3✔
2020
        if (r < 0)
3✔
UNCOV
2021
                return bus_log_create_error(r);
×
2022

2023
        if (*p)
3✔
UNCOV
2024
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
×
2025

2026
        r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
3✔
2027
        if (r < 0) {
3✔
2028
                notify_bus_error(&error);
2✔
2029
                return log_error_errno(r, "Failed to set property %s on interface %s: %s",
2✔
2030
                                       argv[4], argv[3],
2031
                                       bus_error_message(&error, r));
2032
        }
2033

2034
        return 0;
2035
}
2036

2037
static int help(void) {
2✔
2038
        _cleanup_free_ char *link = NULL;
2✔
2039
        int r;
2✔
2040

2041
        r = terminal_urlify_man("busctl", "1", &link);
2✔
2042
        if (r < 0)
2✔
2043
                return log_oom();
×
2044

2045
        pager_open(arg_pager_flags);
2✔
2046

2047
        printf("%1$s [OPTIONS...] COMMAND ...\n\n"
4✔
2048
               "%5$sIntrospect the D-Bus IPC bus.%6$s\n"
2049
               "\n%3$sCommands%4$s:\n"
2050
               "  list                     List bus names\n"
2051
               "  status [SERVICE]         Show bus service, process or bus owner credentials\n"
2052
               "  monitor [SERVICE...]     Show bus traffic\n"
2053
               "  capture [SERVICE...]     Capture bus traffic as pcap\n"
2054
               "  tree [SERVICE...]        Show object tree of service\n"
2055
               "  introspect SERVICE OBJECT [INTERFACE]\n"
2056
               "  call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
2057
               "                           Call a method\n"
2058
               "  emit OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT...]]\n"
2059
               "                           Emit a signal\n"
2060
               "  wait OBJECT INTERFACE SIGNAL\n"
2061
               "                           Wait for a signal\n"
2062
               "  get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
2063
               "                           Get property value\n"
2064
               "  set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
2065
               "                           Set property value\n"
2066
               "  help                     Show this help\n"
2067
               "\n%3$sOptions:%4$s\n"
2068
               "  -h --help                Show this help\n"
2069
               "     --version             Show package version\n"
2070
               "     --no-pager            Do not pipe output into a pager\n"
2071
               "     --no-legend           Do not show the headers and footers\n"
2072
               "  -l --full                Do not ellipsize output\n"
2073
               "     --system              Connect to system bus\n"
2074
               "     --user                Connect to user bus\n"
2075
               "  -H --host=[USER@]HOST    Operate on remote host\n"
2076
               "  -M --machine=CONTAINER   Operate on local container\n"
2077
               "     --address=ADDRESS     Connect to bus specified by address\n"
2078
               "     --show-machine        Show machine ID column in list\n"
2079
               "     --unique              Only show unique names\n"
2080
               "     --acquired            Only show acquired names\n"
2081
               "     --activatable         Only show activatable names\n"
2082
               "     --match=MATCH         Only show matching messages\n"
2083
               "     --size=SIZE           Maximum length of captured packet\n"
2084
               "     --list                Don't show tree, but simple object path list\n"
2085
               "  -q --quiet               Don't show method call reply\n"
2086
               "     --verbose             Show result values in long format\n"
2087
               "     --json=MODE           Output as JSON\n"
2088
               "  -j                       Same as --json=pretty on tty, --json=short otherwise\n"
2089
               "     --xml-interface       Dump the XML description in introspect command\n"
2090
               "     --expect-reply=BOOL   Expect a method call reply\n"
2091
               "     --auto-start=BOOL     Auto-start destination service\n"
2092
               "     --allow-interactive-authorization=BOOL\n"
2093
               "                           Allow interactive authorization for operation\n"
2094
               "     --timeout=SECS        Maximum time to wait for method call completion\n"
2095
               "     --augment-creds=BOOL  Extend credential data with data read from /proc/$PID\n"
2096
               "     --watch-bind=BOOL     Wait for bus AF_UNIX socket to be bound in the file\n"
2097
               "                           system\n"
2098
               "     --destination=SERVICE Destination service of a signal\n"
2099
               "  -N --limit-messages=NUMBER\n"
2100
               "                           Stop monitoring after receiving the specified number\n"
2101
               "                           of messages\n"
2102
               "\nSee the %2$s for details.\n",
2103
               program_invocation_short_name,
2104
               link,
2105
               ansi_underline(),
2106
               ansi_normal(),
2107
               ansi_highlight(),
2108
               ansi_normal());
2109

2110
        return 0;
2111
}
2112

2113
static int verb_help(int argc, char **argv, void *userdata) {
1✔
2114
        return help();
1✔
2115
}
2116

2117
static int parse_argv(int argc, char *argv[]) {
1,156✔
2118

2119
        enum {
1,156✔
2120
                ARG_VERSION = 0x100,
2121
                ARG_NO_PAGER,
2122
                ARG_NO_LEGEND,
2123
                ARG_SYSTEM,
2124
                ARG_USER,
2125
                ARG_ADDRESS,
2126
                ARG_MATCH,
2127
                ARG_SHOW_MACHINE,
2128
                ARG_UNIQUE,
2129
                ARG_ACQUIRED,
2130
                ARG_ACTIVATABLE,
2131
                ARG_SIZE,
2132
                ARG_LIST,
2133
                ARG_VERBOSE,
2134
                ARG_XML_INTERFACE,
2135
                ARG_EXPECT_REPLY,
2136
                ARG_AUTO_START,
2137
                ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
2138
                ARG_TIMEOUT,
2139
                ARG_AUGMENT_CREDS,
2140
                ARG_WATCH_BIND,
2141
                ARG_JSON,
2142
                ARG_DESTINATION,
2143
        };
2144

2145
        static const struct option options[] = {
1,156✔
2146
                { "help",                            no_argument,       NULL, 'h'                                 },
2147
                { "version",                         no_argument,       NULL, ARG_VERSION                         },
2148
                { "no-pager",                        no_argument,       NULL, ARG_NO_PAGER                        },
2149
                { "no-legend",                       no_argument,       NULL, ARG_NO_LEGEND                       },
2150
                { "full",                            no_argument,       NULL, 'l'                                 },
2151
                { "system",                          no_argument,       NULL, ARG_SYSTEM                          },
2152
                { "user",                            no_argument,       NULL, ARG_USER                            },
2153
                { "address",                         required_argument, NULL, ARG_ADDRESS                         },
2154
                { "show-machine",                    no_argument,       NULL, ARG_SHOW_MACHINE                    },
2155
                { "unique",                          no_argument,       NULL, ARG_UNIQUE                          },
2156
                { "acquired",                        no_argument,       NULL, ARG_ACQUIRED                        },
2157
                { "activatable",                     no_argument,       NULL, ARG_ACTIVATABLE                     },
2158
                { "match",                           required_argument, NULL, ARG_MATCH                           },
2159
                { "host",                            required_argument, NULL, 'H'                                 },
2160
                { "machine",                         required_argument, NULL, 'M'                                 },
2161
                { "capsule",                         required_argument, NULL, 'C'                                 },
2162
                { "size",                            required_argument, NULL, ARG_SIZE                            },
2163
                { "list",                            no_argument,       NULL, ARG_LIST                            },
2164
                { "quiet",                           no_argument,       NULL, 'q'                                 },
2165
                { "verbose",                         no_argument,       NULL, ARG_VERBOSE                         },
2166
                { "xml-interface",                   no_argument,       NULL, ARG_XML_INTERFACE                   },
2167
                { "expect-reply",                    required_argument, NULL, ARG_EXPECT_REPLY                    },
2168
                { "auto-start",                      required_argument, NULL, ARG_AUTO_START                      },
2169
                { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
2170
                { "timeout",                         required_argument, NULL, ARG_TIMEOUT                         },
2171
                { "augment-creds",                   required_argument, NULL, ARG_AUGMENT_CREDS                   },
2172
                { "watch-bind",                      required_argument, NULL, ARG_WATCH_BIND                      },
2173
                { "json",                            required_argument, NULL, ARG_JSON                            },
2174
                { "destination",                     required_argument, NULL, ARG_DESTINATION                     },
2175
                { "limit-messages",                  required_argument, NULL, 'N'                                 },
2176
                {},
2177
        };
2178

2179
        int c, r;
1,156✔
2180

2181
        assert(argc >= 0);
1,156✔
2182
        assert(argv);
1,156✔
2183

2184
        while ((c = getopt_long(argc, argv, "hH:M:C:J:qjlN:", options, NULL)) >= 0)
1,204✔
2185

2186
                switch (c) {
50✔
2187

2188
                case 'h':
1✔
2189
                        return help();
1✔
2190

2191
                case ARG_VERSION:
1✔
2192
                        return version();
1✔
2193

2194
                case ARG_NO_PAGER:
7✔
2195
                        arg_pager_flags |= PAGER_DISABLE;
7✔
2196
                        break;
7✔
2197

2198
                case ARG_NO_LEGEND:
1✔
2199
                        arg_legend = false;
1✔
2200
                        break;
1✔
2201

2202
                case 'l':
1✔
2203
                        arg_full = true;
1✔
2204
                        break;
1✔
2205

2206
                case ARG_USER:
1✔
2207
                        arg_runtime_scope = RUNTIME_SCOPE_USER;
1✔
2208
                        break;
1✔
2209

2210
                case ARG_SYSTEM:
×
UNCOV
2211
                        arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
×
UNCOV
2212
                        break;
×
2213

UNCOV
2214
                case ARG_ADDRESS:
×
UNCOV
2215
                        arg_address = optarg;
×
2216
                        break;
×
2217

2218
                case ARG_SHOW_MACHINE:
1✔
2219
                        arg_show_machine = true;
1✔
2220
                        break;
1✔
2221

2222
                case ARG_UNIQUE:
1✔
2223
                        arg_unique = true;
1✔
2224
                        break;
1✔
2225

2226
                case ARG_ACQUIRED:
1✔
2227
                        arg_acquired = true;
1✔
2228
                        break;
1✔
2229

2230
                case ARG_ACTIVATABLE:
1✔
2231
                        arg_activatable = true;
1✔
2232
                        break;
1✔
2233

2234
                case ARG_MATCH:
2✔
2235
                        if (strv_extend(&arg_matches, optarg) < 0)
2✔
UNCOV
2236
                                return log_oom();
×
2237
                        break;
2238

UNCOV
2239
                case ARG_SIZE: {
×
UNCOV
2240
                        uint64_t sz;
×
2241

UNCOV
2242
                        r = parse_size(optarg, 1024, &sz);
×
UNCOV
2243
                        if (r < 0)
×
UNCOV
2244
                                return log_error_errno(r, "Failed to parse size '%s': %m", optarg);
×
2245

UNCOV
2246
                        if ((uint64_t) (size_t) sz !=  sz)
×
2247
                                return log_error_errno(SYNTHETIC_ERRNO(E2BIG),
2248
                                                       "Size out of range.");
2249

UNCOV
2250
                        arg_snaplen = (size_t) sz;
×
2251
                        break;
×
2252
                }
2253

2254
                case ARG_LIST:
1✔
2255
                        arg_list = true;
1✔
2256
                        break;
1✔
2257

UNCOV
2258
                case 'H':
×
UNCOV
2259
                        arg_transport = BUS_TRANSPORT_REMOTE;
×
UNCOV
2260
                        arg_host = optarg;
×
2261
                        break;
×
2262

2263
                case 'M':
2✔
2264
                        arg_transport = BUS_TRANSPORT_MACHINE;
2✔
2265
                        arg_host = optarg;
2✔
2266
                        break;
2✔
2267

2268
                case 'C':
1✔
2269
                        r = capsule_name_is_valid(optarg);
1✔
2270
                        if (r < 0)
1✔
UNCOV
2271
                                return log_error_errno(r, "Unable to validate capsule name '%s': %m", optarg);
×
2272
                        if (r == 0)
1✔
UNCOV
2273
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", optarg);
×
2274

2275
                        arg_host = optarg;
1✔
2276
                        arg_transport = BUS_TRANSPORT_CAPSULE;
1✔
2277
                        break;
1✔
2278

2279
                case 'q':
2✔
2280
                        arg_quiet = true;
2✔
2281
                        break;
2✔
2282

2283
                case ARG_VERBOSE:
2✔
2284
                        arg_verbose = true;
2✔
2285
                        break;
2✔
2286

2287
                case ARG_XML_INTERFACE:
1✔
2288
                        arg_xml_interface = true;
1✔
2289
                        break;
1✔
2290

2291
                case ARG_EXPECT_REPLY:
1✔
2292
                        r = parse_boolean_argument("--expect-reply=", optarg, &arg_expect_reply);
1✔
2293
                        if (r < 0)
1✔
2294
                                return r;
2295
                        break;
2296

2297
                case ARG_AUTO_START:
1✔
2298
                        r = parse_boolean_argument("--auto-start=", optarg, &arg_auto_start);
1✔
2299
                        if (r < 0)
1✔
2300
                                return r;
2301
                        break;
2302

2303
                case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1✔
2304
                        r = parse_boolean_argument("--allow-interactive-authorization=", optarg,
1✔
2305
                                                   &arg_allow_interactive_authorization);
2306
                        if (r < 0)
1✔
2307
                                return r;
2308
                        break;
2309

2310
                case ARG_TIMEOUT:
4✔
2311
                        if (isempty(optarg)) {
4✔
UNCOV
2312
                                arg_timeout = 0; /* Reset to default */
×
UNCOV
2313
                                break;
×
2314
                        }
2315

2316
                        r = parse_sec(optarg, &arg_timeout);
4✔
2317
                        if (r < 0)
4✔
2318
                                return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", optarg);
×
2319

2320
                        break;
2321

2322
                case ARG_AUGMENT_CREDS:
1✔
2323
                        r = parse_boolean_argument("--augment-creds=", optarg, &arg_augment_creds);
1✔
2324
                        if (r < 0)
1✔
2325
                                return r;
2326
                        break;
2327

2328
                case ARG_WATCH_BIND:
1✔
2329
                        r = parse_boolean_argument("--watch-bind=", optarg, &arg_watch_bind);
1✔
2330
                        if (r < 0)
1✔
2331
                                return r;
2332
                        break;
2333

2334
                case 'j':
3✔
2335
                        arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO;
3✔
2336
                        break;
3✔
2337

2338
                case ARG_JSON:
9✔
2339
                        r = parse_json_argument(optarg, &arg_json_format_flags);
9✔
2340
                        if (r <= 0)
9✔
2341
                                return r;
2342

2343
                        break;
2344

2345
                case ARG_DESTINATION:
1✔
2346
                        arg_destination = optarg;
1✔
2347
                        break;
1✔
2348

2349
                case 'N':
1✔
2350
                        if (isempty(optarg)) {
1✔
2351
                                arg_limit_messages = UINT64_MAX; /* Reset to default */
×
UNCOV
2352
                                break;
×
2353
                        }
2354

2355
                        r = safe_atou64(optarg, &arg_limit_messages);
1✔
2356
                        if (r < 0)
1✔
2357
                                return log_error_errno(r, "Failed to parse --limit-messages= parameter: %s", optarg);
×
2358
                        if (arg_limit_messages == 0)
1✔
UNCOV
2359
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--limit-messages= parameter cannot be 0");
×
2360

2361
                        break;
2362

2363
                case '?':
2364
                        return -EINVAL;
2365

UNCOV
2366
                default:
×
UNCOV
2367
                        assert_not_reached();
×
2368
                }
2369

2370
        if (arg_full < 0)
1,154✔
2371
                arg_full = terminal_is_dumb();
1,153✔
2372

2373
        return 1;
2374
}
2375

2376
static int busctl_main(int argc, char *argv[]) {
1,154✔
2377
        static const Verb verbs[] = {
1,154✔
2378
                { "list",         VERB_ANY, 1,        VERB_DEFAULT, list_bus_names },
2379
                { "status",       VERB_ANY, 2,        0,            status         },
2380
                { "monitor",      VERB_ANY, VERB_ANY, 0,            verb_monitor   },
2381
                { "capture",      VERB_ANY, VERB_ANY, 0,            verb_capture   },
2382
                { "tree",         VERB_ANY, VERB_ANY, 0,            tree           },
2383
                { "introspect",   3,        4,        0,            introspect     },
2384
                { "call",         5,        VERB_ANY, 0,            call           },
2385
                { "emit",         4,        VERB_ANY, 0,            emit_signal    },
2386
                { "wait",         4,        5,        0,            wait_signal    },
2387
                { "get-property", 5,        VERB_ANY, 0,            get_property   },
2388
                { "set-property", 6,        VERB_ANY, 0,            set_property   },
2389
                { "help",         VERB_ANY, VERB_ANY, 0,            verb_help      },
2390
                {}
2391
        };
2392

2393
        return dispatch_verb(argc, argv, verbs, NULL);
1,154✔
2394
}
2395

2396
static int run(int argc, char *argv[]) {
1,156✔
2397
        int r;
1,156✔
2398

2399
        log_setup();
1,156✔
2400

2401
        r = parse_argv(argc, argv);
1,156✔
2402
        if (r <= 0)
1,156✔
2403
                return r;
2404

2405
        return busctl_main(argc, argv);
1,154✔
2406
}
2407

2408
DEFINE_MAIN_FUNCTION(run);
2,312✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc