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

systemd / systemd / 15263807472

26 May 2025 08:53PM UTC coverage: 72.046% (-0.002%) from 72.048%
15263807472

push

github

yuwata
src/core/manager.c: log preset activity on first boot

This gives us a little more information about what units were enabled
or disabled on that first boot and will be useful for OS developers
tracking down the source of unit state.

An example with this enabled looks like:

```
NET: Registered PF_VSOCK protocol family
systemd[1]: Applying preset policy.
systemd[1]: Unit /etc/systemd/system/dnsmasq.service is masked, ignoring.
systemd[1]: Unit /etc/systemd/system/systemd-repart.service is masked, ignoring.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket'.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir.mount' → '/etc/systemd/system/var-mnt-workdir.mount'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir\x2dtmp.mount' → '/etc/systemd/system/var-mnt-workdir\x2dtmp.mount'.
systemd[1]: Created symlink '/etc/systemd/system/afterburn-sshkeys.target.requires/afterburn-sshkeys@core.service' → '/usr/lib/systemd/system/afterburn-sshkeys@.service'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket' → '/usr/lib/systemd/system/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket' → '/usr/lib/systemd/system/systemd-resolved-monitor.socket'.
systemd[1]: Populated /etc with preset unit settings.
```

Considering it only happens on first boot and not on every boot I think
the extra information is worth the extra verbosity in the logs just for
that boot.

5 of 6 new or added lines in 1 file covered. (83.33%)

5463 existing lines in 165 files now uncovered.

299151 of 415222 relevant lines covered (72.05%)

702386.45 hits per line

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

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

3
#include "alloc-util.h"
4
#include "errno-util.h"
5
#include "fd-util.h"
6
#include "format-util.h"
7
#include "hash-funcs.h"
8
#include "log.h"
9
#include "missing_wait.h"
10
#include "parse-util.h"
11
#include "pidfd-util.h"
12
#include "pidref.h"
13
#include "process-util.h"
14
#include "siphash24.h"
15

16
int pidref_acquire_pidfd_id(PidRef *pidref) {
10,579✔
17
        int r;
10,579✔
18

19
        assert(pidref);
10,579✔
20

21
        if (!pidref_is_set(pidref))
10,579✔
22
                return -ESRCH;
23

24
        if (pidref_is_remote(pidref))
10,579✔
25
                return -EREMOTE;
26

27
        if (pidref->fd < 0)
10,579✔
28
                return -ENOMEDIUM;
29

30
        if (pidref->fd_id > 0)
10,568✔
31
                return 0;
32

33
        r = pidfd_get_inode_id(pidref->fd, &pidref->fd_id);
5,226✔
34
        if (r < 0) {
5,226✔
UNCOV
35
                if (!ERRNO_IS_NEG_NOT_SUPPORTED(r))
×
36
                        log_debug_errno(r, "Failed to get inode number of pidfd for pid " PID_FMT ": %m",
×
37
                                        pidref->pid);
UNCOV
38
                return r;
×
39
        }
40

41
        return 0;
42
}
43

