• 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

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

3
#include <fcntl.h>
4
#include <stdio_ext.h>
5
#include <stdlib.h>
6
#include <sys/stat.h>
7
#include <unistd.h>
8

9
#include "alloc-util.h"
10
#include "errno-util.h"
11
#include "extract-word.h"
12
#include "fd-util.h"
13
#include "fileio.h"
14
#include "fs-util.h"
15
#include "hexdecoct.h"
16
#include "label.h"
17
#include "log.h"
18
#include "mkdir.h"
19
#include "nulstr-util.h"
20
#include "parse-util.h"
21
#include "path-util.h"
22
#include "socket-util.h"
23
#include "stat-util.h"
24
#include "stdio-util.h"
25
#include "string-util.h"
26
#include "strv.h"
27
#include "sync-util.h"
28
#include "terminal-util.h"
29
#include "time-util.h"
30
#include "tmpfile-util.h"
31

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

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

48
int fdopen_unlocked(int fd, const char *options, FILE **ret) {
343,530✔
49
        assert(ret);
343,530✔
50

51
        FILE *f = fdopen(fd, options);
343,530✔
52
        if (!f)
343,530✔
UNCOV
53
                return -errno;
×
54

55
        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
343,530✔
56

57
        *ret = f;
343,530✔
58
        return 0;
343,530✔
59
}
60

61
int take_fdopen_unlocked(int *fd, const char *options, FILE **ret) {
343,530✔
62
        int r;
343,530✔
63

64
        assert(fd);
343,530✔
65

66
        r = fdopen_unlocked(*fd, options, ret);
343,530✔
67
        if (r < 0)
343,530✔
68
                return r;
69

70
        *fd = -EBADF;
343,530✔
71

72
        return 0;
343,530✔
73
}
74

75
FILE* take_fdopen(int *fd, const char *options) {
42,992✔
76
        assert(fd);
42,992✔
77

78
        FILE *f = fdopen(*fd, options);
42,992✔
79
        if (!f)
42,992✔
80
                return NULL;
81

82
        *fd = -EBADF;
42,992✔
83

84
        return f;
42,992✔
85
}
86

87
DIR* take_fdopendir(int *dfd) {
261,771✔
88
        assert(dfd);
261,771✔
89

90
        DIR *d = fdopendir(*dfd);
261,771✔
91
        if (!d)
261,771✔
92
                return NULL;
93

94
        *dfd = -EBADF;
261,771✔
95

96
        return d;
261,771✔
97
}
98

99
FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) {
705,267✔
100
        FILE *f = open_memstream(ptr, sizeloc);
705,267✔
101
        if (!f)
705,267✔
102
                return NULL;
103

104
        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
705,267✔
105

106
        return f;
705,267✔
107
}
108

109
FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode) {
103✔
110
        FILE *f = fmemopen(buf, size, mode);
103✔
111
        if (!f)
103✔
112
                return NULL;
113

114
        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
103✔
115

116
        return f;
103✔
117
}
118

119
int write_string_stream_full(
148,570✔
120
                FILE *f,
121
                const char *line,
122
                WriteStringFileFlags flags,
123
                const struct timespec *ts) {
124

125
        bool needs_nl;
148,570✔
126
        int r, fd = -EBADF;
148,570✔
127

128
        assert(f);
148,570✔
129
        assert(line);
148,570✔
130

131
        if (ferror(f))
148,570✔
132
                return -EIO;
133

134
        if (ts) {
148,570✔
135
                /* If we shall set the timestamp we need the fd. But fmemopen() streams generally don't have
136
                 * an fd. Let's fail early in that case. */
137
                fd = fileno(f);
2✔
138
                if (fd < 0)
2✔
139
                        return -EBADF;
140
        }
141

142
        if (flags & WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) {
148,570✔
143
                _cleanup_free_ char *t = NULL;
8,280✔
144

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

147
                if (fd < 0) {
8,280✔
148
                        fd = fileno(f);
8,280✔
149
                        if (fd < 0)
8,280✔
150
                                return -EBADF;
151
                }
152

153
                /* Read an additional byte to detect cases where the prefix matches but the rest
154
                 * doesn't. Also, 0 returned by read_virtual_file_fd() means the read was truncated and
155
                 * it won't be equal to the new value. */
156
                if (read_virtual_file_fd(fd, strlen(line)+1, &t, NULL) > 0 &&
16,403✔
157
                    streq_skip_trailing_chars(line, t, NEWLINE)) {
8,123✔
158
                        log_debug("No change in value '%s', suppressing write", line);
5,957✔
159
                        return 0;
5,957✔
160
                }
161

162
                if (lseek(fd, 0, SEEK_SET) < 0)
2,323✔
UNCOV
163
                        return -errno;
×
164
        }
165

166
        needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
142,613✔
167

168
        if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) {
44,100✔
169
                /* If STDIO buffering was disabled, then let's append the newline character to the string
170
                 * itself, so that the write goes out in one go, instead of two */
171

172
                line = strjoina(line, "\n");
215,255✔
173
                needs_nl = false;
43,051✔
174
        }
175

176
        if (fputs(line, f) == EOF)
142,613✔
177
                return -errno;
22✔
178

179
        if (needs_nl)
142,591✔
180
                if (fputc('\n', f) == EOF)
1,048✔
UNCOV
181
                        return -errno;
×
182

183
        if (flags & WRITE_STRING_FILE_SYNC)
142,591✔
184
                r = fflush_sync_and_check(f);
1,708✔
185
        else
186
                r = fflush_and_check(f);
140,883✔
187
        if (r < 0)
142,591✔
188
                return r;
189

190
        if (ts) {
142,579✔
191
                const struct timespec twice[2] = {*ts, *ts};
2✔
192

193
                assert(fd >= 0);
2✔
194
                if (futimens(fd, twice) < 0)
2✔
UNCOV
195
                        return -errno;
×
196
        }
197

198
        return 0;
199
}
200

201
static mode_t write_string_file_flags_to_mode(WriteStringFileFlags flags) {
75,342✔
202

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

210
        return FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 :
75,342✔
211
                FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0444) ? 0444 : 0644;
75,132✔
212
}
213

214
static int write_string_file_atomic_at(
2,451✔
215
                int dir_fd,
216
                const char *fn,
217
                const char *line,
218
                WriteStringFileFlags flags,
219
                const struct timespec *ts) {
220

221
        _cleanup_fclose_ FILE *f = NULL;
2,451✔
222
        _cleanup_free_ char *p = NULL;
2,451✔
223
        int r;
2,451✔
224

225
        assert(fn);
2,451✔
226
        assert(line);
2,451✔
227

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

231
        mode_t mode = write_string_file_flags_to_mode(flags);
2,451✔
232

233
        bool call_label_ops_post = false;
2,451✔
234
        if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL)) {
2,451✔
235
                r = label_ops_pre(dir_fd, fn, mode);
157✔
236
                if (r < 0)
157✔
237
                        return r;
238

239
                call_label_ops_post = true;
240
        }
241

242
        r = fopen_temporary_at(dir_fd, fn, &f, &p);
2,451✔
243
        if (call_label_ops_post)
2,451✔
244
                /* If fopen_temporary_at() failed in the above, propagate the error code, and ignore failures
245
                 * in label_ops_post(). */
246
                RET_GATHER(r, label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f));
314✔
247
        if (r < 0)
2,451✔
248
                goto fail;
1✔
249

250
        r = write_string_stream_full(f, line, flags, ts);
2,450✔
251
        if (r < 0)
2,450✔
UNCOV
252
                goto fail;
×
253

254
        r = fchmod_umask(fileno(f), mode);
