• 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

96.26
/src/basic/env-file.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <unistd.h>
4

5
#include "alloc-util.h"
6
#include "env-file.h"
7
#include "env-util.h"
8
#include "escape.h"
9
#include "fd-util.h"
10
#include "fileio.h"
11
#include "fs-util.h"
12
#include "log.h"
13
#include "string-util.h"
14
#include "strv.h"
15
#include "tmpfile-util.h"
16
#include "utf8.h"
17

18
typedef int (*push_env_func_t)(
19
                const char *filename,
20
                unsigned line,
21
                const char *key,
22
                char *value,
23
                void *userdata);
24

25
static int parse_env_file_internal(
185,055✔
26
                FILE *f,
27
                const char *fname,
28
                push_env_func_t push,
29
                void *userdata) {
30

31
        size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX;
185,055✔
32
        _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
185,055✔
33
        unsigned line = 1;
185,055✔
34
        int r;
185,055✔
35

36
        enum {
185,055✔
37
                PRE_KEY,
38
                KEY,
39
                PRE_VALUE,
40
                VALUE,
41
                VALUE_ESCAPE,
42
                SINGLE_QUOTE_VALUE,
43
                DOUBLE_QUOTE_VALUE,
44
                DOUBLE_QUOTE_VALUE_ESCAPE,
45
                COMMENT,
46
                COMMENT_ESCAPE
47
        } state = PRE_KEY;
185,055✔
48

49
        assert(f || fname);
185,055✔
50
        assert(push);
185,055✔
51

52
        if (f)
185,055✔
53
                r = read_full_stream(f, &contents, NULL);
9,015✔
54
        else
55
                r = read_full_file(fname, &contents, NULL);
176,040✔
56
        if (r < 0)
185,055✔
57
                return r;
58

59
        for (char *p = contents; *p; p++) {
62,926,894✔
60
                char c = *p;
62,748,181✔
61

62
                switch (state) {
62,748,181✔
63

64
                case PRE_KEY:
2,584,231✔
65
                        if (strchr(COMMENTS, c))
2,584,231✔
66
                                state = COMMENT;
67
                        else if (!strchr(WHITESPACE, c)) {
2,412,939✔
68
                                state = KEY;
2,407,656✔
69
                                last_key_whitespace = SIZE_MAX;
2,407,656✔
70

71
                                if (!GREEDY_REALLOC(key, n_key+2))
2,407,656✔
72
                                        return -ENOMEM;
73

74
                                key[n_key++] = c;
2,407,656✔
75
                        }
76
                        break;
77

78
                case KEY:
31,681,087✔
79
                        if (strchr(NEWLINE, c)) {
31,681,087✔
80
                                state = PRE_KEY;
25✔
81
                                line++;
25✔
82
                                n_key = 0;
25✔
83
                        } else if (c == '=') {
31,681,062✔
84
                                state = PRE_VALUE;
85
                                last_value_whitespace = SIZE_MAX;
86
                        } else {
87
                                if (!strchr(WHITESPACE, c))
29,273,431✔
88
                                        last_key_whitespace = SIZE_MAX;
89
                                else if (last_key_whitespace == SIZE_MAX)
86✔
90
                                         last_key_whitespace = n_key;
40✔
91

92
                                if (!GREEDY_REALLOC(key, n_key+2))
29,273,431✔
93
                                        return -ENOMEM;
94

95
                                key[n_key++] = c;
29,273,431✔
96
                        }
97

98
                        break;
99

100
                case PRE_VALUE:
2,600,774✔
101
                        if (strchr(NEWLINE, c)) {
2,600,774✔
102
                                state = PRE_KEY;
602,457✔
103
                                line++;
602,457✔
104
                                key[n_key] = 0;
602,457✔
105

106
                                if (value)
602,457✔
107
                                        value[n_value] = 0;
40,408✔
108

109
                                /* strip trailing whitespace from key */
110
                                if (last_key_whitespace != SIZE_MAX)
602,457✔
111
                                        key[last_key_whitespace] = 0;
6✔
112

113
                                r = push(fname, line, key, value, userdata);
602,457✔
114
                                if (r < 0)
602,457✔
115
                                        return r;
116

117
                                n_key = 0;
602,457✔
118
                                value = NULL;
602,457✔
119
                                n_value = 0;
602,457✔
120

121
                        } else if (c == '\'')
1,998,317✔
122
                                state = SINGLE_QUOTE_VALUE;
123
                        else if (c == '"')
1,998,307✔
124
                                state = DOUBLE_QUOTE_VALUE;
125
                        else if (c == '\\')
1,805,220✔
126
                                state = VALUE_ESCAPE;
127
                        else if (!strchr(WHITESPACE, c)) {
1,805,216✔
128
                                state = VALUE;
1,805,164✔
129

130
                                if (!GREEDY_REALLOC(value, n_value+2))
1,805,164✔
131
                                        return -ENOMEM;
132

133
                                value[n_value++] = c;
1,805,164✔
134
                        }
135

136
                        break;
137

138
                case VALUE:
17,114,537✔
139
                        if (strchr(NEWLINE, c)) {
17,114,537✔
140
                                state = PRE_KEY;
1,805,147✔
141
                                line++;
1,805,147✔
142

143
                                key[n_key] = 0;
1,805,147✔
144

145
                                if (value)
1,805,147✔
146
                                        value[n_value] = 0;
1,805,147✔
147

148
                                /* Chomp off trailing whitespace from value */
149
                                if (last_value_whitespace != SIZE_MAX)
1,805,147✔
150
                                        value[last_value_whitespace] = 0;
16✔
151

152
                                /* strip trailing whitespace from key */
153
                                if (last_key_whitespace != SIZE_MAX)
1,805,147✔
154
                                        key[last_key_whitespace] = 0;
6✔
155

156
                                r = push(fname, line, key, value, userdata);
1,805,147✔
157
                                if (r < 0)
1,805,147✔
158
                                        return r;
159

160
                                n_key = 0;
1,805,147✔
161
                                value = NULL;
1,805,147✔
162
                                n_value = 0;
1,805,147✔
163

164
                        } else if (c == '\\') {
15,309,390✔
165
                                state = VALUE_ESCAPE;
166
                                last_value_whitespace = SIZE_MAX;
167
                        } else {
168
                                if (!strchr(WHITESPACE, c))
15,309,368✔
169
                                        last_value_whitespace = SIZE_MAX;
170
                                else if (last_value_whitespace == SIZE_MAX)
13,187✔
171
                                        last_value_whitespace = n_value;
13,145✔
172

173
                                if (!GREEDY_REALLOC(value, n_value+2))
15,309,368✔
174
                                        return -ENOMEM;
175

176
                                value[n_value++] = c;
15,309,368✔
177
                        }
178

179
                        break;
180

181
                case VALUE_ESCAPE:
25✔
182
                        state = VALUE;
25✔
183

184
                        if (!strchr(NEWLINE, c)) {
25✔
185
                                /* Escaped newlines we eat up entirely */
186
                                if (!GREEDY_REALLOC(value, n_value+2))
16✔
187
                                        return -ENOMEM;
188

189
                                value[n_value++] = c;
16✔
190
                        }
191
                        break;
192

193
                case SINGLE_QUOTE_VALUE:
98✔
194
                        if (c == '\'')
98✔
195
                                state = PRE_VALUE;
196
                        else {
197
                                if (!GREEDY_REALLOC(value, n_value+2))
88✔
198
                                        return -ENOMEM;
199

200
                                value[n_value++] = c;
88✔
201
                        }
202

203
                        break;
204

205
                case DOUBLE_QUOTE_VALUE:
2,413,260✔
206
                        if (c == '"')
2,413,260✔
207
                                state = PRE_VALUE;
208
                        else if (c == '\\')
2,220,173✔
209
                                state = DOUBLE_QUOTE_VALUE_ESCAPE;
210
                        else {
211
                                if (!GREEDY_REALLOC(value, n_value+2))
2,220,141✔
212
                                        return -ENOMEM;
213

214
                                value[n_value++] = c;
2,220,141✔
215
                        }
216

217
                        break;
218

219
                case DOUBLE_QUOTE_VALUE_ESCAPE:
32✔
220
                        state = DOUBLE_QUOTE_VALUE;
32✔
221

222
                        if (strchr(SHELL_NEED_ESCAPE, c)) {
32✔
223
                                /* If this is a char that needs escaping, just unescape it. */
224
                                if (!GREEDY_REALLOC(value, n_value+2))
24✔
225
                                        return -ENOMEM;
226
                                value[n_value++] = c;
24✔
227
                        } else if (c != '\n') {
8✔
228
                                /* If other char than what needs escaping, keep the "\" in place, like the
229
                                 * real shell does. */
230
                                if (!GREEDY_REALLOC(value, n_value+3))
4✔
231
                                        return -ENOMEM;
232
                                value[n_value++] = '\\';
4✔
233
                                value[n_value++] = c;
4✔
234
                        }
235

236
                        /* Escaped newlines (aka "continuation lines") are eaten up entirely */
237
                        break;
238

239
                case COMMENT:
6,354,134✔
240
                        if (c == '\\')
6,354,134✔
241
                                state = COMMENT_ESCAPE;
242
                        else if (strchr(NEWLINE, c)) {
6,354,131✔
243
                                state = PRE_KEY;
171,289✔
244
                                line++;
171,289✔
245
                        }
246
                        break;
247

248
                case COMMENT_ESCAPE:
249
                        log_debug("The line which doesn't begin with \";\" or \"#\", but follows a comment" \
3✔
250
                                  " line trailing with escape is now treated as a non comment line since v254.");
251
                        if (strchr(NEWLINE, c)) {
3✔
252
                                state = PRE_KEY;
3✔
253
                                line++;
3✔
254
                        } else
255
                                state = COMMENT;
256
                        break;
257
                }
258
        }
259

260
        if (IN_SET(state,
178,713✔
261
                   PRE_VALUE,
262
                   VALUE,
263
                   VALUE_ESCAPE,
264
                   SINGLE_QUOTE_VALUE,
265
                   DOUBLE_QUOTE_VALUE,
266
                   DOUBLE_QUOTE_VALUE_ESCAPE)) {
267

268
                key[n_key] = 0;
27✔
269

270
                if (value)
27✔
271
                        value[n_value] = 0;
26✔
272

273
                if (state == VALUE)
27✔
274
                        if (last_value_whitespace != SIZE_MAX)
20✔
UNCOV
275
                                value[last_value_whitespace] = 0;
×
276

277
                /* strip trailing whitespace from key */
278
                if (last_key_whitespace != SIZE_MAX)
27✔
UNCOV
279
                        key[last_key_whitespace] = 0;
×
280

281
                r = push(fname, line, key, value, userdata);
27✔
282
                if (r < 0)
27✔
283
                        return r;
284

285
                value = NULL;
24✔
286
        }
287

288
        return 0;
289
}
290

