]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/fstab-generator/fstab-generator.c
Merge pull request #7547 from hvenev/sysctl-no-net-default
[thirdparty/systemd.git] / src / fstab-generator / fstab-generator.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <mntent.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "alloc-util.h"
28 #include "fd-util.h"
29 #include "fileio.h"
30 #include "fs-util.h"
31 #include "fstab-util.h"
32 #include "generator.h"
33 #include "log.h"
34 #include "mkdir.h"
35 #include "mount-setup.h"
36 #include "mount-util.h"
37 #include "parse-util.h"
38 #include "path-util.h"
39 #include "proc-cmdline.h"
40 #include "special.h"
41 #include "specifier.h"
42 #include "stat-util.h"
43 #include "string-util.h"
44 #include "strv.h"
45 #include "unit-name.h"
46 #include "util.h"
47 #include "virt.h"
48 #include "volatile-util.h"
49
50 typedef enum MountpointFlags {
51 NOAUTO = 1 << 0,
52 NOFAIL = 1 << 1,
53 AUTOMOUNT = 1 << 2,
54 MAKEFS = 1 << 3,
55 GROWFS = 1 << 4,
56 } MountpointFlags;
57
58 static const char *arg_dest = "/tmp";
59 static const char *arg_dest_late = "/tmp";
60 static bool arg_fstab_enabled = true;
61 static char *arg_root_what = NULL;
62 static char *arg_root_fstype = NULL;
63 static char *arg_root_options = NULL;
64 static char *arg_root_hash = NULL;
65 static int arg_root_rw = -1;
66 static char *arg_usr_what = NULL;
67 static char *arg_usr_fstype = NULL;
68 static char *arg_usr_options = NULL;
69 static VolatileMode arg_volatile_mode = _VOLATILE_MODE_INVALID;
70
71 static int write_options(FILE *f, const char *options) {
72 _cleanup_free_ char *o = NULL;
73
74 if (isempty(options))
75 return 0;
76
77 if (streq(options, "defaults"))
78 return 0;
79
80 o = specifier_escape(options);
81 if (!o)
82 return log_oom();
83
84 fprintf(f, "Options=%s\n", o);
85 return 1;
86 }
87
88 static int write_what(FILE *f, const char *what) {
89 _cleanup_free_ char *w = NULL;
90
91 w = specifier_escape(what);
92 if (!w)
93 return log_oom();
94
95 fprintf(f, "What=%s\n", w);
96 return 1;
97 }
98
99 static int add_swap(
100 const char *what,
101 struct mntent *me,
102 MountpointFlags flags) {
103
104 _cleanup_free_ char *name = NULL, *unit = NULL;
105 _cleanup_fclose_ FILE *f = NULL;
106 int r;
107
108 assert(what);
109 assert(me);
110
111 if (access("/proc/swaps", F_OK) < 0) {
112 log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
113 return 0;
114 }
115
116 if (detect_container() > 0) {
117 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
118 return 0;
119 }
120
121 r = unit_name_from_path(what, ".swap", &name);
122 if (r < 0)
123 return log_error_errno(r, "Failed to generate unit name: %m");
124
125 unit = strjoin(arg_dest, "/", name);
126 if (!unit)
127 return log_oom();
128
129 f = fopen(unit, "wxe");
130 if (!f)
131 return log_error_errno(errno,
132 errno == EEXIST ?
133 "Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?" :
134 "Failed to create unit file %s: %m",
135 unit);
136
137 fputs_unlocked("# Automatically generated by systemd-fstab-generator\n\n"
138 "[Unit]\n"
139 "SourcePath=/etc/fstab\n"
140 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
141 "[Swap]\n", f);
142
143 r = write_what(f, what);
144 if (r < 0)
145 return r;
146
147 r = write_options(f, me->mnt_opts);
148 if (r < 0)
149 return r;
150
151 r = fflush_and_check(f);
152 if (r < 0)
153 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
154
155 /* use what as where, to have a nicer error message */
156 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
157 if (r < 0)
158 return r;
159
160 if (flags & MAKEFS) {
161 r = generator_hook_up_mkswap(arg_dest, what);
162 if (r < 0)
163 return r;
164 }
165
166 if (flags & GROWFS)
167 /* TODO: swap devices must be wiped and recreated */
168 log_warning("%s: growing swap devices is currently unsupported.", what);
169
170 if (!(flags & NOAUTO)) {
171 r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET,
172 (flags & NOFAIL) ? "wants" : "requires", name);
173 if (r < 0)
174 return r;
175 }
176
177 return 0;
178 }
179
180 static bool mount_is_network(struct mntent *me) {
181 assert(me);
182
183 return fstab_test_option(me->mnt_opts, "_netdev\0") ||
184 fstype_is_network(me->mnt_type);
185 }
186
187 static bool mount_in_initrd(struct mntent *me) {
188 assert(me);
189
190 return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
191 streq(me->mnt_dir, "/usr");
192 }
193
194 static int write_timeout(FILE *f, const char *where, const char *opts,
195 const char *filter, const char *variable) {
196 _cleanup_free_ char *timeout = NULL;
197 char timespan[FORMAT_TIMESPAN_MAX];
198 usec_t u;
199 int r;
200
201 r = fstab_filter_options(opts, filter, NULL, &timeout, NULL);
202 if (r < 0)
203 return log_warning_errno(r, "Failed to parse options: %m");
204 if (r == 0)
205 return 0;
206
207 r = parse_sec_fix_0(timeout, &u);
208 if (r < 0) {
209 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
210 return 0;
211 }
212
213 fprintf(f, "%s=%s\n", variable, format_timespan(timespan, sizeof(timespan), u, 0));
214
215 return 0;
216 }
217
218 static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
219 return write_timeout(f, where, opts,
220 "x-systemd.idle-timeout\0", "TimeoutIdleSec");
221 }
222
223 static int write_mount_timeout(FILE *f, const char *where, const char *opts) {
224 return write_timeout(f, where, opts,
225 "x-systemd.mount-timeout\0", "TimeoutSec");
226 }
227
228 static int write_dependency(FILE *f, const char *opts,
229 const char *filter, const char *format) {
230 _cleanup_strv_free_ char **names = NULL, **units = NULL;
231 _cleanup_free_ char *res = NULL;
232 char **s;
233 int r;
234
235 assert(f);
236 assert(opts);
237
238 r = fstab_extract_values(opts, filter, &names);
239 if (r < 0)
240 return log_warning_errno(r, "Failed to parse options: %m");
241 if (r == 0)
242 return 0;
243
244 STRV_FOREACH(s, names) {
245 char *x;
246
247 r = unit_name_mangle_with_suffix(*s, UNIT_NAME_NOGLOB, ".mount", &x);
248 if (r < 0)
249 return log_error_errno(r, "Failed to generate unit name: %m");
250 r = strv_consume(&units, x);
251 if (r < 0)
252 return log_oom();
253 }
254
255 if (units) {
256 res = strv_join(units, " ");
257 if (!res)
258 return log_oom();
259 #pragma GCC diagnostic push
260 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
261 fprintf(f, format, res);
262 #pragma GCC diagnostic pop
263 }
264
265 return 0;
266 }
267
268 static int write_after(FILE *f, const char *opts) {
269 return write_dependency(f, opts, "x-systemd.after", "After=%1$s\n");
270 }
271
272 static int write_requires_after(FILE *f, const char *opts) {
273 return write_dependency(f, opts,
274 "x-systemd.requires", "After=%1$s\nRequires=%1$s\n");
275 }
276
277 static int write_before(FILE *f, const char *opts) {
278 return write_dependency(f, opts,
279 "x-systemd.before", "Before=%1$s\n");
280 }
281
282 static int write_requires_mounts_for(FILE *f, const char *opts) {
283 _cleanup_strv_free_ char **paths = NULL, **paths_escaped = NULL;
284 _cleanup_free_ char *res = NULL;
285 int r;
286
287 assert(f);
288 assert(opts);
289
290 r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
291 if (r < 0)
292 return log_warning_errno(r, "Failed to parse options: %m");
293 if (r == 0)
294 return 0;
295
296 r = specifier_escape_strv(paths, &paths_escaped);
297 if (r < 0)
298 return log_error_errno(r, "Failed to escape paths: %m");
299
300 res = strv_join(paths_escaped, " ");
301 if (!res)
302 return log_oom();
303
304 fprintf(f, "RequiresMountsFor=%s\n", res);
305
306 return 0;
307 }
308
309 static int add_mount(
310 const char *dest,
311 const char *what,
312 const char *where,
313 const char *original_where,
314 const char *fstype,
315 const char *opts,
316 int passno,
317 MountpointFlags flags,
318 const char *post,
319 const char *source) {
320
321 _cleanup_free_ char
322 *name = NULL,
323 *automount_name = NULL, *automount_unit = NULL,
324 *filtered = NULL,
325 *where_escaped = NULL;
326 const char *unit;
327 _cleanup_fclose_ FILE *f = NULL;
328 int r;
329
330 assert(what);
331 assert(where);
332 assert(opts);
333 assert(post);
334 assert(source);
335
336 if (streq_ptr(fstype, "autofs"))
337 return 0;
338
339 if (!is_path(where)) {
340 log_warning("Mount point %s is not a valid path, ignoring.", where);
341 return 0;
342 }
343
344 if (mount_point_is_api(where) ||
345 mount_point_ignore(where))
346 return 0;
347
348 if (path_equal(where, "/")) {
349 if (flags & NOAUTO)
350 log_warning("Ignoring \"noauto\" for root device");
351 if (flags & NOFAIL)
352 log_warning("Ignoring \"nofail\" for root device");
353 if (flags & AUTOMOUNT)
354 log_warning("Ignoring automount option for root device");
355
356 SET_FLAG(flags, NOAUTO | NOFAIL | AUTOMOUNT, false);
357 }
358
359 r = unit_name_from_path(where, ".mount", &name);
360 if (r < 0)
361 return log_error_errno(r, "Failed to generate unit name: %m");
362
363 unit = strjoina(dest, "/", name);
364
365 f = fopen(unit, "wxe");
366 if (!f)
367 return log_error_errno(errno,
368 errno == EEXIST ?
369 "Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?" :
370 "Failed to create unit file %s: %m",
371 unit);
372
373 fprintf(f,
374 "# Automatically generated by systemd-fstab-generator\n\n"
375 "[Unit]\n"
376 "SourcePath=%s\n"
377 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
378 source);
379
380 if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !(flags & AUTOMOUNT) &&
381 fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
382 /* The default retry timeout that mount.nfs uses for 'bg' mounts
383 * is 10000 minutes, where as it uses 2 minutes for 'fg' mounts.
384 * As we are making 'bg' mounts look like an 'fg' mount to
385 * mount.nfs (so systemd can manage the job-control aspects of 'bg'),
386 * we need to explicitly preserve that default, and also ensure
387 * the systemd mount-timeout doesn't interfere.
388 * By placing these options first, they can be over-ridden by
389 * settings in /etc/fstab. */
390 opts = strjoina("x-systemd.mount-timeout=infinity,retry=10000,", opts, ",fg");
391 SET_FLAG(flags, NOFAIL, true);
392 }
393
394 if (!(flags & NOFAIL) && !(flags & AUTOMOUNT))
395 fprintf(f, "Before=%s\n", post);
396
397 if (!(flags & AUTOMOUNT) && opts) {
398 r = write_after(f, opts);
399 if (r < 0)
400 return r;
401 r = write_requires_after(f, opts);
402 if (r < 0)
403 return r;
404 r = write_before(f, opts);
405 if (r < 0)
406 return r;
407 r = write_requires_mounts_for(f, opts);
408 if (r < 0)
409 return r;
410 }
411
412 if (passno != 0) {
413 r = generator_write_fsck_deps(f, dest, what, where, fstype);
414 if (r < 0)
415 return r;
416 }
417
418 fprintf(f, "\n[Mount]\n");
419 if (original_where)
420 fprintf(f, "# Canonicalized from %s\n", original_where);
421
422 where_escaped = specifier_escape(where);
423 if (!where_escaped)
424 return log_oom();
425 fprintf(f, "Where=%s\n", where_escaped);
426
427 r = write_what(f, what);
428 if (r < 0)
429 return r;
430
431 if (!isempty(fstype) && !streq(fstype, "auto")) {
432 _cleanup_free_ char *t;
433
434 t = specifier_escape(fstype);
435 if (!t)
436 return -ENOMEM;
437
438 fprintf(f, "Type=%s\n", t);
439 }
440
441 r = generator_write_timeouts(dest, what, where, opts, &filtered);
442 if (r < 0)
443 return r;
444
445 r = generator_write_device_deps(dest, what, where, opts);
446 if (r < 0)
447 return r;
448
449 r = write_mount_timeout(f, where, opts);
450 if (r < 0)
451 return r;
452
453 r = write_options(f, filtered);
454 if (r < 0)
455 return r;
456
457 r = fflush_and_check(f);
458 if (r < 0)
459 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
460
461 if (flags & MAKEFS) {
462 r = generator_hook_up_mkfs(dest, what, where, fstype);
463 if (r < 0)
464 return r;
465 }
466
467 if (flags & GROWFS) {
468 r = generator_hook_up_growfs(dest, where, post);
469 if (r < 0)
470 return r;
471 }
472
473 if (!(flags & NOAUTO) && !(flags & AUTOMOUNT)) {
474 r = generator_add_symlink(dest, post,
475 (flags & NOFAIL) ? "wants" : "requires", name);
476 if (r < 0)
477 return r;
478 }
479
480 if (flags & AUTOMOUNT) {
481 r = unit_name_from_path(where, ".automount", &automount_name);
482 if (r < 0)
483 return log_error_errno(r, "Failed to generate unit name: %m");
484
485 automount_unit = strjoin(dest, "/", automount_name);
486 if (!automount_unit)
487 return log_oom();
488
489 fclose(f);
490 f = fopen(automount_unit, "wxe");
491 if (!f)
492 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
493
494 fprintf(f,
495 "# Automatically generated by systemd-fstab-generator\n\n"
496 "[Unit]\n"
497 "SourcePath=%s\n"
498 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
499 source);
500
501 fprintf(f, "Before=%s\n", post);
502
503 if (opts) {
504 r = write_after(f, opts);
505 if (r < 0)
506 return r;
507 r = write_requires_after(f, opts);
508 if (r < 0)
509 return r;
510 r = write_before(f, opts);
511 if (r < 0)
512 return r;
513 r = write_requires_mounts_for(f, opts);
514 if (r < 0)
515 return r;
516 }
517
518 fprintf(f,
519 "\n"
520 "[Automount]\n"
521 "Where=%s\n",
522 where_escaped);
523
524 r = write_idle_timeout(f, where, opts);
525 if (r < 0)
526 return r;
527
528 r = fflush_and_check(f);
529 if (r < 0)
530 return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit);
531
532 r = generator_add_symlink(dest, post,
533 (flags & NOFAIL) ? "wants" : "requires", automount_name);
534 if (r < 0)
535 return r;
536 }
537
538 return 0;
539 }
540
541 static int parse_fstab(bool initrd) {
542 _cleanup_endmntent_ FILE *f = NULL;
543 const char *fstab_path;
544 struct mntent *me;
545 int r = 0;
546
547 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
548 f = setmntent(fstab_path, "re");
549 if (!f) {
550 if (errno == ENOENT)
551 return 0;
552
553 return log_error_errno(errno, "Failed to open %s: %m", fstab_path);
554 }
555
556 while ((me = getmntent(f))) {
557 _cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
558 bool makefs, growfs, noauto, nofail;
559 int k;
560
561 if (initrd && !mount_in_initrd(me))
562 continue;
563
564 what = fstab_node_to_udev_node(me->mnt_fsname);
565 if (!what)
566 return log_oom();
567
568 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
569 log_info("Running in a container, ignoring fstab device entry for %s.", what);
570 continue;
571 }
572
573 where = strdup(me->mnt_dir);
574 if (!where)
575 return log_oom();
576
577 if (is_path(where)) {
578 path_kill_slashes(where);
579 /* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
580 * mount units, but causes problems since it historically worked to have symlinks in e.g.
581 * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
582 * where a symlink refers to another mount target; this works assuming the sub-mountpoint
583 * target is the final directory.
584 */
585 r = chase_symlinks(where, initrd ? "/sysroot" : NULL,
586 CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
587 &canonical_where);
588 if (r < 0)
589 /* In this case for now we continue on as if it wasn't a symlink */
590 log_warning_errno(r, "Failed to read symlink target for %s: %m", where);
591 else {
592 if (streq(canonical_where, where))
593 canonical_where = mfree(canonical_where);
594 else
595 log_debug("Canonicalized what=%s where=%s to %s",
596 what, where, canonical_where);
597 }
598 }
599
600 makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
601 growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
602 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
603 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
604 log_debug("Found entry what=%s where=%s type=%s makefs=%s nofail=%s noauto=%s",
605 what, where, me->mnt_type,
606 yes_no(makefs),
607 yes_no(noauto), yes_no(nofail));
608
609 if (streq(me->mnt_type, "swap"))
610 k = add_swap(what, me,
611 makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL);
612 else {
613 bool automount;
614 const char *post;
615
616 automount = fstab_test_option(me->mnt_opts,
617 "comment=systemd.automount\0"
618 "x-systemd.automount\0");
619 if (initrd)
620 post = SPECIAL_INITRD_FS_TARGET;
621 else if (mount_is_network(me))
622 post = SPECIAL_REMOTE_FS_TARGET;
623 else
624 post = SPECIAL_LOCAL_FS_TARGET;
625
626 k = add_mount(arg_dest,
627 what,
628 canonical_where ?: where,
629 canonical_where ? where: NULL,
630 me->mnt_type,
631 me->mnt_opts,
632 me->mnt_passno,
633 makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT,
634 post,
635 fstab_path);
636 }
637
638 if (r >= 0 && k < 0)
639 r = k;
640 }
641
642 return r;
643 }
644
645 static int add_sysroot_mount(void) {
646 _cleanup_free_ char *what = NULL;
647 const char *opts;
648 int r;
649
650 if (isempty(arg_root_what)) {
651 log_debug("Could not find a root= entry on the kernel command line.");
652 return 0;
653 }
654
655 if (streq(arg_root_what, "gpt-auto")) {
656 /* This is handled by the gpt-auto generator */
657 log_debug("Skipping root directory handling, as gpt-auto was requested.");
658 return 0;
659 }
660
661 if (path_equal(arg_root_what, "/dev/nfs")) {
662 /* This is handled by the kernel or the initrd */
663 log_debug("Skipping root directory handling, as /dev/nfs was requested.");
664 return 0;
665 }
666
667 what = fstab_node_to_udev_node(arg_root_what);
668 if (!what)
669 return log_oom();
670
671 if (!arg_root_options)
672 opts = arg_root_rw > 0 ? "rw" : "ro";
673 else if (arg_root_rw >= 0 ||
674 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
675 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
676 else
677 opts = arg_root_options;
678
679 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
680
681 if (is_device_path(what)) {
682 r = generator_write_initrd_root_device_deps(arg_dest, what);
683 if (r < 0)
684 return r;
685 }
686
687 return add_mount(arg_dest,
688 what,
689 "/sysroot",
690 NULL,
691 arg_root_fstype,
692 opts,
693 is_device_path(what) ? 1 : 0, /* passno */
694 0, /* makefs off, growfs off, noauto off, nofail off, automount off */
695 SPECIAL_INITRD_ROOT_FS_TARGET,
696 "/proc/cmdline");
697 }
698
699 static int add_sysroot_usr_mount(void) {
700 _cleanup_free_ char *what = NULL;
701 const char *opts;
702
703 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
704 return 0;
705
706 if (arg_root_what && !arg_usr_what) {
707 /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
708 arg_usr_what = strdup(arg_root_what);
709 if (!arg_usr_what)
710 return log_oom();
711 }
712
713 if (arg_root_fstype && !arg_usr_fstype) {
714 arg_usr_fstype = strdup(arg_root_fstype);
715 if (!arg_usr_fstype)
716 return log_oom();
717 }
718
719 if (arg_root_options && !arg_usr_options) {
720 arg_usr_options = strdup(arg_root_options);
721 if (!arg_usr_options)
722 return log_oom();
723 }
724
725 if (!arg_usr_what)
726 return 0;
727
728 what = fstab_node_to_udev_node(arg_usr_what);
729 if (!what)
730 return log_oom();
731
732 if (!arg_usr_options)
733 opts = arg_root_rw > 0 ? "rw" : "ro";
734 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
735 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
736 else
737 opts = arg_usr_options;
738
739 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
740 return add_mount(arg_dest,
741 what,
742 "/sysroot/usr",
743 NULL,
744 arg_usr_fstype,
745 opts,
746 is_device_path(what) ? 1 : 0, /* passno */
747 0,
748 SPECIAL_INITRD_FS_TARGET,
749 "/proc/cmdline");
750 }
751
752 static int add_volatile_root(void) {
753 const char *from, *to;
754
755 if (arg_volatile_mode != VOLATILE_YES)
756 return 0;
757
758 /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
759 * requested, leaving only /usr from the root mount inside. */
760
761 from = strjoina(SYSTEM_DATA_UNIT_PATH "/systemd-volatile-root.service");
762 to = strjoina(arg_dest, "/" SPECIAL_INITRD_ROOT_FS_TARGET, ".requires/systemd-volatile-root.service");
763
764 (void) mkdir_parents(to, 0755);
765
766 if (symlink(from, to) < 0)
767 return log_error_errno(errno, "Failed to hook in volatile remount service: %m");
768
769 return 0;
770 }
771
772 static int add_volatile_var(void) {
773
774 if (arg_volatile_mode != VOLATILE_STATE)
775 return 0;
776
777 /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
778
779 return add_mount(arg_dest_late,
780 "tmpfs",
781 "/var",
782 NULL,
783 "tmpfs",
784 "mode=0755",
785 0,
786 0,
787 SPECIAL_LOCAL_FS_TARGET,
788 "/proc/cmdline");
789 }
790
791 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
792 int r;
793
794 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
795 * instance should take precedence. In the case of multiple rootflags=
796 * or usrflags= the arguments should be concatenated */
797
798 if (STR_IN_SET(key, "fstab", "rd.fstab")) {
799
800 r = value ? parse_boolean(value) : 1;
801 if (r < 0)
802 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
803 else
804 arg_fstab_enabled = r;
805
806 } else if (streq(key, "root")) {
807
808 if (proc_cmdline_value_missing(key, value))
809 return 0;
810
811 if (free_and_strdup(&arg_root_what, value) < 0)
812 return log_oom();
813
814 } else if (streq(key, "rootfstype")) {
815
816 if (proc_cmdline_value_missing(key, value))
817 return 0;
818
819 if (free_and_strdup(&arg_root_fstype, value) < 0)
820 return log_oom();
821
822 } else if (streq(key, "rootflags")) {
823
824 if (proc_cmdline_value_missing(key, value))
825 return 0;
826
827 if (!strextend_with_separator(&arg_root_options, ",", value, NULL))
828 return log_oom();
829
830 } else if (streq(key, "roothash")) {
831
832 if (proc_cmdline_value_missing(key, value))
833 return 0;
834
835 if (free_and_strdup(&arg_root_hash, value) < 0)
836 return log_oom();
837
838 } else if (streq(key, "mount.usr")) {
839
840 if (proc_cmdline_value_missing(key, value))
841 return 0;
842
843 if (free_and_strdup(&arg_usr_what, value) < 0)
844 return log_oom();
845
846 } else if (streq(key, "mount.usrfstype")) {
847
848 if (proc_cmdline_value_missing(key, value))
849 return 0;
850
851 if (free_and_strdup(&arg_usr_fstype, value) < 0)
852 return log_oom();
853
854 } else if (streq(key, "mount.usrflags")) {
855
856 if (proc_cmdline_value_missing(key, value))
857 return 0;
858
859 if (!strextend_with_separator(&arg_usr_options, ",", value, NULL))
860 return log_oom();
861
862 } else if (streq(key, "rw") && !value)
863 arg_root_rw = true;
864 else if (streq(key, "ro") && !value)
865 arg_root_rw = false;
866 else if (streq(key, "systemd.volatile")) {
867 VolatileMode m;
868
869 if (value) {
870 m = volatile_mode_from_string(value);
871 if (m < 0)
872 log_warning("Failed to parse systemd.volatile= argument: %s", value);
873 else
874 arg_volatile_mode = m;
875 } else
876 arg_volatile_mode = VOLATILE_YES;
877 }
878
879 return 0;
880 }
881
882 static int determine_root(void) {
883 /* If we have a root hash but no root device then Verity is used, and we use the "root" DM device as root. */
884
885 if (arg_root_what)
886 return 0;
887
888 if (!arg_root_hash)
889 return 0;
890
891 arg_root_what = strdup("/dev/mapper/root");
892 if (!arg_root_what)
893 return log_oom();
894
895 log_info("Using verity root device %s.", arg_root_what);
896
897 return 1;
898 }
899
900 int main(int argc, char *argv[]) {
901 int r = 0;
902
903 if (argc > 1 && argc != 4) {
904 log_error("This program takes three or no arguments.");
905 return EXIT_FAILURE;
906 }
907
908 if (argc > 1)
909 arg_dest = argv[1];
910 if (argc > 3)
911 arg_dest_late = argv[3];
912
913 log_set_target(LOG_TARGET_SAFE);
914 log_parse_environment();
915 log_open();
916
917 umask(0022);
918
919 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
920 if (r < 0)
921 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
922
923 (void) determine_root();
924
925 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
926 if (in_initrd()) {
927 int k;
928
929 r = add_sysroot_mount();
930
931 k = add_sysroot_usr_mount();
932 if (k < 0)
933 r = k;
934
935 k = add_volatile_root();
936 if (k < 0)
937 r = k;
938 } else
939 r = add_volatile_var();
940
941 /* Honour /etc/fstab only when that's enabled */
942 if (arg_fstab_enabled) {
943 int k;
944
945 log_debug("Parsing /etc/fstab");
946
947 /* Parse the local /etc/fstab, possibly from the initrd */
948 k = parse_fstab(false);
949 if (k < 0)
950 r = k;
951
952 /* If running in the initrd also parse the /etc/fstab from the host */
953 if (in_initrd()) {
954 log_debug("Parsing /sysroot/etc/fstab");
955
956 k = parse_fstab(true);
957 if (k < 0)
958 r = k;
959 }
960 }
961
962 free(arg_root_what);
963 free(arg_root_fstype);
964 free(arg_root_options);
965 free(arg_root_hash);
966
967 free(arg_usr_what);
968 free(arg_usr_fstype);
969 free(arg_usr_options);
970
971 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
972 }