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

systemd / systemd / 14072511923

25 Mar 2025 07:34PM UTC coverage: 71.954% (+0.03%) from 71.927%
14072511923

push

github

web-flow
tools/check-version-history: avoid DeprecationWarning with newer lxml (#36860)

We get the same warning thousands of times:
/work/src/tools/check-version-history.py:28: FutureWarning: This search
incorrectly ignores the root element, and will be fixed in a future
version. If you rely on the current behaviour, change it to

"./refsynopsisdiv/funcsynopsis/funcprototype/funcdef/function[.='udev_device_get_properties_list_entry']"

We also need to update the ignorelist to the new form.

296652 of 412279 relevant lines covered (71.95%)

716218.11 hits per line

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

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

3
#include <getopt.h>
4

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

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

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

70
STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
1,165✔
71

72
#define NAME_IS_ACQUIRED INT_TO_PTR(1)
73
#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
74

75
static int json_transform_message(sd_bus_message *m, sd_json_variant **ret);
76

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

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

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

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

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

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

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

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

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

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

120
                case BUS_TRANSPORT_LOCAL:
1,158✔
121

122
                        switch (arg_runtime_scope) {
1,158✔
123

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

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

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

136
                        break;
137

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

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

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

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

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

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

162
        return 0;
1,161✔
163
}
164

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

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

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

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

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

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

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

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

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

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

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

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

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

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

244
        table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
6✔
245

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

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

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

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

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

292
                        continue;
41✔
293
                }
294

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

400
                l++;
331✔
401
        }
402

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

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

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

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

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

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

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

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

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

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

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

456
        return 0;
457
}
458

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

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

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

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

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

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

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

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

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

505
                if (set_contains(done, p) ||
685✔
506
                    set_contains(failed, p))
343✔
507
                        continue;
342✔
508

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

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

519
        pager_open(arg_pager_flags);
15✔
520

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

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

528
        fflush(stdout);
15✔
529

530
        return r;
531
}
532

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

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

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

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

550
        if (argc <= 1) {
10✔
551
                _cleanup_strv_free_ char **names = NULL;
1✔
552
                bool not_first = false;
1✔
553

554
                r = sd_bus_list_names(bus, &names, NULL);
1✔
555
                if (r < 0)
1✔
556
                        return log_error_errno(r, "Failed to get name list: %m");
×
557

558
                pager_open(arg_pager_flags);
1✔
559

560
                STRV_FOREACH(i, names) {
15✔
561
                        int q;
14✔
562

563
                        if (!arg_unique && (*i)[0] == ':')
14✔
564
                                continue;
8✔
565

566
                        if (!arg_acquired && (*i)[0] == ':')
6✔
567
                                continue;
×
568

569
                        if (not_first)
6✔
570
                                printf("\n");
5✔
571

572
                        printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
18✔
573

574
                        q = tree_one(bus, *i);
6✔
575
                        if (q < 0 && r >= 0)
6✔
576
                                r = q;
×
577

578
                        not_first = true;
579
                }
580
        } else
581
                STRV_FOREACH(i, strv_skip(argv, 1)) {
18✔
582
                        int q;
9✔
583

584
                        if (i > argv+1)
9✔
585
                                printf("\n");
×
586

587
                        if (argv[2]) {
9✔
588
                                pager_open(arg_pager_flags);
×
589
                                printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
×
590
                        }
591

592
                        q = tree_one(bus, *i);
9✔
593
                        if (q < 0 && r >= 0)
9✔
594
                                r = q;
1✔
595
                }
596

597
        return r;
598
}
599

600
static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
369✔
601
        int r;
824✔
602

603
        for (;;) {
824✔
604
                const char *contents = NULL;
824✔
605
                char type;
824✔
606
                union {
824✔
607
                        uint8_t u8;
608
                        uint16_t u16;
609
                        int16_t s16;
610
                        uint32_t u32;
611
                        int32_t s32;
612
                        uint64_t u64;
613
                        int64_t s64;
614
                        double d64;
615
                        const char *string;
616
                        int i;
617
                } basic;
618

619
                r = sd_bus_message_peek_type(m, &type, &contents);
824✔
620
                if (r < 0)
824✔
621
                        return r;
369✔
622
                if (r == 0)
824✔
623
                        return needs_space;
369✔
624

625
                if (bus_type_is_container(type) > 0) {
455✔
626

627
                        r = sd_bus_message_enter_container(m, type, contents);
15✔
628
                        if (r < 0)
15✔
629
                                return r;
630

631
                        if (type == SD_BUS_TYPE_ARRAY) {
15✔
632
                                unsigned n = 0;
633

634
                                /* count array entries */
635
                                for (;;) {
107✔
636

637
                                        r = sd_bus_message_skip(m, contents);
58✔
638
                                        if (r < 0)
58✔
639
                                                return r;
640
                                        if (r == 0)
58✔
641
                                                break;
642

643
                                        n++;
49✔
644
                                }
645

646
                                r = sd_bus_message_rewind(m, false);
9✔
647
                                if (r < 0)
9✔
648
                                        return r;
649

650
                                if (needs_space)
9✔
651
                                        fputc(' ', f);
1✔
652

653
                                fprintf(f, "%u", n);
9✔
654
                                needs_space = true;
655

656
                        } else if (type == SD_BUS_TYPE_VARIANT) {
6✔
657

658
                                if (needs_space)
×
659
                                        fputc(' ', f);
×
660

661
                                fprintf(f, "%s", contents);
×
662
                                needs_space = true;
663
                        }
664

665
                        r = format_cmdline(m, f, needs_space);
15✔
666
                        if (r < 0)
15✔
667
                                return r;
668

669
                        needs_space = r > 0;
15✔
670

671
                        r = sd_bus_message_exit_container(m);
15✔
672
                        if (r < 0)
15✔
673
                                return r;
674

675
                        continue;
15✔
676
                }
677

678
                r = sd_bus_message_read_basic(m, type, &basic);
440✔
679
                if (r < 0)
440✔
680
                        return r;
681

682
                if (needs_space)
440✔
683
                        fputc(' ', f);
94✔
684

685
                switch (type) {
440✔
686
                case SD_BUS_TYPE_BYTE:
6✔
687
                        fprintf(f, "%u", basic.u8);
6✔
688
                        break;
689

690
                case SD_BUS_TYPE_BOOLEAN:
23✔
691
                        fputs(true_false(basic.i), f);
36✔
692
                        break;
693

694
                case SD_BUS_TYPE_INT16:
×
695
                        fprintf(f, "%i", basic.s16);
×
696
                        break;
697

698
                case SD_BUS_TYPE_UINT16:
×
699
                        fprintf(f, "%u", basic.u16);
×
700
                        break;
701

702
                case SD_BUS_TYPE_INT32:
41✔
703
                        fprintf(f, "%i", basic.s32);
41✔
704
                        break;
705

706
                case SD_BUS_TYPE_UINT32:
15✔
707
                        fprintf(f, "%u", basic.u32);
15✔
708
                        break;
709

710
                case SD_BUS_TYPE_INT64:
×
711
                        fprintf(f, "%" PRIi64, basic.s64);
×
712
                        break;
713

714
                case SD_BUS_TYPE_UINT64:
177✔
715
                        fprintf(f, "%" PRIu64, basic.u64);
177✔
716
                        break;
717

718
                case SD_BUS_TYPE_DOUBLE:
2✔
719
                        fprintf(f, "%g", basic.d64);
2✔
720
                        break;
721

722
                case SD_BUS_TYPE_STRING:
176✔
723
                case SD_BUS_TYPE_OBJECT_PATH:
724
                case SD_BUS_TYPE_SIGNATURE: {
725
                        _cleanup_free_ char *b = NULL;
176✔
726

727
                        b = cescape(basic.string);
176✔
728
                        if (!b)
176✔
729
                                return -ENOMEM;
×
730

731
                        fprintf(f, "\"%s\"", b);
176✔
732
                        break;
176✔
733
                }
734

735
                case SD_BUS_TYPE_UNIX_FD:
×
736
                        fprintf(f, "%i", basic.i);
×
737
                        break;
738

739
                default:
×
740
                        assert_not_reached();
×
741
                }
742

743
                needs_space = true;
440✔
744
        }
745
}
746

747
typedef struct Member {
748
        const char *type;
749
        char *interface;
750
        char *name;
751
        char *signature;
752
        char *result;
753
        char *value;
754
        bool writable;
755
        uint64_t flags;
756
} Member;
757

758
static void member_hash_func(const Member *m, struct siphash *state) {
1,442✔
759
        uint64_t arity = 1;
1,442✔
760

761
        assert(m);
1,442✔
762
        assert(m->type);
1,442✔
763

764
        string_hash_func(m->type, state);
1,442✔
765

766
        arity += !!m->name + !!m->interface;
1,442✔
767

768
        uint64_hash_func(&arity, state);
1,442✔
769

770
        if (m->name)
1,442✔
771
                string_hash_func(m->name, state);
1,400✔
772

773
        if (m->signature)
1,442✔
774
                string_hash_func(m->signature, state);
1,304✔
775

776
        if (m->interface)
1,442✔
777
                string_hash_func(m->interface, state);
1,442✔
778
}
1,442✔
779

780
static int member_compare_func(const Member *x, const Member *y) {
3,544✔
781
        int d;
3,544✔
782

783
        assert(x);
3,544✔
784
        assert(y);
3,544✔
785
        assert(x->type);
3,544✔
786
        assert(y->type);
3,544✔
787

788
        d = strcmp_ptr(x->interface, y->interface);
3,544✔
789
        if (d != 0)
3,544✔
790
                return d;
791

792
        d = strcmp(x->type, y->type);
3,432✔
793
        if (d != 0)
3,432✔
794
                return d;
795

796
        d = strcmp_ptr(x->name, y->name);
2,900✔
797
        if (d != 0)
2,900✔
798
                return d;
799

800
        return strcmp_ptr(x->signature, y->signature);
252✔
801
}
802

803
static int member_compare_funcp(Member * const *a, Member * const *b) {
2,996✔
804
        return member_compare_func(*a, *b);
2,996✔
805
}
806

807
static Member* member_free(Member *m) {
466✔
808
        if (!m)
466✔
809
                return NULL;
810

811
        free(m->interface);
466✔
812
        free(m->name);
466✔
813
        free(m->signature);
466✔
814
        free(m->result);
466✔
815
        free(m->value);
466✔
816
        return mfree(m);
466✔
817
}
818
DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
466✔
819

820
static Set* member_set_free(Set *s) {
6✔
821
        return set_free_with_destructor(s, member_free);
472✔
822
}
823
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
6✔
824

825
static int on_interface(const char *interface, uint64_t flags, void *userdata) {
8✔
826
        _cleanup_(member_freep) Member *m = NULL;
8✔
827
        Set *members = ASSERT_PTR(userdata);
8✔
828
        int r;
8✔
829

830
        assert(interface);
8✔
831

832
        m = new(Member, 1);
8✔
833
        if (!m)
8✔
834
                return log_oom();
×
835

836
        *m = (Member) {
8✔
837
                .type = "interface",
838
                .flags = flags,
839
        };
840

841
        r = free_and_strdup(&m->interface, interface);
8✔
842
        if (r < 0)
8✔
843
                return log_oom();
×
844

845
        r = set_put(members, m);
8✔
846
        if (r == 0)
8✔
847
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
848
                                       "Invalid introspection data: duplicate interface '%s'.", interface);