291
static int check_utf8ness_and_warn(
2,407,618✔
292
                const char *filename, unsigned line,
293
                const char *key, char *value) {
294

295
        assert(key);
2,407,618✔
296

297
        if (!utf8_is_valid(key)) {
2,407,618✔
298
                _cleanup_free_ char *p = NULL;
1✔
299

300
                p = utf8_escape_invalid(key);
1✔
301
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1✔
302
                                       "%s:%u: invalid UTF-8 in key '%s', ignoring.",
303
                                       strna(filename), line, p);
304
        }
305

306
        if (value && !utf8_is_valid(value)) {
4,253,194✔
307
                _cleanup_free_ char *p = NULL;
2✔
308

309
                p = utf8_escape_invalid(value);
2✔
310
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2✔
311
                                       "%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
312
                                       strna(filename), line, key, p);
313
        }
314

315
        return 0;
316
}
317

318
static int parse_env_file_push(
2,368,976✔
319
                const char *filename, unsigned line,
320
                const char *key, char *value,
321
                void *userdata) {
322

323
        const char *k;
2,368,976✔
324
        va_list aq, *ap = userdata;
2,368,976✔
325
        int r;
2,368,976✔
326

327
        assert(key);
2,368,976✔
328

329
        r = check_utf8ness_and_warn(filename, line, key, value);
2,368,976✔
330
        if (r < 0)
2,368,976✔
331
                return r;
2,368,976✔
332

333
        va_copy(aq, *ap);
2,368,976✔
334

335
        while ((k = va_arg(aq, const char *))) {
4,697,929✔
336
                char **v;
2,448,578✔
337

338
                v = va_arg(aq, char **);
2,448,578✔
339

340
                if (streq(key, k)) {
2,448,578✔
341
                        va_end(aq);
119,625✔
342
                        free_and_replace(*v, value);
119,625✔
343

344
                        return 1;
119,625✔
345
                }
346
        }
347

348
        va_end(aq);
2,249,351✔
349
        free(value);
2,249,351✔
350

351
        return 0;
2,249,351✔
352
}
353

