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

systemd / systemd / 12940458095

23 Jan 2025 10:34PM UTC coverage: 71.463% (+0.02%) from 71.444%
12940458095

push

github

web-flow
nspawn: support unpriv directory-tree containers (#35685)

So far nspawn supported unpriv containers only if backed by a DDI. This
adds dir-based unpriv containers too.

To make this work this introduces a new UID concept to systemd: the
"foreign UID range". This is a high UID range of size 64K. The idea is
that disk images that are "foreign" to the local system can use that,
and when a container or similar is invoked from it, a transiently
allocated dynamic UID range is mapped from that foreign UID range via id
mapped mounts.

This means the fully dynamic, transient UID ranges never hit the disk,
which should vastly simplify management, and does not require that uid
"subranges" are persistently delegated to any users.

The mountfsd daemon gained a new method call for acquiring an idmapped
mount fd for an mount tree owned by the foreign UID range. Access is
permitted to unpriv clients – as long as the referenced inode is located
within a dir owned by client's own uid range.

166 of 349 new or added lines in 6 files covered. (47.56%)

2432 existing lines in 65 files now uncovered.

291664 of 408131 relevant lines covered (71.46%)

709262.54 hits per line

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

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

3
#include <ctype.h>
4
#include <errno.h>
5
#include <fcntl.h>
6
#include <limits.h>
7
#include <stdarg.h>
8
#include <stdint.h>
9
#include <stdio_ext.h>
10
#include <stdlib.h>
11
#include <sys/stat.h>
12
#include <sys/types.h>
13
#include <unistd.h>
14

15
#include "alloc-util.h"
16
#include "chase.h"
17
#include "extract-word.h"
18
#include "fd-util.h"
19
#include "fileio.h"
20
#include "fs-util.h"
21
#include "hexdecoct.h"
22
#include "label.h"
23
#include "log.h"
24
#include "macro.h"
25
#include "mkdir.h"
26
#include "nulstr-util.h"
27
#include "parse-util.h"
28
#include "path-util.h"
29
#include "socket-util.h"
30
#include "stdio-util.h"
31
#include "string-util.h"
32
#include "sync-util.h"
33
#include "terminal-util.h"
34
#include "tmpfile-util.h"
35

36
/* The maximum size of the file we'll read in one go in read_full_file() (64M). */
37
#define READ_FULL_BYTES_MAX (64U * U64_MB - UINT64_C(1))
38
/* Used when a size is specified for read_full_file() with READ_FULL_FILE_UNBASE64 or _UNHEX */
39
#define READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY 3
40

41
/* The maximum size of virtual files (i.e. procfs, sysfs, and other virtual "API" files) we'll read in one go
42
 * in read_virtual_file(). Note that this limit is different (and much lower) than the READ_FULL_BYTES_MAX
43
 * limit. This reflects the fact that we use different strategies for reading virtual and regular files:
44
 * virtual files we generally have to read in a single read() syscall since the kernel doesn't support
45
 * continuation read()s for them. Thankfully they are somewhat size constrained. Thus we can allocate the
46
 * full potential buffer in advance. Regular files OTOH can be much larger, and there we grow the allocations
47
 * exponentially in a loop. We use a size limit of 4M-2 because 4M-1 is the maximum buffer that /proc/sys/
48
 * allows us to read() (larger reads will fail with ENOMEM), and we want to read one extra byte so that we
49
 * can detect EOFs. */
50
#define READ_VIRTUAL_BYTES_MAX (4U * U64_MB - UINT64_C(2))
51

52
int fdopen_unlocked(int fd, const char *options, FILE **ret) {
407,350✔
53
        assert(ret);
407,350✔
54

55
        FILE *f = fdopen(fd, options);
407,350✔
56
        if (!f)
407,350✔
57
                return -errno;
×
58

59
        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
407,350✔
60

61
        *ret = f;
407,350✔
62
        return 0;
407,350✔
63
}
64

65
int take_fdopen_unlocked(int *fd, const char *options, FILE **ret) {
407,350✔
66
        int r;
407,350✔
67

68
        assert(fd);
407,350✔
69

70
        r = fdopen_unlocked(*fd, options, ret);
407,350✔
71
        if (r < 0)
407,350✔
72
                return r;
73

74
        *fd = -EBADF;
407,350✔
75

76
        return 0;
407,350✔
77
}
78

79
FILE* take_fdopen(int *fd, const char *options) {
40,482✔
80
        assert(fd);
40,482✔
81

82
        FILE *f = fdopen(*fd, options);
40,482✔
83
        if (!f)
40,482✔
84
                return NULL;
85

86
        *fd = -EBADF;
40,482✔
87

88
        return f;
40,482✔
89
}
90

91
DIR* take_fdopendir(int *dfd) {
241,066✔
92
        assert(dfd);
241,066✔
93

94
        DIR *d = fdopendir(*dfd);
241,066✔
95
        if (!d)
241,066✔
96
                return NULL;
97

98
        *dfd = -EBADF;
241,066✔
99

100
        return d;
241,066✔
101
}
102

103
FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) {
510,596✔
104
        FILE *f = open_memstream(ptr, sizeloc);
510,596✔
105
        if (!f)
510,596✔
106
                return NULL;
107

108
        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
510,596✔
109

110
        return f;
510,596✔
111
}
112

113
FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode) {
103✔
114
        FILE *f = fmemopen(buf, size, mode);
103✔
115
        if (!f)
103✔
116
                return NULL;
117

118
        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
103✔
119

120
        return f;
103✔
121
}
122

123
int write_string_stream_full(
203,906✔
124
                FILE *f,
125
                const char *line,
126
                WriteStringFileFlags flags,
127
                const struct timespec *ts) {
128

129
        bool needs_nl;
203,906✔
130
        int r, fd = -EBADF;
203,906✔
131

132
        assert(f);
203,906✔
133
        assert(line);
203,906✔
134

135
        if (ferror(f))
203,906✔
136
                return -EIO;
137

138
        if (ts) {
203,906✔
139
                /* If we shall set the timestamp we need the fd. But fmemopen() streams generally don't have
140
                 * an fd. Let's fail early in that case. */
141
                fd = fileno(f);
200✔
142
                if (fd < 0)
200✔
143
                        return -EBADF;
144
        }
145

146
        if (flags & WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) {
203,906✔
147
                _cleanup_free_ char *t = NULL;
9,172✔
148

149
                /* If value to be written is same as that of the existing value, then suppress the write. */
150

151
                if (fd < 0) {
9,172✔
152
                        fd = fileno(f);
9,172✔
153
                        if (fd < 0)
9,172✔
154
                                return -EBADF;
155
                }
156

157
                /* Read an additional byte to detect cases where the prefix matches but the rest
158
                 * doesn't. Also, 0 returned by read_virtual_file_fd() means the read was truncated and
159
                 * it won't be equal to the new value. */
160
                if (read_virtual_file_fd(fd, strlen(line)+1, &t, NULL) > 0 &&
18,298✔
161
                    streq_skip_trailing_chars(line, t, NEWLINE)) {
9,126✔
162
                        log_debug("No change in value '%s', suppressing write", line);
6,657✔
163
                        return 0;
6,657✔
164
                }
165

166
                if (lseek(fd, 0, SEEK_SET) < 0)
2,515✔
167
                        return -errno;
×
168
        }
169

170
        needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
197,249✔
171

172
        if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) {
46,918✔
173
                /* If STDIO buffering was disabled, then let's append the newline character to the string
174
                 * itself, so that the write goes out in one go, instead of two */
175

176
                line = strjoina(line, "\n");
228,510✔
177
                needs_nl = false;
45,702✔
178
        }
179

180
        if (fputs(line, f) == EOF)
197,249✔
181
                return -errno;
74✔
182

183
        if (needs_nl)
197,175✔
184
                if (fputc('\n', f) == EOF)
1,215✔
185
                        return -errno;
×
186

187
        if (flags & WRITE_STRING_FILE_SYNC)
197,175✔
188
                r = fflush_sync_and_check(f);
1,676✔
189
        else
190
                r = fflush_and_check(f);
195,499✔
191
        if (r < 0)
197,175✔
192
                return r;
193