849
        if (r < 0)
8✔
850
                return log_oom();
×
851

852
        m = NULL;
8✔
853
        return 0;
8✔
854
}
855

856
static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
190✔
857
        _cleanup_(member_freep) Member *m = NULL;
190✔
858
        Set *members = userdata;
190✔
859
        int r;
190✔
860

861
        assert(interface);
190✔
862
        assert(name);
190✔
863

864
        m = new(Member, 1);
190✔
865
        if (!m)
190✔
866
                return log_oom();
×
867

868
        *m = (Member) {
190✔
869
                .type = "method",
870
                .flags = flags,
871
        };
872

873
        r = free_and_strdup(&m->interface, interface);
190✔
874
        if (r < 0)
190✔
875
                return log_oom();
×
876

877
        r = free_and_strdup(&m->name, name);
190✔
878
        if (r < 0)
190✔
879
                return log_oom();
×
880

881
        r = free_and_strdup(&m->signature, signature);
190✔
882
        if (r < 0)
190✔
883
                return log_oom();
×
884

885
        r = free_and_strdup(&m->result, result);
190✔
886
        if (r < 0)
190✔
887
                return log_oom();
×
888

889
        r = set_put(members, m);
190✔
890
        if (r == 0)
190✔
891
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
892
                                       "Invalid introspection data: duplicate method '%s' on interface '%s'.", name, interface);
893
        if (r < 0)
190✔
894
                return log_oom();
×
895

896
        m = NULL;
190✔
897
        return 0;
190✔
898
}
899

900
static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
16✔
901
        _cleanup_(member_freep) Member *m = NULL;
16✔
902
        Set *members = userdata;
16✔
903
        int r;
16✔
904

905
        assert(interface);
16✔
906
        assert(name);
16✔
907

908
        m = new(Member, 1);
16✔
909
        if (!m)
16✔
910
                return log_oom();
×
911

912
        *m = (Member) {
16✔
913
                .type = "signal",
914
                .flags = flags,
915
        };
916

917
        r = free_and_strdup(&m->interface, interface);
16✔
918
        if (r < 0)
16✔
919
                return log_oom();
×
920

921
        r = free_and_strdup(&m->name, name);
16✔
922
        if (r < 0)
16✔
923
                return log_oom();
×
924

925
        r = free_and_strdup(&m->signature, signature);
16✔
926
        if (r < 0)
16✔
927
                return log_oom();
×
928

929
        r = set_put(members, m);
16✔
930
        if (r == 0)
16✔
931
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
932
                                       "Invalid introspection data: duplicate signal '%s' on interface '%s'.", name, interface);
933
        if (r < 0)
16✔
934
                return log_oom();
×
935

936
        m = NULL;
16✔
937
        return 0;
16✔
938
}
939

940
static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
252✔
941
        _cleanup_(member_freep) Member *m = NULL;
252✔
942
        Set *members = userdata;
252✔
943
        int r;
252✔
944

945
        assert(interface);
252✔
946
        assert(name);
252✔
947

948
        m = new(Member, 1);
252✔
949
        if (!m)
252✔
950
                return log_oom();
×
951

952
        *m = (Member) {
252✔
953
                .type = "property",
954
                .flags = flags,
955
                .writable = writable,
956
        };
957

958
        r = free_and_strdup(&m->interface, interface);
252✔
959
        if (r < 0)
252✔
960
                return log_oom();
×
961

962
        r = free_and_strdup(&m->name, name);
252✔
963
        if (r < 0)
252✔
964
                return log_oom();
×
965

966
        r = free_and_strdup(&m->signature, signature);
252✔
967
        if (r < 0)
252✔
968
                return log_oom();
×
969

970
        r = set_put(members, m);
252✔
971
        if (r == 0)
252✔
972
                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
×
973
                                       "Invalid introspection data: duplicate property '%s' on interface '%s'.", name, interface);
974
        if (r < 0)
252✔
975
                return log_oom();
×
976

977
        m = NULL;
252✔
978
        return 0;
252✔
979
}
980

981
DEFINE_PRIVATE_HASH_OPS(member_hash_ops, Member, member_hash_func, member_compare_func);
982

