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

systemd / systemd / 23672908348

27 Mar 2026 10:16PM UTC coverage: 72.401% (+0.3%) from 72.113%
23672908348

push

github

daandemeyer
boot-entry: add 'auto' keyword to parse_boot_entry_token_type

Add the auto keyword as documented in the help message and man pages of
`kernel-install`, `bootctl` and `systemd-pcrlock`.

0 of 4 new or added lines in 1 file covered. (0.0%)

2759 existing lines in 71 files now uncovered.

318227 of 439535 relevant lines covered (72.4%)

1197709.62 hits per line

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

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

3
#include <stdlib.h>
4
#include <unistd.h>
5

6
#include "alloc-util.h"
7
#include "errno-util.h"
8
#include "fd-util.h"
9
#include "fileio.h"
10
#include "fs-util.h"
11
#include "log.h"
12
#include "path-util.h"
13
#include "random-util.h"
14
#include "string-util.h"
15
#include "sync-util.h"
16
#include "tmpfile-util.h"
17
#include "umask-util.h"
18

19
static int fopen_temporary_internal(int dir_fd, const char *path, FILE **ret_file) {
186,550✔
20
        _cleanup_fclose_ FILE *f = NULL;
186,550✔
21
        _cleanup_close_ int fd = -EBADF;
186,550✔
22
        int r;
186,550✔
23

24
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
186,550✔
25
        assert(path);
186,550✔
26

27
        fd = openat(dir_fd, path, O_CLOEXEC|O_NOCTTY|O_RDWR|O_CREAT|O_EXCL, 0600);
186,550✔
28
        if (fd < 0)
186,550✔
29
                return -errno;
1✔
30

31
        /* This assumes that returned FILE object is short-lived and used within the same single-threaded
32
         * context and never shared externally, hence locking is not necessary. */
33

34
        r = take_fdopen_unlocked(&fd, "w", &f);
186,549✔
35
        if (r < 0) {
186,549✔
36
                (void) unlinkat(dir_fd, path, 0);
×
37
                return r;
×
38
        }
39

40
        if (ret_file)
186,549✔
41
                *ret_file = TAKE_PTR(f);
186,549✔
42

43
        return 0;
44
}
45

46
int fopen_temporary_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path) {
186,546✔
47
        _cleanup_free_ char *t = NULL;
186,546✔
48
        int r;
186,546✔
49

50
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
186,546✔
51
        assert(path);
186,546✔
52

53
        r = tempfn_random(path, NULL, &t);
186,546✔
54
        if (r < 0)
186,546✔
55
                return r;
56

57
        r = fopen_temporary_internal(dir_fd, t, ret_file);
186,546✔
58
        if (r < 0)
186,546✔
59
                return r;
60

61
        if (ret_path)
186,545✔
62
                *ret_path = TAKE_PTR(t);
186,545✔
63

64
        return 0;
65
}
66

67
int fopen_temporary_child_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path) {
4✔
68
        _cleanup_free_ char *t = NULL;
4✔
69
        int r;
4✔
70

71
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
4✔
72

73
        if (!path) {
4✔
74
                r = tmp_dir(&path);
1✔
75
                if (r < 0)
1✔
76
                        return r;
77
        }
78

79
        r = tempfn_random_child(path, NULL, &t);
4✔
80
        if (r < 0)
4✔
81
                return r;
82

83
        r = fopen_temporary_internal(dir_fd, t, ret_file);
4✔
84
        if (r < 0)
4✔
85
                return r;
86

87
        if (ret_path)
4✔
88
                *ret_path = TAKE_PTR(t);
4✔
89

90
        return 0;
91
}
92

93
/* This is much like mkostemp() but is subject to umask(). */
94
int mkostemp_safe(char *pattern) {
247✔
95
        assert(pattern);
247✔
96
        BLOCK_WITH_UMASK(0077);
247✔
97
        return RET_NERRNO(mkostemp(pattern, O_CLOEXEC));
247✔
98
}
99

100
int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
40✔
101
        _cleanup_close_ int fd = -EBADF;
40✔
102
        FILE *f;
40✔
103

104
        fd = mkostemp_safe(pattern);
40✔
105
        if (fd < 0)
40✔
106
                return fd;
107

108
        f = take_fdopen(&fd, mode);