44
bool pidref_equal(PidRef *a, PidRef *b) {
20,328✔
45

46
        /* If this is the very same structure, it definitely refers to the same process */
47
        if (a == b)
20,328✔
48
                return true;
49

50
        if (!pidref_is_set(a))
20,325✔
51
                return !pidref_is_set(b);
6,012✔
52

53
        if (!pidref_is_set(b))
17,319✔
54
                return false;
55

56
        if (a->pid != b->pid)
17,313✔
57
                return false;
58

59
        if (pidref_is_remote(a)) {
3,708✔
60
                /* If one is remote and the other isn't, they are not the same */
UNCOV
61
                if (!pidref_is_remote(b))
×
62
                        return false;
63

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

72
                /* PID1 cannot exit, hence it cannot change pidfs ids, hence no point in comparing them, we
73
                 * can shortcut things */
74
                if (a->pid == 1)
3,707✔
75
                        return true;
76

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

85
        return a->fd_id == b->fd_id;
3,587✔
86
}
87

88
int pidref_set_pid(PidRef *pidref, pid_t pid) {
61,292✔
89
        uint64_t pidfdid = 0;
61,292✔
90
        int fd;
61,292✔
91

92
        assert(pidref);
61,292✔
93

94
        if (pid < 0)
61,292✔
95
                return -ESRCH;
61,292✔
96
        if (pid == 0) {
61,292✔
97
                pid = getpid_cached();
37,920✔
98
                (void) pidfd_get_inode_id_self_cached(&pidfdid);
37,920✔
99
        }
100

101
        fd = pidfd_open(pid, 0);
61,292✔
102
        if (fd < 0) {
61,292✔
103
                /* Graceful fallback in case the kernel is out of fds */
UNCOV
104
                if (!ERRNO_IS_RESOURCE(errno))
×
UNCOV
105
                        return log_debug_errno(errno, "Failed to open pidfd for pid " PID_FMT ": %m", pid);
×
106

107
                fd = -EBADF;
108
        }
109

110
        *pidref = (PidRef) {
61,292✔
111
                .fd = fd,
112
                .pid = pid,
113
                .fd_id = pidfdid,
114
        };
115

116
        return 0;
61,292✔
117
}
118

119
int pidref_set_pidstr(PidRef *pidref, const char *pid) {
4✔
120
        pid_t nr;
4✔
121
        int r;
4✔
122

123
        assert(pidref);
4✔
124

125
        r = parse_pid(pid, &nr);
4✔
126
        if (r < 0)
4✔
127
                return r;
4✔
128

129
        return pidref_set_pid(pidref, nr);
4✔
130
}
131

132
int pidref_set_pidfd(PidRef *pidref, int fd) {
604✔
133
        int r;
604✔
134

135
        assert(pidref);
604✔
136

137
        if (fd < 0)
604✔
138
                return -EBADF;
139

140
        int fd_copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
604✔
141
        if (fd_copy < 0) {
604✔
142
                pid_t pid;
×
143

UNCOV
144
                if (!ERRNO_IS_RESOURCE(errno))
×
UNCOV
145
                        return -errno;
×
146

147
                /* Graceful fallback if we are out of fds */
UNCOV
148
                r = pidfd_get_pid(fd, &pid);
×
UNCOV
149
                if (r < 0)
×
150
                        return r;
151

UNCOV
152
                *pidref = PIDREF_MAKE_FROM_PID(pid);
×
UNCOV
153
                return 0;
×
154
        }
155

156
        return pidref_set_pidfd_consume(pidref, fd_copy);
604✔
157
}
158

159
int pidref_set_pidfd_take(PidRef *pidref, int fd) {
2,877✔
160
        pid_t pid;
2,877✔
161
        int r;
2,877✔
162

163
        assert(pidref);
2,877✔
164

165
        if (fd < 0)
2,877✔
166
                return -EBADF;
2,877✔
167

168
        r = pidfd_get_pid(fd, &pid);
2,877✔
169
        if (r < 0)
2,877✔
170
                return r;
171

172
        *pidref = (PidRef) {
2,877✔
173
                .fd = fd,
174
                .pid = pid,
175
        };
176

177
        return 0;
2,877✔
178
}
179

180
int pidref_set_pidfd_consume(PidRef *pidref, int fd) {
2,848✔
181
        int r;
2,848✔
182

183
        r = pidref_set_pidfd_take(pidref, fd);
2,848✔
184
        if (r < 0)
2,848✔
UNCOV
185
                safe_close(fd);
×
186

187
        return r;
2,848✔
188
}
189

190
int pidref_set_parent(PidRef *ret) {
1,137✔
191
        _cleanup_(pidref_done) PidRef parent = PIDREF_NULL;
1,137✔
192
        pid_t ppid;
1,137✔
193
        int r;
1,137✔
194

195
        assert(ret);
1,137✔
196

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

200
        ppid = getppid();
1,137✔
201
        for (;;) {
1,137✔
202
                r = pidref_set_pid(&parent, ppid);
1,137✔
203
                if (r < 0)
1,137✔
204
                        return r;
205

206
                if (parent.fd < 0) /* If pidfds are not available, then we are done */
1,137✔
207
                        break;
208

209
                pid_t now_ppid = getppid();
1,137✔
210
                if (now_ppid == ppid) /* If our ppid is still the same, then we are done */
1,137✔
211
                        break;
212

213
                /* Otherwise let's try again with the new ppid */
UNCOV
214
                ppid = now_ppid;
×
UNCOV
215
                pidref_done(&parent);
×
216
        }
217

218
        *ret = TAKE_PIDREF(parent);
1,137✔
219
        return 0;
1,137✔
220
}
221

222
void pidref_done(PidRef *pidref) {
216,128✔
223
        assert(pidref);
216,128✔
224

225
        *pidref = (PidRef) {
432,256✔
226
                .fd = safe_close(pidref->fd),
216,128✔
227
        };
228
}
216,128✔
229

230
PidRef* pidref_free(PidRef *pidref) {
2,900✔
231
        /* Regularly, this is an embedded structure. But sometimes we want it on the heap too */
232
        if (!pidref)
2,900✔
233
                return NULL;
234

235
        pidref_done(pidref);
2,900✔
236
        return mfree(pidref);
2,900✔
237
}
238

239
int pidref_copy(const PidRef *pidref, PidRef *ret) {
2,901✔
240
        _cleanup_(pidref_done) PidRef copy = PIDREF_NULL;
2,901✔
241

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

245
        assert(ret);
2,901✔
246

247
        if (pidref) {
2,901✔
248
                if (pidref_is_remote(pidref)) /* Propagate remote flag */
2,899✔
UNCOV
249
                        copy.fd = -EREMOTE;
×
250
                else if (pidref->fd >= 0) {
2,899✔
251
                        copy.fd = fcntl(pidref->fd, F_DUPFD_CLOEXEC, 3);
2,893✔
252
                        if (copy.fd < 0) {
2,893✔
UNCOV
253
                                if (!ERRNO_IS_RESOURCE(errno))
×
254
                                        return -errno;
×
255

UNCOV
256
                                copy.fd = -EBADF;
×
257
                        }
258
                }
259

260
                copy.pid = pidref->pid;
2,899✔
261
                copy.fd_id = pidref->fd_id;
2,899✔
262
        }
263

264
        *ret = TAKE_PIDREF(copy);
2,901✔
265
        return 0;
2,901✔
266
}
267

268
int pidref_dup(const PidRef *pidref, PidRef **ret) {
2,897✔
269
        _cleanup_(pidref_freep) PidRef *dup_pidref = NULL;
2,897✔
270
        int r;
2,897✔
271

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

275
        assert(ret);
2,897✔
276

277
        dup_pidref = newdup(PidRef, &PIDREF_NULL, 1);
2,897✔
278
        if (!dup_pidref)
2,897✔
279
                return -ENOMEM;
280

281
        r = pidref_copy(pidref, dup_pidref);
2,897✔
282
        if (r < 0)
2,897✔
283
                return r;
284

285
        *ret = TAKE_PTR(dup_pidref);
2,897✔
286
        return 0;
2,897✔
287
}
288

289
int pidref_new_from_pid(pid_t pid, PidRef **ret) {
4✔
290
        _cleanup_(pidref_freep) PidRef *n = NULL;
4✔
291
        int r;
4✔
292

293
        assert(ret);
4✔
294

295
        if (pid < 0)
4✔
296
                return -ESRCH;
297

298
        n = new(PidRef, 1);
3✔
299
        if (!n)
3✔
300
                return -ENOMEM;
301

302
        *n = PIDREF_NULL;
3✔
303

304
        r = pidref_set_pid(n, pid);
3✔
305
        if (r < 0)
3✔
306
                return r;
307

308
        *ret = TAKE_PTR(n);
3✔
309
        return 0;
3✔
310
}
311

312
int pidref_kill(const PidRef *pidref, int sig) {
16,476✔
313

314
        if (!pidref)
16,476✔
315
                return -ESRCH;
316

317
        if (pidref_is_remote(pidref))
16,476✔
318
                return -EREMOTE;
319

320
        if (pidref->fd >= 0)
16,474✔
321
                return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, NULL, 0));