194
        if (ts) {
197,163✔
195
                const struct timespec twice[2] = {*ts, *ts};
200✔
196

197
                assert(fd >= 0);
200✔
198
                if (futimens(fd, twice) < 0)
200✔
199
                        return -errno;
×
200
        }
201

202
        return 0;
203
}
204

205
static mode_t write_string_file_flags_to_mode(WriteStringFileFlags flags) {
90,520✔
206

207
        /* We support three different modes, that are the ones that really make sense for text files like this:
208
         *
209
         *     → 0600 (i.e. root-only)
210
         *     → 0444 (i.e. read-only)
211
         *     → 0644 (i.e. writable for root, readable for everyone else)
212
         */
213

214
        return FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 :
90,520✔
215
                FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0444) ? 0444 : 0644;
90,442✔
216
}
217

218
static int write_string_file_atomic_at(
2,279✔
219
                int dir_fd,
220
                const char *fn,
221
                const char *line,
222
                WriteStringFileFlags flags,
223
                const struct timespec *ts) {
224

225
        _cleanup_fclose_ FILE *f = NULL;
2,279✔
226
        _cleanup_free_ char *p = NULL;
2,279✔
227
        int r;
2,279✔
228

229
        assert(fn);
2,279✔
230
        assert(line);
2,279✔
231

232
        /* Note that we'd really like to use O_TMPFILE here, but can't really, since we want replacement
233
         * semantics here, and O_TMPFILE can't offer that. i.e. rename() replaces but linkat() doesn't. */
234

235
        mode_t mode = write_string_file_flags_to_mode(flags);
2,279✔
236

237
        bool call_label_ops_post = false;
2,279✔
238
        if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL)) {
2,279✔
239
                r = label_ops_pre(dir_fd, fn, mode);
355✔
240
                if (r < 0)
355✔
241
                        return r;
242

243
                call_label_ops_post = true;
244
        }
245

246
        r = fopen_temporary_at(dir_fd, fn, &f, &p);
2,279✔
247
        if (r < 0)
2,279✔
248
                goto fail;
1✔
249

250
        if (call_label_ops_post) {
2,278✔
251
                call_label_ops_post = false;
355✔
252

253
                r = label_ops_post(fileno(f), /* path= */ NULL, /* created= */ true);
355✔
254
                if (r < 0)
355✔
255
                        goto fail;
×
256
        }
257

258
        r = write_string_stream_full(f, line, flags, ts);
2,278✔
259
        if (r < 0)
2,278✔
260
                goto fail;
×
261

262
        r = fchmod_umask(fileno(f), mode);
2,278✔
263
        if (r < 0)
2,278✔
264
                goto fail;
×
265

266
        r = RET_NERRNO(renameat(dir_fd, p, dir_fd, fn));
2,278✔
267
        if (r < 0)
×
268
                goto fail;
×
269

270
        if (FLAGS_SET(flags, WRITE_STRING_FILE_SYNC)) {
2,278✔
271
                /* Sync the rename, too */
272
                r = fsync_directory_of_file(fileno(f));
1,676✔
273
                if (r < 0)
1,676✔
274
                        return r;
×
275
        }
276

277
        return 0;
278

279
fail:
1✔
280
        if (call_label_ops_post)
1✔
281
                (void) label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f);
×
282

283
        if (f)
1✔
284
                (void) unlinkat(dir_fd, p, 0);
×
285
        return r;
286
}
287

288
int write_string_file_full(
178,709✔
289
                int dir_fd,
290
                const char *fn,
291
                const char *line,
292
                WriteStringFileFlags flags,
293
                const struct timespec *ts,
294
                const char *label_fn) {
295

296
        bool call_label_ops_post = false, made_file = false;
178,709✔
297
        _cleanup_fclose_ FILE *f = NULL;
178,709✔
298
        _cleanup_close_ int fd = -EBADF;
178,709✔
299
        int r;
178,709✔
300

301
        assert(dir_fd == AT_FDCWD || dir_fd >= 0);
178,709✔
302
        assert(line);
178,709✔
303

304
        /* We don't know how to verify whether the file contents was already on-disk. */
305
        assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
178,709✔
306

307
        if (flags & WRITE_STRING_FILE_MKDIR_0755) {
178,709✔
308
                assert(fn);
248✔
309

310
                r = mkdirat_parents(dir_fd, fn, 0755);
248✔
311
                if (r < 0)
248✔
312
                        return r;
313
        }
314

315
        if (flags & WRITE_STRING_FILE_ATOMIC) {
178,709✔
316
                assert(fn);
2,279✔
317
                assert(flags & WRITE_STRING_FILE_CREATE);
2,279✔
318

319
                r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts);
2,279✔
320
                if (r < 0)
2,279✔
321
                        goto fail;
1✔
322

323
                return r;
324
        }
325

326
        /* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
327
        if (isempty(fn))
176,430✔
328
                fd = fd_reopen(ASSERT_FD(dir_fd), O_CLOEXEC | O_NOCTTY |
88,189✔
329
                               (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
88,189✔
330
                               (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY));
88,189✔
331
        else {
332
                mode_t mode = write_string_file_flags_to_mode(flags);
88,241✔
333

334
                if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) {
88,241✔
335
                        r = label_ops_pre(dir_fd, label_fn ?: fn, mode);
292✔
336
                        if (r < 0)
292✔
UNCOV
337
                                goto fail;
×
338

339
                        call_label_ops_post = true;
340
                }
341

342
                fd = openat_report_new(
88,241✔
343
                                dir_fd, fn, O_CLOEXEC | O_NOCTTY |
88,241✔
344
                                (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
88,241✔
345
                                (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
88,241✔
346
                                (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
88,241✔
347
                                (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY),
88,241✔
348
                                mode,
349
                                &made_file);
350
        }
351
        if (fd < 0) {
176,430✔
352
                r = fd;
1,594✔
353
                goto fail;
1,594✔
354
        }
355

356
        if (call_label_ops_post) {
174,836✔
357
                call_label_ops_post = false;
292✔
358

359
                r = label_ops_post(fd, /* path= */ NULL, made_file);
292✔
360
                if (r < 0)
292✔
UNCOV
361
                        goto fail;
×
362
        }
363

364
        r = take_fdopen_unlocked(&fd, "w", &f);
174,836✔
365
        if (r < 0)
174,836✔
UNCOV
366
                goto fail;
×
367

368
        if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
174,836✔
369
                setvbuf(f, NULL, _IONBF, 0);
173,784✔
370

371
        r = write_string_stream_full(f, line, flags, ts);
174,836✔
372
        if (r < 0)
174,836✔
373
                goto fail;
79✔
374

375
        return 0;
376

377
fail:
1,673✔
378
        if (call_label_ops_post)
1,674✔
UNCOV
379
                (void) label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, made_file);
×
380

381
        if (made_file)
1,674✔
UNCOV
382
                (void) unlinkat(dir_fd, fn, 0);
×
383

384
        if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
1,674✔
385
                return r;
386

387
        f = safe_fclose(f);
1,644✔
388
        fd = safe_close(fd);
1,644✔
389

390
        /* OK, the operation failed, but let's see if the right contents in place already. If so, eat up the
391
         * error. */
392
        if (verify_file_at(dir_fd, fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) || (flags & WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE)) > 0)
1,644✔
393
                return 0;
446✔
394

395
        return r;
396
}
397

398
int write_string_filef(
274✔
399
                const char *fn,
400
                WriteStringFileFlags flags,
401
                const char *format, ...) {
402

403
        _cleanup_free_ char *p = NULL;
274✔
404
        va_list ap;
274✔
405
        int r;
274✔
406

407
        va_start(ap, format);
274✔
408
        r = vasprintf(&p, format, ap);
274✔
409
        va_end(ap);
274✔
410

411
        if (r < 0)
274✔
412
                return -ENOMEM;
413

414
        return write_string_file(fn, p, flags);
274✔
415
}
416

417
int write_base64_file_at(
7✔
418
                int dir_fd,
419
                const char *fn,
420
                const struct iovec *data,
421
                WriteStringFileFlags flags) {
422

423
        _cleanup_free_ char *encoded = NULL;
7✔
424
        ssize_t n;
7✔
425

426
        n = base64mem_full(data ? data->iov_base : NULL, data ? data->iov_len : 0, 79, &encoded);
7✔
427
        if (n < 0)
7✔
UNCOV
428
                return n;
×
429

430
        return write_string_file_at(dir_fd, fn, encoded, flags);
7✔
431
}
432

