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

systemd / systemd / 14895667988

07 May 2025 08:57PM UTC coverage: 72.225% (-0.007%) from 72.232%
14895667988

push

github

yuwata
network: log_link_message_debug_errno() automatically append %m if necessary

Follow-up for d28746ef5.
Fixes CID#1609753.

0 of 1 new or added line in 1 file covered. (0.0%)

20297 existing lines in 338 files now uncovered.

297407 of 411780 relevant lines covered (72.22%)

695716.85 hits per line

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

82.45
/src/shared/bus-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <errno.h>
4
#include <fcntl.h>
5
#include <inttypes.h>
6
#include <stdlib.h>
7
#include <sys/ioctl.h>
8
#include <sys/resource.h>
9
#include <sys/socket.h>
10
#include <unistd.h>
11

12
#include "sd-bus.h"
13
#include "sd-daemon.h"
14
#include "sd-event.h"
15
#include "sd-id128.h"
16

17
#include "alloc-util.h"
18
#include "bus-common-errors.h"
19
#include "bus-internal.h"
20
#include "bus-label.h"
21
#include "bus-util.h"
22
#include "capsule-util.h"
23
#include "chase.h"
24
#include "daemon-util.h"
25
#include "env-util.h"
26
#include "fd-util.h"
27
#include "format-util.h"
28
#include "log.h"
29
#include "memfd-util.h"
30
#include "memstream-util.h"
31
#include "path-util.h"
32
#include "socket-util.h"
33
#include "stdio-util.h"
34
#include "string-table.h"
35
#include "strv.h"
36
#include "uid-classification.h"
37

38
static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
16✔
39
        sd_event *e = ASSERT_PTR(userdata);
16✔
40

41
        assert(m);
16✔
42

43
        sd_bus_close(sd_bus_message_get_bus(m));
16✔
44
        sd_event_exit(e, 0);
16✔
45

46
        return 1;
16✔
47
}
48

UNCOV
49
int bus_log_address_error(int r, BusTransport transport) {
×
50
        bool hint = transport == BUS_TRANSPORT_LOCAL && r == -ENOMEDIUM;
×
51

UNCOV
52
        return log_error_errno(r,
×
53
                               hint ? "Failed to set bus address: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user)" :
54
                                      "Failed to set bus address: %m");
55
}
56

57
int bus_log_connect_full(int log_level, int r, BusTransport transport, RuntimeScope scope) {
8✔
58
        bool hint_vars = transport == BUS_TRANSPORT_LOCAL && r == -ENOMEDIUM,
8✔
59
             hint_addr = transport == BUS_TRANSPORT_LOCAL && ERRNO_IS_PRIVILEGE(r);
8✔
60

61
        return log_full_errno(log_level, r,
15✔
62
                              hint_vars ? "Failed to connect to %s scope bus via %s transport: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user)" :
63
                              hint_addr ? "Failed to connect to %s scope bus via %s transport: Operation not permitted (consider using --machine=<user>@.host --user to connect to bus of other user)" :
64
                                          "Failed to connect to %s scope bus via %s transport: %m", runtime_scope_to_string(scope), bus_transport_to_string(transport));
65
}
66

67
int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name) {
16✔
68
        const char *match;
16✔
69
        const char *unique;
16✔
70
        int r;
16✔
71

72
        assert(e);
16✔
73
        assert(bus);
16✔
74
        assert(name);
16✔
75

76
        /* We unregister the name here and then wait for the
77
         * NameOwnerChanged signal for this event to arrive before we
78
         * quit. We do this in order to make sure that any queued
79
         * requests are still processed before we really exit. */
80

81
        r = sd_bus_get_unique_name(bus, &unique);
16✔
82
        if (r < 0)
16✔
83
                return r;
16✔
84

85
        match = strjoina(
240✔
86
                        "sender='org.freedesktop.DBus',"
87
                        "type='signal',"
88
                        "interface='org.freedesktop.DBus',"
89
                        "member='NameOwnerChanged',"
90
                        "path='/org/freedesktop/DBus',"
91
                        "arg0='", name, "',",
92
                        "arg1='", unique, "',",
93
                        "arg2=''");
94

95
        r = sd_bus_add_match_async(bus, NULL, match, name_owner_change_callback, NULL, e);
16✔
96
        if (r < 0)
16✔
97
                return r;
98

99
        r = sd_bus_release_name_async(bus, NULL, name, NULL, NULL);
16✔
100
        if (r < 0)
16✔
UNCOV
101
                return r;
×
102

103
        return 0;
104
}
105