354
int parse_env_filev(
175,648✔
355
                FILE *f,
356
                const char *fname,
357
                va_list ap) {
358

359
        int r;
175,648✔
360
        va_list aq;
175,648✔
361

362
        assert(f || fname);
175,648✔
363

364
        va_copy(aq, ap);
175,648✔
365
        r = parse_env_file_internal(f, fname, parse_env_file_push, &aq);
175,648✔
366
        va_end(aq);
175,648✔
367
        return r;
175,648✔
368
}
369

370
int parse_env_file_fdv(int fd, const char *fname, va_list ap) {
2,003✔
371
        _cleanup_fclose_ FILE *f = NULL;
2,003✔
372
        va_list aq;
2,003✔
373
        int r;
2,003✔
374

375
        assert(fd >= 0);
2,003✔
376

377
        r = fdopen_independent(fd, "re", &f);
2,003✔
378
        if (r < 0)
2,003✔
379
                return r;
380

381
        va_copy(aq, ap);
2,003✔
382
        r = parse_env_file_internal(f, fname, parse_env_file_push, &aq);
2,003✔
383
        va_end(aq);
2,003✔
384
        return r;
2,003✔
385
}
386

387
int parse_env_file_sentinel(
175,648✔
388
                FILE *f,
389
                const char *fname,
390
                ...) {
391

392
        va_list ap;
175,648✔
393
        int r;
175,648✔
394

395
        assert(f || fname);
175,648✔
396

397
        va_start(ap, fname);
175,648✔
398
        r = parse_env_filev(f, fname, ap);
175,648✔
399
        va_end(ap);
175,648✔
400

401
        return r;
175,648✔
402
}
403

