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

systemd / systemd / 20447389715

21 Dec 2025 07:31PM UTC coverage: 72.37% (-0.1%) from 72.5%
20447389715

push

github

DaanDeMeyer
mkosi: Use initrd as exitrd

Let's speed up image builds by avoiding building
an exitrd and instead reusing the initrd image for
the same purpose.

308584 of 426400 relevant lines covered (72.37%)

1134231.7 hits per line

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

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

3
#include <getopt.h>
4
#include <unistd.h>
5

6
#include "sd-bus.h"
7
#include "sd-daemon.h"
8
#include "sd-event.h"
9
#include "sd-json.h"
10

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

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

76
STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
1,159✔
77

78
#define NAME_IS_ACQUIRED INT_TO_PTR(1)
79
#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
80

81
static int acquire_bus(bool set_monitor, sd_bus **ret) {
1,152✔
82
        _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
1,152✔
83
        _cleanup_close_ int pin_fd = -EBADF;
1,152✔
84
        int r;
1,152✔
85

86
        r = sd_bus_new(&bus);
1,152✔
87
        if (r < 0)
1,152✔
88
                return log_error_errno(r, "Failed to allocate bus: %m");
×
89

90
        (void) sd_bus_set_description(bus, "busctl");
1,152✔
91

92
        if (set_monitor) {
1,152✔
93
                r = sd_bus_set_monitor(bus, true);
2✔
94
                if (r < 0)
2✔
95
                        return log_error_errno(r, "Failed to set monitor mode: %m");
×
96

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

101
                r = sd_bus_negotiate_timestamp(bus, true);
2✔
102
                if (r < 0)
2✔
103
                        return log_error_errno(r, "Failed to enable timestamps: %m");
×
104

105
                r = sd_bus_negotiate_fds(bus, true);
2✔
106
                if (r < 0)
2✔
107
                        return log_error_errno(r, "Failed to enable fds: %m");
×
108
        }
109

110
        r = sd_bus_set_bus_client(bus, true);
1,152✔
111
        if (r < 0)
1,152✔
112
                return log_error_errno(r, "Failed to set bus client: %m");
×
113

114
        r = sd_bus_set_watch_bind(bus, arg_watch_bind);
1,152✔
115
        if (r < 0)
1,152✔
116
                return log_error_errno(r, "Failed to set watch-bind setting to '%s': %m",
×
117
                                       yes_no(arg_watch_bind));
118

119
        if (arg_address)
1,152✔
120
                r = sd_bus_set_address(bus, arg_address);
×
121
        else
122
                switch (arg_transport) {
1,152✔
123

124
                case BUS_TRANSPORT_LOCAL:
1,149✔
125

126
                        switch (arg_runtime_scope) {
1,149✔
127

128
                        case RUNTIME_SCOPE_USER:
×
129
                                r = bus_set_address_user(bus);
×
130
                                break;
131

132
                        case RUNTIME_SCOPE_SYSTEM:
1,149✔
133
                                r = bus_set_address_system(bus);
1,149✔
134
                                break;
135

136
                        default:
×
137
                                assert_not_reached();
×
138
                        }
139

140
                        break;
141

142
                case BUS_TRANSPORT_REMOTE:
×
143
                        r = bus_set_address_system_remote(bus, arg_host);
×
144
                        break;
145

146
                case BUS_TRANSPORT_MACHINE:
2✔
147
                        r = bus_set_address_machine(bus, arg_runtime_scope, arg_host);
2✔
148
                        break;
149

150
                case BUS_TRANSPORT_CAPSULE:
1✔
151
                        r = bus_set_address_capsule_bus(bus, arg_host, &pin_fd);
1✔
152
                        break;
153

154
                default:
×
155
                        assert_not_reached();
×
156
                }
157
        if (r < 0)
1,152✔
158
                return bus_log_address_error(r, arg_transport);
×
159

160
        r = sd_bus_start(bus);
1,152✔
161
        if (r < 0)
1,152✔
162
                return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
×
163

164
        *ret = TAKE_PTR(bus);
1,152✔
165

166
        return 0;
1,152✔
167
}
168

169
static void notify_bus_error(const sd_bus_error *error) {
1,014✔
170

171
        if (!sd_bus_error_is_set(error))
1,014✔
172
                return;
173

174
        (void) sd_notifyf(/* unset_environment= */ false, "BUSERROR=%s", error->name);
1,014✔
175
}
176

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

186
        enum {
6✔
187
                COLUMN_ACTIVATABLE,
188
                COLUMN_NAME,
189
                COLUMN_PID,
190
                COLUMN_PROCESS,
191
                COLUMN_USER,
192
                COLUMN_CONNECTION,
193
                COLUMN_UNIT,
194
                COLUMN_SESSION,
195
                COLUMN_DESCRIPTION,
196
                COLUMN_MACHINE,
197
        };
198

199
        if (!arg_unique && !arg_acquired && !arg_activatable)
6✔
200
                arg_unique = arg_acquired = arg_activatable = true;
4✔
201

202
        r = acquire_bus(false, &bus);
6✔
203
        if (r < 0)
6✔
204
                return r;
205

206
        r = sd_bus_list_names(bus,
6✔
207
                              (arg_acquired || arg_unique) ? &acquired : NULL,
6✔
208
                              arg_activatable ? &activatable : NULL);
6✔
209
        if (r < 0)
6✔
210
                return log_error_errno(r, "Failed to list names: %m");
×
211

212
        names = hashmap_new(&string_hash_ops);
6✔
213
        if (!names)
6✔
214
                return log_oom();
×
215

216
        STRV_FOREACH(i, acquired) {
78✔
217
                r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
72✔
218
                if (r < 0)
72✔
219
                        return log_error_errno(r, "Failed to add to hashmap: %m");
×
220
        }
221

222
        STRV_FOREACH(i, activatable) {
74✔
223
                r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
68✔
224
                if (r < 0 && r != -EEXIST)
68✔
225
                        return log_error_errno(r, "Failed to add to hashmap: %m");
×
226
        }
227

228
        table = table_new("activatable",
6✔
229
                          "name",
230
                          "pid",
231
                          "process",
232
                          "user",
233
                          "connection",
234
                          "unit",
235
                          "session",
236
                          "description",
237
                          "machine");
238
        if (!table)
6✔
239
                return log_oom();
×
240

241
        if (arg_full > 0)
6✔
242
                table_set_width(table, 0);
6✔
243

244
        r = table_set_align_percent(table, table_get_cell(table, 0, COLUMN_PID), 100);
6✔
245
        if (r < 0)
6✔
246
                return log_error_errno(r, "Failed to set alignment: %m");
×
247

248
        table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
6✔
249

250
        r = table_set_sort(table, (size_t) COLUMN_NAME);
6✔
251
        if (r < 0)
6✔
252
                return log_error_errno(r, "Failed to set sort column: %m");
×
253

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

274
        if (r < 0)
6✔
275
                return log_error_errno(r, "Failed to set columns to display: %m");
×
276

277
        HASHMAP_FOREACH_KEY(v, k, names) {
121✔
278
                _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
115✔
279

280
                if (v == NAME_IS_ACTIVATABLE) {
115✔
281
                        r = table_add_many(
43✔
282
                                        table,
283
                                        TABLE_INT, PTR_TO_INT(v),
284
                                        TABLE_STRING, k,
285
                                        TABLE_EMPTY,
286
                                        TABLE_EMPTY,
287
                                        TABLE_EMPTY,
288
                                        TABLE_STRING, "(activatable)", TABLE_SET_COLOR, ansi_grey(),
289
                                        TABLE_EMPTY,
290
                                        TABLE_EMPTY,
291
                                        TABLE_EMPTY,
292
                                        TABLE_EMPTY);
293
                        if (r < 0)
43✔
294
                                return table_log_add_error(r);
×
295

296
                        continue;
43✔
297
                }
298

299
                assert(v == NAME_IS_ACQUIRED);
72✔
300

301
                if (!arg_unique && k[0] == ':')
72✔
302
                        continue;
8✔
303

304
                if (!arg_acquired && k[0] != ':')
64✔
305
                        continue;
6✔
306

307
                r = table_add_many(table,
58✔
308
                                   TABLE_INT, PTR_TO_INT(v),
309
                                   TABLE_STRING, k);
310
                if (r < 0)
58✔
311
                        return table_log_add_error(r);
×
312

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

322
                        r = table_fill_empty(table, COLUMN_MACHINE);
×
323
                } else {
324
                        const char *unique = NULL, *session = NULL, *unit = NULL, *cn = NULL;
58✔
325
                        pid_t pid;
58✔
326
                        uid_t uid;
58✔
327

328
                        r = sd_bus_creds_get_pid(creds, &pid);
58✔
329
                        if (r >= 0) {
58✔
330
                                const char *comm = NULL;
58✔
331

332
                                (void) sd_bus_creds_get_comm(creds, &comm);
58✔
333

334
                                r = table_add_many(table,
59✔
335
                                                   TABLE_PID, pid,
336
                                                   TABLE_STRING, strna(comm));
337
                        } else
338
                                r = table_add_many(table, TABLE_EMPTY, TABLE_EMPTY);
×
339
                        if (r < 0)
58✔
340
                                return table_log_add_error(r);
×
341

342
                        r = sd_bus_creds_get_euid(creds, &uid);
58✔
343
                        if (r >= 0) {
58✔
344
                                _cleanup_free_ char *u = NULL;
58✔
345

346
                                u = uid_to_name(uid);
58✔
347
                                if (!u)
58✔
348
                                        return log_oom();
×
349

350
                                r = table_add_cell(table, NULL, TABLE_STRING, u);
58✔
351
                        } else
352
                                r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
×
353
                        if (r < 0)
58✔
354
                                return table_log_add_error(r);
×
355

356
                        (void) sd_bus_creds_get_unique_name(creds, &unique);
58✔
357
                        (void) sd_bus_creds_get_unit(creds, &unit);
58✔
358
                        (void) sd_bus_creds_get_session(creds, &session);
58✔
359
                        (void) sd_bus_creds_get_description(creds, &cn);
58✔
360

361
                        r = table_add_many(
58✔
362
                                        table,
363
                                        TABLE_STRING, unique,
364
                                        TABLE_STRING, unit,
365
                                        TABLE_STRING, session,
366
                                        TABLE_STRING, cn);
367
                }