106
static bool idle_allowed(void) {
49,704✔
107
        static int allowed = -1;
49,704✔
108

109
        if (allowed >= 0)
49,704✔
UNCOV
110
                return allowed;
×
111

112
        allowed = secure_getenv_bool("SYSTEMD_EXIT_ON_IDLE");
49,704✔
113
        if (allowed < 0 && allowed != -ENXIO)
49,704✔
UNCOV
114
                log_debug_errno(allowed, "Failed to parse $SYSTEMD_EXIT_ON_IDLE, ignoring: %m");
×
115

116
        return allowed != 0;
49,704✔
117
}
118

119
int bus_event_loop_with_idle(
120✔
120
                sd_event *e,
121
                sd_bus *bus,
122
                const char *name,
123
                usec_t timeout,
124
                check_idle_t check_idle,
125
                void *userdata) {
126

127
        bool exiting = false;
120✔
128
        int r, code;
120✔
129

130
        assert(e);
120✔
131
        assert(bus);
120✔
132
        assert(name);
120✔
133

134
        for (;;) {
49,769✔
135
                bool idle;
49,769✔
136

137
                r = sd_event_get_state(e);
49,769✔
138
                if (r < 0)
49,769✔
139
                        return r;
65✔
140
                if (r == SD_EVENT_FINISHED)
49,769✔
141
                        break;
142

143
                if (!idle_allowed() || sd_bus_pending_method_calls(bus) > 0)
49,704✔
144
                        idle = false;
145
                else if (check_idle)
48,651✔
146
                        idle = check_idle(userdata);
48,651✔
147
                else
148
                        idle = true;
149

150
                r = sd_event_run(e, exiting || !idle ? UINT64_MAX : timeout);
90,071✔
151
                if (r < 0)
49,649✔
152
                        return r;
153

154
                if (r == 0 && !exiting && idle) {
49,649✔
155
                        log_debug("Idle for %s, exiting.", FORMAT_TIMESPAN(timeout, 1));
16✔
156

157
                        /* Inform the service manager that we are going down, so that it will queue all
158
                         * further start requests, instead of assuming we are still running. */
159
                        (void) sd_notify(false, NOTIFY_STOPPING_MESSAGE);
16✔
160

161
                        r = bus_async_unregister_and_exit(e, bus, name);
16✔
162
                        if (r < 0)
16✔
163
                                return r;
164

165
                        exiting = true;
166
                }
167
        }
168

169
        r = sd_event_get_exit_code(e, &code);
65✔
170
        if (r < 0)
65✔
171
                return r;
172

173
        return code;
65✔
174
}
175

176
int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) {
118✔
177
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL;
118✔
178
        int r, has_owner = 0;
118✔
179

180
        assert(c);
118✔
181
        assert(name);
118✔
182

183
        r = sd_bus_call_method(c,
118✔
184
                               "org.freedesktop.DBus",
185
                               "/org/freedesktop/dbus",
186
                               "org.freedesktop.DBus",
187
                               "NameHasOwner",
188
                               error,
189
                               &rep,
190
                               "s",
191
                               name);
192
        if (r < 0)
118✔
193
                return r;
194

195
        r = sd_bus_message_read_basic(rep, 'b', &has_owner);
118✔
196
        if (r < 0)
118✔
UNCOV
197
                return sd_bus_error_set_errno(error, r);
×
198

199
        return has_owner;
118✔
200
}
201

202
bool bus_error_is_unknown_service(const sd_bus_error *error) {
84✔
203
        return sd_bus_error_has_names(error,
84✔
204
                                      SD_BUS_ERROR_SERVICE_UNKNOWN,
205
                                      SD_BUS_ERROR_NAME_HAS_NO_OWNER,
206
                                      BUS_ERROR_NO_SUCH_UNIT);
207
}
208

209
int bus_check_peercred(sd_bus *c) {
12,346✔
210
        struct ucred ucred;
12,346✔
211
        int fd, r;
12,346✔
212

213
        assert(c);
12,346✔
214

215
        fd = sd_bus_get_fd(c);
12,346✔
216
        if (fd < 0)
12,346✔
217
                return fd;
12,346✔
218

219
        r = getpeercred(fd, &ucred);
12,346✔
220
        if (r < 0)
12,346✔
221
                return r;
222

223
        if (ucred.uid != 0 && ucred.uid != geteuid())
12,346✔
UNCOV
224
                return -EPERM;
×
225

226
        return 1;
227
}
228

