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

systemd / systemd / 16062852561

03 Jul 2025 10:04PM UTC coverage: 72.193% (+0.1%) from 72.096%
16062852561

push

github

bluca
pcrlock: process components outside of location window properly

So far, when we tried to match a component to eent log entries we
skipped those components if they were outside of our location window.
That however is too aggressive, since it means any components that are
already in the logs, but outside of the location window will be
considered unrecognized in the logs, and thus removed from the PCR
policy.

Change things around: always try to match up all components, regardless
if inside the location window or outside, but then make it non-fatal we
can't find a component outside of the location window.

Fixes: #36079

7 of 9 new or added lines in 1 file covered. (77.78%)

4116 existing lines in 75 files now uncovered.

301219 of 417241 relevant lines covered (72.19%)

730820.5 hits per line

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

77.53
/src/basic/fd-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fcntl.h>
4
#include <linux/fs.h>
5
#include <linux/kcmp.h>
6
#include <sys/ioctl.h>
7
#include <sys/resource.h>
8
#include <sys/stat.h>
9
#include <unistd.h>
10

11
#include "alloc-util.h"
12
#include "dirent-util.h"
13
#include "errno-util.h"
14
#include "fd-util.h"
15
#include "fileio.h"
16
#include "format-util.h"
17
#include "fs-util.h"
18
#include "log.h"
19
#include "missing_syscall.h"
20
#include "mountpoint-util.h"
21
#include "parse-util.h"
22
#include "path-util.h"
23
#include "process-util.h"
24
#include "socket-util.h"
25
#include "sort-util.h"
26
#include "stat-util.h"
27
#include "stdio-util.h"
28
#include "string-util.h"
29

30
/* The maximum number of iterations in the loop to close descriptors in the fallback case
31
 * when /proc/self/fd/ is inaccessible. */
32
#define MAX_FD_LOOP_LIMIT (1024*1024)
33

34
int close_nointr(int fd) {
43,215,937✔
35
        assert(fd >= 0);
43,215,937✔
36

37
        if (close(fd) >= 0)
43,215,937✔
38
                return 0;
39

40
        /*
41
         * Just ignore EINTR; a retry loop is the wrong thing to do on
42
         * Linux.
43
         *
44
         * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
45
         * https://bugzilla.gnome.org/show_bug.cgi?id=682819
46
         * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
47
         * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
48
         */
49
        if (errno == EINTR)
16,064✔
50
                return 0;
51

52
        return -errno;
16,064✔
53
}
54

55
int safe_close(int fd) {
112,683,959✔
56
        /*
57
         * Like close_nointr() but cannot fail. Guarantees errno is unchanged. Is a noop for negative fds,
58
         * and returns -EBADF, so that it can be used in this syntax:
59
         *
60
         * fd = safe_close(fd);
61
         */
62

63
        if (fd >= 0) {
112,683,959✔
UNCOV
64
                PROTECT_ERRNO;
×
65

66
                /* The kernel might return pretty much any error code
67
                 * via close(), but the fd will be closed anyway. The
68
                 * only condition we want to check for here is whether
69
                 * the fd was invalid at all... */
70

71
                assert_se(close_nointr(fd) != -EBADF);
42,786,873✔
72
        }
73

74
        return -EBADF;
112,683,959✔
75
}
76

77
void safe_close_pair(int p[static 2]) {
512,743✔
78
        assert(p);
512,743✔
79

80
        if (p[0] == p[1]) {
512,743✔
81
                /* Special case pairs which use the same fd in both
82
                 * directions... */
83
                p[0] = p[1] = safe_close(p[0]);
477,102✔
84
                return;
477,102✔
85
        }
86

87
        p[0] = safe_close(p[0]);
35,641✔
88
        p[1] = safe_close(p[1]);
35,641✔
89
}
90

91
void close_many(const int fds[], size_t n_fds) {
3,427,439✔
92
        assert(fds || n_fds == 0);
3,427,439✔
93

94
        FOREACH_ARRAY(fd, fds, n_fds)
3,478,342✔
95
                safe_close(*fd);
50,903✔
96
}
3,427,439✔
97

98
void close_many_unset(int fds[], size_t n_fds) {
28✔
99
        assert(fds || n_fds == 0);
28✔
100

101
        FOREACH_ARRAY(fd, fds, n_fds)
29✔
102
                *fd = safe_close(*fd);
1✔
103
}
28✔
104

105
void close_many_and_free(int *fds, size_t n_fds) {
618✔
106
        assert(fds || n_fds == 0);
618✔
107

108
        close_many(fds, n_fds);
618✔
109
        free(fds);
618✔
110
}
618✔
111

112
int fclose_nointr(FILE *f) {
2,012,819✔
113
        assert(f);
2,012,819✔
114

115
        /* Same as close_nointr(), but for fclose() */
116

117
        errno = 0; /* Extra safety: if the FILE* object is not encapsulating an fd, it might not set errno
2,012,819✔
118
                    * correctly. Let's hence initialize it to zero first, so that we aren't confused by any
119
                    * prior errno here */
120
        if (fclose(f) == 0)
2,012,819✔
121
                return 0;
122

UNCOV
123
        if (errno == EINTR)
×
124
                return 0;
125

UNCOV
126
        return errno_or_else(EIO);
×
127
}
128

129
FILE* safe_fclose(FILE *f) {
3,909,060✔
130

131
        /* Same as safe_close(), but for fclose() */
132

133
        if (f) {
3,909,060✔
UNCOV
134
                PROTECT_ERRNO;
×
135

136
                assert_se(fclose_nointr(f) != -EBADF);
2,012,819✔
137
        }
138

139
        return NULL;
3,909,060✔
140
}
141

UNCOV
142
DIR* safe_closedir(DIR *d) {
×
143

UNCOV
144
        if (d) {
×
145
                PROTECT_ERRNO;
×
146

UNCOV
147
                assert_se(closedir(d) >= 0 || errno != EBADF);
×
148
        }
149

UNCOV
150
        return NULL;
×
151
}
152

