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"
46 static const char *arg_dest
= "/tmp";
47 static bool arg_fstab_enabled
= true;
48 static char *arg_root_what
= NULL
;
49 static char *arg_root_fstype
= NULL
;
50 static char *arg_root_options
= NULL
;
51 static int arg_root_rw
= -1;
52 static char *arg_usr_what
= NULL
;
53 static char *arg_usr_fstype
= NULL
;
54 static char *arg_usr_options
= NULL
;
62 _cleanup_free_
char *name
= NULL
, *unit
= NULL
, *lnk
= NULL
;
63 _cleanup_fclose_
FILE *f
= NULL
;
69 if (access("/proc/swaps", F_OK
) < 0) {
70 log_info("Swap not supported, ignoring fstab swap entry for %s.", what
);
74 if (detect_container() > 0) {
75 log_info("Running in a container, ignoring fstab swap entry for %s.", what
);
79 r
= unit_name_from_path(what
, ".swap", &name
);
81 return log_error_errno(r
, "Failed to generate unit name: %m");
83 unit
= strjoin(arg_dest
, "/", name
, NULL
);
87 f
= fopen(unit
, "wxe");
89 return log_error_errno(errno
,
91 "Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?" :
92 "Failed to create unit file %s: %m",
96 "# Automatically generated by systemd-fstab-generator\n\n"
98 "SourcePath=/etc/fstab\n"
99 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
104 if (!isempty(me
->mnt_opts
) && !streq(me
->mnt_opts
, "defaults"))
105 fprintf(f
, "Options=%s\n", me
->mnt_opts
);
107 r
= fflush_and_check(f
);
109 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
111 /* use what as where, to have a nicer error message */
112 r
= generator_write_timeouts(arg_dest
, what
, what
, me
->mnt_opts
, NULL
);
117 lnk
= strjoin(arg_dest
, "/" SPECIAL_SWAP_TARGET
,
118 nofail
? ".wants/" : ".requires/", name
, NULL
);
122 mkdir_parents_label(lnk
, 0755);
123 if (symlink(unit
, lnk
) < 0)
124 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
130 static bool mount_is_network(struct mntent
*me
) {
133 return fstab_test_option(me
->mnt_opts
, "_netdev\0") ||
134 fstype_is_network(me
->mnt_type
);
137 static bool mount_in_initrd(struct mntent
*me
) {
140 return fstab_test_option(me
->mnt_opts
, "x-initrd.mount\0") ||
141 streq(me
->mnt_dir
, "/usr");
144 static int write_idle_timeout(FILE *f
, const char *where
, const char *opts
) {
145 _cleanup_free_
char *timeout
= NULL
;
146 char timespan
[FORMAT_TIMESPAN_MAX
];
150 r
= fstab_filter_options(opts
, "x-systemd.idle-timeout\0", NULL
, &timeout
, NULL
);
152 return log_warning_errno(r
, "Failed to parse options: %m");
156 r
= parse_sec(timeout
, &u
);
158 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
162 fprintf(f
, "TimeoutIdleSec=%s\n", format_timespan(timespan
, sizeof(timespan
), u
, 0));
167 static int write_requires_after(FILE *f
, const char *opts
) {
168 _cleanup_strv_free_
char **names
= NULL
, **units
= NULL
;
169 _cleanup_free_
char *res
= NULL
;
176 r
= fstab_extract_values(opts
, "x-systemd.requires", &names
);
178 return log_warning_errno(r
, "Failed to parse options: %m");
182 STRV_FOREACH(s
, names
) {
185 r
= unit_name_mangle_with_suffix(*s
, UNIT_NAME_NOGLOB
, ".mount", &x
);
187 return log_error_errno(r
, "Failed to generate unit name: %m");
188 r
= strv_consume(&units
, x
);
194 res
= strv_join(units
, " ");
197 fprintf(f
, "After=%1$s\nRequires=%1$s\n", res
);
203 static int write_requires_mounts_for(FILE *f
, const char *opts
) {
204 _cleanup_strv_free_
char **paths
= NULL
;
205 _cleanup_free_
char *res
= NULL
;
211 r
= fstab_extract_values(opts
, "x-systemd.requires-mounts-for", &paths
);
213 return log_warning_errno(r
, "Failed to parse options: %m");
217 res
= strv_join(paths
, " ");
221 fprintf(f
, "RequiresMountsFor=%s\n", res
);
226 static int add_mount(
236 const char *source
) {
239 *name
= NULL
, *unit
= NULL
, *lnk
= NULL
,
240 *automount_name
= NULL
, *automount_unit
= NULL
,
242 _cleanup_fclose_
FILE *f
= NULL
;
251 if (streq_ptr(fstype
, "autofs"))
254 if (!is_path(where
)) {
255 log_warning("Mount point %s is not a valid path, ignoring.", where
);
259 if (mount_point_is_api(where
) ||
260 mount_point_ignore(where
))
263 if (path_equal(where
, "/")) {
265 log_warning("Ignoring \"noauto\" for root device");
267 log_warning("Ignoring \"nofail\" for root device");
269 log_warning("Ignoring automount option for root device");
271 noauto
= nofail
= automount
= false;
274 r
= unit_name_from_path(where
, ".mount", &name
);
276 return log_error_errno(r
, "Failed to generate unit name: %m");
278 unit
= strjoin(arg_dest
, "/", name
, NULL
);
282 f
= fopen(unit
, "wxe");
284 return log_error_errno(errno
,
286 "Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?" :
287 "Failed to create unit file %s: %m",
291 "# Automatically generated by systemd-fstab-generator\n\n"
294 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
297 if (!noauto
&& !nofail
&& !automount
)
298 fprintf(f
, "Before=%s\n", post
);
300 if (!automount
&& opts
) {
301 r
= write_requires_after(f
, opts
);
304 r
= write_requires_mounts_for(f
, opts
);
310 r
= generator_write_fsck_deps(f
, arg_dest
, what
, where
, fstype
);
323 if (!isempty(fstype
) && !streq(fstype
, "auto"))
324 fprintf(f
, "Type=%s\n", fstype
);
326 r
= generator_write_timeouts(arg_dest
, what
, where
, opts
, &filtered
);
330 if (!isempty(filtered
) && !streq(filtered
, "defaults"))
331 fprintf(f
, "Options=%s\n", filtered
);
333 r
= fflush_and_check(f
);
335 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
337 if (!noauto
&& !automount
) {
338 lnk
= strjoin(arg_dest
, "/", post
, nofail
? ".wants/" : ".requires/", name
, NULL
);
342 mkdir_parents_label(lnk
, 0755);
343 if (symlink(unit
, lnk
) < 0)
344 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
348 r
= unit_name_from_path(where
, ".automount", &automount_name
);
350 return log_error_errno(r
, "Failed to generate unit name: %m");
352 automount_unit
= strjoin(arg_dest
, "/", automount_name
, NULL
);
357 f
= fopen(automount_unit
, "wxe");
359 return log_error_errno(errno
, "Failed to create unit file %s: %m", automount_unit
);
362 "# Automatically generated by systemd-fstab-generator\n\n"
365 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
368 fprintf(f
, "Before=%s\n", post
);
371 r
= write_requires_after(f
, opts
);
374 r
= write_requires_mounts_for(f
, opts
);
385 r
= write_idle_timeout(f
, where
, opts
);
389 r
= fflush_and_check(f
);
391 return log_error_errno(r
, "Failed to write unit file %s: %m", automount_unit
);
394 lnk
= strjoin(arg_dest
, "/", post
, nofail
? ".wants/" : ".requires/", automount_name
, NULL
);
398 mkdir_parents_label(lnk
, 0755);
399 if (symlink(automount_unit
, lnk
) < 0)
400 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
406 static int parse_fstab(bool initrd
) {
407 _cleanup_endmntent_
FILE *f
= NULL
;
408 const char *fstab_path
;
412 fstab_path
= initrd
? "/sysroot/etc/fstab" : "/etc/fstab";
413 f
= setmntent(fstab_path
, "re");
418 return log_error_errno(errno
, "Failed to open %s: %m", fstab_path
);
421 while ((me
= getmntent(f
))) {
422 _cleanup_free_
char *where
= NULL
, *what
= NULL
;
426 if (initrd
&& !mount_in_initrd(me
))
429 what
= fstab_node_to_udev_node(me
->mnt_fsname
);
433 if (is_device_path(what
) && path_is_read_only_fs("sys") > 0) {
434 log_info("Running in a container, ignoring fstab device entry for %s.", what
);
438 where
= initrd
? strappend("/sysroot/", me
->mnt_dir
) : strdup(me
->mnt_dir
);
443 path_kill_slashes(where
);
445 noauto
= fstab_test_yes_no_option(me
->mnt_opts
, "noauto\0" "auto\0");
446 nofail
= fstab_test_yes_no_option(me
->mnt_opts
, "nofail\0" "fail\0");
447 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
448 what
, where
, me
->mnt_type
,
449 yes_no(noauto
), yes_no(nofail
));
451 if (streq(me
->mnt_type
, "swap"))
452 k
= add_swap(what
, me
, noauto
, nofail
);
457 automount
= fstab_test_option(me
->mnt_opts
,
458 "comment=systemd.automount\0"
459 "x-systemd.automount\0");
461 post
= SPECIAL_INITRD_FS_TARGET
;
462 else if (mount_is_network(me
))
463 post
= SPECIAL_REMOTE_FS_TARGET
;
465 post
= SPECIAL_LOCAL_FS_TARGET
;
486 static int add_sysroot_mount(void) {
487 _cleanup_free_
char *what
= NULL
;
491 if (isempty(arg_root_what
)) {
492 log_debug("Could not find a root= entry on the kernel command line.");
496 if (streq(arg_root_what
, "gpt-auto")) {
497 /* This is handled by the gpt-auto generator */
498 log_debug("Skipping root directory handling, as gpt-auto was requested.");
502 if (path_equal(arg_root_what
, "/dev/nfs")) {
503 /* This is handled by the kernel or the initrd */
504 log_debug("Skipping root directory handling, as /dev/nfs was requested.");
508 what
= fstab_node_to_udev_node(arg_root_what
);
512 if (!arg_root_options
)
513 opts
= arg_root_rw
> 0 ? "rw" : "ro";
514 else if (arg_root_rw
>= 0 ||
515 !fstab_test_option(arg_root_options
, "ro\0" "rw\0"))
516 opts
= strjoina(arg_root_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
518 opts
= arg_root_options
;
520 log_debug("Found entry what=%s where=/sysroot type=%s", what
, strna(arg_root_fstype
));
522 if (is_device_path(what
)) {
523 r
= generator_write_initrd_root_device_deps(arg_dest
, what
);
528 return add_mount(what
,
532 is_device_path(what
) ? 1 : 0, /* passno */
533 false, /* noauto off */
534 false, /* nofail off */
535 false, /* automount off */
536 SPECIAL_INITRD_ROOT_FS_TARGET
,
540 static int add_sysroot_usr_mount(void) {
541 _cleanup_free_
char *what
= NULL
;
544 if (!arg_usr_what
&& !arg_usr_fstype
&& !arg_usr_options
)
547 if (arg_root_what
&& !arg_usr_what
) {
548 /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
549 arg_usr_what
= strdup(arg_root_what
);
554 if (arg_root_fstype
&& !arg_usr_fstype
) {
555 arg_usr_fstype
= strdup(arg_root_fstype
);
560 if (arg_root_options
&& !arg_usr_options
) {
561 arg_usr_options
= strdup(arg_root_options
);
562 if (!arg_usr_options
)
569 what
= fstab_node_to_udev_node(arg_usr_what
);
573 if (!arg_usr_options
)
574 opts
= arg_root_rw
> 0 ? "rw" : "ro";
575 else if (!fstab_test_option(arg_usr_options
, "ro\0" "rw\0"))
576 opts
= strjoina(arg_usr_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
578 opts
= arg_usr_options
;
580 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what
, strna(arg_usr_fstype
));
581 return add_mount(what
,
585 is_device_path(what
) ? 1 : 0, /* passno */
586 false, /* noauto off */
587 false, /* nofail off */
588 false, /* automount off */
589 SPECIAL_INITRD_FS_TARGET
,
593 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
596 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
597 * instance should take precedence. In the case of multiple rootflags=
598 * or usrflags= the arguments should be concatenated */
600 if (STR_IN_SET(key
, "fstab", "rd.fstab") && value
) {
602 r
= parse_boolean(value
);
604 log_warning("Failed to parse fstab switch %s. Ignoring.", value
);
606 arg_fstab_enabled
= r
;
608 } else if (streq(key
, "root") && value
) {
610 if (free_and_strdup(&arg_root_what
, value
) < 0)
613 } else if (streq(key
, "rootfstype") && value
) {
615 if (free_and_strdup(&arg_root_fstype
, value
) < 0)
618 } else if (streq(key
, "rootflags") && value
) {
621 o
= arg_root_options
?
622 strjoin(arg_root_options
, ",", value
, NULL
) :
627 free(arg_root_options
);
628 arg_root_options
= o
;
630 } else if (streq(key
, "mount.usr") && value
) {
632 if (free_and_strdup(&arg_usr_what
, value
) < 0)
635 } else if (streq(key
, "mount.usrfstype") && value
) {
637 if (free_and_strdup(&arg_usr_fstype
, value
) < 0)
640 } else if (streq(key
, "mount.usrflags") && value
) {
643 o
= arg_usr_options
?
644 strjoin(arg_usr_options
, ",", value
, NULL
) :
649 free(arg_usr_options
);
652 } else if (streq(key
, "rw") && !value
)
654 else if (streq(key
, "ro") && !value
)
660 int main(int argc
, char *argv
[]) {
663 if (argc
> 1 && argc
!= 4) {
664 log_error("This program takes three or no arguments.");
671 log_set_target(LOG_TARGET_SAFE
);
672 log_parse_environment();
677 r
= parse_proc_cmdline(parse_proc_cmdline_item
, NULL
);
679 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
681 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
685 r
= add_sysroot_mount();
687 k
= add_sysroot_usr_mount();
693 /* Honour /etc/fstab only when that's enabled */
694 if (arg_fstab_enabled
) {
697 log_debug("Parsing /etc/fstab");
699 /* Parse the local /etc/fstab, possibly from the initrd */
700 k
= parse_fstab(false);
704 /* If running in the initrd also parse the /etc/fstab from the host */
706 log_debug("Parsing /sysroot/etc/fstab");
708 k
= parse_fstab(true);
715 free(arg_root_fstype
);
716 free(arg_root_options
);
719 free(arg_usr_fstype
);
720 free(arg_usr_options
);
722 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;