8,086✔
322

323
        if (pidref->pid > 0)
8,388✔
324
                return RET_NERRNO(kill(pidref->pid, sig));
15,643✔
325

326
        return -ESRCH;
327
}
328

329
int pidref_kill_and_sigcont(const PidRef *pidref, int sig) {
585✔
330
        int r;
585✔
331

332
        r = pidref_kill(pidref, sig);
585✔
333
        if (r < 0)
585✔
334
                return r;
335

336
        if (!IN_SET(sig, SIGCONT, SIGKILL))
584✔
337
                (void) pidref_kill(pidref, SIGCONT);
584✔
338

339
        return 0;
340
}
341

342
int pidref_sigqueue(const PidRef *pidref, int sig, int value) {
9,786✔
343

344
        if (!pidref)
9,786✔
345
                return -ESRCH;
346

347
        if (pidref_is_remote(pidref))
9,786✔
348
                return -EREMOTE;
349

350
        if (pidref->fd >= 0) {
9,786✔
351
                siginfo_t si;
9,786✔
352

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

363
                return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, &si, 0));
9,786✔
364
        }
365

UNCOV
366
        if (pidref->pid > 0)
×
UNCOV
367
                return RET_NERRNO(sigqueue(pidref->pid, sig, (const union sigval) { .sival_int = value }));
×
368

369
        return -ESRCH;
370
}
371