153
int fd_nonblock(int fd, bool nonblock) {
1,807,901✔
154
        int flags, nflags;
1,807,901✔
155

156
        assert(fd >= 0);
1,807,901✔
157

158
        flags = fcntl(fd, F_GETFL, 0);
1,807,901✔
159
        if (flags < 0)
1,807,901✔
UNCOV
160
                return -errno;
×
161

162
        nflags = UPDATE_FLAG(flags, O_NONBLOCK, nonblock);
1,807,901✔
163
        if (nflags == flags)
1,807,901✔
164
                return 0;
165

166
        if (fcntl(fd, F_SETFL, nflags) < 0)
1,785,631✔
UNCOV
167
                return -errno;
×
168

169
        return 1;
170
}
171

172
int stdio_disable_nonblock(void) {
14,634✔
173
        int ret = 0;
14,634✔
174

175
        /* stdin/stdout/stderr really should have O_NONBLOCK, which would confuse apps if left on, as
176
         * write()s might unexpectedly fail with EAGAIN. */
177

178
        RET_GATHER(ret, fd_nonblock(STDIN_FILENO, false));
14,634✔
179
        RET_GATHER(ret, fd_nonblock(STDOUT_FILENO, false));
14,634✔
180
        RET_GATHER(ret, fd_nonblock(STDERR_FILENO, false));
14,634✔
181

182
        return ret;
14,634✔
183
}
184

185
int fd_cloexec(int fd, bool cloexec) {
88,895✔
186
        int flags, nflags;
88,895✔
187

188
        assert(fd >= 0);
88,895✔
189

190
        flags = fcntl(fd, F_GETFD, 0);
88,895✔
191
        if (flags < 0)
88,895✔
UNCOV
192
                return -errno;
×
193

194
        nflags = UPDATE_FLAG(flags, FD_CLOEXEC, cloexec);
88,895✔
195
        if (nflags == flags)
88,895✔
196
                return 0;
197

198
        return RET_NERRNO(fcntl(fd, F_SETFD, nflags));
78,438✔
199
}
200

201
int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec) {
100✔
202
        int r = 0;
100✔
203

204
        assert(fds || n_fds == 0);
100✔
205

206
        FOREACH_ARRAY(fd, fds, n_fds) {
126✔
207
                if (*fd < 0) /* Skip gracefully over already invalidated fds */
26✔
UNCOV
208
                        continue;
×
209

210
                RET_GATHER(r, fd_cloexec(*fd, cloexec));
26✔
211
        }
212

213
        return r;
100✔
214
}
215

216
static bool fd_in_set(int fd, const int fds[], size_t n_fds) {
33,894✔
217
        assert(fd >= 0);
33,894✔
218
        assert(fds || n_fds == 0);
33,894✔
219

220
        FOREACH_ARRAY(i, fds, n_fds) {
16,312,337✔
221
                if (*i < 0)
16,281,274✔
UNCOV
222
                        continue;
×
223

224
                if (*i == fd)
16,281,274✔
225
                        return true;
226
        }
227

228
        return false;
229
}
230

231
int get_max_fd(void) {
9✔
232
        struct rlimit rl;
9✔
233
        rlim_t m;
9✔
234

235
        /* Return the highest possible fd, based RLIMIT_NOFILE, but enforcing FD_SETSIZE-1 as lower boundary
236
         * and INT_MAX as upper boundary. */
237

238
        if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
9✔
UNCOV
239
                return -errno;
×
240

241
        m = MAX(rl.rlim_cur, rl.rlim_max);
9✔
242
        if (m < FD_SETSIZE) /* Let's always cover at least 1024 fds */
9✔
243
                return FD_SETSIZE-1;
244

245
        if (m == RLIM_INFINITY || m > INT_MAX) /* Saturate on overflow. After all fds are "int", hence can
9✔
246
                                                * never be above INT_MAX */
247
                return INT_MAX;
248

249
        return (int) (m - 1);
9✔
250
}
251

252
static int close_all_fds_frugal(const int except[], size_t n_except) {
4✔
253
        int max_fd, r = 0;
4✔
254

255
        assert(except || n_except == 0);
4✔
256

257
        /* This is the inner fallback core of close_all_fds(). This never calls malloc() or opendir() or so
258
         * and hence is safe to be called in signal handler context. Most users should call close_all_fds(),
259
         * but when we assume we are called from signal handler context, then use this simpler call
260
         * instead. */
261

262
        max_fd = get_max_fd();
4✔
263
        if (max_fd < 0)
4✔
264
                return max_fd;
4✔
265

266
        /* Refuse to do the loop over more too many elements. It's better to fail immediately than to
267
         * spin the CPU for a long time. */
268
        if (max_fd > MAX_FD_LOOP_LIMIT)
4✔
UNCOV
269
                return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
×
270
                                       "Refusing to loop over %d potential fds.", max_fd);
271

272
        for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -EBADF) {
27,992✔
273
                int q;
27,988✔
274

275
                if (fd_in_set(fd, except, n_except))
27,988✔
276
                        continue;
1,925✔
277

278
                q = close_nointr(fd);
26,063✔
279
                if (q != -EBADF)
26,063✔
280
                        RET_GATHER(r, q);
10,000✔
281
        }
282

283
        return r;
284
}
285

286
static bool have_close_range = true; /* Assume we live in the future */
287

