]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/fstab-generator/fstab-generator.c
Merge pull request #8149 from poettering/fake-root-cgroup
[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
561 /* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
562 * mount units, but causes problems since it historically worked to have symlinks in e.g.
563 * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
564 * where a symlink refers to another mount target; this works assuming the sub-mountpoint
565 * target is the final directory. */
566 r = chase_symlinks(where, initrd ? "/sysroot" : NULL,
567 CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
568 &canonical_where);
569 if (r < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
570 log_debug_errno(r, "Failed to read symlink target for %s, ignoring: %m", where);
571 else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
572 canonical_where = mfree(canonical_where);
573 else
574 log_debug("Canonicalized what=%s where=%s to %s", what, where, canonical_where);
575 }
576
577 makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
578 growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
579 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
580 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
581
582 log_debug("Found entry what=%s where=%s type=%s makefs=%s nofail=%s noauto=%s",
583 what, where, me->mnt_type,
584 yes_no(makefs),
585 yes_no(noauto), yes_no(nofail));
586
587 if (streq(me->mnt_type, "swap"))
588 k = add_swap(what, me,
589 makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL);
590 else {
591 bool automount;
592 const char *post;
593
594 automount = fstab_test_option(me->mnt_opts,
595 "comment=systemd.automount\0"
596 "x-systemd.automount\0");
597 if (initrd)
598 post = SPECIAL_INITRD_FS_TARGET;
599 else if (mount_is_network(me))
600 post = SPECIAL_REMOTE_FS_TARGET;
601 else
602 post = SPECIAL_LOCAL_FS_TARGET;
603
604 k = add_mount(arg_dest,
605 what,
606 canonical_where ?: where,
607 canonical_where ? where: NULL,
608 me->mnt_type,
609 me->mnt_opts,
610 me->mnt_passno,
611 makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT,
612 post,
613 fstab_path);
614 }
615
616 if (r >= 0 && k < 0)
617 r = k;
618 }
619
620 return r;
621 }
622
623 static int add_sysroot_mount(void) {
624 _cleanup_free_ char *what = NULL;
625 const char *opts;
626 int r;
627
628 if (isempty(arg_root_what)) {
629 log_debug("Could not find a root= entry on the kernel command line.");
630 return 0;
631 }
632
633 if (streq(arg_root_what, "gpt-auto")) {
634 /* This is handled by the gpt-auto generator */
635 log_debug("Skipping root directory handling, as gpt-auto was requested.");
636 return 0;
637 }
638
639 if (path_equal(arg_root_what, "/dev/nfs")) {
640 /* This is handled by the kernel or the initrd */
641 log_debug("Skipping root directory handling, as /dev/nfs was requested.");
642 return 0;
643 }
644
645 what = fstab_node_to_udev_node(arg_root_what);
646 if (!what)
647 return log_oom();
648
649 if (!arg_root_options)
650 opts = arg_root_rw > 0 ? "rw" : "ro";
651 else if (arg_root_rw >= 0 ||
652 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
653 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
654 else
655 opts = arg_root_options;
656
657 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
658
659 if (is_device_path(what)) {
660 r = generator_write_initrd_root_device_deps(arg_dest, what);
661 if (r < 0)
662 return r;
663 }
664
665 return add_mount(arg_dest,
666 what,
667 "/sysroot",
668 NULL,
669 arg_root_fstype,
670 opts,
671 is_device_path(what) ? 1 : 0, /* passno */
672 0, /* makefs off, growfs off, noauto off, nofail off, automount off */
673 SPECIAL_INITRD_ROOT_FS_TARGET,
674 "/proc/cmdline");
675 }
676
677 static int add_sysroot_usr_mount(void) {
678 _cleanup_free_ char *what = NULL;
679 const char *opts;
680
681 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
682 return 0;
683
684 if (arg_root_what && !arg_usr_what) {
685 /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
686 arg_usr_what = strdup(arg_root_what);
687 if (!arg_usr_what)
688 return log_oom();
689 }
690
691 if (arg_root_fstype && !arg_usr_fstype) {
692 arg_usr_fstype = strdup(arg_root_fstype);
693 if (!arg_usr_fstype)
694 return log_oom();
695 }
696
697 if (arg_root_options && !arg_usr_options) {
698 arg_usr_options = strdup(arg_root_options);
699 if (!arg_usr_options)
700 return log_oom();
701 }
702
703 if (!arg_usr_what)
704 return 0;
705
706 what = fstab_node_to_udev_node(arg_usr_what);
707 if (!what)
708 return log_oom();
709
710 if (!arg_usr_options)
711 opts = arg_root_rw > 0 ? "rw" : "ro";
712 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
713 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
714 else
715 opts = arg_usr_options;
716
717 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
718 return add_mount(arg_dest,
719 what,
720 "/sysroot/usr",
721 NULL,
722 arg_usr_fstype,
723 opts,
724 is_device_path(what) ? 1 : 0, /* passno */
725 0,
726 SPECIAL_INITRD_FS_TARGET,
727 "/proc/cmdline");
728 }
729
730 static int add_volatile_root(void) {
731 const char *from, *to;
732
733 if (arg_volatile_mode != VOLATILE_YES)
734 return 0;
735
736 /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
737 * requested, leaving only /usr from the root mount inside. */
738
739 from = strjoina(SYSTEM_DATA_UNIT_PATH "/systemd-volatile-root.service");
740 to = strjoina(arg_dest, "/" SPECIAL_INITRD_ROOT_FS_TARGET, ".requires/systemd-volatile-root.service");
741
742 (void) mkdir_parents(to, 0755);
743
744 if (symlink(from, to) < 0)
745 return log_error_errno(errno, "Failed to hook in volatile remount service: %m");
746
747 return 0;
748 }
749
750 static int add_volatile_var(void) {
751
752 if (arg_volatile_mode != VOLATILE_STATE)
753 return 0;
754
755 /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
756
757 return add_mount(arg_dest_late,
758 "tmpfs",
759 "/var",
760 NULL,
761 "tmpfs",
762 "mode=0755",
763 0,
764 0,
765 SPECIAL_LOCAL_FS_TARGET,
766 "/proc/cmdline");
767 }
768
769 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
770 int r;
771
772 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
773 * instance should take precedence. In the case of multiple rootflags=
774 * or usrflags= the arguments should be concatenated */
775
776 if (STR_IN_SET(key, "fstab", "rd.fstab")) {
777
778 r = value ? parse_boolean(value) : 1;
779 if (r < 0)
780 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
781 else
782 arg_fstab_enabled = r;
783
784 } else if (streq(key, "root")) {
785
786 if (proc_cmdline_value_missing(key, value))
787 return 0;
788
789 if (free_and_strdup(&arg_root_what, value) < 0)
790 return log_oom();
791
792 } else if (streq(key, "rootfstype")) {
793
794 if (proc_cmdline_value_missing(key, value))
795 return 0;
796
797 if (free_and_strdup(&arg_root_fstype, value) < 0)
798 return log_oom();
799
800 } else if (streq(key, "rootflags")) {
801
802 if (proc_cmdline_value_missing(key, value))
803 return 0;
804
805 if (!strextend_with_separator(&arg_root_options, ",", value, NULL))
806 return log_oom();
807
808 } else if (streq(key, "roothash")) {
809
810 if (proc_cmdline_value_missing(key, value))
811 return 0;
812
813 if (free_and_strdup(&arg_root_hash, value) < 0)
814 return log_oom();
815
816 } else if (streq(key, "mount.usr")) {
817
818 if (proc_cmdline_value_missing(key, value))
819 return 0;
820
821 if (free_and_strdup(&arg_usr_what, value) < 0)
822 return log_oom();
823
824 } else if (streq(key, "mount.usrfstype")) {
825
826 if (proc_cmdline_value_missing(key, value))
827 return 0;
828
829 if (free_and_strdup(&arg_usr_fstype, value) < 0)
830 return log_oom();
831
832 } else if (streq(key, "mount.usrflags")) {
833
834 if (proc_cmdline_value_missing(key, value))
835 return 0;
836
837 if (!strextend_with_separator(&arg_usr_options, ",", value, NULL))
838 return log_oom();
839
840 } else if (streq(key, "rw") && !value)
841 arg_root_rw = true;
842 else if (streq(key, "ro") && !value)
843 arg_root_rw = false;
844 else if (streq(key, "systemd.volatile")) {
845 VolatileMode m;
846
847 if (value) {
848 m = volatile_mode_from_string(value);
849 if (m < 0)
850 log_warning("Failed to parse systemd.volatile= argument: %s", value);
851 else
852 arg_volatile_mode = m;
853 } else
854 arg_volatile_mode = VOLATILE_YES;
855 }
856
857 return 0;
858 }
859
860 static int determine_root(void) {
861 /* If we have a root hash but no root device then Verity is used, and we use the "root" DM device as root. */
862
863 if (arg_root_what)
864 return 0;
865
866 if (!arg_root_hash)
867 return 0;
868
869 arg_root_what = strdup("/dev/mapper/root");
870 if (!arg_root_what)
871 return log_oom();
872
873 log_info("Using verity root device %s.", arg_root_what);
874
875 return 1;
876 }
877
878 int main(int argc, char *argv[]) {
879 int r = 0;
880
881 if (argc > 1 && argc != 4) {
882 log_error("This program takes three or no arguments.");
883 return EXIT_FAILURE;
884 }
885
886 if (argc > 1)
887 arg_dest = argv[1];
888 if (argc > 3)
889 arg_dest_late = argv[3];
890
891 log_set_prohibit_ipc(true);
892 log_set_target(LOG_TARGET_AUTO);
893 log_parse_environment();
894 log_open();
895
896 umask(0022);
897
898 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
899 if (r < 0)
900 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
901
902 (void) determine_root();
903
904 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
905 if (in_initrd()) {
906 int k;
907
908 r = add_sysroot_mount();
909
910 k = add_sysroot_usr_mount();
911 if (k < 0)
912 r = k;
913
914 k = add_volatile_root();
915 if (k < 0)
916 r = k;
917 } else
918 r = add_volatile_var();
919
920 /* Honour /etc/fstab only when that's enabled */
921 if (arg_fstab_enabled) {
922 int k;
923
924 log_debug("Parsing /etc/fstab");
925
926 /* Parse the local /etc/fstab, possibly from the initrd */
927 k = parse_fstab(false);
928 if (k < 0)
929 r = k;
930
931 /* If running in the initrd also parse the /etc/fstab from the host */
932 if (in_initrd()) {
933 log_debug("Parsing /sysroot/etc/fstab");
934
935 k = parse_fstab(true);
936 if (k < 0)
937 r = k;
938 }
939 }
940
941 free(arg_root_what);
942 free(arg_root_fstype);
943 free(arg_root_options);
944 free(arg_root_hash);
945
946 free(arg_usr_what);
947 free(arg_usr_fstype);
948 free(arg_usr_options);
949
950 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
951 }