983
static int introspect(int argc, char **argv, void *userdata) {
6✔
984
        static const XMLIntrospectOps ops = {
6✔
985
                .on_interface = on_interface,
986
                .on_method = on_method,
987
                .on_signal = on_signal,
988
                .on_property = on_property,
989
        };
990

991
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
6✔
992
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_xml = NULL;
6✔
993
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6✔
994
        _cleanup_(member_set_freep) Set *members = NULL;
6✔
995
        unsigned name_width, type_width, signature_width, result_width;
6✔
996
        Member *m;
6✔
997
        const char *xml;
6✔
998
        int r;
6✔
999

1000
        r = acquire_bus(false, &bus);
6✔
1001
        if (r < 0)
6✔
1002
                return r;
1003

1004
        members = set_new(&member_hash_ops);
6✔
1005
        if (!members)
6✔
1006
                return log_oom();
×
1007

1008
        r = sd_bus_call_method(bus, argv[1], argv[2],
6✔
1009
                               "org.freedesktop.DBus.Introspectable", "Introspect",
1010
                               &error, &reply_xml, NULL);
1011
        if (r < 0) {
6✔
1012
                notify_bus_error(&error);
3✔
1013
                return log_error_errno(r, "Failed to introspect object %s of service %s: %s",
3✔
1014
                                       argv[2], argv[1], bus_error_message(&error, r));
1015
        }
1016

1017
        r = sd_bus_message_read(reply_xml, "s", &xml);
3✔
1018
        if (r < 0)
3✔
1019
                return bus_log_parse_error(r);
×
1020

1021
        if (arg_xml_interface) {
3✔
1022
                /* Just dump the received XML and finish */
1023
                pager_open(arg_pager_flags);
1✔
1024
                puts(xml);
1✔
1025
                return 0;
1026
        }
1027

1028
        /* First, get list of all properties */
1029
        r = parse_xml_introspect(argv[2], xml, &ops, members);
2✔
1030
        if (r < 0)
2✔
1031
                return r;
1032

1033
        /* Second, find the current values for them */
1034
        SET_FOREACH(m, members) {
468✔
1035
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
466✔
1036

1037
                if (!streq(m->type, "property"))
466✔
1038
                        continue;
214✔
1039

1040
                if (m->value)
252✔
1041
                        continue;
250✔
1042

1043
                if (argv[3] && !streq(argv[3], m->interface))
2✔
1044
                        continue;
×
1045

1046
                r = sd_bus_call_method(bus, argv[1], argv[2],
2✔
1047
                                       "org.freedesktop.DBus.Properties", "GetAll",
1048
                                       &error, &reply, "s", m->interface);
1049
                if (r < 0) {
2✔
1050
                        notify_bus_error(&error);
×
1051
                        return log_error_errno(r, "Failed to get all properties on interface %s: %s",
×
1052
                                               m->interface, bus_error_message(&error, r));
1053
                }
1054

1055
                r = sd_bus_message_enter_container(reply, 'a', "{sv}");
2✔
1056
                if (r < 0)
2✔
1057
                        return bus_log_parse_error(r);
×
1058

1059
                for (;;) {
252✔
1060
                        _cleanup_(memstream_done) MemStream ms = {};
×
1061
                        _cleanup_free_ char *buf = NULL;
254✔
1062
                        const char *name, *contents;
254✔
1063
                        Member *z;
254✔
1064
                        char type;
254✔
1065
                        FILE *mf;
254✔
1066

1067
                        r = sd_bus_message_enter_container(reply, 'e', "sv");
254✔
1068
                        if (r < 0)
254✔
1069
                                return bus_log_parse_error(r);
×
1070
                        if (r == 0)
254✔
1071
                                break;
1072

1073
                        r = sd_bus_message_read(reply, "s", &name);
252✔
1074
                        if (r < 0)
252✔
1075
                                return bus_log_parse_error(r);
×
1076

1077
                        r = sd_bus_message_peek_type(reply, &type, &contents);
252✔
1078
                        if (r < 0)
252✔
1079
                                return bus_log_parse_error(r);
×
1080
                        if (type != 'v')
252✔
1081
                                return bus_log_parse_error(EINVAL);
×
1082

1083
                        r = sd_bus_message_enter_container(reply, 'v', contents);
252✔
1084
                        if (r < 0)
252✔
1085
                                return bus_log_parse_error(r);
×
1086

1087
                        mf = memstream_init(&ms);
252✔
1088
                        if (!mf)
252✔
1089
                                return log_oom();
×
1090

1091
                        r = format_cmdline(reply, mf, false);
252✔
1092
                        if (r < 0)
252✔
1093
                                return bus_log_parse_error(r);
×
1094

1095
                        r = memstream_finalize(&ms, &buf, NULL);
252✔
1096
                        if (r < 0)
252✔
1097
                                return log_error_errno(r, "Failed to flush and close memstream: %m");
×
1098

1099
                        z = set_get(members, &((Member) {
504✔
1100
                                                .type = "property",
1101
                                                .interface = m->interface,
252✔
1102
                                                .signature = (char*) contents,
1103
                                                .name = (char*) name }));
1104
                        if (z)
252✔
1105
                                free_and_replace(z->value, buf);
252✔
1106

1107
                        r = sd_bus_message_exit_container(reply);
252✔
1108
                        if (r < 0)
252✔
1109
                                return bus_log_parse_error(r);
×
1110

1111
                        r = sd_bus_message_exit_container(reply);
252✔
1112
                        if (r < 0)
252✔
1113
                                return bus_log_parse_error(r);
×
1114
                }
1115

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

1121
        name_width = strlen("NAME");
2✔
1122
        type_width = strlen("TYPE");
2✔
1123
        signature_width = strlen("SIGNATURE");
2✔
1124
        result_width = strlen("RESULT/VALUE");
2✔
1125

1126
        Member **sorted = newa(Member*, set_size(members));
2✔
1127
        size_t k = 0;
2✔
1128

1129
        SET_FOREACH(m, members) {
468✔
1130
                if (argv[3] && !streq(argv[3], m->interface))
466✔
1131
                        continue;
10✔
1132

1133
                if (m->interface)
456✔
1134
                        name_width = MAX(name_width, strlen(m->interface));
456✔
1135
                if (m->name)
456✔
1136
                        name_width = MAX(name_width, strlen(m->name) + 1);
451✔
1137
                if (m->type)
456✔
1138
                        type_width = MAX(type_width, strlen(m->type));
456✔
1139
                if (m->signature)
456✔
1140
                        signature_width = MAX(signature_width, strlen(m->signature));
408✔
1141
                if (m->result)
456✔
1142
                        result_width = MAX(result_width, strlen(m->result));
116✔
1143
                if (m->value)
456✔
1144
                        result_width = MAX(result_width, strlen(m->value));
252✔
1145

1146
                sorted[k++] = m;
456✔
1147
        }
1148

1149
        if (result_width > 40 && arg_full <= 0)
2✔
1150
                result_width = 40;
×
1151

1152
        typesafe_qsort(sorted, k, member_compare_funcp);
2✔
1153

1154
        pager_open(arg_pager_flags);
2✔
1155

1156
        if (arg_legend)
2✔
1157
                printf("%-*s %-*s %-*s %-*s %s\n",
2✔
1158
                       (int) name_width, "NAME",
1159
                       (int) type_width, "TYPE",
1160
                       (int) signature_width, "SIGNATURE",
1161
                       (int) result_width, "RESULT/VALUE",
1162
                       "FLAGS");
1163

1164
        for (size_t j = 0; j < k; j++) {
458✔
1165
                _cleanup_free_ char *ellipsized = NULL;
455✔
1166
                const char *rv;
456✔
1167
                bool is_interface;
456✔
1168

1169
                m = sorted[j];
456✔
1170

1171
                if (argv[3] && !streq(argv[3], m->interface))
456✔
1172
                        continue;
×
1173

1174
                is_interface = streq(m->type, "interface");
456✔
1175

1176
                if (argv[3] && is_interface)
456✔
1177
                        continue;
1✔
1178

1179
                if (m->value) {
455✔
1180
                        ellipsized = ellipsize(m->value, result_width, 100);
252✔
1181
                        if (!ellipsized)
252✔
1182
                                return log_oom();
×
1183

1184
                        rv = ellipsized;
1185
                } else
1186
                        rv = empty_to_dash(m->result);
203✔
1187

1188
                printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
1,369✔
1189
                       is_interface ? ansi_highlight() : "",
1190
                       is_interface ? "" : ".",
1191
                       - !is_interface + (int) name_width,
455✔
1192
                       empty_to_dash(streq_ptr(m->type, "interface") ? m->interface : m->name),
455✔
1193
                       is_interface ? ansi_normal() : "",
1194
                       (int) type_width, empty_to_dash(m->type),
1195
                       (int) signature_width, empty_to_dash(m->signature),
455✔
1196
                       (int) result_width, rv,
1197
                       (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
455✔
1198
                       (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
455✔
1199
                       (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
455✔
1200
                       (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
455✔
1201
                       (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
455✔
1202
                       m->writable ? " writable" : "");
455✔
1203
        }
1204

1205
        return 0;
1206
}
1207

1208
static int message_dump(sd_bus_message *m, FILE *f) {
×
1209
        return sd_bus_message_dump(m, f, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
×
1210
}
1211

1212
static int message_pcap(sd_bus_message *m, FILE *f) {
×
1213
        return bus_message_pcap_frame(m, arg_snaplen, f);
×
1214
}
1215

1216
static int message_json(sd_bus_message *m, FILE *f) {
×
1217
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
×
1218
        char e[2];
×
1219
        int r;
×
1220
        usec_t ts;
×
1221

1222
        r = json_transform_message(m, &v);
×
1223
        if (r < 0)
×
1224
                return r;
1225

1226
        e[0] = m->header->endian;
×
1227
        e[1] = 0;
×
1228

1229
        ts = m->realtime;
×
1230
        if (ts == 0)
×
1231
                ts = now(CLOCK_REALTIME);
×
1232

1233
        r = sd_json_buildo(&w,
×
1234
                SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(bus_message_type_to_string(m->header->type))),
1235
                SD_JSON_BUILD_PAIR("endian", SD_JSON_BUILD_STRING(e)),
1236
                SD_JSON_BUILD_PAIR("flags", SD_JSON_BUILD_INTEGER(m->header->flags)),
1237
                SD_JSON_BUILD_PAIR("version", SD_JSON_BUILD_INTEGER(m->header->version)),
1238
                SD_JSON_BUILD_PAIR("cookie", SD_JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m))),
1239
                SD_JSON_BUILD_PAIR_CONDITION(m->reply_cookie != 0, "reply_cookie", SD_JSON_BUILD_INTEGER(m->reply_cookie)),
1240
                SD_JSON_BUILD_PAIR("timestamp-realtime", SD_JSON_BUILD_UNSIGNED(ts)),
1241
                SD_JSON_BUILD_PAIR_CONDITION(!!m->sender, "sender", SD_JSON_BUILD_STRING(m->sender)),
1242
                SD_JSON_BUILD_PAIR_CONDITION(!!m->destination, "destination", SD_JSON_BUILD_STRING(m->destination)),
1243
                SD_JSON_BUILD_PAIR_CONDITION(!!m->path, "path", SD_JSON_BUILD_STRING(m->path)),
1244
                SD_JSON_BUILD_PAIR_CONDITION(!!m->interface, "interface", SD_JSON_BUILD_STRING(m->interface)),
1245
                SD_JSON_BUILD_PAIR_CONDITION(!!m->member, "member", SD_JSON_BUILD_STRING(m->member)),
1246
                SD_JSON_BUILD_PAIR_CONDITION(m->monotonic != 0, "monotonic", SD_JSON_BUILD_INTEGER(m->monotonic)),
1247
                SD_JSON_BUILD_PAIR_CONDITION(m->realtime != 0, "realtime", SD_JSON_BUILD_INTEGER(m->realtime)),
1248
                SD_JSON_BUILD_PAIR_CONDITION(m->seqnum != 0, "seqnum", SD_JSON_BUILD_INTEGER(m->seqnum)),
1249
                SD_JSON_BUILD_PAIR_CONDITION(!!m->error.name, "error_name", SD_JSON_BUILD_STRING(m->error.name)),
1250
                SD_JSON_BUILD_PAIR("payload", SD_JSON_BUILD_VARIANT(v)));
1251
        if (r < 0)
×
1252
                return log_error_errno(r, "Failed to build JSON object: %m");
×
1253

1254
        sd_json_variant_dump(w, arg_json_format_flags, f, NULL);
×
1255
        return 0;
1256
}
1257

1258
static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f)) {
2✔
1259
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2✔
1260
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
2✔
1261
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2✔
1262
        uint32_t flags = 0;
2✔
1263
        const char *unique_name;
2✔
1264
        bool is_monitor = false;
2✔
1265
        int r;
2✔
1266

1267
        r = acquire_bus(true, &bus);
2✔
1268
        if (r < 0)
2✔
1269
                return r;
1270

1271
        usec_t end = arg_timeout > 0 ?
4✔
1272
                usec_add(now(CLOCK_MONOTONIC), arg_timeout) : USEC_INFINITY;
2✔
1273

1274
        /* upgrade connection; it's not used for anything else after this call */
1275
        r = sd_bus_message_new_method_call(bus,
2✔
1276
                                           &message,
1277
                                           "org.freedesktop.DBus",
1278
                                           "/org/freedesktop/DBus",
1279
                                           "org.freedesktop.DBus.Monitoring",
1280
                                           "BecomeMonitor");
1281
        if (r < 0)
2✔
1282
                return bus_log_create_error(r);
×
1283

1284
        r = sd_bus_message_open_container(message, 'a', "s");
2✔
1285
        if (r < 0)
2✔
1286
                return bus_log_create_error(r);
×
1287

1288
        STRV_FOREACH(i, argv+1) {
2✔
1289
                _cleanup_free_ char *m = NULL;
×
1290

1291
                if (!sd_bus_service_name_is_valid(*i))
×
1292
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name '%s'", *i);
×
1293

1294
                m = strjoin("sender='", *i, "'");
×
1295
                if (!m)
×
1296
                        return log_oom();
×
1297

1298
                r = sd_bus_message_append_basic(message, 's', m);
×
1299
                if (r < 0)
×
1300
                        return bus_log_create_error(r);
×
1301

1302
                free(m);
×
1303
                m = strjoin("destination='", *i, "'");
×
1304
                if (!m)
×
1305
                        return log_oom();
×
1306

1307
                r = sd_bus_message_append_basic(message, 's', m);
×
1308
                if (r < 0)
×
1309
                        return bus_log_create_error(r);
×
1310
        }
1311

1312
        STRV_FOREACH(i, arg_matches) {
4✔
1313
                r = sd_bus_message_append_basic(message, 's', *i);
2✔
1314
                if (r < 0)
2✔
1315
                        return bus_log_create_error(r);
×
1316
        }
1317

1318
        r = sd_bus_message_close_container(message);
2✔
1319
        if (r < 0)
2✔
1320
                return bus_log_create_error(r);
×
1321

1322
        r = sd_bus_message_append_basic(message, 'u', &flags);
2✔
1323
        if (r < 0)
2✔
1324
                return bus_log_create_error(r);
×
1325

1326
        r = sd_bus_call(bus, message, arg_timeout, &error, NULL);
2✔
1327
        if (r < 0) {
2✔
1328
                notify_bus_error(&error);
×
1329
                return log_error_errno(r, "Call to org.freedesktop.DBus.Monitoring.BecomeMonitor failed: %s",
×
1330
                                       bus_error_message(&error, r));
1331
        }
1332

1333
        r = sd_bus_get_unique_name(bus, &unique_name);
2✔
1334
        if (r < 0)
2✔
1335
                return log_error_errno(r, "Failed to get unique name: %m");
×
1336

1337
        if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
2✔
1338
                log_info("Monitoring bus message stream.");
×
1339

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

1342
        for (;;) {
6✔
1343
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
6✔
1344

1345
                r = sd_bus_process(bus, &m);
6✔
1346
                if (r < 0)
6✔
1347
                        return log_error_errno(r, "Failed to process bus: %m");
×
1348

1349
                if (m) {
6✔
1350
                        if (!is_monitor) {
4✔
1351
                                const char *name;
4✔
1352

1353
                                /* wait until we lose our unique name */
1354
                                if (sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameLost") <= 0)
4✔
1355
                                        continue;
4✔
1356

1357
                                r = sd_bus_message_read(m, "s", &name);
2✔
1358
                                if (r < 0)
2✔
1359
                                        return bus_log_parse_error(r);
×
1360

1361
                                if (streq(name, unique_name))
2✔
1362
                                        is_monitor = true;
2✔
1363

1364
                                continue;
2✔
1365
                        }
1366

1367
                        dump(m, stdout);
×
1368
                        fflush(stdout);
×
1369

1370
                        if (arg_limit_messages != UINT64_MAX) {
×
1371
                                arg_limit_messages--;
×
1372

1373
                                if (arg_limit_messages == 0) {
×
1374
                                        if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
×
1375
                                                log_info("Received requested maximum number of messages, exiting.");
×
1376
                                        return 0;
×
1377
                                }
1378
                        }
1379

1380
                        if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) {
×
1381
                                if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
×
1382
                                        log_info("Connection terminated, exiting.");
×
1383
                                return 0;
×
1384
                        }
1385

1386
                        continue;
×
1387
                }
1388

1389
                if (r > 0)
2✔
1390
                        continue;
×
1391

1392
                r = sd_bus_wait(bus, arg_timeout > 0 ? usec_sub_unsigned(end, now(CLOCK_MONOTONIC)) : UINT64_MAX);
4✔
1393
                if (r == 0 && arg_timeout > 0 && now(CLOCK_MONOTONIC) >= end) {
2✔
1394
                        if (!arg_quiet && !sd_json_format_enabled(arg_json_format_flags))
2✔
1395
                                log_info("Timed out waiting for messages, exiting.");
×
1396
                        return 0;
2✔
1397
                }
1398
                if (r < 0)
×
1399
                        return log_error_errno(r, "Failed to wait for bus: %m");
×
1400
        }
1401
}
1402

1403
static int verb_monitor(int argc, char **argv, void *userdata) {
2✔
1404
        return monitor(argc, argv, sd_json_format_enabled(arg_json_format_flags) ? message_json : message_dump);
4✔
1405
}
1406

1407
static int verb_capture(int argc, char **argv, void *userdata) {
×
1408
        _cleanup_free_ char *osname = NULL;
×
1409
        static const char info[] =
×
1410
                "busctl (systemd) " PROJECT_VERSION_FULL " (Git " GIT_VERSION ")";
1411
        int r;
×
1412

1413
        if (isatty_safe(STDOUT_FILENO))
×
1414
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1415
                                       "Refusing to write message data to console, please redirect output to a file.");
1416

1417
        r = parse_os_release(NULL, "PRETTY_NAME", &osname);
×
1418
        if (r < 0)
×
1419
                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_INFO, r,
×
1420
                               "Failed to read os-release file, ignoring: %m");
