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

systemd / systemd / 20012523220

07 Dec 2025 11:33PM UTC coverage: 72.656% (+0.1%) from 72.546%
20012523220

push

github

yuwata
import: include unistd.h for pipe2

This is needed for e.g. pipe2 and unlinkat and a build failure
is reproducible when libarchive support is disabled.

309255 of 425645 relevant lines covered (72.66%)

1123501.7 hits per line

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

78.19
/src/nspawn/nspawn-settings.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include "sd-bus.h"
4

5
#include "alloc-util.h"
6
#include "capability-list.h"
7
#include "conf-parser.h"
8
#include "cpu-set-util.h"
9
#include "extract-word.h"
10
#include "namespace-util.h"
11
#include "nspawn-expose-ports.h"
12
#include "nspawn-mount.h"
13
#include "nspawn-network.h"
14
#include "nspawn-settings.h"
15
#include "parse-util.h"
16
#include "process-util.h"
17
#include "rlimit-util.h"
18
#include "socket-util.h"
19
#include "string-table.h"
20
#include "string-util.h"
21
#include "strv.h"
22
#include "user-util.h"
23

24
Settings *settings_new(void) {
468✔
25
        Settings *s;
468✔
26

27
        s = new(Settings, 1);
468✔
28
        if (!s)
468✔
29
                return NULL;
30

31
        *s = (Settings) {
468✔
32
                .start_mode = _START_MODE_INVALID,
33
                .ephemeral = -1,
34
                .personality = PERSONALITY_INVALID,
35

36
                .resolv_conf = _RESOLV_CONF_MODE_INVALID,
37
                .link_journal = _LINK_JOURNAL_INVALID,
38
                .timezone = _TIMEZONE_MODE_INVALID,
39

40
                .userns_mode = _USER_NAMESPACE_MODE_INVALID,
41
                .userns_ownership = _USER_NAMESPACE_OWNERSHIP_INVALID,
42
                .uid_shift = UID_INVALID,
43
                .uid_range = UID_INVALID,
44

45
                .no_new_privileges = -1,
46

47
                .read_only = -1,
48
                .volatile_mode = _VOLATILE_MODE_INVALID,
49

50
                .private_network = -1,
51
                .network_veth = -1,
52

53
                .full_capabilities = CAPABILITY_QUINTET_NULL,
54

55
                .uid = UID_INVALID,
56
                .gid = GID_INVALID,
57

58
                .console_mode = _CONSOLE_MODE_INVALID,
59
                .console_width = UINT_MAX,
60
                .console_height = UINT_MAX,
61

62
                .clone_ns_flags = ULONG_MAX,
63
                .use_cgns = -1,
64

65
                .notify_ready = -1,
66
                .suppress_sync = -1,
67
        };
68

69
        return s;
468✔
70
}
71

72
int settings_load(FILE *f, const char *path, Settings **ret) {
434✔
73
        _cleanup_(settings_freep) Settings *s = NULL;
434✔
74
        int r;
434✔
75

76
        assert(path);
434✔
77
        assert(ret);
434✔
78

79
        s = settings_new();
434✔
80
        if (!s)
434✔
81
                return -ENOMEM;
82

83
        r = config_parse(NULL, path, f,
434✔
84
                         "Exec\0"
85
                         "Network\0"
86
                         "Files\0",
87
                         config_item_perf_lookup, nspawn_gperf_lookup,
88
                         CONFIG_PARSE_WARN,
89
                         s, NULL);
90
        if (r < 0)
434✔
91
                return r;
92

93
        /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
94
         * both fields shall be initialized or neither. */
95
        if (s->userns_mode >= 0 && s->userns_ownership < 0)
434✔
96
                s->userns_ownership = s->userns_mode == USER_NAMESPACE_PICK ? USER_NAMESPACE_OWNERSHIP_CHOWN : USER_NAMESPACE_OWNERSHIP_OFF;
×
97
        if (s->userns_ownership >= 0 && s->userns_mode < 0)
434✔
98
                s->userns_mode = USER_NAMESPACE_NO;
×
99

100
        *ret = TAKE_PTR(s);
434✔
101
        return 0;
434✔
102
}
103

104
static void free_oci_hooks(OciHook *hooks, size_t n) {
1,404✔
105
        assert(hooks || n == 0);
1,404✔
106

107
        FOREACH_ARRAY(hook, hooks, n) {
1,408✔
108
                free(hook->path);
4✔
109
                strv_free(hook->args);
4✔
110
                strv_free(hook->env);
4✔
111
        }
112

113
        free(hooks);
1,404✔
114
}
1,404✔
115

