]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nspawn/nspawn-settings.c
Rework cpu affinity parsing
[thirdparty/systemd.git] / src / nspawn / nspawn-settings.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f757855e 2
b5efdb8a 3#include "alloc-util.h"
f757855e 4#include "cap-list.h"
7b3e062c 5#include "conf-parser.h"
d107bb7d 6#include "cpu-set-util.h"
3a9530e5 7#include "hostname-util.h"
f6d6bad1 8#include "nspawn-network.h"
f757855e 9#include "nspawn-settings.h"
7732f92b 10#include "parse-util.h"
7b3e062c 11#include "process-util.h"
bf428efb 12#include "rlimit-util.h"
22b28dfd 13#include "socket-util.h"
09d423e9 14#include "string-table.h"
22b28dfd 15#include "string-util.h"
7b3e062c 16#include "strv.h"
0de7acce 17#include "user-util.h"
7b3e062c 18#include "util.h"
f757855e 19
de40a303
LP
20Settings *settings_new(void) {
21 Settings *s;
22
23 s = new(Settings, 1);
24 if (!s)
25 return NULL;
26
27 *s = (Settings) {
28 .start_mode = _START_MODE_INVALID,
29 .personality = PERSONALITY_INVALID,
30
31 .resolv_conf = _RESOLV_CONF_MODE_INVALID,
32 .link_journal = _LINK_JOURNAL_INVALID,
33 .timezone = _TIMEZONE_MODE_INVALID,
34
35 .userns_mode = _USER_NAMESPACE_MODE_INVALID,
36 .userns_chown = -1,
37 .uid_shift = UID_INVALID,
38 .uid_range = UID_INVALID,
39
40 .no_new_privileges = -1,
41
42 .read_only = -1,
43 .volatile_mode = _VOLATILE_MODE_INVALID,
44
45 .private_network = -1,
46 .network_veth = -1,
47
48 .full_capabilities = CAPABILITY_QUINTET_NULL,
49
50 .uid = UID_INVALID,
51 .gid = GID_INVALID,
52
53 .console_mode = _CONSOLE_MODE_INVALID,
54 .console_width = (unsigned) -1,
55 .console_height = (unsigned) -1,
56
57 .clone_ns_flags = (unsigned long) -1,
58 .use_cgns = -1,
59 };
60
61 return s;
62}
63
f757855e
LP
64int settings_load(FILE *f, const char *path, Settings **ret) {
65 _cleanup_(settings_freep) Settings *s = NULL;
66 int r;
67
68 assert(path);
69 assert(ret);
70
de40a303 71 s = settings_new();
f757855e
LP
72 if (!s)
73 return -ENOMEM;
74
f757855e
LP
75 r = config_parse(NULL, path, f,
76 "Exec\0"
77 "Network\0"
78 "Files\0",
79 config_item_perf_lookup, nspawn_gperf_lookup,
bcde742e 80 CONFIG_PARSE_WARN,
f757855e
LP
81 s);
82 if (r < 0)
83 return r;
84
0de7acce
LP
85 /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
86 * both fields shall be initialized or neither. */
87 if (s->userns_mode == USER_NAMESPACE_PICK)
88 s->userns_chown = true;
89 else if (s->userns_mode != _USER_NAMESPACE_MODE_INVALID && s->userns_chown < 0)
90 s->userns_chown = false;
91
92 if (s->userns_chown >= 0 && s->userns_mode == _USER_NAMESPACE_MODE_INVALID)
93 s->userns_mode = USER_NAMESPACE_NO;
94
1cc6c93a 95 *ret = TAKE_PTR(s);
f757855e
LP
96 return 0;
97}
98
de40a303
LP
99static void free_oci_hooks(OciHook *h, size_t n) {
100 size_t i;
101
102 assert(h || n == 0);
103
104 for (i = 0; i < n; i++) {
105 free(h[i].path);
106 strv_free(h[i].args);
107 strv_free(h[i].env);
108 }
109
110 free(h);
111}
112
b2645747 113void device_node_array_free(DeviceNode *node, size_t n) {
de40a303
LP
114 size_t i;
115
116 for (i = 0; i < n; i++)
117 free(node[i].path);
118
119 free(node);
120}
f757855e 121
de40a303 122Settings* settings_free(Settings *s) {
f757855e
LP
123 if (!s)
124 return NULL;
125
126 strv_free(s->parameters);
127 strv_free(s->environment);
128 free(s->user);
b53ede69
PW
129 free(s->pivot_root_new);
130 free(s->pivot_root_old);
5f932eb9 131 free(s->working_directory);
960e4569
LP
132 strv_free(s->syscall_whitelist);
133 strv_free(s->syscall_blacklist);
bf428efb 134 rlimit_free_all(s->rlimit);
3a9530e5 135 free(s->hostname);
0985c7c4 136 cpu_set_reset(&s->cpu_set);
f757855e
LP
137
138 strv_free(s->network_interfaces);
139 strv_free(s->network_macvlan);
140 strv_free(s->network_ipvlan);
f6d6bad1 141 strv_free(s->network_veth_extra);
f757855e 142 free(s->network_bridge);
22b28dfd 143 free(s->network_zone);
f757855e
LP
144 expose_port_free_all(s->expose_ports);
145
146 custom_mount_free_all(s->custom_mounts, s->n_custom_mounts);
de40a303
LP
147
148 free(s->bundle);
149 free(s->root);
150
151 free_oci_hooks(s->oci_hooks_prestart, s->n_oci_hooks_prestart);
152 free_oci_hooks(s->oci_hooks_poststart, s->n_oci_hooks_poststart);
153 free_oci_hooks(s->oci_hooks_poststop, s->n_oci_hooks_poststop);
154
155 free(s->slice);
156 sd_bus_message_unref(s->properties);
157
158 free(s->supplementary_gids);
b2645747 159 device_node_array_free(s->extra_nodes, s->n_extra_nodes);
de40a303
LP
160 free(s->network_namespace_path);
161
162 strv_free(s->sysctl);
163
164#if HAVE_SECCOMP
165 seccomp_release(s->seccomp);
166#endif
167
6b430fdb 168 return mfree(s);
f757855e
LP
169}
170
0e265674
LP
171bool settings_private_network(Settings *s) {
172 assert(s);
173
174 return
175 s->private_network > 0 ||
176 s->network_veth > 0 ||
177 s->network_bridge ||
22b28dfd 178 s->network_zone ||
0e265674
LP
179 s->network_interfaces ||
180 s->network_macvlan ||
f6d6bad1
LP
181 s->network_ipvlan ||
182 s->network_veth_extra;
0e265674
LP
183}
184
185bool settings_network_veth(Settings *s) {
186 assert(s);
187
188 return
189 s->network_veth > 0 ||
22b28dfd
LP
190 s->network_bridge ||
191 s->network_zone;
0e265674
LP
192}
193
de40a303
LP
194int settings_allocate_properties(Settings *s) {
195 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
196 int r;
197
198 assert(s);
199
200 if (s->properties)
201 return 0;
202
203 r = sd_bus_default_system(&bus);
204 if (r < 0)
205 return r;
206
207 r = sd_bus_message_new(bus, &s->properties, SD_BUS_MESSAGE_METHOD_CALL);
208 if (r < 0)
209 return r;
210
211 return 0;
212}
213
f757855e
LP
214DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
215
216int config_parse_expose_port(
217 const char *unit,
218 const char *filename,
219 unsigned line,
220 const char *section,
221 unsigned section_line,
222 const char *lvalue,
223 int ltype,
224 const char *rvalue,
225 void *data,
226 void *userdata) {
227
228 Settings *s = data;
229 int r;
230
231 assert(filename);
232 assert(lvalue);
233 assert(rvalue);
234
235 r = expose_port_parse(&s->expose_ports, rvalue);
236 if (r == -EEXIST) {
237 log_syntax(unit, LOG_ERR, filename, line, r, "Duplicate port specification, ignoring: %s", rvalue);
238 return 0;
239 }
240 if (r < 0) {
241 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse host port %s: %m", rvalue);
242 return 0;
243 }
244
245 return 0;
246}
247
248int config_parse_capability(
249 const char *unit,
250 const char *filename,
251 unsigned line,
252 const char *section,
253 unsigned section_line,
254 const char *lvalue,
255 int ltype,
256 const char *rvalue,
257 void *data,
258 void *userdata) {
259
260 uint64_t u = 0, *result = data;
261 int r;
262
263 assert(filename);
264 assert(lvalue);
265 assert(rvalue);
266
267 for (;;) {
268 _cleanup_free_ char *word = NULL;
f757855e
LP
269
270 r = extract_first_word(&rvalue, &word, NULL, 0);
271 if (r < 0) {
272 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract capability string, ignoring: %s", rvalue);
273 return 0;
274 }
275 if (r == 0)
276 break;
277
acf4d158
YW
278 r = capability_from_name(word);
279 if (r < 0) {
280 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse capability, ignoring: %s", word);
f757855e
LP
281 continue;
282 }
283
acf4d158 284 u |= UINT64_C(1) << r;
f757855e
LP
285 }
286
287 if (u == 0)
288 return 0;
289
290 *result |= u;
291 return 0;
292}
293
294int config_parse_id128(
295 const char *unit,
296 const char *filename,
297 unsigned line,
298 const char *section,
299 unsigned section_line,
300 const char *lvalue,
301 int ltype,
302 const char *rvalue,
303 void *data,
304 void *userdata) {
305
306 sd_id128_t t, *result = data;
307 int r;
308
309 assert(filename);
310 assert(lvalue);
311 assert(rvalue);
312
313 r = sd_id128_from_string(rvalue, &t);
314 if (r < 0) {
315 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue);
316 return 0;
317 }
318
319 *result = t;
320 return 0;
321}
322
b53ede69
PW
323int config_parse_pivot_root(
324 const char *unit,
325 const char *filename,
326 unsigned line,
327 const char *section,
328 unsigned section_line,
329 const char *lvalue,
330 int ltype,
331 const char *rvalue,
332 void *data,
333 void *userdata) {
334
335 Settings *settings = data;
336 int r;
337
338 assert(filename);
339 assert(lvalue);
340 assert(rvalue);
341
342 r = pivot_root_parse(&settings->pivot_root_new, &settings->pivot_root_old, rvalue);
343 if (r < 0) {
344 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid pivot root mount specification %s: %m", rvalue);
345 return 0;
346 }
347
348 return 0;
349}
350
f757855e
LP
351int config_parse_bind(
352 const char *unit,
353 const char *filename,
354 unsigned line,
355 const char *section,
356 unsigned section_line,
357 const char *lvalue,
358 int ltype,
359 const char *rvalue,
360 void *data,
361 void *userdata) {
362
363 Settings *settings = data;
364 int r;
365
366 assert(filename);
367 assert(lvalue);
368 assert(rvalue);
369
370 r = bind_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
371 if (r < 0) {
372 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bind mount specification %s: %m", rvalue);
373 return 0;
374 }
375
376 return 0;
377}
378
379int config_parse_tmpfs(
380 const char *unit,
381 const char *filename,
382 unsigned line,
383 const char *section,
384 unsigned section_line,
385 const char *lvalue,
386 int ltype,
387 const char *rvalue,
388 void *data,
389 void *userdata) {
390
391 Settings *settings = data;
392 int r;
393
394 assert(filename);
395 assert(lvalue);
396 assert(rvalue);
397
398 r = tmpfs_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
399 if (r < 0) {
400 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid temporary file system specification %s: %m", rvalue);
401 return 0;
402 }
403
f6d6bad1
LP
404 return 0;
405}
f757855e 406
de40a303
LP
407int config_parse_inaccessible(
408 const char *unit,
409 const char *filename,
410 unsigned line,
411 const char *section,
412 unsigned section_line,
413 const char *lvalue,
414 int ltype,
415 const char *rvalue,
416 void *data,
417 void *userdata) {
418
419 Settings *settings = data;
420 int r;
421
422 assert(filename);
423 assert(lvalue);
424 assert(rvalue);
425
426 r = inaccessible_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
427 if (r < 0) {
428 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid inaccessible file system specification %s: %m", rvalue);
429 return 0;
430 }
431
432 return 0;
433}
434
7b4318b6
LP
435int config_parse_overlay(
436 const char *unit,
437 const char *filename,
438 unsigned line,
439 const char *section,
440 unsigned section_line,
441 const char *lvalue,
442 int ltype,
443 const char *rvalue,
444 void *data,
445 void *userdata) {
446
447 Settings *settings = data;
448 int r;
449
450 assert(filename);
451 assert(lvalue);
452 assert(rvalue);
453
454 r = overlay_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
455 if (r < 0)
456 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid overlay file system specification %s, ignoring: %m", rvalue);
457
458 return 0;
459}
460
f6d6bad1
LP
461int config_parse_veth_extra(
462 const char *unit,
463 const char *filename,
464 unsigned line,
465 const char *section,
466 unsigned section_line,
467 const char *lvalue,
468 int ltype,
469 const char *rvalue,
470 void *data,
471 void *userdata) {
472
473 Settings *settings = data;
474 int r;
475
476 assert(filename);
477 assert(lvalue);
478 assert(rvalue);
479
480 r = veth_extra_parse(&settings->network_veth_extra, rvalue);
481 if (r < 0) {
482 log_syntax(unit, LOG_ERR, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue);
483 return 0;
484 }
f757855e
LP
485
486 return 0;
487}
7732f92b 488
22b28dfd
LP
489int config_parse_network_zone(
490 const char *unit,
491 const char *filename,
492 unsigned line,
493 const char *section,
494 unsigned section_line,
495 const char *lvalue,
496 int ltype,
497 const char *rvalue,
498 void *data,
499 void *userdata) {
500
501 Settings *settings = data;
502 _cleanup_free_ char *j = NULL;
503
504 assert(filename);
505 assert(lvalue);
506 assert(rvalue);
507
508 j = strappend("vz-", rvalue);
509 if (!ifname_valid(j)) {
c65ac075 510 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid network zone name, ignoring: %s", rvalue);
22b28dfd
LP
511 return 0;
512 }
513
f9ecfd3b 514 free_and_replace(settings->network_zone, j);
22b28dfd
LP
515
516 return 0;
517}
518
7732f92b
LP
519int config_parse_boot(
520 const char *unit,
521 const char *filename,
522 unsigned line,
523 const char *section,
524 unsigned section_line,
525 const char *lvalue,
526 int ltype,
527 const char *rvalue,
528 void *data,
529 void *userdata) {
530
531 Settings *settings = data;
532 int r;
533
534 assert(filename);
535 assert(lvalue);
536 assert(rvalue);
537
538 r = parse_boolean(rvalue);
539 if (r < 0) {
540 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue);
541 return 0;
542 }
543
544 if (r > 0) {
545 if (settings->start_mode == START_PID2)
546 goto conflict;
547
548 settings->start_mode = START_BOOT;
549 } else {
550 if (settings->start_mode == START_BOOT)
551 goto conflict;
552
553 if (settings->start_mode < 0)
554 settings->start_mode = START_PID1;
555 }
556
557 return 0;
558
559conflict:
560 log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
561 return 0;
562}
563
564int config_parse_pid2(
565 const char *unit,
566 const char *filename,
567 unsigned line,
568 const char *section,
569 unsigned section_line,
570 const char *lvalue,
571 int ltype,
572 const char *rvalue,
573 void *data,
574 void *userdata) {
575
576 Settings *settings = data;
577 int r;
578
579 assert(filename);
580 assert(lvalue);
581 assert(rvalue);
582
583 r = parse_boolean(rvalue);
584 if (r < 0) {
585 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue);
586 return 0;
587 }
588
589 if (r > 0) {
590 if (settings->start_mode == START_BOOT)
591 goto conflict;
592
593 settings->start_mode = START_PID2;
594 } else {
595 if (settings->start_mode == START_PID2)
596 goto conflict;
597
598 if (settings->start_mode < 0)
599 settings->start_mode = START_PID1;
600 }
601
602 return 0;
603
604conflict:
605 log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
606 return 0;
607}
0de7acce
LP
608
609int config_parse_private_users(
610 const char *unit,
611 const char *filename,
612 unsigned line,
613 const char *section,
614 unsigned section_line,
615 const char *lvalue,
616 int ltype,
617 const char *rvalue,
618 void *data,
619 void *userdata) {
620
621 Settings *settings = data;
622 int r;
623
624 assert(filename);
625 assert(lvalue);
626 assert(rvalue);
627
628 r = parse_boolean(rvalue);
629 if (r == 0) {
630 /* no: User namespacing off */
631 settings->userns_mode = USER_NAMESPACE_NO;
632 settings->uid_shift = UID_INVALID;
633 settings->uid_range = UINT32_C(0x10000);
634 } else if (r > 0) {
635 /* yes: User namespacing on, UID range is read from root dir */
636 settings->userns_mode = USER_NAMESPACE_FIXED;
637 settings->uid_shift = UID_INVALID;
638 settings->uid_range = UINT32_C(0x10000);
639 } else if (streq(rvalue, "pick")) {
640 /* pick: User namespacing on, UID range is picked randomly */
641 settings->userns_mode = USER_NAMESPACE_PICK;
642 settings->uid_shift = UID_INVALID;
643 settings->uid_range = UINT32_C(0x10000);
644 } else {
645 const char *range, *shift;
646 uid_t sh, rn;
647
648 /* anything else: User namespacing on, UID range is explicitly configured */
649
650 range = strchr(rvalue, ':');
651 if (range) {
652 shift = strndupa(rvalue, range - rvalue);
653 range++;
654
655 r = safe_atou32(range, &rn);
656 if (r < 0 || rn <= 0) {
657 log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID range invalid, ignoring: %s", range);
658 return 0;
659 }
660 } else {
661 shift = rvalue;
662 rn = UINT32_C(0x10000);
663 }
664
665 r = parse_uid(shift, &sh);
666 if (r < 0) {
667 log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID shift invalid, ignoring: %s", range);
668 return 0;
669 }
670
671 settings->userns_mode = USER_NAMESPACE_FIXED;
672 settings->uid_shift = sh;
673 settings->uid_range = rn;
674 }
675
676 return 0;
677}
960e4569
LP
678
679int config_parse_syscall_filter(
680 const char *unit,
681 const char *filename,
682 unsigned line,
683 const char *section,
684 unsigned section_line,
685 const char *lvalue,
686 int ltype,
687 const char *rvalue,
688 void *data,
689 void *userdata) {
690
691 Settings *settings = data;
692 bool negative;
693 const char *items;
694 int r;
695
696 assert(filename);
697 assert(lvalue);
698 assert(rvalue);
699
700 negative = rvalue[0] == '~';
701 items = negative ? rvalue + 1 : rvalue;
702
703 for (;;) {
704 _cleanup_free_ char *word = NULL;
705
706 r = extract_first_word(&items, &word, NULL, 0);
707 if (r == 0)
708 break;
709 if (r == -ENOMEM)
710 return log_oom();
711 if (r < 0) {
712 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue);
713 return 0;
714 }
715
716 if (negative)
717 r = strv_extend(&settings->syscall_blacklist, word);
718 else
719 r = strv_extend(&settings->syscall_whitelist, word);
720 if (r < 0)
721 return log_oom();
722 }
723
724 return 0;
725}
3a9530e5
LP
726
727int config_parse_hostname(
728 const char *unit,
729 const char *filename,
730 unsigned line,
731 const char *section,
732 unsigned section_line,
733 const char *lvalue,
734 int ltype,
735 const char *rvalue,
736 void *data,
737 void *userdata) {
738
739 char **s = data;
740
741 assert(rvalue);
742 assert(s);
743
744 if (!hostname_is_valid(rvalue, false)) {
745 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue);
746 return 0;
747 }
748
749 if (free_and_strdup(s, empty_to_null(rvalue)) < 0)
750 return log_oom();
751
752 return 0;
753}
81f345df
LP
754
755int config_parse_oom_score_adjust(
756 const char *unit,
757 const char *filename,
758 unsigned line,
759 const char *section,
760 unsigned section_line,
761 const char *lvalue,
762 int ltype,
763 const char *rvalue,
764 void *data,
765 void *userdata) {
766
767 Settings *settings = data;
768 int oa, r;
769
770 assert(rvalue);
771 assert(settings);
772
773 if (isempty(rvalue)) {
774 settings->oom_score_adjust_set = false;
775 return 0;
776 }
777
778 r = parse_oom_score_adjust(rvalue, &oa);
779 if (r == -ERANGE) {
780 log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
781 return 0;
782 }
783 if (r < 0) {
784 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
785 return 0;
786 }
787
788 settings->oom_score_adjust = oa;
789 settings->oom_score_adjust_set = true;
790
791 return 0;
792}
d107bb7d
LP
793
794int config_parse_cpu_affinity(
795 const char *unit,
796 const char *filename,
797 unsigned line,
798 const char *section,
799 unsigned section_line,
800 const char *lvalue,
801 int ltype,
802 const char *rvalue,
803 void *data,
804 void *userdata) {
805
d107bb7d 806 Settings *settings = data;
d107bb7d
LP
807
808 assert(rvalue);
809 assert(settings);
810
0985c7c4 811 return parse_cpu_set_extend(rvalue, &settings->cpu_set, true, unit, filename, line, lvalue);
d107bb7d 812}
09d423e9
LP
813
814DEFINE_CONFIG_PARSE_ENUM(config_parse_resolv_conf, resolv_conf_mode, ResolvConfMode, "Failed to parse resolv.conf mode");
815
816static const char *const resolv_conf_mode_table[_RESOLV_CONF_MODE_MAX] = {
817 [RESOLV_CONF_OFF] = "off",
818 [RESOLV_CONF_COPY_HOST] = "copy-host",
819 [RESOLV_CONF_COPY_STATIC] = "copy-static",
820 [RESOLV_CONF_BIND_HOST] = "bind-host",
821 [RESOLV_CONF_BIND_STATIC] = "bind-static",
822 [RESOLV_CONF_DELETE] = "delete",
823 [RESOLV_CONF_AUTO] = "auto",
824};
825
826DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(resolv_conf_mode, ResolvConfMode, RESOLV_CONF_AUTO);
4e1d6aa9
LP
827
828int parse_link_journal(const char *s, LinkJournal *ret_mode, bool *ret_try) {
829 assert(s);
830 assert(ret_mode);
831 assert(ret_try);
832
833 if (streq(s, "auto")) {
834 *ret_mode = LINK_AUTO;
835 *ret_try = false;
836 } else if (streq(s, "no")) {
837 *ret_mode = LINK_NO;
838 *ret_try = false;
839 } else if (streq(s, "guest")) {
840 *ret_mode = LINK_GUEST;
841 *ret_try = false;
842 } else if (streq(s, "host")) {
843 *ret_mode = LINK_HOST;
844 *ret_try = false;
845 } else if (streq(s, "try-guest")) {
846 *ret_mode = LINK_GUEST;
847 *ret_try = true;
848 } else if (streq(s, "try-host")) {
849 *ret_mode = LINK_HOST;
850 *ret_try = true;
851 } else
852 return -EINVAL;
853
854 return 0;
855}
856
857int config_parse_link_journal(
858 const char *unit,
859 const char *filename,
860 unsigned line,
861 const char *section,
862 unsigned section_line,
863 const char *lvalue,
864 int ltype,
865 const char *rvalue,
866 void *data,
867 void *userdata) {
868
869 Settings *settings = data;
870 int r;
871
872 assert(rvalue);
873 assert(settings);
874
875 r = parse_link_journal(rvalue, &settings->link_journal, &settings->link_journal_try);
876 if (r < 0) {
877 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse link journal mode, ignoring: %s", rvalue);
878 return 0;
879 }
880
881 return 0;
882}
1688841f
LP
883
884DEFINE_CONFIG_PARSE_ENUM(config_parse_timezone, timezone_mode, TimezoneMode, "Failed to parse timezone mode");
885
886static const char *const timezone_mode_table[_TIMEZONE_MODE_MAX] = {
887 [TIMEZONE_OFF] = "off",
888 [TIMEZONE_COPY] = "copy",
889 [TIMEZONE_BIND] = "bind",
890 [TIMEZONE_SYMLINK] = "symlink",
891 [TIMEZONE_DELETE] = "delete",
892 [TIMEZONE_AUTO] = "auto",
893};
894
895DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(timezone_mode, TimezoneMode, TIMEZONE_AUTO);