40✔
109
        if (!f)
40✔
110
                return -errno;
×
111

112
        *ret_f = f;
40✔
113
        return 0;
40✔
114
}
115

116
void unlink_tempfilep(char (*p)[]) {
120✔
117
        assert(p);
120✔
118

119
        /* If the file is created with mkstemp(), it will (almost always) change the suffix.
120
         * Treat this as a sign that the file was successfully created. We ignore both the rare case
121
         * where the original suffix is used and unlink failures. */
122

123
        if (!endswith(*p, ".XXXXXX"))
120✔
124
                (void) unlink(*p);
118✔
125
}
120✔
126

127
static int tempfn_build(const char *p, const char *pre, const char *post, bool child, char **ret) {
336,568✔
128
        _cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL, *result = NULL;
336,568✔
129
        size_t len_pre, len_post, len_add;
336,568✔
130
        int r;
336,568✔
131

132
        assert(p);
336,568✔
133
        assert(ret);
336,568✔
134

135
        /*
136
         * Turns this:
137
         *         /foo/bar/waldo
138
         *
139
         * Into this :
140
         *         /foo/bar/waldo/.#<pre><post> (child == true)
141
         *         /foo/bar/.#<pre>waldo<post> (child == false)
142
         */
143

144
        if (pre && strchr(pre, '/'))
336,568✔
145
                return -EINVAL;
146

147
        if (post && strchr(post, '/'))
336,565✔
148
                return -EINVAL;
149

150
        len_pre = strlen_ptr(pre);
336,565✔
151
        len_post = strlen_ptr(post);
336,565✔
152
        /* NAME_MAX is counted *without* the trailing NUL byte. */
153
        if (len_pre > NAME_MAX - STRLEN(".#") ||
336,565✔
154
            len_post > NAME_MAX - STRLEN(".#") - len_pre)
336,565✔
155
                return -EINVAL;
156

157
        len_add = len_pre + len_post + STRLEN(".#");
336,565✔
158

159
        if (child) {
336,565✔
160
                d = strdup(p);
698✔
161
                if (!d)
698✔
162
                        return -ENOMEM;
163
        } else {
164
                r = path_split_prefix_filename(p, &d, &fn);
335,867✔
165
                if (r < 0)
335,867✔
166
                        return r;
167

168
                /* Truncate the filename if it would become too long after mangling. */
169
                strshorten(fn, NAME_MAX - len_add);
335,859✔
170
        }
171

172
        nf = strjoin(".#", strempty(pre), strempty(fn), strempty(post));
673,053✔
173
        if (!nf)
336,557✔
174
                return -ENOMEM;
175

176
        if (d) {
336,557✔
177
                if (!path_extend(&d, nf))
329,894✔
178
                        return -ENOMEM;
179

180
                result = path_simplify(TAKE_PTR(d));
329,894✔
181
        } else
182
                result = TAKE_PTR(nf);
183

184
        if (!path_is_valid(result)) /* New path is not valid? (Maybe because too long?) Refuse. */
336,557✔
185
                return -EINVAL;
186

187
        *ret = TAKE_PTR(result);
336,554✔
188
        return 0;
336,554✔
189
}
190

191
int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
27✔
192
        /*
193
         * Turns this:
194
         *         /foo/bar/waldo
195
         *
196
         * Into this:
197
         *         /foo/bar/.#<extra>waldoXXXXXX
198
         */
199

200
        return tempfn_build(p, extra, "XXXXXX", /* child= */ false, ret);
27✔
201
}
202

203
int tempfn_random(const char *p, const char *extra, char **ret) {
335,842✔
204
        _cleanup_free_ char *s = NULL;
335,842✔
205

206
        assert(p);
335,842✔
207
        assert(ret);
335,842✔
208

209
        /*
210
         * Turns this:
211
         *         /foo/bar/waldo
212
         *
213
         * Into this:
214
         *         /foo/bar/.#<extra>waldobaa2a261115984a9
215
         */
216

217
        if (asprintf(&s, "%016" PRIx64, random_u64()) < 0)
335,842✔
218
                return -ENOMEM;
219

220
        return tempfn_build(p, extra, s, /* child= */ false, ret);
335,842✔
221
}
222