433
int read_one_line_file_at(int dir_fd, const char *filename, char **ret) {
185,856✔
434
        _cleanup_fclose_ FILE *f = NULL;
185,856✔
435
        int r;
185,856✔
436

437
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
185,856✔
438
        assert(filename);
185,856✔
439
        assert(ret);
185,856✔
440

441
        r = fopen_unlocked_at(dir_fd, filename, "re", 0, &f);
185,856✔
442
        if (r < 0)
185,856✔
443
                return r;
444

445
        return read_line(f, LONG_LINE_MAX, ret);
185,856✔
446
}
447

448
int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl) {
1,644✔
449
        _cleanup_fclose_ FILE *f = NULL;
1,644✔
450
        _cleanup_free_ char *buf = NULL;
1,644✔
451
        size_t l, k;
1,644✔
452
        int r;
1,644✔
453

454
        assert(blob);
1,644✔
455

456
        l = strlen(blob);
1,644✔
457

458
        if (accept_extra_nl && endswith(blob, "\n"))
1,644✔
459
                accept_extra_nl = false;
1✔
460

461
        buf = malloc(l + accept_extra_nl + 1);
1,644✔
462
        if (!buf)
1,644✔
463
                return -ENOMEM;
464

465
        r = fopen_unlocked_at(dir_fd, strempty(fn), "re", 0, &f);
1,644✔
466
        if (r < 0)
1,644✔
467
                return r;
468

469
        /* We try to read one byte more than we need, so that we know whether we hit eof */
470
        errno = 0;
903✔
471
        k = fread(buf, 1, l + accept_extra_nl + 1, f);
903✔
472
        if (ferror(f))
903✔
UNCOV
473
                return errno_or_else(EIO);
×
474

475
        if (k != l && k != l + accept_extra_nl)
903✔
476
                return 0;
477
        if (memcmp(buf, blob, l) != 0)
717✔
478
                return 0;
479
        if (k > l && buf[l] != '\n')
446✔
UNCOV
480
                return 0;
×
481

482
        return 1;
483
}
484

485
int read_virtual_file_at(
1,007,038✔
486
                int dir_fd,
487
                const char *filename,
488
                size_t max_size,
489
                char **ret_contents,
490
                size_t *ret_size) {
491

492
        _cleanup_free_ char *buf = NULL;
1,007,038✔
493
        size_t n, size;
1,007,038✔
494
        int n_retries;
1,007,038✔
495
        bool truncated = false;
1,007,038✔
496

497
        /* Virtual filesystems such as sysfs or procfs use kernfs, and kernfs can work with two sorts of
498
         * virtual files. One sort uses "seq_file", and the results of the first read are buffered for the
499
         * second read. The other sort uses "raw" reads which always go direct to the device. In the latter
500
         * case, the content of the virtual file must be retrieved with a single read otherwise a second read
501
         * might get the new value instead of finding EOF immediately. That's the reason why the usage of
502
         * fread(3) is prohibited in this case as it always performs a second call to read(2) looking for
503
         * EOF. See issue #13585.
504
         *
505
         * max_size specifies a limit on the bytes read. If max_size is SIZE_MAX, the full file is read. If
506
         * the full file is too large to read, an error is returned. For other values of max_size, *partial
507
         * contents* may be returned. (Though the read is still done using one syscall.) Returns 0 on
508
         * partial success, 1 if untruncated contents were read. */
509

510
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
1,007,038✔
511
        assert(max_size <= READ_VIRTUAL_BYTES_MAX || max_size == SIZE_MAX);
1,007,038✔
512

513
        _cleanup_close_ int fd = -EBADF;
1,007,038✔
514
        if (isempty(filename))
1,007,038✔
515
                fd = fd_reopen(ASSERT_FD(dir_fd), O_RDONLY | O_NOCTTY | O_CLOEXEC);
763,287✔
516
        else
517
                fd = RET_NERRNO(openat(dir_fd, filename, O_RDONLY | O_NOCTTY | O_CLOEXEC));
243,751✔
518
        if (fd < 0)
1,007,038✔
519
                return fd;
520

521
        /* Limit the number of attempts to read the number of bytes returned by fstat(). */
522
        n_retries = 3;
523

524
        for (;;) {
903,371✔
525
                struct stat st;
903,370✔
526

527
                if (fstat(fd, &st) < 0)
903,370✔
528
                        return -errno;
1,083✔
529

530
                if (!S_ISREG(st.st_mode))
903,370✔
531
                        return -EBADF;
532

533
                /* Be prepared for files from /proc which generally report a file size of 0. */
534
                assert_cc(READ_VIRTUAL_BYTES_MAX < SSIZE_MAX);
903,370✔
535
                if (st.st_size > 0 && n_retries > 1) {
903,370✔
536
                        /* Let's use the file size if we have more than 1 attempt left. On the last attempt
537
                         * we'll ignore the file size */
538

539
                        if (st.st_size > SSIZE_MAX) { /* Avoid overflow with 32-bit size_t and 64-bit off_t. */
662,452✔
540

541
                                if (max_size == SIZE_MAX)
542
                                        return -EFBIG;
543

544
                                size = max_size;
545
                        } else {
546
                                size = MIN((size_t) st.st_size, max_size);
662,452✔
547

548
                                if (size > READ_VIRTUAL_BYTES_MAX)
662,452✔
549
                                        return -EFBIG;
550
                        }
551

552
                        n_retries--;
662,452✔
553
                } else if (n_retries > 1) {
240,918✔
554
                        /* Files in /proc are generally smaller than the page size so let's start with
555
                         * a page size buffer from malloc and only use the max buffer on the final try. */
556
                        size = MIN3(page_size() - 1, READ_VIRTUAL_BYTES_MAX, max_size);
240,917✔
557
                        n_retries = 1;
240,917✔
558
                } else {
559
                        size = MIN(READ_VIRTUAL_BYTES_MAX, max_size);
1✔
560
                        n_retries = 0;
1✔
561
                }
562

563
                buf = malloc(size + 1);
903,370✔
564
                if (!buf)
903,370✔
565
                        return -ENOMEM;
566

567
                /* Use a bigger allocation if we got it anyway, but not more than the limit. */
568
                size = MIN3(MALLOC_SIZEOF_SAFE(buf) - 1, max_size, READ_VIRTUAL_BYTES_MAX);
903,370✔
569

570
                for (;;) {
903,370✔
571
                        ssize_t k;
903,370✔
572

573
                        /* Read one more byte so we can detect whether the content of the
574
                         * file has already changed or the guessed size for files from /proc
575
                         * wasn't large enough . */
576
                        k = read(fd, buf, size + 1);
903,370✔
577
                        if (k >= 0) {
903,370✔
578
                                n = k;
902,287✔
579
                                break;
902,287✔
580
                        }
581

582
                        if (errno != EINTR)
1,083✔
583
                                return -errno;
1,083✔
584
                }
585

586
                /* Consider a short read as EOF */
587
                if (n <= size)
902,287✔
588
                        break;
589

590
                /* If a maximum size is specified and we already read more we know the file is larger, and
591
                 * can handle this as truncation case. Note that if the size of what we read equals the
592
                 * maximum size then this doesn't mean truncation, the file might or might not end on that
593
                 * byte. We need to rerun the loop in that case, with a larger buffer size, so that we read
594
                 * at least one more byte to be able to distinguish EOF from truncation. */
595
                if (max_size != SIZE_MAX && n > max_size) {
41,160✔
596
                        n = size; /* Make sure we never use more than what we sized the buffer for (so that
597
                                   * we have one free byte in it for the trailing NUL we add below). */
598
                        truncated = true;
599
                        break;
600
                }
601

602
                /* We have no further attempts left? Then the file is apparently larger than our limits. Give up. */
603
                if (n_retries <= 0)
1✔
604
                        return -EFBIG;
605

606
                /* Hmm... either we read too few bytes from /proc or less likely the content of the file
607
                 * might have been changed (and is now bigger) while we were processing, let's try again
608
                 * either with the new file size. */
609

610
                if (lseek(fd, 0, SEEK_SET) < 0)
1✔
UNCOV
611
                        return -errno;
×
612

613
                buf = mfree(buf);
1✔
614
        }
615

616
        if (ret_contents) {
902,286✔
617

618
                /* Safety check: if the caller doesn't want to know the size of what we just read it will
619
                 * rely on the trailing NUL byte. But if there's an embedded NUL byte, then we should refuse
620
                 * operation as otherwise there'd be ambiguity about what we just read. */
621
                if (!ret_size && memchr(buf, 0, n))
861,228✔
622
                        return -EBADMSG;
623

624
                if (n < size) {
861,228✔
625
                        char *p;
852,810✔
626

627
                        /* Return rest of the buffer to libc */
628
                        p = realloc(buf, n + 1);
852,810✔
629
                        if (!p)
852,810✔
630
                                return -ENOMEM;
631
                        buf = p;
852,810✔
632
                }
633

634
                buf[n] = 0;
861,228✔
635
                *ret_contents = TAKE_PTR(buf);
861,228✔
636
        }
637

638
        if (ret_size)
902,286✔
639
                *ret_size = n;
675,299✔
640

641
        return !truncated;
902,286✔
642
}
643

