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

systemd / systemd / 15837872256

23 Jun 2025 09:28PM UTC coverage: 72.09% (-0.02%) from 72.105%
15837872256

push

github

bluca
test-cpu-set-util: fix check for CPUSet.allocated

The check was simply wrong and meaningless, as it always checked
CPUSet.allocated is greater than or equals to 1, as sizeof(__cpu_mask) is 8.

Let's make the test more strict.

300458 of 416781 relevant lines covered (72.09%)

709101.32 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,972✔
17
        int r;
10,972✔
18

19
        assert(pidref);
10,972✔
20

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

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

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

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

33
        r = pidfd_get_inode_id(pidref->fd, &pidref->fd_id);
5,330✔
34
        if (r < 0) {
5,330✔
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);
38
                return r;
×
39
        }
40

41
        return 0;
42
}
43

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

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

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

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

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

59
        if (pidref_is_remote(a)) {
3,733✔
60
                /* If one is remote and the other isn't, they are not the same */
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 */
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,733✔
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,732✔
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,614✔
82
                        return true;
2✔
83
        }
84

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

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

92
        assert(pidref);
63,009✔
93

94
        if (pid < 0)
63,009✔
95
                return -ESRCH;
63,009✔
96
        if (pid == 0) {
63,009✔
97
                pid = getpid_cached();
39,113✔
98
                (void) pidfd_get_inode_id_self_cached(&pidfdid);
39,113✔
99
        }
100

101
        fd = pidfd_open(pid, 0);
63,009✔
102
        if (fd < 0) {
63,009✔
103
                /* Graceful fallback in case the kernel is out of fds */
104
                if (!ERRNO_IS_RESOURCE(errno))
×
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) {
63,009✔
111
                .fd = fd,
112
                .pid = pid,
113
                .fd_id = pidfdid,
114
        };
115

116
        return 0;
63,009✔
117
}
118

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

123
        assert(pidref);
19✔
124

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

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

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

135
        assert(pidref);
620✔
136

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

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

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

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

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

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

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

163
        assert(pidref);
2,909✔
164

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

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

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

177
        return 0;
2,909✔
178
}
179

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

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

187
        return r;
2,883✔
188
}
189

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

195
        assert(ret);
1,409✔
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,409✔
201
        for (;;) {
1,409✔
202
                r = pidref_set_pid(&parent, ppid);
1,409✔
203
                if (r < 0)
1,409✔
204
                        return r;
205

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

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

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

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

222
void pidref_done(PidRef *pidref) {
219,634✔
223
        assert(pidref);
219,634✔
224

225
        *pidref = (PidRef) {
439,268✔
226
                .fd = safe_close(pidref->fd),
219,634✔
227
        };
228
}
219,634✔
229

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

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

239
int pidref_copy(const PidRef *pidref, PidRef *ret) {
2,921✔
240
        _cleanup_(pidref_done) PidRef copy = PIDREF_NULL;
2,921✔
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,921✔
246

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

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

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

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

268
int pidref_dup(const PidRef *pidref, PidRef **ret) {
2,917✔
269
        _cleanup_(pidref_freep) PidRef *dup_pidref = NULL;
2,917✔
270
        int r;
2,917✔
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,917✔
276

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

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

285
        *ret = TAKE_PTR(dup_pidref);
2,917✔
286
        return 0;
2,917✔
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) {
14,966✔
313

314
        if (!pidref)
14,966✔
315
                return -ESRCH;
316

317
        if (pidref_is_remote(pidref))
14,966✔
318
                return -EREMOTE;
319

320
        if (pidref->fd >= 0)
14,964✔
321
                return RET_NERRNO(pidfd_send_signal(pidref->fd, sig, NULL, 0));
8,211✔
322

323
        if (pidref->pid > 0)
6,753✔
324
                return RET_NERRNO(kill(pidref->pid, sig));
12,522✔
325

326
        return -ESRCH;
327
}
328

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

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

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

339
        return 0;
340
}
341

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

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

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

350
        if (pidref->fd >= 0) {
9,813✔
351
                siginfo_t si;
9,813✔
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,813✔
357
                si.si_signo = sig;
9,813✔
358
                si.si_code = SI_QUEUE;
9,813✔
359
                si.si_pid = getpid_cached();
9,813✔
360
                si.si_uid = getuid();
9,813✔
361
                si.si_value.sival_int = value;
9,813✔
362

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

366
        if (pidref->pid > 0)
×
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) {
75,222✔
373
        int r;
75,222✔
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))
75,222✔
380
                return -ESRCH;
381

382
        if (pidref_is_remote(pidref))
75,220✔
383
                return -EREMOTE;
384

385
        if (pidref->pid == 1)
75,219✔
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)
60,199✔
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);
42,779✔
392
        if (r < 0)
42,779✔
393
                return r;
2,405✔
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) {
37,374✔
399
        if (!pidref_is_set(pidref))
37,374✔
400
                return false;
37,374✔
401

402
        if (pidref_is_remote(pidref))
37,372✔
403
                return false;
404

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

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

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

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

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

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

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

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

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

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

443
        if (ret)
13,959✔
444
                *ret = si;
9,902✔
445

446
        return 0;
447
}
448

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

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

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

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

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

470
        assert(a);
88,343✔
471
        assert(b);
88,343✔
472

473
        r = CMP(pidref_is_set(a), pidref_is_set(b));
265,029✔
474
        if (r != 0)
88,343✔
475
                return r;
×
476

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

481
        r = CMP(pidref_is_remote(a), pidref_is_remote(b));
176,686✔
482
        if (r != 0)
88,343✔
483
                return r;
×
484

485
        r = CMP(a->pid, b->pid);
88,343✔
486
        if (r != 0)
71,235✔
487
                return r;
20,526✔
488

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

492
        return 0;
493
}
494

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

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