• 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

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

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

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

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

35
int close_nointr(int fd) {
40,212,774✔
36
        assert(fd >= 0);
40,212,774✔
37

38
        if (close(fd) >= 0)
40,212,774✔
39
                return 0;
40

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

53
        return -errno;
16,009✔
54
}
55

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

64
        if (fd >= 0) {
105,328,964✔
UNCOV
65
                PROTECT_ERRNO;
×
66

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

72
                assert_se(close_nointr(fd) != -EBADF);
39,783,683✔
73
        }
74

75
        return -EBADF;
105,328,964✔
76
}
77

78
void safe_close_pair(int p[static 2]) {
522,452✔
79
        assert(p);
522,452✔
80

81
        if (p[0] == p[1]) {
522,452✔
82
                /* Special case pairs which use the same fd in both
83
                 * directions... */
84
                p[0] = p[1] = safe_close(p[0]);
486,559✔
85
                return;
486,559✔
86
        }
87

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

92
void close_many(const int fds[], size_t n_fds) {
3,067,825✔
93
        assert(fds || n_fds == 0);
3,067,825✔
94

95
        FOREACH_ARRAY(fd, fds, n_fds)
3,118,308✔
96
                safe_close(*fd);
50,483✔
97
}
3,067,825✔
98

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

102
        FOREACH_ARRAY(fd, fds, n_fds)
51✔
103
                *fd = safe_close(*fd);
1✔
104
}
50✔
105

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

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

113
int fclose_nointr(FILE *f) {
1,874,768✔
114
        assert(f);
1,874,768✔
115

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

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

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

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

130
FILE* safe_fclose(FILE *f) {
3,627,405✔
131

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

134
        if (f) {
3,627,405✔
UNCOV
135
                PROTECT_ERRNO;
×
136

137
                assert_se(fclose_nointr(f) != -EBADF);
1,874,768✔
138
        }
139

140
        return NULL;
3,627,405✔
141
}
142

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

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

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

UNCOV
151
        return NULL;
×
152
}
153

154
int fd_nonblock(int fd, bool nonblock) {
1,854,232✔
155
        int flags, nflags;
1,854,232✔
156

157
        assert(fd >= 0);
1,854,232✔
158

159
        flags = fcntl(fd, F_GETFL, 0);
1,854,232✔
160
        if (flags < 0)
1,854,232✔
UNCOV
161
                return -errno;
×
162

163
        nflags = UPDATE_FLAG(flags, O_NONBLOCK, nonblock);
1,854,232✔
164
        if (nflags == flags)
1,854,232✔
165
                return 0;
166

167
        if (fcntl(fd, F_SETFL, nflags) < 0)
1,832,428✔
UNCOV
168
                return -errno;
×
169

170
        return 1;
171
}
172

173
int stdio_disable_nonblock(void) {
14,542✔
174
        int ret = 0;
14,542✔
175

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

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

183
        return ret;
14,542✔
184
}
185

186
int fd_cloexec(int fd, bool cloexec) {
81,593✔
187
        int flags, nflags;
81,593✔
188

189
        assert(fd >= 0);
81,593✔
190

191
        flags = fcntl(fd, F_GETFD, 0);
81,593✔
192
        if (flags < 0)
81,593✔
UNCOV
193
                return -errno;
×
194

195
        nflags = UPDATE_FLAG(flags, FD_CLOEXEC, cloexec);
81,593✔
196
        if (nflags == flags)
81,593✔
197
                return 0;
198

199
        return RET_NERRNO(fcntl(fd, F_SETFD, nflags));
72,558✔
200
}
201

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

205
        assert(fds || n_fds == 0);
99✔
206

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

211
                RET_GATHER(r, fd_cloexec(*fd, cloexec));
25✔
212
        }
213

214
        return r;
99✔
215
}
216

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

221
        FOREACH_ARRAY(i, fds, n_fds) {
14,632,992✔
222
                if (*i < 0)
14,601,984✔
UNCOV
223
                        continue;
×
224

225
                if (*i == fd)
14,601,984✔
226
                        return true;
227
        }