1421
        bus_pcap_header(arg_snaplen, osname, info, stdout);
×
1422

1423
        r = monitor(argc, argv, message_pcap);
×
1424
        if (r < 0)
×
1425
                return r;
1426

1427
        r = fflush_and_check(stdout);
×
1428
        if (r < 0)
×
1429
                return log_error_errno(r, "Couldn't write capture file: %m");
×
1430

1431
        return r;
1432
}
1433

1434
static int status(int argc, char **argv, void *userdata) {
5✔
1435
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
5✔
1436
        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
5✔
1437
        pid_t pid;
5✔
1438
        int r;
5✔
1439

1440
        r = acquire_bus(false, &bus);
5✔
1441
        if (r < 0)
5✔
1442
                return r;
1443

1444
        pager_open(arg_pager_flags);
5✔
1445

1446
        if (!isempty(argv[1])) {
5✔
1447
                r = parse_pid(argv[1], &pid);
2✔
1448
                if (r < 0)
2✔
1449
                        r = sd_bus_get_name_creds(
2✔
1450
                                        bus,
1451
                                        argv[1],
1452
                                        (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
2✔
1453
                                        &creds);
1454
                else
1455
                        r = sd_bus_creds_new_from_pid(
×
1456
                                        &creds,
1457
                                        pid,
1458
                                        _SD_BUS_CREDS_ALL);
1459
        } else {
1460
                const char *scope, *address;
3✔
1461
                sd_id128_t bus_id;
3✔
1462

1463
                r = sd_bus_get_address(bus, &address);
3✔
1464
                if (r >= 0)
3✔
1465
                        printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal());
9✔
1466

1467
                r = sd_bus_get_scope(bus, &scope);
3✔
1468
                if (r >= 0)
3✔
1469
                        printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal());
3✔
1470

1471
                r = sd_bus_get_bus_id(bus, &bus_id);
3✔
1472
                if (r >= 0)
3✔
1473
                        printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n",
6✔
1474
                               ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal());
3✔
1475

1476
                r = sd_bus_get_owner_creds(
3✔
1477
                                bus,
1478
                                (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
3✔
1479
                                &creds);
1480
        }
1481

1482
        if (r < 0)
5✔
1483
                return log_error_errno(r, "Failed to get credentials: %m");
1✔
1484

1485
        bus_creds_dump(creds, NULL, false);
4✔
1486
        return 0;
1487
}
1488

1489
static int message_append_cmdline(sd_bus_message *m, const char *signature, FDSet **passed_fdset, char ***x) {
1,155✔
1490
        char **p;
1,155✔
1491
        int r;
1,155✔
1492

1493
        assert(m);
1,155✔
1494
        assert(signature);
1,155✔
1495
        assert(passed_fdset);
1,155✔
1496
        assert(x);
1,155✔
1497

1498
        p = *x;
1,155✔
1499

1500
        for (;;) {
2,375✔
1501
                const char *v;
2,375✔
1502
                char t;
2,375✔
1503

1504
                t = *signature;
2,375✔
1505
                v = *p;
2,375✔
1506

1507
                if (t == 0)
2,375✔
1508
                        break;
1509
                if (!v)
1,225✔
1510
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1✔
1511
                                               "Too few parameters for signature.");
1512

1513
                signature++;
1,224✔
1514
                p++;
1,224✔
1515

1516
                switch (t) {
1,224✔
1517

1518
                case SD_BUS_TYPE_BOOLEAN:
12✔
1519

1520
                        r = parse_boolean(v);
12✔
1521
                        if (r < 0)
12✔
1522
                                return log_error_errno(r, "Failed to parse '%s' as boolean: %m", v);
×
1523

1524
                        r = sd_bus_message_append_basic(m, t, &r);
12✔
1525
                        break;
12✔
1526

1527
                case SD_BUS_TYPE_BYTE: {
1528
                        uint8_t z;
×
1529

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

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

1538
                case SD_BUS_TYPE_INT16: {
×
1539
                        int16_t z;
×
1540

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

1545
                        r = sd_bus_message_append_basic(m, t, &z);
×
1546
                        break;
×
1547
                }
1548

1549
                case SD_BUS_TYPE_UINT16: {
1550
                        uint16_t z;
×
1551

1552
                        r = safe_atou16(v, &z);
×
1553
                        if (r < 0)
×
1554
                                return log_error_errno(r, "Failed to parse '%s' as unsigned 16-bit integer: %m", v);
×
1555

1556
                        r = sd_bus_message_append_basic(m, t, &z);
×
1557
                        break;
×
1558
                }
1559

1560
                case SD_BUS_TYPE_INT32: {
1561
                        int32_t z;
2✔
1562

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

1567
                        r = sd_bus_message_append_basic(m, t, &z);
2✔
1568
                        break;
2✔
1569
                }
1570

1571
                case SD_BUS_TYPE_UINT32: {
1572
                        uint32_t z;
1,003✔
1573

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

1578
                        r = sd_bus_message_append_basic(m, t, &z);
1,002✔
1579
                        break;
1,002✔
1580
                }
1581

1582
                case SD_BUS_TYPE_INT64: {
1583
                        int64_t z;
×
1584

1585
                        r = safe_atoi64(v, &z);
×
1586
                        if (r < 0)
×
1587
                                return log_error_errno(r, "Failed to parse '%s' as signed 64-bit integer: %m", v);
×
1588

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

1593
                case SD_BUS_TYPE_UINT64: {
1594
                        uint64_t z;
8✔
1595

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

1600
                        r = sd_bus_message_append_basic(m, t, &z);
7✔
1601
                        break;
7✔
1602
                }
1603

1604
                case SD_BUS_TYPE_DOUBLE: {
×
1605
                        double z;
×
1606

1607
                        r = safe_atod(v, &z);
×
1608
                        if (r < 0)
×
1609
                                return log_error_errno(r, "Failed to parse '%s' as double precision floating point: %m", v);
×
1610

1611
                        r = sd_bus_message_append_basic(m, t, &z);
×
1612
                        break;
×
1613
                }
1614

1615
                case SD_BUS_TYPE_STRING:
119✔
1616
                case SD_BUS_TYPE_OBJECT_PATH:
1617
                case SD_BUS_TYPE_SIGNATURE:
1618

1619
                        r = sd_bus_message_append_basic(m, t, v);
119✔
1620
                        break;
119✔
1621

1622
                case SD_BUS_TYPE_ARRAY: {
1623
                        uint32_t n;
38✔
1624
                        size_t k;
38✔
1625

1626
                        r = safe_atou32(v, &n);
38✔
1627
                        if (r < 0)
38✔
1628
                                return log_error_errno(r, "Failed to parse '%s' number of array entries: %m", v);
2✔
1629

1630
                        r = signature_element_length(signature, &k);
37✔
1631
                        if (r < 0)
37✔
1632
                                return log_error_errno(r, "Invalid array signature: %m");
×
1633

1634
                        {
37✔
1635
                                char s[k + 1];
37✔
1636
                                memcpy(s, signature, k);
37✔
1637
                                s[k] = 0;
37✔
1638

1639
                                r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
37✔
1640
                                if (r < 0)
37✔
1641
                                        return bus_log_create_error(r);
1✔
1642

1643
                                for (unsigned i = 0; i < n; i++) {
82✔
1644
                                        r = message_append_cmdline(m, s, passed_fdset, &p);
46✔
1645
                                        if (r < 0)
46✔
1646
                                                return r;
1647
                                }
1648
                        }
1649

1650
                        signature += k;
36✔
1651

1652
                        r = sd_bus_message_close_container(m);
36✔
1653
                        break;
36✔
1654
                }
1655

1656
                case SD_BUS_TYPE_VARIANT:
16✔
1657
                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
16✔
1658
                        if (r < 0)
16✔
1659
                                return bus_log_create_error(r);
×
1660

1661
                        r = message_append_cmdline(m, v, passed_fdset, &p);
16✔
1662
                        if (r < 0)
16✔
1663
                                return r;
1664

1665
                        r = sd_bus_message_close_container(m);
16✔
1666
                        break;
16✔
1667

1668
                case SD_BUS_TYPE_STRUCT_BEGIN:
24✔
1669
                case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
1670
                        size_t k;
24✔
1671

1672
                        signature--;
24✔
1673
                        p--;
24✔
1674

1675
                        r = signature_element_length(signature, &k);
24✔
1676
                        if (r < 0 || k < 2) {
24✔
1677
                                if (r >= 0 && k < 2)
×
1678
                                        r = -ERANGE;
×
1679
                                return log_error_errno(r, "Invalid struct/dict entry signature: %m");
×
1680
                        }
1681

1682
                        {
24✔
1683
                                char s[k-1];
24✔
1684
                                memcpy(s, signature + 1, k - 2);
24✔
1685
                                s[k - 2] = 0;
24✔
1686

1687
                                const char ctype = t == SD_BUS_TYPE_STRUCT_BEGIN ?
24✔
1688
                                        SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
1689
                                r = sd_bus_message_open_container(m, ctype, s);
24✔
1690
                                if (r < 0)
24✔
1691
                                        return bus_log_create_error(r);
×
1692

1693
                                r = message_append_cmdline(m, s, passed_fdset, &p);
24✔
1694
                                if (r < 0)
24✔
1695
                                        return r;
1696
                        }
1697

1698
                        signature += k;
24✔
1699

1700
                        r = sd_bus_message_close_container(m);
24✔
1701
                        break;
24✔
1702
                }
1703

1704
                case SD_BUS_TYPE_UNIX_FD: {
2✔
1705
                        int fd;
2✔
1706

1707
                        fd = parse_fd(v);
2✔
1708
                        if (fd < 0)
2✔
1709
                                return log_error_errno(fd, "Failed to parse '%s' as a file descriptor: %m", v);
×
1710

1711
                        if (!*passed_fdset) {
2✔
1712
                                r = fdset_new_fill(/* filter_cloexec= */ 0, passed_fdset);
1✔
1713
                                if (r < 0)
1✔
1714
                                        return log_error_errno(r, "Failed to create fd set: %m");
×
1715
                        }
1716

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

1720
                        r = sd_bus_message_append_basic(m, t, &fd);
2✔
1721
                        break;
2✔
1722
                }
1723

1724
                default:
1725
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1726
                                               "Unknown signature type %c.", t);
1727
                }
1728

1729
                if (r < 0)
1,220✔
1730
                        return bus_log_create_error(r);
×
1731
        }
