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 add_mount(
167 const char *source) {
170 *name = NULL, *unit = NULL, *lnk = NULL,
171 *automount_name = NULL, *automount_unit = NULL,
173 _cleanup_fclose_ FILE *f = NULL;
181 if (streq_ptr(fstype, "autofs"))
184 if (!is_path(where)) {
185 log_warning("Mount point %s is not a valid path, ignoring.", where);
189 if (mount_point_is_api(where) ||
190 mount_point_ignore(where))
193 if (path_equal(where, "/")) {
194 /* The root disk is not an option */
200 name = unit_name_from_path(where, ".mount");
204 unit = strjoin(arg_dest, "/", name, NULL);
208 f = fopen(unit, "wxe");
211 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
213 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
218 "# Automatically generated by systemd-fstab-generator\n\n"
221 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
224 if (post && !noauto && !nofail && !automount)
225 fprintf(f, "Before=%s\n", post);
228 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
241 if (!isempty(fstype) && !streq(fstype, "auto"))
242 fprintf(f, "Type=%s\n", fstype);
244 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
248 if (!isempty(filtered) && !streq(filtered, "defaults"))
249 fprintf(f, "Options=%s\n", filtered);
253 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
255 if (!noauto && post) {
256 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
260 mkdir_parents_label(lnk, 0755);
261 if (symlink(unit, lnk) < 0)
262 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
266 automount_name = unit_name_from_path(where, ".automount");
270 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
275 f = fopen(automount_unit, "wxe");
277 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
280 "# Automatically generated by systemd-fstab-generator\n\n"
283 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
298 return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
301 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
305 mkdir_parents_label(lnk, 0755);
306 if (symlink(automount_unit, lnk) < 0)
307 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
313 static int parse_fstab(bool initrd) {
314 _cleanup_endmntent_ FILE *f = NULL;
315 const char *fstab_path;
319 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
320 f = setmntent(fstab_path, "re");
325 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
329 while ((me = getmntent(f))) {
330 _cleanup_free_ char *where = NULL, *what = NULL;
334 if (initrd && !mount_in_initrd(me))
337 what = fstab_node_to_udev_node(me->mnt_fsname);
341 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
342 log_info("Running in a container, ignoring fstab device entry for %s.", what);
346 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
351 path_kill_slashes(where);
353 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
354 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
355 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
356 what, where, me->mnt_type,
357 yes_no(noauto), yes_no(nofail));
359 if (streq(me->mnt_type, "swap"))
360 k = add_swap(what, me, noauto, nofail);
365 automount = fstab_test_option(me->mnt_opts,
366 "comment=systemd.automount\0"
367 "x-systemd.automount\0");
369 post = SPECIAL_INITRD_FS_TARGET;
370 else if (mount_in_initrd(me))
371 post = SPECIAL_INITRD_ROOT_FS_TARGET;
372 else if (mount_is_network(me))
373 post = SPECIAL_REMOTE_FS_TARGET;
375 post = SPECIAL_LOCAL_FS_TARGET;
396 static int add_root_mount(void) {
397 _cleanup_free_ char *what = NULL;
400 if (isempty(arg_root_what)) {
401 log_debug("Could not find a root= entry on the kernel command line.");
405 what = fstab_node_to_udev_node(arg_root_what);
406 if (!path_is_absolute(what)) {
407 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
411 if (!arg_root_options)
412 opts = arg_root_rw > 0 ? "rw" : "ro";
413 else if (arg_root_rw >= 0 ||
414 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
415 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
417 opts = arg_root_options;
419 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
420 return add_mount(what,
428 SPECIAL_INITRD_ROOT_FS_TARGET,
432 static int add_usr_mount(void) {
433 _cleanup_free_ char *what = NULL;
436 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
439 if (arg_root_what && !arg_usr_what) {
440 arg_usr_what = strdup(arg_root_what);
446 if (arg_root_fstype && !arg_usr_fstype) {
447 arg_usr_fstype = strdup(arg_root_fstype);
453 if (arg_root_options && !arg_usr_options) {
454 arg_usr_options = strdup(arg_root_options);
456 if (!arg_usr_options)
463 what = fstab_node_to_udev_node(arg_usr_what);
464 if (!path_is_absolute(what)) {
465 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
469 if (!arg_usr_options)
470 opts = arg_root_rw > 0 ? "rw" : "ro";
471 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
472 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
474 opts = arg_usr_options;
476 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
477 return add_mount(what,
485 SPECIAL_INITRD_ROOT_FS_TARGET,
489 static int parse_proc_cmdline_item(const char *key, const char *value) {
492 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
493 * instance should take precedence. In the case of multiple rootflags=
494 * or usrflags= the arguments should be concatenated */
496 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
498 r = parse_boolean(value);
500 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
502 arg_fstab_enabled = r;
504 } else if (streq(key, "root") && value) {
506 if (free_and_strdup(&arg_root_what, value) < 0)
509 } else if (streq(key, "rootfstype") && value) {
511 if (free_and_strdup(&arg_root_fstype, value) < 0)
514 } else if (streq(key, "rootflags") && value) {
517 o = arg_root_options ?
518 strjoin(arg_root_options, ",", value, NULL) :
523 free(arg_root_options);
524 arg_root_options = o;
526 } else if (streq(key, "mount.usr") && value) {
528 if (free_and_strdup(&arg_usr_what, value) < 0)
531 } else if (streq(key, "mount.usrfstype") && value) {
533 if (free_and_strdup(&arg_usr_fstype, value) < 0)
536 } else if (streq(key, "mount.usrflags") && value) {
539 o = arg_usr_options ?
540 strjoin(arg_usr_options, ",", value, NULL) :
545 free(arg_usr_options);
548 } else if (streq(key, "rw") && !value)
550 else if (streq(key, "ro") && !value)
556 int main(int argc, char *argv[]) {
559 if (argc > 1 && argc != 4) {
560 log_error("This program takes three or no arguments.");
567 log_set_target(LOG_TARGET_SAFE);
568 log_parse_environment();
573 r = parse_proc_cmdline(parse_proc_cmdline_item);
575 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
577 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
579 r = add_root_mount();
584 /* Honour /etc/fstab only when that's enabled */
585 if (arg_fstab_enabled) {
588 log_debug("Parsing /etc/fstab");
590 /* Parse the local /etc/fstab, possibly from the initrd */
591 k = parse_fstab(false);
595 /* If running in the initrd also parse the /etc/fstab from the host */
597 log_debug("Parsing /sysroot/etc/fstab");
599 k = parse_fstab(true);
606 free(arg_root_fstype);
607 free(arg_root_options);
610 free(arg_usr_fstype);
611 free(arg_usr_options);
613 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;