368
                if (r < 0)
58✔
369
                        return table_log_add_error(r);
×
370

371
                if (arg_show_machine) {
58✔
372
                        sd_id128_t mid;
8✔
373

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

382
                                continue; /* line fully filled, no need to fill the remainder below */
6✔
383
                        }
384
                }
385

386
                r = table_fill_empty(table, 0);
52✔
387
                if (r < 0)
52✔
388
                        return log_error_errno(r, "Failed to fill line: %m");
×
389
        }
390

391
        return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
6✔
392
}
393

394
static void print_subtree(const char *prefix, const char *path, char **l) {
344✔
395
        /* We assume the list is sorted. Let's first skip over the
396
         * entry we are looking at. */
397
        for (;;) {
1,032✔
398
                if (!*l)
688✔
399
                        return;
400

401
                if (!streq(*l, path))
675✔
402
                        break;
403

404
                l++;
344✔
405
        }
406

407
        const char
331✔
408
                *vertical = strjoina(prefix, glyph(GLYPH_TREE_VERTICAL)),
1,655✔
409
                *space = strjoina(prefix, glyph(GLYPH_TREE_SPACE));
1,655✔
410

411
        for (;;) {
331✔
412
                bool has_more = false;
662✔
413
                char **n;
662✔
414

415
                if (!*l || !path_startswith(*l, path))
662✔
416
                        break;
417

418
                n = l + 1;
331✔
419
                for (;;) {
2,667✔
420
                        if (!*n || !path_startswith(*n, path))
1,499✔
421
                                break;
422

423
                        if (!path_startswith(*n, *l)) {
1,436✔
424
                                has_more = true;
425
                                break;
426
                        }
427

428
                        n++;
1,168✔
429
                }
430

431
                printf("%s%s %s\n",
662✔
432
                       prefix,
433
                       glyph(has_more ? GLYPH_TREE_BRANCH : GLYPH_TREE_RIGHT),
434
                       *l);
435

436
                print_subtree(has_more ? vertical : space, *l, l);
331✔
437
                l = n;
331✔
438
        }
439
}
440

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

452
static int on_path(const char *path, void *userdata) {
696✔
453
        Set *paths = ASSERT_PTR(userdata);
696✔
454
        int r;
696✔
455

456
        r = set_put_strdup(&paths, path);
696✔
457
        if (r < 0)
696✔
458
                return log_oom();
×
459

460
        return 0;
461
}
462

463
static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths) {
356✔
464
        static const XMLIntrospectOps ops = {
356✔
465
                .on_path = on_path,
466
        };
467

468
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
356✔
469
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
356✔
470
        const char *xml;
356✔
471
        int r;
356✔
472

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

485
        r = sd_bus_message_read(reply, "s", &xml);
355✔
486
        if (r < 0)
355✔
487
                return bus_log_parse_error(r);
×
488

489
        return parse_xml_introspect(path, xml, &ops, paths);
355✔
490
}
491

492
static int tree_one(sd_bus *bus, const char *service) {
15✔
493
        _cleanup_set_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
15✔
494
        _cleanup_free_ char **l = NULL;
15✔
495
        int r;
15✔
496

497
        r = set_put_strdup(&paths, "/");
15✔
498
        if (r < 0)
15✔
499
                return log_oom();
×
500

501
        for (;;) {
726✔
502
                _cleanup_free_ char *p = NULL;
355✔
503
                int q;
726✔
504

505
                p = set_steal_first(paths);
726✔
506
                if (!p)
726✔
507
                        break;
508

509
                if (set_contains(done, p) ||
711✔
510
                    set_contains(failed, p))
356✔
511
                        continue;
355✔
512

513
                q = find_nodes(bus, service, p, paths);
356✔
514
                if (q < 0 && r >= 0)
356✔
515
                        r = q;
516

517
                q = set_ensure_consume(q < 0 ? &failed : &done, &string_hash_ops_free, TAKE_PTR(p));
711✔
518
                assert(q != 0);
356✔
519
                if (q < 0)
356✔
520
                        return log_oom();
×
521
        }
522

523
        pager_open(arg_pager_flags);
15✔
524

525
        l = set_get_strv(done);
15✔
526
        if (!l)
15✔
527
                return log_oom();
×
528

529
        strv_sort(l);
15✔
530
        print_tree(l);
15✔
531

532
        fflush(stdout);
15✔
533

534
        return r;
535
}
536

537
static int tree(int argc, char **argv, void *userdata) {
10✔
538
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
10✔
539
        int r;
10✔
540

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

547
        if (!arg_unique && !arg_acquired)
10✔
548
                arg_acquired = true;
10✔
549

550
        r = acquire_bus(false, &bus);
10✔
551
        if (r < 0)
10✔
552
                return r;
553

554
        char **args = strv_skip(argv, 1);
10✔
555
        if (args)
10✔
556
                STRV_FOREACH(arg, args) {
18✔
557
                        if (arg != args)
9✔
558
                                puts("");
×
559

560
                        if (args[1]) {
9✔
561
                                pager_open(arg_pager_flags);
×
562
                                printf("Service %s%s%s:\n", ansi_highlight(), *arg, ansi_normal());
×
563
                        }
564

565
                        RET_GATHER(r, tree_one(bus, *arg));
9✔
566
                }
567
        else {
568
                _cleanup_strv_free_ char **names = NULL;
1✔
569

570
                r = sd_bus_list_names(bus, &names, NULL);
1✔
571
                if (r < 0)
1✔
572
                        return log_error_errno(r, "Failed to get name list: %m");
×
573

574
                pager_open(arg_pager_flags);
1✔
575

576
                STRV_FOREACH(name, names) {
15✔
577
                        if (!arg_unique && (*name)[0] == ':')
14✔
578
                                continue;
8✔
579

580
                        if (!arg_acquired && (*name)[0] == ':')
6✔
581
                                continue;
×
582

583
                        if (name != names)
6✔
584
                                puts("");
5✔
585

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

588
                        RET_GATHER(r, tree_one(bus, *name));
6✔
589
                }
590
        }
591

592
        return r;
593
}
594

595
static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
360✔
596
        int r;
798✔
597

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

614
                r = sd_bus_message_peek_type(m, &type, &contents);
798✔
615
                if (r < 0)
798✔
616
                        return r;
360✔
617
                if (r == 0)
798✔
618
                        return needs_space;
360✔
619

620
                if (bus_type_is_container(type) > 0) {
438✔
621

622
                        r = sd_bus_message_enter_container(m, type, contents);
17✔
623
                        if (r < 0)
17✔
624
                                return r;
625

626
                        if (type == SD_BUS_TYPE_ARRAY) {
17✔
627
                                unsigned n = 0;
628

629
                                /* count array entries */
630
                                for (;;) {
109✔
631

632
                                        r = sd_bus_message_skip(m, contents);
60✔
633
                                        if (r < 0)
60✔
634
                                                return r;
635
                                        if (r == 0)
60✔
636
                                                break;
637

638
                                        n++;
49✔
639
                                }
640

641
                                r = sd_bus_message_rewind(m, false);
11✔
642
                                if (r < 0)
11✔
643
                                        return r;
644

645
                                if (needs_space)
11✔
646
                                        fputc(' ', f);
1✔
647

648
                                fprintf(f, "%u", n);
11✔
649
                                needs_space = true;
650

651
                        } else if (type == SD_BUS_TYPE_VARIANT) {
6✔
652

653
                                if (needs_space)
×
654
                                        fputc(' ', f);
×
655

656
                                fprintf(f, "%s", contents);
×
657
                                needs_space = true;
658
                        }
659

660
                        r = format_cmdline(m, f, needs_space);
17✔
661
                        if (r < 0)
17✔
662
                                return r;
663

664
                        needs_space = r > 0;
17✔
665

666
                        r = sd_bus_message_exit_container(m);
17✔
667
                        if (r < 0)
17✔
668
                                return r;
669

670
                        continue;
17✔
671
                }