1732

1733
        *x = p;
1,150✔
1734
        return 0;
1,150✔
1735
}
1736

1737
static int json_transform_one(sd_bus_message *m, sd_json_variant **ret);
1738

1739
static int json_transform_and_append(sd_bus_message *m, sd_json_variant **array) {
71✔
1740
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *element = NULL;
71✔
1741
        int r;
71✔
1742

1743
        assert(m);
71✔
1744
        assert(array);
71✔
1745

1746
        r = json_transform_one(m, &element);
71✔
1747
        if (r < 0)
71✔
1748
                return r;
1749

1750
        r = sd_json_variant_append_array(array, element);
71✔
1751
        if (r < 0)
71✔
1752
                return log_error_errno(r, "Failed to append json element to array: %m");
×
1753

1754
        return 0;
1755
}
1756

1757
static int json_transform_array_or_struct(sd_bus_message *m, sd_json_variant **ret) {
16✔
1758
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *array = NULL;
16✔
1759
        int r;
16✔
1760

1761
        assert(m);
16✔
1762
        assert(ret);
16✔
1763

1764
        r = sd_json_variant_new_array(&array, NULL, 0);
16✔
1765
        if (r < 0)
16✔
1766
                return log_error_errno(r, "Failed to allocate json empty array: %m");
×
1767

1768
        for (;;) {
87✔
1769
                r = sd_bus_message_at_end(m, false);
87✔
1770
                if (r < 0)
87✔
1771
                        return bus_log_parse_error(r);
×
1772
                if (r > 0)
87✔
1773
                        break;
1774

1775
                r = json_transform_and_append(m, &array);
71✔
1776
                if (r < 0)
71✔
1777
                        return r;
1778
        }
1779

1780
        *ret = TAKE_PTR(array);
16✔
1781
        return 0;
16✔
1782
}
1783

1784
static int json_transform_variant(sd_bus_message *m, const char *contents, sd_json_variant **ret) {
139✔
1785
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *value = NULL;
139✔
1786
        int r;
139✔
1787

1788
        assert(m);
139✔
1789
        assert(contents);
139✔
1790
        assert(ret);
139✔
1791

1792
        r = json_transform_one(m, &value);
139✔
1793
        if (r < 0)
139✔
1794
                return r;
1795

1796
        r = sd_json_buildo(ret,
139✔
1797
                          SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(contents)),
1798
                          SD_JSON_BUILD_PAIR("data", SD_JSON_BUILD_VARIANT(value)));
1799
        if (r < 0)
139✔
1800
                return log_error_errno(r, "Failed to build json object: %m");
×
1801

1802
        return r;
1803
}
1804

1805
static int json_transform_dict_array(sd_bus_message *m, sd_json_variant **ret) {
1✔
1806
        sd_json_variant **elements = NULL;
1✔
1807
        size_t n_elements = 0;
1✔
1808
        int r;
1✔
1809

1810
        assert(m);
1✔
1811
        assert(ret);
1✔
1812

1813
        CLEANUP_ARRAY(elements, n_elements, sd_json_variant_unref_many);
2✔
1814

1815
        for (;;) {
126✔
1816
                const char *contents;
127✔
1817
                char type;
127✔
1818

1819
                r = sd_bus_message_at_end(m, false);
127✔
1820
                if (r < 0)
127✔
1821
                        return bus_log_parse_error(r);
×
1822
                if (r > 0)
127✔
1823
                        break;
1824

1825
                r = sd_bus_message_peek_type(m, &type, &contents);
126✔
1826
                if (r < 0)
126✔
1827
                        return bus_log_parse_error(r);
×
1828

1829
                assert(type == 'e');
126✔
1830

1831
                if (!GREEDY_REALLOC(elements, n_elements + 2))
126✔
1832
                        return log_oom();
×
1833

1834
                r = sd_bus_message_enter_container(m, type, contents);
126✔
1835
                if (r < 0)
126✔
1836
                        return bus_log_parse_error(r);
×
1837

1838
                r = json_transform_one(m, elements + n_elements);
126✔
1839
                if (r < 0)
126✔
1840
                        return r;
1841

1842
                n_elements++;
126✔
1843

1844
                r = json_transform_one(m, elements + n_elements);
126✔
1845
                if (r < 0)
126✔
1846
                        return r;
1847

1848
                n_elements++;
126✔
1849

1850
                r = sd_bus_message_exit_container(m);
126✔
1851
                if (r < 0)
126✔
1852
                        return bus_log_parse_error(r);
×
1853
        }
1854

1855
        r = sd_json_variant_new_object(ret, elements, n_elements);
1✔
1856
        if (r < 0)
1✔
1857
                return log_error_errno(r, "Failed to create new json object: %m");
×
1858

1859
        return 0;
1860
}
1861

1862
static int json_transform_one(sd_bus_message *m, sd_json_variant **ret) {
462✔
1863
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
462✔
1864
        const char *contents;
462✔
1865
        char type;
462✔
1866
        int r;
462✔
1867

1868
        assert(m);
462✔
1869
        assert(ret);
462✔
1870

1871
        r = sd_bus_message_peek_type(m, &type, &contents);
462✔
1872
        if (r < 0)
462✔
1873
                return bus_log_parse_error(r);
×
1874

1875
        switch (type) {
462✔
1876

1877
        case SD_BUS_TYPE_BYTE: {
1✔
1878
                uint8_t b;
1✔
1879

1880
                r = sd_bus_message_read_basic(m, type, &b);
1✔
1881
                if (r < 0)
1✔
1882
                        return bus_log_parse_error(r);
×
1883

1884
                r = sd_json_variant_new_unsigned(&v, b);
1✔
1885
                if (r < 0)
1✔
1886
                        return log_error_errno(r, "Failed to transform byte: %m");
×
1887

1888
                break;
1✔
1889
        }
1890

1891
        case SD_BUS_TYPE_BOOLEAN: {
11✔
1892
                int b;
11✔
1893

1894
                r = sd_bus_message_read_basic(m, type, &b);
11✔
1895
                if (r < 0)
11✔
1896
                        return bus_log_parse_error(r);
×
1897

1898
                r = sd_json_variant_new_boolean(&v, b);
11✔
1899
                if (r < 0)
11✔
1900
                        return log_error_errno(r, "Failed to transform boolean: %m");
×
1901

1902
                break;
11✔
1903
        }
1904

1905
        case SD_BUS_TYPE_INT16: {
×
1906
                int16_t b;
×
1907

1908
                r = sd_bus_message_read_basic(m, type, &b);
×
1909
                if (r < 0)
×
1910
                        return bus_log_parse_error(r);
×
1911

1912
                r = sd_json_variant_new_integer(&v, b);
×
1913
                if (r < 0)
×
1914
                        return log_error_errno(r, "Failed to transform int16: %m");
×
1915

1916
                break;
×
1917
        }
1918

1919
        case SD_BUS_TYPE_UINT16: {
×
1920
                uint16_t b;
×
1921

1922
                r = sd_bus_message_read_basic(m, type, &b);
×
1923
                if (r < 0)
×
1924
                        return bus_log_parse_error(r);
×
1925

1926
                r = sd_json_variant_new_unsigned(&v, b);
×
1927
                if (r < 0)
×
1928
                        return log_error_errno(r, "Failed to transform uint16: %m");
×
1929

1930
                break;
×
1931
        }
1932

1933
        case SD_BUS_TYPE_INT32: {
1✔
1934
                int32_t b;
1✔
1935

1936
                r = sd_bus_message_read_basic(m, type, &b);
1✔
1937
                if (r < 0)
1✔
1938
                        return bus_log_parse_error(r);
×
1939

1940
                r = sd_json_variant_new_integer(&v, b);
1✔
1941
                if (r < 0)
1✔
1942
                        return log_error_errno(r, "Failed to transform int32: %m");
×
1943

1944
                break;
1✔
1945
        }
1946

1947
        case SD_BUS_TYPE_UINT32: {
11✔
1948
                uint32_t b;
11✔
1949

1950
                r = sd_bus_message_read_basic(m, type, &b);
11✔
1951
                if (r < 0)
11✔
1952
                        return bus_log_parse_error(r);
×
1953

1954
                r = sd_json_variant_new_unsigned(&v, b);
11✔
1955
                if (r < 0)
11✔
1956
                        return log_error_errno(r, "Failed to transform uint32: %m");
×
1957

1958
                break;
11✔
1959
        }
1960

1961
        case SD_BUS_TYPE_INT64: {
×
1962
                int64_t b;
×
1963

1964
                r = sd_bus_message_read_basic(m, type, &b);
×
1965
                if (r < 0)
×
1966
                        return bus_log_parse_error(r);
×
1967

1968
                r = sd_json_variant_new_integer(&v, b);
×
1969
                if (r < 0)
×
1970
                        return log_error_errno(r, "Failed to transform int64: %m");
×
1971

1972
                break;
×
1973
        }
1974

1975
        case SD_BUS_TYPE_UINT64: {
89✔
1976
                uint64_t b;
89✔
1977

1978
                r = sd_bus_message_read_basic(m, type, &b);
89✔
1979
                if (r < 0)
89✔
1980
                        return bus_log_parse_error(r);
×
1981

1982
                r = sd_json_variant_new_unsigned(&v, b);
89✔
1983
                if (r < 0)
89✔
1984
                        return log_error_errno(r, "Failed to transform uint64: %m");
×
1985

1986
                break;
89✔
1987
        }
1988

1989
        case SD_BUS_TYPE_DOUBLE: {
1✔
1990
                double d;
1✔
1991

1992
                r = sd_bus_message_read_basic(m, type, &d);
1✔
1993
                if (r < 0)
1✔
1994
                        return bus_log_parse_error(r);
×
1995

1996
                r = sd_json_variant_new_real(&v, d);
1✔
1997
                if (r < 0)
1✔
1998
                        return log_error_errno(r, "Failed to transform double: %m");
×
1999

2000
                break;
1✔
2001
        }
2002

2003
        case SD_BUS_TYPE_STRING:
208✔
2004
        case SD_BUS_TYPE_OBJECT_PATH:
2005
        case SD_BUS_TYPE_SIGNATURE: {
2006
                const char *s;
208✔
2007

2008
                r = sd_bus_message_read_basic(m, type, &s);
208✔
2009
                if (r < 0)
208✔
2010
                        return bus_log_parse_error(r);
×
2011

2012
                r = sd_json_variant_new_string(&v, s);
208✔
2013
                if (r < 0)
208✔
2014
                        return log_error_errno(r, "Failed to transform double: %m");
×
2015

2016
                break;
208✔
2017
        }
2018

2019
        case SD_BUS_TYPE_UNIX_FD: {
1✔
2020
                int fd;
1✔
2021

2022
                r = sd_bus_message_read_basic(m, type, &fd);
1✔
2023
                if (r < 0)
1✔
2024
                        return bus_log_parse_error(r);
×
2025

2026
                r = json_variant_new_fd_info(&v, fd);
1✔
2027
                if (r < 0)
1✔
2028
                        return log_error_errno(r, "Failed to transform fd: %m");
×
2029

2030
                break;
1✔
2031
        }
2032

2033
        case SD_BUS_TYPE_ARRAY:
139✔
2034
        case SD_BUS_TYPE_VARIANT:
2035
        case SD_BUS_TYPE_STRUCT:
2036
                r = sd_bus_message_enter_container(m, type, contents);
139✔
2037
                if (r < 0)
139✔
2038
                        return bus_log_parse_error(r);
×
2039

2040
                if (type == SD_BUS_TYPE_VARIANT)
139✔
2041
                        r = json_transform_variant(m, contents, &v);
126✔
2042
                else if (type == SD_BUS_TYPE_ARRAY && contents[0] == '{')
13✔
2043
                        r = json_transform_dict_array(m, &v);
1✔
2044
                else
2045
                        r = json_transform_array_or_struct(m, &v);
12✔
2046
                if (r < 0)
139✔
2047
                        return r;
2048

2049
                r = sd_bus_message_exit_container(m);
139✔
2050
                if (r < 0)
139✔
2051
                        return bus_log_parse_error(r);
×
2052

2053
                break;
2054

2055
        default:
×
2056
                assert_not_reached();
×
2057
        }
2058

2059
        *ret = TAKE_PTR(v);
462✔
2060
        return 0;
462✔
2061
}
2062