116
void device_node_array_free(DeviceNode *nodes, size_t n) {
1,276✔
117
        assert(nodes || n == 0);
1,276✔
118

119
        FOREACH_ARRAY(node, nodes, n)
1,277✔
120
                free(node->path);
1✔
121

122
        free(nodes);
1,276✔
123
}
1,276✔
124

125
Settings* settings_free(Settings *s) {
468✔
126
        if (!s)
468✔
127
                return NULL;
128

129
        strv_free(s->parameters);
468✔
130
        strv_free(s->environment);
468✔
131
        free(s->user);
468✔
132
        free(s->pivot_root_new);
468✔
133
        free(s->pivot_root_old);
468✔
134
        free(s->working_directory);
468✔
135
        strv_free(s->syscall_allow_list);
468✔
136
        strv_free(s->syscall_deny_list);
468✔
137
        rlimit_free_all(s->rlimit);
468✔
138
        free(s->hostname);
468✔
139
        cpu_set_done(&s->cpu_set);
468✔
140
        strv_free(s->bind_user);
468✔
141
        free(s->bind_user_shell);
468✔
142

143
        strv_free(s->network_interfaces);
468✔
144
        strv_free(s->network_macvlan);
468✔
145
        strv_free(s->network_ipvlan);
468✔
146
        strv_free(s->network_veth_extra);
468✔
147
        free(s->network_bridge);
468✔
148
        free(s->network_zone);
468✔
149
        expose_port_free_all(s->expose_ports);
468✔
150

151
        custom_mount_free_all(s->custom_mounts, s->n_custom_mounts);
468✔
152

153
        free(s->bundle);
468✔
154
        free(s->root);
468✔
155

156
        free_oci_hooks(s->oci_hooks_prestart, s->n_oci_hooks_prestart);
468✔
157
        free_oci_hooks(s->oci_hooks_poststart, s->n_oci_hooks_poststart);
468✔
158
        free_oci_hooks(s->oci_hooks_poststop, s->n_oci_hooks_poststop);
468✔
159

160
        free(s->slice);
468✔
161
        sd_bus_message_unref(s->properties);
468✔
162

163
        free(s->supplementary_gids);
468✔
164
        device_node_array_free(s->extra_nodes, s->n_extra_nodes);
468✔
165
        free(s->network_namespace_path);
468✔
166

167
        strv_free(s->sysctl);
468✔
168

169
#if HAVE_SECCOMP
170
        if (s->seccomp)
468✔
171
                sym_seccomp_release(s->seccomp);
×
172
#endif
173

174
        return mfree(s);
468✔
175
}
176

177
bool settings_private_network(Settings *s) {
16✔
178
        assert(s);
16✔
179

180
        /* Determines whether we shall open up our own private network */
181

182
        return
16✔
183
                s->private_network > 0 ||
16✔
184
                s->network_veth > 0 ||
×
185
                s->network_bridge ||
×
186
                s->network_zone ||
×
187
                s->network_interfaces ||
×
188
                s->network_macvlan ||
×
189
                s->network_ipvlan ||
16✔
190
                s->network_veth_extra;
×
191
}
192

193
bool settings_network_veth(Settings *s) {
8✔
194
        assert(s);
8✔
195

196
        return
8✔
197
                s->network_veth > 0 ||
9✔
198
                s->network_bridge ||
8✔
199
                s->network_zone;
1✔
200
}
201

202
bool settings_network_configured(Settings *s) {
565✔
203
        assert(s);
565✔
204

205
        /* Determines whether any network configuration setting was used. (i.e. in contrast to
206
         * settings_private_network() above this might also indicate if private networking was explicitly
207
         * turned off.) */
208

209
        return
565✔
210
                s->private_network >= 0 ||
1,114✔
211
                s->network_veth >= 0 ||
549✔
212
                s->network_bridge ||
549✔
213
                s->network_zone ||
549✔
214
                s->network_interfaces ||
549✔
215
                s->network_macvlan ||
549✔
216
                s->network_ipvlan ||
549✔
217
                s->network_veth_extra ||
1,114✔
218
                s->network_namespace_path;
549✔
219
}
220

221
int settings_allocate_properties(Settings *s) {
13✔
222
        _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
13✔
223
        int r;
13✔
224

225
        assert(s);
13✔
226

227
        if (s->properties)
13✔
228
                return 0;
229

230
        r = sd_bus_default_system(&bus);
1✔
231
        if (r < 0)
1✔
232
                return r;
233

234
        r = sd_bus_message_new(bus, &s->properties, SD_BUS_MESSAGE_METHOD_CALL);
1✔
235
        if (r < 0)
1✔
236
                return r;
×
237

238
        return 0;
239
}
240