288
static int close_all_fds_special_case(const int except[], size_t n_except) {
45,623✔
289
        assert(n_except == 0 || except);
45,623✔
290

291
        /* Handles a few common special cases separately, since they are common and can be optimized really
292
         * nicely, since we won't need sorting for them. Returns > 0 if the special casing worked, 0
293
         * otherwise. */
294

295
        if (!have_close_range)
45,623✔
296
                return 0;
297

298
        if (n_except == 1 && except[0] < 0) /* Minor optimization: if we only got one fd, and it's invalid,
45,619✔
299
                                             * we got none */
300
                n_except = 0;
301

302
        switch (n_except) {
45,619✔
303

304
        case 0:
8,337✔
305
                /* Close everything. Yay! */
306

307
                if (close_range(3, INT_MAX, 0) >= 0)
8,337✔
308
                        return 1;
309

UNCOV
310
                if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
×
311
                        have_close_range = false;
×
312
                        return 0;
×
313
                }
314

UNCOV
315
                return -errno;
×
316

317
        case 1:
14,775✔
318
                /* Close all but exactly one, then we don't need no sorting. This is a pretty common
319
                 * case, hence let's handle it specially. */
320

321
                if ((except[0] <= 3 || close_range(3, except[0]-1, 0) >= 0) &&
14,775✔
322
                    (except[0] >= INT_MAX || close_range(MAX(3, except[0]+1), -1, 0) >= 0))
14,775✔
323
                        return 1;
14,775✔
324

UNCOV
325
                if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
×
326
                        have_close_range = false;
×
327
                        return 0;
×
328
                }
329

UNCOV
330
                return -errno;
×
331

332
        default:
333
                return 0;
334
        }
335
}
336

UNCOV
337
int close_all_fds_without_malloc(const int except[], size_t n_except) {
×
338
        int r;
×
339

UNCOV
340
        assert(n_except == 0 || except);
×
341

UNCOV
342
        r = close_all_fds_special_case(except, n_except);
×
343
        if (r < 0)
×
344
                return r;
UNCOV
345
        if (r > 0) /* special case worked! */
×
346
                return 0;
347

UNCOV
348
        return close_all_fds_frugal(except, n_except);
×
349
}
350

351
int close_all_fds(const int except[], size_t n_except) {
45,623✔
352
        _cleanup_closedir_ DIR *d = NULL;
45,623✔
353
        int r = 0;
45,623✔
354

355
        assert(n_except == 0 || except);
45,623✔
356

357
        r = close_all_fds_special_case(except, n_except);
45,623✔
358
        if (r < 0)
45,623✔
359
                return r;
360
        if (r > 0) /* special case worked! */
45,623✔
361
                return 0;
362

363
        if (have_close_range) {
22,511✔
364
                _cleanup_free_ int *sorted_malloc = NULL;
22,507✔
365
                size_t n_sorted;
22,507✔
366
                int *sorted;
22,507✔
367

368
                /* In the best case we have close_range() to close all fds between a start and an end fd,
369
                 * which we can use on the "inverted" exception array, i.e. all intervals between all
370
                 * adjacent pairs from the sorted exception array. This changes loop complexity from O(n)
371
                 * where n is number of open fds to O(mâ‹…log(m)) where m is the number of fds to keep
372
                 * open. Given that we assume n ≫ m that's preferable to us. */
373

374
                assert(n_except < SIZE_MAX);
22,507✔
375
                n_sorted = n_except + 1;
22,507✔
376

377
                if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */
22,507✔
378
                        sorted = sorted_malloc = new(int, n_sorted);
4✔
379
                else
380
                        sorted = newa(int, n_sorted);
22,503✔
381

382
                if (sorted) {
22,507✔
383
                        memcpy(sorted, except, n_except * sizeof(int));
22,507✔
384

385
                        /* Let's add fd 2 to the list of fds, to simplify the loop below, as this
386
                         * allows us to cover the head of the array the same way as the body */
387
                        sorted[n_sorted-1] = 2;
22,507✔
388

389
                        typesafe_qsort(sorted, n_sorted, cmp_int);
22,507✔
390

391
                        for (size_t i = 0; i < n_sorted-1; i++) {
103,304✔
392
                                int start, end;
80,799✔
393

394
                                start = MAX(sorted[i], 2); /* The first three fds shall always remain open */
80,799✔
395
                                end = MAX(sorted[i+1], 2);
80,799✔
396

397
                                assert(end >= start);
80,799✔
398

399
                                if (end - start <= 1)
80,799✔
400
                                        continue;
32,046✔
401

402
                                /* Close everything between the start and end fds (both of which shall stay open) */
403
                                if (close_range(start + 1, end - 1, 0) < 0) {
48,753✔
404
                                        if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
2✔
UNCOV
405
                                                return -errno;
×
406

407
                                        have_close_range = false;
2✔
408
                                        break;
2✔
409
                                }
410
                        }
411

412
                        if (have_close_range) {
22,507✔
413
                                /* The loop succeeded. Let's now close everything beyond the end */
414

415
                                if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
22,505✔
416
                                        return 0;
417

418
                                if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) >= 0)
22,505✔
419
                                        return 0;
420

UNCOV
421
                                if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
×
422
                                        return -errno;
×
423

UNCOV
424
                                have_close_range = false;
×
425
                        }
426
                }
427

428
                /* Fallback on OOM or if close_range() is not supported */
429
        }
430

431
        d = opendir("/proc/self/fd");
6✔
432
        if (!d)
6✔
433
                return close_all_fds_frugal(except, n_except); /* ultimate fallback if /proc/ is not available */
4✔
434

435
        FOREACH_DIRENT(de, d, return -errno) {
5,920✔
436
                int fd = -EBADF, q;
5,914✔
437

438
                if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
5,914✔
UNCOV
439
                        continue;
×
440

441
                fd = parse_fd(de->d_name);
5,914✔
442
                if (fd < 0)
5,914✔
443
                        /* Let's better ignore this, just in case */
UNCOV
444
                        continue;
×
445

446
                if (fd < 3)
5,914✔
447
                        continue;
6✔
448

449
                if (fd == dirfd(d))
5,908✔
450
                        continue;
2✔
451

452
                if (fd_in_set(fd, except, n_except))
5,906✔
453
                        continue;
906✔
454

455
                q = close_nointr(fd);
5,000✔
456
                if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */
5,000✔
UNCOV
457
                        r = q;
×
458
        }
459

460
        return r;
461
}
462