2063
static int json_transform_message(sd_bus_message *m, sd_json_variant **ret) {
4✔
2064
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
4✔
2065
        const char *type;
4✔
2066
        int r;
4✔
2067

2068
        assert(m);
4✔
2069
        assert(ret);
4✔
2070

2071
        assert_se(type = sd_bus_message_get_signature(m, false));
4✔
2072

2073
        r = json_transform_array_or_struct(m, &v);
4✔
2074
        if (r < 0)
4✔
2075
                return r;
2076

2077
        r = sd_json_buildo(ret,
4✔
2078
                          SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(type)),
2079
                          SD_JSON_BUILD_PAIR("data", SD_JSON_BUILD_VARIANT(v)));
2080
        if (r < 0)
4✔
2081
                return log_error_errno(r, "Failed to build json object: %m");
×
2082

2083
        return 0;
2084
}
2085

2086
static int call(int argc, char **argv, void *userdata) {
1,071✔
2087
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1,071✔
2088
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
2089
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
2,142✔
2090
        _cleanup_fdset_free_ FDSet *passed_fdset = NULL;
1,071✔
2091
        int r;
1,071✔
2092

2093
        r = acquire_bus(false, &bus);
1,071✔
2094
        if (r < 0)
1,071✔
2095
                return r;
2096

2097
        if (!service_name_is_valid(argv[1]))
1,071✔
2098
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", argv[1]);
×
2099
        if (!object_path_is_valid(argv[2]))
1,071✔
2100
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", argv[2]);
×
2101
        if (!interface_name_is_valid(argv[3]))
1,071✔
2102
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", argv[3]);
×
2103
        if (!member_name_is_valid(argv[4]))
1,071✔
2104
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid member name: %s", argv[4]);
×
2105

2106
        r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
1,071✔
2107
        if (r < 0)
1,071✔
2108
                return bus_log_create_error(r);
×
2109

2110
        r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
1,071✔
2111
        if (r < 0)
1,071✔
2112
                return bus_log_create_error(r);
×
2113

2114
        r = sd_bus_message_set_auto_start(m, arg_auto_start);
1,071✔
2115
        if (r < 0)
1,071✔
2116
                return bus_log_create_error(r);
×
2117

2118
        r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
1,071✔
2119
        if (r < 0)
1,071✔
2120
                return bus_log_create_error(r);
×
2121

2122
        if (!isempty(argv[5])) {
1,071✔
2123
                char **p;
1,062✔
2124

2125
                p = argv+6;
1,062✔
2126

2127
                r = message_append_cmdline(m, argv[5], &passed_fdset, &p);
1,062✔
2128
                if (r < 0)
1,062✔
2129
                        return r;
3✔
2130

2131
                if (*p)
1,059✔
2132
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2133
                                               "Too many parameters for signature.");
2134
        }
2135

2136
        if (!arg_expect_reply) {
1,068✔
2137
                r = sd_bus_send(bus, m, NULL);
×
2138
                if (r < 0)
×
2139
                        return log_error_errno(r, "Failed to send message: %m");
×
2140

2141
                return 0;
2142
        }
2143

2144
        r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
1,068✔
2145
        if (r < 0) {
1,068✔
2146
                notify_bus_error(&error);
1,005✔
2147
                return log_error_errno(r, "Call failed: %s", bus_error_message(&error, r));
1,005✔
2148
        }
2149

2150
        r = sd_bus_message_is_empty(reply);
63✔
2151
        if (r < 0)
63✔
2152
                return bus_log_parse_error(r);
×
2153
        if (r > 0 || arg_quiet)
63✔
2154
                return 0;
2155

2156
        if (sd_json_format_enabled(arg_json_format_flags)) {
62✔
2157
                _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
4✔
2158

2159
                if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
4✔
2160
                        pager_open(arg_pager_flags);
3✔
2161

2162
                r = json_transform_message(reply, &v);
4✔
2163
                if (r < 0)
4✔
2164
                        return r;
×
2165

2166
                sd_json_variant_dump(v, arg_json_format_flags, NULL, NULL);
4✔
2167

2168
        } else if (arg_verbose) {
58✔
2169
                pager_open(arg_pager_flags);
1✔
2170

2171
                r = sd_bus_message_dump(reply, stdout, 0);
1✔
2172
                if (r < 0)
1✔
2173
                        return log_error_errno(r, "Failed to dump dbus message: %m");
×
2174
        } else {
2175

2176
                fputs(sd_bus_message_get_signature(reply, true), stdout);
57✔
2177
                fputc(' ', stdout);
57✔
2178

2179
                r = format_cmdline(reply, stdout, false);
57✔
2180
                if (r < 0)
57✔
2181
                        return bus_log_parse_error(r);
×
2182

2183
                fputc('\n', stdout);
57✔
2184
        }
2185

2186
        return 0;
2187
}
2188

2189
static int emit_signal(int argc, char **argv, void *userdata) {
3✔
2190
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
3✔
2191
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
3✔
2192
        _cleanup_fdset_free_ FDSet *passed_fdset = NULL;
3✔
2193
        int r;
3✔
2194

2195
        r = acquire_bus(false, &bus);
3✔
2196
        if (r < 0)
3✔
2197
                return r;
2198

2199
        r = sd_bus_message_new_signal(bus, &m, argv[1], argv[2], argv[3]);
3✔
2200
        if (r < 0)
3✔
2201
                return bus_log_create_error(r);
×
2202

2203
        if (arg_destination) {
3✔
2204
                r = sd_bus_message_set_destination(m, arg_destination);
1✔
2205
                if (r < 0)
1✔
2206
                        return bus_log_create_error(r);
×
2207
        }
2208

2209
        r = sd_bus_message_set_auto_start(m, arg_auto_start);
3✔
2210
        if (r < 0)
3✔
2211
                return bus_log_create_error(r);
×
2212

2213
        if (!isempty(argv[4])) {
3✔
2214
                char **p;
3✔
2215

2216
                p = argv+5;
3✔
2217

2218
                r = message_append_cmdline(m, argv[4], &passed_fdset, &p);
3✔
2219
                if (r < 0)
3✔
2220
                        return r;
×
2221

2222
                if (*p)
3✔
2223
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2224
                                               "Too many parameters for signature.");
2225
        }
2226

2227
        r = sd_bus_send(bus, m, NULL);
3✔
2228
        if (r < 0)
3✔
2229
                return log_error_errno(r, "Failed to send signal: %m");
×
2230

2231
        return 0;
2232
}
2233

2234
static int get_property(int argc, char **argv, void *userdata) {
53✔
2235
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
53✔
2236
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
53✔
2237
        int r;
53✔
2238

2239
        r = acquire_bus(false, &bus);
53✔
2240
        if (r < 0)
53✔
2241
                return r;
2242

2243
        STRV_FOREACH(i, argv + 4) {
114✔
2244
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
63✔
2245
                const char *contents = NULL;
63✔
2246
                char type;
63✔
2247

2248
                r = sd_bus_call_method(bus, argv[1], argv[2],
63✔
2249
                                       "org.freedesktop.DBus.Properties", "Get",
2250
                                       &error, &reply, "ss", argv[3], *i);
2251
                if (r < 0) {
63✔
2252
                        notify_bus_error(&error);
2✔
2253
                        return log_error_errno(r, "Failed to get property %s on interface %s: %s",
2✔
2254
                                               *i, argv[3],
2255
                                               bus_error_message(&error, r));
2256
                }
2257

2258
                r = sd_bus_message_peek_type(reply, &type, &contents);
61✔
2259
                if (r < 0)
61✔
2260
                        return bus_log_parse_error(r);
×
2261

2262
                r = sd_bus_message_enter_container(reply, 'v', contents);
61✔
2263
                if (r < 0)
61✔
2264
                        return bus_log_parse_error(r);
×
2265

2266
                if (sd_json_format_enabled(arg_json_format_flags)) {
61✔
2267
                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
13✔
2268

2269
                        if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
13✔
2270
                                pager_open(arg_pager_flags);
5✔
2271

2272
                        r = json_transform_variant(reply, contents, &v);
13✔
2273
                        if (r < 0)
13✔
2274
                                return r;
×
2275

2276
                        sd_json_variant_dump(v, arg_json_format_flags, NULL, NULL);
13✔
2277

2278
                } else if (arg_verbose) {
48✔
2279
                        pager_open(arg_pager_flags);
4✔
2280

2281
                        r = sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY);
4✔
2282
                        if (r < 0)
4✔
2283
                                return r;
2284
                } else {
2285
                        fputs(contents, stdout);
44✔
2286
                        fputc(' ', stdout);
44✔
2287

2288
                        r = format_cmdline(reply, stdout, false);
44✔
2289
                        if (r < 0)
44✔
2290
                                return bus_log_parse_error(r);
×
2291

2292
                        fputc('\n', stdout);
44✔
2293
                }
2294

2295
                r = sd_bus_message_exit_container(reply);
61✔
2296
                if (r < 0)
61✔
2297
                        return bus_log_parse_error(r);
×
2298
        }
2299

2300
        return 0;
2301
}
2302