229
int bus_connect_system_systemd(sd_bus **ret_bus) {
11,469✔
230
        _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
11,469✔
231
        int r;
11,469✔
232

233
        assert(ret_bus);
11,469✔
234

235
        r = sd_bus_new(&bus);
11,469✔
236
        if (r < 0)
11,469✔
237
                return r;
238

239
        r = sd_bus_set_address(bus, "unix:path=/run/systemd/private");
11,469✔
240
        if (r < 0)
11,469✔
241
                return r;
242

243
        r = sd_bus_start(bus);
11,469✔
244
        if (r < 0)
11,469✔
245
                return r;
246

247
        r = bus_check_peercred(bus);
11,467✔
248
        if (r < 0)
11,467✔
249
                return r;
250

251
        *ret_bus = TAKE_PTR(bus);
11,467✔
252
        return 0;
11,467✔
253
}
254

255
int bus_connect_user_systemd(sd_bus **ret_bus) {
179✔
256
        _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
179✔
257
        _cleanup_free_ char *ee = NULL;
179✔
258
        const char *e;
179✔
259
        int r;
179✔
260

261
        assert(ret_bus);
179✔
262

263
        e = secure_getenv("XDG_RUNTIME_DIR");
179✔
264
        if (!e)
179✔
265
                return -ENOMEDIUM;
266

267
        ee = bus_address_escape(e);
178✔
268
        if (!ee)
178✔
269
                return -ENOMEM;
270

271
        r = sd_bus_new(&bus);
178✔
272
        if (r < 0)
178✔
273
                return r;
274

275
        bus->address = strjoin("unix:path=", ee, "/systemd/private");
178✔
276
        if (!bus->address)
178✔
277
                return -ENOMEM;
278

279
        r = sd_bus_start(bus);
178✔
280
        if (r < 0)
178✔
281
                return r;
282

283
        r = bus_check_peercred(bus);
178✔
284
        if (r < 0)
178✔
285
                return r;
286

287
        *ret_bus = TAKE_PTR(bus);
178✔
288
        return 0;
178✔
289
}
290

291
static int pin_capsule_socket(const char *capsule, const char *suffix, uid_t *ret_uid, gid_t *ret_gid) {
5✔
292
        _cleanup_close_ int inode_fd = -EBADF;
5✔
293
        _cleanup_free_ char *p = NULL;
5✔
294
        struct stat st;
5✔
295
        int r;
5✔
296

297
        assert(capsule);
5✔
298
        assert(suffix);
5✔
299
        assert(ret_uid);
5✔
300
        assert(ret_gid);
5✔
301

302
        p = path_join("/run/capsules", capsule, suffix);
5✔
303
        if (!p)
5✔
304
                return -ENOMEM;
305

306
        /* We enter territory owned by the user, hence let's be paranoid about symlinks and ownership */
307
        r = chase(p, /* root= */ NULL, CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS, /* ret_path= */ NULL, &inode_fd);
5✔
308
        if (r < 0)
5✔
309
                return r;
310

311
        if (fstat(inode_fd, &st) < 0)
5✔
UNCOV
312
                return negative_errno();
×
313

314
        /* Paranoid safety check */
315
        if (uid_is_system(st.st_uid) || gid_is_system(st.st_gid))
5✔
UNCOV
316
                return -EPERM;
×
317

318
        *ret_uid = st.st_uid;
5✔
319
        *ret_gid = st.st_gid;
5✔
320

321
        return TAKE_FD(inode_fd);
5✔
322
}
323

324
static int bus_set_address_capsule(sd_bus *bus, const char *capsule, const char *suffix, int *ret_pin_fd) {
5✔
325
        _cleanup_close_ int inode_fd = -EBADF;
5✔
326
        _cleanup_free_ char *pp = NULL;
5✔
327
        uid_t uid;
5✔
328
        gid_t gid;
5✔
329
        int r;
5✔
330

331
        assert(bus);
5✔
332
        assert(capsule);
5✔
333
        assert(suffix);
5✔
334
        assert(ret_pin_fd);
5✔
335

336
        /* Connects to a capsule's user bus. We need to do so under the capsule's UID/GID, otherwise
337
         * the service manager might refuse our connection. Hence fake it. */
338

339
        r = capsule_name_is_valid(capsule);
5✔
340
        if (r < 0)
5✔
341
                return r;
342
        if (r == 0)
5✔
343
                return -EINVAL;
344

345
        inode_fd = pin_capsule_socket(capsule, suffix, &uid, &gid);
5✔
346
        if (inode_fd < 0)
5✔
347
                return inode_fd;
348

349
        pp = bus_address_escape(FORMAT_PROC_FD_PATH(inode_fd));
5✔
350
        if (!pp)
5✔
351
                return -ENOMEM;
352

353
        if (asprintf(&bus->address, "unix:path=%s,uid=" UID_FMT ",gid=" GID_FMT, pp, uid, gid) < 0)
5✔
354
                return -ENOMEM;
355

356
        *ret_pin_fd = TAKE_FD(inode_fd); /* This fd must be kept pinned until the connection has been established */
5✔
357
        return 0;
5✔
358
}
359