2,450✔
255
        if (r < 0)
2,450✔
UNCOV
256
                goto fail;
×
257

258
        r = RET_NERRNO(renameat(dir_fd, p, dir_fd, fn));
2,450✔
UNCOV
259
        if (r < 0)
×
UNCOV
260
                goto fail;
×
261

262
        if (FLAGS_SET(flags, WRITE_STRING_FILE_SYNC)) {
2,450✔
263
                /* Sync the rename, too */
264
                r = fsync_directory_of_file(fileno(f));
1,708✔
265
                if (r < 0)
1,708✔
UNCOV
266
                        return r;
×
267
        }
268

269
        return 0;
270

271
fail:
1✔
272
        if (f)
1✔
UNCOV
273
                (void) unlinkat(dir_fd, p, 0);
×
274
        return r;
275
}
276

277
int write_string_file_full(
132,581✔
278
                int dir_fd,
279
                const char *fn,
280
                const char *line,
281
                WriteStringFileFlags flags,
282
                const struct timespec *ts,
283
                const char *label_fn) {
284

285
        bool made_file = false;
132,581✔
286
        _cleanup_fclose_ FILE *f = NULL;
132,581✔
287
        _cleanup_close_ int fd = -EBADF;
132,581✔
288
        int r;
132,581✔
289

290
        assert(dir_fd == AT_FDCWD || dir_fd >= 0);
132,581✔
291
        assert(line);
132,581✔
292

293
        /* We don't know how to verify whether the file contents was already on-disk. */
294
        assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
132,581✔
295

296
        if (flags & WRITE_STRING_FILE_MKDIR_0755) {
132,581✔
297
                assert(fn);
222✔
298

299
                r = mkdirat_parents(dir_fd, fn, 0755);
222✔
300
                if (r < 0)
222✔
301
                        return r;
302
        }
303

304
        if (flags & WRITE_STRING_FILE_ATOMIC) {
132,581✔
305
                assert(fn);
2,451✔
306
                assert(flags & WRITE_STRING_FILE_CREATE);
2,451✔
307

308
                r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts);
2,451✔
309
                if (r < 0)
2,451✔
310
                        goto fail;
1✔
311

312
                return r;
313
        }
314

315
        /* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
316
        if (isempty(fn))
130,130✔
317
                r = fd = fd_reopen(
57,239✔
318
                                ASSERT_FD(dir_fd), O_CLOEXEC | O_NOCTTY |
57,239✔
319
                                (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
57,239✔
320
                                (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY));
57,239✔
321
        else {
322
                mode_t mode = write_string_file_flags_to_mode(flags);
72,891✔
323
                bool call_label_ops_post = false;
72,891✔
324

325
                if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) {
72,891✔
326
                        r = label_ops_pre(dir_fd, label_fn ?: fn, mode);
359✔
327
                        if (r < 0)
359✔
UNCOV
328
                                goto fail;
×
329

330
                        call_label_ops_post = true;
331
                }
332

333
                r = fd = openat_report_new(
72,891✔
334
                                dir_fd, fn, O_CLOEXEC | O_NOCTTY |
72,891✔
335
                                (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
72,891✔
336
                                (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
72,891✔
337
                                (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
72,891✔
338
                                (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY),
72,891✔
339
                                mode,
340
                                &made_file);
341
                if (call_label_ops_post)
72,891✔
342
                        /* If openat_report_new() failed in the above, propagate the error code, and ignore
343
                         * failures in label_ops_post(). */
344
                        RET_GATHER(r, label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, made_file));
1,077✔
345
        }
346
        if (r < 0)
130,130✔
347
                goto fail;
1,550✔
348

349
        r = take_fdopen_unlocked(&fd, "w", &f);
128,580✔
350
        if (r < 0)
128,580✔
UNCOV
351
                goto fail;
×
352

353
        if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
128,580✔
354
                setvbuf(f, NULL, _IONBF, 0);
127,557✔
355

356
        r = write_string_stream_full(f, line, flags, ts);
128,580✔
357
        if (r < 0)
128,580✔
358
                goto fail;
27✔
359

360
        return 0;
361

362
fail:
1,578✔
363
        if (made_file)
1,578✔
UNCOV
364
                (void) unlinkat(dir_fd, fn, 0);
×
365

366
        if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
1,578✔
367
                return r;
368

369
        f = safe_fclose(f);
1,548✔
370
        fd = safe_close(fd);
1,548✔
371

372
        /* OK, the operation failed, but let's see if the right contents in place already. If so, eat up the
373
         * error. */
374
        if (verify_file_at(dir_fd, fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) || (flags & WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE)) > 0)
1,550✔
375
                return 0;
454✔
376

377
        return r;
378
}
379

380
int write_string_filef(
230✔
381
                const char *fn,
382
                WriteStringFileFlags flags,
383
                const char *format, ...) {
384

385
        _cleanup_free_ char *p = NULL;
230✔
386
        va_list ap;
230✔
387
        int r;
230✔
388

389
        va_start(ap, format);
230✔
390
        r = vasprintf(&p, format, ap);
230✔
391
        va_end(ap);
230✔
392

393
        if (r < 0)
230✔
394
                return -ENOMEM;
395

396
        return write_string_file(fn, p, flags);
230✔
397
}
398

399
int write_base64_file_at(
7✔
400
                int dir_fd,
401
                const char *fn,
402
                const struct iovec *data,
403
                WriteStringFileFlags flags) {
404

405
        _cleanup_free_ char *encoded = NULL;
7✔
406
        ssize_t n;
7✔
407

408
        n = base64mem_full(data ? data->iov_base : NULL, data ? data->iov_len : 0, 79, &encoded);
7✔
409
        if (n < 0)
7✔
UNCOV
410
                return n;
×
411

412
        return write_string_file_at(dir_fd, fn, encoded, flags);
7✔
413
}
414

415
int read_one_line_file_at(int dir_fd, const char *filename, char **ret) {
156,777✔
416
        _cleanup_fclose_ FILE *f = NULL;
156,777✔
417
        int r;
156,777✔
418

419
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
156,777✔
420
        assert(filename);
156,777✔
421
        assert(ret);
156,777✔
422

423
        r = fopen_unlocked_at(dir_fd, filename, "re", 0, &f);
156,777✔
424
        if (r < 0)
156,777✔
425
                return r;
426

427
        return read_line(f, LONG_LINE_MAX, ret);
156,777✔
428
}
429

430
int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl) {
1,548✔
431
        _cleanup_fclose_ FILE *f = NULL;
1,548✔
432
        _cleanup_free_ char *buf = NULL;
1,548✔
433
        size_t l, k;
1,548✔
434
        int r;
1,548✔
435

436
        assert(blob);
1,548✔
437

438
        l = strlen(blob);
1,548✔
439

440
        if (accept_extra_nl && endswith(blob, "\n"))
1,548✔
441
                accept_extra_nl = false;
1✔
442

443
        buf = malloc(l + accept_extra_nl + 1);
1,548✔
444
        if (!buf)
1,548✔
445
                return -ENOMEM;
446

447
        r = fopen_unlocked_at(dir_fd, strempty(fn), "re", 0, &f);
1,548✔
448
        if (r < 0)
1,548✔
449
                return r;
450

451
        /* We try to read one byte more than we need, so that we know whether we hit eof */
452
        errno = 0;
866✔
453
        k = fread(buf, 1, l + accept_extra_nl + 1, f);
866✔
454
        if (ferror(f))
866✔
UNCOV
455
                return errno_or_else(EIO);
×
456

457
        if (k != l && k != l + accept_extra_nl)
866✔
458
                return 0;
459
        if (memcmp(buf, blob, l) != 0)
727✔
460
                return 0;
461
        if (k > l && buf[l] != '\n')
454✔
UNCOV
462
                return 0;
×
463

464
        return 1;
465
}
466

