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"
37 #include "generator.h"
41 static const char *arg_dest = "/tmp";
42 static bool arg_fstab_enabled = true;
43 static char *arg_root_what = NULL;
44 static char *arg_root_fstype = NULL;
45 static char *arg_root_options = NULL;
46 static int arg_root_rw = -1;
47 static char *arg_usr_what = NULL;
48 static char *arg_usr_fstype = NULL;
49 static char *arg_usr_options = NULL;
57 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
58 _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);
74 r = fstab_find_pri(me->mnt_opts, &pri);
76 return log_error_errno(r, "Failed to parse priority: %m");
78 name = unit_name_from_path(what, ".swap");
82 unit = strjoin(arg_dest, "/", name, NULL);
86 f = fopen(unit, "wxe");
89 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
91 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
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 /* Note that we currently pass the priority field twice, once
105 * in Priority=, and once in Options= */
107 fprintf(f, "Priority=%i\n", pri);
109 if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults"))
110 fprintf(f, "Options=%s\n", me->mnt_opts);
112 r = fflush_and_check(f);
114 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
116 /* use what as where, to have a nicer error message */
117 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
122 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
123 nofail ? ".wants/" : ".requires/", name, NULL);
127 mkdir_parents_label(lnk, 0755);
128 if (symlink(unit, lnk) < 0)
129 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
135 static bool mount_is_network(struct mntent *me) {
138 return fstab_test_option(me->mnt_opts, "_netdev\0") ||
139 fstype_is_network(me->mnt_type);
142 static bool mount_in_initrd(struct mntent *me) {
145 return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
146 streq(me->mnt_dir, "/usr");
149 static int add_mount(
159 const char *source) {
162 *name = NULL, *unit = NULL, *lnk = NULL,
163 *automount_name = NULL, *automount_unit = NULL,
165 _cleanup_fclose_ FILE *f = NULL;
173 if (streq_ptr(fstype, "autofs"))
176 if (!is_path(where)) {
177 log_warning("Mount point %s is not a valid path, ignoring.", where);
181 if (mount_point_is_api(where) ||
182 mount_point_ignore(where))
185 if (path_equal(where, "/")) {
186 /* The root disk is not an option */
192 name = unit_name_from_path(where, ".mount");
196 unit = strjoin(arg_dest, "/", name, NULL);
200 f = fopen(unit, "wxe");
203 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
205 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
210 "# Automatically generated by systemd-fstab-generator\n\n"
213 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
216 if (post && !noauto && !nofail && !automount)
217 fprintf(f, "Before=%s\n", post);
220 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
233 if (!isempty(fstype) && !streq(fstype, "auto"))
234 fprintf(f, "Type=%s\n", fstype);
236 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
240 if (!isempty(filtered) && !streq(filtered, "defaults"))
241 fprintf(f, "Options=%s\n", filtered);
245 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
247 if (!noauto && post) {
248 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
252 mkdir_parents_label(lnk, 0755);
253 if (symlink(unit, lnk) < 0)
254 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
258 automount_name = unit_name_from_path(where, ".automount");
262 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
267 f = fopen(automount_unit, "wxe");
269 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
272 "# Automatically generated by systemd-fstab-generator\n\n"
275 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
290 return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
293 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
297 mkdir_parents_label(lnk, 0755);
298 if (symlink(automount_unit, lnk) < 0)
299 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
305 static int parse_fstab(bool initrd) {
306 _cleanup_endmntent_ FILE *f = NULL;
307 const char *fstab_path;
311 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
312 f = setmntent(fstab_path, "re");
317 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
321 while ((me = getmntent(f))) {
322 _cleanup_free_ char *where = NULL, *what = NULL;
326 if (initrd && !mount_in_initrd(me))
329 what = fstab_node_to_udev_node(me->mnt_fsname);
333 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
334 log_info("Running in a container, ignoring fstab device entry for %s.", what);
338 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
343 path_kill_slashes(where);
345 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
346 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
347 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
348 what, where, me->mnt_type,
349 yes_no(noauto), yes_no(nofail));
351 if (streq(me->mnt_type, "swap"))
352 k = add_swap(what, me, noauto, nofail);
357 automount = fstab_test_option(me->mnt_opts,
358 "comment=systemd.automount\0"
359 "x-systemd.automount\0");
361 post = SPECIAL_INITRD_FS_TARGET;
362 else if (mount_in_initrd(me))
363 post = SPECIAL_INITRD_ROOT_FS_TARGET;
364 else if (mount_is_network(me))
365 post = SPECIAL_REMOTE_FS_TARGET;
367 post = SPECIAL_LOCAL_FS_TARGET;
388 static int add_root_mount(void) {
389 _cleanup_free_ char *what = NULL;
392 if (isempty(arg_root_what)) {
393 log_debug("Could not find a root= entry on the kernel command line.");
397 what = fstab_node_to_udev_node(arg_root_what);
398 if (!path_is_absolute(what)) {
399 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
403 if (!arg_root_options)
404 opts = arg_root_rw > 0 ? "rw" : "ro";
405 else if (arg_root_rw >= 0 ||
406 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
407 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
409 opts = arg_root_options;
411 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
412 return add_mount(what,
420 SPECIAL_INITRD_ROOT_FS_TARGET,
424 static int add_usr_mount(void) {
425 _cleanup_free_ char *what = NULL;
428 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
431 if (arg_root_what && !arg_usr_what) {
432 arg_usr_what = strdup(arg_root_what);
438 if (arg_root_fstype && !arg_usr_fstype) {
439 arg_usr_fstype = strdup(arg_root_fstype);
445 if (arg_root_options && !arg_usr_options) {
446 arg_usr_options = strdup(arg_root_options);
448 if (!arg_usr_options)
455 what = fstab_node_to_udev_node(arg_usr_what);
456 if (!path_is_absolute(what)) {
457 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
461 if (!arg_usr_options)
462 opts = arg_root_rw > 0 ? "rw" : "ro";
463 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
464 opts = strappenda(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
466 opts = arg_usr_options;
468 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
469 return add_mount(what,
477 SPECIAL_INITRD_ROOT_FS_TARGET,
481 static int parse_proc_cmdline_item(const char *key, const char *value) {
484 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
485 * instance should take precedence. In the case of multiple rootflags=
486 * or usrflags= the arguments should be concatenated */
488 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
490 r = parse_boolean(value);
492 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
494 arg_fstab_enabled = r;
496 } else if (streq(key, "root") && value) {
498 if (free_and_strdup(&arg_root_what, value) < 0)
501 } else if (streq(key, "rootfstype") && value) {
503 if (free_and_strdup(&arg_root_fstype, value) < 0)
506 } else if (streq(key, "rootflags") && value) {
509 o = arg_root_options ?
510 strjoin(arg_root_options, ",", value, NULL) :
515 free(arg_root_options);
516 arg_root_options = o;
518 } else if (streq(key, "mount.usr") && value) {
520 if (free_and_strdup(&arg_usr_what, value) < 0)
523 } else if (streq(key, "mount.usrfstype") && value) {
525 if (free_and_strdup(&arg_usr_fstype, value) < 0)
528 } else if (streq(key, "mount.usrflags") && value) {
531 o = arg_usr_options ?
532 strjoin(arg_usr_options, ",", value, NULL) :
537 free(arg_usr_options);
540 } else if (streq(key, "rw") && !value)
542 else if (streq(key, "ro") && !value)
548 int main(int argc, char *argv[]) {
551 if (argc > 1 && argc != 4) {
552 log_error("This program takes three or no arguments.");
559 log_set_target(LOG_TARGET_SAFE);
560 log_parse_environment();
565 r = parse_proc_cmdline(parse_proc_cmdline_item);
567 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
569 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
571 r = add_root_mount();
576 /* Honour /etc/fstab only when that's enabled */
577 if (arg_fstab_enabled) {
580 log_debug("Parsing /etc/fstab");
582 /* Parse the local /etc/fstab, possibly from the initrd */
583 k = parse_fstab(false);
587 /* If running in the initrd also parse the /etc/fstab from the host */
589 log_debug("Parsing /sysroot/etc/fstab");
591 k = parse_fstab(true);
598 free(arg_root_fstype);
599 free(arg_root_options);
602 free(arg_usr_fstype);
603 free(arg_usr_options);
605 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;