404
int parse_env_file_fd_sentinel(
1,710✔
405
                int fd,
406
                const char *fname, /* only used for logging */
407
                ...) {
408

409
        va_list ap;
1,710✔
410
        int r;
1,710✔
411

412
        assert(fd >= 0);
1,710✔
413

414
        va_start(ap, fname);
1,710✔
415
        r = parse_env_file_fdv(fd, fname, ap);
1,710✔
416
        va_end(ap);
1,710✔
417

418
        return r;
1,710✔
419
}
420

421
static int load_env_file_push(
554✔
422
                const char *filename, unsigned line,
423
                const char *key, char *value,
424
                void *userdata) {
425

426
        char ***m = userdata;
554✔
427
        char *p;
554✔
428
        int r;
554✔
429

430
        assert(key);
554✔
431

432
        r = check_utf8ness_and_warn(filename, line, key, value);
554✔
433
        if (r < 0)
554✔
434
                return r;
435

436
        p = strjoin(key, "=", value);
551✔
437
        if (!p)
551✔
438
                return -ENOMEM;
439

440
        r = strv_env_replace_consume(m, p);
551✔
441
        if (r < 0)
551✔
442
                return r;
443

444
        free(value);
551✔
445
        return 0;
551✔
446
}
447

448
int load_env_file(FILE *f, const char *fname, char ***ret) {
278✔
449
        _cleanup_strv_free_ char **m = NULL;
278✔
450
        int r;
278✔
451

452
        assert(f || fname);
278✔
453
        assert(ret);
278✔
454

455
        r = parse_env_file_internal(f, fname, load_env_file_push, &m);
278✔
456
        if (r < 0)
278✔
457
                return r;
458

459
        *ret = TAKE_PTR(m);
274✔
460
        return 0;
274✔
461
}
462

