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