463
int pack_fds(int fds[], size_t n_fds) {
10,232✔
464
        if (n_fds <= 0)
10,232✔
465
                return 0;
466

467
        /* Shifts around the fds in the provided array such that they
468
         * all end up packed next to each-other, in order, starting
469
         * from SD_LISTEN_FDS_START. This must be called after close_all_fds();
470
         * it is likely to freeze up otherwise. You should probably use safe_fork_full
471
         * with FORK_CLOSE_ALL_FDS|FORK_PACK_FDS set, to ensure that this is done correctly.
472
         * The fds array is modified in place with the new FD numbers. */
473

474
        assert(fds);
1,732✔
475

476
        for (int start = 0;;) {
477
                int restart_from = -1;
1,732✔
478

479
                for (int i = start; i < (int) n_fds; i++) {
5,004✔
480
                        int nfd;
3,272✔
481

482
                        /* Already at right index? */
483
                        if (fds[i] == i + 3)
3,272✔
484
                                continue;
3✔
485

486
                        nfd = fcntl(fds[i], F_DUPFD, i + 3);
3,269✔
487
                        if (nfd < 0)
3,269✔
UNCOV
488
                                return -errno;
×
489

490
                        safe_close(fds[i]);
3,269✔
491
                        fds[i] = nfd;
3,269✔
492

493
                        /* Hmm, the fd we wanted isn't free? Then
494
                         * let's remember that and try again from here */
495
                        if (nfd != i + 3 && restart_from < 0)
3,269✔
UNCOV
496
                                restart_from = i;
×
497
                }
498

499
                if (restart_from < 0)
1,732✔
500
                        break;
501

502
                start = restart_from;
503
        }
504

505
        assert(fds[0] == 3);
1,732✔
506

507
        return 0;
508
}
509

510
int fd_validate(int fd) {
113,605✔
511
        if (fd < 0)
113,605✔
512
                return -EBADF;
513

514
        if (fcntl(fd, F_GETFD) < 0)
113,603✔
515
                return -errno;
45,867✔
516

517
        return 0;
518
}
519

520
int same_fd(int a, int b) {
13,598✔
521
        struct stat sta, stb;
13,598✔
522
        pid_t pid;
13,598✔
523
        int r, fa, fb;
13,598✔
524

525
        assert(a >= 0);
13,598✔
526
        assert(b >= 0);
13,598✔
527

528
        /* Compares two file descriptors. Note that semantics are quite different depending on whether we
529
         * have F_DUPFD_QUERY/kcmp() or we don't. If we have F_DUPFD_QUERY/kcmp() this will only return true
530
         * for dup()ed file descriptors, but not otherwise. If we don't have F_DUPFD_QUERY/kcmp() this will
531
         * also return true for two fds of the same file, created by separate open() calls. Since we use this
532
         * call mostly for filtering out duplicates in the fd store this difference hopefully doesn't matter
533
         * too much.
534
         *
535
         * Guarantees that if either of the passed fds is not allocated we'll return -EBADF. */
536

537
        if (a == b) {
13,598✔
538
                /* Let's validate that the fd is valid */
539
                r = fd_validate(a);
7✔
540
                if (r < 0)
7✔
541
                        return r;
13,598✔
542

543
                return true;
6✔
544
        }
545

546
        /* Try to use F_DUPFD_QUERY if we have it first, as it is the nicest API */
547
        r = fcntl(a, F_DUPFD_QUERY, b);
13,591✔
548
        if (r > 0)
13,591✔
549
                return true;
550
        if (r == 0) {
13,583✔
551
                /* The kernel will return 0 in case the first fd is allocated, but the 2nd is not. (Which is different in the kcmp() case) Explicitly validate it hence. */
552
                r = fd_validate(b);
13,582✔
553
                if (r < 0)
13,582✔
554
                        return r;
555

556
                return false;
13,581✔
557
        }
558
        /* On old kernels (< 6.10) that do not support F_DUPFD_QUERY this will return EINVAL for regular fds, and EBADF on O_PATH fds. Confusing. */
559
        if (errno == EBADF) {
1✔
560
                /* EBADF could mean two things: the first fd is not valid, or it is valid and is O_PATH and
561
                 * F_DUPFD_QUERY is not supported. Let's validate the fd explicitly, to distinguish this
562
                 * case. */
563
                r = fd_validate(a);
1✔
564
                if (r < 0)
1✔
565
                        return r;
566

567
                /* If the fd is valid, but we got EBADF, then let's try kcmp(). */
UNCOV
568
        } else if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
×
569
                return -errno;
×
570

571
        /* Try to use kcmp() if we have it. */
UNCOV
572
        pid = getpid_cached();
×
573
        r = kcmp(pid, pid, KCMP_FILE, a, b);
×
574
        if (r >= 0)
×
575
                return !r;
×
576
        if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
×
577
                return -errno;
×
578

579
        /* We have neither F_DUPFD_QUERY nor kcmp(), use fstat() instead. */
UNCOV
580
        if (fstat(a, &sta) < 0)
×
581
                return -errno;
×
582

UNCOV
583
        if (fstat(b, &stb) < 0)
×
584
                return -errno;
×
585

UNCOV
586
        if (!stat_inode_same(&sta, &stb))
×
587
                return false;
588

589
        /* We consider all device fds different, since two device fds might refer to quite different device
590
         * contexts even though they share the same inode and backing dev_t. */
591

UNCOV
592
        if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
×
593
                return false;
594

595
        /* The fds refer to the same inode on disk, let's also check if they have the same fd flags. This is
596
         * useful to distinguish the read and write side of a pipe created with pipe(). */
UNCOV
597
        fa = fcntl(a, F_GETFL);
×
598
        if (fa < 0)
×
599
                return -errno;
×
600

UNCOV
601
        fb = fcntl(b, F_GETFL);
×
602
        if (fb < 0)
×
603
                return -errno;
×
604

UNCOV
605
        return fa == fb;
×
606
}
607