672

673
                r = sd_bus_message_read_basic(m, type, &basic);
421✔
674
                if (r < 0)
421✔
675
                        return r;
676

677
                if (needs_space)
421✔
678
                        fputc(' ', f);
88✔
679

680
                switch (type) {
421✔
681
                case SD_BUS_TYPE_BYTE:
6✔
682
                        fprintf(f, "%u", basic.u8);
6✔
683
                        break;
684

685
                case SD_BUS_TYPE_BOOLEAN:
21✔
686
                        fputs(true_false(basic.i), f);
34✔
687
                        break;
688

689
                case SD_BUS_TYPE_INT16:
×
690
                        fprintf(f, "%i", basic.s16);
×
691
                        break;
692

693
                case SD_BUS_TYPE_UINT16:
×
694
                        fprintf(f, "%u", basic.u16);
×
695
                        break;
696

697
                case SD_BUS_TYPE_INT32:
35✔
698
                        fprintf(f, "%i", basic.s32);
35✔
699
                        break;
700

701
                case SD_BUS_TYPE_UINT32:
15✔
702
                        fprintf(f, "%u", basic.u32);
15✔
703
                        break;
704

705
                case SD_BUS_TYPE_INT64:
×
706
                        fprintf(f, "%" PRIi64, basic.s64);
×
707
                        break;
708

709
                case SD_BUS_TYPE_UINT64:
177✔
710
                        fprintf(f, "%" PRIu64, basic.u64);
177✔
711
                        break;
712

713
                case SD_BUS_TYPE_DOUBLE:
2✔
714
                        fprintf(f, "%g", basic.d64);
2✔
715
                        break;
716

717
                case SD_BUS_TYPE_STRING:
165✔
718
                case SD_BUS_TYPE_OBJECT_PATH:
719
                case SD_BUS_TYPE_SIGNATURE: {
720
                        _cleanup_free_ char *b = NULL;
165✔
721

722
                        b = cescape(basic.string);
165✔
723
                        if (!b)
165✔
724
                                return -ENOMEM;
×
725

726
                        fprintf(f, "\"%s\"", b);
165✔
727
                        break;
165✔
728
                }
729

730
                case SD_BUS_TYPE_UNIX_FD:
×
731
                        fprintf(f, "%i", basic.i);
×
732
                        break;
733

734
                default:
×
735
                        assert_not_reached();
×
736
                }
737

738
                needs_space = true;
421✔
739
        }
740
}
741

742
typedef struct Member {
743
        const char *type;
744
        char *interface;
745
        char *name;
746
        char *signature;
747
        char *result;
748
        char *value;
749
        bool writable;
750
        uint64_t flags;
751
} Member;
752

753
static void member_hash_func(const Member *m, struct siphash *state) {
1,442✔
754
        uint64_t arity = 1;
1,442✔
755

756
        assert(m);
1,442✔
757
        assert(m->type);
1,442✔
758

759
        string_hash_func(m->type, state);
1,442✔
760

761
        arity += !!m->name + !!m->interface;
1,442✔
762

763
        uint64_hash_func(&arity, state);
1,442✔
764

765
        if (m->name)
1,442✔
766
                string_hash_func(m->name, state);
1,400✔
767

768
        if (m->signature)
1,442✔
769
                string_hash_func(m->signature, state);
1,306✔
770

771
        if (m->interface)
1,442✔
772
                string_hash_func(m->interface, state);
1,442✔
773
}
1,442✔
774

775
static int member_compare_func(const Member *x, const Member *y) {
3,634✔
776
        int d;
3,634✔
777

778
        assert(x);
3,634✔
779
        assert(y);
3,634✔
780
        assert(x->type);
3,634✔
781
        assert(y->type);
3,634✔
782

783
        d = strcmp_ptr(x->interface, y->interface);
3,634✔
784
        if (d != 0)
3,634✔
785
                return d;
786

787
        d = strcmp(x->type, y->type);
3,453✔
788
        if (d != 0)
3,453✔
789
                return d;
790

791
        d = strcmp_ptr(x->name, y->name);
2,832✔
792
        if (d != 0)
2,832✔
793
                return d;
794

795
        return strcmp_ptr(x->signature, y->signature);
252✔
796
}
797

798
static Member* member_free(Member *m) {
466✔
799
        if (!m)
466✔
800
                return NULL;
801

802
        free(m->interface);
466✔
803
        free(m->name);
466✔
804
        free(m->signature);
466✔
805
        free(m->result);
466✔
806
        free(m->value);
466✔
807
        return mfree(m);
466✔
808
}
809
DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
466✔
810

811
static int on_interface(const char *interface, uint64_t flags, void *userdata) {
8✔
812
        _cleanup_(member_freep) Member *m = NULL;
8✔
813
        Set *members = ASSERT_PTR(userdata);
8✔
814
        int r;
8✔
815

816
        assert(interface);
8✔
817

818
        m = new(Member, 1);
8✔
819
        if (!m)
8✔
820
                return log_oom();
×
821

822
        *m = (Member) {
8✔
823
                .type = "interface",
824
                .flags = flags,
825
        };
826

827
        r = strdup_to(&m->interface, interface);
8✔
828
        if (r < 0)
8✔
829
                return log_oom();
×
830

831
        r = set_consume(members, TAKE_PTR(m));
8✔
832
        if (r < 0)
8✔
833
                return log_oom();
×
834
        if (r == 0)
8✔
835
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
836
                                       "Invalid introspection data: duplicate interface '%s'.", interface);
837

838
        return 0;
839
}
840

841
static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
190✔
842
        _cleanup_(member_freep) Member *m = NULL;
190✔
843
        Set *members = userdata;
190✔
844
        int r;
190✔
845

846
        assert(interface);
190✔
847
        assert(name);
190✔
848

849
        m = new(Member, 1);
190✔
850
        if (!m)
190✔
851
                return log_oom();
×
852

853
        *m = (Member) {
190✔
854
                .type = "method",
855
                .flags = flags,
856
        };
857

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

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

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

870
        r = strdup_to(&m->result, result);
190✔
871
        if (r < 0)
190✔
872
                return log_oom();
×
873

874
        r = set_consume(members, TAKE_PTR(m));
190✔
875
        if (r < 0)
190✔
876
                return log_oom();
×
877
        if (r == 0)
190✔
878
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
879
                                       "Invalid introspection data: duplicate method '%s' on interface '%s'.", name, interface);
880

881
        return 0;
882
}
883

884
static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
16✔
885
        _cleanup_(member_freep) Member *m = NULL;
16✔
886
        Set *members = userdata;
16✔
887
        int r;
16✔
888

889
        assert(interface);
16✔
890
        assert(name);
16✔
891

892
        m = new(Member, 1);
16✔
893
        if (!m)
16✔
894
                return log_oom();
×
895

896
        *m = (Member) {
16✔
897
                .type = "signal",
898
                .flags = flags,
899
        };
900

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

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

909
        r = strdup_to(&m->signature, signature);
16✔
910
        if (r < 0)
16✔
911
                return log_oom();
×
912

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

920
        return 0;
921
}
922

923
static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
252✔
924
        _cleanup_(member_freep) Member *m = NULL;
252✔
925
        Set *members = userdata;
252✔
926
        int r;
252✔
927

928
        assert(interface);
252✔
929
        assert(name);
252✔
930

931
        m = new(Member, 1);
252✔
932
        if (!m)
252✔
933
                return log_oom();
×
934

935
        *m = (Member) {
252✔
936
                .type = "property",
937
                .flags = flags,
938
                .writable = writable,
939
        };
940

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

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

949
        r = strdup_to(&m->signature, signature);
252✔
950
        if (r < 0)
252✔
951
                return log_oom();
×
952

953
        r = set_consume(members, TAKE_PTR(m));
252✔
954
        if (r < 0)
252✔
955
                return log_oom();
×
956
        if (r == 0)
252✔
957
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
958
                                       "Invalid introspection data: duplicate property '%s' on interface '%s'.", name, interface);
959

960
        return 0;
961
}
962

963
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
466✔
964
                member_hash_ops,
965
                Member,
966
                member_hash_func,
967
                member_compare_func,
968
                member_free);
969