467
int read_virtual_file_at(
828,292✔
468
                int dir_fd,
469
                const char *filename,
470
                size_t max_size,
471
                char **ret_contents,
472
                size_t *ret_size) {
473

474
        _cleanup_free_ char *buf = NULL;
828,292✔
475
        size_t n, size;
828,292✔
476
        int n_retries;
828,292✔
477
        bool truncated = false;
828,292✔
478

479
        /* Virtual filesystems such as sysfs or procfs use kernfs, and kernfs can work with two sorts of
480
         * virtual files. One sort uses "seq_file", and the results of the first read are buffered for the
481
         * second read. The other sort uses "raw" reads which always go direct to the device. In the latter
482
         * case, the content of the virtual file must be retrieved with a single read otherwise a second read
483
         * might get the new value instead of finding EOF immediately. That's the reason why the usage of
484
         * fread(3) is prohibited in this case as it always performs a second call to read(2) looking for
485
         * EOF. See issue #13585.
486
         *
487
         * max_size specifies a limit on the bytes read. If max_size is SIZE_MAX, the full file is read. If
488
         * the full file is too large to read, an error is returned. For other values of max_size, *partial
489
         * contents* may be returned. (Though the read is still done using one syscall.) Returns 0 on
490
         * partial success, 1 if untruncated contents were read.
491
         *
492
         * Rule: for kernfs files using "seq_file" → use regular read_full_file_at()
493
         *       for kernfs files using "raw" → use read_virtual_file_at()
494
         */
495

496
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
828,292✔
497
        assert(max_size <= READ_VIRTUAL_BYTES_MAX || max_size == SIZE_MAX);
828,292✔
498

499
        _cleanup_close_ int fd = -EBADF;
828,292✔
500
        if (isempty(filename))
828,292✔
501
                fd = fd_reopen(ASSERT_FD(dir_fd), O_RDONLY | O_NOCTTY | O_CLOEXEC);
659,644✔
502
        else
503
                fd = RET_NERRNO(openat(dir_fd, filename, O_RDONLY | O_NOCTTY | O_CLOEXEC));
168,648✔
504
        if (fd < 0)
828,292✔
505
                return fd;
506

507
        /* Limit the number of attempts to read the number of bytes returned by fstat(). */
508
        n_retries = 3;
509

510
        for (;;) {
768,401✔
511
                struct stat st;
768,400✔
512

513
                if (fstat(fd, &st) < 0)
768,400✔
514
                        return -errno;
1,154✔
515

516
                if (!S_ISREG(st.st_mode))
768,400✔
517
                        return -EBADF;
518

519
                /* Be prepared for files from /proc which generally report a file size of 0. */
520
                assert_cc(READ_VIRTUAL_BYTES_MAX < SSIZE_MAX);
768,400✔
521
                if (st.st_size > 0 && n_retries > 1) {
768,400✔
522
                        /* Let's use the file size if we have more than 1 attempt left. On the last attempt
523
                         * we'll ignore the file size */
524

525
                        if (st.st_size > SSIZE_MAX) { /* Avoid overflow with 32-bit size_t and 64-bit off_t. */
603,718✔
526

527
                                if (max_size == SIZE_MAX)
528
                                        return -EFBIG;
529

530
                                size = max_size;
531
                        } else {
532
                                size = MIN((size_t) st.st_size, max_size);
603,718✔
533

534
                                if (size > READ_VIRTUAL_BYTES_MAX)
603,718✔
535
                                        return -EFBIG;
536
                        }
537

538
                        n_retries--;
603,718✔
539
                } else if (n_retries > 1) {
164,682✔
540
                        /* Files in /proc are generally smaller than the page size so let's start with
541
                         * a page size buffer from malloc and only use the max buffer on the final try. */
542
                        size = MIN3(page_size() - 1, READ_VIRTUAL_BYTES_MAX, max_size);
164,681✔
543
                        n_retries = 1;
164,681✔
544
                } else {
545
                        size = MIN(READ_VIRTUAL_BYTES_MAX, max_size);
1✔
546
                        n_retries = 0;
1✔
547
                }
548

549
                buf = malloc(size + 1);
768,400✔
550
                if (!buf)
768,400✔
551
                        return -ENOMEM;
552

553
                /* Use a bigger allocation if we got it anyway, but not more than the limit. */
554
                size = MIN3(MALLOC_SIZEOF_SAFE(buf) - 1, max_size, READ_VIRTUAL_BYTES_MAX);
768,400✔
555

556
                for (;;) {
768,400✔
557
                        ssize_t k;
768,400✔
558

559
                        /* Read one more byte so we can detect whether the content of the
560
                         * file has already changed or the guessed size for files from /proc
561
                         * wasn't large enough . */
562
                        k = read(fd, buf, size + 1);
768,400✔
563
                        if (k >= 0) {
768,400✔
564
                                n = k;
767,246✔
565
                                break;
767,246✔
566
                        }
567

568
                        if (errno != EINTR)
1,154✔
569
                                return -errno;
1,154✔
570
                }
571

572
                /* Consider a short read as EOF */
573
                if (n <= size)
767,246✔
574
                        break;
575

576
                /* If a maximum size is specified and we already read more we know the file is larger, and
577
                 * can handle this as truncation case. Note that if the size of what we read equals the
578
                 * maximum size then this doesn't mean truncation, the file might or might not end on that
579
                 * byte. We need to rerun the loop in that case, with a larger buffer size, so that we read
580
                 * at least one more byte to be able to distinguish EOF from truncation. */
581
                if (max_size != SIZE_MAX && n > max_size) {
35,889✔
582
                        n = size; /* Make sure we never use more than what we sized the buffer for (so that
583
                                   * we have one free byte in it for the trailing NUL we add below). */
584
                        truncated = true;
585
                        break;
586
                }
587

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

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

596
                if (lseek(fd, 0, SEEK_SET) < 0)
1✔
UNCOV
597
                        return -errno;
×
598

599
                buf = mfree(buf);
1✔
600
        }
601

602
        if (ret_contents) {
767,245✔
603

604
                /* Safety check: if the caller doesn't want to know the size of what we just read it will
605
                 * rely on the trailing NUL byte. But if there's an embedded NUL byte, then we should refuse
606
                 * operation as otherwise there'd be ambiguity about what we just read. */
607
                if (!ret_size && memchr(buf, 0, n))
731,578✔
608
                        return -EBADMSG;
609

610
                if (n < size) {
731,578✔
611
                        char *p;
723,769✔
612

613
                        /* Return rest of the buffer to libc */
614
                        p = realloc(buf, n + 1);
723,769✔
615
                        if (!p)
723,769✔
616
                                return -ENOMEM;
617
                        buf = p;
723,769✔
618
                }
619

620
                buf[n] = 0;
731,578✔
621
                *ret_contents = TAKE_PTR(buf);
731,578✔
622
        }
623

624
        if (ret_size)
767,245✔
625
                *ret_size = n;
617,133✔
626

627
        return !truncated;
767,245✔
628
}
629

630
int read_full_stream_full(
472,090✔
631
                FILE *f,
632
                const char *filename,
633
                uint64_t offset,
634
                size_t size,
635
                ReadFullFileFlags flags,
636
                char **ret_contents,
637
                size_t *ret_size) {
638

639
        _cleanup_free_ char *buf = NULL;
472,090✔
640
        size_t n, n_next = 0, l, expected_decoded_size = size;
472,090✔
641
        int fd, r;
472,090✔
642

643
        assert(f);
472,090✔
644
        assert(ret_contents);
472,090✔
645
        assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
472,090✔
646
        assert(size != SIZE_MAX || !FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER));
