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

systemd / systemd / 13610116813

01 Mar 2025 03:22PM UTC coverage: 71.857% (+0.04%) from 71.822%
13610116813

push

github

DaanDeMeyer
Add a few more bypass environment variables

When we're building ParticleOS images, we don't want the package
manager (or mkosi) to run systemd-sysusers, systemd-tmpfiles or
systemctl preset so let's add a few more bypass environment
variables that we can set to have execution of these skipped like
we already have $SYSTEMD_HWDB_UPDATE_BYPASS and $KERNEL_INSTALL_BYPASS.

12 of 16 new or added lines in 7 files covered. (75.0%)

4203 existing lines in 46 files now uncovered.

294791 of 410246 relevant lines covered (71.86%)

717494.72 hits per line

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

88.79
/src/basic/pidref.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include "errno-util.h"
4
#include "fd-util.h"
5
#include "missing_syscall.h"
6
#include "missing_wait.h"
7
#include "parse-util.h"
8
#include "pidfd-util.h"
9
#include "pidref.h"
10
#include "process-util.h"
11
#include "signal-util.h"
12

13
int pidref_acquire_pidfd_id(PidRef *pidref) {
15,920✔
14
        int r;
15,920✔
15

16
        assert(pidref);
15,920✔
17

18
        if (!pidref_is_set(pidref))
15,920✔
19
                return -ESRCH;
20

21
        if (pidref_is_remote(pidref))
15,920✔
22
                return -EREMOTE;
23

24
        if (pidref->fd < 0)
15,920✔
25
                return -ENOMEDIUM;
26

27
        if (pidref->fd_id > 0)
15,474✔
28
                return 0;
29

30
        r = pidfd_get_inode_id(pidref->fd, &pidref->fd_id);
9,615✔
31
        if (r < 0) {
9,615✔
32
                if (!ERRNO_IS_NEG_NOT_SUPPORTED(r))
2,214✔
33
                        log_debug_errno(r, "Failed to get inode number of pidfd for pid " PID_FMT ": %m",
×
34
                                        pidref->pid);
35
                return r;
2,214✔
36
        }
37

38
        return 0;
39
}
40

41
bool pidref_equal(PidRef *a, PidRef *b) {
25,704✔
42

43
        /* If this is the very same structure, it definitely refers to the same process */
44
        if (a == b)
25,704✔
45
                return true;
46

47
        if (!pidref_is_set(a))
25,701✔
48
                return !pidref_is_set(b);
8,050✔
49

50
        if (!pidref_is_set(b))
21,676✔
51
                return false;
52

53
        if (a->pid != b->pid)
21,670✔
54
                return false;
55

56
        if (pidref_is_remote(a)) {
8,085✔
57
                /* If one is remote and the other isn't, they are not the same */
58
                if (!pidref_is_remote(b))
×
59
                        return false;
60

61
                /* If both are remote, compare fd IDs if we have both, otherwise don't bother, and cut things short */
62
                if (a->fd_id == 0 || b->fd_id == 0)
×
63
                        return true;
64
        } else {
65
                /* If the other side is remote, then this is not the same */
66
                if (pidref_is_remote(b))
8,085✔
67
                        return false;
68

69
                /* PID1 cannot exit, hence it cannot change pidfs ids, hence no point in comparing them, we
70
                 * can shortcut things */
71
                if (a->pid == 1)
8,084✔
72
                        return true;
73

74
                /* Try to compare pidfds using their inode numbers. This way we can ensure that we
75
                 * don't spuriously consider two PidRefs equal if the pid has been reused once. Note
76
                 * that we ignore all errors here, not only EOPNOTSUPP, as fstat() might fail due to
77
                 * many reasons. */
78
                if (pidref_acquire_pidfd_id(a) < 0 || pidref_acquire_pidfd_id(b) < 0)
7,810✔
79
                        return true;
1,548✔
80
        }
81

82
        return a->fd_id == b->fd_id;
6,262✔
83
}
84