372
int pidref_verify(const PidRef *pidref) {
64,810✔
373
        int r;
64,810✔
374

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

379
        if (!pidref_is_set(pidref))
64,810✔
380
                return -ESRCH;
381

382
        if (pidref_is_remote(pidref))
64,808✔
383
                return -EREMOTE;
384

385
        if (pidref->pid == 1)
64,807✔
386
                return 1; /* PID 1 can never go away, hence never be recycled to a different process → return 1 */
387

388
        if (pidref->fd < 0)
50,416✔
389
                return 0; /* If we don't have a pidfd we cannot validate it, hence we assume it's all OK → return 0 */
390

391
        r = pidfd_verify_pid(pidref->fd, pidref->pid);
32,954✔
392
        if (r < 0)
32,954✔
393
                return r;
2,080✔
394

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

398
bool pidref_is_self(PidRef *pidref) {
38,781✔
399
        if (!pidref_is_set(pidref))
38,781✔
400
                return false;
38,781✔
401

402
        if (pidref_is_remote(pidref))
38,779✔
403
                return false;
404

405
        if (pidref->pid != getpid_cached())
38,779✔
406
                return false;
407

408
        /* PID1 cannot exit, hence no point in comparing pidfd IDs, they can never change */
409
        if (pidref->pid == 1)
664✔
410
                return true;
411

412
        /* Also compare pidfd ID if we can get it */
413
        if (pidref_acquire_pidfd_id(pidref) < 0)
664✔
414
                return true;
415

416
        uint64_t self_id;
655✔
417
        if (pidfd_get_inode_id_self_cached(&self_id) < 0)
655✔
418
                return true;
419

420
        return pidref->fd_id == self_id;
655✔
421
}
422

423
int pidref_wait(PidRef *pidref, siginfo_t *ret, int options) {
13,815✔
424
        int r;
13,815✔
425

426
        if (!pidref_is_set(pidref))
13,815✔
427
                return -ESRCH;
13,815✔
428

429
        if (pidref_is_remote(pidref))
13,815✔
430
                return -EREMOTE;
431

432
        if (pidref->pid == 1 || pidref_is_self(pidref))
13,814✔
UNCOV
433
                return -ECHILD;
×
434

435
        siginfo_t si = {};
13,814✔
436
        if (pidref->fd >= 0)
13,814✔
437
                r = RET_NERRNO(waitid(P_PIDFD, pidref->fd, &si, options));
4,998✔
438
        else
439
                r = RET_NERRNO(waitid(P_PID, pidref->pid, &si, options));
8,816✔
UNCOV
440
        if (r < 0)
×
441
                return r;
442

443
        if (ret)
13,814✔
444
                *ret = si;
9,819✔
445

446
        return 0;
447
}
448

449
int pidref_wait_for_terminate(PidRef *pidref, siginfo_t *ret) {
13,815✔
450
        int r;
13,815✔
451

452
        for (;;) {
13,815✔
453
                r = pidref_wait(pidref, ret, WEXITED);
13,815✔
454
                if (r != -EINTR)
13,815✔
455
                        return r;
13,815✔
456
        }
457
}
458

459
bool pidref_is_automatic(const PidRef *pidref) {
180,864✔
460
        return pidref && pid_is_automatic(pidref->pid);
180,864✔
461
}
462

463
void pidref_hash_func(const PidRef *pidref, struct siphash *state) {
84,116✔
464
        siphash24_compress_typesafe(pidref->pid, state);
84,116✔
465
}
84,116✔
466

467
int pidref_compare_func(const PidRef *a, const PidRef *b) {
90,406✔
468
        int r;
90,406✔
469

470
        assert(a);
90,406✔
471
        assert(b);
90,406✔
472

473
        r = CMP(pidref_is_set(a), pidref_is_set(b));
271,218✔
474
        if (r != 0)
90,406✔
UNCOV
475
                return r;
×
476

477
        r = CMP(pidref_is_automatic(a), pidref_is_automatic(b));
90,406✔
478
        if (r != 0)
90,406✔
UNCOV
479
                return r;
×
480

481
        r = CMP(pidref_is_remote(a), pidref_is_remote(b));
180,812✔
482
        if (r != 0)
90,406✔
UNCOV
483
                return r;
×
484

485
        r = CMP(a->pid, b->pid);
90,406✔
486
        if (r != 0)
71,388✔
487
                return r;
22,965✔
488

489
        if (a->fd_id != 0 && b->fd_id != 0)
67,441✔
490
                return CMP(a->fd_id, b->fd_id);
498✔
491

492
        return 0;
493
}
494

495
DEFINE_HASH_OPS(pidref_hash_ops, PidRef, pidref_hash_func, pidref_compare_func);
496

UNCOV
497
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(pidref_hash_ops_free,
×
498
                                    PidRef, pidref_hash_func, pidref_compare_func,
499
                                    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