970
static int members_flags_to_string(const Member *m, char **ret) {
455✔
971
        static const char *map[] = {
455✔
972
                [LOG2U(SD_BUS_VTABLE_DEPRECATED)]                  = "deprecated",
973
                [LOG2U(SD_BUS_VTABLE_METHOD_NO_REPLY)]             = "no-reply",
974
                [LOG2U(SD_BUS_VTABLE_PROPERTY_CONST)]              = "const",
975
                [LOG2U(SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)]       = "emits-change",
976
                [LOG2U(SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)] = "emits-invalidation",
977
        };
978

979
        assert(m);
455✔
980
        assert(ret);
455✔
981

982
        _cleanup_free_ char *str = NULL;
455✔
983
        for (size_t i = 0; i < ELEMENTSOF(map); i++)
3,640✔
984
                if (BIT_SET(m->flags, i) && map[i])
3,185✔
985
                        if (!strextend_with_separator(&str, " ", map[i]))
204✔
986
                                return -ENOMEM;
987

988
        if (m->writable)
455✔
989
                if (!strextend_with_separator(&str, " ", "writable"))
16✔
990
                        return -ENOMEM;
991

992
        *ret = TAKE_PTR(str);
455✔
993
        return 0;
455✔
994
}
995

996
static int introspect(int argc, char **argv, void *userdata) {
6✔
997
        static const XMLIntrospectOps ops = {
6✔
998
                .on_interface = on_interface,
999
                .on_method = on_method,
1000
                .on_signal = on_signal,
1001
                .on_property = on_property,
1002
        };
1003

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

1012
        r = acquire_bus(false, &bus);
6✔
1013
        if (r < 0)
6✔
1014
                return r;
1015

1016
        members = set_new(&member_hash_ops);
6✔
1017
        if (!members)
6✔
1018
                return log_oom();
×
1019

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

1029
        r = sd_bus_message_read(reply_xml, "s", &xml);
3✔
1030
        if (r < 0)
3✔
1031
                return bus_log_parse_error(r);
×
1032

1033
        if (arg_xml_interface) {
3✔
1034
                /* Just dump the received XML and finish */
1035
                pager_open(arg_pager_flags);
1✔
1036
                puts(xml);
1✔
1037
                return 0;
1038
        }
1039

1040
        /* First, get list of all properties */
1041
        r = parse_xml_introspect(argv[2], xml, &ops, members);
2✔
1042
        if (r < 0)
2✔
1043
                return r;
1044

1045
        /* Second, find the current values for them */
1046
        SET_FOREACH(m, members) {
468✔
1047
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
466✔
1048

1049
                if (!streq(m->type, "property"))
466✔
1050
                        continue;
214✔
1051

1052
                if (m->value)
252✔
1053
                        continue;
250✔
1054

1055
                if (argv[3] && !streq(argv[3], m->interface))
2✔
1056
                        continue;
×
1057

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

1067
                r = sd_bus_message_enter_container(reply, 'a', "{sv}");
2✔
1068
                if (r < 0)
2✔
1069
                        return bus_log_parse_error(r);
×
1070

1071
                for (;;) {
252✔
1072
                        _cleanup_(memstream_done) MemStream ms = {};
×
1073
                        _cleanup_free_ char *buf = NULL;
254✔
1074
                        const char *name, *contents;
254✔
1075
                        Member *z;
254✔
1076
                        char type;
254✔
1077
                        FILE *mf;
254✔
1078

1079
                        r = sd_bus_message_enter_container(reply, 'e', "sv");
254✔
1080
                        if (r < 0)
254✔
1081
                                return bus_log_parse_error(r);
×
1082
                        if (r == 0)
254✔
1083
                                break;
1084

1085
                        r = sd_bus_message_read(reply, "s", &name);
252✔
1086
                        if (r < 0)
252✔
1087
                                return bus_log_parse_error(r);
×
1088

1089
                        r = sd_bus_message_peek_type(reply, &type, &contents);
252✔
1090
                        if (r < 0)
252✔
1091
                                return bus_log_parse_error(r);
×
1092
                        if (type != 'v')
252✔
1093
                                return bus_log_parse_error(EINVAL);
×
1094

1095
                        r = sd_bus_message_enter_container(reply, 'v', contents);
252✔
1096
                        if (r < 0)
252✔
1097
                                return bus_log_parse_error(r);
×
1098

1099
                        mf = memstream_init(&ms);
252✔
1100
                        if (!mf)
252✔
1101
                                return log_oom();
×
1102

1103
                        r = format_cmdline(reply, mf, false);
252✔
1104
                        if (r < 0)
252✔
1105
                                return bus_log_parse_error(r);
×
1106

1107
                        r = memstream_finalize(&ms, &buf, NULL);
252✔
1108
                        if (r < 0)
252✔
1109
                                return log_error_errno(r, "Failed to flush and close memstream: %m");
×
1110

1111
                        z = set_get(members, &((Member) {
504✔
1112
                                                .type = "property",
1113
                                                .interface = m->interface,
252✔
1114
                                                .signature = (char*) contents,
1115
                                                .name = (char*) name }));
1116
                        if (z)
252✔
1117
                                free_and_replace(z->value, buf);
252✔
1118

1119
                        r = sd_bus_message_exit_container(reply);
252✔
1120
                        if (r < 0)
252✔
1121
                                return bus_log_parse_error(r);
×
1122

1123
                        r = sd_bus_message_exit_container(reply);
252✔
1124
                        if (r < 0)
252✔
1125
                                return bus_log_parse_error(r);
×
1126
                }
1127

1128
                r = sd_bus_message_exit_container(reply);
2✔
1129
                if (r < 0)
2✔
1130
                        return bus_log_parse_error(r);
×
1131
        }
1132

1133
        size_t n;
2✔
1134
        _cleanup_free_ Member **sorted = NULL;
2✔
1135
        r = set_dump_sorted(members, (void***) &sorted, &n);
2✔
1136
        if (r < 0)
2✔
1137
                return log_oom();
×
1138

1139
        _cleanup_(table_unrefp) Table *table = table_new("name", "type", "signature", "result/value", "flags");
4✔
1140
        if (!table)
2✔
1141
                return log_oom();
×
1142

1143
        if (arg_full)
2✔
1144
                table_set_width(table, 0);
2✔
1145
        (void) table_set_maximum_width(table, table_get_cell(table, 0, 3), arg_full ? 100 : 40);
2✔
1146
        table_set_header(table, arg_legend);
2✔
1147
        table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
2✔
1148

1149
        FOREACH_ARRAY(p, sorted, n) {
468✔
1150
                bool is_interface;
466✔
1151

1152
                m = *p;
466✔
1153

1154
                if (argv[3] && !streq(argv[3], m->interface))
466✔
1155
                        continue;
11✔
1156

1157
                is_interface = streq(m->type, "interface");
456✔
1158

1159
                if (argv[3] && is_interface)
456✔
1160
                        continue;
1✔
1161

1162
                if (is_interface)
233✔
1163
                        r = table_add_many(
8✔
1164
                                        table,
1165
                                        TABLE_STRING, m->interface,
1166
                                        TABLE_SET_COLOR, ansi_highlight());
1167
                else
1168
                        r = table_add_cell_stringf(
451✔
1169
                                        table, /* ret_cell= */ NULL, ".%s", m->name);
1170
                if (r < 0)
455✔
1171
                        return table_log_add_error(r);
×
1172

1173
                _cleanup_free_ char *flags = NULL;
455✔
1174
                r = members_flags_to_string(m, &flags);
455✔
1175
                if (r < 0)
455✔
1176
                        return log_oom();
×
1177

1178
                r = table_add_many(
455✔
1179
                                table,
1180
                                TABLE_STRING, m->type,
1181
                                TABLE_STRING, m->signature,
1182
                                TABLE_STRING, m->value ?: m->result,
1183
                                TABLE_STRING, flags);
1184
                if (r < 0)
455✔
1185
                        return table_log_add_error(r);
×
1186
        }
1187

1188
        pager_open(arg_pager_flags);
2✔
1189

1190
        r = table_print(table, NULL);
2✔
1191
        if (r < 0)
2✔
1192
                return table_log_print_error(r);
×
1193

1194
        return 0;
1195
}
1196