472,090✔
647

648
        if (offset != UINT64_MAX && offset > LONG_MAX) /* fseek() can only deal with "long" offsets */
472,090✔
649
                return -ERANGE;
650

651
        if ((flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) != 0) {
472,090✔
652
                if (size <= SIZE_MAX / READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY)
34✔
653
                        size *= READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY;
32✔
654
                else
655
                        size = SIZE_MAX;
656
        }
657

658
        fd = fileno(f);
472,090✔
659
        if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see
472,090✔
660
                        * fmemopen()), let's optimize our buffering */
661
                struct stat st;
472,000✔
662

663
                if (fstat(fd, &st) < 0)
472,000✔
UNCOV
664
                        return -errno;
×
665

666
                if (S_ISREG(st.st_mode)) {
472,000✔
667

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

674
                        if (st.st_size > 0 &&
471,583✔
675
                            (size == SIZE_MAX || FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER))) {
1,253✔
676

677
                                uint64_t rsize =
1,346,454✔
678
                                        LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset);
448,818✔
679

680
                                if (rsize < SIZE_MAX) /* overflow check */
448,818✔
681
                                        n_next = rsize + 1;
448,818✔
682
                        }
683

684
                        if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
471,583✔
685
                                (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
130✔
686
                }
687
        }
688

689
        /* If we don't know how much to read, figure it out now. If we shall read a part of the file, then
690
         * allocate the requested size. If we shall load the full file start with LINE_MAX. Note that if
691
         * READ_FULL_FILE_FAIL_WHEN_LARGER we consider the specified size a safety limit, and thus also start
692
         * with LINE_MAX, under assumption the file is most likely much shorter. */
693
        if (n_next == 0)
472,000✔
694
                n_next = size != SIZE_MAX && !FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) ? size : LINE_MAX;
23,272✔
695

696
        /* Never read more than we need to determine that our own limit is hit */
697
        if (n_next > READ_FULL_BYTES_MAX)
449,013✔
UNCOV
698
                n_next = READ_FULL_BYTES_MAX + 1;
×
699

700
        if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0)
472,090✔
UNCOV
701
                return -errno;
×
702

703
        n = l = 0;
704
        for (;;) {
472,380✔
705
                char *t;
472,235✔
706
                size_t k;
472,235✔
707

708
                /* If we shall fail when reading overly large data, then read exactly one byte more than the
709
                 * specified size at max, since that'll tell us if there's anymore data beyond the limit. */
710
                if (FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) && n_next > size)
472,235✔
711
                        n_next = size + 1;
8✔
712

713
                if (flags & READ_FULL_FILE_SECURE) {
472,235✔
714
                        t = malloc(n_next + 1);
1,449✔
715
                        if (!t) {
1,449✔
UNCOV
716
                                r = -ENOMEM;
×
UNCOV
717
                                goto finalize;
×
718
                        }
719
                        memcpy_safe(t, buf, n);
1,449✔
720
                        explicit_bzero_safe(buf, n);
1,449✔
721
                        free(buf);
1,449✔
722
                } else {
723
                        t = realloc(buf, n_next + 1);
470,786✔
724
                        if (!t)
470,786✔
725
                                return -ENOMEM;
726
                }
727

728
                buf = t;
472,235✔
729
                /* Unless a size has been explicitly specified, try to read as much as fits into the memory
730
                 * we allocated (minus 1, to leave one byte for the safety NUL byte) */
731
                n = size == SIZE_MAX ? MALLOC_SIZEOF_SAFE(buf) - 1 : n_next;
472,235✔
732

733
                errno = 0;
472,235✔
734
                k = fread(buf + l, 1, n - l, f);
472,235✔
735

736
                assert(k <= n - l);
472,235✔
737
                l += k;
472,235✔
738

739
                if (ferror(f)) {
472,235✔
740
                        r = errno_or_else(EIO);
2✔
741
                        goto finalize;
2✔
742
                }
743
                if (feof(f))
472,233✔
744
                        break;
745

746
                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 */
244✔
747
                        assert(l == size);
93✔
748
                        break;
749
                }
750

751
                assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
151✔
752

753
                if (FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) && l > size) {
151✔
754
                        r = -E2BIG;
6✔
755
                        goto finalize;
6✔
756
                }
757

758
                if (n >= READ_FULL_BYTES_MAX) {
145✔
UNCOV
759
                        r = -E2BIG;
×
UNCOV
760
                        goto finalize;
×
761
                }
762

763
                n_next = MIN(n * 2, READ_FULL_BYTES_MAX);
145✔
764
        }
765

766
        if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) {
472,082✔
767
                _cleanup_free_ void *decoded = NULL;
32✔
768
                size_t decoded_size;
32✔
769

770
                buf[l++] = 0;
32✔
771
                if (flags & READ_FULL_FILE_UNBASE64)
32✔
772
                        r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
30✔
773
                else
774
                        r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
2✔
775
                if (r < 0)
32✔
UNCOV
776
                        goto finalize;
×
777

778
                if (flags & READ_FULL_FILE_SECURE)
32✔
779
                        explicit_bzero_safe(buf, n);
14✔
780
                free_and_replace(buf, decoded);
32✔
781
                n = l = decoded_size;
32✔
782

783
                if (FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) && l > expected_decoded_size) {
32✔
UNCOV
784
                        r = -E2BIG;
×
UNCOV
785
                        goto finalize;
×
786
                }
787
        }
788

789
        if (!ret_size) {
472,082✔
790
                /* Safety check: if the caller doesn't want to know the size of what we just read it will rely on the
791
                 * trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise
792
                 * there'd be ambiguity about what we just read. */
793

794
                if (memchr(buf, 0, l)) {
336,169✔
795
                        r = -EBADMSG;
2✔
796
                        goto finalize;
2✔
797
                }
798
        }
799

800
        buf[l] = 0;
472,080✔
801
        *ret_contents = TAKE_PTR(buf);
472,080✔
802

803
        if (ret_size)
472,080✔
804
                *ret_size = l;
135,913✔
805

806
        return 0;
807

808
finalize:
10✔
809
        if (flags & READ_FULL_FILE_SECURE)
10✔
810
                explicit_bzero_safe(buf, n);
3✔
811

812
        return r;
813
}
814

815
int read_full_file_full(
663,902✔
816
                int dir_fd,
817
                const char *filename,
818
                uint64_t offset,
819
                size_t size,
820
                ReadFullFileFlags flags,
821
                const char *bind_name,
822
                char **ret_contents,
823
                size_t *ret_size) {
824

825
        _cleanup_fclose_ FILE *f = NULL;
663,902✔
826
        XfopenFlags xflags = XFOPEN_UNLOCKED;
663,902✔
827
        int r;
663,902✔
828

829
        assert(filename);
663,902✔
830
        assert(ret_contents);
663,902✔
831

832
        if (FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET) && /* If this is enabled, let's try to connect to it */
663,902✔
833
            offset == UINT64_MAX)                              /* Seeking is not supported on AF_UNIX sockets */
834
                xflags |= XFOPEN_SOCKET;
185✔
835

836
        r = xfopenat_full(dir_fd, filename, "re", 0, xflags, bind_name, &f);
663,902✔
837
        if (r < 0)
663,902✔
838
                return r;
839

840
        return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
457,366✔
841
}
842