223
int tempfn_random_child(const char *p, const char *extra, char **ret) {
699✔
224
        _cleanup_free_ char *s = NULL;
699✔
225
        int r;
699✔
226

227
        assert(ret);
699✔
228

229
        /* Turns this:
230
         *         /foo/bar/waldo
231
         * Into this:
232
         *         /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
233
         */
234

235
        if (!p) {
699✔
236
                r = tmp_dir(&p);
15✔
237
                if (r < 0)
15✔
238
                        return r;
239
        }
240

241
        if (asprintf(&s, "%016" PRIx64, random_u64()) < 0)
699✔
242
                return -ENOMEM;
243

244
        return tempfn_build(p, extra, s, /* child= */ true, ret);
699✔
245
}
246

247
int open_tmpfile_unlinkable(const char *directory, int flags) {
6,371✔
248
        int r;
6,371✔
249

250
        if (!directory) {
6,371✔
251
                r = tmp_dir(&directory);
7✔
252
                if (r < 0)
7✔
253
                        return r;
6,371✔
254
        } else if (isempty(directory))
12,735✔
255
                return -EINVAL;
256

257
        /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
258

259
        /* Try O_TMPFILE first, if it is supported */
260
        int fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
6,371✔
261
        if (fd >= 0)
6,371✔
262
                return fd;
263

264
        /* Fall back to unguessable name + unlinking */
265
        _cleanup_free_ char *p = path_join(directory, "/systemd-tmp-XXXXXX");
×
266
        if (!p)
×
267
                return -ENOMEM;
268

269
        fd = mkostemp_safe(p);
×
270
        if (fd < 0)
×
271
                return fd;
272

273
        (void) unlink(p);
×
274

275
        return fd;
×
276
}
277