228

229
        return false;
230
}
231

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

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

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

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

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

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

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

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

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

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

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

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

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

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

284
        return r;
285
}
286

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

289
static int close_all_fds_special_case(const int except[], size_t n_except) {
43,924✔
290
        assert(n_except == 0 || except);
43,924✔
291

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

296
        if (!have_close_range)
43,924✔
297
                return 0;
298

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

303
        switch (n_except) {
43,920✔
304

305
        case 0:
8,266✔
306
                /* Close everything. Yay! */
307

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

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

UNCOV
316
                return -errno;
×
317

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

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

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

UNCOV
331
                return -errno;
×
332

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

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

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

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

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

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

356
        assert(n_except == 0 || except);
43,924✔
357

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

364
        if (have_close_range) {
21,205✔
365
                _cleanup_free_ int *sorted_malloc = NULL;
21,201✔
366
                size_t n_sorted;
21,201✔
367
                int *sorted;
21,201✔
368

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

375
                assert(n_except < SIZE_MAX);
21,201✔
376
                n_sorted = n_except + 1;
21,201✔
377

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

383
                if (sorted) {
21,201✔
384
                        memcpy(sorted, except, n_except * sizeof(int));
21,201✔
385

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

390
                        typesafe_qsort(sorted, n_sorted, cmp_int);
21,201✔
391

392
                        for (size_t i = 0; i < n_sorted-1; i++) {
96,843✔
393
                                int start, end;
75,644✔
394

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

398
                                assert(end >= start);
75,644✔
399

400
                                if (end - start <= 1)
75,644✔
401
                                        continue;
29,569✔
402

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

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

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

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

419
                                if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) >= 0)
21,199✔
420
                                        return 0;
421

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

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

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

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

436
        FOREACH_DIRENT(de, d, return -errno) {
5,389✔
437
                int fd = -EBADF, q;
5,383✔
438

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

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

447
                if (fd < 3)
5,383✔
448
                        continue;
6✔
449

450
                if (fd == dirfd(d))
5,377✔
451
                        continue;
2✔
452

453
                if (fd_in_set(fd, except, n_except))
5,375✔
454
                        continue;
375✔
455

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

461
        return r;
462
}
463

464
int pack_fds(int fds[], size_t n_fds) {
9,657✔
465
        if (n_fds <= 0)
9,657✔
466
                return 0;
467

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

475
        assert(fds);
1,545✔
476

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

480
                for (int i = start; i < (int) n_fds; i++) {
4,140✔
481
                        int nfd;
2,595✔
482

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

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

491
                        safe_close(fds[i]);
2,593✔
492
                        fds[i] = nfd;
2,593✔
493

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

500
                if (restart_from < 0)
1,545✔
501
                        break;
502

503
                start = restart_from;
504
        }
505

506
        assert(fds[0] == 3);
1,545✔
507

508
        return 0;
509
}
510

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

515
        if (fcntl(fd, F_GETFD) < 0)
113,021✔
516
                return -errno;
45,756✔
517

518
        return 0;
519
}
520

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

526
        assert(a >= 0);
13,016✔
527
        assert(b >= 0);
13,016✔
528

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

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

544
                return true;
6✔
545
        }
546

547
        /* Try to use F_DUPFD_QUERY if we have it first, as it is the nicest API */
548
        r = fcntl(a, F_DUPFD_QUERY, b);
13,009✔
549
        if (r > 0)
13,009✔
550
                return true;
551
        if (r == 0) {
13,001✔
552
                /* 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. */
553
                r = fd_validate(b);
13,000✔
554
                if (r < 0)
13,000✔
555
                        return r;
556

557
                return false;
12,999✔
558
        }
559
        /* 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. */
560
        if (errno == EBADF) {
1✔
561
                /* EBADF could mean two things: the first fd is not valid, or it is valid and is O_PATH and
562
                 * F_DUPFD_QUERY is not supported. Let's validate the fd explicitly, to distinguish this
563
                 * case. */
564
                r = fd_validate(a);
1✔
565
                if (r < 0)
1✔
566
                        return r;
567

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

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

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

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

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

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

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

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

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

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

609
void cmsg_close_all(struct msghdr *mh) {
95,301✔
610
        assert(mh);
95,301✔
611

612
        struct cmsghdr *cmsg;
95,301✔
613
        CMSG_FOREACH(cmsg, mh) {
316,134✔
614
                if (cmsg->cmsg_level != SOL_SOCKET)
62,766✔
UNCOV
615
                        continue;
×
616

617
                if (cmsg->cmsg_type == SCM_RIGHTS)
62,766✔
UNCOV
618
                        close_many(CMSG_TYPED_DATA(cmsg, int),
×
619
                                   (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
×
620
                else if (cmsg->cmsg_type == SCM_PIDFD) {
62,766✔
UNCOV
621
                        assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
×
622
                        safe_close(*CMSG_TYPED_DATA(cmsg, int));
×
623
                }
624
        }
625
}
95,301✔
626

627
bool fdname_is_valid(const char *s) {
13,423✔
628
        const char *p;
13,423✔
629

630
        /* Validates a name for $LISTEN_FDNAMES. We basically allow
631
         * everything ASCII that's not a control character. Also, as
632
         * special exception the ":" character is not allowed, as we
633
         * use that as field separator in $LISTEN_FDNAMES.
634
         *
635
         * Note that the empty string is explicitly allowed
636
         * here. However, we limit the length of the names to 255
637
         * characters. */
638

639
        if (!s)
13,423✔
640
                return false;
641

642
        for (p = s; *p; p++) {
203,912✔
643
                if (*p < ' ')
190,494✔
644
                        return false;
645
                if (*p >= 127)
190,494✔
646
                        return false;
647
                if (*p == ':')
190,494✔
648
                        return false;
649
        }
650

651
        return p - s <= FDNAME_MAX;
13,418✔
652
}
653

654
int fd_get_path(int fd, char **ret) {
1,808,684✔
655
        int r;
1,808,684✔
656

657
        assert(fd >= 0 || fd == AT_FDCWD);
1,808,684✔
658

659
        if (fd == AT_FDCWD)
1,808,684✔
660
                return safe_getcwd(ret);
5,107✔
661

662
        r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret);
1,803,577✔
663
        if (r == -ENOENT)
1,803,577✔
664
                return proc_fd_enoent_errno();
4✔
665
        return r;
666
}
667

668
int move_fd(int from, int to, int cloexec) {
21,644✔
669
        int r;
21,644✔
670

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

675
        if (from < 0)
21,644✔
676
                return -EBADF;
677
        if (to < 0)
21,644✔
678
                return -EBADF;
679

680
        if (from == to) {
21,644✔
681

UNCOV
682
                if (cloexec >= 0) {
×
683
                        r = fd_cloexec(to, cloexec);
×
684
                        if (r < 0)
×
685
                                return r;
686
                }
687

UNCOV
688
                return to;
×
689
        }
690

691
        if (cloexec < 0) {
21,644✔
UNCOV
692
                int fl;
×
693

UNCOV
694
                fl = fcntl(from, F_GETFD, 0);
×
695
                if (fl < 0)
×
696
                        return -errno;
×
697

UNCOV
698
                cloexec = FLAGS_SET(fl, FD_CLOEXEC);
×
699
        }
700

701
        r = dup3(from, to, cloexec ? O_CLOEXEC : 0);
43,288✔
702
        if (r < 0)
21,644✔
UNCOV
703
                return -errno;
×
704

705
        assert(r == to);
21,644✔
706

707
        safe_close(from);
21,644✔
708

709
        return to;
21,644✔
710
}
711

712
int fd_move_above_stdio(int fd) {
736,342✔
713
        int flags, copy;
736,342✔
714
        PROTECT_ERRNO;
736,342✔
715

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

729
        if (fd < 0 || fd > 2)
736,342✔
730
                return fd;
731

732
        flags = fcntl(fd, F_GETFD, 0);
105✔
733
        if (flags < 0)
105✔
734
                return fd;
735

736
        if (flags & FD_CLOEXEC)
105✔
737
                copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
103✔
738
        else
739
                copy = fcntl(fd, F_DUPFD, 3);
2✔
740
        if (copy < 0)
105✔
741
                return fd;
742

743
        assert(copy > 2);
105✔
744

745
        (void) close(fd);
105✔
746
        return copy;
747
}
748

749
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd) {
14,839✔
750
        int fd[3] = { original_input_fd,             /* Put together an array of fds we work on */
14,839✔
751
                      original_output_fd,
752
                      original_error_fd },
753
            null_fd = -EBADF,                        /* If we open /dev/null, we store the fd to it here */
14,839✔
754
            copy_fd[3] = EBADF_TRIPLET,              /* This contains all fds we duplicate here
14,839✔
755
                                                      * temporarily, and hence need to close at the end. */
756
            r;
757
        bool null_readable, null_writable;
14,839✔
758

759
        /* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors
760
         * is specified as -EBADF it will be connected with /dev/null instead. If any of the file descriptors
761
         * is passed as itself (e.g. stdin as STDIN_FILENO) it is left unmodified, but the O_CLOEXEC bit is
762
         * turned off should it be on.
763
         *
764
         * Note that if any of the passed file descriptors are > 2 they will be closed — both on success and
765
         * on failure! Thus, callers should assume that when this function returns the input fds are
766
         * invalidated.
767
         *
768
         * Note that when this function fails stdin/stdout/stderr might remain half set up!
769
         *
770
         * O_CLOEXEC is turned off for all three file descriptors (which is how it should be for
771
         * stdin/stdout/stderr). */
772

773
        null_readable = original_input_fd < 0;
14,839✔
774
        null_writable = original_output_fd < 0 || original_error_fd < 0;
14,839✔
775

776
        /* First step, open /dev/null once, if we need it */
777
        if (null_readable || null_writable) {
14,839✔
778

779
                /* Let's open this with O_CLOEXEC first, and convert it to non-O_CLOEXEC when we move the fd to the final position. */
780
                null_fd = open("/dev/null", (null_readable && null_writable ? O_RDWR :
24,673✔
781
                                             null_readable ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
12,292✔
782
                if (null_fd < 0) {
12,381✔
UNCOV
783
                        r = -errno;
×
784
                        goto finish;
×
785
                }
786

787
                /* If this fd is in the 0…2 range, let's move it out of it */
788
                if (null_fd < 3) {
12,381✔
789
                        int copy;
13✔
790

791
                        copy = fcntl(null_fd, F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
13✔
792
                        if (copy < 0) {
13✔
UNCOV
793
                                r = -errno;
×
794
                                goto finish;
×
795
                        }
796

797
                        close_and_replace(null_fd, copy);
13✔
798
                }
799
        }
800

801
        /* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */
802
        for (int i = 0; i < 3; i++)
59,356✔
803
                if (fd[i] < 0)
44,517✔
804
                        fd[i] = null_fd;        /* A negative parameter means: connect this one to /dev/null */
12,553✔
805
                else if (fd[i] != i && fd[i] < 3) {
31,964✔
806
                        /* 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. */
807
                        copy_fd[i] = fcntl(fd[i], F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
82✔
808
                        if (copy_fd[i] < 0) {
82✔
UNCOV
809
                                r = -errno;
×
810
                                goto finish;
×
811
                        }
812

813
                        fd[i] = copy_fd[i];
82✔
814
                }
815

816
        /* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that
817
         * we have freedom to move them around. If the fds already were at the right places then the specific
818
         * fds are -EBADF. Let's now move them to the right places. This is the point of no return. */
819
        for (int i = 0; i < 3; i++)
59,356✔
820
                if (fd[i] == i) {
44,517✔
821
                        /* fd is already in place, but let's make sure O_CLOEXEC is off */
822
                        r = fd_cloexec(i, false);
4,772✔
823
                        if (r < 0)
4,772✔
UNCOV
824
                                goto finish;
×
825
                } else {
826
                        assert(fd[i] > 2);
39,745✔
827

828
                        if (dup2(fd[i], i) < 0) { /* Turns off O_CLOEXEC on the new fd. */
39,745✔
UNCOV
829
                                r = -errno;
×
830
                                goto finish;
×
831
                        }
832
                }
833

834
        r = 0;
835

836
finish:
14,839✔
837
        /* Close the original fds, but only if they were outside of the stdio range. Also, properly check for the same
838
         * fd passed in multiple times. */
839
        safe_close_above_stdio(original_input_fd);
14,839✔
840
        if (original_output_fd != original_input_fd)
14,839✔
841
                safe_close_above_stdio(original_output_fd);
14,602✔
842
        if (original_error_fd != original_input_fd && original_error_fd != original_output_fd)
14,839✔
843
                safe_close_above_stdio(original_error_fd);
14,427✔
844

845
        /* Close the copies we moved > 2 */
846
        close_many(copy_fd, 3);
14,839✔
847

848
        /* Close our null fd, if it's > 2 */
849
        safe_close_above_stdio(null_fd);
14,839✔
850

851
        return r;
14,839✔
852
}
853

854
int fd_reopen(int fd, int flags) {
1,471,628✔
855
        assert(fd >= 0 || fd == AT_FDCWD);
1,471,628✔
856
        assert(!FLAGS_SET(flags, O_CREAT));
1,471,628✔
857

858
        /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
859
         * turn O_RDWR fds into O_RDONLY fds.
860
         *
861
         * This doesn't work on sockets (since they cannot be open()ed, ever).
862
         *
863
         * This implicitly resets the file read index to 0.
864
         *
865
         * If AT_FDCWD is specified as file descriptor gets an fd to the current cwd.
866
         *
867
         * If the specified file descriptor refers to a symlink via O_PATH, then this function cannot be used
868
         * to follow that symlink. Because we cannot have non-O_PATH fds to symlinks reopening it without
869
         * O_PATH will always result in -ELOOP. Or in other words: if you have an O_PATH fd to a symlink you
870
         * can reopen it only if you pass O_PATH again. */
871

872
        if (FLAGS_SET(flags, O_NOFOLLOW))
1,471,628✔
873
                /* O_NOFOLLOW is not allowed in fd_reopen(), because after all this is primarily implemented
874
                 * via a symlink-based interface in /proc/self/fd. Let's refuse this here early. Note that
875
                 * the kernel would generate ELOOP here too, hence this manual check is mostly redundant –
876
                 * the only reason we add it here is so that the O_DIRECTORY special case (see below) behaves
877
                 * the same way as the non-O_DIRECTORY case. */
878
                return -ELOOP;
1,471,628✔
879

880
        if (FLAGS_SET(flags, O_DIRECTORY) || fd == AT_FDCWD)
1,471,622✔
881
                /* If we shall reopen the fd as directory we can just go via "." and thus bypass the whole
882
                 * magic /proc/ directory, and make ourselves independent of that being mounted. */
883
                return RET_NERRNO(openat(fd, ".", flags | O_DIRECTORY));
247,760✔
884

885
        int new_fd = open(FORMAT_PROC_FD_PATH(fd), flags);
1,223,868✔
886
        if (new_fd < 0) {
1,223,868✔
887
                if (errno != ENOENT)
49,204✔
888
                        return -errno;
49,201✔
889

890
                return proc_fd_enoent_errno();
3✔
891
        }
892

893
        return new_fd;
894
}
895

896
int fd_reopen_propagate_append_and_position(int fd, int flags) {
28✔
897
        /* Invokes fd_reopen(fd, flags), but propagates O_APPEND if set on original fd, and also tries to
898
         * keep current file position.
899
         *
900
         * You should use this if the original fd potentially is O_APPEND, otherwise we get rather
901
         * "unexpected" behavior. Unless you intentionally want to overwrite pre-existing data, and have
902
         * your output overwritten by the next user.
903
         *
904
         * Use case: "systemd-run --pty >> some-log".
905
         *
906
         * The "keep position" part is obviously nonsense for the O_APPEND case, but should reduce surprises
907
         * if someone carefully pre-positioned the passed in original input or non-append output FDs. */
908

909
        assert(fd >= 0);
28✔
910
        assert(!(flags & (O_APPEND|O_DIRECTORY)));
28✔
911

912
        int existing_flags = fcntl(fd, F_GETFL);
28✔
913
        if (existing_flags < 0)
28✔
UNCOV
914
                return -errno;
×
915

916
        int new_fd = fd_reopen(fd, flags | (existing_flags & O_APPEND));
28✔
917
        if (new_fd < 0)
28✔
918
                return new_fd;
919

920
        /* Try to adjust the offset, but ignore errors. */
921
        off_t p = lseek(fd, 0, SEEK_CUR);
19✔
922
        if (p > 0) {
19✔
UNCOV
923
                off_t new_p = lseek(new_fd, p, SEEK_SET);
×
924
                if (new_p < 0)
×
925
                        log_debug_errno(errno,
×
926
                                        "Failed to propagate file position for re-opened fd %d, ignoring: %m",
927
                                        fd);
UNCOV
928
                else if (new_p != p)
×
929
                        log_debug("Failed to propagate file position for re-opened fd %d (%lld != %lld), ignoring.",
×
930
                                  fd, (long long) new_p, (long long) p);
931
        }
932

933
        return new_fd;
934
}
935

936
int fd_reopen_condition(
1,201,454✔
937
                int fd,
938
                int flags,
939
                int mask,
940
                int *ret_new_fd) {
941

942
        int r, new_fd;
1,201,454✔
943

944
        assert(fd >= 0);
1,201,454✔
945
        assert(!FLAGS_SET(flags, O_CREAT));
1,201,454✔
946

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

951
        r = fcntl(fd, F_GETFL);
1,201,454✔
952
        if (r < 0)
1,201,454✔
UNCOV
953
                return -errno;
×
954

955
        if ((r & mask) == (flags & mask)) {
1,201,454✔
956
                *ret_new_fd = -EBADF;
1,197,414✔
957
                return fd;
1,197,414✔
958
        }
959

960
        new_fd = fd_reopen(fd, flags);
4,040✔
961
        if (new_fd < 0)
4,040✔
962
                return new_fd;
963

964
        *ret_new_fd = new_fd;
4,040✔
965
        return new_fd;
4,040✔
966
}
967

968
int fd_is_opath(int fd) {
445,572✔
969
        int r;
445,572✔
970

971
        assert(fd >= 0);
445,572✔
972

973
        r = fcntl(fd, F_GETFL);
445,572✔
974
        if (r < 0)
445,572✔
UNCOV
975
                return -errno;
×
976

977
        return FLAGS_SET(r, O_PATH);
445,572✔
978
}
979

980
int fd_verify_safe_flags_full(int fd, int extra_flags) {
486✔
981
        int flags, unexpected_flags;
486✔
982

983
        /* Check if an extrinsic fd is safe to work on (by a privileged service). This ensures that clients
984
         * can't trick a privileged service into giving access to a file the client doesn't already have
985
         * access to (especially via something like O_PATH).
986
         *
987
         * O_NOFOLLOW: For some reason the kernel will return this flag from fcntl(); it doesn't go away
988
         *             immediately after open(). It should have no effect whatsoever to an already-opened FD,
989
         *             and since we refuse O_PATH it should be safe.
990
         *
991
         * RAW_O_LARGEFILE: glibc secretly sets this and neglects to hide it from us if we call fcntl.
992
         *                  See comment in missing_fcntl.h for more details about this.
993
         *
994
         * If 'extra_flags' is specified as non-zero the included flags are also allowed.
995
         */
996

997
        assert(fd >= 0);
486✔
998

999
        flags = fcntl(fd, F_GETFL);
486✔
1000
        if (flags < 0)
486✔
UNCOV
1001
                return -errno;
×
1002

1003
        unexpected_flags = flags & ~(O_ACCMODE_STRICT|O_NOFOLLOW|RAW_O_LARGEFILE|extra_flags);
486✔
1004
        if (unexpected_flags != 0)
486✔
UNCOV
1005
                return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
×
1006
                                       "Unexpected flags set for extrinsic fd: 0%o",
1007
                                       (unsigned) unexpected_flags);
1008

1009
        return flags & (O_ACCMODE_STRICT | extra_flags); /* return the flags variable, but remove the noise */
486✔
1010
}
1011

1012
int read_nr_open(void) {
29,333✔
1013
        _cleanup_free_ char *nr_open = NULL;
29,333✔
1014
        int r;
29,333✔
1015

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

1019
        r = read_one_line_file("/proc/sys/fs/nr_open", &nr_open);
29,333✔
1020
        if (r < 0)
29,333✔
1021
                log_debug_errno(r, "Failed to read /proc/sys/fs/nr_open, ignoring: %m");
29,333✔
1022
        else {
1023
                int v;
29,330✔
1024

1025
                r = safe_atoi(nr_open, &v);
29,330✔
1026
                if (r < 0)
29,330✔
UNCOV
1027
                        log_debug_errno(r, "Failed to parse /proc/sys/fs/nr_open value '%s', ignoring: %m", nr_open);
×
1028
                else
1029
                        return v;
29,330✔
1030
        }
1031

1032
        /* If we fail, fall back to the hard-coded kernel limit of 1024 * 1024. */
1033
        return 1024 * 1024;
1034
}
1035

1036
int fd_get_diskseq(int fd, uint64_t *ret) {
57,245✔
1037
        uint64_t diskseq;
57,245✔
1038

1039
        assert(fd >= 0);
57,245✔
1040
        assert(ret);
57,245✔
1041

1042
        if (ioctl(fd, BLKGETDISKSEQ, &diskseq) < 0) {
57,245✔
1043
                /* Note that the kernel is weird: non-existing ioctls currently return EINVAL
1044
                 * rather than ENOTTY on loopback block devices. They should fix that in the kernel,
1045
                 * but in the meantime we accept both here. */
UNCOV
1046
                if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL)
×
1047
                        return -errno;
×
1048

1049
                return -EOPNOTSUPP;
1050
        }
1051

1052
        *ret = diskseq;
57,245✔
1053

1054
        return 0;
57,245✔
1055
}
1056

1057
int path_is_root_at(int dir_fd, const char *path) {
3,315,968✔
1058
        _cleanup_close_ int fd = -EBADF, pfd = -EBADF;
3,315,968✔
1059

1060
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
3,315,968✔
1061

1062
        if (!isempty(path)) {
3,315,968✔
1063
                fd = openat(dir_fd, path, O_PATH|O_DIRECTORY|O_CLOEXEC);
100,452✔
1064
                if (fd < 0)
100,452✔
1065
                        return errno == ENOTDIR ? false : -errno;
14,603✔
1066

1067
                dir_fd = fd;
1068
        }
1069

1070
        pfd = openat(dir_fd, "..", O_PATH|O_DIRECTORY|O_CLOEXEC);
3,301,365✔
1071
        if (pfd < 0)
3,301,365✔
1072
                return errno == ENOTDIR ? false : -errno;
2✔
1073

1074
        /* Even if the parent directory has the same inode, the fd may not point to the root directory "/",
1075
         * and we also need to check that the mount ids are the same. Otherwise, a construct like the
1076
         * following could be used to trick us:
1077
         *
1078
         * $ mkdir /tmp/x /tmp/x/y
1079
         * $ mount --bind /tmp/x /tmp/x/y
1080
         */
1081

1082
        return fds_are_same_mount(dir_fd, pfd);
3,301,363✔
1083
}
1084

1085
int fds_are_same_mount(int fd1, int fd2) {
3,301,381✔
1086
        struct statx sx1 = {}, sx2 = {}; /* explicitly initialize the struct to make msan silent. */
3,301,381✔
1087
        int r;
3,301,381✔
1088

1089
        assert(fd1 >= 0);
3,301,381✔
1090
        assert(fd2 >= 0);
3,301,381✔
1091

1092
        if (statx(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx1) < 0)
3,301,381✔
UNCOV
1093
                return -errno;
×
1094

1095
        if (statx(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &sx2) < 0)
3,301,381✔
UNCOV
1096
                return -errno;
×
1097

1098
        /* First, compare inode. If these are different, the fd does not point to the root directory "/". */
1099
        if (!statx_inode_same(&sx1, &sx2))
3,301,381✔
1100
                return false;
1101

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

1106
        if (!FLAGS_SET(sx1.stx_mask, STATX_MNT_ID)) {
3,047,679✔
UNCOV
1107
                int mntid;
×
1108

UNCOV
1109
                r = path_get_mnt_id_at_fallback(fd1, "", &mntid);
×
1110
                if (r < 0)
×
1111
                        return r;
×
1112
                assert(mntid >= 0);
×
1113

UNCOV
1114
                sx1.stx_mnt_id = mntid;
×
1115
                sx1.stx_mask |= STATX_MNT_ID;
×
1116
        }
1117

1118
        if (!FLAGS_SET(sx2.stx_mask, STATX_MNT_ID)) {
3,047,679✔
UNCOV
1119
                int mntid;
×
1120

UNCOV
1121
                r = path_get_mnt_id_at_fallback(fd2, "", &mntid);
×
1122
                if (r < 0)
×
1123
                        return r;
×
1124
                assert(mntid >= 0);
×
1125

UNCOV
1126
                sx2.stx_mnt_id = mntid;
×
1127
                sx2.stx_mask |= STATX_MNT_ID;
×
1128
        }
1129

1130
        return statx_mount_same(&sx1, &sx2);
3,047,679✔
1131
}
1132

1133
char* format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int fd) {
3,292,166✔
1134
        assert(buf);
3,292,166✔
1135
        assert(fd >= 0);
3,292,166✔
1136
        assert_se(snprintf_ok(buf, PROC_FD_PATH_MAX, "/proc/self/fd/%i", fd));
3,292,166✔
1137
        return buf;
3,292,166✔
1138
}
1139

1140
const char* accmode_to_string(int flags) {
176✔
1141
        switch (flags & O_ACCMODE_STRICT) {
176✔
1142
        case O_RDONLY:
1143
                return "ro";
1144
        case O_WRONLY:
3✔
1145
                return "wo";
3✔
1146
        case O_RDWR:
170✔
1147
                return "rw";
170✔
UNCOV
1148
        default:
×
UNCOV
1149
                return NULL;
×
1150
        }
1151
}
1152

1153
char* format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid, int fd) {
1✔
1154
        assert(buf);
1✔
1155
        assert(fd >= 0);
1✔
1156
        assert(pid >= 0);
1✔
1157
        assert_se(snprintf_ok(buf, PROC_PID_FD_PATH_MAX, "/proc/" PID_FMT "/fd/%i", pid == 0 ? getpid_cached() : pid, fd));
1✔
1158
        return buf;
1✔
1159
}
1160

1161
int proc_fd_enoent_errno(void) {
7✔
1162
        int r;
7✔
1163

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

1168
        r = proc_mounted();
7✔
1169
        if (r == 0)
7✔
1170
                return -ENOSYS;  /* /proc/ is not available or not set up properly, we're most likely
1171
                                    in some chroot environment. */
1172
        if (r > 0)
7✔
1173
                return -EBADF;   /* If /proc/ is definitely around then this means the fd is not valid. */
7✔
1174

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