644
int read_full_stream_full(
443,129✔
645
                FILE *f,
646
                const char *filename,
647
                uint64_t offset,
648
                size_t size,
649
                ReadFullFileFlags flags,
650
                char **ret_contents,
651
                size_t *ret_size) {
652

653
        _cleanup_free_ char *buf = NULL;
443,129✔
654
        size_t n, n_next = 0, l, expected_decoded_size = size;
443,129✔
655
        int fd, r;
443,129✔
656

657
        assert(f);
443,129✔
658
        assert(ret_contents);
443,129✔
659
        assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
443,129✔
660
        assert(size != SIZE_MAX || !FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER));
443,129✔
661

662
        if (offset != UINT64_MAX && offset > LONG_MAX) /* fseek() can only deal with "long" offsets */
443,129✔
663
                return -ERANGE;
664

665
        if ((flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) != 0) {
443,129✔
666
                if (size <= SIZE_MAX / READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY)
35✔
667
                        size *= READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY;
33✔
668
                else
669
                        size = SIZE_MAX;
670
        }
671

672
        fd = fileno(f);
443,129✔
673
        if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see
443,129✔
674
                        * fmemopen()), let's optimize our buffering */
675
                struct stat st;
443,039✔
676

677
                if (fstat(fd, &st) < 0)
443,039✔
UNCOV
678
                        return -errno;
×
679

680
                if (S_ISREG(st.st_mode)) {
443,039✔
681

682
                        /* Try to start with the right file size if we shall read the file in full. Note
683
                         * that we increase the size to read here by one, so that the first read attempt
684
                         * already makes us notice the EOF. If the reported size of the file is zero, we
685
                         * avoid this logic however, since quite likely it might be a virtual file in procfs
686
                         * that all report a zero file size. */
687

688
                        if (st.st_size > 0 &&
442,659✔
689
                            (size == SIZE_MAX || FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER))) {
1,194✔
690

691
                                uint64_t rsize =
1,236,810✔
692
                                        LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset);
824,534✔
693

694
                                if (rsize < SIZE_MAX) /* overflow check */
412,270✔
695
                                        n_next = rsize + 1;
412,270✔
696
                        }
697

698
                        if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
442,659✔
699
                                (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
124✔
700
                }
701
        }
702

703
        /* If we don't know how much to read, figure it out now. If we shall read a part of the file, then
704
         * allocate the requested size. If we shall load the full file start with LINE_MAX. Note that if
705
         * READ_FULL_FILE_FAIL_WHEN_LARGER we consider the specified size a safety limit, and thus also start
706
         * with LINE_MAX, under assumption the file is most likely much shorter. */
707
        if (n_next == 0)
443,039✔
708
                n_next = size != SIZE_MAX && !FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) ? size : LINE_MAX;
30,859✔
709

710
        /* Never read more than we need to determine that our own limit is hit */
711
        if (n_next > READ_FULL_BYTES_MAX)
412,616✔
UNCOV
712
                n_next = READ_FULL_BYTES_MAX + 1;
×
713

714
        if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0)
443,129✔
715
                return -errno;
×
716

717
        n = l = 0;
718
        for (;;) {
443,355✔
719
                char *t;
443,242✔
720
                size_t k;
443,242✔
721

722
                /* If we shall fail when reading overly large data, then read exactly one byte more than the
723
                 * specified size at max, since that'll tell us if there's anymore data beyond the limit*/
724
                if (FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) && n_next > size)
443,242✔
725
                        n_next = size + 1;
8✔
726

727
                if (flags & READ_FULL_FILE_SECURE) {
443,242✔
728
                        t = malloc(n_next + 1);
1,385✔
729
                        if (!t) {
1,385✔
UNCOV
730
                                r = -ENOMEM;
×
UNCOV
731
                                goto finalize;
×
732
                        }
733
                        memcpy_safe(t, buf, n);
1,385✔
734
                        explicit_bzero_safe(buf, n);
1,385✔
735
                        free(buf);
1,385✔
736
                } else {
737
                        t = realloc(buf, n_next + 1);
441,857✔
738
                        if (!t)
441,857✔
739
                                return -ENOMEM;
740
                }
741

742
                buf = t;
443,242✔
743
                /* Unless a size has been explicitly specified, try to read as much as fits into the memory
744
                 * we allocated (minus 1, to leave one byte for the safety NUL byte) */
745
                n = size == SIZE_MAX ? MALLOC_SIZEOF_SAFE(buf) - 1 : n_next;
443,242✔
746

747
                errno = 0;
443,242✔
748
                k = fread(buf + l, 1, n - l, f);
443,242✔
749

750
                assert(k <= n - l);
443,242✔
751
                l += k;
443,242✔
752

753
                if (ferror(f)) {
443,242✔
754
                        r = errno_or_else(EIO);
2✔
755
                        goto finalize;
2✔
756
                }
757
                if (feof(f))
443,240✔
758
                        break;
759

760
                if (size != SIZE_MAX && !FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER)) { /* If we got asked to read some specific size, we already sized the buffer right, hence leave */
263✔
761
                        assert(l == size);
144✔
762
                        break;
763
                }
764

765
                assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
119✔
766

767
                if (FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) && l > size) {
119✔
768
                        r = -E2BIG;
6✔
769
                        goto finalize;
6✔
770
                }
771

772
                if (n >= READ_FULL_BYTES_MAX) {
113✔
UNCOV
773
                        r = -E2BIG;
×
UNCOV
774
                        goto finalize;
×
775
                }
776

777
                n_next = MIN(n * 2, READ_FULL_BYTES_MAX);
113✔
778
        }
779

780
        if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) {
443,121✔
781
                _cleanup_free_ void *decoded = NULL;
33✔
782
                size_t decoded_size;
33✔
783

784
                buf[l++] = 0;
33✔
785
                if (flags & READ_FULL_FILE_UNBASE64)
33✔
786
                        r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
31✔
787
                else
788
                        r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
2✔
789
                if (r < 0)
33✔
UNCOV
790
                        goto finalize;
×
791

792
                if (flags & READ_FULL_FILE_SECURE)
33✔
793
                        explicit_bzero_safe(buf, n);
14✔
794
                free_and_replace(buf, decoded);
33✔
795
                n = l = decoded_size;
33✔
796

797
                if (FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) && l > expected_decoded_size) {
33✔
UNCOV
798
                        r = -E2BIG;
×
UNCOV
799
                        goto finalize;
×
800
                }
801
        }
802

803
        if (!ret_size) {
443,121✔
804
                /* Safety check: if the caller doesn't want to know the size of what we just read it will rely on the
805
                 * trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise
806
                 * there'd be ambiguity about what we just read. */
807

808
                if (memchr(buf, 0, l)) {
323,112✔
809
                        r = -EBADMSG;
2✔
810
                        goto finalize;
2✔
811
                }
812
        }
813

814
        buf[l] = 0;
443,119✔
815
        *ret_contents = TAKE_PTR(buf);
443,119✔
816

817
        if (ret_size)
443,119✔
818
                *ret_size = l;
120,009✔
819

820
        return 0;
821

822
finalize:
10✔
823
        if (flags & READ_FULL_FILE_SECURE)
10✔
824
                explicit_bzero_safe(buf, n);