463
static int load_env_file_push_pairs(
38,088✔
464
                const char *filename, unsigned line,
465
                const char *key, char *value,
466
                void *userdata) {
467

468
        char ***m = ASSERT_PTR(userdata);
38,088✔
469
        int r;
38,088✔
470

471
        assert(key);
38,088✔
472

473
        r = check_utf8ness_and_warn(filename, line, key, value);
38,088✔
474
        if (r < 0)
38,088✔
475
                return r;
476

477
        /* Check if the key is present */
478
        for (char **t = *m; t && *t; t += 2)
207,302✔
479
                if (streq(t[0], key)) {
169,219✔
480
                        if (value)
5✔
481
                                return free_and_replace(t[1], value);
5✔
482
                        else
UNCOV
483
                                return free_and_strdup(t+1, "");
×
484
                }
485

486
        r = strv_extend(m, key);
38,083✔
487
        if (r < 0)
38,083✔
488
                return r;
489

490
        if (value)
38,083✔
491
                return strv_push(m, value);
38,080✔
492
        else
493
                return strv_extend(m, "");
3✔
494
}
495

496
int load_env_file_pairs(FILE *f, const char *fname, char ***ret) {
6,944✔
497
        _cleanup_strv_free_ char **m = NULL;
6,944✔
498
        int r;
6,944✔
499

500
        assert(f || fname);
6,944✔
501
        assert(ret);
6,944✔
502

503
        r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m);
6,944✔
504
        if (r < 0)
6,944✔
505
                return r;
506

507
        *ret = TAKE_PTR(m);
6,924✔
508
        return 0;
6,924✔
509
}
510

511
int load_env_file_pairs_fd(int fd, const char *fname, char ***ret) {
5,381✔
512
        _cleanup_fclose_ FILE *f = NULL;
5,381✔
513
        int r;
5,381✔
514

515
        assert(fd >= 0);
5,381✔
516

517
        r = fdopen_independent(fd, "re", &f);
5,381✔
518
        if (r < 0)
5,381✔
519
                return r;
520

521
        return load_env_file_pairs(f, fname, ret);
5,381✔
522
}
523

524
static int merge_env_file_push(
53✔
525
                const char *filename, unsigned line,
526
                const char *key, char *value,
527
                void *userdata) {
528

529
        char ***env = ASSERT_PTR(userdata);
53✔
530
        char *expanded_value;
53✔
531
        int r;
53✔
532

533
        assert(key);
53✔
534

535
        if (!value) {
53✔
536
                log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
20✔
537
                return 0;
10✔
538
        }
539

540
        if (!env_name_is_valid(key)) {
43✔
541
                log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key);
6✔
542
                free(value);
3✔
543
                return 0;
3✔
544
        }
545

546
        r = replace_env(value,
40✔
547
                        *env,
548
                        REPLACE_ENV_USE_ENVIRONMENT|REPLACE_ENV_ALLOW_BRACELESS|REPLACE_ENV_ALLOW_EXTENDED,
549
                        &expanded_value);
550
        if (r < 0)
40✔
UNCOV
551
                return log_error_errno(r, "%s:%u: Failed to expand variable '%s': %m", strna(filename), line, value);
×
552

553
        free_and_replace(value, expanded_value);
40✔
554

555
        log_debug("%s:%u: setting %s=%s", filename, line, key, value);
40✔
556

557
        return load_env_file_push(filename, line, key, value, env);
40✔
558
}
559

560
int merge_env_file(
182✔
561
                char ***env,
562
                FILE *f,
563
                const char *fname) {
564

565
        assert(env);
182✔
566
        assert(f || fname);
182✔
567

568
        /* NOTE: this function supports braceful and braceless variable expansions,
569
         * plus "extended" substitutions, unlike other exported parsing functions.
570
         */
571

572
        return parse_env_file_internal(f, fname, merge_env_file_push, env);
182✔
573
}
574