85
int pidref_set_pid(PidRef *pidref, pid_t pid) {
34,282✔
86
        uint64_t pidfdid = 0;
34,282✔
87
        int fd;
34,282✔
88

89
        assert(pidref);
34,282✔
90

91
        if (pid < 0)
34,282✔
92
                return -ESRCH;
34,282✔
93
        if (pid == 0) {
34,282✔
94
                pid = getpid_cached();
18,729✔
95
                (void) pidfd_get_inode_id_self_cached(&pidfdid);
18,729✔
96
        }
97

98
        fd = pidfd_open(pid, 0);
34,282✔
99
        if (fd < 0) {
34,282✔
100
                /* Graceful fallback in case the kernel is out of fds */
101
                if (!ERRNO_IS_RESOURCE(errno))
2✔
102
                        return log_debug_errno(errno, "Failed to open pidfd for pid " PID_FMT ": %m", pid);
2✔
103

104
                fd = -EBADF;
105
        }
106

107
        *pidref = (PidRef) {
34,280✔
108
                .fd = fd,
109
                .pid = pid,
110
                .fd_id = pidfdid,
111
        };
112

113
        return 0;
34,280✔
114
}
115

116
int pidref_set_pidstr(PidRef *pidref, const char *pid) {
4✔
117
        pid_t nr;
4✔
118
        int r;
4✔
119

120
        assert(pidref);
4✔
121

122
        r = parse_pid(pid, &nr);
4✔
123
        if (r < 0)
4✔
124
                return r;
4✔
125

126
        return pidref_set_pid(pidref, nr);
4✔
127
}
128

129
int pidref_set_pidfd(PidRef *pidref, int fd) {
517✔
130
        int r;
517✔
131

132
        assert(pidref);
517✔
133

134
        if (fd < 0)
517✔
135
                return -EBADF;
136

137
        int fd_copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
517✔
138
        if (fd_copy < 0) {
517✔
139
                pid_t pid;
×
140

141
                if (!ERRNO_IS_RESOURCE(errno))
×
142
                        return -errno;
×
143

144
                /* Graceful fallback if we are out of fds */
145
                r = pidfd_get_pid(fd, &pid);
×
146
                if (r < 0)
×
147
                        return r;
148

149
                *pidref = PIDREF_MAKE_FROM_PID(pid);
×
150
                return 0;
×
151
        }
152

153
        return pidref_set_pidfd_consume(pidref, fd_copy);
517✔
154
}
155

156
int pidref_set_pidfd_take(PidRef *pidref, int fd) {
4,386✔
157
        pid_t pid;
4,386✔
158
        int r;
4,386✔
159

160
        assert(pidref);
4,386✔
161

162
        if (fd < 0)
4,386✔
163
                return -EBADF;
4,386✔
164

165
        r = pidfd_get_pid(fd, &pid);
4,386✔
166
        if (r < 0)
4,386✔
167
                return r;
168

169
        *pidref = (PidRef) {
4,385✔
170
                .fd = fd,
171
                .pid = pid,
172
        };
173

174
        return 0;
4,385✔
175
}
176

177
int pidref_set_pidfd_consume(PidRef *pidref, int fd) {
4,369✔
178
        int r;
4,369✔
179

180
        r = pidref_set_pidfd_take(pidref, fd);
4,369✔
181
        if (r < 0)
4,369✔
182
                safe_close(fd);
×
183

184
        return r;
4,369✔
185
}
186