278
int open_tmpfile_linkable_at(int dir_fd, const char *target, int flags, char **ret_path) {
24,169✔
279
        int r;
24,169✔
280

281
        assert(target);
24,169✔
282
        assert(ret_path);
24,169✔
283

284
        /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
285
        assert((flags & O_EXCL) == 0);
24,169✔
286

287
        /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
288
         * which case "ret_path" will be returned as NULL. If not possible the temporary path name used is returned in
289
         * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
290

291
        int fd = open_parent_at(dir_fd, target, O_TMPFILE|flags, 0640);
24,169✔
292
        if (fd >= 0) {
24,169✔
293
                *ret_path = NULL;
24,077✔
294
                return fd;
24,169✔
295
        }
296

297
        if (!ERRNO_IS_NEG_NOT_SUPPORTED(fd))
92✔
298
                log_debug_errno(fd, "Failed to use O_TMPFILE for %s: %m", target);
33✔
299

300
        _cleanup_free_ char *tmp = NULL;
92✔
301
        r = tempfn_random(target, NULL, &tmp);
92✔
302
        if (r < 0)
92✔
303
                return r;
304

305
        fd = openat(dir_fd, tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
92✔
306
        if (fd < 0)
92✔
307
                return -errno;
33✔
308

309
        *ret_path = TAKE_PTR(tmp);
59✔
310

311
        return fd;
59✔
312
}
313

314
int fopen_tmpfile_linkable_at(int dir_fd, const char *target, int flags, char **ret_path, FILE **ret_file) {
5,738✔
315
        _cleanup_free_ char *path = NULL;
5,738✔
316
        _cleanup_fclose_ FILE *f = NULL;
5,738✔
317
        _cleanup_close_ int fd = -EBADF;
5,738✔
318

319
        assert(target);
5,738✔
320
        assert(ret_file);
5,738✔
321
        assert(ret_path);
5,738✔
322

323
        fd = open_tmpfile_linkable_at(dir_fd, target, flags, &path);
5,738✔
324
        if (fd < 0)
5,738✔
325
                return fd;
326

327
        f = take_fdopen(&fd, "w");
5,738✔
328
        if (!f)
5,738✔
329
                return -ENOMEM;
330

331
        *ret_path = TAKE_PTR(path);
5,738✔
332
        *ret_file = TAKE_PTR(f);
5,738✔
333
        return 0;
5,738✔
334
}
335

336
int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, LinkTmpfileFlags flags) {
23,948✔
337
        int r;
23,948✔
338

339
        assert(fd >= 0);
23,948✔
340
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
23,948✔
341
        assert(target);
23,948✔
342

343
        /* Moves a temporary file created with open_tmpfile() above into its final place. If "path" is NULL
344
         * an fd created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE
345
         * is not supported on the directory, and renameat2() is used instead. */
346

347
        if (FLAGS_SET(flags, LINK_TMPFILE_SYNC) && fsync(fd) < 0)
23,948✔
UNCOV
348
                return -errno;
×
349

350
        if (path) {
23,948✔
351
                if (FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
59✔
352
                        r = RET_NERRNO(renameat(dir_fd, path, dir_fd, target));
38✔
353
                else
354
                        r = rename_noreplace(dir_fd, path, dir_fd, target);
21✔
355
        } else {
356
                if (FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
23,889✔
357
                        r = linkat_replace(fd, /* oldpath= */ NULL, dir_fd, target);
22,823✔
358
                else
359
                        r = link_fd(fd, dir_fd, target);
1,066✔
360
        }
361
        if (r < 0)
23,910✔
362
                return r;
363

364
        if (FLAGS_SET(flags, LINK_TMPFILE_SYNC)) {
23,944✔
365
                r = fsync_full(fd);
1,693✔
366
                if (r < 0)
1,693✔
UNCOV
367
                        return r;
×
368
        }
369

370
        return 0;
371
}
372

373
int flink_tmpfile_at(FILE *f, int dir_fd, const char *path, const char *target, LinkTmpfileFlags flags) {
5,738✔
374
        int fd, r;
5,738✔
375

376
        assert(f);
5,738✔
377
        assert(target);
5,738✔
378

379
        fd = fileno(f);
5,738✔
380
        if (fd < 0) /* Not all FILE* objects encapsulate fds */
5,738✔
381
                return -EBADF;
382

383
        r = fflush_and_check(f);
5,738✔
384
        if (r < 0)
5,738✔
385
                return r;
386

387
        return link_tmpfile_at(fd, dir_fd, path, target, flags);
5,738✔
388
}
389

390
int mkdtemp_malloc(const char *template, char **ret) {
4,560✔
391
        _cleanup_free_ char *p = NULL;
9,120✔
392
        int r;
4,560✔
393

394
        assert(ret);
4,560✔
395

396
        if (template)
4,560✔
397
                p = strdup(template);
4,431✔
398
        else {
399
                const char *tmp;
129✔
400

401
                r = tmp_dir(&tmp);
129✔
402
                if (r < 0)
129✔
UNCOV
403
                        return r;
×
404

405
                p = path_join(tmp, "XXXXXX");
129✔
406
        }
407
        if (!p)
4,560✔
408
                return -ENOMEM;
409

410
        if (!mkdtemp(p))
4,560✔
UNCOV
411
                return -errno;
×
412

413
        *ret = TAKE_PTR(p);
4,560✔
414
        return 0;
4,560✔
415
}
416

417
int mkdtemp_open(const char *template, int flags, char **ret) {
55✔
418
        _cleanup_free_ char *p = NULL;
55✔
419
        int fd, r;
55✔
420

421
        r = mkdtemp_malloc(template, &p);
55✔
422
        if (r < 0)
55✔
423
                return r;
424

425
        fd = RET_NERRNO(open(p, O_DIRECTORY|O_CLOEXEC|flags));
55✔
426
        if (fd < 0) {
×
427
                (void) rmdir(p);
×
UNCOV
428
                return fd;
×
429
        }
430

431
        if (ret)
55✔
432
                *ret = TAKE_PTR(p);
55✔
433

434
        return fd;
435
}
436

437
void cleanup_tmpfile_data_done(struct cleanup_tmpfile_data *d) {
18,725✔
438
        assert(d);
18,725✔
439

440
        if (!d->dir_fd ||
18,725✔
441
            (*d->dir_fd < 0 && *d->dir_fd != AT_FDCWD) ||
18,725✔
442
            !d->filename ||
18,725✔
443
            !*d->filename)
18,725✔
444
                return;
18,724✔
445

446
        PROTECT_ERRNO;
2✔
447

448
        (void) unlinkat(*d->dir_fd, *d->filename, /* flags= */ 0);
1✔
449
        d->dir_fd = NULL;
1✔
450
        d->filename = NULL;
1✔
451
}
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