2303
static int on_bus_signal_impl(sd_bus_message *msg) {
1✔
2304
        int r;
1✔
2305

2306
        assert(msg);
1✔
2307

2308
        r = sd_bus_message_is_empty(msg);
1✔
2309
        if (r < 0)
1✔
2310
                return bus_log_parse_error(r);
×
2311
        if (r > 0 || arg_quiet)
1✔
2312
                return 0;
2313

2314
        if (!FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF)) {
1✔
2315
                _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
×
2316

2317
                if (arg_json_format_flags & (SD_JSON_FORMAT_PRETTY|SD_JSON_FORMAT_PRETTY_AUTO))
×
2318
                        pager_open(arg_pager_flags);
×
2319

2320
                r = json_transform_message(msg, &v);
×
2321
                if (r < 0)
×
2322
                        return r;
×
2323

2324
                sd_json_variant_dump(v, arg_json_format_flags, NULL, NULL);
×
2325

2326
        } else if (arg_verbose) {
1✔
2327
                pager_open(arg_pager_flags);
×
2328

2329
                r = sd_bus_message_dump(msg, stdout, 0);
×
2330
                if (r < 0)
×
2331
                        return log_error_errno(r, "Failed to dump dbus message: %m\n");
×
2332
        } else {
2333

2334
                fputs(sd_bus_message_get_signature(msg, true), stdout);
1✔
2335
                fputc(' ', stdout);
1✔
2336

2337
                r = format_cmdline(msg, stdout, false);
1✔
2338
                if (r < 0)
1✔
2339
                        return bus_log_parse_error(r);
×
2340

2341
                fputc('\n', stdout);
1✔
2342
        }
2343

2344
        return 0;
2345
}
2346

2347
static int on_bus_signal(sd_bus_message *msg, void *userdata, sd_bus_error *ret_error) {
1✔
2348
        sd_event *e = sd_bus_get_event(sd_bus_message_get_bus(ASSERT_PTR(msg)));
1✔
2349
        return sd_event_exit(e, on_bus_signal_impl(msg));
1✔
2350
}
2351

2352
static int wait_signal(int argc, char **argv, void *userdata) {
1✔
2353
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1✔
2354
        _cleanup_(sd_event_unrefp) sd_event *e = NULL;
1✔
2355
        _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
1✔
2356
        int argn = 1, r;
1✔
2357

2358
        const char *sender = argc == 5 ? argv[argn++] : NULL;
1✔
2359
        const char *path = argv[argn++];
1✔
2360
        const char *interface = argv[argn++];
1✔
2361
        const char *member = argv[argn++];
1✔
2362

2363
        if (sender && !service_name_is_valid(sender))
1✔
2364
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name: %s", sender);
×
2365
        if (!object_path_is_valid(path))
1✔
2366
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid object path: %s", path);
×
2367
        if (!interface_name_is_valid(interface))
1✔
2368
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name: %s", interface);
×
2369
        if (!member_name_is_valid(member))
1✔
2370
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid member name: %s", member);
×
2371

2372
        r = acquire_bus(/* set_monitor= */ false, &bus);
1✔
2373
        if (r < 0)
1✔
2374
                return r;
2375

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

2380
        r = sd_event_new(&e);
1✔
2381
        if (r < 0)
1✔
2382
                return log_error_errno(r, "Failed to allocate event loop: %m\n");
×
2383

2384
        r = sd_bus_attach_event(bus, e, SD_EVENT_PRIORITY_NORMAL);
1✔
2385
        if (r < 0)
1✔
2386
                return log_error_errno(r, "Failed to attach bus event: %m\n");
×
2387

2388
        if (arg_timeout) {
1✔
2389
                r = sd_event_add_time_relative(e, &timer, CLOCK_MONOTONIC, arg_timeout, 0, NULL, NULL);
1✔
2390
                if (r < 0)
1✔
2391
                        return log_error_errno(r, "Failed to schedule timeout: %m\n");
×
2392
        }
2393

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

2397
        return sd_event_loop(e);
1✔
2398
}
2399

2400
static int set_property(int argc, char **argv, void *userdata) {
4✔
2401
        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
4✔
2402
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
4✔
2403
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4✔
2404
        _cleanup_fdset_free_ FDSet *passed_fdset = NULL;
4✔
2405
        char **p;
4✔
2406
        int r;
4✔
2407

2408
        r = acquire_bus(false, &bus);
4✔
2409
        if (r < 0)
4✔
2410
                return r;
2411

2412
        r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2],
4✔
2413
                                           "org.freedesktop.DBus.Properties", "Set");
2414
        if (r < 0)
4✔
2415
                return bus_log_create_error(r);
×
2416

2417
        r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
4✔
2418
        if (r < 0)
4✔
2419
                return bus_log_create_error(r);
×
2420

2421
        r = sd_bus_message_open_container(m, 'v', argv[5]);
4✔
2422
        if (r < 0)
4✔
2423
                return bus_log_create_error(r);
×
2424

2425
        p = argv + 6;
4✔
2426
        r = message_append_cmdline(m, argv[5], &passed_fdset, &p);
4✔
2427
        if (r < 0)
4✔
2428
                return r;
2429

2430
        r = sd_bus_message_close_container(m);
3✔
2431
        if (r < 0)
3✔
2432
                return bus_log_create_error(r);
×
2433

2434
        if (*p)
3✔
2435
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
×
2436

2437
        r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
3✔
2438
        if (r < 0) {
3✔
2439
                notify_bus_error(&error);
2✔
2440
                return log_error_errno(r, "Failed to set property %s on interface %s: %s",
2✔
2441
                                       argv[4], argv[3],
2442
                                       bus_error_message(&error, r));
2443
        }
2444

2445
        return 0;
2446
}
2447

2448
static int help(void) {
2✔
2449
        _cleanup_free_ char *link = NULL;
2✔
2450
        int r;
2✔
2451

2452
        r = terminal_urlify_man("busctl", "1", &link);
2✔
2453
        if (r < 0)
2✔
2454
                return log_oom();
×
2455

2456
        pager_open(arg_pager_flags);
2✔
2457

2458
        printf("%1$s [OPTIONS...] COMMAND ...\n\n"
4✔
2459
               "%5$sIntrospect the D-Bus IPC bus.%6$s\n"
2460
               "\n%3$sCommands%4$s:\n"
2461
               "  list                     List bus names\n"
2462
               "  status [SERVICE]         Show bus service, process or bus owner credentials\n"
2463
               "  monitor [SERVICE...]     Show bus traffic\n"
2464
               "  capture [SERVICE...]     Capture bus traffic as pcap\n"
2465
               "  tree [SERVICE...]        Show object tree of service\n"
2466
               "  introspect SERVICE OBJECT [INTERFACE]\n"
2467
               "  call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
2468
               "                           Call a method\n"
2469
               "  emit OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT...]]\n"
2470
               "                           Emit a signal\n"
2471
               "  wait OBJECT INTERFACE SIGNAL\n"
2472
               "                           Wait for a signal\n"
2473
               "  get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
2474
               "                           Get property value\n"
2475
               "  set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
2476
               "                           Set property value\n"
2477
               "  help                     Show this help\n"
2478
               "\n%3$sOptions:%4$s\n"
2479
               "  -h --help                Show this help\n"
2480
               "     --version             Show package version\n"
2481
               "     --no-pager            Do not pipe output into a pager\n"
2482
               "     --no-legend           Do not show the headers and footers\n"
2483
               "  -l --full                Do not ellipsize output\n"
2484
               "     --system              Connect to system bus\n"
2485
               "     --user                Connect to user bus\n"
2486
               "  -H --host=[USER@]HOST    Operate on remote host\n"
2487
               "  -M --machine=CONTAINER   Operate on local container\n"
2488
               "     --address=ADDRESS     Connect to bus specified by address\n"
2489
               "     --show-machine        Show machine ID column in list\n"
2490
               "     --unique              Only show unique names\n"
2491
               "     --acquired            Only show acquired names\n"
2492
               "     --activatable         Only show activatable names\n"
2493
               "     --match=MATCH         Only show matching messages\n"
2494
               "     --size=SIZE           Maximum length of captured packet\n"
2495
               "     --list                Don't show tree, but simple object path list\n"
2496
               "  -q --quiet               Don't show method call reply\n"
2497
               "     --verbose             Show result values in long format\n"
2498
               "     --json=MODE           Output as JSON\n"
2499
               "  -j                       Same as --json=pretty on tty, --json=short otherwise\n"
2500
               "     --xml-interface       Dump the XML description in introspect command\n"
2501
               "     --expect-reply=BOOL   Expect a method call reply\n"
2502
               "     --auto-start=BOOL     Auto-start destination service\n"
2503
               "     --allow-interactive-authorization=BOOL\n"
2504
               "                           Allow interactive authorization for operation\n"
2505
               "     --timeout=SECS        Maximum time to wait for method call completion\n"
2506
               "     --augment-creds=BOOL  Extend credential data with data read from /proc/$PID\n"
2507
               "     --watch-bind=BOOL     Wait for bus AF_UNIX socket to be bound in the file\n"
2508
               "                           system\n"
2509
               "     --destination=SERVICE Destination service of a signal\n"
2510
               "  -N --limit-messages=NUMBER\n"
2511
               "                           Stop monitoring after receiving the specified number\n"
2512
               "                           of messages\n"
2513
               "\nSee the %2$s for details.\n",
2514
               program_invocation_short_name,
2515
               link,
2516
               ansi_underline(),
2517
               ansi_normal(),
2518
               ansi_highlight(),
2519
               ansi_normal());
2520

2521
        return 0;
2522
}
2523

2524
static int verb_help(int argc, char **argv, void *userdata) {
1✔
2525
        return help();
1✔
2526
}
2527