3✔
825

826
        return r;
827
}
828

829
int read_full_file_full(
703,536✔
830
                int dir_fd,
831
                const char *filename,
832
                uint64_t offset,
833
                size_t size,
834
                ReadFullFileFlags flags,
835
                const char *bind_name,
836
                char **ret_contents,
837
                size_t *ret_size) {
838

839
        _cleanup_fclose_ FILE *f = NULL;
703,536✔
840
        XfopenFlags xflags = XFOPEN_UNLOCKED;
703,536✔
841
        int r;
703,536✔
842

843
        assert(filename);
703,536✔
844
        assert(ret_contents);
703,536✔
845

846
        if (FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET) && /* If this is enabled, let's try to connect to it */
703,536✔
847
            offset == UINT64_MAX)                              /* Seeking is not supported on AF_UNIX sockets */
848
                xflags |= XFOPEN_SOCKET;
162✔
849

850
        r = xfopenat_full(dir_fd, filename, "re", 0, xflags, bind_name, &f);
703,536✔
851
        if (r < 0)
703,536✔
852
                return r;
853

854
        return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
429,911✔
855
}
856

857
int script_get_shebang_interpreter(const char *path, char **ret) {
8✔
858
        _cleanup_fclose_ FILE *f = NULL;
8✔
859
        int r;
8✔
860

861
        assert(path);
8✔
862

863
        f = fopen(path, "re");
8✔
864
        if (!f)
8✔
865
                return -errno;
1✔
866

867
        char c;
7✔
868
        r = safe_fgetc(f, &c);
7✔
869
        if (r < 0)
7✔
870
                return r;
871
        if (r == 0)
7✔
872
                return -EBADMSG;
873
        if (c != '#')
7✔
874
                return -EMEDIUMTYPE;
875
        r = safe_fgetc(f, &c);
2✔
876
        if (r < 0)
2✔
877
                return r;
878
        if (r == 0)
2✔
879
                return -EBADMSG;
880
        if (c != '!')
2✔
881
                return -EMEDIUMTYPE;
882

883
        _cleanup_free_ char *line = NULL;
2✔
884
        r = read_line(f, LONG_LINE_MAX, &line);
2✔
885
        if (r < 0)
2✔
886
                return r;
887

888
        _cleanup_free_ char *p = NULL;
2✔
889
        const char *s = line;
2✔
890

891
        r = extract_first_word(&s, &p, /* separators = */ NULL, /* flags = */ 0);
2✔
892
        if (r < 0)
2✔
893
                return r;
894
        if (r == 0)
2✔
895
                return -ENOEXEC;
896

897
        if (ret)
2✔
898
                *ret = TAKE_PTR(p);
2✔
899
        return 0;
900
}
901

902
/**
903
 * Retrieve one field from a file like /proc/self/status.  pattern
904
 * should not include whitespace or the delimiter (':'). pattern matches only
905
 * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
906
 * zeros after the ':' will be skipped. field must be freed afterwards.
907
 * terminator specifies the terminating characters of the field value (not
908
 * included in the value).
909
 */
910
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
22,431✔
911
        _cleanup_free_ char *status = NULL;
22,431✔
912
        char *t, *f;
22,431✔
913
        int r;
22,431✔
914

915
        assert(terminator);
22,431✔
916
        assert(filename);
22,431✔
917
        assert(pattern);
22,431✔
918
        assert(field);
22,431✔
919

920
        r = read_full_virtual_file(filename, &status, NULL);
22,431✔
921
        if (r < 0)
22,431✔
922
                return r;
923

924
        t = status;
22,370✔
925

926
        do {
22,370✔
927
                bool pattern_ok;
22,370✔
928

929
                do {
22,370✔
930
                        t = strstr(t, pattern);
22,370✔
931
                        if (!t)
22,370✔
932
                                return -ENOENT;
933

934
                        /* Check that pattern occurs in beginning of line. */
935
                        pattern_ok = (t == status || t[-1] == '\n');
22,369✔
936

937
                        t += strlen(pattern);
22,369✔
938

939
                } while (!pattern_ok);
22,369✔
940

941
                t += strspn(t, " \t");
22,369✔
942
                if (!*t)
22,369✔
943
                        return -ENOENT;
944

945
        } while (*t != ':');
22,369✔
946

947
        t++;
22,369✔
948

949
        if (*t) {
22,369✔
950
                t += strspn(t, " \t");
22,369✔
951

952
                /* Also skip zeros, because when this is used for
953
                 * capabilities, we don't want the zeros. This way the
954
                 * same capability set always maps to the same string,
955
                 * irrespective of the total capability set size. For
956
                 * other numbers it shouldn't matter. */
957
                t += strspn(t, "0");
22,369✔
958
                /* Back off one char if there's nothing but whitespace
959
                   and zeros */
960
                if (!*t || isspace(*t))
22,369✔
961
                        t--;
9,267✔
962
        }
963

964
        f = strdupcspn(t, terminator);
22,369✔
965
        if (!f)
22,369✔
966
                return -ENOMEM;
967

968
        *field = f;
22,369✔
969
        return 0;
22,369✔
970
}
971

972
DIR* xopendirat(int dir_fd, const char *name, int flags) {
205,628✔
973
        _cleanup_close_ int fd = -EBADF;
205,628✔
974

975
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
205,628✔
976
        assert(name);
205,628✔
977
        assert(!(flags & (O_CREAT|O_TMPFILE)));
205,628✔
978

979
        if (dir_fd == AT_FDCWD && flags == 0)
205,628✔
UNCOV
980
                return opendir(name);
×
981

982
        fd = openat(dir_fd, name, O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags);
205,628✔
983
        if (fd < 0)
205,628✔
984
                return NULL;
985

986
        return take_fdopendir(&fd);
204,918✔
987
}
988

989
int fopen_mode_to_flags(const char *mode) {
78,625✔
990
        const char *p;
78,625✔
991
        int flags;
78,625✔
992

993
        assert(mode);
78,625✔
994

995
        if ((p = startswith(mode, "r+")))
78,625✔
996
                flags = O_RDWR;
997
        else if ((p = startswith(mode, "r")))
78,624✔
998
                flags = O_RDONLY;
UNCOV
999
        else if ((p = startswith(mode, "w+")))
×
1000
                flags = O_RDWR|O_CREAT|O_TRUNC;
UNCOV
1001
        else if ((p = startswith(mode, "w")))
×
1002
                flags = O_WRONLY|O_CREAT|O_TRUNC;
UNCOV
1003
        else if ((p = startswith(mode, "a+")))
×
1004
                flags = O_RDWR|O_CREAT|O_APPEND;
UNCOV
1005
        else if ((p = startswith(mode, "a")))
×
1006
                flags = O_WRONLY|O_CREAT|O_APPEND;
1007
        else
1008
                return -EINVAL;
1009

1010
        for (; *p != 0; p++) {
153,664✔
1011

1012
                switch (*p) {
75,039✔
1013

1014
                case 'e':
75,039✔
1015
                        flags |= O_CLOEXEC;
75,039✔
1016
                        break;
75,039✔
1017

UNCOV
1018
                case 'x':
×
UNCOV
1019
                        flags |= O_EXCL;
×
UNCOV
1020
                        break;
×
1021

1022
                case 'm':
1023
                        /* ignore this here, fdopen() might care later though */
1024
                        break;
1025

1026
                case 'c': /* not sure what to do about this one */
1027
                default:
1028
                        return -EINVAL;
1029
                }
1030
        }
1031

1032
        return flags;
1033
}
1034

1035
static int xfopenat_regular(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
951,653✔
1036
        FILE *f;
951,653✔
1037

1038
        /* A combination of fopen() with openat() */
1039

1040
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
951,653✔
1041
        assert(path);
951,653✔
1042
        assert(mode);
951,653✔
1043
        assert(ret);
951,653✔
1044

1045
        if (dir_fd == AT_FDCWD && open_flags == 0)
951,653✔
1046
                f = fopen(path, mode);
951,070✔
1047
        else {
1048
                _cleanup_close_ int fd = -EBADF;
583✔
1049
                int mode_flags;
583✔
1050

1051
                mode_flags = fopen_mode_to_flags(mode);
583✔
1052
                if (mode_flags < 0)
583✔
1053
                        return mode_flags;
1054

1055
                fd = openat(dir_fd, path, mode_flags | open_flags);
583✔
1056
                if (fd < 0)
583✔
1057
                        return -errno;
261✔
1058

1059
                f = take_fdopen(&fd, mode);
322✔
1060
        }
1061
        if (!f)
951,392✔
1062
                return -errno;
316,781✔
1063

1064
        *ret = f;
634,611✔
1065
        return 0;
634,611✔
1066
}
1067

