2 This file is part of systemd.
4 Copyright 2012 Lennart Poettering
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.
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.
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/>.
26 #include "alloc-util.h"
29 #include "fstab-util.h"
30 #include "generator.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"
39 #include "stat-util.h"
40 #include "string-util.h"
42 #include "unit-name.h"
45 #include "volatile-util.h"
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
;
60 static int write_options(FILE *f
, const char *options
) {
61 _cleanup_free_
char *o
= NULL
;
66 if (streq(options
, "defaults"))
69 o
= strreplace(options
, "%", "%%");
73 fprintf(f
, "Options=%s\n", o
);
77 static int write_what(FILE *f
, const char *what
) {
78 _cleanup_free_
char *w
= NULL
;
80 w
= strreplace(what
, "%", "%%");
84 fprintf(f
, "What=%s\n", w
);
94 _cleanup_free_
char *name
= NULL
, *unit
= NULL
, *lnk
= NULL
;
95 _cleanup_fclose_
FILE *f
= NULL
;
101 if (access("/proc/swaps", F_OK
) < 0) {
102 log_info("Swap not supported, ignoring fstab swap entry for %s.", what
);
106 if (detect_container() > 0) {
107 log_info("Running in a container, ignoring fstab swap entry for %s.", what
);
111 r
= unit_name_from_path(what
, ".swap", &name
);
113 return log_error_errno(r
, "Failed to generate unit name: %m");
115 unit
= strjoin(arg_dest
, "/", name
);
119 f
= fopen(unit
, "wxe");
121 return log_error_errno(errno
,
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",
127 fputs("# Automatically generated by systemd-fstab-generator\n\n"
129 "SourcePath=/etc/fstab\n"
130 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
133 r
= write_what(f
, what
);
137 r
= write_options(f
, me
->mnt_opts
);
141 r
= fflush_and_check(f
);
143 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
145 /* use what as where, to have a nicer error message */
146 r
= generator_write_timeouts(arg_dest
, what
, what
, me
->mnt_opts
, NULL
);
151 lnk
= strjoin(arg_dest
, "/" SPECIAL_SWAP_TARGET
,
152 nofail
? ".wants/" : ".requires/", name
, NULL
);
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
);
164 static bool mount_is_network(struct mntent
*me
) {
167 return fstab_test_option(me
->mnt_opts
, "_netdev\0") ||
168 fstype_is_network(me
->mnt_type
);
171 static bool mount_in_initrd(struct mntent
*me
) {
174 return fstab_test_option(me
->mnt_opts
, "x-initrd.mount\0") ||
175 streq(me
->mnt_dir
, "/usr");
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
];
185 r
= fstab_filter_options(opts
, filter
, NULL
, &timeout
, NULL
);
187 return log_warning_errno(r
, "Failed to parse options: %m");
191 r
= parse_sec_fix_0(timeout
, &u
);
193 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
197 fprintf(f
, "%s=%s\n", variable
, format_timespan(timespan
, sizeof(timespan
), u
, 0));
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");
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");
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
;
222 r
= fstab_extract_values(opts
, filter
, &names
);
224 return log_warning_errno(r
, "Failed to parse options: %m");
228 STRV_FOREACH(s
, names
) {
231 r
= unit_name_mangle_with_suffix(*s
, UNIT_NAME_NOGLOB
, ".mount", &x
);
233 return log_error_errno(r
, "Failed to generate unit name: %m");
234 r
= strv_consume(&units
, x
);
240 res
= strv_join(units
, " ");
243 #pragma GCC diagnostic push
244 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
245 fprintf(f
, format
, res
);
246 #pragma GCC diagnostic pop
252 static int write_after(FILE *f
, const char *opts
) {
253 return write_dependency(f
, opts
, "x-systemd.after", "After=%1$s\n");
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");
261 static int write_before(FILE *f
, const char *opts
) {
262 return write_dependency(f
, opts
,
263 "x-systemd.before", "Before=%1$s\n");
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
;
274 r
= fstab_extract_values(opts
, "x-systemd.requires-mounts-for", &paths
);
276 return log_warning_errno(r
, "Failed to parse options: %m");
280 res
= strv_join(paths
, " ");
284 fprintf(f
, "RequiresMountsFor=%s\n", res
);
289 static int add_mount(
300 const char *source
) {
303 *name
= NULL
, *unit
= NULL
, *lnk
= NULL
,
304 *automount_name
= NULL
, *automount_unit
= NULL
,
306 _cleanup_fclose_
FILE *f
= NULL
;
315 if (streq_ptr(fstype
, "autofs"))
318 if (!is_path(where
)) {
319 log_warning("Mount point %s is not a valid path, ignoring.", where
);
323 if (mount_point_is_api(where
) ||
324 mount_point_ignore(where
))
327 if (path_equal(where
, "/")) {
329 log_warning("Ignoring \"noauto\" for root device");
331 log_warning("Ignoring \"nofail\" for root device");
333 log_warning("Ignoring automount option for root device");
335 noauto
= nofail
= automount
= false;
338 r
= unit_name_from_path(where
, ".mount", &name
);
340 return log_error_errno(r
, "Failed to generate unit name: %m");
342 unit
= strjoin(dest
, "/", name
);
346 f
= fopen(unit
, "wxe");
348 return log_error_errno(errno
,
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",
355 "# Automatically generated by systemd-fstab-generator\n\n"
358 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
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");
375 if (!nofail
&& !automount
)
376 fprintf(f
, "Before=%s\n", post
);
378 if (!automount
&& opts
) {
379 r
= write_after(f
, opts
);
382 r
= write_requires_after(f
, opts
);
385 r
= write_before(f
, opts
);
388 r
= write_requires_mounts_for(f
, opts
);
394 r
= generator_write_fsck_deps(f
, dest
, what
, where
, fstype
);
405 r
= write_what(f
, what
);
409 if (!isempty(fstype
) && !streq(fstype
, "auto"))
410 fprintf(f
, "Type=%s\n", fstype
);
412 r
= generator_write_timeouts(dest
, what
, where
, opts
, &filtered
);
416 r
= generator_write_device_deps(dest
, what
, where
, opts
);
420 r
= write_mount_timeout(f
, where
, opts
);
424 r
= write_options(f
, filtered
);
428 r
= fflush_and_check(f
);
430 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
432 if (!noauto
&& !automount
) {
433 lnk
= strjoin(dest
, "/", post
, nofail
? ".wants/" : ".requires/", name
);
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
);
443 r
= unit_name_from_path(where
, ".automount", &automount_name
);
445 return log_error_errno(r
, "Failed to generate unit name: %m");
447 automount_unit
= strjoin(dest
, "/", automount_name
);
452 f
= fopen(automount_unit
, "wxe");
454 return log_error_errno(errno
, "Failed to create unit file %s: %m", automount_unit
);
457 "# Automatically generated by systemd-fstab-generator\n\n"
460 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
463 fprintf(f
, "Before=%s\n", post
);
466 r
= write_after(f
, opts
);
469 r
= write_requires_after(f
, opts
);
472 r
= write_before(f
, opts
);
475 r
= write_requires_mounts_for(f
, opts
);
486 r
= write_idle_timeout(f
, where
, opts
);
490 r
= fflush_and_check(f
);
492 return log_error_errno(r
, "Failed to write unit file %s: %m", automount_unit
);
495 lnk
= strjoin(dest
, "/", post
, nofail
? ".wants/" : ".requires/", automount_name
);
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
);
507 static int parse_fstab(bool initrd
) {
508 _cleanup_endmntent_
FILE *f
= NULL
;
509 const char *fstab_path
;
513 fstab_path
= initrd
? "/sysroot/etc/fstab" : "/etc/fstab";
514 f
= setmntent(fstab_path
, "re");
519 return log_error_errno(errno
, "Failed to open %s: %m", fstab_path
);
522 while ((me
= getmntent(f
))) {
523 _cleanup_free_
char *where
= NULL
, *what
= NULL
;
527 if (initrd
&& !mount_in_initrd(me
))
530 what
= fstab_node_to_udev_node(me
->mnt_fsname
);
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
);
539 where
= initrd
? strappend("/sysroot/", me
->mnt_dir
) : strdup(me
->mnt_dir
);
544 path_kill_slashes(where
);
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
));
552 if (streq(me
->mnt_type
, "swap"))
553 k
= add_swap(what
, me
, noauto
, nofail
);
558 automount
= fstab_test_option(me
->mnt_opts
,
559 "comment=systemd.automount\0"
560 "x-systemd.automount\0");
562 post
= SPECIAL_INITRD_FS_TARGET
;
563 else if (mount_is_network(me
))
564 post
= SPECIAL_REMOTE_FS_TARGET
;
566 post
= SPECIAL_LOCAL_FS_TARGET
;
568 k
= add_mount(arg_dest
,
588 static int add_sysroot_mount(void) {
589 _cleanup_free_
char *what
= NULL
;
593 if (isempty(arg_root_what
)) {
594 log_debug("Could not find a root= entry on the kernel command line.");
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.");
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.");
610 what
= fstab_node_to_udev_node(arg_root_what
);
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");
620 opts
= arg_root_options
;
622 log_debug("Found entry what=%s where=/sysroot type=%s", what
, strna(arg_root_fstype
));
624 if (is_device_path(what
)) {
625 r
= generator_write_initrd_root_device_deps(arg_dest
, what
);
630 return add_mount(arg_dest
,
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
,
643 static int add_sysroot_usr_mount(void) {
644 _cleanup_free_
char *what
= NULL
;
647 if (!arg_usr_what
&& !arg_usr_fstype
&& !arg_usr_options
)
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
);
657 if (arg_root_fstype
&& !arg_usr_fstype
) {
658 arg_usr_fstype
= strdup(arg_root_fstype
);
663 if (arg_root_options
&& !arg_usr_options
) {
664 arg_usr_options
= strdup(arg_root_options
);
665 if (!arg_usr_options
)
672 what
= fstab_node_to_udev_node(arg_usr_what
);
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");
681 opts
= arg_usr_options
;
683 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what
, strna(arg_usr_fstype
));
684 return add_mount(arg_dest
,
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
,
697 static int add_volatile_root(void) {
698 const char *from
, *to
;
700 if (arg_volatile_mode
!= VOLATILE_YES
)
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. */
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");
709 (void) mkdir_parents(to
, 0755);
711 if (symlink(from
, to
) < 0)
712 return log_error_errno(errno
, "Failed to hook in volatile remount service: %m");
717 static int add_volatile_var(void) {
719 if (arg_volatile_mode
!= VOLATILE_STATE
)
722 /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
724 return add_mount(arg_dest_late
,
733 SPECIAL_LOCAL_FS_TARGET
,
737 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
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 */
744 if (STR_IN_SET(key
, "fstab", "rd.fstab")) {
746 r
= value
? parse_boolean(value
) : 1;
748 log_warning("Failed to parse fstab switch %s. Ignoring.", value
);
750 arg_fstab_enabled
= r
;
752 } else if (streq(key
, "root")) {
754 if (proc_cmdline_value_missing(key
, value
))
757 if (free_and_strdup(&arg_root_what
, value
) < 0)
760 } else if (streq(key
, "rootfstype")) {
762 if (proc_cmdline_value_missing(key
, value
))
765 if (free_and_strdup(&arg_root_fstype
, value
) < 0)
768 } else if (streq(key
, "rootflags")) {
771 if (proc_cmdline_value_missing(key
, value
))
774 o
= arg_root_options
?
775 strjoin(arg_root_options
, ",", value
) :
780 free(arg_root_options
);
781 arg_root_options
= o
;
782 } else if (streq(key
, "roothash")) {
784 if (proc_cmdline_value_missing(key
, value
))
787 if (free_and_strdup(&arg_root_hash
, value
) < 0)
790 } else if (streq(key
, "mount.usr")) {
792 if (proc_cmdline_value_missing(key
, value
))
795 if (free_and_strdup(&arg_usr_what
, value
) < 0)
798 } else if (streq(key
, "mount.usrfstype")) {
800 if (proc_cmdline_value_missing(key
, value
))
803 if (free_and_strdup(&arg_usr_fstype
, value
) < 0)
806 } else if (streq(key
, "mount.usrflags")) {
809 if (proc_cmdline_value_missing(key
, value
))
812 o
= arg_usr_options
?
813 strjoin(arg_usr_options
, ",", value
) :
818 free(arg_usr_options
);
821 } else if (streq(key
, "rw") && !value
)
823 else if (streq(key
, "ro") && !value
)
825 else if (streq(key
, "systemd.volatile")) {
829 m
= volatile_mode_from_string(value
);
831 log_warning("Failed to parse systemd.volatile= argument: %s", value
);
833 arg_volatile_mode
= m
;
835 arg_volatile_mode
= VOLATILE_YES
;
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. */
850 arg_root_what
= strdup("/dev/mapper/root");
854 log_info("Using verity root device %s.", arg_root_what
);
859 int main(int argc
, char *argv
[]) {
862 if (argc
> 1 && argc
!= 4) {
863 log_error("This program takes three or no arguments.");
870 arg_dest_late
= argv
[3];
872 log_set_target(LOG_TARGET_SAFE
);
873 log_parse_environment();
878 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, 0);
880 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
882 (void) determine_root();
884 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
888 r
= add_sysroot_mount();
890 k
= add_sysroot_usr_mount();
894 k
= add_volatile_root();
898 r
= add_volatile_var();
900 /* Honour /etc/fstab only when that's enabled */
901 if (arg_fstab_enabled
) {
904 log_debug("Parsing /etc/fstab");
906 /* Parse the local /etc/fstab, possibly from the initrd */
907 k
= parse_fstab(false);
911 /* If running in the initrd also parse the /etc/fstab from the host */
913 log_debug("Parsing /sysroot/etc/fstab");
915 k
= parse_fstab(true);
922 free(arg_root_fstype
);
923 free(arg_root_options
);
927 free(arg_usr_fstype
);
928 free(arg_usr_options
);
930 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;