843
int script_get_shebang_interpreter(const char *path, char **ret) {
8✔
844
        _cleanup_fclose_ FILE *f = NULL;
8✔
845
        int r;
8✔
846

847
        assert(path);
8✔
848

849
        f = fopen(path, "re");
8✔
850
        if (!f)
8✔
851
                return -errno;
1✔
852

853
        char c;
7✔
854
        r = safe_fgetc(f, &c);
7✔
855
        if (r < 0)
7✔
856
                return r;
857
        if (r == 0)
7✔
858
                return -EBADMSG;
859
        if (c != '#')
7✔
860
                return -EMEDIUMTYPE;
861
        r = safe_fgetc(f, &c);
2✔
862
        if (r < 0)
2✔
863
                return r;
864
        if (r == 0)
2✔
865
                return -EBADMSG;
866
        if (c != '!')
2✔
867
                return -EMEDIUMTYPE;
868

869
        _cleanup_free_ char *line = NULL;
2✔
870
        r = read_line(f, LONG_LINE_MAX, &line);
2✔
871
        if (r < 0)
2✔
872
                return r;
873

874
        _cleanup_free_ char *p = NULL;
2✔
875
        const char *s = line;
2✔
876

877
        r = extract_first_word(&s, &p, /* separators = */ NULL, /* flags = */ 0);
2✔
878
        if (r < 0)
2✔
879
                return r;
880
        if (r == 0)
2✔
881
                return -ENOEXEC;
882

883
        if (ret)
2✔
884
                *ret = TAKE_PTR(p);
2✔
885
        return 0;
886
}
887

888
int get_proc_field(const char *path, const char *key, char **ret) {
50,756✔
889
        _cleanup_fclose_ FILE *f = NULL;
50,756✔
890
        int r;
50,756✔
891

892
        /* Retrieve one field from a file like /proc/self/status. "key" matches the beginning of the line
893
         * and should not include whitespace or the delimiter (':').
894
         * Whitespaces after the ':' will be skipped. Only the first element is returned
895
         * (i.e. for /proc/meminfo line "MemTotal: 1024 kB" -> return "1024"). */
896

897
        assert(path);
50,756✔
898
        assert(key);
50,756✔
899

900
        r = fopen_unlocked(path, "re", &f);
50,756✔
901
        if (r == -ENOENT && proc_mounted() == 0)
50,756✔
902
                return -ENOSYS;
903
        if (r < 0)
50,744✔
904
                return r;
905

906
        for (;;) {
333,084✔
907
                 _cleanup_free_ char *line = NULL;
188,258✔
908

909
                 r = read_line(f, LONG_LINE_MAX, &line);
188,258✔
910
                 if (r < 0)
188,258✔
911
                         return r;
912
                 if (r == 0)
188,258✔
913
                         return -ENODATA;
914

915
                 char *l = startswith(line, key);
188,258✔
916
                 if (l && *l == ':') {
188,258✔
917
                         if (ret) {
43,432✔
918
                                 char *s = strdupcspn(skip_leading_chars(l + 1, " \t"), WHITESPACE);
43,432✔
919
                                 if (!s)
43,432✔
920
                                         return -ENOMEM;
921

922
                                 *ret = s;
43,432✔
923
                         }
924

925
                         return 0;
43,432✔
926
                 }
927
        }
928
}
929

930
DIR* xopendirat(int dir_fd, const char *name, int flags) {
225,495✔
931
        _cleanup_close_ int fd = -EBADF;
225,495✔
932

933
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
225,495✔
934
        assert(name);
225,495✔
935
        assert(!(flags & (O_CREAT|O_TMPFILE)));
225,495✔
936

937
        if (dir_fd == AT_FDCWD && flags == 0)
225,495✔
UNCOV
938
                return opendir(name);
×
939

940
        fd = openat(dir_fd, name, O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags);
225,495✔
941
        if (fd < 0)
225,495✔
942
                return NULL;
943

944
        return take_fdopendir(&fd);
224,996✔
945
}
946

947
int fopen_mode_to_flags(const char *mode) {
86,677✔
948
        const char *p;
86,677✔
949
        int flags;
86,677✔
950

951
        assert(mode);
86,677✔
952

953
        if ((p = startswith(mode, "r+")))
86,677✔
954
                flags = O_RDWR;
955
        else if ((p = startswith(mode, "r")))
86,676✔
956
                flags = O_RDONLY;
UNCOV
957
        else if ((p = startswith(mode, "w+")))
×
958
                flags = O_RDWR|O_CREAT|O_TRUNC;
UNCOV
959
        else if ((p = startswith(mode, "w")))
×
960
                flags = O_WRONLY|O_CREAT|O_TRUNC;
UNCOV
961
        else if ((p = startswith(mode, "a+")))
×
962
                flags = O_RDWR|O_CREAT|O_APPEND;
UNCOV
963
        else if ((p = startswith(mode, "a")))
×
964
                flags = O_WRONLY|O_CREAT|O_APPEND;
965
        else
966
                return -EINVAL;
967

968
        for (; *p != 0; p++) {
169,768✔
969

970
                switch (*p) {
83,091✔
971

972
                case 'e':
83,091✔
973
                        flags |= O_CLOEXEC;
83,091✔
974
                        break;
83,091✔
975

UNCOV
976
                case 'x':
×
UNCOV
977
                        flags |= O_EXCL;
×
UNCOV
978
                        break;
×
979

980
                case 'm':
981
                        /* ignore this here, fdopen() might care later though */
982
                        break;
983

984
                case 'c': /* not sure what to do about this one */
985
                default:
986
                        return -EINVAL;
987
                }
988
        }
989

990
        return flags;
991
}
992

993
static int xfopenat_regular(int dir_fd, const char *path, const char *mode, int open_flags, FILE **ret) {
919,884✔
994
        FILE *f;
919,884✔
995

996
        /* A combination of fopen() with openat() */
997

998
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
919,884✔
999
        assert(path);
919,884✔
1000
        assert(mode);
919,884✔
1001
        assert(ret);
919,884✔
1002

1003
        if (dir_fd == AT_FDCWD && open_flags == 0)
919,884✔
1004
                f = fopen(path, mode);
919,051✔
1005
        else {
1006
                _cleanup_close_ int fd = -EBADF;
833✔
1007
                int mode_flags;
833✔
1008

1009
                mode_flags = fopen_mode_to_flags(mode);
833✔
1010
                if (mode_flags < 0)
833✔
1011
                        return mode_flags;
1012

1013
                fd = openat(dir_fd, path, mode_flags | open_flags);
833✔
1014
                if (fd < 0)
833✔
1015
                        return -errno;
278✔
1016

1017
                f = take_fdopen(&fd, mode);
555✔
1018
        }
1019
        if (!f)
919,606✔
1020
                return -errno;
240,339✔
1021

1022
        *ret = f;
679,267✔
1023
        return 0;
679,267✔
1024
}
1025