1197
static int message_dump(sd_bus_message *m, FILE *f) {
×
1198
        int r;
×
1199

1200
        assert(m);
×
1201

1202
        r = sd_bus_message_dump(m, f, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
×
1203
        if (r < 0)
×
1204
                return log_error_errno(r, "Failed to dump DBus message: %m");
×
1205

1206
        return 0;
1207
}
1208

1209
static int message_pcap(sd_bus_message *m, FILE *f) {
×
1210
        int r;
×
1211

1212
        assert(m);
×
1213

1214
        r = bus_message_pcap_frame(m, arg_snaplen, f);
×
1215
        if (r < 0)
×
1216
                return log_error_errno(r, "Failed to dump DBus message in PCAP format: %m");
×
1217

1218
        return 0;
1219
}
1220

1221
static int message_json(sd_bus_message *m, FILE *f) {
×
1222
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
×
1223
        int r;
×
1224

1225
        assert(m);
×
1226

1227
        r = sd_bus_message_dump_json(m, SD_BUS_MESSAGE_DUMP_WITH_HEADER, &v);
×
1228
        if (r < 0)
×
1229
                return log_error_errno(r, "Failed to build JSON object from DBus message: %m");
×
1230

1231
        r = sd_json_variant_dump(v, arg_json_format_flags, f, NULL);
×
1232
        if (r < 0)
×
1233
                return log_error_errno(r, "Failed to show JSON object: %m");
×
1234

1235
        return 0;
1236
}
1237

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

1247
        r = acquire_bus(true, &bus);
2✔
1248
        if (r < 0)
2✔
1249
                return r;
1250

1251
        usec_t end = arg_timeout > 0 ?
2✔
1252
                usec_add(now(CLOCK_MONOTONIC), arg_timeout) : USEC_INFINITY;
2✔
1253

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

1264
        r = sd_bus_message_open_container(message, 'a', "s");
2✔
1265
        if (r < 0)
2✔
1266
                return bus_log_create_error(r);
×
1267

1268
        STRV_FOREACH(i, argv+1) {
2✔
1269
                _cleanup_free_ char *m = NULL;
×
1270

1271
                if (!sd_bus_service_name_is_valid(*i))
×
1272
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name '%s'", *i);
×
1273

1274
                m = strjoin("sender='", *i, "'");
×
1275
                if (!m)
×
1276
                        return log_oom();
×
1277

1278
                r = sd_bus_message_append_basic(message, 's', m);
×
1279
                if (r < 0)
×
1280
                        return bus_log_create_error(r);
×
1281

1282
                free(m);
×
1283
                m = strjoin("destination='", *i, "'");
×
1284
                if (!m)
×
1285
                        return log_oom();
×
1286

1287
                r = sd_bus_message_append_basic(message, 's', m);
×
1288
                if (r < 0)
×
1289
                        return bus_log_create_error(r);
×
1290
        }
1291

1292
        STRV_FOREACH(i, arg_matches) {
4✔
1293
                r = sd_bus_message_append_basic(message, 's', *i);
2✔
1294
                if (r < 0)
2✔
1295
                        return bus_log_create_error(r);
×
1296
        }
1297

1298
        r = sd_bus_message_close_container(message);
2✔
1299
        if (r < 0)
2✔
1300
                return bus_log_create_error(r);
×
1301

1302
        r = sd_bus_message_append_basic(message, 'u', &flags);
2✔
1303
        if (r < 0)
2✔
1304
                return bus_log_create_error(r);
×
1305

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

1313
        r = sd_bus_get_unique_name(bus, &unique_name);
2✔
1314
        if (r < 0)
2✔
1315
                return log_error_errno(r, "Failed to get unique name: %m");
×
1316

1317
        if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
2✔
1318
                log_info("Monitoring bus message stream.");
×
1319

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

1322
        for (;;) {
6✔
1323
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
6✔
1324

1325
                r = sd_bus_process(bus, &m);
6✔
1326
                if (r < 0)
6✔
1327
                        return log_error_errno(r, "Failed to process bus: %m");
×
1328

1329
                if (m) {
6✔
1330
                        if (!is_monitor) {
4✔
1331
                                const char *name;
4✔
1332

1333
                                /* wait until we lose our unique name */
1334
                                if (sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameLost") <= 0)
4✔
1335
                                        continue;
4✔
1336

1337
                                r = sd_bus_message_read(m, "s", &name);
2✔
1338
                                if (r < 0)
2✔
1339
                                        return bus_log_parse_error(r);
×
1340

1341
                                if (streq(name, unique_name))
2✔
1342
                                        is_monitor = true;
2✔
1343

1344
                                continue;
2✔
1345
                        }
1346

1347
                        dump(m, stdout);
×
1348
                        fflush(stdout);
×
1349

1350
                        if (arg_limit_messages != UINT64_MAX) {
×
1351
                                arg_limit_messages--;
×
1352

1353
                                if (arg_limit_messages == 0) {
×
1354
                                        if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
×
1355
                                                log_info("Received requested maximum number of messages, exiting.");
×
1356
                                        return 0;
×
1357
                                }
1358
                        }
1359

1360
                        if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
×
1361
                                if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
×
1362
                                        log_info("Connection terminated, exiting.");
×
1363
                                return 0;
×
1364
                        }
1365

1366
                        continue;
×
1367
                }
1368

1369
                if (r > 0)
2✔
1370
                        continue;
×
1371

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

1383
static int verb_monitor(int argc, char **argv, void *userdata) {
2✔
1384
        return monitor(argc, argv, sd_json_format_enabled(arg_json_format_flags) ? message_json : message_dump);
4✔
1385
}
1386

1387
static int verb_capture(int argc, char **argv, void *userdata) {
×
1388
        _cleanup_free_ char *osname = NULL;
×
1389
        static const char info[] =
×
1390
                "busctl (systemd) " PROJECT_VERSION_FULL " (Git " GIT_VERSION ")";
1391
        int r;
×
1392

1393
        if (isatty_safe(STDOUT_FILENO))
×
1394
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1395
                                       "Refusing to write message data to console, please redirect output to a file.");
1396

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

1403
        r = monitor(argc, argv, message_pcap);
×
1404
        if (r < 0)
×
1405
                return r;
1406

1407
        r = fflush_and_check(stdout);
×
1408
        if (r < 0)
×
1409
                return log_error_errno(r, "Couldn't write capture file: %m");
×
1410

1411
        return r;
1412
}
1413

1414
static int status(int argc, char **argv, void *userdata) {
5✔
1415
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
5✔
1416
        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
5✔
1417
        pid_t pid;
5✔
1418
        int r;
5✔
1419

1420
        r = acquire_bus(false, &bus);
5✔
1421
        if (r < 0)
5✔
1422
                return r;
1423

1424
        pager_open(arg_pager_flags);
5✔
1425

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

1443
                r = sd_bus_get_address(bus, &address);
3✔
1444
                if (r >= 0)
3✔
1445
                        printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal());
9✔
1446

1447
                r = sd_bus_get_scope(bus, &scope);
3✔
1448
                if (r >= 0)
3✔
1449
                        printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal());
3✔
1450

1451
                r = sd_bus_get_bus_id(bus, &bus_id);
3✔
1452
                if (r >= 0)
3✔
1453
                        printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n",
6✔
1454
                               ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal());
3✔
1455

1456
                r = sd_bus_get_owner_creds(
3✔
1457
                                bus,
1458
                                (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
3✔
1459
                                &creds);
1460
        }
1461

1462
        if (r < 0)
5✔
1463
                return log_error_errno(r, "Failed to get credentials: %m");
1✔
1464

1465
        bus_creds_dump(creds, NULL, false);
4✔
1466
        return 0;
1467
}
1468