360
int bus_set_address_capsule_bus(sd_bus *bus, const char *capsule, int *ret_pin_fd) {
1✔
361
        return bus_set_address_capsule(bus, capsule, "bus", ret_pin_fd);
1✔
362
}
363

364
int bus_connect_capsule_systemd(const char *capsule, sd_bus **ret_bus) {
4✔
365
        _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
4✔
366
        _cleanup_close_ int inode_fd = -EBADF;
4✔
367
        int r;
4✔
368

369
        assert(capsule);
4✔
370
        assert(ret_bus);
4✔
371

372
        r = sd_bus_new(&bus);
4✔
373
        if (r < 0)
4✔
374
                return r;
375

376
        r = bus_set_address_capsule(bus, capsule, "systemd/private", &inode_fd);
4✔
377
        if (r < 0)
4✔
378
                return r;
379

380
        r = sd_bus_start(bus);
4✔
381
        if (r < 0)
4✔
382
                return r;
383

384
        *ret_bus = TAKE_PTR(bus);
4✔
385
        return 0;
4✔
386
}
387

388
int bus_connect_capsule_bus(const char *capsule, sd_bus **ret_bus) {
×
389
        _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
×
UNCOV
390
        _cleanup_close_ int inode_fd = -EBADF;
×
391
        int r;
×
392

UNCOV
393
        assert(capsule);
×
394
        assert(ret_bus);
×
395

UNCOV
396
        r = sd_bus_new(&bus);
×
UNCOV
397
        if (r < 0)
×
398
                return r;
399

UNCOV
400
        r = bus_set_address_capsule_bus(bus, capsule, &inode_fd);
×
UNCOV
401
        if (r < 0)
×
402
                return r;
403

UNCOV
404
        r = sd_bus_set_bus_client(bus, true);
×
UNCOV
405
        if (r < 0)
×
406
                return r;
407

UNCOV
408
        r = sd_bus_start(bus);
×
UNCOV
409
        if (r < 0)
×
410
                return r;
411

UNCOV
412
        *ret_bus = TAKE_PTR(bus);
×
UNCOV
413
        return 0;
×
414
}
415

416
int bus_connect_transport(
2,344✔
417
                BusTransport transport,
418
                const char *host,
419
                RuntimeScope runtime_scope,
420
                sd_bus **ret) {
421

422
        _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
2,344✔
423
        int r;
2,344✔
424

425
        assert(transport >= 0);
2,344✔
426
        assert(transport < _BUS_TRANSPORT_MAX);
2,344✔
427
        assert(ret);
2,344✔
428

429
        switch (transport) {
2,344✔
430

431
        case BUS_TRANSPORT_LOCAL:
2,274✔
432
                assert_return(!host, -EINVAL);
2,274✔
433

434
                switch (runtime_scope) {
2,274✔
435

436
                case RUNTIME_SCOPE_USER:
30✔
437
                        r = sd_bus_default_user(&bus);
30✔
438
                        break;
439

440
                case RUNTIME_SCOPE_SYSTEM:
2,244✔
441
                        if (sd_booted() <= 0)
2,244✔
442
                                /* Print a friendly message when the local system is actually not running systemd as PID 1. */
UNCOV
443
                                return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
×
444
                                                       "System has not been booted with systemd as init system (PID 1). Can't operate.");
445

446
                        r = sd_bus_default_system(&bus);
2,244✔
447
                        break;
448

UNCOV
449
                default:
×
UNCOV
450
                        assert_not_reached();
×
451
                }
452
                break;
453

UNCOV
454
        case BUS_TRANSPORT_REMOTE:
×
455
                assert_return(runtime_scope == RUNTIME_SCOPE_SYSTEM, -EOPNOTSUPP);
×
456

UNCOV
457
                r = sd_bus_open_system_remote(&bus, host);
×
458
                break;
459

460
        case BUS_TRANSPORT_MACHINE:
70✔
461
                switch (runtime_scope) {
70✔
462

463
                case RUNTIME_SCOPE_USER:
53✔
464
                        r = sd_bus_open_user_machine(&bus, host);
53✔
465
                        break;
466

467
                case RUNTIME_SCOPE_SYSTEM:
17✔
468
                        r = sd_bus_open_system_machine(&bus, host);
17✔
469
                        break;
470

UNCOV
471
                default:
×
UNCOV
472
                        assert_not_reached();
×
473
                }
474

475
                break;
476

UNCOV
477
        case BUS_TRANSPORT_CAPSULE:
×
478
                assert_return(runtime_scope == RUNTIME_SCOPE_USER, -EINVAL);
×
479

UNCOV
480
                r = bus_connect_capsule_bus(host, &bus);
×
481
                break;
482

UNCOV
483
        default:
×
UNCOV
484
                assert_not_reached();
×
485
        }