1026
static int xfopenat_unix_socket(int dir_fd, const char *path, const char *bind_name, FILE **ret) {
1✔
1027
        _cleanup_close_ int sk = -EBADF;
1✔
1028
        FILE *f;
1✔
1029
        int r;
1✔
1030

1031
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
1✔
1032
        assert(path);
1✔
1033
        assert(ret);
1✔
1034

1035
        sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
1✔
1036
        if (sk < 0)
1✔
UNCOV
1037
                return -errno;
×
1038

1039
        if (bind_name) {
1✔
1040
                /* If the caller specified a socket name to bind to, do so before connecting. This is
1041
                 * useful to communicate some minor, short meta-information token from the client to
1042
                 * the server. */
1043
                union sockaddr_union bsa;
1✔
1044

1045
                r = sockaddr_un_set_path(&bsa.un, bind_name);
1✔
1046
                if (r < 0)
1✔
UNCOV
1047
                        return r;
×
1048

1049
                if (bind(sk, &bsa.sa, r) < 0)
1✔
UNCOV
1050
                        return -errno;
×
1051
        }
1052

1053
        r = connect_unix_path(sk, dir_fd, path);
1✔
1054
        if (r < 0)
1✔
1055
                return r;
1056

1057
        if (shutdown(sk, SHUT_WR) < 0)
1✔
UNCOV
1058
                return -errno;
×
1059

1060
        f = take_fdopen(&sk, "r");
1✔
1061
        if (!f)
1✔
UNCOV
1062
                return -errno;
×
1063

1064
        *ret = f;
1✔
1065
        return 0;
1✔
1066
}
1067

