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

systemd / systemd / 14630481637

23 Apr 2025 07:04PM UTC coverage: 72.178% (-0.002%) from 72.18%
14630481637

push

github

DaanDeMeyer
mkosi: Run clangd within the tools tree instead of the build container

Running within the build sandbox has a number of disadvantages:
- We have a separate clangd cache for each distribution/release combo
- It requires to build the full image before clangd can be used
- It breaks every time the image becomes out of date and requires a
  rebuild
- We can't look at system headers as we don't have the knowledge to map
  them from inside the build sandbox to the corresponding path on the host

Instead, let's have mkosi.clangd run clangd within the tools tree. We
already require building systemd for both the host and the target anyway,
and all the dependencies to build systemd are installed in the tools tree
already for that, as well as clangd since it's installed together with the
other clang tooling we install in the tools tree. Unlike the previous approach,
this approach only requires the mkosi tools tree to be built upfront, which has
a much higher chance of not invalidating its cache. We can also trivially map
system header lookups from within the sandbox to the path within mkosi.tools
on the host so that starts working as well.

297054 of 411557 relevant lines covered (72.18%)

686269.58 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 "errno-util.h"
4
#include "fd-util.h"
5
#include "log.h"
6
#include "missing_syscall.h"
7
#include "missing_wait.h"
8
#include "parse-util.h"
9
#include "pidfd-util.h"
10
#include "pidref.h"
11
#include "process-util.h"
12
#include "signal-util.h"
13

14
int pidref_acquire_pidfd_id(PidRef *pidref) {
10,157✔
15
        int r;
10,157✔
16

17
        assert(pidref);
10,157✔
18

19
        if (!pidref_is_set(pidref))
10,157✔
20
                return -ESRCH;
21

22
        if (pidref_is_remote(pidref))
10,157✔
23
                return -EREMOTE;
24

25
        if (pidref->fd < 0)
10,157✔
26
                return -ENOMEDIUM;
27

28
        if (pidref->fd_id > 0)
9,399✔
29
                return 0;
30

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

39
        return 0;
40
}
41

42
bool pidref_equal(PidRef *a, PidRef *b) {
20,198✔
43

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

48
        if (!pidref_is_set(a))
20,195✔
49
                return !pidref_is_set(b);
5,936✔
50

51
        if (!pidref_is_set(b))
17,227✔
52
                return false;
53

54
        if (a->pid != b->pid)
17,221✔
55
                return false;
56

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

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

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

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

83
        return a->fd_id == b->fd_id;
3,602✔
84
}
85

86
int pidref_set_pid(PidRef *pidref, pid_t pid) {
59,932✔
87
        uint64_t pidfdid = 0;
59,932✔
88
        int fd;
59,932✔
89

90
        assert(pidref);
59,932✔
91

92
        if (pid < 0)
59,932✔
93
                return -ESRCH;
59,932✔
94
        if (pid == 0) {
59,932✔
95
                pid = getpid_cached();
37,169✔
96
                (void) pidfd_get_inode_id_self_cached(&pidfdid);
37,169✔
97
        }
98

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

105
                fd = -EBADF;
106
        }
107

108
        *pidref = (PidRef) {
59,932✔
109
                .fd = fd,
110
                .pid = pid,
111
                .fd_id = pidfdid,
112
        };
113

114
        return 0;
59,932✔
115
}
116

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

121
        assert(pidref);
4✔
122

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

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

130
int pidref_set_pidfd(PidRef *pidref, int fd) {
586✔
131
        int r;
586✔
132

133
        assert(pidref);
586✔
134

135
        if (fd < 0)
586✔
136
                return -EBADF;
137

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

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

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

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

154
        return pidref_set_pidfd_consume(pidref, fd_copy);
586✔
155
}
156

157
int pidref_set_pidfd_take(PidRef *pidref, int fd) {
2,845✔
158
        pid_t pid;
2,845✔
159
        int r;
2,845✔
160

161
        assert(pidref);
2,845✔
162

163
        if (fd < 0)
2,845✔
164
                return -EBADF;
2,845✔
165

166
        r = pidfd_get_pid(fd, &pid);
2,845✔
167
        if (r < 0)
2,845✔
168
                return r;
169

170
        *pidref = (PidRef) {
2,845✔
171
                .fd = fd,
172
                .pid = pid,
173
        };
174

175
        return 0;
2,845✔
176
}
177

178
int pidref_set_pidfd_consume(PidRef *pidref, int fd) {
2,816✔
179
        int r;
2,816✔
180

181
        r = pidref_set_pidfd_take(pidref, fd);
2,816✔
182
        if (r < 0)
2,816✔
183
                safe_close(fd);
×
184

185
        return r;
2,816✔
186
}
187

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

193
        assert(ret);
860✔
194

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

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

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

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

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

216
        *ret = TAKE_PIDREF(parent);
860✔
217
        return 0;
860✔
218
}
219

220
void pidref_done(PidRef *pidref) {
212,863✔
221
        assert(pidref);
212,863✔
222

223
        *pidref = (PidRef) {
425,726✔
224
                .fd = safe_close(pidref->fd),
212,863✔
225
        };
226
}
212,863✔
227

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

233
        pidref_done(pidref);
2,890✔
234
        return mfree(pidref);
2,890✔
235
}
236

237
int pidref_copy(const PidRef *pidref, PidRef *ret) {
2,891✔
238
        _cleanup_(pidref_done) PidRef copy = PIDREF_NULL;
2,891✔
239

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

243
        assert(ret);
2,891✔
244

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

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

258
                copy.pid = pidref->pid;
2,889✔
259
                copy.fd_id = pidref->fd_id;
2,889✔
260
        }