486
        if (r < 0)
2,344✔
487
                return r;
488

489
        r = sd_bus_set_exit_on_disconnect(bus, true);
2,337✔
490
        if (r < 0)
2,337✔
491
                return r;
492

493
        *ret = TAKE_PTR(bus);
2,337✔
494
        return 0;
2,337✔
495
}
496

497
int bus_connect_transport_systemd(
11,412✔
498
                BusTransport transport,
499
                const char *host,
500
                RuntimeScope runtime_scope,
501
                sd_bus **ret_bus) {
502

503
        int r;
11,412✔
504

505
        assert(transport >= 0);
11,412✔
506
        assert(transport < _BUS_TRANSPORT_MAX);
11,412✔
507
        assert(ret_bus);
11,412✔
508

509
        switch (transport) {
11,412✔
510

511
        case BUS_TRANSPORT_LOCAL:
11,407✔
512
                assert_return(!host, -EINVAL);
11,407✔
513

514
                switch (runtime_scope) {
11,407✔
515

516
                case RUNTIME_SCOPE_USER:
179✔
517
                        r = bus_connect_user_systemd(ret_bus);
179✔
518
                        /* We used to always fall back to the user session bus if we couldn't connect to the
519
                         * private manager bus. To keep compat with existing code that was setting
520
                         * DBUS_SESSION_BUS_ADDRESS without setting XDG_RUNTIME_DIR, connect to the user
521
                         * session bus if DBUS_SESSION_BUS_ADDRESS is set and XDG_RUNTIME_DIR isn't. */
522
                        if (r == -ENOMEDIUM && secure_getenv("DBUS_SESSION_BUS_ADDRESS")) {
179✔
UNCOV
523
                                log_debug_errno(r, "$XDG_RUNTIME_DIR not set, unable to connect to private bus. Falling back to session bus.");
×
UNCOV
524
                                r = sd_bus_default_user(ret_bus);
×
525
                        }
526

527
                        return r;
528

529
                case RUNTIME_SCOPE_SYSTEM:
11,228✔
530
                        if (sd_booted() <= 0)
11,228✔
531
                                /* Print a friendly message when the local system is actually not running systemd as PID 1. */
UNCOV
532
                                return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN),
×
533
                                                       "System has not been booted with systemd as init system (PID 1). Can't operate.");
534

535
                        /* If we are root then let's talk directly to the system instance, instead of
536
                         * going via the bus. */
537
                        if (geteuid() == 0)
11,228✔
538
                                return bus_connect_system_systemd(ret_bus);
11,214✔
539

540
                        return sd_bus_default_system(ret_bus);
14✔
541

UNCOV
542
                default:
×
UNCOV
543
                        assert_not_reached();
×
544
                }
545

546
                break;
×
547

548
        case BUS_TRANSPORT_REMOTE:
×
UNCOV
549
                assert_return(runtime_scope == RUNTIME_SCOPE_SYSTEM, -EOPNOTSUPP);
×
UNCOV
550
                return sd_bus_open_system_remote(ret_bus, host);
×
551

552
        case BUS_TRANSPORT_MACHINE:
1✔
553
                assert_return(runtime_scope == RUNTIME_SCOPE_SYSTEM, -EOPNOTSUPP);
1✔
554
                return sd_bus_open_system_machine(ret_bus, host);
1✔
555

556
        case BUS_TRANSPORT_CAPSULE:
4✔
557
                assert_return(runtime_scope == RUNTIME_SCOPE_USER, -EINVAL);
4✔
558
                return bus_connect_capsule_systemd(host, ret_bus);
4✔
559

UNCOV
560
        default:
×
UNCOV
561
                assert_not_reached();
×
562
        }
563
}
564

