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