241
DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode);
7✔
242

243
int config_parse_expose_port(
28✔
244
                const char *unit,
245
                const char *filename,
246
                unsigned line,
247
                const char *section,
248
                unsigned section_line,
249
                const char *lvalue,
250
                int ltype,
251
                const char *rvalue,
252
                void *data,
253
                void *userdata) {
254

255
        Settings *s = data;
28✔
256
        int r;
28✔
257

258
        assert(filename);
28✔
259
        assert(lvalue);
28✔
260
        assert(rvalue);
28✔
261

262
        r = expose_port_parse(&s->expose_ports, rvalue);
28✔
263
        if (r == -EEXIST)
28✔
264
                log_syntax(unit, LOG_WARNING, filename, line, r, "Duplicate port specification, ignoring: %s", rvalue);
×
265
        else if (r < 0)
28✔
266
                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse host port %s: %m", rvalue);
×
267

268
        return 0;
28✔
269
}
270

271
int config_parse_capability(
21✔
272
                const char *unit,
273
                const char *filename,
274
                unsigned line,
275
                const char *section,
276
                unsigned section_line,
277
                const char *lvalue,
278
                int ltype,
279
                const char *rvalue,
280
                void *data,
281
                void *userdata) {
282

283
        uint64_t u = 0, *result = data;
21✔
284
        int r;
21✔
285

286
        assert(filename);
21✔
287
        assert(lvalue);
21✔
288
        assert(rvalue);
21✔
289

290
        for (;;) {
70✔
291
                _cleanup_free_ char *word = NULL;
49✔
292

293
                r = extract_first_word(&rvalue, &word, NULL, 0);
70✔
294
                if (r == -ENOMEM)
70✔
295
                        return log_oom();
×
296
                if (r < 0) {
70✔
297
                        log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract capability string, ignoring: %s", rvalue);
×
298
                        return 0;
×
299
                }
300
                if (r == 0)
70✔
301
                        break;
302

303
                if (streq(word, "all"))
49✔
304
                        u = UINT64_MAX;
305
                else {
306
                        r = capability_from_name(word);
49✔
307
                        if (r < 0) {
49✔
308
                                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse capability, ignoring: %s", word);
×
309
                                continue;
×
310
                        }
311

312
                        u |= UINT64_C(1) << r;
49✔
313
                }
314
        }
315

316
        *result |= u;
21✔
317
        return 0;
21✔
318
}
319

320
int config_parse_pivot_root(
×
321
                const char *unit,
322
                const char *filename,
323
                unsigned line,
324
                const char *section,
325
                unsigned section_line,
326
                const char *lvalue,
327
                int ltype,
328
                const char *rvalue,
329
                void *data,
330
                void *userdata) {
331

332
        Settings *settings = data;
×
333
        int r;
×
334

335
        assert(filename);
×
336
        assert(lvalue);
×
337
        assert(rvalue);
×
338

339
        r = pivot_root_parse(&settings->pivot_root_new, &settings->pivot_root_old, rvalue);
×
340
        if (r < 0)
×
341
                log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid pivot root mount specification %s: %m", rvalue);
×
342

343
        return 0;
×
344
}
345

346
int config_parse_bind(
417✔
347
                const char *unit,
348
                const char *filename,
349
                unsigned line,
350
                const char *section,
351
                unsigned section_line,
352
                const char *lvalue,
353
                int ltype,
354
                const char *rvalue,
355
                void *data,
356
                void *userdata) {
357

358
        Settings *settings = data;
417✔
359
        int r;
417✔
360

361
        assert(filename);
417✔
362
        assert(lvalue);
417✔
363
        assert(rvalue);
417✔
364

365
        r = bind_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
417✔
366
        if (r < 0)
417✔
367
                log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid bind mount specification %s: %m", rvalue);
×
368

369
        return 0;
417✔
370
}
371

372
int config_parse_tmpfs(
14✔
373
                const char *unit,
374
                const char *filename,
375
                unsigned line,
376
                const char *section,
377
                unsigned section_line,
378
                const char *lvalue,
379
                int ltype,
380
                const char *rvalue,
381
                void *data,
382
                void *userdata) {
383

384
        Settings *settings = data;
14✔
385
        int r;
14✔
386

387
        assert(filename);
14✔
388
        assert(lvalue);
14✔
389
        assert(rvalue);
14✔
390

391
        r = tmpfs_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
14✔
392
        if (r < 0)
14✔
393
                log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid temporary file system specification %s: %m", rvalue);
×
394

395
        return 0;
14✔
396
}
397