565
/**
566
 * bus_path_encode_unique() - encode unique object path
567
 * @b: bus connection or NULL
568
 * @prefix: object path prefix
569
 * @sender_id: unique-name of client, or NULL
570
 * @external_id: external ID to be chosen by client, or NULL
571
 * @ret_path: storage for encoded object path pointer
572
 *
573
 * Whenever we provide a bus API that allows clients to create and manage
574
 * server-side objects, we need to provide a unique name for these objects. If
575
 * we let the server choose the name, we suffer from a race condition: If a
576
 * client creates an object asynchronously, it cannot destroy that object until
577
 * it received the method reply. It cannot know the name of the new object,
578
 * thus, it cannot destroy it. Furthermore, it enforces a round-trip.
579
 *
580
 * Therefore, many APIs allow the client to choose the unique name for newly
581
 * created objects. There're two problems to solve, though:
582
 *    1) Object names are usually defined via dbus object paths, which are
583
 *       usually globally namespaced. Therefore, multiple clients must be able
584
 *       to choose unique object names without interference.
585
 *    2) If multiple libraries share the same bus connection, they must be
586
 *       able to choose unique object names without interference.
587
 * The first problem is solved easily by prefixing a name with the
588
 * unique-bus-name of a connection. The server side must enforce this and
589
 * reject any other name. The second problem is solved by providing unique
590
 * suffixes from within sd-bus.
591
 *
592
 * This helper allows clients to create unique object-paths. It uses the
593
 * template '/prefix/sender_id/external_id' and returns the new path in
594
 * @ret_path (must be freed by the caller).
595
 * If @sender_id is NULL, the unique-name of @b is used. If @external_id is
596
 * NULL, this function allocates a unique suffix via @b (by requesting a new
597
 * cookie). If both @sender_id and @external_id are given, @b can be passed as
598
 * NULL.
599
 *
600
 * Returns: 0 on success, negative error code on failure.
601
 */
602
int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path) {
1✔
603
        _cleanup_free_ char *sender_label = NULL, *external_label = NULL;
1✔
604
        char external_buf[DECIMAL_STR_MAX(uint64_t)], *p;
1✔
605
        int r;
1✔
606

607
        assert_return(b || (sender_id && external_id), -EINVAL);
1✔
608
        assert_return(sd_bus_object_path_is_valid(prefix), -EINVAL);
1✔
609
        assert_return(ret_path, -EINVAL);
1✔
610

611
        if (!sender_id) {
1✔
UNCOV
612
                r = sd_bus_get_unique_name(b, &sender_id);
×
UNCOV
613
                if (r < 0)
×
614
                        return r;
615
        }
616

617
        if (!external_id) {
1✔
UNCOV
618
                xsprintf(external_buf, "%"PRIu64, ++b->cookie);
×
619
                external_id = external_buf;
620
        }
621

622
        sender_label = bus_label_escape(sender_id);
1✔
623
        if (!sender_label)
1✔
624
                return -ENOMEM;
625

626
        external_label = bus_label_escape(external_id);
1✔
627
        if (!external_label)
1✔
628
                return -ENOMEM;
629

630
        p = path_join(prefix, sender_label, external_label);
1✔
631
        if (!p)
1✔
632
                return -ENOMEM;
633

634
        *ret_path = p;
1✔
635
        return 0;
1✔
636
}
637

638
/**
639
 * bus_path_decode_unique() - decode unique object path
640
 * @path: object path to decode
641
 * @prefix: object path prefix
642
 * @ret_sender: output parameter for sender-id label
643
 * @ret_external: output parameter for external-id label
644
 *
645
 * This does the reverse of bus_path_encode_unique() (see its description for
646
 * details). Both trailing labels, sender-id and external-id, are unescaped and
647
 * returned in the given output parameters (the caller must free them).
648
 *
649
 * Note that this function returns 0 if the path does not match the template
650
 * (see bus_path_encode_unique()), 1 if it matched.
651
 *
652
 * Returns: Negative error code on failure, 0 if the given object path does not
653
 *          match the template (return parameters are set to NULL), 1 if it was
654
 *          parsed successfully (return parameters contain allocated labels).
655
 */
656
int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external) {
4✔
657
        const char *p, *q;
4✔
658
        char *sender, *external;
4✔
659

660
        assert(sd_bus_object_path_is_valid(path));
4✔
661
        assert(sd_bus_object_path_is_valid(prefix));
4✔
662
        assert(ret_sender);
4✔
663
        assert(ret_external);
4✔
664

665
        p = object_path_startswith(path, prefix);
4✔
666
        if (!p) {
4✔
667
                *ret_sender = NULL;
1✔
668
                *ret_external = NULL;
1✔
669
                return 0;
1✔
670
        }
671

672
        q = strchr(p, '/');
3✔
673
        if (!q) {
3✔
674
                *ret_sender = NULL;
1✔
675
                *ret_external = NULL;
1✔
676
                return 0;
1✔
677
        }
678

679
        sender = bus_label_unescape_n(p, q - p);
2✔
680
        external = bus_label_unescape(q + 1);
2✔
681
        if (!sender || !external) {
2✔
682
                free(sender);
×
UNCOV
683
                free(external);
×
UNCOV
684
                return -ENOMEM;
×
685
        }
686

687
        *ret_sender = sender;
2✔
688
        *ret_external = external;
2✔
689
        return 1;
2✔
690
}
691