2528
static int parse_argv(int argc, char *argv[]) {
1,165✔
2529

2530
        enum {
1,165✔
2531
                ARG_VERSION = 0x100,
2532
                ARG_NO_PAGER,
2533
                ARG_NO_LEGEND,
2534
                ARG_SYSTEM,
2535
                ARG_USER,
2536
                ARG_ADDRESS,
2537
                ARG_MATCH,
2538
                ARG_SHOW_MACHINE,
2539
                ARG_UNIQUE,
2540
                ARG_ACQUIRED,
2541
                ARG_ACTIVATABLE,
2542
                ARG_SIZE,
2543
                ARG_LIST,
2544
                ARG_VERBOSE,
2545
                ARG_XML_INTERFACE,
2546
                ARG_EXPECT_REPLY,
2547
                ARG_AUTO_START,
2548
                ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
2549
                ARG_TIMEOUT,
2550
                ARG_AUGMENT_CREDS,
2551
                ARG_WATCH_BIND,
2552
                ARG_JSON,
2553
                ARG_DESTINATION,
2554
        };
2555

2556
        static const struct option options[] = {
1,165✔
2557
                { "help",                            no_argument,       NULL, 'h'                                 },
2558
                { "version",                         no_argument,       NULL, ARG_VERSION                         },
2559
                { "no-pager",                        no_argument,       NULL, ARG_NO_PAGER                        },
2560
                { "no-legend",                       no_argument,       NULL, ARG_NO_LEGEND                       },
2561
                { "full",                            no_argument,       NULL, 'l'                                 },
2562
                { "system",                          no_argument,       NULL, ARG_SYSTEM                          },
2563
                { "user",                            no_argument,       NULL, ARG_USER                            },
2564
                { "address",                         required_argument, NULL, ARG_ADDRESS                         },
2565
                { "show-machine",                    no_argument,       NULL, ARG_SHOW_MACHINE                    },
2566
                { "unique",                          no_argument,       NULL, ARG_UNIQUE                          },
2567
                { "acquired",                        no_argument,       NULL, ARG_ACQUIRED                        },
2568
                { "activatable",                     no_argument,       NULL, ARG_ACTIVATABLE                     },
2569
                { "match",                           required_argument, NULL, ARG_MATCH                           },
2570
                { "host",                            required_argument, NULL, 'H'                                 },
2571
                { "machine",                         required_argument, NULL, 'M'                                 },
2572
                { "capsule",                         required_argument, NULL, 'C'                                 },
2573
                { "size",                            required_argument, NULL, ARG_SIZE                            },
2574
                { "list",                            no_argument,       NULL, ARG_LIST                            },
2575
                { "quiet",                           no_argument,       NULL, 'q'                                 },
2576
                { "verbose",                         no_argument,       NULL, ARG_VERBOSE                         },
2577
                { "xml-interface",                   no_argument,       NULL, ARG_XML_INTERFACE                   },
2578
                { "expect-reply",                    required_argument, NULL, ARG_EXPECT_REPLY                    },
2579
                { "auto-start",                      required_argument, NULL, ARG_AUTO_START                      },
2580
                { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
2581
                { "timeout",                         required_argument, NULL, ARG_TIMEOUT                         },
2582
                { "augment-creds",                   required_argument, NULL, ARG_AUGMENT_CREDS                   },
2583
                { "watch-bind",                      required_argument, NULL, ARG_WATCH_BIND                      },
2584
                { "json",                            required_argument, NULL, ARG_JSON                            },
2585
                { "destination",                     required_argument, NULL, ARG_DESTINATION                     },
2586
                { "limit-messages",                  required_argument, NULL, 'N'                                 },
2587
                {},
2588
        };
2589

2590
        int c, r;
1,165✔
2591

2592
        assert(argc >= 0);
1,165✔
2593
        assert(argv);
1,165✔
2594

2595
        while ((c = getopt_long(argc, argv, "hH:M:C:J:qjlN:", options, NULL)) >= 0)
1,213✔
2596

2597
                switch (c) {
50✔
2598

2599
                case 'h':
1✔
2600
                        return help();
1✔
2601

2602
                case ARG_VERSION:
1✔
2603
                        return version();
1✔
2604

2605
                case ARG_NO_PAGER:
7✔
2606
                        arg_pager_flags |= PAGER_DISABLE;
7✔
2607
                        break;
7✔
2608

2609
                case ARG_NO_LEGEND:
1✔
2610
                        arg_legend = false;
1✔
2611
                        break;
1✔
2612

2613
                case 'l':
1✔
2614
                        arg_full = true;
1✔
2615
                        break;
1✔
2616

2617
                case ARG_USER:
1✔
2618
                        arg_runtime_scope = RUNTIME_SCOPE_USER;
1✔
2619
                        break;
1✔
2620

2621
                case ARG_SYSTEM:
×
2622
                        arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
×
2623
                        break;
×
2624

2625
                case ARG_ADDRESS:
×
2626
                        arg_address = optarg;
×
2627
                        break;
×
2628

2629
                case ARG_SHOW_MACHINE:
1✔
2630
                        arg_show_machine = true;
1✔
2631
                        break;
1✔
2632

2633
                case ARG_UNIQUE:
1✔
2634
                        arg_unique = true;
1✔
2635
                        break;
1✔
2636

2637
                case ARG_ACQUIRED:
1✔
2638
                        arg_acquired = true;
1✔
2639
                        break;
1✔
2640

2641
                case ARG_ACTIVATABLE:
1✔
2642
                        arg_activatable = true;
1✔
2643
                        break;
1✔
2644

2645
                case ARG_MATCH:
2✔
2646
                        if (strv_extend(&arg_matches, optarg) < 0)
2✔
2647
                                return log_oom();
×
2648
                        break;
2649

2650
                case ARG_SIZE: {
×
2651
                        uint64_t sz;
×
2652

2653
                        r = parse_size(optarg, 1024, &sz);
×
2654
                        if (r < 0)
×
2655
                                return log_error_errno(r, "Failed to parse size '%s': %m", optarg);
×
2656

2657
                        if ((uint64_t) (size_t) sz !=  sz)
×
2658
                                return log_error_errno(SYNTHETIC_ERRNO(E2BIG),
2659
                                                       "Size out of range.");
2660

2661
                        arg_snaplen = (size_t) sz;
×
2662
                        break;
×
2663
                }
2664

2665
                case ARG_LIST:
1✔
2666
                        arg_list = true;
1✔
2667
                        break;
1✔
2668

2669
                case 'H':
×
2670
                        arg_transport = BUS_TRANSPORT_REMOTE;
×
2671
                        arg_host = optarg;
×
2672
                        break;
×
2673

2674
                case 'M':
2✔
2675
                        arg_transport = BUS_TRANSPORT_MACHINE;
2✔
2676
                        arg_host = optarg;
2✔
2677
                        break;
2✔
2678

2679
                case 'C':
1✔
2680
                        r = capsule_name_is_valid(optarg);
1✔
2681
                        if (r < 0)
1✔
2682
                                return log_error_errno(r, "Unable to validate capsule name '%s': %m", optarg);
×
2683
                        if (r == 0)
1✔
2684
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", optarg);
×
2685

2686
                        arg_host = optarg;
1✔
2687
                        arg_transport = BUS_TRANSPORT_CAPSULE;
1✔
2688
                        break;
1✔
2689

2690
                case 'q':
2✔
2691
                        arg_quiet = true;
2✔
2692
                        break;
2✔
2693

2694
                case ARG_VERBOSE:
2✔
2695
                        arg_verbose = true;
2✔
2696
                        break;
2✔
2697

2698
                case ARG_XML_INTERFACE:
1✔
2699
                        arg_xml_interface = true;
1✔
2700
                        break;
1✔
2701

2702
                case ARG_EXPECT_REPLY:
1✔
2703
                        r = parse_boolean_argument("--expect-reply=", optarg, &arg_expect_reply);
1✔
2704
                        if (r < 0)
1✔
2705
                                return r;
2706
                        break;
2707

2708
                case ARG_AUTO_START:
1✔
2709
                        r = parse_boolean_argument("--auto-start=", optarg, &arg_auto_start);
1✔
2710
                        if (r < 0)
1✔
2711
                                return r;
2712
                        break;
2713

2714
                case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
1✔
2715
                        r = parse_boolean_argument("--allow-interactive-authorization=", optarg,
1✔
2716
                                                   &arg_allow_interactive_authorization);
2717
                        if (r < 0)
1✔
2718
                                return r;
2719
                        break;
2720

2721
                case ARG_TIMEOUT:
4✔
2722
                        if (isempty(optarg)) {
4✔
2723
                                arg_timeout = 0; /* Reset to default */
×
2724
                                break;
×
2725
                        }
2726

2727
                        r = parse_sec(optarg, &arg_timeout);
4✔
2728
                        if (r < 0)
4✔
2729
                                return log_error_errno(r, "Failed to parse --timeout= parameter '%s': %m", optarg);
×
2730

2731
                        break;
2732

2733
                case ARG_AUGMENT_CREDS:
1✔
2734
                        r = parse_boolean_argument("--augment-creds=", optarg, &arg_augment_creds);
1✔
2735
                        if (r < 0)
1✔
2736
                                return r;
2737
                        break;
2738

2739
                case ARG_WATCH_BIND:
1✔
2740
                        r = parse_boolean_argument("--watch-bind=", optarg, &arg_watch_bind);
1✔
2741
                        if (r < 0)
1✔
2742
                                return r;
2743
                        break;
2744

2745
                case 'j':
3✔
2746
                        arg_json_format_flags = SD_JSON_FORMAT_PRETTY_AUTO|SD_JSON_FORMAT_COLOR_AUTO;
3✔
2747
                        break;
3✔
2748

2749
                case ARG_JSON:
9✔
2750
                        r = parse_json_argument(optarg, &arg_json_format_flags);
9✔
2751
                        if (r <= 0)
9✔
2752
                                return r;
2753

2754
                        break;
2755

2756
                case ARG_DESTINATION:
1✔
2757
                        arg_destination = optarg;
1✔
2758
                        break;
1✔
2759

2760
                case 'N':
1✔
2761
                        if (isempty(optarg)) {
1✔
2762
                                arg_limit_messages = UINT64_MAX; /* Reset to default */
×
2763
                                break;
×
2764
                        }
2765

2766
                        r = safe_atou64(optarg, &arg_limit_messages);
1✔
2767
                        if (r < 0)
1✔
2768
                                return log_error_errno(r, "Failed to parse --limit-messages= parameter: %s", optarg);
×
2769
                        if (arg_limit_messages == 0)
1✔
2770
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--limit-messages= parameter cannot be 0");
×
2771

2772
                        break;
2773

2774
                case '?':
2775
                        return -EINVAL;
2776

2777
                default:
×
2778
                        assert_not_reached();
×
2779
                }
2780

2781
        if (arg_full < 0)
1,163✔
2782
                arg_full = terminal_is_dumb();
1,162✔
2783

2784
        return 1;
2785
}
2786

2787
static int busctl_main(int argc, char *argv[]) {
1,163✔
2788
        static const Verb verbs[] = {
1,163✔
2789
                { "list",         VERB_ANY, 1,        VERB_DEFAULT, list_bus_names },
2790
                { "status",       VERB_ANY, 2,        0,            status         },
2791
                { "monitor",      VERB_ANY, VERB_ANY, 0,            verb_monitor   },
2792
                { "capture",      VERB_ANY, VERB_ANY, 0,            verb_capture   },
2793
                { "tree",         VERB_ANY, VERB_ANY, 0,            tree           },
2794
                { "introspect",   3,        4,        0,            introspect     },
2795
                { "call",         5,        VERB_ANY, 0,            call           },
2796
                { "emit",         4,        VERB_ANY, 0,            emit_signal    },
2797
                { "wait",         4,        5,        0,            wait_signal    },
2798
                { "get-property", 5,        VERB_ANY, 0,            get_property   },
2799
                { "set-property", 6,        VERB_ANY, 0,            set_property   },
2800
                { "help",         VERB_ANY, VERB_ANY, 0,            verb_help      },
2801
                {}
2802
        };
2803

2804
        return dispatch_verb(argc, argv, verbs, NULL);
1,163✔
2805
}
2806

2807
static int run(int argc, char *argv[]) {
1,165✔
2808
        int r;
1,165✔
2809

2810
        log_setup();
1,165✔
2811

2812
        r = parse_argv(argc, argv);
1,165✔
2813
        if (r <= 0)
1,165✔
2814
                return r;
2815

2816
        return busctl_main(argc, argv);
1,163✔
2817
}
2818

2819
DEFINE_MAIN_FUNCTION(run);
2,330✔
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