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