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

systemd / systemd / 15057632786

15 May 2025 09:01PM UTC coverage: 72.267% (+0.02%) from 72.244%
15057632786

push

github

bluca
man: document how to hook stuff into system wakeup

Fixes: #6364

298523 of 413084 relevant lines covered (72.27%)

738132.88 hits per line

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

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

3
#include <getopt.h>
4

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

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

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

73
STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
1,170✔
74

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

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

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

87
        (void) sd_bus_set_description(bus, "busctl");
1,163✔
88

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

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

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

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

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

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

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

121
                case BUS_TRANSPORT_LOCAL:
1,160✔
122

123
                        switch (arg_runtime_scope) {
1,160✔
124

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

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

133
                        default:
×
134
                                assert_not_reached();
×
135
                        }
136

137
                        break;
138

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

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

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

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

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

161
        *ret = TAKE_PTR(bus);
1,163✔
162

163
        return 0;
1,163✔
164
}
165

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

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

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

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

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

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

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

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

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

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

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

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

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

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

245
        table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
6✔
246

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

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

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

274
        HASHMAP_FOREACH_KEY(v, k, names) {
119✔
275
                _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
113✔
276

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

293
                        continue;
41✔
294
                }
295

296
                assert(v == NAME_IS_ACQUIRED);
72✔
297

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

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

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

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

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

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

329
                                (void) sd_bus_creds_get_comm(creds, &comm);
58✔
330

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

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

343
                                u = uid_to_name(uid);
58✔
344
                                if (!u)
58✔
345
                                        return log_oom();
×
346

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

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

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

368
                if (arg_show_machine) {
58✔
369
                        sd_id128_t mid;
8✔
370

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

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

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

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

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

398
                if (!streq(*l, path))
655✔
399
                        break;
400

401
                l++;
334✔
402
        }
403

404
        const char
321✔
405
                *vertical = strjoina(prefix, glyph(GLYPH_TREE_VERTICAL)),
1,605✔
406
                *space = strjoina(prefix, glyph(GLYPH_TREE_SPACE));
1,605✔
407

408
        for (;;) {
321✔
409
                bool has_more = false;
642✔
410
                char **n;
642✔
411

412
                if (!*l || !path_startswith(*l, path))
642✔
413
                        break;
414

415
                n = l + 1;
321✔
416
                for (;;) {
2,579✔
417
                        if (!*n || !path_startswith(*n, path))
1,450✔
418
                                break;
419

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

425
                        n++;
1,129✔
426
                }
427

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

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

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

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

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

457
        return 0;
458
}
459

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

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

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

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

486
        return parse_xml_introspect(path, xml, &ops, paths);
345✔
487
}
488

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

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

498
        for (;;) {
706✔
499
                _cleanup_free_ char *p = NULL;
345✔
500
                int q;
706✔
501

502
                p = set_steal_first(paths);
706✔
503
                if (!p)
706✔
504
                        break;
505

506
                if (set_contains(done, p) ||
691✔
507
                    set_contains(failed, p))
346✔
508
                        continue;
345✔
509

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

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

520
        pager_open(arg_pager_flags);
15✔
521

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

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

529
        fflush(stdout);
15✔
530

531
        return r;
532
}
533

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

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

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

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

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

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

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

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

571
                pager_open(arg_pager_flags);
1✔
572

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

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

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

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

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

589
        return r;
590
}
591

592
static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
367✔
593
        int r;
821✔
594

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

611
                r = sd_bus_message_peek_type(m, &type, &contents);
821✔
612
                if (r < 0)
821✔
613
                        return r;
367✔
614
                if (r == 0)
821✔
615
                        return needs_space;
367✔
616

617
                if (bus_type_is_container(type) > 0) {
454✔
618

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

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

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

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

635
                                        n++;
49✔
636
                                }
637

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

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

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

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

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

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

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

661
                        needs_space = r > 0;
15✔
662

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

667
                        continue;
15✔
668
                }
669

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

674
                if (needs_space)
439✔
675
                        fputc(' ', f);
95✔
676

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

682
                case SD_BUS_TYPE_BOOLEAN:
19✔
683
                        fputs(true_false(basic.i), f);
30✔
684
                        break;
685

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

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

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

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

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

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

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

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

719
                        b = cescape(basic.string);
178✔
720
                        if (!b)
178✔
721
                                return -ENOMEM;
×
722

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

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

731
                default:
×
732
                        assert_not_reached();
×
733
                }
734

735
                needs_space = true;
439✔
736
        }
737
}
738

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

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

753
        assert(m);
1,432✔
754
        assert(m->type);
1,432✔
755

756
        string_hash_func(m->type, state);
1,432✔
757

758
        arity += !!m->name + !!m->interface;
1,432✔
759

760
        uint64_hash_func(&arity, state);
1,432✔
761

762
        if (m->name)
1,432✔
763
                string_hash_func(m->name, state);
1,390✔
764

765
        if (m->signature)
1,432✔
766
                string_hash_func(m->signature, state);
1,292✔
767

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

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

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

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

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

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

792
        return strcmp_ptr(x->signature, y->signature);
248✔
793
}
794

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

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

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

813
        assert(interface);
8✔
814

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

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

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

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

835
        return 0;
836
}
837

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

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

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

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

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

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

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

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

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

878
        return 0;
879
}
880

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

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

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

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

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

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

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

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

917
        return 0;
918
}
919

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

925
        assert(interface);
248✔
926
        assert(name);
248✔
927

928
        m = new(Member, 1);
248✔
929
        if (!m)
248✔
930
                return log_oom();
×
931

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

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

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

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

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

957
        return 0;
958
}
959

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

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

976
        assert(m);
449✔
977
        assert(ret);
449✔
978

979
        _cleanup_free_ char *str = NULL;
449✔
980
        for (size_t i = 0; i < ELEMENTSOF(map); i++)
3,592✔
981
                if (BIT_SET(m->flags, i) && map[i])
3,143✔
982
                        if (!strextend_with_separator(&str, " ", map[i]))
202✔
983
                                return -ENOMEM;
984

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

989
        *ret = TAKE_PTR(str);
449✔
990
        return 0;
449✔
991
}
992

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

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

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

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

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

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

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

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

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

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

1049
                if (m->value)
248✔
1050
                        continue;
246✔
1051

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

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

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

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

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

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

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

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

1096
                        mf = memstream_init(&ms);
248✔
1097
                        if (!mf)
248✔
1098
                                return log_oom();
×
1099

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

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

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

1116
                        r = sd_bus_message_exit_container(reply);
248✔
1117
                        if (r < 0)
248✔
1118
                                return bus_log_parse_error(r);
×
1119

1120
                        r = sd_bus_message_exit_container(reply);
248✔
1121
                        if (r < 0)
248✔
1122
                                return bus_log_parse_error(r);
×
1123
                }
1124

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

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

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

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

1146
        FOREACH_ARRAY(p, sorted, n) {
462✔
1147
                bool is_interface;
460✔
1148

1149
                m = *p;
460✔
1150

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

1154
                is_interface = streq(m->type, "interface");
450✔
1155

1156
                if (argv[3] && is_interface)
450✔
1157
                        continue;
1✔
1158

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

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

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

1185
        pager_open(arg_pager_flags);
2✔
1186

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

1191
        return 0;
1192
}
1193

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

1197
        assert(m);
×
1198

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

1203
        return 0;
1204
}
1205

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

1209
        assert(m);
×
1210

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

1215
        return 0;
1216
}
1217

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

1222
        assert(m);
×
1223

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

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

1232
        return 0;
1233
}
1234

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1341
                                continue;
2✔
1342
                        }
1343

1344
                        dump(m, stdout);
×
1345
                        fflush(stdout);
×
1346

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

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

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

1363
                        continue;
×
1364
                }
1365

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

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

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

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

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

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

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

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

1408
        return r;
1409
}
1410

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

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

1421
        pager_open(arg_pager_flags);
5✔
1422

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

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

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

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

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

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

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

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

1470
        assert(m);
1,156✔
1471
        assert(signature);
1,156✔
1472
        assert(passed_fdset);
1,156✔
1473
        assert(x);