608
bool fdname_is_valid(const char *s) {
14,309✔
609
        const char *p;
14,309✔
610

611
        /* Validates a name for $LISTEN_FDNAMES. We basically allow
612
         * everything ASCII that's not a control character. Also, as
613
         * special exception the ":" character is not allowed, as we
614
         * use that as field separator in $LISTEN_FDNAMES.
615
         *
616
         * Note that the empty string is explicitly allowed
617
         * here. However, we limit the length of the names to 255
618
         * characters. */
619

620
        if (!s)
14,309✔
621
                return false;
622

623
        for (p = s; *p; p++) {
217,530✔
624
                if (*p < ' ')
203,226✔
625
                        return false;
626
                if (*p >= 127)
203,226✔
627
                        return false;
628
                if (*p == ':')
203,226✔
629
                        return false;
630
        }
631

632
        return p - s <= FDNAME_MAX;
14,304✔
633
}
634

635
int fd_get_path(int fd, char **ret) {
1,761,195✔
636
        int r;
1,761,195✔
637

638
        assert(fd >= 0 || fd == AT_FDCWD);
1,761,195✔
639

640
        if (fd == AT_FDCWD)
1,761,195✔
641
                return safe_getcwd(ret);
5,107✔
642

643
        r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret);
1,756,088✔
644
        if (r == -ENOENT)
1,756,088✔
645
                return proc_fd_enoent_errno();
4✔
646
        return r;
647
}
648

649
int move_fd(int from, int to, int cloexec) {
22,996✔
650
        int r;
22,996✔
651

652
        /* Move fd 'from' to 'to', make sure FD_CLOEXEC remains equal if requested, and release the old fd. If
653
         * 'cloexec' is passed as -1, the original FD_CLOEXEC is inherited for the new fd. If it is 0, it is turned
654
         * off, if it is > 0 it is turned on. */
655

656
        if (from < 0)
22,996✔
657
                return -EBADF;
658
        if (to < 0)
22,996✔
659
                return -EBADF;
660

661
        if (from == to) {
22,996✔
662

UNCOV
663
                if (cloexec >= 0) {
×
664
                        r = fd_cloexec(to, cloexec);
×
665
                        if (r < 0)
×
666
                                return r;
667
                }
668

UNCOV
669
                return to;
×
670
        }
671

672
        if (cloexec < 0) {
22,996✔
UNCOV
673
                int fl;
×
674

UNCOV
675
                fl = fcntl(from, F_GETFD, 0);
×
676
                if (fl < 0)
×
677
                        return -errno;
×
678

UNCOV
679
                cloexec = FLAGS_SET(fl, FD_CLOEXEC);
×
680
        }
681

682
        r = dup3(from, to, cloexec ? O_CLOEXEC : 0);
45,992✔
683
        if (r < 0)
22,996✔
UNCOV
684
                return -errno;
×
685

686
        assert(r == to);
22,996✔
687

688
        safe_close(from);
22,996✔
689

690
        return to;
22,996✔
691
}
692

693
int fd_move_above_stdio(int fd) {
786,482✔
694
        int flags, copy;
786,482✔
695
        PROTECT_ERRNO;
786,482✔
696

697
        /* Moves the specified file descriptor if possible out of the range [0…2], i.e. the range of
698
         * stdin/stdout/stderr. If it can't be moved outside of this range the original file descriptor is
699
         * returned. This call is supposed to be used for long-lasting file descriptors we allocate in our code that
700
         * might get loaded into foreign code, and where we want ensure our fds are unlikely used accidentally as
701
         * stdin/stdout/stderr of unrelated code.
702
         *
703
         * Note that this doesn't fix any real bugs, it just makes it less likely that our code will be affected by
704
         * buggy code from others that mindlessly invokes 'fprintf(stderr, …' or similar in places where stderr has
705
         * been closed before.
706
         *
707
         * This function is written in a "best-effort" and "least-impact" style. This means whenever we encounter an
708
         * error we simply return the original file descriptor, and we do not touch errno. */
709

710
        if (fd < 0 || fd > 2)
786,482✔
711
                return fd;
712

713
        flags = fcntl(fd, F_GETFD, 0);
105✔
714
        if (flags < 0)
105✔
715
                return fd;
716

717
        if (flags & FD_CLOEXEC)
105✔
718
                copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
103✔
719
        else
720
                copy = fcntl(fd, F_DUPFD, 3);
2✔
721
        if (copy < 0)
105✔
722
                return fd;
723

724
        assert(copy > 2);
105✔
725

726
        (void) close(fd);
105✔
727
        return copy;
728
}
729