398
int config_parse_inaccessible(
14✔
399
                const char *unit,
400
                const char *filename,
401
                unsigned line,
402
                const char *section,
403
                unsigned section_line,
404
                const char *lvalue,
405
                int ltype,
406
                const char *rvalue,
407
                void *data,
408
                void *userdata) {
409

410
        Settings *settings = data;
14✔
411
        int r;
14✔
412

413
        assert(filename);
14✔
414
        assert(lvalue);
14✔
415
        assert(rvalue);
14✔
416

417
        r = inaccessible_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
14✔
418
        if (r < 0)
14✔
419
                log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid inaccessible file system specification %s: %m", rvalue);
×
420

421
        return 0;
14✔
422
}
423

424
int config_parse_overlay(
7✔
425
                const char *unit,
426
                const char *filename,
427
                unsigned line,
428
                const char *section,
429
                unsigned section_line,
430
                const char *lvalue,
431
                int ltype,
432
                const char *rvalue,
433
                void *data,
434
                void *userdata) {
435

436
        Settings *settings = data;
7✔
437
        int r;
7✔
438

439
        assert(filename);
7✔
440
        assert(lvalue);
7✔
441
        assert(rvalue);
7✔
442

443
        r = overlay_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
7✔
444
        if (r < 0)
7✔
445
                log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid overlay file system specification %s, ignoring: %m", rvalue);
×
446

447
        return 0;
7✔
448
}
449

450
int config_parse_veth_extra(
14✔
451
                const char *unit,
452
                const char *filename,
453
                unsigned line,
454
                const char *section,
455
                unsigned section_line,
456
                const char *lvalue,
457
                int ltype,
458
                const char *rvalue,
459
                void *data,
460
                void *userdata) {
461

462
        Settings *settings = data;
14✔
463
        int r;
14✔
464

465
        assert(filename);
14✔
466
        assert(lvalue);
14✔
467
        assert(rvalue);
14✔
468

469
        r = veth_extra_parse(&settings->network_veth_extra, rvalue);
14✔
470
        if (r < 0)
14✔
471
                log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue);
×
472

473
        return 0;
14✔
474
}
475

476
int config_parse_network_iface_pair(
7✔
477
                const char *unit,
478
                const char *filename,
479
                unsigned line,
480
                const char *section,
481
                unsigned section_line,
482
                const char *lvalue,
483
                int ltype,
484
                const char *rvalue,
485
                void *data,
486
                void *userdata) {
487

488
        char*** l = data;
7✔
489

490
        assert(filename);
7✔
491
        assert(lvalue);
7✔
492
        assert(rvalue);
7✔
493

494
        return interface_pair_parse(l, rvalue);
7✔
495
}
496

497
int config_parse_macvlan_iface_pair(
7✔
498
                const char *unit,
499
                const char *filename,
500
                unsigned line,
501
                const char *section,
502
                unsigned section_line,
503
                const char *lvalue,
504
                int ltype,
505
                const char *rvalue,
506
                void *data,
507
                void *userdata) {
508

509
        char*** l = data;
7✔
510

511
        assert(filename);
7✔
512
        assert(lvalue);
7✔
513
        assert(rvalue);
7✔
514

515
        return macvlan_pair_parse(l, rvalue);
7✔
516
}
517

518
int config_parse_ipvlan_iface_pair(
7✔
519
                const char *unit,
520
                const char *filename,
521
                unsigned line,
522
                const char *section,
523
                unsigned section_line,
524
                const char *lvalue,
525
                int ltype,
526
                const char *rvalue,
527
                void *data,
528
                void *userdata) {
529

530
        char*** l = data;
7✔
531

532
        assert(filename);
7✔
533
        assert(lvalue);
7✔
534
        assert(rvalue);
7✔
535

536
        return ipvlan_pair_parse(l, rvalue);
7✔
537
}
538

539
int config_parse_network_zone(
7✔
540
                const char *unit,
541
                const char *filename,
542
                unsigned line,
543
                const char *section,
544
                unsigned section_line,
545
                const char *lvalue,
546
                int ltype,
547
                const char *rvalue,
548
                void *data,
549
                void *userdata) {
550

551
        Settings *settings = data;
7✔
552
        _cleanup_free_ char *j = NULL;
7✔
553

554
        assert(filename);
7✔
555
        assert(lvalue);
7✔
556
        assert(rvalue);
7✔
557

558
        j = strjoin("vz-", rvalue);
7✔
559
        if (!ifname_valid(j)) {
7✔
560
                log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid network zone name, ignoring: %s", rvalue);
×
561
                return 0;
×
562
        }
563

564
        return free_and_replace(settings->network_zone, j);
7✔
565
}
566