1469
static int message_append_cmdline(sd_bus_message *m, const char *signature, FDSet **passed_fdset, char ***x) {
1,183✔
1470
        char **p;
1,183✔
1471
        int r;
1,183✔
1472

1473
        assert(m);
1,183✔
1474
        assert(signature);
1,183✔
1475
        assert(passed_fdset);
1,183✔
1476
        assert(x);
1,183✔
1477

1478
        p = *x;
1,183✔
1479

1480
        for (;;) {
2,441✔
1481
                const char *v;
2,441✔
1482
                char t;
2,441✔
1483

1484
                t = *signature;
2,441✔
1485
                v = *p;
2,441✔
1486

1487
                if (t == 0)
2,441✔
1488
                        break;
1489
                if (!v)
1,263✔
1490
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1✔
1491
                                               "Too few parameters for signature.");
1492

1493
                signature++;
1,262✔
1494
                p++;
1,262✔
1495

1496
                switch (t) {
1,262✔
1497

1498
                case SD_BUS_TYPE_BOOLEAN:
12✔
1499

1500
                        r = parse_boolean(v);
12✔
1501
                        if (r < 0)
12✔
1502
                                return log_error_errno(r, "Failed to parse '%s' as boolean: %m", v);
×
1503

1504
                        r = sd_bus_message_append_basic(m, t, &r);
12✔
1505
                        break;
12✔
1506

1507
                case SD_BUS_TYPE_BYTE: {
1508
                        uint8_t z;
32✔
1509

1510
                        r = safe_atou8(v, &z);
32✔
1511
                        if (r < 0)
32✔
1512
                                return log_error_errno(r, "Failed to parse '%s' as byte (unsigned 8-bit integer): %m", v);
×
1513

1514
                        r = sd_bus_message_append_basic(m, t, &z);
32✔
1515
                        break;
32✔
1516
                }
1517

1518
                case SD_BUS_TYPE_INT16: {
×
1519
                        int16_t z;
×
1520

1521
                        r = safe_atoi16(v, &z);
×
1522
                        if (r < 0)
×
1523
                                return log_error_errno(r, "Failed to parse '%s' as signed 16-bit integer: %m", v);
×
1524

1525
                        r = sd_bus_message_append_basic(m, t, &z);
×
1526
                        break;
×
1527
                }
1528

1529
                case SD_BUS_TYPE_UINT16: {
1530
                        uint16_t z;
×
1531

1532
                        r = safe_atou16(v, &z);
×
1533
                        if (r < 0)
×
1534
                                return log_error_errno(r, "Failed to parse '%s' as unsigned 16-bit integer: %m", v);
×
1535

1536
                        r = sd_bus_message_append_basic(m, t, &z);
×
1537
                        break;
×
1538
                }
1539

1540
                case SD_BUS_TYPE_INT32: {
1541
                        int32_t z;
2✔
1542

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

1547
                        r = sd_bus_message_append_basic(m, t, &z);
2✔
1548
                        break;
2✔
1549
                }
1550

1551
                case SD_BUS_TYPE_UINT32: {
1552
                        uint32_t z;
1,005✔
1553

1554
                        r = safe_atou32(v, &z);
1,005✔
1555
                        if (r < 0)
1,005✔
1556
                                return log_error_errno(r, "Failed to parse '%s' as unsigned 32-bit integer: %m", v);
1✔
1557

1558
                        r = sd_bus_message_append_basic(m, t, &z);
1,004✔
1559
                        break;
1,004✔
1560
                }
1561

1562
                case SD_BUS_TYPE_INT64: {
1563
                        int64_t z;
×
1564

1565
                        r = safe_atoi64(v, &z);
×
1566
                        if (r < 0)
×
1567
                                return log_error_errno(r, "Failed to parse '%s' as signed 64-bit integer: %m", v);
×
1568

1569
                        r = sd_bus_message_append_basic(m, t, &z);
×
1570
                        break;
×
1571
                }
1572

1573
                case SD_BUS_TYPE_UINT64: {
1574
                        uint64_t z;
8✔
1575

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

1580
                        r = sd_bus_message_append_basic(m, t, &z);
7✔
1581
                        break;
7✔
1582
                }
1583

1584
                case SD_BUS_TYPE_DOUBLE: {
×
1585
                        double z;
×
1586

1587
                        r = safe_atod(v, &z);
×
1588
                        if (r < 0)
×
1589
                                return log_error_errno(r, "Failed to parse '%s' as double precision floating point: %m", v);
×
1590

1591
                        r = sd_bus_message_append_basic(m, t, &z);
×
1592
                        break;
×
1593
                }
1594

1595
                case SD_BUS_TYPE_STRING:
121✔
1596
                case SD_BUS_TYPE_OBJECT_PATH:
1597
                case SD_BUS_TYPE_SIGNATURE:
1598

1599
                        r = sd_bus_message_append_basic(m, t, v);
121✔
1600
                        break;
121✔
1601

1602
                case SD_BUS_TYPE_ARRAY: {
1603
                        uint32_t n;
40✔
1604
                        size_t k;
40✔
1605

1606
                        r = safe_atou32(v, &n);
40✔
1607
                        if (r < 0)
40✔
1608
                                return log_error_errno(r, "Failed to parse '%s' number of array entries: %m", v);
2✔
1609

1610
                        r = signature_element_length(signature, &k);
39✔
1611
                        if (r < 0)
39✔
1612
                                return log_error_errno(r, "Invalid array signature: %m");
×
1613

1614
                        {
39✔
1615
                                char s[k + 1];
39✔
1616
                                memcpy(s, signature, k);
39✔
1617
                                s[k] = 0;
39✔
1618

1619
                                r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
39✔
1620
                                if (r < 0)
39✔
1621
                                        return bus_log_create_error(r);
1✔
1622

1623
                                for (unsigned i = 0; i < n; i++) {
116✔
1624
                                        r = message_append_cmdline(m, s, passed_fdset, &p);
78✔
1625
                                        if (r < 0)
78✔
1626
                                                return r;
1627
                                }
1628
                        }
1629

1630
                        signature += k;
38✔
1631

1632
                        r = sd_bus_message_close_container(m);
38✔
1633
                        break;
38✔
1634
                }
1635

1636
                case SD_BUS_TYPE_VARIANT:
16✔
1637
                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
16✔
1638
                        if (r < 0)
16✔
1639
                                return bus_log_create_error(r);
×
1640

1641
                        r = message_append_cmdline(m, v, passed_fdset, &p);
16✔
1642
                        if (r < 0)
16✔
1643
                                return r;
1644

1645
                        r = sd_bus_message_close_container(m);
16✔
1646
                        break;
16✔
1647

1648
                case SD_BUS_TYPE_STRUCT_BEGIN:
24✔
1649
                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1650
                        size_t k;
24✔
1651

1652
                        signature--;
24✔
1653
                        p--;
24✔
1654

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

1662
                        {
24✔
1663
                                char s[k-1];
24✔
1664
                                memcpy(s, signature + 1, k - 2);
24✔
1665
                                s[k - 2] = 0;
24✔
1666

1667
                                const char ctype = t == SD_BUS_TYPE_STRUCT_BEGIN ?
24✔
1668
                                        SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
1669
                                r = sd_bus_message_open_container(m, ctype, s);
24✔
1670
                                if (r < 0)
24✔
1671
                                        return bus_log_create_error(r);
×
1672

1673
                                r = message_append_cmdline(m, s, passed_fdset, &p);
24✔
1674
                                if (r < 0)
24✔
1675
                                        return r;
1676
                        }
1677

1678
                        signature += k;
24✔
1679

1680
                        r = sd_bus_message_close_container(m);
24✔
1681
                        break;
24✔
1682
                }
1683

1684
                case SD_BUS_TYPE_UNIX_FD: {
2✔
1685
                        int fd;
2✔
1686

1687
                        fd = parse_fd(v);
2✔
1688
                        if (fd < 0)
2✔
1689
                                return log_error_errno(fd, "Failed to parse '%s' as a file descriptor: %m", v);
×
1690

1691
                        if (!*passed_fdset) {
2✔
1692
                                r = fdset_new_fill(/* filter_cloexec= */ 0, passed_fdset);
1✔
1693
                                if (r < 0)
1✔
1694
                                        return log_error_errno(r, "Failed to create fd set: %m");
×
1695
                        }
1696

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

1700
                        r = sd_bus_message_append_basic(m, t, &fd);
2✔
1701
                        break;
2✔
1702
                }
1703

1704
                default:
1705
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1706
                                               "Unknown signature type %c.", t);
1707
                }
1708

1709
                if (r < 0)
1,258✔
1710
                        return bus_log_create_error(r);
×
1711
        }
1712

1713
        *x = p;
1,178✔
1714
        return 0;
1,178✔
1715
}
1716

1717
static int bus_message_dump(sd_bus_message *m, uint64_t flags) {
115✔
1718
        const char *contents;
115✔
1719
        int r;
115✔
1720

1721
        assert(m);
115✔
1722

1723
        r = sd_bus_message_rewind(m, !FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY));
115✔
1724
        if (r < 0)
115✔
1725
                return log_error_errno(r, "Failed to rewind: %m");
115✔
1726

1727
        if (FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
115✔
1728
                r = sd_bus_message_peek_type(m, /* ret_type= */ NULL, &contents);
56✔
1729
                if (r < 0)
56✔
1730
                        return bus_log_parse_error(r);
×
1731

1732
                r = sd_bus_message_enter_container(m, 'v', contents);
56✔
1733
                if (r < 0)
56✔
1734
                        return bus_log_parse_error(r);
×
1735
        } else {
1736
                r = sd_bus_message_is_empty(m);
59✔
1737
                if (r < 0)
59✔
1738
                        return bus_log_parse_error(r);
×
1739
                if (r > 0 || arg_quiet)
59✔
1740
                        return 0;
1741
        }
1742

1743
        if (sd_json_format_enabled(arg_json_format_flags)) {
115✔
1744
                _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
19✔
1745

1746
                if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
19✔
1747
                        pager_open(arg_pager_flags);
9✔
1748

1749
                r = sd_bus_message_dump_json(m, flags, &v);
19✔
1750
                if (r < 0)
19✔
1751
                        return log_error_errno(r, "Failed to dump DBus message to JSON object: %m");
×
1752

1753
                r = sd_json_variant_dump(v, arg_json_format_flags, NULL, NULL);
19✔
1754
                if (r < 0)
19✔
1755
                        return log_error_errno(r, "Failed to dump JSON object: %m");
×
1756

1757
        } else if (arg_verbose) {
96✔
1758
                pager_open(arg_pager_flags);
5✔
1759

1760
                r = sd_bus_message_dump(m, NULL, flags);
5✔
1761
                if (r < 0)
5✔
1762
                        return log_error_errno(r, "Failed to dump DBus message: %m");
×
1763
        } else {
1764

1765
                fputs(FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY) ? contents : sd_bus_message_get_signature(m, true), stdout);