1068
int xfopenat_full(
919,884✔
1069
                int dir_fd,
1070
                const char *path,
1071
                const char *mode,
1072
                int open_flags,
1073
                XfopenFlags flags,
1074
                const char *bind_name,
1075
                FILE **ret) {
1076

1077
        FILE *f = NULL;  /* avoid false maybe-uninitialized warning */
919,884✔
1078
        int r;
919,884✔
1079

1080
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
919,884✔
1081
        assert(path);
919,884✔
1082
        assert(mode);
919,884✔
1083
        assert(ret);
919,884✔
1084

1085
        r = xfopenat_regular(dir_fd, path, mode, open_flags, &f);
919,884✔
1086
        if (r == -ENXIO && FLAGS_SET(flags, XFOPEN_SOCKET)) {
919,884✔
1087
                /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
1088
                r = xfopenat_unix_socket(dir_fd, path, bind_name, &f);
1✔
1089
                if (IN_SET(r, -ENOTSOCK, -EINVAL))
1✔
1090
                        return -ENXIO; /* propagate original error if this is not a socket after all */
919,884✔
1091
        }
1092
        if (r < 0)
919,884✔
1093
                return r;
1094

1095
        if (FLAGS_SET(flags, XFOPEN_UNLOCKED))
679,268✔
1096
                (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
679,036✔
1097

1098
        *ret = f;
679,268✔
1099
        return 0;
679,268✔
1100
}
1101

1102
int fdopen_independent(int fd, const char *mode, FILE **ret) {
10,972✔
1103
        _cleanup_close_ int copy_fd = -EBADF;
10,972✔
1104
        _cleanup_fclose_ FILE *f = NULL;
10,972✔
1105
        int mode_flags;
10,972✔
1106

1107
        assert(fd >= 0);
10,972✔
1108
        assert(mode);
10,972✔
1109
        assert(ret);
10,972✔
1110

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

1114
        mode_flags = fopen_mode_to_flags(mode);
10,972✔
1115
        if (mode_flags < 0)
10,972✔
1116
                return mode_flags;
1117

1118
        /* Flags returned by fopen_mode_to_flags might contain O_CREAT, but it doesn't make sense for fd_reopen
1119
         * since we're working on an existing fd anyway. Let's drop it here to avoid triggering assertion. */
1120
        copy_fd = fd_reopen(fd, mode_flags & ~O_CREAT);
10,972✔
1121
        if (copy_fd < 0)
10,972✔
1122
                return copy_fd;
1123

1124
        f = take_fdopen(&copy_fd, mode);
10,972✔
1125
        if (!f)
10,972✔
UNCOV
1126
                return -errno;
×
1127

1128
        *ret = TAKE_PTR(f);
10,972✔
1129
        return 0;
10,972✔
1130
}
1131

1132
static int search_and_open_internal(
28,130✔
1133
                const char *path,
1134
                int mode,            /* if ret_fd is NULL this is an [FRWX]_OK mode for access(), otherwise an open mode for open() */
1135
                const char *root,
1136
                char **search,
1137
                int *ret_fd,
1138
                char **ret_path) {
1139

1140
        int r;
28,130✔
1141

1142
        assert(!ret_fd || !FLAGS_SET(mode, O_CREAT)); /* We don't support O_CREAT for this */
28,130✔
1143
        assert(path);
28,130✔
1144

1145
        if (path_is_absolute(path)) {
28,130✔
UNCOV
1146
                _cleanup_close_ int fd = -EBADF;
×
1147

1148
                if (ret_fd)
5,374✔
1149
                        /* We only specify 0777 here to appease static analyzers, it's never used since we
1150
                         * don't support O_CREAT here */
1151
                        r = fd = RET_NERRNO(open(path, mode, 0777));
5,372✔
1152
                else
1153
                        r = RET_NERRNO(access(path, mode));
2✔
1154
                if (r < 0)
124✔
1155
                        return r;
1156

1157
                if (ret_path) {
5,250✔
1158
                        r = path_simplify_alloc(path, ret_path);
5,250✔
1159
                        if (r < 0)
5,250✔
1160
                                return r;
1161
                }
1162

1163
                if (ret_fd)
5,250✔
1164
                        *ret_fd = TAKE_FD(fd);
5,249✔
1165

1166
                return 0;
5,250✔
1167
        }
1168

1169
        if (!path_strv_resolve_uniq(search, root))
22,756✔
1170
                return -ENOMEM;
1171

1172
        STRV_FOREACH(i, search) {
127,706✔
1173
                _cleanup_close_ int fd = -EBADF;
133,080✔
1174
                _cleanup_free_ char *p = NULL;
106,643✔
1175

1176
                p = path_join(root, *i, path);
106,643✔
1177
                if (!p)
106,643✔
1178
                        return -ENOMEM;
1179

1180
                if (ret_fd)
106,643✔
1181
                        /* as above, 0777 is static analyzer appeasement */
1182
                        r = fd = RET_NERRNO(open(p, mode, 0777));
106,325✔
1183
                else
1184
                        r = RET_NERRNO(access(p, F_OK));
318✔
1185
                if (r >= 0) {
104,950✔
1186
                        if (ret_path)
1,693✔
1187
                                *ret_path = path_simplify(TAKE_PTR(p));
1,693✔
1188

1189
                        if (ret_fd)
1,693✔
1190
                                *ret_fd = TAKE_FD(fd);
1,686✔
1191

1192
                        return 0;
1,693✔
1193
                }
1194
                if (r != -ENOENT)
104,950✔
1195
                        return r;
1196
        }
1197

1198
        return -ENOENT;
1199
}
1200

1201
int search_and_open(
28,130✔
1202
                const char *path,
1203
                int mode,
1204
                const char *root,
1205
                char **search,
1206
                int *ret_fd,
1207
                char **ret_path) {
1208

1209
        _cleanup_strv_free_ char **copy = NULL;
28,130✔
1210

1211
        assert(path);
28,130✔
1212

1213
        copy = strv_copy((char**) search);
28,130✔
1214
        if (!copy)
28,130✔
1215
                return -ENOMEM;
1216

1217
        return search_and_open_internal(path, mode, root, copy, ret_fd, ret_path);
28,130✔
1218
}
1219

1220
static int search_and_fopen_internal(
28,125✔
1221
                const char *path,
1222
                const char *mode,
1223
                const char *root,
1224
                char **search,
1225
                FILE **ret_file,
1226
                char **ret_path) {
1227

1228
        _cleanup_free_ char *found_path = NULL;
28,125✔
1229
        _cleanup_close_ int fd = -EBADF;
28,125✔
1230
        int r;
28,125✔
1231

1232
        assert(path);
28,125✔
1233
        assert(mode || !ret_file);
28,125✔
1234

1235
        r = search_and_open(
56,353✔
1236
                        path,
1237
                        mode ? fopen_mode_to_flags(mode) : 0,
27,974✔
1238
                        root,
1239
                        search,
1240
                        ret_file ? &fd : NULL,
1241
                        ret_path ? &found_path : NULL);
1242
        if (r < 0)
28,125✔
1243
                return r;
1244

1245
        if (ret_file) {
6,938✔
1246
                FILE *f = take_fdopen(&fd, mode);
6,935✔
1247
                if (!f)
6,935✔
UNCOV
1248
                        return -errno;
×
1249

1250
                *ret_file = f;
6,935✔
1251
        }
1252

1253
        if (ret_path)
6,938✔
1254
                *ret_path = TAKE_PTR(found_path);
6,938✔
1255

1256
        return 0;
1257
}
1258

1259
int search_and_fopen(
5,379✔
1260
                const char *path,
1261
                const char *mode,
1262
                const char *root,
1263
                const char **search,
1264
                FILE **ret_file,
1265
                char **ret_path) {
1266

1267
        _cleanup_strv_free_ char **copy = NULL;
5,379✔
1268

1269
        assert(path);
5,379✔
1270
        assert(mode || !ret_file);
5,379✔
1271

1272
        copy = strv_copy((char**) search);
5,379✔
1273
        if (!copy)
5,379✔
1274
                return -ENOMEM;
1275

1276
        return search_and_fopen_internal(path, mode, root, copy, ret_file, ret_path);
5,379✔
1277
}
1278

1279
int search_and_fopen_nulstr(
22,746✔
1280
                const char *path,
1281
                const char *mode,
1282
                const char *root,
1283
                const char *search,
1284
                FILE **ret_file,
1285
                char **ret_path) {
1286

1287
        _cleanup_strv_free_ char **l = NULL;
22,746✔
1288

1289
        assert(path);
22,746✔
1290
        assert(mode || !ret_file);
22,746✔
1291

1292
        l = strv_split_nulstr(search);
22,746✔
1293
        if (!l)
22,746✔
1294
                return -ENOMEM;
1295

1296
        return search_and_fopen_internal(path, mode, root, l, ret_file, ret_path);
22,746✔
1297
}
1298

1299
int fflush_and_check(FILE *f) {
1,016,248✔
1300
        assert(f);
1,016,248✔
1301

1302
        errno = 0;
1,016,248✔
1303
        fflush(f);
1,016,248✔
1304

1305
        if (ferror(f))
1,016,248✔
1306
                return errno_or_else(EIO);
24✔
1307

1308
        return 0;
1309
}
1310

1311
int fflush_sync_and_check(FILE *f) {
2,142✔
1312
        int r, fd;
2,142✔
1313

1314
        assert(f);
2,142✔
1315

1316
        r = fflush_and_check(f);
2,142✔
1317
        if (r < 0)
2,142✔
1318
                return r;
1319

1320
        /* Not all file streams have an fd associated (think: fmemopen()), let's handle this gracefully and
1321
         * assume that in that case we need no explicit syncing */
1322
        fd = fileno(f);
2,142✔
1323
        if (fd < 0)
2,142✔
1324
                return 0;
1325

1326
        r = fsync_full(fd);
2,142✔
1327
        if (r < 0)
2,142✔
UNCOV
1328
                return r;
×
1329

1330
        return 0;
1331
}
1332

1333
int write_timestamp_file_atomic(const char *fn, usec_t n) {
145✔
1334
        char ln[DECIMAL_STR_MAX(n)+2];
145✔
1335

1336
        /* Creates a "timestamp" file, that contains nothing but a
1337
         * usec_t timestamp, formatted in ASCII. */
1338

1339
        if (!timestamp_is_set(n))
145✔
1340
                return -ERANGE;
145✔
1341

1342
        xsprintf(ln, USEC_FMT "\n", n);
145✔
1343

1344
        return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
145✔
1345
}
1346

1347
int read_timestamp_file(const char *fn, usec_t *ret) {
24✔
1348
        _cleanup_free_ char *ln = NULL;
24✔
1349
        uint64_t t;
24✔
1350
        int r;
24✔
1351

1352
        r = read_one_line_file(fn, &ln);
24✔
1353
        if (r < 0)
24✔
1354
                return r;
1355

UNCOV
1356
        r = safe_atou64(ln, &t);
×
UNCOV
1357
        if (r < 0)
×
1358
                return r;
1359

UNCOV
1360
        if (!timestamp_is_set(t))
×
1361
                return -ERANGE;
1362

UNCOV
1363
        *ret = (usec_t) t;
×
UNCOV
1364
        return 0;
×
1365
}
1366

1367
int fputs_with_separator(FILE *f, const char *s, const char *separator, bool *space) {
3,098✔
1368
        assert(s);
3,098✔
1369
        assert(space);
3,098✔
1370

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

1376
        if (!f)
3,098✔
UNCOV
1377
                f = stdout;
×
1378

1379
        if (!separator)
3,098✔
1380
                separator = " ";
1,415✔
1381

1382
        if (*space)
3,098✔
1383
                if (fputs(separator, f) < 0)
1,361✔
1384
                        return -EIO;
1385

1386
        *space = true;
3,098✔
1387

1388
        if (fputs(s, f) < 0)
3,098✔
UNCOV
1389
                return -EIO;
×
1390

1391
        return 0;
1392
}
1393

1394
int fputs_with_newline(FILE *f, const char *s) {
775✔
1395

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

1399
        if (isempty(s))
775✔
1400
                return 0;
1401

1402
        if (!f)
775✔
UNCOV
1403
                f = stdout;
×
1404

1405
        if (fputs(s, f) < 0)
775✔
1406
                return -EIO;
1407

1408
        if (endswith(s, "\n"))
775✔
1409
                return 0;
1410

1411
        if (fputc('\n', f) < 0)
627✔
UNCOV
1412
                return -EIO;
×
1413

1414
        return 1;
1415
}
1416

1417
/* A bitmask of the EOL markers we know */
1418
typedef enum EndOfLineMarker {
1419
        EOL_NONE     = 0,
1420
        EOL_ZERO     = 1 << 0,  /* \0 (aka NUL) */
1421
        EOL_TEN      = 1 << 1,  /* \n (aka NL, aka LF)  */
1422
        EOL_THIRTEEN = 1 << 2,  /* \r (aka CR)  */
1423
} EndOfLineMarker;
1424

1425
static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
202,451,890✔
1426

1427
        if (!FLAGS_SET(flags, READ_LINE_ONLY_NUL)) {
202,451,890✔
1428
                if (c == '\n')
201,760,882✔
1429
                        return EOL_TEN;
1430
                if (c == '\r')
195,119,892✔
1431
                        return EOL_THIRTEEN;
1432
        }
1433

1434
        if (c == '\0')
195,810,884✔
1435
                return EOL_ZERO;
21,706✔
1436

1437
        return EOL_NONE;
1438
}
1439

1440
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, funlockfile, NULL);
6,223,768✔
1441

1442
int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
6,223,768✔
1443
        _cleanup_free_ char *buffer = NULL;
6,223,768✔
1444
        size_t n = 0, count = 0;
6,223,768✔
1445
        int r;
6,223,768✔
1446

1447
        assert(f);
6,223,768✔
1448

