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
, *filtered
= NULL
;
57 _cleanup_fclose_
FILE *f
= NULL
;
64 if (access("/proc/swaps", F_OK
) < 0) {
65 log_info("Swap not supported, ignoring fstab swap entry for %s.", what
);
69 if (detect_container(NULL
) > 0) {
70 log_info("Running in a container, ignoring fstab swap entry for %s.", what
);
75 r
= fstab_find_pri(opts
, &pri
);
77 log_error_errno(r
, "Failed to parse priority, ignoring: %m");
79 /* Remove invalid pri field */
80 r
= fstab_filter_options(opts
, "pri\0", NULL
, NULL
, &filtered
);
82 return log_error_errno(r
, "Failed to parse options: %m");
86 name
= unit_name_from_path(what
, ".swap");
90 unit
= strjoin(arg_dest
, "/", name
, NULL
);
94 f
= fopen(unit
, "wxe");
97 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit
);
99 log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
104 "# Automatically generated by systemd-fstab-generator\n\n"
106 "SourcePath=/etc/fstab\n"
107 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
112 /* Note that we currently pass the priority field twice, once
113 * in Priority=, and once in Options= */
115 fprintf(f
, "Priority=%i\n", pri
);
117 if (!isempty(opts
) && !streq(opts
, "defaults"))
118 fprintf(f
, "Options=%s\n", opts
);
120 r
= fflush_and_check(f
);
122 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
124 /* use what as where, to have a nicer error message */
125 r
= generator_write_timeouts(arg_dest
, what
, what
, opts
, NULL
);
130 lnk
= strjoin(arg_dest
, "/" SPECIAL_SWAP_TARGET
,
131 nofail
? ".wants/" : ".requires/", name
, NULL
);
135 mkdir_parents_label(lnk
, 0755);
136 if (symlink(unit
, lnk
) < 0)
137 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
143 static bool mount_is_network(struct mntent
*me
) {
146 return fstab_test_option(me
->mnt_opts
, "_netdev\0") ||
147 fstype_is_network(me
->mnt_type
);
150 static bool mount_in_initrd(struct mntent
*me
) {
153 return fstab_test_option(me
->mnt_opts
, "x-initrd.mount\0") ||
154 streq(me
->mnt_dir
, "/usr");
157 static int write_idle_timeout(FILE *f
, const char *where
, const char *opts
) {
158 _cleanup_free_
char *timeout
= NULL
;
159 char timespan
[FORMAT_TIMESPAN_MAX
];
163 r
= fstab_filter_options(opts
, "x-systemd.idle-timeout\0", NULL
, &timeout
, NULL
);
165 return log_warning_errno(r
, "Failed to parse options: %m");
169 r
= parse_sec(timeout
, &u
);
171 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
175 fprintf(f
, "TimeoutIdleSec=%s\n", format_timespan(timespan
, sizeof(timespan
), u
, 0));
179 static int add_mount(
189 const char *source
) {
192 *name
= NULL
, *unit
= NULL
, *lnk
= NULL
,
193 *automount_name
= NULL
, *automount_unit
= NULL
,
195 _cleanup_fclose_
FILE *f
= NULL
;
203 if (streq_ptr(fstype
, "autofs"))
206 if (!is_path(where
)) {
207 log_warning("Mount point %s is not a valid path, ignoring.", where
);
211 if (mount_point_is_api(where
) ||
212 mount_point_ignore(where
))
215 if (path_equal(where
, "/")) {
216 /* The root disk is not an option */
222 name
= unit_name_from_path(where
, ".mount");
226 unit
= strjoin(arg_dest
, "/", name
, NULL
);
230 f
= fopen(unit
, "wxe");
233 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit
);
235 log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
240 "# Automatically generated by systemd-fstab-generator\n\n"
243 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
246 if (post
&& !noauto
&& !nofail
&& !automount
)
247 fprintf(f
, "Before=%s\n", post
);
250 r
= generator_write_fsck_deps(f
, arg_dest
, what
, where
, fstype
);
263 if (!isempty(fstype
) && !streq(fstype
, "auto"))
264 fprintf(f
, "Type=%s\n", fstype
);
266 r
= generator_write_timeouts(arg_dest
, what
, where
, opts
, &filtered
);
270 if (!isempty(filtered
) && !streq(filtered
, "defaults"))
271 fprintf(f
, "Options=%s\n", filtered
);
275 return log_error_errno(errno
, "Failed to write unit file %s: %m", unit
);
277 if (!noauto
&& post
) {
278 lnk
= strjoin(arg_dest
, "/", post
, nofail
|| automount
? ".wants/" : ".requires/", name
, NULL
);
282 mkdir_parents_label(lnk
, 0755);
283 if (symlink(unit
, lnk
) < 0)
284 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
288 automount_name
= unit_name_from_path(where
, ".automount");
292 automount_unit
= strjoin(arg_dest
, "/", automount_name
, NULL
);
297 f
= fopen(automount_unit
, "wxe");
299 return log_error_errno(errno
, "Failed to create unit file %s: %m", automount_unit
);
302 "# Automatically generated by systemd-fstab-generator\n\n"
305 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
318 r
= write_idle_timeout(f
, where
, opts
);
324 return log_error_errno(errno
, "Failed to write unit file %s: %m", automount_unit
);
327 lnk
= strjoin(arg_dest
, "/", post
, nofail
? ".wants/" : ".requires/", automount_name
, NULL
);
331 mkdir_parents_label(lnk
, 0755);
332 if (symlink(automount_unit
, lnk
) < 0)
333 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
339 static int parse_fstab(bool initrd
) {
340 _cleanup_endmntent_
FILE *f
= NULL
;
341 const char *fstab_path
;
345 fstab_path
= initrd
? "/sysroot/etc/fstab" : "/etc/fstab";
346 f
= setmntent(fstab_path
, "re");
351 log_error_errno(errno
, "Failed to open %s: %m", fstab_path
);
355 while ((me
= getmntent(f
))) {
356 _cleanup_free_
char *where
= NULL
, *what
= NULL
;
360 if (initrd
&& !mount_in_initrd(me
))
363 what
= fstab_node_to_udev_node(me
->mnt_fsname
);
367 if (is_device_path(what
) && path_is_read_only_fs("sys") > 0) {
368 log_info("Running in a container, ignoring fstab device entry for %s.", what
);
372 where
= initrd
? strappend("/sysroot/", me
->mnt_dir
) : strdup(me
->mnt_dir
);
377 path_kill_slashes(where
);
379 noauto
= fstab_test_yes_no_option(me
->mnt_opts
, "noauto\0" "auto\0");
380 nofail
= fstab_test_yes_no_option(me
->mnt_opts
, "nofail\0" "fail\0");
381 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
382 what
, where
, me
->mnt_type
,
383 yes_no(noauto
), yes_no(nofail
));
385 if (streq(me
->mnt_type
, "swap"))
386 k
= add_swap(what
, me
, noauto
, nofail
);
391 automount
= fstab_test_option(me
->mnt_opts
,
392 "comment=systemd.automount\0"
393 "x-systemd.automount\0");
395 post
= SPECIAL_INITRD_FS_TARGET
;
396 else if (mount_in_initrd(me
))
397 post
= SPECIAL_INITRD_ROOT_FS_TARGET
;
398 else if (mount_is_network(me
))
399 post
= SPECIAL_REMOTE_FS_TARGET
;
401 post
= SPECIAL_LOCAL_FS_TARGET
;
422 static int add_root_mount(void) {
423 _cleanup_free_
char *what
= NULL
;
426 if (isempty(arg_root_what
)) {
427 log_debug("Could not find a root= entry on the kernel command line.");
431 what
= fstab_node_to_udev_node(arg_root_what
);
435 if (!arg_root_options
)
436 opts
= arg_root_rw
> 0 ? "rw" : "ro";
437 else if (arg_root_rw
>= 0 ||
438 !fstab_test_option(arg_root_options
, "ro\0" "rw\0"))
439 opts
= strjoina(arg_root_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
441 opts
= arg_root_options
;
443 log_debug("Found entry what=%s where=/sysroot type=%s", what
, strna(arg_root_fstype
));
444 return add_mount(what
,
448 is_device_path(what
) ? 1 : 0,
452 SPECIAL_INITRD_ROOT_FS_TARGET
,
456 static int add_usr_mount(void) {
457 _cleanup_free_
char *what
= NULL
;
460 if (!arg_usr_what
&& !arg_usr_fstype
&& !arg_usr_options
)
463 if (arg_root_what
&& !arg_usr_what
) {
464 arg_usr_what
= strdup(arg_root_what
);
470 if (arg_root_fstype
&& !arg_usr_fstype
) {
471 arg_usr_fstype
= strdup(arg_root_fstype
);
477 if (arg_root_options
&& !arg_usr_options
) {
478 arg_usr_options
= strdup(arg_root_options
);
480 if (!arg_usr_options
)
487 what
= fstab_node_to_udev_node(arg_usr_what
);
488 if (!path_is_absolute(what
)) {
489 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what
, strna(arg_usr_fstype
));
493 if (!arg_usr_options
)
494 opts
= arg_root_rw
> 0 ? "rw" : "ro";
495 else if (!fstab_test_option(arg_usr_options
, "ro\0" "rw\0"))
496 opts
= strjoina(arg_usr_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
498 opts
= arg_usr_options
;
500 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what
, strna(arg_usr_fstype
));
501 return add_mount(what
,
509 SPECIAL_INITRD_ROOT_FS_TARGET
,
513 static int parse_proc_cmdline_item(const char *key
, const char *value
) {
516 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
517 * instance should take precedence. In the case of multiple rootflags=
518 * or usrflags= the arguments should be concatenated */
520 if (STR_IN_SET(key
, "fstab", "rd.fstab") && value
) {
522 r
= parse_boolean(value
);
524 log_warning("Failed to parse fstab switch %s. Ignoring.", value
);
526 arg_fstab_enabled
= r
;
528 } else if (streq(key
, "root") && value
) {
530 if (free_and_strdup(&arg_root_what
, value
) < 0)
533 } else if (streq(key
, "rootfstype") && value
) {
535 if (free_and_strdup(&arg_root_fstype
, value
) < 0)
538 } else if (streq(key
, "rootflags") && value
) {
541 o
= arg_root_options
?
542 strjoin(arg_root_options
, ",", value
, NULL
) :
547 free(arg_root_options
);
548 arg_root_options
= o
;
550 } else if (streq(key
, "mount.usr") && value
) {
552 if (free_and_strdup(&arg_usr_what
, value
) < 0)
555 } else if (streq(key
, "mount.usrfstype") && value
) {
557 if (free_and_strdup(&arg_usr_fstype
, value
) < 0)
560 } else if (streq(key
, "mount.usrflags") && value
) {
563 o
= arg_usr_options
?
564 strjoin(arg_usr_options
, ",", value
, NULL
) :
569 free(arg_usr_options
);
572 } else if (streq(key
, "rw") && !value
)
574 else if (streq(key
, "ro") && !value
)
580 int main(int argc
, char *argv
[]) {
583 if (argc
> 1 && argc
!= 4) {
584 log_error("This program takes three or no arguments.");
591 log_set_target(LOG_TARGET_SAFE
);
592 log_parse_environment();
597 r
= parse_proc_cmdline(parse_proc_cmdline_item
);
599 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
601 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
603 r
= add_root_mount();
608 /* Honour /etc/fstab only when that's enabled */
609 if (arg_fstab_enabled
) {
612 log_debug("Parsing /etc/fstab");
614 /* Parse the local /etc/fstab, possibly from the initrd */
615 k
= parse_fstab(false);
619 /* If running in the initrd also parse the /etc/fstab from the host */
621 log_debug("Parsing /sysroot/etc/fstab");
623 k
= parse_fstab(true);
630 free(arg_root_fstype
);
631 free(arg_root_options
);
634 free(arg_usr_fstype
);
635 free(arg_usr_options
);
637 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;