91✔
1766
                fputc(' ', stdout);
91✔
1767

1768
                r = format_cmdline(m, stdout, /* needs_space= */ false);
91✔
1769
                if (r < 0)
91✔
1770
                        return bus_log_parse_error(r);
×
1771

1772
                fputc('\n', stdout);
91✔
1773
        }
1774

1775
        if (FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
115✔
1776
                r = sd_bus_message_exit_container(m);
56✔
1777
                if (r < 0)
56✔
1778
                        return bus_log_parse_error(r);
×
1779
        }
1780

1781
        return 0;
1782
}
1783

1784
static int call(int argc, char **argv, void *userdata) {
1,067✔
1785
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1,067✔
1786
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
1787
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
2,134✔
1788
        _cleanup_fdset_free_ FDSet *passed_fdset = NULL;
1,067✔
1789
        int r;
1,067✔
1790

1791
        r = acquire_bus(false, &bus);
1,067✔
1792
        if (r < 0)
1,067✔
1793
                return r;
1794

1795
        if (!service_name_is_valid(argv[1]))
1,067✔
1796
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]);
×
1797
        if (!object_path_is_valid(argv[2]))
1,067✔
1798
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]);
×
1799
        if (!interface_name_is_valid(argv[3]))
1,067✔
1800
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]);
×
1801
        if (!member_name_is_valid(argv[4]))
1,067✔
1802
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid member name: %s", argv[4]);
×
1803

1804
        r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1,067✔
1805
        if (r < 0)
1,067✔
1806
                return bus_log_create_error(r);
×
1807

1808
        r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1,067✔
1809
        if (r < 0)
1,067✔
1810
                return bus_log_create_error(r);
×
1811

1812
        r = sd_bus_message_set_auto_start(m, arg_auto_start);
1,067✔
1813
        if (r < 0)
1,067✔
1814
                return bus_log_create_error(r);
×
1815

1816
        r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1,067✔
1817
        if (r < 0)
1,067✔
1818
                return bus_log_create_error(r);
×
1819

1820
        if (!isempty(argv[5])) {
1,067✔
1821
                char **p;
1,058✔
1822

1823
                p = argv+6;
1,058✔
1824

1825
                r = message_append_cmdline(m, argv[5], &passed_fdset, &p);
1,058✔
1826
                if (r < 0)
1,058✔
1827
                        return r;
3✔
1828

1829
                if (*p)
1,055✔
1830
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1831
                                               "Too many parameters for signature.");
1832
        }
1833

1834
        if (!arg_expect_reply) {
1,064✔
1835
                r = sd_bus_send(bus, m, NULL);
×
1836
                if (r < 0)
×
1837
                        return log_error_errno(r, "Failed to send message: %m");
×
1838

1839
                return 0;
1840
        }
1841

1842
        r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1,064✔
1843
        if (r < 0) {
1,064✔
1844
                notify_bus_error(&error);
1,006✔
1845
                return log_error_errno(r, "Call failed: %s", bus_error_message(&error, r));
1,006✔
1846
        }
1847

1848
        return bus_message_dump(reply, /* flags= */ 0);
58✔
1849
}
1850

1851
static int emit_signal(int argc, char **argv, void *userdata) {
3✔
1852
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
3✔
1853
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
3✔
1854
        _cleanup_fdset_free_ FDSet *passed_fdset = NULL;
3✔
1855
        int r;
3✔
1856

1857
        r = acquire_bus(false, &bus);
3✔
1858
        if (r < 0)
3✔
1859
                return r;
1860

1861
        r = sd_bus_message_new_signal(bus, &m, argv[1], argv[2], argv[3]);
3✔
1862
        if (r < 0)
3✔
1863
                return bus_log_create_error(r);
×
1864

1865
        if (arg_destination) {
3✔
1866
                r = sd_bus_message_set_destination(m, arg_destination);
1✔
1867
                if (r < 0)
1✔
1868
                        return bus_log_create_error(r);
×
1869
        }
1870

1871
        r = sd_bus_message_set_auto_start(m, arg_auto_start);
3✔
1872
        if (r < 0)
3✔
1873
                return bus_log_create_error(r);
×
1874

1875
        if (!isempty(argv[4])) {
3✔
1876
                char **p;
3✔
1877

1878
                p = argv+5;
3✔
1879

1880
                r = message_append_cmdline(m, argv[4], &passed_fdset, &p);
3✔
1881
                if (r < 0)
3✔
1882
                        return r;
×
1883

1884
                if (*p)
3✔
1885
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1886
                                               "Too many parameters for signature.");
1887
        }
1888

1889
        r = sd_bus_send(bus, m, NULL);
3✔
1890
        if (r < 0)
3✔
1891
                return log_error_errno(r, "Failed to send signal: %m");
×
1892

1893
        return 0;
1894
}
1895

1896
static int get_property(int argc, char **argv, void *userdata) {
51✔
1897
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
51✔
1898
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
51✔
1899
        int r;
51✔
1900

1901
        if (!service_name_is_valid(argv[1]))
51✔
1902
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]);
1✔
1903
        if (!object_path_is_valid(argv[2]))
50✔
1904
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]);
1✔
1905
        if (!interface_name_is_valid(argv[3]))
49✔
1906
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]);
1✔
1907

1908
        r = acquire_bus(false, &bus);
48✔
1909
        if (r < 0)
48✔
1910
                return r;
1911

1912
        STRV_FOREACH(i, argv + 4) {
104✔
1913
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
58✔
1914

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

1925
                r = bus_message_dump(reply, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY);
56✔
1926
                if (r < 0)
56✔
1927
                        return r;
1928
        }
1929

1930
        return 0;
1931
}
1932

1933
static int on_bus_signal(sd_bus_message *msg, void *userdata, sd_bus_error *ret_error) {
1✔
1934
        return sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(ASSERT_PTR(msg))),
1✔
1935
                             bus_message_dump(msg, /* flags= */ 0));
1936
}
1937

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

1944
        const char *sender = argc == 5 ? argv[argn++] : NULL;
1✔
1945
        const char *path = argv[argn++];
1✔
1946
        const char *interface = argv[argn++];
1✔
1947
        const char *member = argv[argn++];
1✔
1948

1949
        if (sender && !service_name_is_valid(sender))
1✔
1950
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", sender);
×
1951
        if (!object_path_is_valid(path))
1✔
1952
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", path);
×
1953
        if (!interface_name_is_valid(interface))
1✔
1954
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", interface);
×
1955
        if (!member_name_is_valid(member))
1✔
1956
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid member name: %s", member);
×
1957

1958
        r = acquire_bus(/* set_monitor= */ false, &bus);
1✔
1959
        if (r < 0)
1✔
1960
                return r;
1961

1962
        r = sd_bus_match_signal(bus, NULL, sender, path, interface, member, on_bus_signal, NULL);
1✔
1963
        if (r < 0)
1✔
1964
                return log_error_errno(r, "Failed to match signal %s on interface %s: %m", member, interface);
×
1965

1966
        r = sd_event_new(&e);
1✔
1967
        if (r < 0)
1✔
1968
                return log_error_errno(r, "Failed to allocate event loop: %m\n");
×
1969

1970
        r = sd_bus_attach_event(bus, e, SD_EVENT_PRIORITY_NORMAL);
1✔
1971
        if (r < 0)
1✔
1972
                return log_error_errno(r, "Failed to attach bus event: %m\n");
×
1973

1974
        if (arg_timeout) {
1✔
1975
                r = sd_event_add_time_relative(e, &timer, CLOCK_MONOTONIC, arg_timeout, 0, NULL, NULL);
1✔
1976
                if (r < 0)
1✔
1977
                        return log_error_errno(r, "Failed to schedule timeout: %m\n");
×
1978
        }
1979

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

1983
        return sd_event_loop(e);
1✔
1984
}
1985

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

1994
        if (!service_name_is_valid(argv[1]))
4✔
1995
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]);
×
1996
        if (!object_path_is_valid(argv[2]))
4✔
1997
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]);
×
1998
        if (!interface_name_is_valid(argv[3]))
4✔
1999
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]);
×
2000

2001
        r = acquire_bus(false, &bus);
4✔
2002
        if (r < 0)
4✔
2003
                return r;
2004

2005
        r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2],
4✔
2006
                                           "org.freedesktop.DBus.Properties", "Set");
2007
        if (r < 0)
4✔
2008
                return bus_log_create_error(r);
×
2009

2010
        r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
4✔
2011
        if (r < 0)
4✔
2012
                return bus_log_create_error(r);
×
2013

2014
        r = sd_bus_message_open_container(m, 'v', argv[5]);
4✔
2015
        if (r < 0)
4✔
2016
                return bus_log_create_error(r);
×
2017