1449
        /* Something like a bounded version of getline().
1450
         *
1451
         * Considers EOF, \n, \r and \0 end of line delimiters (or combinations of these), and does not include these
1452
         * delimiters in the string returned. Specifically, recognizes the following combinations of markers as line
1453
         * endings:
1454
         *
1455
         *     • \n        (UNIX)
1456
         *     • \r        (old MacOS)
1457
         *     • \0        (C strings)
1458
         *     • \n\0
1459
         *     • \r\0
1460
         *     • \r\n      (Windows)
1461
         *     • \n\r
1462
         *     • \r\n\0
1463
         *     • \n\r\0
1464
         *
1465
         * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
1466
         * the number of characters in the returned string). When EOF is hit, 0 is returned.
1467
         *
1468
         * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
1469
         * delimiters. If the limit is hit we fail and return -ENOBUFS.
1470
         *
1471
         * If a line shall be skipped ret may be initialized as NULL. */
1472

1473
        if (ret) {
6,223,768✔
1474
                if (!GREEDY_REALLOC(buffer, 1))
6,223,737✔
1475
                        return -ENOMEM;
1476
        }
1477

1478
        {
1479
                _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
6,223,768✔
1480
                EndOfLineMarker previous_eol = EOL_NONE;
6,223,768✔
1481
                flockfile(f);
6,223,768✔
1482

1483
                for (;;) {
202,913,544✔
1484
                        EndOfLineMarker eol;
202,913,544✔
1485
                        char c;
202,913,544✔
1486

1487
                        if (n >= limit)
202,913,544✔
1488
                                return -ENOBUFS;
13✔
1489

1490
                        if (count >= INT_MAX) /* We couldn't return the counter anymore as "int", hence refuse this */
202,913,538✔
1491
                                return -ENOBUFS;
1492

1493
                        r = safe_fgetc(f, &c);
202,913,538✔
1494
                        if (r < 0)
202,913,538✔
1495
                                return r;
1496
                        if (r == 0) /* EOF is definitely EOL */
202,913,531✔
1497
                                break;
1498

1499
                        eol = categorize_eol(c, flags);
202,451,890✔
1500

1501
                        if (FLAGS_SET(previous_eol, EOL_ZERO) ||
202,451,890✔
1502
                            (eol == EOL_NONE && previous_eol != EOL_NONE) ||
202,433,029✔
1503
                            (eol != EOL_NONE && (previous_eol & eol) != 0)) {
6,662,706✔
1504
                                /* Previous char was a NUL? This is not an EOL, but the previous char was? This type of
1505
                                 * EOL marker has been seen right before?  In either of these three cases we are
1506
                                 * done. But first, let's put this character back in the queue. (Note that we have to
1507
                                 * cast this to (unsigned char) here as ungetc() expects a positive 'int', and if we
1508
                                 * are on an architecture where 'char' equals 'signed char' we need to ensure we don't
1509
                                 * pass a negative value here. That said, to complicate things further ungetc() is
1510
                                 * actually happy with most negative characters and implicitly casts them back to
1511
                                 * positive ones as needed, except for \xff (aka -1, aka EOF), which it refuses. What a
1512
                                 * godawful API!) */
1513
                                assert_se(ungetc((unsigned char) c, f) != EOF);
5,762,114✔
1514
                                break;
1515
                        }
1516

1517
                        count++;
196,689,776✔
1518

1519
                        if (eol != EOL_NONE) {
190,604,499✔
1520
                                /* If we are on a tty, we can't shouldn't wait for more input, because that
1521
                                 * generally means waiting for the user, interactively. In the case of a TTY
1522
                                 * we expect only \n as the single EOL marker, so we are in the lucky
1523
                                 * position that there is no need to wait. We check this condition last, to
1524
                                 * avoid isatty() check if not necessary. */
1525

1526
                                if ((flags & (READ_LINE_IS_A_TTY|READ_LINE_NOT_A_TTY)) == 0) {
6,085,277✔
1527
                                        int fd;
5,363,833✔
1528

1529
                                        fd = fileno(f);
5,363,833✔
1530
                                        if (fd < 0) /* Maybe an fmemopen() stream? Handle this gracefully,
5,363,833✔
1531
                                                     * and don't call isatty() on an invalid fd */
1532
                                                flags |= READ_LINE_NOT_A_TTY;
28✔
1533
                                        else
1534
                                                flags |= isatty_safe(fd) ? READ_LINE_IS_A_TTY : READ_LINE_NOT_A_TTY;
10,727,610✔
1535
                                }
1536
                                if (FLAGS_SET(flags, READ_LINE_IS_A_TTY))
6,085,277✔
1537
                                        break;
1538
                        }
1539

1540
                        if (eol != EOL_NONE) {
196,689,776✔
1541
                                previous_eol |= eol;
6,085,277✔
1542
                                continue;
6,085,277✔
1543
                        }
1544

1545
                        if (ret) {
190,604,499✔
1546
                                if (!GREEDY_REALLOC(buffer, n + 2))
190,604,399✔
1547
                                        return -ENOMEM;
1548

1549
                                buffer[n] = c;
190,604,399✔
1550
                        }
1551

1552
                        n++;
190,604,499✔
1553
                }
1554
        }
1555

1556
        if (ret) {
6,223,755✔
1557
                buffer[n] = 0;
6,223,724✔
1558

1559
                *ret = TAKE_PTR(buffer);
6,223,724✔
1560
        }
1561

1562
        return (int) count;
6,223,755✔
1563
}
1564

1565
int read_stripped_line(FILE *f, size_t limit, char **ret) {
2,644,136✔
1566
        _cleanup_free_ char *s = NULL;
2,644,136✔
1567
        int r, k;
2,644,136✔
1568

1569
        assert(f);
2,644,136✔
1570

1571
        r = read_line(f, limit, ret ? &s : NULL);
2,644,136✔
1572
        if (r < 0)
2,644,136✔
1573
                return r;
1574

1575
        if (ret) {
2,644,136✔
1576
                const char *p = strstrip(s);
2,644,136✔
1577
                if (p == s)
2,644,136✔
1578
                        *ret = TAKE_PTR(s);
2,644,133✔
1579
                else {
1580
                        k = strdup_to(ret, p);
3✔
1581
                        if (k < 0)
3✔
1582
                                return k;
1583
                }
1584
        }
1585

1586
        return r > 0;          /* Return 1 if something was read. */
2,644,136✔
1587
}
1588

1589
int safe_fgetc(FILE *f, char *ret) {
202,920,418✔
1590
        int k;
202,920,418✔
1591

1592
        assert(f);
202,920,418✔
1593

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

1598
        errno = 0;
202,920,418✔
1599
        k = fgetc(f);
202,920,418✔
1600
        if (k == EOF) {
202,920,418✔
1601
                if (ferror(f))
461,741✔
1602
                        return errno_or_else(EIO);
14✔
1603

1604
                if (ret)
461,734✔
1605
                        *ret = 0;
461,658✔
1606

1607
                return 0;
461,734✔
1608
        }
1609

1610
        if (ret)
202,458,677✔
1611
                *ret = k;
202,458,677✔
1612

1613
        return 1;
1614
}
1615

1616
int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line) {
152✔
1617
        struct stat _st;
152✔
1618

1619
        if (!filename)
152✔
1620
                return 0;
152✔
1621

1622
        if (!st) {
152✔
1623
                if (stat(filename, &_st) < 0)
22✔
UNCOV
1624
                        return -errno;
×
1625
                st = &_st;
1626
        }
1627

1628
        if ((st->st_mode & S_IRWXO) == 0)
152✔
1629
                return 0;
1630

1631
        if (unit)
35✔
UNCOV
1632
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1633
                           "%s has %04o mode that is too permissive, please adjust the ownership and access mode.",
1634
                           filename, st->st_mode & 07777);
1635
        else
1636
                log_warning("%s has %04o mode that is too permissive, please adjust the ownership and access mode.",
35✔
1637
                            filename, st->st_mode & 07777);
1638
        return 0;
1639
}
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