692
int bus_track_add_name_many(sd_bus_track *t, char * const *l) {
31✔
693
        int r = 0;
31✔
694

695
        assert(t);
31✔
696

697
        /* Continues adding after failure, and returns the first failure. */
698

699
        STRV_FOREACH(i, l)
89✔
700
                RET_GATHER(r, sd_bus_track_add_name(t, *i));
58✔
701
        return r;
31✔
702
}
703

704
int bus_track_to_strv(sd_bus_track *t, char ***ret) {
78✔
705
        _cleanup_strv_free_ char **subscribed = NULL;
78✔
706
        int r;
78✔
707

708
        assert(ret);
78✔
709

710
        for (const char *n = sd_bus_track_first(t); n; n = sd_bus_track_next(t)) {
193✔
711
                int c = sd_bus_track_count_name(t, n);
115✔
712
                assert(c >= 0);
115✔
713

714
                for (int j = 0; j < c; j++) {
230✔
715
                        r = strv_extend(&subscribed, n);
115✔
716
                        if (r < 0)
115✔
717
                                return r;
718
                }
719
        }
720

721
        *ret = TAKE_PTR(subscribed);
78✔
722
        return 0;
78✔
723
}
724

725
int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) {
693✔
726
        _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
693✔
727
        const char *e;
693✔
728
        int r;
693✔
729

730
        assert(ret);
693✔
731

732
        /* Match like sd_bus_open_system(), but with the "watch_bind" feature and the Connected() signal
733
         * turned on. */
734

735
        r = sd_bus_new(&bus);
693✔
736
        if (r < 0)
693✔
737
                return r;
738

739
        if (description) {
693✔
740
                r = sd_bus_set_description(bus, description);
688✔
741
                if (r < 0)
688✔
742
                        return r;
743
        }
744

745
        e = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
693✔
746
        if (!e)
693✔
747
                e = DEFAULT_SYSTEM_BUS_ADDRESS;
693✔
748

749
        r = sd_bus_set_address(bus, e);
693✔
750
        if (r < 0)
693✔
751
                return r;
752

753
        r = sd_bus_set_bus_client(bus, true);
693✔
754
        if (r < 0)
693✔
755
                return r;
756

757
        r = sd_bus_negotiate_creds(bus, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS);
693✔
758
        if (r < 0)
693✔
759
                return r;
760

761
        r = sd_bus_set_watch_bind(bus, true);
693✔
762
        if (r < 0)
693✔
763
                return r;
764

765
        r = sd_bus_set_connected_signal(bus, true);
693✔
766
        if (r < 0)
693✔
767
                return r;
768

769
        r = sd_bus_start(bus);
693✔
770
        if (r < 0)
693✔
771
                return r;
772

773
        *ret = TAKE_PTR(bus);
693✔
774

775
        return 0;
693✔
776
}
777

778
int bus_reply_pair_array(sd_bus_message *m, char **l) {
55✔
779
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
55✔
780
        int r;
55✔
781

782
        assert(m);
55✔
783

784
        /* Reply to the specified message with a message containing a dictionary put together from the
785
         * specified strv */
786

787
        r = sd_bus_message_new_method_return(m, &reply);
55✔
788
        if (r < 0)
55✔
789
                return r;
790

791
        r = sd_bus_message_open_container(reply, 'a', "{ss}");
55✔
792
        if (r < 0)
55✔
793
                return r;
794

795
        STRV_FOREACH_PAIR(k, v, l) {
440✔
796
                r = sd_bus_message_append(reply, "{ss}", *k, *v);
385✔
797
                if (r < 0)
385✔
798
                        return r;
799
        }
800

801
        r = sd_bus_message_close_container(reply);
55✔
802
        if (r < 0)
55✔
803
                return r;
804

805
        return sd_bus_send(NULL, reply, NULL);
55✔
806
}
807