2018
        p = argv + 6;
4✔
2019
        r = message_append_cmdline(m, argv[5], &passed_fdset, &p);
4✔
2020
        if (r < 0)
4✔
2021
                return r;
2022

2023
        r = sd_bus_message_close_container(m);
3✔
2024
        if (r < 0)
3✔
2025
                return bus_log_create_error(r);
×
2026

2027
        if (*p)
3✔
2028
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
×
2029

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

2038
        return 0;
2039
}
2040

2041
static int help(void) {
2✔
2042
        _cleanup_free_ char *link = NULL;
2✔
2043
        int r;
2✔
2044

2045
        r = terminal_urlify_man("busctl", "1", &link);
2✔
2046
        if (r < 0)
2✔
2047
                return log_oom();
×
2048

2049
        pager_open(arg_pager_flags);
2✔
2050

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

2114
        return 0;
2115
}
2116

2117
static int verb_help(int argc, char **argv, void *userdata) {
1✔
2118
        return help();
1✔
2119
}
2120

2121
static int parse_argv(int argc, char *argv[]) {
1,159✔
2122

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

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

2183
        int c, r;
1,159✔
2184

2185
        assert(argc >= 0);
1,159✔
2186
        assert(argv);
1,159✔
2187

2188
        while ((c = getopt_long(argc, argv, "hH:M:C:J:qjlN:", options, NULL)) >= 0)
1,209✔
2189

2190
                switch (c) {
52✔
2191

2192
                case 'h':
1✔
2193
                        return help();
1✔
2194

2195
                case ARG_VERSION:
1✔
2196
                        return version();
1✔
2197

2198
                case ARG_NO_PAGER:
7✔
2199
                        arg_pager_flags |= PAGER_DISABLE;
7✔
2200
                        break;
7✔
2201

2202
                case ARG_NO_LEGEND:
1✔
2203
                        arg_legend = false;
1✔
2204
                        break;
1✔
2205

2206
                case 'l':
1✔
2207
                        arg_full = true;
1✔
2208
                        break;
1✔
2209

2210
                case ARG_USER:
1✔
2211
                        arg_runtime_scope = RUNTIME_SCOPE_USER;
1✔
2212
                        break;
1✔
2213

2214
                case ARG_SYSTEM:
×
2215
                        arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
×
2216
                        break;
×
2217

2218
                case ARG_ADDRESS:
×
2219
                        arg_address = optarg;
×
2220
                        break;
×
2221

2222
                case ARG_SHOW_MACHINE:
1✔
2223
                        arg_show_machine = true;
1✔
2224
                        break;
1✔
2225

2226
                case ARG_UNIQUE:
1✔
2227
                        arg_unique = true;
1✔
2228
                        break;
1✔
2229

2230
                case ARG_ACQUIRED:
1✔
2231
                        arg_acquired = true;
1✔
2232
                        break;
1✔
2233

2234
                case ARG_ACTIVATABLE:
1✔
2235
                        arg_activatable = true;
1✔
2236
                        break;
1✔
2237

2238
                case ARG_MATCH:
2✔
2239
                        if (strv_extend(&arg_matches, optarg) < 0)
2✔
2240
                                return log_oom();
×
2241
                        break;
2242

2243
                case ARG_SIZE: {
×
2244
                        uint64_t sz;
×
2245

2246
                        r = parse_size(optarg, 1024, &sz);
×
2247
                        if (r < 0)
×
2248
                                return log_error_errno(r, "Failed to parse size '%s': %m", optarg);
×
2249

2250
                        if ((uint64_t) (size_t) sz !=  sz)
×
2251
                                return log_error_errno(SYNTHETIC_ERRNO(E2BIG),
2252
                                                       "Size out of range.");
2253

2254
                        arg_snaplen = (size_t) sz;
×
2255
                        break;
×
2256
                }
2257

2258
                case ARG_LIST:
1✔
2259
                        arg_list = true;
1✔
2260
                        break;
1✔
2261

2262
                case 'H':
×
2263
                        arg_transport = BUS_TRANSPORT_REMOTE;
×
2264
                        arg_host = optarg;
×
2265
                        break;
×
2266

2267
                case 'M':
2✔
2268
                        r = parse_machine_argument(optarg, &arg_host, &arg_transport);
2✔
2269
                        if (r < 0)
2✔
2270
                                return r;
2271
                        break;
2272

2273
                case 'C':
1✔
2274
                        r = capsule_name_is_valid(optarg);
1✔
2275
                        if (r < 0)
1✔
2276
                                return log_error_errno(r, "Unable to validate capsule name '%s': %m", optarg);
×
2277
                        if (r == 0)
1✔
2278
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", optarg);
×
2279

2280
                        arg_host = optarg;
1✔
2281
                        arg_transport = BUS_TRANSPORT_CAPSULE;
1✔
2282
                        break;
1✔
2283

2284
                case 'q':
2✔
2285
                        arg_quiet = true;
2✔
2286
                        break;
2✔
2287

2288
                case ARG_VERBOSE:
2✔
2289
                        arg_verbose = true;
2✔
2290
                        break;
2✔
2291

2292
                case ARG_XML_INTERFACE:
1✔
2293
                        arg_xml_interface = true;
1✔
2294
                        break;
1✔
2295

2296
                case ARG_EXPECT_REPLY:
1✔
2297
                        r = parse_boolean_argument("--expect-reply=", optarg, &arg_expect_reply);
1✔
2298
                        if (r < 0)
1✔
2299
                                return r;
2300
                        break;
2301

2302
                case ARG_AUTO_START:
1✔
2303
                        r = parse_boolean_argument("--auto-start=", optarg, &arg_auto_start);
1✔
2304
                        if (r < 0)
1✔
2305
                                return r;
2306
                        break;
2307

2308
                case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1✔
2309
                        r = parse_boolean_argument("--allow-interactive-authorization=", optarg,
1✔
2310
                                                   &arg_allow_interactive_authorization);
2311
                        if (r < 0)
1✔
2312
                                return r;
2313
                        break;
2314

2315
                case ARG_TIMEOUT:
4✔
2316
                        if (isempty(optarg)) {
4✔
2317
                                arg_timeout = 0; /* Reset to default */
×
2318
                                break;
×
2319
                        }
2320

2321
                        r = parse_sec(optarg, &arg_timeout);
4✔
2322
                        if (r < 0)
4✔
2323
                                return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", optarg);
×
2324

2325
                        break;
2326

2327
                case ARG_AUGMENT_CREDS:
1✔
2328
                        r = parse_boolean_argument("--augment-creds=", optarg, &arg_augment_creds);
1✔
2329
                        if (r < 0)
1✔
2330
                                return r;
2331
                        break;
2332

2333
                case ARG_WATCH_BIND:
1✔
2334
                        r = parse_boolean_argument("--watch-bind=", optarg, &arg_watch_bind);
1✔
2335
                        if (r < 0)
1✔
2336
                                return r;
2337
                        break;
2338

2339
                case 'j':
4✔
2340
                        arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO;
4✔
2341
                        break;
4✔
2342

2343
                case ARG_JSON:
10✔
2344
                        r = parse_json_argument(optarg, &arg_json_format_flags);
10✔
2345
                        if (r <= 0)
10✔
2346
                                return r;
2347

2348
                        break;
2349

2350
                case ARG_DESTINATION:
1✔
2351
                        arg_destination = optarg;
1✔
2352
                        break;
1✔
2353

2354
                case 'N':
1✔
2355
                        if (isempty(optarg)) {
1✔
2356
                                arg_limit_messages = UINT64_MAX; /* Reset to default */
×
2357
                                break;
×
2358
                        }
2359

2360
                        r = safe_atou64(optarg, &arg_limit_messages);
1✔
2361
                        if (r < 0)
1✔
2362
                                return log_error_errno(r, "Failed to parse --limit-messages= parameter: %s", optarg);
×
2363
                        if (arg_limit_messages == 0)
1✔
2364
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--limit-messages= parameter cannot be 0");
×
2365

2366
                        break;
2367

2368
                case '?':
2369
                        return -EINVAL;
2370

2371
                default:
×
2372
                        assert_not_reached();
×
2373
                }
2374

2375
        if (arg_full < 0)
1,157✔
2376
                arg_full = terminal_is_dumb();
1,156✔
2377

2378
        return 1;
2379
}
2380

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

2398
        return dispatch_verb(argc, argv, verbs, NULL);
1,157✔
2399
}
2400

2401
static int run(int argc, char *argv[]) {
1,159✔
2402
        int r;
1,159✔
2403

2404
        log_setup();
1,159✔
2405

2406
        r = parse_argv(argc, argv);
1,159✔
2407
        if (r <= 0)
1,159✔
2408
                return r;
2409

2410
        return busctl_main(argc, argv);
1,157✔
2411
}
2412

2413
DEFINE_MAIN_FUNCTION(run);
1,159✔
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