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(NULL) > 0) {
69 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
73 r = fstab_find_pri(me->mnt_opts, &pri);
75 return log_error_errno(r, "Failed to parse priority: %m");
77 name = unit_name_from_path(what, ".swap");
81 unit = strjoin(arg_dest, "/", name, NULL);
85 f = fopen(unit, "wxe");
88 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
90 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
95 "# Automatically generated by systemd-fstab-generator\n\n"
97 "SourcePath=/etc/fstab\n"
98 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
103 /* Note that we currently pass the priority field twice, once
104 * in Priority=, and once in Options= */
106 fprintf(f, "Priority=%i\n", pri);
108 if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults"))
109 fprintf(f, "Options=%s\n", me->mnt_opts);
111 r = fflush_and_check(f);
113 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
115 /* use what as where, to have a nicer error message */
116 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
121 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
122 nofail ? ".wants/" : ".requires/", name, NULL);
126 mkdir_parents_label(lnk, 0755);
127 if (symlink(unit, lnk) < 0)
128 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
134 static bool mount_is_network(struct mntent *me) {
137 return fstab_test_option(me->mnt_opts, "_netdev\0") ||
138 fstype_is_network(me->mnt_type);
141 static bool mount_in_initrd(struct mntent *me) {
144 return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
145 streq(me->mnt_dir, "/usr");
148 static int add_mount(
158 const char *source) {
161 *name = NULL, *unit = NULL, *lnk = NULL,
162 *automount_name = NULL, *automount_unit = NULL,
164 _cleanup_fclose_ FILE *f = NULL;
172 if (streq_ptr(fstype, "autofs"))
175 if (!is_path(where)) {
176 log_warning("Mount point %s is not a valid path, ignoring.", where);
180 if (mount_point_is_api(where) ||
181 mount_point_ignore(where))
184 if (path_equal(where, "/")) {
185 /* The root disk is not an option */
191 name = unit_name_from_path(where, ".mount");
195 unit = strjoin(arg_dest, "/", name, NULL);
199 f = fopen(unit, "wxe");
202 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
204 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
209 "# Automatically generated by systemd-fstab-generator\n\n"
212 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
215 if (post && !noauto && !nofail && !automount)
216 fprintf(f, "Before=%s\n", post);
219 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
232 if (!isempty(fstype) && !streq(fstype, "auto"))
233 fprintf(f, "Type=%s\n", fstype);
235 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
239 if (!isempty(filtered) && !streq(filtered, "defaults"))
240 fprintf(f, "Options=%s\n", filtered);
244 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
246 if (!noauto && post) {
247 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
251 mkdir_parents_label(lnk, 0755);
252 if (symlink(unit, lnk) < 0)
253 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
257 automount_name = unit_name_from_path(where, ".automount");
261 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
266 f = fopen(automount_unit, "wxe");
268 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
271 "# Automatically generated by systemd-fstab-generator\n\n"
274 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
289 return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
292 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
296 mkdir_parents_label(lnk, 0755);
297 if (symlink(automount_unit, lnk) < 0)
298 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
304 static int parse_fstab(bool initrd) {
305 _cleanup_endmntent_ FILE *f = NULL;
306 const char *fstab_path;
310 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
311 f = setmntent(fstab_path, "re");
316 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
320 while ((me = getmntent(f))) {
321 _cleanup_free_ char *where = NULL, *what = NULL;
325 if (initrd && !mount_in_initrd(me))
328 what = fstab_node_to_udev_node(me->mnt_fsname);
332 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
333 log_info("Running in a container, ignoring fstab device entry for %s.", what);
337 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
342 path_kill_slashes(where);
344 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
345 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
346 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
347 what, where, me->mnt_type,
348 yes_no(noauto), yes_no(nofail));
350 if (streq(me->mnt_type, "swap"))
351 k = add_swap(what, me, noauto, nofail);
356 automount = fstab_test_option(me->mnt_opts,
357 "comment=systemd.automount\0"
358 "x-systemd.automount\0");
360 post = SPECIAL_INITRD_FS_TARGET;
361 else if (mount_in_initrd(me))
362 post = SPECIAL_INITRD_ROOT_FS_TARGET;
363 else if (mount_is_network(me))
364 post = SPECIAL_REMOTE_FS_TARGET;
366 post = SPECIAL_LOCAL_FS_TARGET;
387 static int add_root_mount(void) {
388 _cleanup_free_ char *what = NULL;
391 if (isempty(arg_root_what)) {
392 log_debug("Could not find a root= entry on the kernel command line.");
396 what = fstab_node_to_udev_node(arg_root_what);
397 if (!path_is_absolute(what)) {
398 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
402 if (!arg_root_options)
403 opts = arg_root_rw > 0 ? "rw" : "ro";
404 else if (arg_root_rw >= 0 ||
405 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
406 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
408 opts = arg_root_options;
410 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
411 return add_mount(what,
419 SPECIAL_INITRD_ROOT_FS_TARGET,
423 static int add_usr_mount(void) {
424 _cleanup_free_ char *what = NULL;
427 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
430 if (arg_root_what && !arg_usr_what) {
431 arg_usr_what = strdup(arg_root_what);
437 if (arg_root_fstype && !arg_usr_fstype) {
438 arg_usr_fstype = strdup(arg_root_fstype);
444 if (arg_root_options && !arg_usr_options) {
445 arg_usr_options = strdup(arg_root_options);
447 if (!arg_usr_options)
454 what = fstab_node_to_udev_node(arg_usr_what);
455 if (!path_is_absolute(what)) {
456 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
460 if (!arg_usr_options)
461 opts = arg_root_rw > 0 ? "rw" : "ro";
462 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
463 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
465 opts = arg_usr_options;
467 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
468 return add_mount(what,
476 SPECIAL_INITRD_ROOT_FS_TARGET,
480 static int parse_proc_cmdline_item(const char *key, const char *value) {
483 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
484 * instance should take precedence. In the case of multiple rootflags=
485 * or usrflags= the arguments should be concatenated */
487 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
489 r = parse_boolean(value);
491 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
493 arg_fstab_enabled = r;
495 } else if (streq(key, "root") && value) {
497 if (free_and_strdup(&arg_root_what, value) < 0)
500 } else if (streq(key, "rootfstype") && value) {
502 if (free_and_strdup(&arg_root_fstype, value) < 0)
505 } else if (streq(key, "rootflags") && value) {
508 o = arg_root_options ?
509 strjoin(arg_root_options, ",", value, NULL) :
514 free(arg_root_options);
515 arg_root_options = o;
517 } else if (streq(key, "mount.usr") && value) {
519 if (free_and_strdup(&arg_usr_what, value) < 0)
522 } else if (streq(key, "mount.usrfstype") && value) {
524 if (free_and_strdup(&arg_usr_fstype, value) < 0)
527 } else if (streq(key, "mount.usrflags") && value) {
530 o = arg_usr_options ?
531 strjoin(arg_usr_options, ",", value, NULL) :
536 free(arg_usr_options);
539 } else if (streq(key, "rw") && !value)
541 else if (streq(key, "ro") && !value)
547 int main(int argc, char *argv[]) {
550 if (argc > 1 && argc != 4) {
551 log_error("This program takes three or no arguments.");
558 log_set_target(LOG_TARGET_SAFE);
559 log_parse_environment();
564 r = parse_proc_cmdline(parse_proc_cmdline_item);
566 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
568 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
570 r = add_root_mount();
575 /* Honour /etc/fstab only when that's enabled */
576 if (arg_fstab_enabled) {
579 log_debug("Parsing /etc/fstab");
581 /* Parse the local /etc/fstab, possibly from the initrd */
582 k = parse_fstab(false);
586 /* If running in the initrd also parse the /etc/fstab from the host */
588 log_debug("Parsing /sysroot/etc/fstab");
590 k = parse_fstab(true);
597 free(arg_root_fstype);
598 free(arg_root_options);
601 free(arg_usr_fstype);
602 free(arg_usr_options);
604 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;