575
static void env_file_fputs_escaped(FILE *f, const char *p) {
8,567✔
576
        assert(f);
8,567✔
577
        assert(p);
8,567✔
578

579
        flockfile(f);
8,567✔
580

581
        if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
8,567✔
582
                fputc_unlocked('"', f);
18✔
583

584
                for (; *p; p++) {
249✔
585
                        if (strchr(SHELL_NEED_ESCAPE, *p))
231✔
586
                                fputc_unlocked('\\', f);
12✔
587

588
                        fputc_unlocked(*p, f);
462✔
589
                }
590

591
                fputc_unlocked('"', f);
18✔
592
        } else
593
                fputs_unlocked(p, f);
8,549✔
594

595
        funlockfile(f);
8,567✔
596
}
8,567✔
597

598
void env_file_fputs_assignment(FILE *f, const char *k, const char *v) {
19,524✔
599
        assert(f);
19,524✔
600
        assert(k);
19,524✔
601

602
        if (!v)
19,524✔
603
                return;
604

605
        fputs(k, f);
8,070✔
606
        env_file_fputs_escaped(f, v);
8,070✔
607
        fputc('\n', f);
8,070✔
608
}
609

610
static void write_env_var(FILE *f, const char *v) {
497✔
611
        const char *p;
497✔
612

613
        assert(f);
497✔
614
        assert(v);
497✔
615

616
        p = strchr(v, '=');
497✔
617
        if (!p) {
497✔
618
                /* Fallback */
619
                fputs_unlocked(v, f);
×
UNCOV
620
                fputc_unlocked('\n', f);
×
UNCOV
621
                return;
×
622
        }
623

624
        p++;
497✔
625
        fwrite_unlocked(v, 1, p-v, f);
497✔
626

627
        env_file_fputs_escaped(f, p);
497✔
628

629
        fputc_unlocked('\n', f);
497✔
630
}
631

632
int write_env_file(int dir_fd, const char *fname, char **headers, char **l) {
284✔
633
        _cleanup_fclose_ FILE *f = NULL;
284✔
634
        _cleanup_free_ char *p = NULL;
284✔
635
        int r;
284✔
636

637
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
284✔
638
        assert(fname);
284✔
639

640
        r = fopen_tmpfile_linkable_at(dir_fd, fname, O_WRONLY|O_CLOEXEC, &p, &f);
284✔
641
        if (r < 0)
284✔
642
                return r;
643

644
        r = fchmod_umask(fileno(f), 0644);
284✔
645
        if (r < 0)
284✔
UNCOV
646
                goto fail;
×
647

648
        STRV_FOREACH(i, headers) {
809✔
649
                assert(isempty(*i) || startswith(*i, "#"));
525✔
650
                fputs_unlocked(*i, f);
525✔
651
                fputc_unlocked('\n', f);
1,050✔
652
        }
653

654
        STRV_FOREACH(i, l)
781✔
655
                write_env_var(f, *i);
497✔
656

657
        r = flink_tmpfile_at(f, dir_fd, p, fname, LINK_TMPFILE_REPLACE|LINK_TMPFILE_SYNC);
284✔
658
        if (r < 0)
284✔
UNCOV
659
                goto fail;
×
660

661
        return 0;
662

663
fail:
×
UNCOV
664
        if (p)
×
UNCOV
665
                (void) unlinkat(dir_fd, p, 0);
×
666

667
        return r;
668
}
669

670
int write_vconsole_conf(int dir_fd, const char *fname, char **l) {
249✔
671
        char **headers = STRV_MAKE(
249✔
672
                "# Written by systemd-localed(8) or systemd-firstboot(1), read by systemd-localed",
673
                "# and systemd-vconsole-setup(8). Use localectl(1) to update this file.");
674

675
        return write_env_file(dir_fd, fname, headers, l);
249✔
676
}
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