1068
static int xfopenat_unix_socket(int dir_fd, const char *path, const char *bind_name, FILE **ret) {
1✔
1069
        _cleanup_close_ int sk = -EBADF;
1✔
1070
        FILE *f;
1✔
1071
        int r;
1✔
1072

1073
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
1✔
1074
        assert(path);
1✔
1075
        assert(ret);
1✔
1076

1077
        sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
1✔
1078
        if (sk < 0)
1✔
UNCOV
1079
                return -errno;
×
1080

1081
        if (bind_name) {
1✔
1082
                /* If the caller specified a socket name to bind to, do so before connecting. This is
1083
                 * useful to communicate some minor, short meta-information token from the client to
1084
                 * the server. */
1085
                union sockaddr_union bsa;
1✔
1086

1087
                r = sockaddr_un_set_path(&bsa.un, bind_name);
1✔
1088
                if (r < 0)
1✔
UNCOV
1089
                        return r;
×
1090

1091
                if (bind(sk, &bsa.sa, r) < 0)
1✔
1092
                        return -errno;
×
1093
        }
1094

1095
        r = connect_unix_path(sk, dir_fd, path);
1✔
1096
        if (r < 0)
1✔
1097
                return r;
1098

1099
        if (shutdown(sk, SHUT_WR) < 0)
1✔
UNCOV
1100
                return -errno;
×
1101

1102
        f = take_fdopen(&sk, "r");
1✔
1103
        if (!f)
1✔
UNCOV
1104
                return -errno;
×
1105

1106
        *ret = f;
1✔
1107
        return 0;
1✔
1108
}
1109