808
static int method_dump_memory_state_by_fd(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
×
809
        _cleanup_(memstream_done) MemStream m = {};
×
810
        _cleanup_free_ char *dump = NULL;
×
811
        _cleanup_close_ int fd = -EBADF;
×
812
        size_t dump_size;
×
UNCOV
813
        FILE *f;
×
814
        int r;
×
815

816
        assert(message);
×
817

UNCOV
818
        f = memstream_init(&m);
×
UNCOV
819
        if (!f)
×
820
                return -ENOMEM;
821

UNCOV
822
        r = RET_NERRNO(malloc_info(/* options= */ 0, f));
×
UNCOV
823
        if (r < 0)
×
824
                return r;
825

UNCOV
826
        r = memstream_finalize(&m, &dump, &dump_size);
×
UNCOV
827
        if (r < 0)
×
828
                return r;
829

UNCOV
830
        fd = memfd_new_and_seal("malloc-info", dump, dump_size);
×
UNCOV
831
        if (fd < 0)
×
832
                return fd;
833

834
        r = sd_bus_reply_method_return(message, "h", fd);
×
UNCOV
835
        if (r < 0)
×
UNCOV
836
                return r;
×
837

838
        return 1; /* Stop further processing */
839
}
840

841
/* The default install callback will fail and disconnect the bus if it cannot register the match, but this
842
 * is only a debug method, we definitely don't want to fail in case there's some permission issue. */
843
static int dummy_install_callback(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
78✔
844
        return 1;
78✔
845
}
846

847
int bus_register_malloc_status(sd_bus *bus, const char *destination) {
779✔
848
        const char *match;
779✔
849
        int r;
779✔
850

851
        assert(bus);
779✔
852
        assert(!isempty(destination));
779✔
853

854
        match = strjoina("type='method_call',"
7,011✔
855
                         "interface='org.freedesktop.MemoryAllocation1',"
856
                         "path='/org/freedesktop/MemoryAllocation1',"
857
                         "destination='", destination, "',",
858
                         "member='GetMallocInfo'");
859

860
        r = sd_bus_add_match_async(bus, NULL, match, method_dump_memory_state_by_fd, dummy_install_callback, NULL);
779✔
861
        if (r < 0)
779✔
UNCOV
862
                return log_debug_errno(r, "Failed to subscribe to GetMallocInfo() calls on MemoryAllocation1 interface: %m");
×
863

864
        return 0;
865
}
866

867
int bus_creds_get_pidref(
67✔
868
                sd_bus_creds *c,
869
                PidRef *ret) {
870

871
        int pidfd = -EBADF;
67✔
872
        pid_t pid;
67✔
873
        int r;
67✔
874

875
        assert(c);
67✔
876
        assert(ret);
67✔
877

878
        r = sd_bus_creds_get_pid(c, &pid);
67✔
879
        if (r < 0)
67✔
880
                return r;
67✔
881

882
        r = sd_bus_creds_get_pidfd_dup(c, &pidfd);
67✔
883
        if (r < 0 && r != -ENODATA)
67✔
884
                return r;
885

886
        *ret = (PidRef) {
67✔
887
                .pid = pid,
888
                .fd = pidfd,
889
        };
890

891
        return 0;
67✔
892
}
893

894
int bus_query_sender_pidref(
1✔
895
                sd_bus_message *m,
896
                PidRef *ret) {
897

898
        _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
1✔
899
        int r;
1✔
900

901
        assert(m);
1✔
902
        assert(ret);
1✔
903

904
        r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
1✔
905
        if (r < 0)
1✔
906
                return r;
907

908
        return bus_creds_get_pidref(creds, ret);
1✔
909
}
910

911
int bus_get_instance_id(sd_bus *bus, sd_id128_t *ret) {
78✔
912
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
78✔
913
        int r;
78✔
914

915
        assert(bus);
78✔
916
        assert(ret);
78✔
917

918
        r = sd_bus_call_method(bus,
78✔
919
                               "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetId",
920
                               /* error = */ NULL, &reply,
921
                               NULL);
922
        if (r < 0)
78✔
923
                return r;
924

925
        const char *id;
78✔
926

927
        r = sd_bus_message_read_basic(reply, 's', &id);
78✔
928
        if (r < 0)
78✔
929
                return r;
930

931
        return sd_id128_from_string(id, ret);
78✔
932
}
933

934
static const char* const bus_transport_table[] = {
935
        [BUS_TRANSPORT_LOCAL]   = "local",
936
        [BUS_TRANSPORT_REMOTE]  = "remote",
937
        [BUS_TRANSPORT_MACHINE] = "machine",
938
        [BUS_TRANSPORT_CAPSULE] = "capsule",
939
};
940

941
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(bus_transport, BusTransport);
8✔
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