1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "unit-name.h"
31 #include "path-util.h"
32 #include "fstab-util.h"
33 #include "mount-setup.h"
36 #include "generator.h"
40 static const char *arg_dest
= "/tmp";
41 static bool arg_fstab_enabled
= true;
42 static char *arg_root_what
= NULL
;
43 static char *arg_root_fstype
= NULL
;
44 static char *arg_root_options
= NULL
;
45 static int arg_root_rw
= -1;
46 static char *arg_usr_what
= NULL
;
47 static char *arg_usr_fstype
= NULL
;
48 static char *arg_usr_options
= NULL
;
56 _cleanup_free_
char *name
= NULL
, *unit
= NULL
, *lnk
= NULL
;
57 _cleanup_fclose_
FILE *f
= NULL
;
63 if (access("/proc/swaps", F_OK
) < 0) {
64 log_info("Swap not supported, ignoring fstab swap entry for %s.", what
);
68 if (detect_container() > 0) {
69 log_info("Running in a container, ignoring fstab swap entry for %s.", what
);
73 r
= unit_name_from_path(what
, ".swap", &name
);
75 return log_error_errno(r
, "Failed to generate unit name: %m");
77 unit
= strjoin(arg_dest
, "/", name
, NULL
);
81 f
= fopen(unit
, "wxe");
84 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit
);
86 log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
91 "# Automatically generated by systemd-fstab-generator\n\n"
93 "SourcePath=/etc/fstab\n"
94 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
99 if (!isempty(me
->mnt_opts
) && !streq(me
->mnt_opts
, "defaults"))
100 fprintf(f
, "Options=%s\n", me
->mnt_opts
);
102 r
= fflush_and_check(f
);
104 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
106 /* use what as where, to have a nicer error message */
107 r
= generator_write_timeouts(arg_dest
, what
, what
, me
->mnt_opts
, NULL
);
112 lnk
= strjoin(arg_dest
, "/" SPECIAL_SWAP_TARGET
,
113 nofail
? ".wants/" : ".requires/", name
, NULL
);
117 mkdir_parents_label(lnk
, 0755);
118 if (symlink(unit
, lnk
) < 0)
119 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
125 static bool mount_is_network(struct mntent
*me
) {
128 return fstab_test_option(me
->mnt_opts
, "_netdev\0") ||
129 fstype_is_network(me
->mnt_type
);
132 static bool mount_in_initrd(struct mntent
*me
) {
135 return fstab_test_option(me
->mnt_opts
, "x-initrd.mount\0") ||
136 streq(me
->mnt_dir
, "/usr");
139 static int write_idle_timeout(FILE *f
, const char *where
, const char *opts
) {
140 _cleanup_free_
char *timeout
= NULL
;
141 char timespan
[FORMAT_TIMESPAN_MAX
];
145 r
= fstab_filter_options(opts
, "x-systemd.idle-timeout\0", NULL
, &timeout
, NULL
);
147 return log_warning_errno(r
, "Failed to parse options: %m");
151 r
= parse_sec(timeout
, &u
);
153 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
157 fprintf(f
, "TimeoutIdleSec=%s\n", format_timespan(timespan
, sizeof(timespan
), u
, 0));
162 static int write_requires_after(FILE *f
, const char *opts
) {
163 _cleanup_strv_free_
char **names
= NULL
, **units
= NULL
;
164 _cleanup_free_
char *res
= NULL
;
171 r
= fstab_extract_values(opts
, "x-systemd.requires", &names
);
173 return log_warning_errno(r
, "Failed to parse options: %m");
177 STRV_FOREACH(s
, names
) {
180 r
= unit_name_mangle_with_suffix(*s
, UNIT_NAME_NOGLOB
, ".mount", &x
);
182 return log_error_errno(r
, "Failed to generate unit name: %m");
183 r
= strv_consume(&units
, x
);
189 res
= strv_join(units
, " ");
192 fprintf(f
, "After=%1$s\nRequires=%1$s\n", res
);
198 static int write_requires_mounts_for(FILE *f
, const char *opts
) {
199 _cleanup_strv_free_
char **paths
= NULL
;
200 _cleanup_free_
char *res
= NULL
;
206 r
= fstab_extract_values(opts
, "x-systemd.requires-mounts-for", &paths
);
208 return log_warning_errno(r
, "Failed to parse options: %m");
212 res
= strv_join(paths
, " ");
216 fprintf(f
, "RequiresMountsFor=%s\n", res
);
221 static int add_mount(
231 const char *source
) {
234 *name
= NULL
, *unit
= NULL
, *lnk
= NULL
,
235 *automount_name
= NULL
, *automount_unit
= NULL
,
237 _cleanup_fclose_
FILE *f
= NULL
;
245 if (streq_ptr(fstype
, "autofs"))
248 if (!is_path(where
)) {
249 log_warning("Mount point %s is not a valid path, ignoring.", where
);
253 if (mount_point_is_api(where
) ||
254 mount_point_ignore(where
))
257 if (path_equal(where
, "/")) {
259 log_warning("Ignoring \"noauto\" for root device");
261 log_warning("Ignoring \"nofail\" for root device");
263 log_warning("Ignoring automount option for root device");
265 noauto
= nofail
= automount
= false;
268 r
= unit_name_from_path(where
, ".mount", &name
);
270 return log_error_errno(r
, "Failed to generate unit name: %m");
272 unit
= strjoin(arg_dest
, "/", name
, NULL
);
276 f
= fopen(unit
, "wxe");
279 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit
);
281 log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
286 "# Automatically generated by systemd-fstab-generator\n\n"
289 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
292 if (post
&& !noauto
&& !nofail
&& !automount
)
293 fprintf(f
, "Before=%s\n", post
);
295 if (!automount
&& opts
) {
296 r
= write_requires_after(f
, opts
);
299 r
= write_requires_mounts_for(f
, opts
);
305 r
= generator_write_fsck_deps(f
, arg_dest
, what
, where
, fstype
);
318 if (!isempty(fstype
) && !streq(fstype
, "auto"))
319 fprintf(f
, "Type=%s\n", fstype
);
321 r
= generator_write_timeouts(arg_dest
, what
, where
, opts
, &filtered
);
325 if (!isempty(filtered
) && !streq(filtered
, "defaults"))
326 fprintf(f
, "Options=%s\n", filtered
);
328 r
= fflush_and_check(f
);
330 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
332 if (!noauto
&& post
) {
333 lnk
= strjoin(arg_dest
, "/", post
, nofail
|| automount
? ".wants/" : ".requires/", name
, NULL
);
337 mkdir_parents_label(lnk
, 0755);
338 if (symlink(unit
, lnk
) < 0)
339 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
343 r
= unit_name_from_path(where
, ".automount", &automount_name
);
345 return log_error_errno(r
, "Failed to generate unit name: %m");
347 automount_unit
= strjoin(arg_dest
, "/", automount_name
, NULL
);
352 f
= fopen(automount_unit
, "wxe");
354 return log_error_errno(errno
, "Failed to create unit file %s: %m", automount_unit
);
357 "# Automatically generated by systemd-fstab-generator\n\n"
360 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
369 r
= write_requires_after(f
, opts
);
372 r
= write_requires_mounts_for(f
, opts
);
382 r
= write_idle_timeout(f
, where
, opts
);
386 r
= fflush_and_check(f
);
388 return log_error_errno(r
, "Failed to write unit file %s: %m", automount_unit
);
391 lnk
= strjoin(arg_dest
, "/", post
, nofail
? ".wants/" : ".requires/", automount_name
, NULL
);
395 mkdir_parents_label(lnk
, 0755);
396 if (symlink(automount_unit
, lnk
) < 0)
397 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
403 static int parse_fstab(bool initrd
) {
404 _cleanup_endmntent_
FILE *f
= NULL
;
405 const char *fstab_path
;
409 fstab_path
= initrd
? "/sysroot/etc/fstab" : "/etc/fstab";
410 f
= setmntent(fstab_path
, "re");
415 log_error_errno(errno
, "Failed to open %s: %m", fstab_path
);
419 while ((me
= getmntent(f
))) {
420 _cleanup_free_
char *where
= NULL
, *what
= NULL
;
424 if (initrd
&& !mount_in_initrd(me
))
427 what
= fstab_node_to_udev_node(me
->mnt_fsname
);
431 if (is_device_path(what
) && path_is_read_only_fs("sys") > 0) {
432 log_info("Running in a container, ignoring fstab device entry for %s.", what
);
436 where
= initrd
? strappend("/sysroot/", me
->mnt_dir
) : strdup(me
->mnt_dir
);
441 path_kill_slashes(where
);
443 noauto
= fstab_test_yes_no_option(me
->mnt_opts
, "noauto\0" "auto\0");
444 nofail
= fstab_test_yes_no_option(me
->mnt_opts
, "nofail\0" "fail\0");
445 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
446 what
, where
, me
->mnt_type
,
447 yes_no(noauto
), yes_no(nofail
));
449 if (streq(me
->mnt_type
, "swap"))
450 k
= add_swap(what
, me
, noauto
, nofail
);
455 automount
= fstab_test_option(me
->mnt_opts
,
456 "comment=systemd.automount\0"
457 "x-systemd.automount\0");
459 post
= SPECIAL_INITRD_FS_TARGET
;
460 else if (mount_in_initrd(me
))
461 post
= SPECIAL_INITRD_ROOT_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
;
490 if (isempty(arg_root_what
)) {
491 log_debug("Could not find a root= entry on the kernel command line.");
495 what
= fstab_node_to_udev_node(arg_root_what
);
499 if (!arg_root_options
)
500 opts
= arg_root_rw
> 0 ? "rw" : "ro";
501 else if (arg_root_rw
>= 0 ||
502 !fstab_test_option(arg_root_options
, "ro\0" "rw\0"))
503 opts
= strjoina(arg_root_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
505 opts
= arg_root_options
;
507 log_debug("Found entry what=%s where=/sysroot type=%s", what
, strna(arg_root_fstype
));
508 return add_mount(what
,
512 is_device_path(what
) ? 1 : 0,
516 SPECIAL_INITRD_ROOT_FS_TARGET
,
520 static int add_sysroot_usr_mount(void) {
521 _cleanup_free_
char *what
= NULL
;
524 if (!arg_usr_what
&& !arg_usr_fstype
&& !arg_usr_options
)
527 if (arg_root_what
&& !arg_usr_what
) {
528 arg_usr_what
= strdup(arg_root_what
);
534 if (arg_root_fstype
&& !arg_usr_fstype
) {
535 arg_usr_fstype
= strdup(arg_root_fstype
);
541 if (arg_root_options
&& !arg_usr_options
) {
542 arg_usr_options
= strdup(arg_root_options
);
544 if (!arg_usr_options
)
551 what
= fstab_node_to_udev_node(arg_usr_what
);
552 if (!path_is_absolute(what
)) {
553 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what
, strna(arg_usr_fstype
));
557 if (!arg_usr_options
)
558 opts
= arg_root_rw
> 0 ? "rw" : "ro";
559 else if (!fstab_test_option(arg_usr_options
, "ro\0" "rw\0"))
560 opts
= strjoina(arg_usr_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
562 opts
= arg_usr_options
;
564 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what
, strna(arg_usr_fstype
));
565 return add_mount(what
,
573 SPECIAL_INITRD_ROOT_FS_TARGET
,
577 static int parse_proc_cmdline_item(const char *key
, const char *value
) {
580 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
581 * instance should take precedence. In the case of multiple rootflags=
582 * or usrflags= the arguments should be concatenated */
584 if (STR_IN_SET(key
, "fstab", "rd.fstab") && value
) {
586 r
= parse_boolean(value
);
588 log_warning("Failed to parse fstab switch %s. Ignoring.", value
);
590 arg_fstab_enabled
= r
;
592 } else if (streq(key
, "root") && value
) {
594 if (free_and_strdup(&arg_root_what
, value
) < 0)
597 } else if (streq(key
, "rootfstype") && value
) {
599 if (free_and_strdup(&arg_root_fstype
, value
) < 0)
602 } else if (streq(key
, "rootflags") && value
) {
605 o
= arg_root_options
?
606 strjoin(arg_root_options
, ",", value
, NULL
) :
611 free(arg_root_options
);
612 arg_root_options
= o
;
614 } else if (streq(key
, "mount.usr") && value
) {
616 if (free_and_strdup(&arg_usr_what
, value
) < 0)
619 } else if (streq(key
, "mount.usrfstype") && value
) {
621 if (free_and_strdup(&arg_usr_fstype
, value
) < 0)
624 } else if (streq(key
, "mount.usrflags") && value
) {
627 o
= arg_usr_options
?
628 strjoin(arg_usr_options
, ",", value
, NULL
) :
633 free(arg_usr_options
);
636 } else if (streq(key
, "rw") && !value
)
638 else if (streq(key
, "ro") && !value
)
644 int main(int argc
, char *argv
[]) {
647 if (argc
> 1 && argc
!= 4) {
648 log_error("This program takes three or no arguments.");
655 log_set_target(LOG_TARGET_SAFE
);
656 log_parse_environment();
661 r
= parse_proc_cmdline(parse_proc_cmdline_item
);
663 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
665 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
667 r
= add_sysroot_mount();
669 r
= add_sysroot_usr_mount();
672 /* Honour /etc/fstab only when that's enabled */
673 if (arg_fstab_enabled
) {
676 log_debug("Parsing /etc/fstab");
678 /* Parse the local /etc/fstab, possibly from the initrd */
679 k
= parse_fstab(false);
683 /* If running in the initrd also parse the /etc/fstab from the host */
685 log_debug("Parsing /sysroot/etc/fstab");
687 k
= parse_fstab(true);
694 free(arg_root_fstype
);
695 free(arg_root_options
);
698 free(arg_usr_fstype
);
699 free(arg_usr_options
);
701 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;