261

262
        *ret = TAKE_PIDREF(copy);
2,891✔
263
        return 0;
2,891✔
264
}
265

266
int pidref_dup(const PidRef *pidref, PidRef **ret) {
2,887✔
267
        _cleanup_(pidref_freep) PidRef *dup_pidref = NULL;
2,887✔
268
        int r;
2,887✔
269

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

273
        assert(ret);
2,887✔
274

275
        dup_pidref = newdup(PidRef, &PIDREF_NULL, 1);
2,887✔
276
        if (!dup_pidref)
2,887✔
277
                return -ENOMEM;
278

279
        r = pidref_copy(pidref, dup_pidref);
2,887✔
280
        if (r < 0)
2,887✔
281
                return r;
282

283
        *ret = TAKE_PTR(dup_pidref);
2,887✔
284
        return 0;
2,887✔
285
}
286

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

291
        assert(ret);
4✔
292

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

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

300
        *n = PIDREF_NULL;
3✔
301

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

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

310
int pidref_kill(const PidRef *pidref, int sig) {
15,246✔
311

312
        if (!pidref)
15,246✔
313
                return -ESRCH;
314

315
        if (pidref_is_remote(pidref))
15,246✔
316
                return -EREMOTE;
317

318
        if (pidref->fd >= 0)
15,244✔
319
                return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, NULL, 0));
8,044✔
320

321
        if (pidref->pid > 0)
7,200✔
322
                return RET_NERRNO(kill(pidref->pid, sig));
13,639✔
323

324
        return -ESRCH;
325
}
326

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

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

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

337
        return 0;
338
}
339

340
int pidref_sigqueue(const PidRef *pidref, int sig, int value) {
9,128✔
341

342
        if (!pidref)
9,128✔
343
                return -ESRCH;
344

345
        if (pidref_is_remote(pidref))
9,128✔
346
                return -EREMOTE;
347

348
        if (pidref->fd >= 0) {
9,128✔
349
                siginfo_t si;
9,128✔
350

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

361
                return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, &si, 0));
9,128✔
362
        }
363

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

367
        return -ESRCH;
368
}
369

370
int pidref_verify(const PidRef *pidref) {
63,709✔
371
        int r;
63,709✔
372

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

377
        if (!pidref_is_set(pidref))
63,709✔
378
                return -ESRCH;
379

380
        if (pidref_is_remote(pidref))
63,707✔
381
                return -EREMOTE;
382

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

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

389
        r = pidfd_verify_pid(pidref->fd, pidref->pid);
32,366✔
390
        if (r < 0)
32,366✔
391
                return r;
1,963✔
392

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

396
bool pidref_is_self(PidRef *pidref) {
38,545✔
397
        if (!pidref_is_set(pidref))
38,545✔
398
                return false;
38,545✔
399

400
        if (pidref_is_remote(pidref))
38,543✔
401
                return false;
402

403
        if (pidref->pid != getpid_cached())
38,543✔
404
                return false;
405

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

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

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

418
        return pidref->fd_id == self_id;
752✔
419
}
420

421
int pidref_wait(PidRef *pidref, siginfo_t *ret, int options) {
13,842✔
422
        int r;
13,842✔
423

424
        if (!pidref_is_set(pidref))
13,842✔
425
                return -ESRCH;
13,842✔
426

427
        if (pidref_is_remote(pidref))
13,842✔
428
                return -EREMOTE;
429

430
        if (pidref->pid == 1 || pidref_is_self(pidref))
13,841✔
431
                return -ECHILD;
×
432

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

441
        if (ret)
13,841✔
442
                *ret = si;
9,866✔
443

444
        return 0;
445
}
446

447
int pidref_wait_for_terminate(PidRef *pidref, siginfo_t *ret) {
13,842✔
448
        int r;
13,842✔
449

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

457
bool pidref_is_automatic(const PidRef *pidref) {
175,046✔
458
        return pidref && pid_is_automatic(pidref->pid);
175,046✔
459
}
460

461
void pidref_hash_func(const PidRef *pidref, struct siphash *state) {
81,498✔
462
        siphash24_compress_typesafe(pidref->pid, state);
81,498✔
463
}
81,498✔
464

465
int pidref_compare_func(const PidRef *a, const PidRef *b) {
87,497✔
466
        int r;
87,497✔
467

468
        assert(a);
87,497✔
469
        assert(b);
87,497✔
470

471
        r = CMP(pidref_is_set(a), pidref_is_set(b));
87,497✔
472
        if (r != 0)
87,497✔
473
                return r;
×
474

475
        r = CMP(pidref_is_automatic(a), pidref_is_automatic(b));
87,497✔
476
        if (r != 0)
87,497✔
477
                return r;
×
478

479
        r = CMP(pidref_is_remote(a), pidref_is_remote(b));
174,994✔
480
        if (r != 0)
87,497✔
481
                return r;
×
482

483
        r = CMP(a->pid, b->pid);
87,497✔
484
        if (r != 0)
67,706✔
485
                return r;
22,507✔
486

487
        if (a->fd_id != 0 && b->fd_id != 0)
64,990✔
488
                return CMP(a->fd_id, b->fd_id);
458✔
489

490
        return 0;
491
}
492

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

495
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(pidref_hash_ops_free,
×
496
                                    PidRef, pidref_hash_func, pidref_compare_func,
497
                                    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