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