187
int pidref_set_parent(PidRef *ret) {
882✔
188
        _cleanup_(pidref_done) PidRef parent = PIDREF_NULL;
882✔
189
        pid_t ppid;
882✔
190
        int r;
882✔
191

192
        assert(ret);
882✔
193

194
        /* Acquires a pidref to our parent process. Deals with the fact that parent processes might exit, and
195
         * we get reparented to other processes, with our old parent's PID already being recycled. */
196

197
        ppid = getppid();
882✔
198
        for (;;) {
882✔
199
                r = pidref_set_pid(&parent, ppid);
882✔
200
                if (r < 0)
882✔
201
                        return r;
202

203
                if (parent.fd < 0) /* If pidfds are not available, then we are done */
882✔
204
                        break;
205

206
                pid_t now_ppid = getppid();
882✔
207
                if (now_ppid == ppid) /* If our ppid is still the same, then we are done */
882✔
208
                        break;
209

210
                /* Otherwise let's try again with the new ppid */
211
                ppid = now_ppid;
×
212
                pidref_done(&parent);
×
213
        }
214

215
        *ret = TAKE_PIDREF(parent);
882✔
216
        return 0;
882✔
217
}
218

219
void pidref_done(PidRef *pidref) {
175,400✔
220
        assert(pidref);
175,400✔
221

222
        *pidref = (PidRef) {
350,800✔
223
                .fd = safe_close(pidref->fd),
175,400✔
224
        };
225
}
175,400✔
226

227
PidRef* pidref_free(PidRef *pidref) {
4,479✔
228
        /* Regularly, this is an embedded structure. But sometimes we want it on the heap too */
229
        if (!pidref)
4,479✔
230
                return NULL;
231

232
        pidref_done(pidref);
4,479✔
233
        return mfree(pidref);
4,479✔
234
}
235

236
int pidref_copy(const PidRef *pidref, PidRef *ret) {
4,480✔
237
        _cleanup_(pidref_done) PidRef copy = PIDREF_NULL;
4,480✔
238

239
        /* If NULL is passed we'll generate a PidRef that refers to no process. This makes it easy to
240
         * copy pidref fields that might or might not reference a process yet. */
241

242
        assert(ret);
4,480✔
243

244
        if (pidref) {
4,480✔
245
                if (pidref_is_remote(pidref)) /* Propagate remote flag */
4,478✔
246
                        copy.fd = -EREMOTE;
×
247
                else if (pidref->fd >= 0) {
4,478✔
248
                        copy.fd = fcntl(pidref->fd, F_DUPFD_CLOEXEC, 3);
4,472✔
249
                        if (copy.fd < 0) {
4,472✔
250
                                if (!ERRNO_IS_RESOURCE(errno))
×
251
                                        return -errno;
×
252

253
                                copy.fd = -EBADF;
×
254
                        }
255
                }
256

257
                copy.pid = pidref->pid;
4,478✔
258
                copy.fd_id = pidref->fd_id;
4,478✔
259
        }
260

261
        *ret = TAKE_PIDREF(copy);
4,480✔
262
        return 0;
4,480✔
263
}
264

265
int pidref_dup(const PidRef *pidref, PidRef **ret) {
4,476✔
266
        _cleanup_(pidref_freep) PidRef *dup_pidref = NULL;
4,476✔
267
        int r;
4,476✔
268

269
        /* Allocates a new PidRef on the heap, making it a copy of the specified pidref. This does not try to
270
         * acquire a pidfd if we don't have one yet! */
271

272
        assert(ret);
4,476✔
273

274
        dup_pidref = newdup(PidRef, &PIDREF_NULL, 1);
4,476✔
275
        if (!dup_pidref)
4,476✔
276
                return -ENOMEM;
277

278
        r = pidref_copy(pidref, dup_pidref);
4,476✔
279
        if (r < 0)
4,476✔
280
                return r;
281

282
        *ret = TAKE_PTR(dup_pidref);
4,476✔
283
        return 0;
4,476✔
284
}
285

