]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/fstab-generator/fstab-generator.c
14a53cd572587e420059d07dbd4e3d6059f3755f
[thirdparty/systemd.git] / src / fstab-generator / fstab-generator.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6
7 #include "sd-bus.h"
8
9 #include "alloc-util.h"
10 #include "argv-util.h"
11 #include "bus-error.h"
12 #include "bus-locator.h"
13 #include "bus-unit-util.h"
14 #include "bus-util.h"
15 #include "chase.h"
16 #include "creds-util.h"
17 #include "efi-loader.h"
18 #include "env-util.h"
19 #include "errno-util.h"
20 #include "extract-word.h"
21 #include "fd-util.h"
22 #include "fileio.h"
23 #include "fstab-util.h"
24 #include "generator.h"
25 #include "in-addr-util.h"
26 #include "initrd-util.h"
27 #include "log.h"
28 #include "main-func.h"
29 #include "mount-setup.h"
30 #include "mount-util.h"
31 #include "mountpoint-util.h"
32 #include "parse-util.h"
33 #include "path-util.h"
34 #include "proc-cmdline.h"
35 #include "special.h"
36 #include "specifier.h"
37 #include "stat-util.h"
38 #include "string-util.h"
39 #include "strv.h"
40 #include "unit-name.h"
41 #include "virt.h"
42 #include "volatile-util.h"
43
44 typedef enum MountPointFlags {
45 MOUNT_NOAUTO = 1 << 0,
46 MOUNT_NOFAIL = 1 << 1,
47 MOUNT_AUTOMOUNT = 1 << 2,
48 MOUNT_MAKEFS = 1 << 3,
49 MOUNT_GROWFS = 1 << 4,
50 MOUNT_RW_ONLY = 1 << 5,
51 MOUNT_PCRFS = 1 << 6,
52 MOUNT_QUOTA = 1 << 7,
53 MOUNT_VALIDATEFS = 1 << 8,
54 } MountPointFlags;
55
56 typedef struct Mount {
57 bool for_initrd;
58 char *what;
59 char *where;
60 char *fstype;
61 char *options;
62 } Mount;
63
64 static void mount_array_free(Mount *mounts, size_t n);
65
66 static bool arg_sysroot_check = false;
67 static const char *arg_dest = NULL;
68 static const char *arg_dest_late = NULL;
69 static bool arg_fstab_enabled = true;
70 static bool arg_swap_enabled = true;
71 static char *arg_root_what = NULL;
72 static char *arg_root_fstype = NULL;
73 static char *arg_root_options = NULL;
74 static char *arg_root_hash = NULL;
75 static int arg_root_rw = -1;
76 static char *arg_usr_what = NULL;
77 static char *arg_usr_fstype = NULL;
78 static char *arg_usr_options = NULL;
79 static char *arg_usr_hash = NULL;
80 static VolatileMode arg_volatile_mode = _VOLATILE_MODE_INVALID;
81 static bool arg_verity = true;
82 static Mount *arg_mounts = NULL;
83 static size_t arg_n_mounts = 0;
84
85 STATIC_DESTRUCTOR_REGISTER(arg_root_what, freep);
86 STATIC_DESTRUCTOR_REGISTER(arg_root_fstype, freep);
87 STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep);
88 STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
89 STATIC_DESTRUCTOR_REGISTER(arg_usr_what, freep);
90 STATIC_DESTRUCTOR_REGISTER(arg_usr_fstype, freep);
91 STATIC_DESTRUCTOR_REGISTER(arg_usr_options, freep);
92 STATIC_DESTRUCTOR_REGISTER(arg_usr_hash, freep);
93 STATIC_ARRAY_DESTRUCTOR_REGISTER(arg_mounts, arg_n_mounts, mount_array_free);
94
95 static void mount_done(Mount *m) {
96 assert(m);
97
98 free(m->what);
99 free(m->where);
100 free(m->fstype);
101 free(m->options);
102 }
103
104 static void mount_array_free(Mount *mounts, size_t n) {
105 FOREACH_ARRAY(m, mounts, n)
106 mount_done(m);
107
108 free(mounts);
109 }
110
111 static int mount_array_add_internal(
112 bool for_initrd,
113 char *in_what,
114 char *in_where,
115 const char *in_fstype,
116 char *in_options) {
117
118 _cleanup_free_ char *what = NULL, *where = NULL, *fstype = NULL, *options = NULL;
119
120 /* This takes what and where. */
121
122 what = ASSERT_PTR(in_what);
123 where = in_where;
124 options = in_options;
125
126 fstype = strdup(isempty(in_fstype) ? "auto" : in_fstype);
127 if (!fstype)
128 return -ENOMEM;
129
130 if (streq(fstype, "swap"))
131 where = mfree(where);
132
133 if (!GREEDY_REALLOC(arg_mounts, arg_n_mounts + 1))
134 return -ENOMEM;
135
136 arg_mounts[arg_n_mounts++] = (Mount) {
137 .for_initrd = for_initrd,
138 .what = TAKE_PTR(what),
139 .where = TAKE_PTR(where),
140 .fstype = TAKE_PTR(fstype),
141 .options = TAKE_PTR(options),
142 };
143
144 return 0;
145 }
146
147 static int mount_array_add(bool for_initrd, const char *str) {
148 _cleanup_free_ char *what = NULL, *where = NULL, *fstype = NULL, *options = NULL;
149 int r;
150
151 assert(str);
152
153 r = extract_many_words(&str, ":", EXTRACT_CUNESCAPE | EXTRACT_DONT_COALESCE_SEPARATORS,
154 &what, &where, &fstype, &options);
155 if (r < 0)
156 return r;
157 if (r < 2)
158 return -EINVAL;
159 if (!isempty(str))
160 return -EINVAL;
161
162 return mount_array_add_internal(for_initrd, TAKE_PTR(what), TAKE_PTR(where), fstype, TAKE_PTR(options));
163 }
164
165 static int mount_array_add_swap(bool for_initrd, const char *str) {
166 _cleanup_free_ char *what = NULL, *options = NULL;
167 int r;
168
169 assert(str);
170
171 r = extract_many_words(&str, ":", EXTRACT_CUNESCAPE | EXTRACT_DONT_COALESCE_SEPARATORS,
172 &what, &options);
173 if (r < 0)
174 return r;
175 if (r < 1)
176 return -EINVAL;
177 if (!isempty(str))
178 return -EINVAL;
179
180 return mount_array_add_internal(for_initrd, TAKE_PTR(what), NULL, "swap", TAKE_PTR(options));
181 }
182
183 static int write_options(FILE *f, const char *options) {
184 _cleanup_free_ char *o = NULL;
185
186 assert(f);
187
188 if (isempty(options))
189 return 0;
190
191 if (streq(options, "defaults"))
192 return 0;
193
194 o = specifier_escape(options);
195 if (!o)
196 return log_oom();
197
198 fprintf(f, "Options=%s\n", o);
199 return 1;
200 }
201
202 static int write_what(FILE *f, const char *what) {
203 _cleanup_free_ char *w = NULL;
204
205 assert(f);
206 assert(what);
207
208 w = specifier_escape(what);
209 if (!w)
210 return log_oom();
211
212 fprintf(f, "What=%s\n", w);
213 return 1;
214 }
215
216 static int add_swap(
217 const char *source,
218 const char *what,
219 const char *options,
220 MountPointFlags flags) {
221
222 _cleanup_free_ char *name = NULL;
223 _cleanup_fclose_ FILE *f = NULL;
224 int r;
225
226 assert(what);
227
228 if (access("/proc/swaps", F_OK) < 0) {
229 log_info("Swap not supported, ignoring swap entry for %s.", what);
230 return 0;
231 }
232
233 if (detect_container() > 0) {
234 log_info("Running in a container, ignoring swap entry for %s.", what);
235 return 0;
236 }
237
238 if (arg_sysroot_check) {
239 log_info("%s should be enabled in the initrd, will request daemon-reload.", what);
240 return true;
241 }
242
243 log_debug("Found swap entry what=%s makefs=%s growfs=%s pcrfs=%s validatefs=%s noauto=%s nofail=%s",
244 what,
245 yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS),
246 yes_no(flags & MOUNT_PCRFS), yes_no(flags & MOUNT_VALIDATEFS),
247 yes_no(flags & MOUNT_NOAUTO), yes_no(flags & MOUNT_NOFAIL));
248
249 r = unit_name_from_path(what, ".swap", &name);
250 if (r < 0)
251 return log_error_errno(r, "Failed to generate unit name: %m");
252
253 r = generator_open_unit_file(arg_dest, source, name, &f);
254 if (r < 0)
255 return r;
256
257 fprintf(f,
258 "[Unit]\n"
259 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
260 "SourcePath=%s\n",
261 source);
262
263 r = generator_write_blockdev_dependency(f, what);
264 if (r < 0)
265 return r;
266
267 fprintf(f,
268 "\n"
269 "[Swap]\n");
270
271 r = write_what(f, what);
272 if (r < 0)
273 return r;
274
275 r = write_options(f, options);
276 if (r < 0)
277 return r;
278
279 r = fflush_and_check(f);
280 if (r < 0)
281 return log_error_errno(r, "Failed to write unit file %s: %m", name);
282
283 /* use what as where, to have a nicer error message */
284 r = generator_write_device_timeout(arg_dest, what, options, NULL);
285 if (r < 0)
286 return r;
287
288 if (flags & MOUNT_MAKEFS) {
289 r = generator_hook_up_mkswap(arg_dest, what);
290 if (r < 0)
291 return r;
292 }
293
294 if (flags & MOUNT_GROWFS)
295 /* TODO: swap devices must be wiped and recreated */
296 log_warning("%s: growing swap devices is currently unsupported.", what);
297 if (flags & MOUNT_PCRFS)
298 log_warning("%s: measuring swap devices is currently unsupported.", what);
299 if (flags & MOUNT_VALIDATEFS)
300 log_warning("%s: validating swap devices is currently unsupported.", what);
301
302 if (!(flags & MOUNT_NOAUTO)) {
303 r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET,
304 (flags & MOUNT_NOFAIL) ? "wants" : "requires", name);
305 if (r < 0)
306 return r;
307 }
308
309 return true;
310 }
311
312 static bool mount_is_network(const char *fstype, const char *options) {
313 return fstab_test_option(options, "_netdev\0") ||
314 (fstype && fstype_is_network(fstype));
315 }
316
317 static bool mount_in_initrd(const char *where, const char *options, bool accept_root) {
318 return fstab_test_option(options, "x-initrd.mount\0") ||
319 (where && PATH_IN_SET(where, "/usr", accept_root ? "/" : NULL));
320 }
321
322 static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
323 return generator_write_unit_timeout(f, where, opts,
324 "x-systemd.idle-timeout\0", "TimeoutIdleSec");
325 }
326
327 static int write_dependency(
328 FILE *f,
329 const char *where,
330 const char *opts,
331 const char *filter,
332 const char* const *unit_settings) {
333
334 _cleanup_strv_free_ char **unit_names = NULL;
335 _cleanup_free_ char *units = NULL;
336 int r;
337
338 assert(f);
339 assert(filter);
340 assert(unit_settings);
341
342 r = fstab_filter_options(opts, filter, NULL, NULL, &unit_names, NULL);
343 if (r < 0)
344 return log_error_errno(r, "Failed to parse options for '%s': %m", where);
345 if (r == 0)
346 return 0;
347
348 STRV_FOREACH(s, unit_names) {
349 _cleanup_free_ char *mangled = NULL;
350
351 r = unit_name_mangle_with_suffix(*s, "as dependency", 0, ".mount", &mangled);
352 if (r < 0)
353 return log_error_errno(r, "Failed to generate dependency unit name for '%s': %m", where);
354
355 if (!strextend_with_separator(&units, " ", mangled))
356 return log_oom();
357 }
358
359 STRV_FOREACH(setting, unit_settings)
360 fprintf(f, "%s=%s\n", *setting, units);
361
362 return 0;
363 }
364
365 static int write_after(FILE *f, const char *where, const char *opts) {
366 return write_dependency(f, where, opts,
367 "x-systemd.after\0", STRV_MAKE_CONST("After"));
368 }
369
370 static int write_requires_after(FILE *f, const char *where, const char *opts) {
371 return write_dependency(f, where, opts,
372 "x-systemd.requires\0", STRV_MAKE_CONST("Requires", "After"));
373 }
374
375 static int write_wants_after(FILE *f, const char *where, const char *opts) {
376 return write_dependency(f, where, opts,
377 "x-systemd.wants\0", STRV_MAKE_CONST("Wants", "After"));
378 }
379
380 static int write_before(FILE *f, const char *where, const char *opts) {
381 return write_dependency(f, where, opts,
382 "x-systemd.before\0", STRV_MAKE_CONST("Before"));
383 }
384
385 static int write_mounts_for(
386 FILE *f,
387 const char *where,
388 const char *opts,
389 const char *filter,
390 const char *unit_setting) {
391
392 _cleanup_strv_free_ char **paths = NULL, **paths_escaped = NULL;
393 int r;
394
395 assert(f);
396 assert(where);
397 assert(filter);
398 assert(unit_setting);
399
400 r = fstab_filter_options(opts, filter, NULL, NULL, &paths, NULL);
401 if (r < 0)
402 return log_error_errno(r, "Failed to parse options for '%s': %m", where);
403 if (r == 0)
404 return 0;
405
406 r = specifier_escape_strv(paths, &paths_escaped);
407 if (r < 0)
408 return log_error_errno(r, "Failed to escape paths for '%s': %m", where);
409
410 fprintf(f, "%s=", unit_setting);
411 fputstrv(f, paths_escaped, NULL, NULL);
412 fputc('\n', f);
413
414 return 0;
415 }
416
417 static int write_extra_dependencies(FILE *f, const char *where, const char *opts) {
418 int r;
419
420 assert(f);
421
422 if (isempty(opts))
423 return 0;
424
425 r = write_after(f, where, opts);
426 if (r < 0)
427 return r;
428
429 r = write_requires_after(f, where, opts);
430 if (r < 0)
431 return r;
432
433 r = write_wants_after(f, where, opts);
434 if (r < 0)
435 return r;
436
437 r = write_before(f, where, opts);
438 if (r < 0)
439 return r;
440
441 r = write_mounts_for(f, where, opts,
442 "x-systemd.requires-mounts-for\0", "RequiresMountsFor");
443 if (r < 0)
444 return r;
445
446 r = write_mounts_for(f, where, opts,
447 "x-systemd.wants-mounts-for\0", "WantsMountsFor");
448 if (r < 0)
449 return r;
450
451 return 0;
452 }
453
454 static int mandatory_mount_drop_unapplicable_options(
455 MountPointFlags *flags,
456 const char *where,
457 const char *options,
458 char **ret_options) {
459
460 int r;
461
462 assert(flags);
463 assert(where);
464 assert(ret_options);
465
466 if (!(*flags & (MOUNT_NOAUTO|MOUNT_NOFAIL|MOUNT_AUTOMOUNT)))
467 return strdup_to(ret_options, options);
468
469 log_debug("Mount '%s' is mandatory, ignoring 'noauto', 'nofail', and 'x-systemd.automount' options.",
470 where);
471
472 *flags &= ~(MOUNT_NOAUTO|MOUNT_NOFAIL|MOUNT_AUTOMOUNT);
473
474 r = fstab_filter_options(options, "noauto\0nofail\0x-systemd.automount\0", NULL, NULL, NULL, ret_options);
475 if (r < 0)
476 return r;
477
478 return 1;
479 }
480
481 static int add_mount(
482 const char *source,
483 const char *dest,
484 const char *what,
485 const char *where,
486 const char *original_where,
487 const char *fstype,
488 const char *opts,
489 int passno,
490 MountPointFlags flags,
491 const char *target_unit,
492 const char *extra_after) {
493
494 _cleanup_free_ char *name = NULL, *automount_name = NULL, *filtered = NULL, *where_escaped = NULL,
495 *opts_root_filtered = NULL;
496 _cleanup_strv_free_ char **wanted_by = NULL, **required_by = NULL;
497 _cleanup_fclose_ FILE *f = NULL;
498 int r;
499
500 assert(what);
501 assert(where);
502 assert(target_unit);
503 assert(source);
504
505 if (streq_ptr(fstype, "autofs"))
506 return 0;
507
508 if (!is_path(where)) {
509 log_warning("Mount point %s is not a valid path, ignoring.", where);
510 return 0;
511 }
512
513 if (mount_point_is_api(where) ||
514 mount_point_ignore(where))
515 return 0;
516
517 if (arg_sysroot_check) {
518 log_info("%s should be mounted in the initrd, will request daemon-reload.", where);
519 return true;
520 }
521
522 r = fstab_filter_options(opts, "x-systemd.wanted-by\0", NULL, NULL, &wanted_by, NULL);
523 if (r < 0)
524 return r;
525
526 r = fstab_filter_options(opts, "x-systemd.required-by\0", NULL, NULL, &required_by, NULL);
527 if (r < 0)
528 return r;
529
530 if (PATH_IN_SET(where, "/", "/usr")) {
531 r = mandatory_mount_drop_unapplicable_options(&flags, where, opts, &opts_root_filtered);
532 if (r < 0)
533 return r;
534 opts = opts_root_filtered;
535
536 if (!strv_isempty(wanted_by))
537 log_debug("Ignoring 'x-systemd.wanted-by=' option for root/usr device.");
538 if (!strv_isempty(required_by))
539 log_debug("Ignoring 'x-systemd.required-by=' option for root/usr device.");
540
541 required_by = strv_free(required_by);
542 wanted_by = strv_free(wanted_by);
543 }
544
545 r = unit_name_from_path(where, ".mount", &name);
546 if (r < 0)
547 return log_error_errno(r, "Failed to generate unit name: %m");
548
549 r = generator_open_unit_file(dest, source, name, &f);
550 if (r < 0)
551 return r;
552
553 fprintf(f,
554 "[Unit]\n"
555 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
556 "SourcePath=%s\n",
557 source);
558
559 if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !(flags & MOUNT_AUTOMOUNT) &&
560 fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
561 /* The default retry timeout that mount.nfs uses for 'bg' mounts
562 * is 10000 minutes, where as it uses 2 minutes for 'fg' mounts.
563 * As we are making 'bg' mounts look like an 'fg' mount to
564 * mount.nfs (so systemd can manage the job-control aspects of 'bg'),
565 * we need to explicitly preserve that default, and also ensure
566 * the systemd mount-timeout doesn't interfere.
567 * By placing these options first, they can be overridden by
568 * settings in /etc/fstab. */
569 opts = strjoina("x-systemd.mount-timeout=infinity,retry=10000,nofail,", opts, ",fg");
570 SET_FLAG(flags, MOUNT_NOFAIL, true);
571 }
572
573 if (!strv_isempty(wanted_by) || !strv_isempty(required_by)) {
574 /* If x-systemd.{wanted,required}-by= is specified, target_unit is not used */
575 target_unit = NULL;
576
577 /* Don't set default ordering dependencies on local-fs.target or remote-fs.target, but we
578 * still need to conflict with umount.target. */
579 fputs("DefaultDependencies=no\n"
580 "Conflicts=umount.target\n"
581 "Before=umount.target\n",
582 f);
583 }
584
585 r = write_extra_dependencies(f, where, opts);
586 if (r < 0)
587 return r;
588
589 /* Order the mount unit we generate relative to target_unit, so that DefaultDependencies= on the
590 * target unit won't affect us. */
591 if (target_unit && !FLAGS_SET(flags, MOUNT_NOFAIL))
592 fprintf(f, "Before=%s\n", target_unit);
593
594 if (extra_after)
595 fprintf(f, "After=%s\n", extra_after);
596
597 if (passno != 0) {
598 r = generator_write_fsck_deps(f, dest, what, where, fstype, opts);
599 if (r < 0)
600 return r;
601 }
602
603 r = generator_write_blockdev_dependency(f, what);
604 if (r < 0)
605 return r;
606
607 fprintf(f,
608 "\n"
609 "[Mount]\n");
610
611 r = write_what(f, what);
612 if (r < 0)
613 return r;
614
615 if (original_where)
616 fprintf(f, "# Canonicalized from %s\n", original_where);
617
618 where_escaped = specifier_escape(where);
619 if (!where_escaped)
620 return log_oom();
621 fprintf(f, "Where=%s\n", where_escaped);
622
623 if (!isempty(fstype) && !streq(fstype, "auto")) {
624 _cleanup_free_ char *t = NULL;
625
626 t = specifier_escape(fstype);
627 if (!t)
628 return -ENOMEM;
629
630 fprintf(f, "Type=%s\n", t);
631 }
632
633 r = generator_write_device_timeout(dest, what, opts, &filtered);
634 if (r < 0)
635 return r;
636
637 r = generator_write_network_device_deps(dest, what, where, opts);
638 if (r < 0)
639 return r;
640
641 if (in_initrd() && path_equal(where, "/sysroot") && is_device_path(what)) {
642 r = generator_write_initrd_root_device_deps(dest, what);
643 if (r < 0)
644 return r;
645 }
646
647 r = generator_write_mount_timeout(f, where, opts);
648 if (r < 0)
649 return r;
650
651 r = write_options(f, filtered);
652 if (r < 0)
653 return r;
654
655 if (flags & MOUNT_RW_ONLY)
656 fprintf(f, "ReadWriteOnly=yes\n");
657
658 r = fflush_and_check(f);
659 if (r < 0)
660 return log_error_errno(r, "Failed to write unit file %s: %m", name);
661
662 if (flags & MOUNT_MAKEFS) {
663 r = generator_hook_up_mkfs(dest, what, where, fstype);
664 if (r < 0)
665 return r;
666 }
667
668 if (flags & MOUNT_GROWFS) {
669 r = generator_hook_up_growfs(dest, where, target_unit);
670 if (r < 0)
671 return r;
672 }
673
674 if (flags & MOUNT_PCRFS) {
675 r = efi_measured_uki(LOG_WARNING);
676 if (r == 0)
677 log_debug("Kernel stub did not measure kernel image into PCR, skipping userspace measurement, too.");
678 else if (r > 0) {
679 r = generator_hook_up_pcrfs(dest, where, target_unit);
680 if (r < 0)
681 return r;
682 }
683 }
684
685 if (flags & MOUNT_VALIDATEFS) {
686 r = generator_hook_up_validatefs(dest, where, target_unit);
687 if (r < 0)
688 return r;
689 }
690
691 if (flags & MOUNT_QUOTA) {
692 r = generator_hook_up_quotacheck(dest, what, where, target_unit, fstype);
693 if (r < 0) {
694 if (r != -EOPNOTSUPP)
695 return r;
696 } else {
697 r = generator_hook_up_quotaon(dest, where, target_unit);
698 if (r < 0)
699 return r;
700 }
701 }
702
703 if (FLAGS_SET(flags, MOUNT_AUTOMOUNT)) {
704 r = unit_name_from_path(where, ".automount", &automount_name);
705 if (r < 0)
706 return log_error_errno(r, "Failed to generate unit name: %m");
707
708 f = safe_fclose(f);
709
710 r = generator_open_unit_file(dest, source, automount_name, &f);
711 if (r < 0)
712 return r;
713
714 fprintf(f,
715 "[Unit]\n"
716 "SourcePath=%s\n"
717 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
718 source);
719
720 fprintf(f,
721 "\n"
722 "[Automount]\n"
723 "Where=%s\n",
724 where_escaped);
725
726 r = write_idle_timeout(f, where, opts);
727 if (r < 0)
728 return r;
729
730 r = fflush_and_check(f);
731 if (r < 0)
732 return log_error_errno(r, "Failed to write unit file %s: %m", automount_name);
733 }
734
735 if (target_unit) {
736 assert(strv_isempty(wanted_by));
737 assert(strv_isempty(required_by));
738
739 /* noauto has no effect if x-systemd.automount is used */
740 if (!FLAGS_SET(flags, MOUNT_NOAUTO) || automount_name) {
741 r = generator_add_symlink(dest, target_unit,
742 FLAGS_SET(flags, MOUNT_NOFAIL) ? "wants" : "requires",
743 automount_name ?: name);
744 if (r < 0)
745 return r;
746 }
747 } else {
748 const char *unit_name = automount_name ?: name;
749
750 STRV_FOREACH(s, wanted_by) {
751 r = generator_add_symlink(dest, *s, "wants", unit_name);
752 if (r < 0)
753 return r;
754 }
755
756 STRV_FOREACH(s, required_by) {
757 r = generator_add_symlink(dest, *s, "requires", unit_name);
758 if (r < 0)
759 return r;
760 }
761
762 if ((flags & (MOUNT_NOAUTO|MOUNT_NOFAIL)) != 0)
763 log_warning("x-systemd.wanted-by= and/or x-systemd.required-by= specified, 'noauto' and 'nofail' have no effect.");
764 }
765
766 return true;
767 }
768
769 static int do_daemon_reload(void) {
770 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
771 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
772 int r, k;
773
774 log_debug("Calling org.freedesktop.systemd1.Manager.Reload()...");
775
776 r = bus_connect_system_systemd(&bus);
777 if (r < 0)
778 return log_error_errno(r, "Failed to get D-Bus connection: %m");
779
780 r = bus_service_manager_reload(bus);
781 if (r < 0)
782 return r;
783
784 /* We need to requeue the two targets so that any new units which previously were not part of the
785 * targets, and which we now added, will be started. */
786
787 r = 0;
788 FOREACH_STRING(unit, SPECIAL_INITRD_FS_TARGET, SPECIAL_SWAP_TARGET) {
789 log_info("Requesting %s/start/replace...", unit);
790
791 k = bus_call_method(bus, bus_systemd_mgr, "StartUnit", &error, NULL, "ss", unit, "replace");
792 if (k < 0) {
793 log_error_errno(k, "Failed to (re)start %s: %s", unit, bus_error_message(&error, r));
794 RET_GATHER(r, k);
795 }
796 }
797
798 return r;
799 }
800
801 static const char* sysroot_fstab_path(void) {
802 return getenv("SYSTEMD_SYSROOT_FSTAB") ?: "/sysroot/etc/fstab";
803 }
804
805 static bool sysfs_check(void) {
806 static int cached = -1;
807 int r;
808
809 if (cached < 0) {
810 r = secure_getenv_bool("SYSTEMD_SYSFS_CHECK");
811 if (r < 0 && r != -ENXIO)
812 log_debug_errno(r, "Failed to parse $SYSTEMD_SYSFS_CHECK, ignoring: %m");
813 cached = r != 0;
814 }
815
816 return cached;
817 }
818
819 static int add_sysusr_sysroot_usr_bind_mount(const char *source, bool validatefs) {
820 log_debug("Synthesizing entry what=/sysusr/usr where=/sysroot/usr opts=bind validatefs=%s", yes_no(validatefs));
821
822 return add_mount(source,
823 arg_dest,
824 "/sysusr/usr",
825 "/sysroot/usr",
826 /* original_where= */ NULL,
827 /* fstype= */ NULL,
828 "bind",
829 /* passno= */ 0,
830 validatefs ? MOUNT_VALIDATEFS : 0,
831 SPECIAL_INITRD_FS_TARGET,
832 /* extra_after= */ NULL);
833 }
834
835 static MountPointFlags fstab_options_to_flags(const char *options, bool is_swap) {
836 MountPointFlags flags = 0;
837
838 if (isempty(options))
839 return 0;
840
841 if (fstab_test_option(options, "x-systemd.makefs\0"))
842 flags |= MOUNT_MAKEFS;
843 if (fstab_test_option(options, "x-systemd.growfs\0"))
844 flags |= MOUNT_GROWFS;
845 if (fstab_test_option(options, "x-systemd.pcrfs\0"))
846 flags |= MOUNT_PCRFS;
847 if (fstab_test_option(options, "x-systemd.validatefs\0"))
848 flags |= MOUNT_VALIDATEFS;
849 if (fstab_test_option(options, "usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0" "prjquota\0"))
850 flags |= MOUNT_QUOTA;
851 if (fstab_test_yes_no_option(options, "noauto\0" "auto\0"))
852 flags |= MOUNT_NOAUTO;
853 if (fstab_test_yes_no_option(options, "nofail\0" "fail\0"))
854 flags |= MOUNT_NOFAIL;
855
856 if (!is_swap) {
857 if (fstab_test_option(options, "x-systemd.rw-only\0"))
858 flags |= MOUNT_RW_ONLY;
859 if (fstab_test_option(options,
860 "comment=systemd.automount\0"
861 "x-systemd.automount\0"))
862 flags |= MOUNT_AUTOMOUNT;
863 }
864
865 return flags;
866 }
867
868 static int canonicalize_mount_path(const char *path, const char *type, bool prefix_sysroot, char **ret) {
869 _cleanup_free_ char *p = NULL;
870 bool changed;
871 int r;
872
873 assert(path);
874 assert(type);
875 assert(STR_IN_SET(type, "where", "what"));
876 assert(ret);
877
878 // FIXME: when chase() learns to chase non-existent paths, use this here and drop the prefixing with
879 // /sysroot on error below.
880 r = chase(path, prefix_sysroot ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &p, NULL);
881 if (r < 0) {
882 log_debug_errno(r, "Failed to chase '%s', using as-is: %m", path);
883
884 if (prefix_sysroot)
885 p = path_join("/sysroot", path);
886 else
887 p = strdup(path);
888 if (!p)
889 return log_oom();
890
891 path_simplify(p);
892 }
893
894 changed = !streq(path, p);
895 if (changed)
896 log_debug("Canonicalized %s=%s to %s", type, path, p);
897
898 *ret = TAKE_PTR(p);
899 return changed;
900 }
901
902 static int parse_fstab_one(
903 const char *source,
904 const char *what_original,
905 const char *where_original,
906 const char *fstype,
907 const char *options,
908 int passno,
909 bool prefix_sysroot,
910 bool accept_root, /* This takes an effect only when prefix_sysroot is true. */
911 bool use_swap_enabled) {
912
913 _cleanup_free_ char *what = NULL, *where = NULL, *opts = NULL;
914 MountPointFlags flags;
915 bool is_swap, where_changed;
916 int r;
917
918 assert(what_original);
919 assert(fstype);
920
921 if (prefix_sysroot && !mount_in_initrd(where_original, options, accept_root))
922 return 0;
923
924 is_swap = streq_ptr(fstype, "swap");
925 if (is_swap && use_swap_enabled && !arg_swap_enabled) {
926 log_info("Swap unit generation disabled on kernel command line, ignoring swap entry for %s.", what_original);
927 return 0;
928 }
929
930 what = fstab_node_to_udev_node(what_original);
931 if (!what)
932 return log_oom();
933
934 if (path_is_read_only_fs("/sys") > 0 &&
935 (streq(what, "sysfs") ||
936 (sysfs_check() && is_device_path(what)))) {
937 log_info("/sys/ is read-only (running in a container?), ignoring mount for %s.", what);
938 return 0;
939 }
940
941 flags = fstab_options_to_flags(options, is_swap);
942
943 if (is_swap)
944 return add_swap(source, what, options, flags);
945
946 if (passno < 0)
947 passno = is_device_path(what);
948
949 assert(where_original); /* 'where' is not necessary for swap entry. */
950
951 if (!is_path(where_original)) {
952 log_warning("Mount point %s is not a valid path, ignoring.", where_original);
953 return 0;
954 }
955
956 /* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
957 * mount units, but causes problems since it historically worked to have symlinks in e.g.
958 * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
959 * where a symlink refers to another mount target; this works assuming the sub-mountpoint
960 * target is the final directory. */
961 r = canonicalize_mount_path(where_original, "where", prefix_sysroot, &where);
962 if (r < 0)
963 return r;
964 where_changed = r > 0;
965
966 if (prefix_sysroot && fstab_is_bind(options, fstype)) {
967 /* When in initrd, the source of bind mount needs to be prepended with /sysroot as well. */
968 _cleanup_free_ char *p = NULL;
969
970 r = canonicalize_mount_path(what, "what", prefix_sysroot, &p);
971 if (r < 0)
972 return r;
973
974 free_and_replace(what, p);
975 }
976
977 log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s pcrfs=%s validatefs=%s noauto=%s nofail=%s",
978 what, where, strna(fstype),
979 yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS),
980 yes_no(flags & MOUNT_PCRFS), yes_no(flags & MOUNT_VALIDATEFS),
981 yes_no(flags & MOUNT_NOAUTO), yes_no(flags & MOUNT_NOFAIL));
982
983 bool is_sysroot = in_initrd() && path_equal(where, "/sysroot");
984 /* See comment from add_sysroot_usr_mount() about the need for extra indirection in case /usr needs
985 * to be mounted in order for the root fs to be synthesized based on configuration included in /usr/,
986 * e.g. systemd-repart. */
987 bool is_sysroot_usr = in_initrd() && path_equal(where, "/sysroot/usr");
988
989 const char *target_unit =
990 is_sysroot ? SPECIAL_INITRD_ROOT_FS_TARGET :
991 is_sysroot_usr ? SPECIAL_INITRD_USR_FS_TARGET :
992 prefix_sysroot ? SPECIAL_INITRD_FS_TARGET :
993 mount_is_network(fstype, options) ? SPECIAL_REMOTE_FS_TARGET :
994 SPECIAL_LOCAL_FS_TARGET;
995
996 /* nofail, noauto and x-systemd.automount don't make sense for critical filesystems we must mount in initrd. */
997 if (is_sysroot || is_sysroot_usr) {
998 r = mandatory_mount_drop_unapplicable_options(&flags, where, options, &opts);
999 if (r < 0)
1000 return r;
1001 options = opts;
1002 }
1003
1004 r = add_mount(source,
1005 arg_dest,
1006 what,
1007 is_sysroot_usr ? "/sysusr/usr" : where,
1008 !is_sysroot_usr && where_changed ? where_original : NULL,
1009 fstype,
1010 options,
1011 passno,
1012 flags & ~(is_sysroot_usr ? MOUNT_VALIDATEFS : 0),
1013 target_unit,
1014 /* extra_after= */ NULL);
1015 if (r <= 0)
1016 return r;
1017
1018 if (is_sysroot_usr) {
1019 r = add_sysusr_sysroot_usr_bind_mount(source, flags & MOUNT_VALIDATEFS);
1020 if (r < 0)
1021 return r;
1022 }
1023
1024 return true;
1025 }
1026
1027 static int parse_fstab(bool prefix_sysroot) {
1028 _cleanup_endmntent_ FILE *f = NULL;
1029 const char *fstab;
1030 struct mntent *me;
1031 int r, ret = 0;
1032
1033 if (prefix_sysroot)
1034 fstab = sysroot_fstab_path();
1035 else {
1036 fstab = fstab_path();
1037 assert(!arg_sysroot_check);
1038 }
1039
1040 log_debug("Parsing %s...", fstab);
1041
1042 f = setmntent(fstab, "re");
1043 if (!f) {
1044 if (errno == ENOENT)
1045 return 0;
1046
1047 return log_error_errno(errno, "Failed to open %s: %m", fstab);
1048 }
1049
1050 while ((me = getmntent(f))) {
1051 r = parse_fstab_one(fstab,
1052 me->mnt_fsname, me->mnt_dir, me->mnt_type, me->mnt_opts, me->mnt_passno,
1053 prefix_sysroot,
1054 /* accept_root = */ false,
1055 /* use_swap_enabled = */ true);
1056 if (r < 0 && ret >= 0)
1057 ret = r;
1058 if (arg_sysroot_check && r > 0)
1059 return true; /* We found a mount or swap that would be started… */
1060 }
1061
1062 return ret;
1063 }
1064
1065 static int mount_source_is_nfsroot(const char *what) {
1066 union in_addr_union u;
1067 const char *sep, *a;
1068 int r;
1069
1070 assert(what);
1071
1072 /* From dracut.cmdline(7).
1073 *
1074 * root=[<server-ip>:]<root-dir>[:<nfs-options>]
1075 * root=nfs:[<server-ip>:]<root-dir>[:<nfs-options>],
1076 * root=nfs4:[<server-ip>:]<root-dir>[:<nfs-options>],
1077 * root={dhcp|dhcp6}
1078 *
1079 * mount nfs share from <server-ip>:/<root-dir>, if no server-ip is given, use dhcp next_server.
1080 * If server-ip is an IPv6 address it has to be put in brackets, e.g. [2001:DB8::1]. NFS options
1081 * can be appended with the prefix ":" or "," and are separated by ",". */
1082
1083 if (path_equal(what, "/dev/nfs") ||
1084 STR_IN_SET(what, "dhcp", "dhcp6") ||
1085 STARTSWITH_SET(what, "nfs:", "nfs4:"))
1086 return true;
1087
1088 /* IPv6 address */
1089 if (what[0] == '[') {
1090 sep = strchr(what + 1, ']');
1091 if (!sep)
1092 return -EINVAL;
1093
1094 a = strndupa_safe(what + 1, sep - what - 1);
1095
1096 r = in_addr_from_string(AF_INET6, a, &u);
1097 if (r < 0)
1098 return r;
1099
1100 return true;
1101 }
1102
1103 /* IPv4 address */
1104 sep = strchr(what, ':');
1105 if (sep) {
1106 a = strndupa_safe(what, sep - what);
1107
1108 if (in_addr_from_string(AF_INET, a, &u) >= 0)
1109 return true;
1110 }
1111
1112 /* root directory without address */
1113 return path_is_absolute(what) && !path_startswith(what, "/dev");
1114 }
1115
1116 static bool validate_root_or_usr_mount_source(const char *what, const char *switch_name) {
1117 int r;
1118
1119 assert(switch_name);
1120
1121 if (isempty(what)) {
1122 log_debug("No %s switch specified on the kernel command line.", switch_name);
1123 return false;
1124 }
1125
1126 if (streq(what, "off")) {
1127 log_debug("Skipping %s directory handling, as this was explicitly turned off.", switch_name);
1128 return false;
1129 }
1130
1131 if (parse_gpt_auto_root(switch_name, what) > 0) {
1132 /* This is handled by gpt-auto-generator */
1133 log_debug("Skipping %s directory handling, as gpt-auto was requested.", switch_name);
1134 return false;
1135 }
1136
1137 if (streq(what, "fstab")) {
1138 /* This is handled by parse_fstab() */
1139 log_debug("Using initrd's fstab for %s configuration.", switch_name);
1140 return false;
1141 }
1142
1143 r = mount_source_is_nfsroot(what);
1144 if (r < 0)
1145 log_debug_errno(r, "Failed to determine if the %s directory is on NFS, assuming not: %m", switch_name);
1146 else if (r > 0) {
1147 /* This is handled by the kernel or the initrd */
1148 log_debug("Skipping %s directory handling, as root on NFS was requested.", switch_name);
1149 return false;
1150 }
1151
1152 if (startswith(what, "cifs://")) {
1153 log_debug("Skipping %s directory handling, as root on CIFS was requested.", switch_name);
1154 return false;
1155 }
1156
1157 if (startswith(what, "iscsi:")) {
1158 log_debug("Skipping %s directory handling, as root on iSCSI was requested.", switch_name);
1159 return false;
1160 }
1161
1162 if (startswith(what, "live:")) {
1163 log_debug("Skipping %s directory handling, as root on live image was requested.", switch_name);
1164 return false;
1165 }
1166
1167 return true;
1168 }
1169
1170 static int add_sysroot_mount(void) {
1171 _cleanup_free_ char *what = NULL;
1172 const char *extra_opts = NULL, *fstype = NULL;
1173 bool default_rw = true;
1174 MountPointFlags flags;
1175
1176 if (!validate_root_or_usr_mount_source(arg_root_what, "root="))
1177 return 0;
1178
1179 const char *bind = startswith(arg_root_what, "bind:");
1180 if (bind) {
1181 if (!path_is_valid(bind) || !path_is_absolute(bind)) {
1182 log_debug("Invalid root=bind: source path, ignoring: %s", bind);
1183 return 0;
1184 }
1185
1186 what = strdup(bind);
1187 if (!what)
1188 return log_oom();
1189
1190 extra_opts = "bind";
1191
1192 } else if (streq(arg_root_what, "tmpfs")) {
1193 /* If root=tmpfs is specified, then take this as shortcut for a writable tmpfs mount as root */
1194
1195 what = strdup("rootfs"); /* just a pretty name, to show up in /proc/self/mountinfo */
1196 if (!what)
1197 return log_oom();
1198
1199 fstype = arg_root_fstype ?: "tmpfs"; /* tmpfs, unless overridden */
1200 if (streq(fstype, "tmpfs") && !fstab_test_option(arg_root_options, "mode\0"))
1201 extra_opts = "mode=0755"; /* root directory should not be world/group writable, unless overridden */
1202 } else {
1203
1204 what = fstab_node_to_udev_node(arg_root_what);
1205 if (!what)
1206 return log_oom();
1207
1208 fstype = arg_root_fstype; /* if not specified explicitly, don't default to anything here */
1209 default_rw = false; /* read-only, unless overridden */
1210 }
1211
1212 _cleanup_free_ char *combined_options = NULL;
1213 if (strdup_to(&combined_options, arg_root_options) < 0)
1214 return log_oom();
1215
1216 if (arg_root_rw >= 0 || !fstab_test_option(combined_options, "ro\0" "rw\0"))
1217 if (!strextend_with_separator(&combined_options, ",", arg_root_rw > 0 || (arg_root_rw < 0 && default_rw) ? "rw" : "ro"))
1218 return log_oom();
1219
1220 if (extra_opts)
1221 if (!strextend_with_separator(&combined_options, ",", extra_opts))
1222 return log_oom();
1223
1224 log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what, strna(fstype), strempty(combined_options));
1225
1226 /* Only honor x-systemd.makefs and .validatefs here, others are not relevant in initrd/not used
1227 * at all (also see mandatory_mount_drop_unapplicable_options()) */
1228 flags = fstab_options_to_flags(combined_options, /* is_swap = */ false) & (MOUNT_MAKEFS|MOUNT_VALIDATEFS);
1229
1230 return add_mount("/proc/cmdline",
1231 arg_dest,
1232 what,
1233 "/sysroot",
1234 /* original_where= */ NULL,
1235 fstype,
1236 combined_options,
1237 /* passno= */ is_device_path(what) ? 1 : 0,
1238 flags,
1239 SPECIAL_INITRD_ROOT_FS_TARGET,
1240 "imports.target");
1241 }
1242
1243 static int add_sysroot_usr_mount(void) {
1244 _cleanup_free_ char *what = NULL;
1245 const char *extra_opts = NULL;
1246 bool makefs, validatefs;
1247 int r;
1248
1249 /* Returns 0 if we didn't do anything, > 0 if we either generated a unit for the /usr/ mount, or we
1250 * know for sure something else did */
1251
1252 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
1253 return 0;
1254
1255 if (arg_root_what && !arg_usr_what) {
1256 /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
1257 arg_usr_what = strdup(arg_root_what);
1258 if (!arg_usr_what)
1259 return log_oom();
1260 }
1261
1262 if (arg_root_fstype && !arg_usr_fstype) {
1263 arg_usr_fstype = strdup(arg_root_fstype);
1264 if (!arg_usr_fstype)
1265 return log_oom();
1266 }
1267
1268 if (arg_root_options && !arg_usr_options) {
1269 arg_usr_options = strdup(arg_root_options);
1270 if (!arg_usr_options)
1271 return log_oom();
1272 }
1273
1274 if (!validate_root_or_usr_mount_source(arg_usr_what, "mount.usr="))
1275 return 0;
1276
1277 const char *bind = startswith(arg_usr_what, "bind:");
1278 if (bind) {
1279 if (!path_is_valid(bind) || !path_is_absolute(bind)) {
1280 log_debug("Invalid mount.usr=bind: source path, ignoring: %s", bind);
1281 return 0;
1282 }
1283
1284 what = strdup(bind);
1285 if (!what)
1286 return log_oom();
1287
1288 extra_opts = "bind";
1289 } else {
1290 what = fstab_node_to_udev_node(arg_usr_what);
1291 if (!what)
1292 return log_oom();
1293 }
1294
1295 _cleanup_free_ char *combined_options = NULL;
1296 if (strdup_to(&combined_options, arg_usr_options) < 0)
1297 return log_oom();
1298
1299 if (!fstab_test_option(combined_options, "ro\0" "rw\0"))
1300 if (!strextend_with_separator(&combined_options, ",", arg_root_rw > 0 ? "rw" : "ro"))
1301 return log_oom();
1302
1303 if (extra_opts)
1304 if (!strextend_with_separator(&combined_options, ",", extra_opts))
1305 return log_oom();
1306
1307 /* When mounting /usr from the initrd, we add an extra level of indirection: we first mount the /usr/
1308 * partition to /sysusr/usr/, and then afterwards bind mount that to /sysroot/usr/. We do this so
1309 * that we can cover for systems that initially only have a /usr/ around and where the root fs needs
1310 * to be synthesized, based on configuration included in /usr/, e.g. systemd-repart. Software like
1311 * this should order itself after initrd-usr-fs.target and before initrd-fs.target; and it should
1312 * look into both /sysusr/ and /sysroot/ for the configuration data to apply. */
1313
1314 log_debug("Found entry what=%s where=/sysusr/usr type=%s opts=%s", what, strna(arg_usr_fstype), strempty(combined_options));
1315
1316 /* Only honor x-systemd.makefs and .validatefs here, others are not relevant in initrd/not used
1317 * at all (also see mandatory_mount_drop_unapplicable_options()) */
1318 makefs = fstab_test_option(combined_options, "x-systemd.makefs\0");
1319 validatefs = fstab_test_option(combined_options, "x-systemd.validatefs\0");
1320
1321 r = add_mount("/proc/cmdline",
1322 arg_dest,
1323 what,
1324 "/sysusr/usr",
1325 /* original_where= */ NULL,
1326 arg_usr_fstype,
1327 combined_options,
1328 /* passno= */ is_device_path(what) ? 1 : 0,
1329 makefs ? MOUNT_MAKEFS : 0,
1330 SPECIAL_INITRD_USR_FS_TARGET,
1331 "imports.target");
1332 if (r < 0)
1333 return r;
1334
1335 r = add_sysusr_sysroot_usr_bind_mount("/proc/cmdline", validatefs);
1336 if (r < 0)
1337 return r;
1338
1339 return 1;
1340 }
1341
1342 static int add_sysroot_usr_mount_or_fallback(void) {
1343 int r;
1344
1345 r = add_sysroot_usr_mount();
1346 if (r != 0)
1347 return r;
1348
1349 /* OK, so we didn't write anything out for /sysusr/usr/ nor /sysroot/usr/. In this case, let's make
1350 * sure that initrd-usr-fs.target is at least ordered after sysroot.mount so that services that order
1351 * themselves after it get the guarantee that /usr/ is definitely mounted somewhere. */
1352
1353 return generator_add_symlink(
1354 arg_dest,
1355 SPECIAL_INITRD_USR_FS_TARGET,
1356 "requires",
1357 "sysroot.mount");
1358 }
1359
1360 static int add_volatile_root(void) {
1361
1362 /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
1363 * requested (or as an overlayfs), leaving only /usr from the root mount inside. */
1364
1365 if (!IN_SET(arg_volatile_mode, VOLATILE_YES, VOLATILE_OVERLAY))
1366 return 0;
1367
1368 return generator_add_symlink(arg_dest, SPECIAL_INITRD_ROOT_FS_TARGET, "requires",
1369 SYSTEM_DATA_UNIT_DIR "/" SPECIAL_VOLATILE_ROOT_SERVICE);
1370 }
1371
1372 static int add_volatile_var(void) {
1373
1374 if (arg_volatile_mode != VOLATILE_STATE)
1375 return 0;
1376
1377 /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
1378
1379 return add_mount("/proc/cmdline",
1380 arg_dest_late,
1381 "tmpfs",
1382 "/var",
1383 /* original_where= */ NULL,
1384 "tmpfs",
1385 "mode=0755" TMPFS_LIMITS_VAR,
1386 /* passno= */ 0,
1387 /* flags= */ 0,
1388 SPECIAL_LOCAL_FS_TARGET,
1389 /* extra_after= */ NULL);
1390 }
1391
1392 static int add_mounts_from_cmdline(void) {
1393 int r = 0;
1394
1395 /* Handle each entries found in cmdline as a fstab entry. */
1396
1397 FOREACH_ARRAY(m, arg_mounts, arg_n_mounts) {
1398 if (m->for_initrd && !in_initrd())
1399 continue;
1400
1401 RET_GATHER(r, parse_fstab_one("/proc/cmdline",
1402 m->what,
1403 m->where,
1404 m->fstype,
1405 m->options,
1406 /* passno = */ -1,
1407 /* prefix_sysroot = */ !m->for_initrd && in_initrd(),
1408 /* accept_root = */ true,
1409 /* use_swap_enabled = */ false));
1410 }
1411
1412 return r;
1413 }
1414
1415 static int add_mounts_from_creds(bool prefix_sysroot) {
1416 _cleanup_free_ void *b = NULL;
1417 struct mntent *me;
1418 size_t bs;
1419 int r;
1420
1421 assert(in_initrd() || !prefix_sysroot);
1422
1423 r = read_credential_with_decryption(
1424 in_initrd() && !prefix_sysroot ? "fstab.extra.initrd" : "fstab.extra",
1425 &b, &bs);
1426 if (r <= 0)
1427 return r;
1428
1429 _cleanup_fclose_ FILE *f = NULL;
1430 f = fmemopen_unlocked(b, bs, "r");
1431 if (!f)
1432 return log_oom();
1433
1434 r = 0;
1435
1436 while ((me = getmntent(f)))
1437 RET_GATHER(r, parse_fstab_one("/run/credentials",
1438 me->mnt_fsname,
1439 me->mnt_dir,
1440 me->mnt_type,
1441 me->mnt_opts,
1442 me->mnt_passno,
1443 /* prefix_sysroot = */ prefix_sysroot,
1444 /* accept_root = */ true,
1445 /* use_swap_enabled = */ true));
1446
1447 return r;
1448 }
1449
1450 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
1451 int r;
1452
1453 assert(key);
1454
1455 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
1456 * instance should take precedence. In the case of multiple rootflags=
1457 * or usrflags= the arguments should be concatenated */
1458
1459 if (STR_IN_SET(key, "fstab", "rd.fstab")) {
1460
1461 r = value ? parse_boolean(value) : 1;
1462 if (r < 0)
1463 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
1464 else
1465 arg_fstab_enabled = fstab_set_enabled(r);
1466
1467 } else if (streq(key, "root")) {
1468
1469 if (proc_cmdline_value_missing(key, value))
1470 return 0;
1471
1472 return free_and_strdup_warn(&arg_root_what, empty_to_null(value));
1473
1474 } else if (streq(key, "rootfstype")) {
1475
1476 if (proc_cmdline_value_missing(key, value))
1477 return 0;
1478
1479 return free_and_strdup_warn(&arg_root_fstype, empty_to_null(value));
1480
1481 } else if (streq(key, "rootflags")) {
1482
1483 if (proc_cmdline_value_missing(key, value))
1484 return 0;
1485
1486 if (!strextend_with_separator(&arg_root_options, ",", value))
1487 return log_oom();
1488
1489 } else if (streq(key, "roothash")) {
1490
1491 if (proc_cmdline_value_missing(key, value))
1492 return 0;
1493
1494 return free_and_strdup_warn(&arg_root_hash, empty_to_null(value));
1495
1496 } else if (streq(key, "mount.usr")) {
1497
1498 if (proc_cmdline_value_missing(key, value))
1499 return 0;
1500
1501 return free_and_strdup_warn(&arg_usr_what, empty_to_null(value));
1502
1503 } else if (streq(key, "mount.usrfstype")) {
1504
1505 if (proc_cmdline_value_missing(key, value))
1506 return 0;
1507
1508 return free_and_strdup_warn(&arg_usr_fstype, empty_to_null(value));
1509
1510 } else if (streq(key, "mount.usrflags")) {
1511
1512 if (proc_cmdline_value_missing(key, value))
1513 return 0;
1514
1515 if (!strextend_with_separator(&arg_usr_options, ",", value))
1516 return log_oom();
1517
1518 } else if (streq(key, "usrhash")) {
1519
1520 if (proc_cmdline_value_missing(key, value))
1521 return 0;
1522
1523 return free_and_strdup_warn(&arg_usr_hash, empty_to_null(value));
1524
1525 } else if (streq(key, "rw") && !value)
1526 arg_root_rw = true;
1527 else if (streq(key, "ro") && !value)
1528 arg_root_rw = false;
1529 else if (streq(key, "systemd.volatile")) {
1530 VolatileMode m;
1531
1532 if (value) {
1533 m = volatile_mode_from_string(value);
1534 if (m < 0)
1535 log_warning_errno(m, "Failed to parse systemd.volatile= argument: %s", value);
1536 else
1537 arg_volatile_mode = m;
1538 } else
1539 arg_volatile_mode = VOLATILE_YES;
1540
1541 } else if (streq(key, "systemd.swap")) {
1542
1543 r = value ? parse_boolean(value) : 1;
1544 if (r < 0)
1545 log_warning("Failed to parse systemd.swap switch %s. Ignoring.", value);
1546 else
1547 arg_swap_enabled = r;
1548
1549 } else if (streq(key, "systemd.verity")) {
1550
1551 r = value ? parse_boolean(value) : 1;
1552 if (r < 0)
1553 log_warning("Failed to parse systemd.verity= kernel command line switch %s. Ignoring.", value);
1554 else
1555 arg_verity = r;
1556
1557 } else if (STR_IN_SET(key, "systemd.mount-extra", "rd.systemd.mount-extra")) {
1558
1559 if (proc_cmdline_value_missing(key, value))
1560 return 0;
1561
1562 r = mount_array_add(startswith(key, "rd."), value);
1563 if (r < 0)
1564 log_warning("Failed to parse systemd.mount-extra= option, ignoring: %s", value);
1565
1566 } else if (STR_IN_SET(key, "systemd.swap-extra", "rd.systemd.swap-extra")) {
1567
1568 if (proc_cmdline_value_missing(key, value))
1569 return 0;
1570
1571 r = mount_array_add_swap(startswith(key, "rd."), value);
1572 if (r < 0)
1573 log_warning("Failed to parse systemd.swap-extra= option, ignoring: %s", value);
1574 }
1575
1576 return 0;
1577 }
1578
1579 static int determine_device(
1580 char **what,
1581 int *rw,
1582 char **options,
1583 const char *hash,
1584 const char *name) {
1585
1586 assert(what);
1587 assert(name);
1588
1589 /* If we have a hash but no device then Verity is used, and we use the DM device. */
1590 if (*what)
1591 return 0;
1592
1593 if (!hash)
1594 return 0;
1595
1596 if (!arg_verity)
1597 return 0;
1598
1599 *what = path_join("/dev/mapper/", name);
1600 if (!*what)
1601 return log_oom();
1602
1603 /* Verity is always read-only */
1604 if (rw)
1605 *rw = false;
1606 if (options && !strextend_with_separator(options, ",", "ro"))
1607 return log_oom();
1608
1609 log_info("Using verity %s device %s.", name, *what);
1610 return 1;
1611 }
1612
1613 static int determine_root(void) {
1614 return determine_device(&arg_root_what, &arg_root_rw, NULL, arg_root_hash, "root");
1615 }
1616
1617 static int determine_usr(void) {
1618 return determine_device(&arg_usr_what, NULL, &arg_usr_options, arg_usr_hash, "usr");
1619 }
1620
1621 /* If arg_sysroot_check is false, run as generator in the usual fashion.
1622 * If it is true, check /sysroot/etc/fstab for any units that we'd want to mount
1623 * in the initrd, and call daemon-reload. We will get reinvoked as a generator,
1624 * with /sysroot/etc/fstab available, and then we can write additional units based
1625 * on that file. */
1626 static int run_generator(void) {
1627 int r;
1628
1629 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
1630 if (r < 0)
1631 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
1632
1633 (void) determine_root();
1634 (void) determine_usr();
1635
1636 if (arg_sysroot_check) {
1637 r = parse_fstab(/* prefix_sysroot = */ true);
1638 if (r == 0)
1639 log_debug("Nothing interesting found, not doing daemon-reload.");
1640 if (r > 0)
1641 r = do_daemon_reload();
1642 return r;
1643 }
1644
1645 r = 0;
1646
1647 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
1648 if (in_initrd()) {
1649 RET_GATHER(r, add_sysroot_mount());
1650
1651 RET_GATHER(r, add_sysroot_usr_mount_or_fallback());
1652
1653 RET_GATHER(r, add_volatile_root());
1654 } else
1655 RET_GATHER(r, add_volatile_var());
1656
1657 /* Honour /etc/fstab only when that's enabled */
1658 if (arg_fstab_enabled) {
1659 /* Parse the local /etc/fstab, possibly from the initrd */
1660 RET_GATHER(r, parse_fstab(/* prefix_sysroot = */ false));
1661
1662 /* If running in the initrd also parse the /etc/fstab from the host */
1663 if (in_initrd())
1664 RET_GATHER(r, parse_fstab(/* prefix_sysroot = */ true));
1665 else
1666 RET_GATHER(r, generator_enable_remount_fs_service(arg_dest));
1667 }
1668
1669 RET_GATHER(r, add_mounts_from_cmdline());
1670
1671 RET_GATHER(r, add_mounts_from_creds(/* prefix_sysroot = */ false));
1672
1673 if (in_initrd())
1674 RET_GATHER(r, add_mounts_from_creds(/* prefix_sysroot = */ true));
1675
1676 return r;
1677 }
1678
1679 static int run(int argc, char **argv) {
1680 arg_sysroot_check = invoked_as(argv, "systemd-sysroot-fstab-check");
1681
1682 if (arg_sysroot_check) {
1683 /* Run as in systemd-sysroot-fstab-check mode */
1684 log_setup();
1685
1686 if (strv_length(argv) > 1)
1687 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1688 "This program takes no arguments.");
1689 if (!in_initrd())
1690 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1691 "This program is only useful in the initrd.");
1692 } else {
1693 /* Run in generator mode */
1694 log_setup_generator();
1695
1696 if (!IN_SET(strv_length(argv), 2, 4))
1697 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1698 "This program takes one or three arguments.");
1699
1700 arg_dest = ASSERT_PTR(argv[1]);
1701 arg_dest_late = ASSERT_PTR(argv[argc > 3 ? 3 : 1]);
1702 }
1703
1704 return run_generator();
1705 }
1706
1707 DEFINE_MAIN_FUNCTION(run);