1110
int xfopenat_full(
951,653✔
1111
                int dir_fd,
1112
                const char *path,
1113
                const char *mode,
1114
                int open_flags,
1115
                XfopenFlags flags,
1116
                const char *bind_name,
1117
                FILE **ret) {
1118

1119
        FILE *f = NULL;  /* avoid false maybe-uninitialized warning */
951,653✔
1120
        int r;
951,653✔
1121

1122
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
951,653✔
1123
        assert(path);
951,653✔
1124
        assert(mode);
951,653✔
1125
        assert(ret);
951,653✔
1126

1127
        r = xfopenat_regular(dir_fd, path, mode, open_flags, &f);
951,653✔
1128
        if (r == -ENXIO && FLAGS_SET(flags, XFOPEN_SOCKET)) {
951,653✔
1129
                /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
1130
                r = xfopenat_unix_socket(dir_fd, path, bind_name, &f);
1✔
1131
                if (IN_SET(r, -ENOTSOCK, -EINVAL))
1✔
1132
                        return -ENXIO; /* propagate original error if this is not a socket after all */
951,653✔
1133
        }
1134
        if (r < 0)
951,653✔
1135
                return r;
1136

1137
        if (FLAGS_SET(flags, XFOPEN_UNLOCKED))
634,612✔
1138
                (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
634,381✔
1139

1140
        *ret = f;
634,612✔
1141
        return 0;
634,612✔
1142
}
1143

1144
int fdopen_independent(int fd, const char *mode, FILE **ret) {
11,311✔
1145
        _cleanup_close_ int copy_fd = -EBADF;
11,311✔
1146
        _cleanup_fclose_ FILE *f = NULL;
11,311✔
1147
        int mode_flags;
11,311✔
1148

1149
        assert(fd >= 0);
11,311✔
1150
        assert(mode);
11,311✔
1151
        assert(ret);
11,311✔
1152

1153
        /* A combination of fdopen() + fd_reopen(). i.e. reopens the inode the specified fd points to and
1154
         * returns a FILE* for it */
1155

1156
        mode_flags = fopen_mode_to_flags(mode);
11,311✔
1157
        if (mode_flags < 0)
11,311✔
1158
                return mode_flags;
1159

1160
        /* Flags returned by fopen_mode_to_flags might contain O_CREAT, but it doesn't make sense for fd_reopen
1161
         * since we're working on an existing fd anyway. Let's drop it here to avoid triggering assertion. */
1162
        copy_fd = fd_reopen(fd, mode_flags & ~O_CREAT);
11,311✔
1163
        if (copy_fd < 0)
11,311✔
1164
                return copy_fd;
1165

1166
        f = take_fdopen(&copy_fd, mode);
11,311✔
1167
        if (!f)
11,311✔
UNCOV
1168
                return -errno;
×
1169

1170
        *ret = TAKE_PTR(f);
11,311✔
1171
        return 0;
11,311✔
1172
}
1173

1174
static int search_and_open_internal(
21,004✔
1175
                const char *path,
1176
                int mode,            /* if ret_fd is NULL this is an [FRWX]_OK mode for access(), otherwise an open mode for open() */
1177
                const char *root,
1178
                char **search,
1179
                int *ret_fd,
1180
                char **ret_path) {
1181

1182
        int r;
21,004✔
1183

1184
        assert(!ret_fd || !FLAGS_SET(mode, O_CREAT)); /* We don't support O_CREAT for this */
21,004✔
1185
        assert(path);
21,004✔
1186

1187
        if (path_is_absolute(path)) {
21,004✔
UNCOV
1188
                _cleanup_close_ int fd = -EBADF;
×
1189

1190
                if (ret_fd)
5,470✔
1191
                        /* We only specify 0777 here to appease static analyzers, it's never used since we
1192
                         * don't support O_CREAT here */
1193
                        r = fd = RET_NERRNO(open(path, mode, 0777));
5,468✔
1194
                else
1195
                        r = RET_NERRNO(access(path, mode));
2✔
1196
                if (r < 0)
177✔
1197
                        return r;
1198

1199
                if (ret_path) {
5,293✔
1200
                        r = path_simplify_alloc(path, ret_path);
5,293✔
1201
                        if (r < 0)
5,293✔
1202
                                return r;
1203
                }
1204

1205
                if (ret_fd)
5,293✔
1206
                        *ret_fd = TAKE_FD(fd);
5,292✔
1207

1208
                return 0;
5,293✔
1209
        }
1210

1211
        if (!path_strv_resolve_uniq(search, root))
15,534✔
1212
                return -ENOMEM;
1213

1214
        STRV_FOREACH(i, search) {
92,350✔
1215
                _cleanup_close_ int fd = -EBADF;
97,820✔
1216
                _cleanup_free_ char *p = NULL;
76,921✔
1217

1218
                p = path_join(root, *i, path);
76,921✔
1219
                if (!p)
76,921✔
1220
                        return -ENOMEM;
1221

1222
                if (ret_fd)
76,921✔
1223
                        /* as above, 0777 is static analyzer appeasement */
1224
                        r = fd = RET_NERRNO(open(p, mode, 0777));
76,629✔
1225
                else
1226
                        r = RET_NERRNO(access(p, F_OK));
292✔
1227
                if (r >= 0) {
76,816✔
1228
                        if (ret_path)
105✔
1229
                                *ret_path = path_simplify(TAKE_PTR(p));
105✔
1230

1231
                        if (ret_fd)
105✔
1232
                                *ret_fd = TAKE_FD(fd);
98✔
1233

1234
                        return 0;
105✔
1235
                }
1236
                if (r != -ENOENT)
76,816✔
1237
                        return r;
1238
        }
1239

1240
        return -ENOENT;
1241
}
1242

1243
int search_and_open(
21,004✔
1244
                const char *path,
1245
                int mode,
1246
                const char *root,
1247
                char **search,
1248
                int *ret_fd,
1249
                char **ret_path) {
1250

1251
        _cleanup_strv_free_ char **copy = NULL;
21,004✔
1252

1253
        assert(path);
21,004✔
1254

1255
        copy = strv_copy((char**) search);
21,004✔
1256
        if (!copy)
21,004✔
1257
                return -ENOMEM;
1258

1259
        return search_and_open_internal(path, mode, root, copy, ret_fd, ret_path);
21,004✔
1260
}
1261

1262
static int search_and_fopen_internal(
20,999✔
1263
                const char *path,
1264
                const char *mode,
1265
                const char *root,
1266
                char **search,
1267
                FILE **ret_file,
1268
                char **ret_path) {
1269

1270
        _cleanup_free_ char *found_path = NULL;
20,999✔
1271
        _cleanup_close_ int fd = -EBADF;
20,999✔
1272
        int r;
20,999✔
1273

1274
        assert(path);
20,999✔
1275
        assert(mode || !ret_file);
20,999✔
1276

1277
        r = search_and_open(
42,101✔
1278
                        path,
1279
                        mode ? fopen_mode_to_flags(mode) : 0,
20,861✔
1280
                        root,
1281
                        search,
1282
                        ret_file ? &fd : NULL,
1283
                        ret_path ? &found_path : NULL);
1284
        if (r < 0)
20,999✔
1285
                return r;
1286

1287
        if (ret_file) {
5,393✔
1288
                FILE *f = take_fdopen(&fd, mode);
5,390✔
1289
                if (!f)
5,390✔
UNCOV
1290
                        return -errno;
×
1291

1292
                *ret_file = f;
5,390✔
1293
        }
1294

1295
        if (ret_path)
5,393✔
1296
                *ret_path = TAKE_PTR(found_path);
5,393✔
1297

1298
        return 0;
1299
}
1300

1301
int search_and_fopen(
5,474✔
1302
                const char *path,
1303
                const char *mode,
1304
                const char *root,
1305
                const char **search,
1306
                FILE **ret_file,
1307
                char **ret_path) {
1308

1309
        _cleanup_strv_free_ char **copy = NULL;
5,474✔
1310

1311
        assert(path);
5,474✔
1312
        assert(mode || !ret_file);
5,474✔
1313

1314
        copy = strv_copy((char**) search);
5,474✔
1315
        if (!copy)
5,474✔
1316
                return -ENOMEM;
1317

1318
        return search_and_fopen_internal(path, mode, root, copy, ret_file, ret_path);
5,474✔
1319
}
1320

1321
int search_and_fopen_nulstr(
15,525✔
1322
                const char *path,
1323
                const char *mode,
1324
                const char *root,
1325
                const char *search,
1326
                FILE **ret_file,
1327
                char **ret_path) {
1328

1329
        _cleanup_strv_free_ char **l = NULL;
15,525✔
1330

1331
        assert(path);
15,525✔
1332
        assert(mode || !ret_file);
15,525✔
1333

1334
        l = strv_split_nulstr(search);
15,525✔
1335
        if (!l)
15,525✔
1336
                return -ENOMEM;
1337

1338
        return search_and_fopen_internal(path, mode, root, l, ret_file, ret_path);
15,525✔
1339
}
1340

1341
int fflush_and_check(FILE *f) {
891,385✔
1342
        assert(f);
891,385✔
1343

1344
        errno = 0;
891,385✔
1345
        fflush(f);
891,385✔
1346

1347
        if (ferror(f))
891,385✔
1348
                return errno_or_else(EIO);
24✔
1349

1350
        return 0;
1351
}
1352

1353
int fflush_sync_and_check(FILE *f) {
2,318✔
1354
        int r, fd;
2,318✔
1355

1356
        assert(f);
2,318✔
1357

1358
        r = fflush_and_check(f);
2,318✔
1359
        if (r < 0)
2,318✔
1360
                return r;
1361

1362
        /* Not all file streams have an fd associated (think: fmemopen()), let's handle this gracefully and
1363
         * assume that in that case we need no explicit syncing */
1364
        fd = fileno(f);
2,318✔
1365
        if (fd < 0)
2,318✔
1366
                return 0;
1367

1368
        r = fsync_full(fd);
2,318✔
1369
        if (r < 0)
2,318✔
UNCOV
1370
                return r;
×
1371

1372
        return 0;
1373
}
1374

1375
int write_timestamp_file_atomic(const char *fn, usec_t n) {
116✔
1376
        char ln[DECIMAL_STR_MAX(n)+2];
116✔
1377

1378
        /* Creates a "timestamp" file, that contains nothing but a
1379
         * usec_t timestamp, formatted in ASCII. */
1380

1381
        if (!timestamp_is_set(n))
116✔
1382
                return -ERANGE;
116✔
1383

1384
        xsprintf(ln, USEC_FMT "\n", n);
116✔
1385

1386
        return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
116✔
1387
}
1388

1389
int read_timestamp_file(const char *fn, usec_t *ret) {
82✔
1390
        _cleanup_free_ char *ln = NULL;
82✔
1391
        uint64_t t;
82✔
1392
        int r;
82✔
1393

1394
        r = read_one_line_file(fn, &ln);
82✔
1395
        if (r < 0)
82✔
1396
                return r;
1397

UNCOV
1398
        r = safe_atou64(ln, &t);
×
UNCOV
1399
        if (r < 0)
×
1400
                return r;
1401

1402
        if (!timestamp_is_set(t))
×
1403
                return -ERANGE;
1404

1405
        *ret = (usec_t) t;
×
UNCOV
1406
        return 0;
×
1407
}
1408

1409
int fputs_with_separator(FILE *f, const char *s, const char *separator, bool *space) {
2,924✔
1410
        assert(s);
2,924✔
1411
        assert(space);
2,924✔
1412

1413
        /* Outputs the specified string with fputs(), but optionally prefixes it with a separator.
1414
         * The *space parameter when specified shall initially point to a boolean variable initialized
1415
         * to false. It is set to true after the first invocation. This call is supposed to be use in loops,
1416
         * where a separator shall be inserted between each element, but not before the first one. */
1417

1418
        if (!f)
2,924✔
UNCOV
1419
                f = stdout;
×
1420

1421
        if (!separator)
2,924✔
1422
                separator = " ";
1,556✔
1423

1424
        if (*space)
2,924✔
1425
                if (fputs(separator, f) < 0)
1,162✔
1426
                        return -EIO;
1427

1428
        *space = true;
2,924✔
1429

1430
        if (fputs(s, f) < 0)
2,924✔
UNCOV
1431
                return -EIO;
×
1432

1433
        return 0;
1434
}
1435

1436
int fputs_with_newline(FILE *f, const char *s) {
597✔
1437

1438
        /* This is like fputs() but outputs a trailing newline char, but only if the string isn't empty
1439
         * and doesn't end in a newline already. Returns 0 in case we didn't append a newline, > 0 otherwise. */
1440

1441
        if (isempty(s))
597✔
1442
                return 0;
1443

1444
        if (!f)
597✔
UNCOV
1445
                f = stdout;
×
1446

1447
        if (fputs(s, f) < 0)
597✔
1448
                return -EIO;
1449

1450
        if (endswith(s, "\n"))
597✔
1451
                return 0;
1452

1453
        if (fputc('\n', f) < 0)
467✔
UNCOV
1454
                return -EIO;
×
1455

1456
        return 1;
1457
}
1458

1459
/* A bitmask of the EOL markers we know */
1460
typedef enum EndOfLineMarker {
1461
        EOL_NONE     = 0,
1462
        EOL_ZERO     = 1 << 0,  /* \0 (aka NUL) */
1463
        EOL_TEN      = 1 << 1,  /* \n (aka NL, aka LF)  */
1464
        EOL_THIRTEEN = 1 << 2,  /* \r (aka CR)  */
1465
} EndOfLineMarker;
1466

1467
static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
253,845,126✔
1468

1469
        if (!FLAGS_SET(flags, READ_LINE_ONLY_NUL)) {
253,845,126✔
1470
                if (c == '\n')
252,771,836✔
1471
                        return EOL_TEN;
1472
                if (c == '\r')
244,814,731✔
1473
                        return EOL_THIRTEEN;
1474
        }
1475

1476
        if (c == '\0')
245,888,005✔
1477
                return EOL_ZERO;
33,186✔
1478

1479
        return EOL_NONE;
1480
}
1481

1482
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, funlockfile, NULL);
7,379,691✔
1483

1484
int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
7,379,691✔
1485
        _cleanup_free_ char *buffer = NULL;
7,379,691✔
1486
        size_t n = 0, count = 0;
7,379,691✔
1487
        int r;
7,379,691✔
1488