730
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd) {
14,943✔
731
        int fd[3] = { original_input_fd,             /* Put together an array of fds we work on */
14,943✔
732
                      original_output_fd,
733
                      original_error_fd },
734
            null_fd = -EBADF,                        /* If we open /dev/null, we store the fd to it here */
14,943✔
735
            copy_fd[3] = EBADF_TRIPLET,              /* This contains all fds we duplicate here
14,943✔
736
                                                      * temporarily, and hence need to close at the end. */
737
            r;
738
        bool null_readable, null_writable;
14,943✔
739

740
        /* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors
741
         * is specified as -EBADF it will be connected with /dev/null instead. If any of the file descriptors
742
         * is passed as itself (e.g. stdin as STDIN_FILENO) it is left unmodified, but the O_CLOEXEC bit is
743
         * turned off should it be on.
744
         *
745
         * Note that if any of the passed file descriptors are > 2 they will be closed — both on success and
746
         * on failure! Thus, callers should assume that when this function returns the input fds are
747
         * invalidated.
748
         *
749
         * Note that when this function fails stdin/stdout/stderr might remain half set up!
750
         *
751
         * O_CLOEXEC is turned off for all three file descriptors (which is how it should be for
752
         * stdin/stdout/stderr). */
753

754
        null_readable = original_input_fd < 0;
14,943✔
755
        null_writable = original_output_fd < 0 || original_error_fd < 0;
14,943✔
756

757
        /* First step, open /dev/null once, if we need it */
758
        if (null_readable || null_writable) {
14,943✔
759

760
                /* Let's open this with O_CLOEXEC first, and convert it to non-O_CLOEXEC when we move the fd to the final position. */
761
                null_fd = open("/dev/null", (null_readable && null_writable ? O_RDWR :
24,796✔
762
                                             null_readable ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
12,351✔
763
                if (null_fd < 0) {
12,445✔
UNCOV
764
                        r = -errno;
×
765
                        goto finish;
×
766
                }
767

768
                /* If this fd is in the 0…2 range, let's move it out of it */
769
                if (null_fd < 3) {
12,445✔
770
                        int copy;
13✔
771

772
                        copy = fcntl(null_fd, F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
13✔
773
                        if (copy < 0) {
13✔
UNCOV
774
                                r = -errno;
×
775
                                goto finish;
×
776
                        }
777

778
                        close_and_replace(null_fd, copy);
13✔
779
                }
780
        }
781

782
        /* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */
783
        for (int i = 0; i < 3; i++)
59,772✔
784
                if (fd[i] < 0)
44,829✔
785
                        fd[i] = null_fd;        /* A negative parameter means: connect this one to /dev/null */
12,626✔
786
                else if (fd[i] != i && fd[i] < 3) {
32,203✔
787
                        /* This fd is in the 0…2 territory, but not at its intended place, move it out of there, so that we can work there. */
788
                        copy_fd[i] = fcntl(fd[i], F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
82✔
789
                        if (copy_fd[i] < 0) {
82✔
UNCOV
790
                                r = -errno;
×
791
                                goto finish;
×
792
                        }
793

794
                        fd[i] = copy_fd[i];
82✔
795
                }
796

797
        /* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that
798
         * we have freedom to move them around. If the fds already were at the right places then the specific
799
         * fds are -EBADF. Let's now move them to the right places. This is the point of no return. */
800
        for (int i = 0; i < 3; i++)
59,772✔
801
                if (fd[i] == i) {
44,829✔
802
                        /* fd is already in place, but let's make sure O_CLOEXEC is off */
803
                        r = fd_cloexec(i, false);
4,842✔
804
                        if (r < 0)
4,842✔
UNCOV
805
                                goto finish;
×
806
                } else {
807
                        assert(fd[i] > 2);
39,987✔
808

809
                        if (dup2(fd[i], i) < 0) { /* Turns off O_CLOEXEC on the new fd. */
39,987✔
UNCOV
810
                                r = -errno;
×
811
                                goto finish;
×
812
                        }
813
                }
814

815
        r = 0;
816

817
finish:
14,943✔
818
        /* Close the original fds, but only if they were outside of the stdio range. Also, properly check for the same
819
         * fd passed in multiple times. */
820
        safe_close_above_stdio(original_input_fd);
14,943✔
821
        if (original_output_fd != original_input_fd)
14,943✔
822
                safe_close_above_stdio(original_output_fd);
14,694✔
823
        if (original_error_fd != original_input_fd && original_error_fd != original_output_fd)
14,943✔
824
                safe_close_above_stdio(original_error_fd);
14,520✔
825

826
        /* Close the copies we moved > 2 */
827
        close_many(copy_fd, 3);
14,943✔
828

829
        /* Close our null fd, if it's > 2 */
830
        safe_close_above_stdio(null_fd);
14,943✔
831

832
        return r;
14,943✔
833
}
834

835
int fd_reopen(int fd, int flags) {
1,527,135✔
836
        assert(fd >= 0 || fd == AT_FDCWD);
1,527,135✔
837
        assert(!FLAGS_SET(flags, O_CREAT));
1,527,135✔
838

839
        /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
840
         * turn O_RDWR fds into O_RDONLY fds.
841
         *
842
         * This doesn't work on sockets (since they cannot be open()ed, ever).
843
         *
844
         * This implicitly resets the file read index to 0.
845
         *
846
         * If AT_FDCWD is specified as file descriptor gets an fd to the current cwd.
847
         *
848
         * If the specified file descriptor refers to a symlink via O_PATH, then this function cannot be used
849
         * to follow that symlink. Because we cannot have non-O_PATH fds to symlinks reopening it without
850
         * O_PATH will always result in -ELOOP. Or in other words: if you have an O_PATH fd to a symlink you
851
         * can reopen it only if you pass O_PATH again. */
852

853
        if (FLAGS_SET(flags, O_NOFOLLOW))
1,527,135✔
854
                /* O_NOFOLLOW is not allowed in fd_reopen(), because after all this is primarily implemented
855
                 * via a symlink-based interface in /proc/self/fd. Let's refuse this here early. Note that
856
                 * the kernel would generate ELOOP here too, hence this manual check is mostly redundant –
857
                 * the only reason we add it here is so that the O_DIRECTORY special case (see below) behaves
858
                 * the same way as the non-O_DIRECTORY case. */
859
                return -ELOOP;
1,527,135✔
860

861
        if (FLAGS_SET(flags, O_DIRECTORY) || fd == AT_FDCWD)
1,527,129✔
862
                /* If we shall reopen the fd as directory we can just go via "." and thus bypass the whole
863
                 * magic /proc/ directory, and make ourselves independent of that being mounted. */
864
                return RET_NERRNO(openat(fd, ".", flags | O_DIRECTORY));
255,323✔
865

866
        int new_fd = open(FORMAT_PROC_FD_PATH(fd), flags);
1,271,812✔
867
        if (new_fd < 0) {
1,271,812✔
868
                if (errno != ENOENT)
57,287✔
869
                        return -errno;
57,284✔
870

871
                return proc_fd_enoent_errno();
3✔
872
        }
873

874
        return new_fd;
875
}
876

877
int fd_reopen_propagate_append_and_position(int fd, int flags) {
28✔
878
        /* Invokes fd_reopen(fd, flags), but propagates O_APPEND if set on original fd, and also tries to
879
         * keep current file position.
880
         *
881
         * You should use this if the original fd potentially is O_APPEND, otherwise we get rather
882
         * "unexpected" behavior. Unless you intentionally want to overwrite pre-existing data, and have
883
         * your output overwritten by the next user.
884
         *
885
         * Use case: "systemd-run --pty >> some-log".
886
         *
887
         * The "keep position" part is obviously nonsense for the O_APPEND case, but should reduce surprises
888
         * if someone carefully pre-positioned the passed in original input or non-append output FDs. */
889

890
        assert(fd >= 0);
28✔
891
        assert(!(flags & (O_APPEND|O_DIRECTORY)));
28✔
892

893
        int existing_flags = fcntl(fd, F_GETFL);
28✔
894
        if (existing_flags < 0)
28✔
UNCOV
895
                return -errno;
×
896

897
        int new_fd = fd_reopen(fd, flags | (existing_flags & O_APPEND));
28✔
898
        if (new_fd < 0)
28✔
899
                return new_fd;
900

901
        /* Try to adjust the offset, but ignore errors. */
902
        off_t p = lseek(fd, 0, SEEK_CUR);
19✔
903
        if (p > 0) {
19✔
UNCOV
904
                off_t new_p = lseek(new_fd, p, SEEK_SET);
×
905
                if (new_p < 0)
×
906
                        log_debug_errno(errno,
×
907
                                        "Failed to propagate file position for re-opened fd %d, ignoring: %m",
908
                                        fd);
UNCOV
909
                else if (new_p != p)
×
910
                        log_debug("Failed to propagate file position for re-opened fd %d (%lld != %lld), ignoring.",
×
911
                                  fd, (long long) new_p, (long long) p);
912
        }
913

914
        return new_fd;
915
}
916

917
int fd_reopen_condition(
1,201,222✔
918
                int fd,
919
                int flags,
920
                int mask,
921
                int *ret_new_fd) {
922

923
        int r, new_fd;
1,201,222✔
924

925
        assert(fd >= 0);
1,201,222✔
926
        assert(!FLAGS_SET(flags, O_CREAT));
1,201,222✔
927

928
        /* Invokes fd_reopen(fd, flags), but only if the existing F_GETFL flags don't match the specified
929
         * flags (masked by the specified mask). This is useful for converting O_PATH fds into real fds if
930
         * needed, but only then. */
931

932
        r = fcntl(fd, F_GETFL);
1,201,222✔
933
        if (r < 0)
1,201,222✔
UNCOV
934
                return -errno;
×
935

936
        if ((r & mask) == (flags & mask)) {
1,201,222✔
937
                *ret_new_fd = -EBADF;
1,197,180✔
938
                return fd;
1,197,180✔
939
        }
940

941
        new_fd = fd_reopen(fd, flags);
4,042✔
942
        if (new_fd < 0)
4,042✔
943
                return new_fd;
944

945
        *ret_new_fd = new_fd;
4,042✔
946
        return new_fd;
4,042✔
947
}
948

949
int fd_is_opath(int fd) {
445,638✔
950
        int r;
445,638✔
951

952
        assert(fd >= 0);
445,638✔
953

954
        r = fcntl(fd, F_GETFL);
445,638✔
955
        if (r < 0)
445,638✔
UNCOV
956
                return -errno;
×
957

958
        return FLAGS_SET(r, O_PATH);
445,638✔
959
}
960

961
int fd_verify_safe_flags_full(int fd, int extra_flags) {
503✔
962
        int flags, unexpected_flags;
503✔
963

964
        /* Check if an extrinsic fd is safe to work on (by a privileged service). This ensures that clients
965
         * can't trick a privileged service into giving access to a file the client doesn't already have
966
         * access to (especially via something like O_PATH).
967
         *
968
         * O_NOFOLLOW: For some reason the kernel will return this flag from fcntl(); it doesn't go away
969
         *             immediately after open(). It should have no effect whatsoever to an already-opened FD,
970
         *             and since we refuse O_PATH it should be safe.
971
         *
972
         * RAW_O_LARGEFILE: glibc secretly sets this and neglects to hide it from us if we call fcntl.
973
         *                  See comment in src/basic/include/fcntl.h for more details about this.
974
         *
975
         * If 'extra_flags' is specified as non-zero the included flags are also allowed.
976
         */
977

978
        assert(fd >= 0);
503✔
979

980
        flags = fcntl(fd, F_GETFL);
503✔
981
        if (flags < 0)
503✔
UNCOV
982
                return -errno;
×
983

984
        unexpected_flags = flags & ~(O_ACCMODE_STRICT|O_NOFOLLOW|RAW_O_LARGEFILE|extra_flags);
503✔
985
        if (unexpected_flags != 0)
503✔
UNCOV
986
                return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
×
987
                                       "Unexpected flags set for extrinsic fd: 0%o",
988
                                       (unsigned) unexpected_flags);
989

990
        return flags & (O_ACCMODE_STRICT | extra_flags); /* return the flags variable, but remove the noise */
503✔
991
}
992

993
int read_nr_open(void) {
30,093✔
994
        _cleanup_free_ char *nr_open = NULL;
30,093✔
995
        int r;
30,093✔
996

997
        /* Returns the kernel's current fd limit, either by reading it of /proc/sys if that works, or using the
998
         * hard-coded default compiled-in value of current kernels (1M) if not. This call will never fail. */
999

1000
        r = read_one_line_file("/proc/sys/fs/nr_open", &nr_open);
30,093✔
1001
        if (r < 0)
30,093✔
1002
                log_debug_errno(r, "Failed to read /proc/sys/fs/nr_open, ignoring: %m");
30,093✔
1003
        else {
1004
                int v;
30,090✔
1005

1006
                r = safe_atoi(nr_open, &v);
30,090✔
1007
                if (r < 0)
30,090✔
UNCOV
1008
                        log_debug_errno(r, "Failed to parse /proc/sys/fs/nr_open value '%s', ignoring: %m", nr_open);
×
1009
                else
1010
                        return v;
30,090✔
1011
        }
1012

1013
        /* If we fail, fall back to the hard-coded kernel limit of 1024 * 1024. */
1014
        return 1024 * 1024;
1015
}
1016

1017
int fd_get_diskseq(int fd, uint64_t *ret) {
57,303✔
1018
        uint64_t diskseq;
57,303✔
1019

1020
        assert(fd >= 0);
57,303✔
1021
        assert(ret);
57,303✔
1022

1023
        if (ioctl(fd, BLKGETDISKSEQ, &diskseq) < 0) {
57,303✔
1024
                /* Note that the kernel is weird: non-existing ioctls currently return EINVAL
1025
                 * rather than ENOTTY on loopback block devices. They should fix that in the kernel,
1026
                 * but in the meantime we accept both here. */
UNCOV
1027
                if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL)
×
1028
                        return -errno;
×
1029

1030
                return -EOPNOTSUPP;
1031
        }
1032

1033
        *ret = diskseq;
57,303✔
1034

1035
        return 0;
57,303✔
1036
}
1037

1038
int path_is_root_at(int dir_fd, const char *path) {
4,447,369✔
1039
        _cleanup_close_ int fd = -EBADF, pfd = -EBADF;
4,447,369✔
1040

1041
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
4,447,369✔
1042

1043
        if (!isempty(path)) {
4,447,369✔
1044
                fd = openat(dir_fd, path, O_PATH|O_DIRECTORY|O_CLOEXEC);
103,875✔
1045
                if (fd < 0)
103,875✔
1046
                        return errno == ENOTDIR ? false : -errno;
15,103✔
1047

1048
                dir_fd = fd;
1049
        }
1050

1051
        pfd = openat(dir_fd, "..", O_PATH|O_DIRECTORY|O_CLOEXEC);
4,432,266✔
1052
        if (pfd < 0)
4,432,266✔
1053
                return errno == ENOTDIR ? false : -errno;
2✔
1054

1055
        /* Even if the parent directory has the same inode, the fd may not point to the root directory "/",
1056
         * and we also need to check that the mount ids are the same. Otherwise, a construct like the
1057
         * following could be used to trick us:
1058
         *
1059
         * $ mkdir /tmp/x /tmp/x/y
1060
         * $ mount --bind /tmp/x /tmp/x/y
1061
         */
1062

1063
        return fds_are_same_mount(dir_fd, pfd);
4,432,264✔
1064
}
1065

1066
int fds_are_same_mount(int fd1, int fd2) {
4,432,282✔
1067
        struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */
4,432,282✔
1068
        int r;
4,432,282✔
1069

1070
        assert(fd1 >= 0);
4,432,282✔
1071
        assert(fd2 >= 0);
4,432,282✔
1072

1073
        if (statx(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0)
4,432,282✔
UNCOV
1074
                return -errno;
×
1075

1076
        if (statx(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0)
4,432,282✔
UNCOV
1077
                return -errno;
×
1078

1079
        /* First, compare inode. If these are different, the fd does not point to the root directory "/". */
1080
        if (!statx_inode_same(&sx1, &sx2))
4,432,282✔
1081
                return false;
1082

1083
        /* Note, statx() does not provide the mount ID and path_get_mnt_id_at() does not work when an old
1084
         * kernel is used. In that case, let's assume that we do not have such spurious mount points in an
1085
         * early boot stage, and silently skip the following check. */
1086

1087
        if (!FLAGS_SET(sx1.stx_mask, STATX_MNT_ID)) {
4,169,064✔
UNCOV
1088
                int mntid;
×
1089

UNCOV
1090
                r = path_get_mnt_id_at_fallback(fd1, "", &mntid);
×
1091
                if (r < 0)
×
1092
                        return r;
×
1093
                assert(mntid >= 0);
×
1094

UNCOV
1095
                sx1.stx_mnt_id = mntid;
×
1096
                sx1.stx_mask |= STATX_MNT_ID;
×
1097
        }
1098

1099
        if (!FLAGS_SET(sx2.stx_mask, STATX_MNT_ID)) {
4,169,064✔
UNCOV
1100
                int mntid;
×
1101

UNCOV
1102
                r = path_get_mnt_id_at_fallback(fd2, "", &mntid);
×
1103
                if (r < 0)
×
1104
                        return r;
×
1105
                assert(mntid >= 0);
×
1106

UNCOV
1107
                sx2.stx_mnt_id = mntid;
×
1108
                sx2.stx_mask |= STATX_MNT_ID;
×
1109
        }
1110

1111
        return statx_mount_same(&sx1, &sx2);
4,169,064✔
1112
}
1113

1114
char* format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int fd) {
3,285,225✔
1115
        assert(buf);
3,285,225✔
1116
        assert(fd >= 0);
3,285,225✔
1117
        assert_se(snprintf_ok(buf, PROC_FD_PATH_MAX, "/proc/self/fd/%i", fd));
3,285,225✔
1118
        return buf;
3,285,225✔
1119
}
1120

1121
const char* accmode_to_string(int flags) {
176✔
1122
        switch (flags & O_ACCMODE_STRICT) {
176✔
1123
        case O_RDONLY:
1124
                return "ro";
1125
        case O_WRONLY:
3✔
1126
                return "wo";
3✔
1127
        case O_RDWR:
170✔
1128
                return "rw";
170✔
UNCOV
1129
        default:
×
1130
                return NULL;
×
1131
        }
1132
}
1133

1134
char* format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid, int fd) {
1✔
1135
        assert(buf);
1✔
1136
        assert(fd >= 0);
1✔
1137
        assert(pid >= 0);
1✔
1138
        assert_se(snprintf_ok(buf, PROC_PID_FD_PATH_MAX, "/proc/" PID_FMT "/fd/%i", pid == 0 ? getpid_cached() : pid, fd));
1✔
1139
        return buf;
1✔
1140
}
1141

1142
int proc_fd_enoent_errno(void) {
7✔
1143
        int r;
7✔
1144

1145
        /* When ENOENT is returned during the use of FORMAT_PROC_FD_PATH, it can mean two things:
1146
         * that the fd does not exist or that /proc/ is not mounted.
1147
         * Let's make things debuggable and figure out the most appropriate errno. */
1148

1149
        r = proc_mounted();
7✔
1150
        if (r == 0)
7✔
1151
                return -ENOSYS;  /* /proc/ is not available or not set up properly, we're most likely
1152
                                    in some chroot environment. */
1153
        if (r > 0)
7✔
1154
                return -EBADF;   /* If /proc/ is definitely around then this means the fd is not valid. */
7✔
1155

1156
        return -ENOENT;          /* Otherwise let's propagate the original ENOENT. */
1157
}
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