567
int config_parse_boot(
7✔
568
                const char *unit,
569
                const char *filename,
570
                unsigned line,
571
                const char *section,
572
                unsigned section_line,
573
                const char *lvalue,
574
                int ltype,
575
                const char *rvalue,
576
                void *data,
577
                void *userdata) {
578

579
        Settings *settings = data;
7✔
580
        int r;
7✔
581

582
        assert(filename);
7✔
583
        assert(lvalue);
7✔
584
        assert(rvalue);
7✔
585

586
        r = parse_boolean(rvalue);
7✔
587
        if (r < 0) {
7✔
588
                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue);
×
589
                return 0;
×
590
        }
591

592
        if (r) {
7✔
593
                if (settings->start_mode == START_PID2)
×
594
                        goto conflict;
×
595

596
                settings->start_mode = START_BOOT;
×
597
        } else {
598
                if (settings->start_mode == START_BOOT)
7✔
599
                        goto conflict;
×
600

601
                if (settings->start_mode < 0)
7✔
602
                        settings->start_mode = START_PID1;
7✔
603
        }
604

605
        return 0;
606

607
conflict:
×
608
        log_syntax(unit, LOG_WARNING, filename, line, 0, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
×
609
        return 0;
610
}
611

612
int config_parse_pid2(
7✔
613
                const char *unit,
614
                const char *filename,
615
                unsigned line,
616
                const char *section,
617
                unsigned section_line,
618
                const char *lvalue,
619
                int ltype,
620
                const char *rvalue,
621
                void *data,
622
                void *userdata) {
623

624
        Settings *settings = data;
7✔
625
        int r;
7✔
626

627
        assert(filename);
7✔
628
        assert(lvalue);
7✔
629
        assert(rvalue);
7✔
630

631
        r = parse_boolean(rvalue);
7✔
632
        if (r < 0) {
7✔
633
                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue);
×
634
                return 0;
×
635
        }
636

637
        if (r) {
7✔
638
                if (settings->start_mode == START_BOOT)
×
639
                        goto conflict;
×
640

641
                settings->start_mode = START_PID2;
×
642
        } else {
643
                if (settings->start_mode == START_PID2)
7✔
644
                        goto conflict;
×
645

646
                if (settings->start_mode < 0)
7✔
647
                        settings->start_mode = START_PID1;
×
648
        }
649

650
        return 0;
651

652
conflict:
×
653
        log_syntax(unit, LOG_WARNING, filename, line, 0, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
×
654
        return 0;
655
}
656

657
int config_parse_private_users(
19✔
658
                const char *unit,
659
                const char *filename,
660
                unsigned line,
661
                const char *section,
662
                unsigned section_line,
663
                const char *lvalue,
664
                int ltype,
665
                const char *rvalue,
666
                void *data,
667
                void *userdata) {
668

669
        Settings *settings = data;
19✔
670
        int r;
19✔
671

672
        assert(filename);
19✔
673
        assert(lvalue);
19✔
674
        assert(rvalue);
19✔
675

676
        r = parse_boolean(rvalue);
19✔
677
        if (r == 0) {
19✔
678
                /* no: User namespacing off */
679
                settings->userns_mode = USER_NAMESPACE_NO;
7✔
680
                settings->uid_shift = UID_INVALID;
7✔
681
                settings->uid_range = UINT32_C(0x10000);
7✔
682
        } else if (r > 0) {
12✔
683
                /* yes: User namespacing on, UID range is read from root dir */
684
                settings->userns_mode = USER_NAMESPACE_FIXED;
3✔
685
                settings->uid_shift = UID_INVALID;
3✔
686
                settings->uid_range = UINT32_C(0x10000);
3✔
687
        } else if (streq(rvalue, "pick")) {
9✔
688
                /* pick: User namespacing on, UID range is picked randomly */
689
                settings->userns_mode = USER_NAMESPACE_PICK;
3✔
690
                settings->uid_shift = UID_INVALID;
3✔
691
                settings->uid_range = UINT32_C(0x10000);
3✔
692
        } else if (streq(rvalue, "identity")) {
6✔
693
                /* identity: User namespacing on, UID range is 0:65536 */
694
                settings->userns_mode = USER_NAMESPACE_FIXED;
3✔
695
                settings->uid_shift = 0;
3✔
696
                settings->uid_range = UINT32_C(0x10000);
3✔
697
        } else {
698
                const char *range, *shift;
3✔
699
                uid_t sh, rn;
3✔
700

701
                /* anything else: User namespacing on, UID range is explicitly configured */
702

703
                range = strchr(rvalue, ':');
3✔
704
                if (range) {
3✔
705
                        shift = strndupa_safe(rvalue, range - rvalue);
3✔
706
                        range++;
3✔
707

708
                        r = safe_atou32(range, &rn);
3✔
709
                        if (r < 0) {
3✔
710
                                log_syntax(unit, LOG_WARNING, filename, line, r, "UID/GID range invalid, ignoring: %s", range);
×
711
                                return 0;
×
712
                        }
713
                } else {
714
                        shift = rvalue;
×
715
                        rn = UINT32_C(0x10000);
×
716
                }
717

718
                r = parse_uid(shift, &sh);
3✔
719
                if (r < 0) {
3✔
720
                        log_syntax(unit, LOG_WARNING, filename, line, r, "UID/GID shift invalid, ignoring: %s", range);
×
721
                        return 0;
×
722
                }
723

724
                if (!userns_shift_range_valid(sh, rn)) {
3✔
725
                        log_syntax(unit, LOG_WARNING, filename, line, 0, "UID/GID shift and range combination invalid, ignoring: %s", range);
×
726
                        return 0;
×
727
                }
728

729
                settings->userns_mode = USER_NAMESPACE_FIXED;
3✔
730
                settings->uid_shift = sh;
3✔
731
                settings->uid_range = rn;
3✔
732
        }
733

734
        return 0;
735
}
736