1489
        assert(f);
7,379,691✔
1490

1491
        /* Something like a bounded version of getline().
1492
         *
1493
         * Considers EOF, \n, \r and \0 end of line delimiters (or combinations of these), and does not include these
1494
         * delimiters in the string returned. Specifically, recognizes the following combinations of markers as line
1495
         * endings:
1496
         *
1497
         *     • \n        (UNIX)
1498
         *     • \r        (old MacOS)
1499
         *     • \0        (C strings)
1500
         *     • \n\0
1501
         *     • \r\0
1502
         *     • \r\n      (Windows)
1503
         *     • \n\r
1504
         *     • \r\n\0
1505
         *     • \n\r\0
1506
         *
1507
         * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
1508
         * the number of characters in the returned string). When EOF is hit, 0 is returned.
1509
         *
1510
         * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
1511
         * delimiters. If the limit is hit we fail and return -ENOBUFS.
1512
         *
1513
         * If a line shall be skipped ret may be initialized as NULL. */
1514

1515
        if (ret) {
7,379,691✔
1516
                if (!GREEDY_REALLOC(buffer, 1))
7,379,660✔
1517
                        return -ENOMEM;
1518
        }
1519

1520
        {
1521
                _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
7,379,691✔
1522
                EndOfLineMarker previous_eol = EOL_NONE;
7,379,691✔
1523
                flockfile(f);
7,379,691✔
1524

1525
                for (;;) {
254,375,199✔
1526
                        EndOfLineMarker eol;
254,375,199✔
1527
                        char c;
254,375,199✔
1528

1529
                        if (n >= limit)
254,375,199✔
1530
                                return -ENOBUFS;
19✔
1531

1532
                        if (count >= INT_MAX) /* We couldn't return the counter anymore as "int", hence refuse this */
254,375,193✔
1533
                                return -ENOBUFS;
1534

1535
                        r = safe_fgetc(f, &c);
254,375,193✔
1536
                        if (r < 0)
254,375,193✔
1537
                                return r;
1538
                        if (r == 0) /* EOF is definitely EOL */
254,375,180✔
1539
                                break;
1540

1541
                        eol = categorize_eol(c, flags);
253,845,126✔
1542

1543
                        if (FLAGS_SET(previous_eol, EOL_ZERO) ||
253,845,126✔
1544
                            (eol == EOL_NONE && previous_eol != EOL_NONE) ||
253,815,488✔
1545
                            (eol != EOL_NONE && (previous_eol & eol) != 0)) {
7,990,301✔
1546
                                /* Previous char was a NUL? This is not an EOL, but the previous char was? This type of
1547
                                 * EOL marker has been seen right before?  In either of these three cases we are
1548
                                 * done. But first, let's put this character back in the queue. (Note that we have to
1549
                                 * cast this to (unsigned char) here as ungetc() expects a positive 'int', and if we
1550
                                 * are on an architecture where 'char' equals 'signed char' we need to ensure we don't
1551
                                 * pass a negative value here. That said, to complicate things further ungetc() is
1552
                                 * actually happy with most negative characters and implicitly casts them back to
1553
                                 * positive ones as needed, except for \xff (aka -1, aka EOF), which it refuses. What a
1554
                                 * godawful API!) */
1555
                                assert_se(ungetc((unsigned char) c, f) != EOF);
6,849,618✔
1556
                                break;
1557
                        }
1558

1559
                        count++;
246,995,508✔
1560

1561
                        if (eol != EOL_NONE) {
239,775,231✔
1562
                                /* If we are on a tty, we can't shouldn't wait for more input, because that
1563
                                 * generally means waiting for the user, interactively. In the case of a TTY
1564
                                 * we expect only \n as the single EOL marker, so we are in the lucky
1565
                                 * position that there is no need to wait. We check this condition last, to
1566
                                 * avoid isatty() check if not necessary. */
1567

1568
                                if ((flags & (READ_LINE_IS_A_TTY|READ_LINE_NOT_A_TTY)) == 0) {
7,220,277✔
1569
                                        int fd;
6,509,811✔
1570

1571
                                        fd = fileno(f);
6,509,811✔
1572
                                        if (fd < 0) /* Maybe an fmemopen() stream? Handle this gracefully,
6,509,811✔
1573
                                                     * and don't call isatty() on an invalid fd */
1574
                                                flags |= READ_LINE_NOT_A_TTY;
28✔
1575
                                        else
1576
                                                flags |= isatty_safe(fd) ? READ_LINE_IS_A_TTY : READ_LINE_NOT_A_TTY;
13,019,566✔
1577
                                }
1578
                                if (FLAGS_SET(flags, READ_LINE_IS_A_TTY))
7,220,277✔
1579
                                        break;
1580
                        }
1581

1582
                        if (eol != EOL_NONE) {
246,995,508✔
1583
                                previous_eol |= eol;
7,220,277✔
1584
                                continue;
7,220,277✔
1585
                        }
1586

1587
                        if (ret) {
239,775,231✔
1588
                                if (!GREEDY_REALLOC(buffer, n + 2))
239,775,131✔
1589
                                        return -ENOMEM;
1590

1591
                                buffer[n] = c;
239,775,131✔
1592
                        }
1593

1594
                        n++;
239,775,231✔
1595
                }
1596
        }
1597

1598
        if (ret) {
7,379,672✔
1599
                buffer[n] = 0;
7,379,641✔
1600

1601
                *ret = TAKE_PTR(buffer);
7,379,641✔
1602
        }
1603

1604
        return (int) count;
7,379,672✔
1605
}
1606

1607
int read_stripped_line(FILE *f, size_t limit, char **ret) {
3,102,844✔
1608
        _cleanup_free_ char *s = NULL;
3,102,844✔
1609
        int r, k;
3,102,844✔
1610

1611
        assert(f);
3,102,844✔
1612

1613
        r = read_line(f, limit, ret ? &s : NULL);
3,102,844✔
1614
        if (r < 0)
3,102,844✔
1615
                return r;
1616

1617
        if (ret) {
3,102,844✔
1618
                const char *p = strstrip(s);
3,102,844✔
1619
                if (p == s)
3,102,844✔
1620
                        *ret = TAKE_PTR(s);
3,102,840✔
1621
                else {
1622
                        k = strdup_to(ret, p);
4✔
1623
                        if (k < 0)
4✔
1624
                                return k;
1625
                }
1626
        }
1627

1628
        return r > 0;          /* Return 1 if something was read. */
3,102,844✔
1629
}
1630

1631
int safe_fgetc(FILE *f, char *ret) {
254,382,248✔
1632
        int k;
254,382,248✔
1633

1634
        assert(f);
254,382,248✔
1635

1636
        /* A safer version of plain fgetc(): let's propagate the error that happened while reading as such, and
1637
         * separate the EOF condition from the byte read, to avoid those confusion signed/unsigned issues fgetc()
1638
         * has. */
1639

1640
        errno = 0;
254,382,248✔
1641
        k = fgetc(f);
254,382,248✔
1642
        if (k == EOF) {
254,382,248✔
1643
                if (ferror(f))
530,162✔
1644
                        return errno_or_else(EIO);
26✔
1645

1646
                if (ret)
530,149✔
1647
                        *ret = 0;
530,071✔
1648

1649
                return 0;
530,149✔
1650
        }
1651

1652
        if (ret)
253,852,086✔
1653
                *ret = k;
253,852,086✔
1654

1655
        return 1;
1656
}
1657

1658
int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line) {
146✔
1659
        struct stat _st;
146✔
1660

1661
        if (!filename)
146✔
1662
                return 0;
146✔
1663

1664
        if (!st) {
146✔
1665
                if (stat(filename, &_st) < 0)
22✔
UNCOV
1666
                        return -errno;
×
1667
                st = &_st;
1668
        }
1669

1670
        if ((st->st_mode & S_IRWXO) == 0)
146✔
1671
                return 0;
1672

1673
        if (unit)
35✔
UNCOV
1674
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1675
                           "%s has %04o mode that is too permissive, please adjust the ownership and access mode.",
1676
                           filename, st->st_mode & 07777);
1677
        else
1678
                log_warning("%s has %04o mode that is too permissive, please adjust the ownership and access mode.",
35✔
1679
                            filename, st->st_mode & 07777);
1680
        return 0;
1681
}
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