286
int pidref_new_from_pid(pid_t pid, PidRef **ret) {
4✔
287
        _cleanup_(pidref_freep) PidRef *n = NULL;
4✔
288
        int r;
4✔
289

290
        assert(ret);
4✔
291

292
        if (pid < 0)
4✔
293
                return -ESRCH;
294

295
        n = new(PidRef, 1);
3✔
296
        if (!n)
3✔
297
                return -ENOMEM;
298

299
        *n = PIDREF_NULL;
3✔
300

301
        r = pidref_set_pid(n, pid);
3✔
302
        if (r < 0)
3✔
303
                return r;
304

305
        *ret = TAKE_PTR(n);
3✔
306
        return 0;
3✔
307
}
308

309
int pidref_kill(const PidRef *pidref, int sig) {
17,281✔
310

311
        if (!pidref)
17,281✔
312
                return -ESRCH;
313

314
        if (pidref_is_remote(pidref))
17,281✔
315
                return -EREMOTE;
316

317
        if (pidref->fd >= 0)
17,279✔
318
                return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, NULL, 0));
9,526✔
319

320
        if (pidref->pid > 0)
7,753✔
321
                return RET_NERRNO(kill(pidref->pid, sig));
14,734✔
322

323
        return -ESRCH;
324
}
325

326
int pidref_kill_and_sigcont(const PidRef *pidref, int sig) {
826✔
327
        int r;
826✔
328

329
        r = pidref_kill(pidref, sig);
826✔
330
        if (r < 0)
826✔
331
                return r;
332

333
        if (!IN_SET(sig, SIGCONT, SIGKILL))
825✔
334
                (void) pidref_kill(pidref, SIGCONT);
825✔
335

336
        return 0;
337
}
338

339
int pidref_sigqueue(const PidRef *pidref, int sig, int value) {
1✔
340

341
        if (!pidref)
1✔
342
                return -ESRCH;
343

344
        if (pidref_is_remote(pidref))
1✔
345
                return -EREMOTE;
346

347
        if (pidref->fd >= 0) {
1✔
348
                siginfo_t si;
1✔
349

350
                /* We can't use structured initialization here, since the structure contains various unions
351
                 * and these fields lie in overlapping (carefully aligned) unions that LLVM is allergic to
352
                 * allow assignments to */
353
                zero(si);
1✔
354
                si.si_signo = sig;
1✔
355
                si.si_code = SI_QUEUE;
1✔
356
                si.si_pid = getpid_cached();
1✔
357
                si.si_uid = getuid();
1✔
358
                si.si_value.sival_int = value;
1✔
359

360
                return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, &si, 0));
1✔
361
        }
362

363
        if (pidref->pid > 0)
×
364
                return RET_NERRNO(sigqueue(pidref->pid, sig, (const union sigval) { .sival_int = value }));
×
365

366
        return -ESRCH;
367
}
368

369
int pidref_verify(const PidRef *pidref) {
79,599✔
370
        int r;
79,599✔
371

372
        /* This is a helper that is supposed to be called after reading information from procfs via a
373
         * PidRef. It ensures that the PID we track still matches the PIDFD we pin. If this value differs
374
         * after a procfs read, we might have read the data from a recycled PID. */
375

376
        if (!pidref_is_set(pidref))
79,599✔
377
                return -ESRCH;
378

379
        if (pidref_is_remote(pidref))
79,597✔
380
                return -EREMOTE;
381

382
        if (pidref->pid == 1)
79,596✔
383
                return 1; /* PID 1 can never go away, hence never be recycled to a different process → return 1 */
384

385
        if (pidref->fd < 0)
64,472✔
386
                return 0; /* If we don't have a pidfd we cannot validate it, hence we assume it's all OK → return 0 */
387

388
        r = pidfd_verify_pid(pidref->fd, pidref->pid);
41,419✔
389
        if (r < 0)
41,419✔
390
                return r;
1,677✔
391

392
        return 1; /* We have a pidfd and it still points to the PID we have, hence all is *really* OK → return 1 */
393
}
394