737
int config_parse_syscall_filter(
14✔
738
                const char *unit,
739
                const char *filename,
740
                unsigned line,
741
                const char *section,
742
                unsigned section_line,
743
                const char *lvalue,
744
                int ltype,
745
                const char *rvalue,
746
                void *data,
747
                void *userdata) {
748

749
        Settings *settings = data;
14✔
750
        bool negative;
14✔
751
        const char *items;
14✔
752
        int r;
14✔
753

754
        assert(filename);
14✔
755
        assert(lvalue);
14✔
756
        assert(rvalue);
14✔
757

758
        negative = rvalue[0] == '~';
14✔
759
        items = negative ? rvalue + 1 : rvalue;
14✔
760

761
        for (;;) {
56✔
762
                _cleanup_free_ char *word = NULL;
35✔
763

764
                r = extract_first_word(&items, &word, NULL, 0);
35✔
765
                if (r == 0)
35✔
766
                        return 0;
767
                if (r == -ENOMEM)
21✔
768
                        return log_oom();
×
769
                if (r < 0) {
21✔
770
                        log_syntax(unit, LOG_WARNING, filename, line, r,
×
771
                                   "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue);
772
                        return 0;
×
773
                }
774

775
                if (negative)
21✔
776
                        r = strv_extend(&settings->syscall_deny_list, word);
7✔
777
                else
778
                        r = strv_extend(&settings->syscall_allow_list, word);
14✔
779
                if (r < 0)
21✔
780
                        return log_oom();
×
781
        }
782
}
783

784
int config_parse_oom_score_adjust(
7✔
785
                const char *unit,
786
                const char *filename,
787
                unsigned line,
788
                const char *section,
789
                unsigned section_line,
790
                const char *lvalue,
791
                int ltype,
792
                const char *rvalue,
793
                void *data,
794
                void *userdata) {
795

796
        Settings *settings = ASSERT_PTR(data);
7✔
797
        int oa, r;
7✔
798

799
        assert(rvalue);
7✔
800

801
        if (isempty(rvalue)) {
7✔
802
                settings->oom_score_adjust_set = false;
×
803
                return 0;
×
804
        }
805

806
        r = parse_oom_score_adjust(rvalue, &oa);
7✔
807
        if (r == -ERANGE) {
7✔
808
                log_syntax(unit, LOG_WARNING, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
×
809
                return 0;
×
810
        }
811
        if (r < 0) {
7✔
812
                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
×
813
                return 0;
×
814
        }
815

816
        settings->oom_score_adjust = oa;
7✔
817
        settings->oom_score_adjust_set = true;
7✔
818

819
        return 0;
7✔
820
}
821

822
DEFINE_CONFIG_PARSE_ENUM(config_parse_resolv_conf, resolv_conf_mode, ResolvConfMode);
7✔
823

824
static const char *const resolv_conf_mode_table[_RESOLV_CONF_MODE_MAX] = {
825
        [RESOLV_CONF_OFF]            = "off",
826
        [RESOLV_CONF_COPY_HOST]      = "copy-host",
827
        [RESOLV_CONF_COPY_STATIC]    = "copy-static",
828
        [RESOLV_CONF_COPY_UPLINK]    = "copy-uplink",
829
        [RESOLV_CONF_COPY_STUB]      = "copy-stub",
830
        [RESOLV_CONF_REPLACE_HOST]   = "replace-host",
831
        [RESOLV_CONF_REPLACE_STATIC] = "replace-static",
832
        [RESOLV_CONF_REPLACE_UPLINK] = "replace-uplink",
833
        [RESOLV_CONF_REPLACE_STUB]   = "replace-stub",
834
        [RESOLV_CONF_BIND_HOST]      = "bind-host",
835
        [RESOLV_CONF_BIND_STATIC]    = "bind-static",
836
        [RESOLV_CONF_BIND_UPLINK]    = "bind-uplink",
837
        [RESOLV_CONF_BIND_STUB]      = "bind-stub",
838
        [RESOLV_CONF_DELETE]         = "delete",
839
        [RESOLV_CONF_AUTO]           = "auto",
840
};
841

842
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(resolv_conf_mode, ResolvConfMode, RESOLV_CONF_AUTO);
102✔
843

844
int parse_link_journal(const char *s, LinkJournal *ret_mode, bool *ret_try) {
63✔
845
        int r;
63✔
846

847
        assert(s);
63✔
848
        assert(ret_mode);
63✔
849
        assert(ret_try);
63✔
850

851
        if (streq(s, "auto")) {
63✔
852
                *ret_mode = LINK_AUTO;
×
853
                *ret_try = false;
×
854
        } else if (streq(s, "guest")) {
63✔
855
                *ret_mode = LINK_GUEST;
×
856
                *ret_try = false;
×
857
        } else if (streq(s, "host")) {
63✔
858
                *ret_mode = LINK_HOST;
12✔
859
                *ret_try = false;
12✔
860
        } else if (streq(s, "try-guest")) {
51✔
861
                *ret_mode = LINK_GUEST;
42✔
862
                *ret_try = true;
42✔
863
        } else if (streq(s, "try-host")) {
9✔
864
                *ret_mode = LINK_HOST;
×
865
                *ret_try = true;
×
866
        } else {
867
                /* Also support boolean values, to make things less confusing. */
868
                r = parse_boolean(s);
9✔
869
                if (r < 0)
9✔
870
                        return r;
871

872
                /* Let's consider "true" to be equivalent to "auto". */
873
                *ret_mode = r ? LINK_AUTO : LINK_NO;
7✔
874
                *ret_try = false;
7✔
875
        }
876

877
        return 0;
878
}
879

880
int config_parse_link_journal(
7✔
881
                const char *unit,
882
                const char *filename,
883
                unsigned line,
884
                const char *section,
885
                unsigned section_line,
886
                const char *lvalue,
887
                int ltype,
888
                const char *rvalue,
889
                void *data,
890
                void *userdata) {
891

892
        Settings *settings = ASSERT_PTR(data);
7✔
893
        int r;
7✔
894

895
        assert(rvalue);
7✔
896

897
        r = parse_link_journal(rvalue, &settings->link_journal, &settings->link_journal_try);
7✔
898
        if (r < 0)
7✔
899
                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse link journal mode, ignoring: %s", rvalue);
×
900

901
        return 0;
7✔
902
}
903

904
DEFINE_CONFIG_PARSE_ENUM(config_parse_timezone_mode, timezone_mode, TimezoneMode);
7✔
905

906
static const char *const timezone_mode_table[_TIMEZONE_MODE_MAX] = {
907
        [TIMEZONE_OFF]     = "off",
908
        [TIMEZONE_COPY]    = "copy",
909
        [TIMEZONE_BIND]    = "bind",
910
        [TIMEZONE_SYMLINK] = "symlink",
911
        [TIMEZONE_DELETE]  = "delete",
912
        [TIMEZONE_AUTO]    = "auto",
913
};
914

915
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(timezone_mode, TimezoneMode, TIMEZONE_AUTO);
73✔
916

917
static const char *const console_mode_table[_CONSOLE_MODE_MAX] = {
918
        [CONSOLE_AUTOPIPE]    = "autopipe",
919
        [CONSOLE_INTERACTIVE] = "interactive",
920
        [CONSOLE_READ_ONLY]   = "read-only",
921
        [CONSOLE_PASSIVE]     = "passive",
922
        [CONSOLE_PIPE]        = "pipe",
923
};
924

925
DEFINE_STRING_TABLE_LOOKUP(console_mode, ConsoleMode);
2✔
926

927
DEFINE_CONFIG_PARSE_ENUM(config_parse_userns_ownership, user_namespace_ownership, UserNamespaceOwnership);
19✔
928

929
static const char *const user_namespace_ownership_table[_USER_NAMESPACE_OWNERSHIP_MAX] = {
930
        [USER_NAMESPACE_OWNERSHIP_OFF]     = "off",
931
        [USER_NAMESPACE_OWNERSHIP_CHOWN]   = "chown",
932
        [USER_NAMESPACE_OWNERSHIP_MAP]     = "map",
933
        [USER_NAMESPACE_OWNERSHIP_FOREIGN] = "foreign",
934
        [USER_NAMESPACE_OWNERSHIP_AUTO]    = "auto",
935
};
936

937
/* Note: while "yes" maps to "auto" here, we don't really document that, in order to make things clearer and less confusing to users. */
938
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(user_namespace_ownership, UserNamespaceOwnership, USER_NAMESPACE_OWNERSHIP_AUTO);
39✔
939

940
int config_parse_userns_chown(
×
941
                const char *unit,
942
                const char *filename,
943
                unsigned line,
944
                const char *section,
945
                unsigned section_line,
946
                const char *lvalue,
947
                int ltype,
948
                const char *rvalue,
949
                void *data,
950
                void *userdata) {
951

952
        UserNamespaceOwnership *ownership = ASSERT_PTR(data);
×
953
        int r;
×
954

955
        assert(rvalue);
×
956

957
        /* Compatibility support for UserNamespaceChown=, whose job has been taken over by UserNamespaceOwnership= */
958

959
        r = parse_boolean(rvalue);
×
960
        if (r < 0) {
×
961
                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse user namespace ownership mode, ignoring: %s", rvalue);
×
962
                return 0;
×
963
        }
964

965
        *ownership = r ? USER_NAMESPACE_OWNERSHIP_CHOWN : USER_NAMESPACE_OWNERSHIP_OFF;
×
966
        return 0;
×
967
}
968

969
int config_parse_bind_user(
18✔
970
                const char *unit,
971
                const char *filename,
972
                unsigned line,
973
                const char *section,
974
                unsigned section_line,
975
                const char *lvalue,
976
                int ltype,
977
                const char *rvalue,
978
                void *data,
979
                void *userdata) {
980

981
        char ***bind_user = ASSERT_PTR(data);
18✔
982
        int r;
18✔
983

984
        assert(rvalue);
18✔
985

986
        if (isempty(rvalue)) {
18✔
987
                *bind_user = strv_free(*bind_user);
12✔
988
                return 0;
12✔
989
        }
990

991
        for (const char* p = rvalue;;) {
6✔
992
                _cleanup_free_ char *word = NULL;
6✔
993

994
                r = extract_first_word(&p, &word, NULL, 0);
12✔
995
                if (r == -ENOMEM)
12✔
996
                        return log_oom();
×
997
                if (r < 0) {
12✔
998
                        log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse BindUser= list, ignoring: %s", rvalue);
×
999
                        return 0;
×
1000
                }
1001
                if (r == 0)
12✔
1002
                        break;
1003

1004
                if (!valid_user_group_name(word, 0)) {
6✔
1005
                        log_syntax(unit, LOG_WARNING, filename, line, 0, "User name '%s' not valid, ignoring.", word);
×
1006
                        return 0;
×
1007
                }
1008

1009
                if (strv_consume(bind_user, TAKE_PTR(word)) < 0)
6✔
1010
                        return log_oom();
×
1011
        }
1012

1013
        return 0;
6✔
1014
}
1015

1016
int config_parse_bind_user_shell(
6✔
1017
                const char *unit,
1018
                const char *filename,
1019
                unsigned line,
1020
                const char *section,
1021
                unsigned section_line,
1022
                const char *lvalue,
1023
                int ltype,
1024
                const char *rvalue,
1025
                void *data,
1026
                void *userdata) {
1027

1028
        Settings *settings = ASSERT_PTR(data);
6✔
1029
        char *sh = NULL;
6✔
1030
        bool copy = false;
6✔
1031
        int r;
6✔
1032

1033
        assert(rvalue);
6✔
1034

1035
        if (isempty(rvalue)) {
6✔
1036
                settings->bind_user_shell = mfree(settings->bind_user_shell);
×
1037
                settings->bind_user_shell_copy = false;
×
1038
                settings->bind_user_shell_set = false;
×
1039

1040
                return 0;
×
1041
        }
1042

1043
        r = parse_user_shell(rvalue, &sh, &copy);
6✔
1044
        if (r == -ENOMEM)
6✔
1045
                return log_oom();
×
1046
        if (r < 0) {
6✔
1047
                log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse BindUserShell= value, ignoring: %s", rvalue);
×
1048
                return 0;
×
1049
        }
1050

1051
        free_and_replace(settings->bind_user_shell, sh);
6✔
1052
        settings->bind_user_shell_copy = copy;
6✔
1053
        settings->bind_user_shell_set = true;
6✔
1054

1055
        return 0;
6✔
1056
}
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