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