395
bool pidref_is_self(PidRef *pidref) {
24,018✔
396
        if (!pidref_is_set(pidref))
24,018✔
397
                return false;
24,018✔
398

399
        if (pidref_is_remote(pidref))
24,016✔
400
                return false;
401

402
        if (pidref->pid != getpid_cached())
24,016✔
403
                return false;
404

405
        /* PID1 cannot exit, hence no point in comparing pidfd IDs, they can never change */
406
        if (pidref->pid == 1)
887✔
407
                return true;
408

409
        /* Also compare pidfd ID if we can get it */
410
        if (pidref_acquire_pidfd_id(pidref) < 0)
887✔
411
                return true;
412

413
        uint64_t self_id;
437✔
414
        if (pidfd_get_inode_id_self_cached(&self_id) < 0)
437✔
415
                return true;
416

417
        return pidref->fd_id == self_id;
437✔
418
}
419

420
int pidref_wait(PidRef *pidref, siginfo_t *ret, int options) {
4,164✔
421
        int r;
4,164✔
422

423
        if (!pidref_is_set(pidref))
4,164✔
424
                return -ESRCH;
4,164✔
425

426
        if (pidref_is_remote(pidref))
4,164✔
427
                return -EREMOTE;
428

429
        if (pidref->pid == 1 || pidref_is_self(pidref))
4,163✔
430
                return -ECHILD;
×
431

432
        siginfo_t si = {};
4,163✔
433
        if (pidref->fd >= 0)
4,163✔
434
                r = RET_NERRNO(waitid(P_PIDFD, pidref->fd, &si, options));
4,163✔
435
        else
436
                r = RET_NERRNO(waitid(P_PID, pidref->pid, &si, options));
×
437
        if (r < 0)
×
438
                return r;
439

440
        if (ret)
4,163✔
441
                *ret = si;
3✔
442

443
        return 0;
444
}
445

446
int pidref_wait_for_terminate(PidRef *pidref, siginfo_t *ret) {
4,164✔
447
        int r;
4,164✔
448

449
        for (;;) {
4,164✔
450
                r = pidref_wait(pidref, ret, WEXITED);
4,164✔
451
                if (r != -EINTR)
4,164✔
452
                        return r;
4,164✔
453
        }
454
}
455

456
bool pidref_is_automatic(const PidRef *pidref) {
77,332✔
457
        return pidref && pid_is_automatic(pidref->pid);
77,332✔
458
}
459

460
void pidref_hash_func(const PidRef *pidref, struct siphash *state) {
51,099✔
461
        siphash24_compress_typesafe(pidref->pid, state);
51,099✔
462
}
51,099✔
463

464
int pidref_compare_func(const PidRef *a, const PidRef *b) {
38,641✔
465
        int r;
38,641✔
466

467
        assert(a);
38,641✔
468
        assert(b);
38,641✔
469

470
        r = CMP(pidref_is_set(a), pidref_is_set(b));
115,923✔
471
        if (r != 0)
38,641✔
UNCOV
472
                return r;
×
473

474
        r = CMP(pidref_is_automatic(a), pidref_is_automatic(b));
38,641✔
475
        if (r != 0)
38,641✔
UNCOV
476
                return r;
×
477

478
        r = CMP(pidref_is_remote(a), pidref_is_remote(b));
77,282✔
479
        if (r != 0)
38,641✔
UNCOV
480
                return r;
×
481

482
        r = CMP(a->pid, b->pid);
38,641✔
483
        if (r != 0)
30,021✔
484
                return r;
9,451✔
485

486
        if (a->fd_id != 0 && b->fd_id != 0)
29,190✔
487
                return CMP(a->fd_id, b->fd_id);
111✔
488

489
        return 0;
490
}
491

492
DEFINE_HASH_OPS(pidref_hash_ops, PidRef, pidref_hash_func, pidref_compare_func);
493

UNCOV
494
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(pidref_hash_ops_free,
×
495
                                    PidRef, pidref_hash_func, pidref_compare_func,
496
                                    pidref_free);
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