1,156✔
1474

1475
        p = *x;
1,156✔
1476

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

1481
                t = *signature;
2,377✔
1482
                v = *p;
2,377✔
1483

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

1490
                signature++;
1,225✔
1491
                p++;
1,225✔
1492

1493
                switch (t) {
1,225✔
1494

1495
                case SD_BUS_TYPE_BOOLEAN:
12✔
1496

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

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

1504
                case SD_BUS_TYPE_BYTE: {
1505
                        uint8_t z;
×
1506

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

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

1515
                case SD_BUS_TYPE_INT16: {
×
1516
                        int16_t z;
×
1517

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

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

1526
                case SD_BUS_TYPE_UINT16: {
1527
                        uint16_t z;
×
1528

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

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

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

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

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

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

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

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

1559
                case SD_BUS_TYPE_INT64: {
1560
                        int64_t z;
×
1561

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

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

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

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

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

1581
                case SD_BUS_TYPE_DOUBLE: {
×
1582
                        double z;
×
1583

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

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

1592
                case SD_BUS_TYPE_STRING:
120✔
1593
                case SD_BUS_TYPE_OBJECT_PATH:
1594
                case SD_BUS_TYPE_SIGNATURE:
1595

1596
                        r = sd_bus_message_append_basic(m, t, v);
120✔
1597
                        break;
120✔
1598

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

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

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

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

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

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

1627
                        signature += k;
36✔
1628

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

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

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

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

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

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

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

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

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

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

1675
                        signature += k;
24✔
1676

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

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

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

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

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

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

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

1706
                if (r < 0)
1,221✔
1707
                        return bus_log_create_error(r);
×
1708
        }
1709

1710
        *x = p;
1,151✔
1711
        return 0;
1,151✔
1712
}
1713

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

1718
        assert(m);
127✔
1719

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

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

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

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

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

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

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

1754
        } else if (arg_verbose) {
109✔
1755
                pager_open(arg_pager_flags);
5✔
1756

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

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

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

1769
                fputc('\n', stdout);
104✔
1770
        }
1771

1772
        if (FLAGS_SET(flags, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
126✔
1773
                r = sd_bus_message_exit_container(m);
62✔
1774
                if (r < 0)
62✔
1775
                        return bus_log_parse_error(r);
×
1776
        }
1777

1778
        return 0;
1779
}
1780

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

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

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

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

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

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

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

1817
        if (!isempty(argv[5])) {
1,072✔
1818
                char **p;
1,063✔
1819

1820
                p = argv+6;
1,063✔
1821

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

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

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

1836
                return 0;
1837
        }
1838

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

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

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

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

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

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

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

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

1875
                p = argv+5;
3✔
1876

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

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

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

1890
        return 0;
1891
}
1892

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

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

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

1909
        STRV_FOREACH(i, argv + 4) {
116✔
1910
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
64✔
1911

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

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

1927
        return 0;
1928
}
1929

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2035
        return 0;
2036
}
2037

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

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

2046
        pager_open(arg_pager_flags);
2✔
2047

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

2111
        return 0;
2112
}
2113

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

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

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

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

2180
        int c, r;
1,170✔
2181

2182
        assert(argc >= 0);
1,170✔
2183
        assert(argv);
1,170✔
2184

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

2187
                switch (c) {
50✔
2188

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

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

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

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

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

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

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

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

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

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

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

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

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

2240
                case ARG_SIZE: {
×
2241
                        uint64_t sz;
×
2242

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2321
                        break;
2322

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

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

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

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

2344
                        break;
2345

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

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

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

2362
                        break;
2363

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

2367
                default:
×
2368
                        assert_not_reached();
×
2369
                }
2370

2371
        if (arg_full < 0)
1,168✔
2372
                arg_full = terminal_is_dumb();
1,167✔
2373

2374
        return 1;
2375
}
2376

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

2394
        return dispatch_verb(argc, argv, verbs, NULL);
1,168✔
2395
}
2396

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

2400
        log_setup();
1,170✔
2401

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

2406
        return busctl_main(argc, argv);
1,168✔
2407
}
2408

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