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);
409 if (!arg_root_options)
410 opts = arg_root_rw > 0 ? "rw" : "ro";
411 else if (arg_root_rw >= 0 ||
412 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
413 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
415 opts = arg_root_options;
417 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
418 return add_mount(what,
422 is_device_path(what) ? 1 : 0,
426 SPECIAL_INITRD_ROOT_FS_TARGET,
430 static int add_usr_mount(void) {
431 _cleanup_free_ char *what = NULL;
434 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
437 if (arg_root_what && !arg_usr_what) {
438 arg_usr_what = strdup(arg_root_what);
444 if (arg_root_fstype && !arg_usr_fstype) {
445 arg_usr_fstype = strdup(arg_root_fstype);
451 if (arg_root_options && !arg_usr_options) {
452 arg_usr_options = strdup(arg_root_options);
454 if (!arg_usr_options)
461 what = fstab_node_to_udev_node(arg_usr_what);
462 if (!path_is_absolute(what)) {
463 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
467 if (!arg_usr_options)
468 opts = arg_root_rw > 0 ? "rw" : "ro";
469 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
470 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
472 opts = arg_usr_options;
474 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
475 return add_mount(what,
483 SPECIAL_INITRD_ROOT_FS_TARGET,
487 static int parse_proc_cmdline_item(const char *key, const char *value) {
490 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
491 * instance should take precedence. In the case of multiple rootflags=
492 * or usrflags= the arguments should be concatenated */
494 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
496 r = parse_boolean(value);
498 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
500 arg_fstab_enabled = r;
502 } else if (streq(key, "root") && value) {
504 if (free_and_strdup(&arg_root_what, value) < 0)
507 } else if (streq(key, "rootfstype") && value) {
509 if (free_and_strdup(&arg_root_fstype, value) < 0)
512 } else if (streq(key, "rootflags") && value) {
515 o = arg_root_options ?
516 strjoin(arg_root_options, ",", value, NULL) :
521 free(arg_root_options);
522 arg_root_options = o;
524 } else if (streq(key, "mount.usr") && value) {
526 if (free_and_strdup(&arg_usr_what, value) < 0)
529 } else if (streq(key, "mount.usrfstype") && value) {
531 if (free_and_strdup(&arg_usr_fstype, value) < 0)
534 } else if (streq(key, "mount.usrflags") && value) {
537 o = arg_usr_options ?
538 strjoin(arg_usr_options, ",", value, NULL) :
543 free(arg_usr_options);
546 } else if (streq(key, "rw") && !value)
548 else if (streq(key, "ro") && !value)
554 int main(int argc, char *argv[]) {
557 if (argc > 1 && argc != 4) {
558 log_error("This program takes three or no arguments.");
565 log_set_target(LOG_TARGET_SAFE);
566 log_parse_environment();
571 r = parse_proc_cmdline(parse_proc_cmdline_item);
573 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
575 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
577 r = add_root_mount();
582 /* Honour /etc/fstab only when that's enabled */
583 if (arg_fstab_enabled) {
586 log_debug("Parsing /etc/fstab");
588 /* Parse the local /etc/fstab, possibly from the initrd */
589 k = parse_fstab(false);
593 /* If running in the initrd also parse the /etc/fstab from the host */
595 log_debug("Parsing /sysroot/etc/fstab");
597 k = parse_fstab(true);
604 free(arg_root_fstype);
605 free(arg_root_options);
608 free(arg_usr_fstype);
609 free(arg_usr_options);
611 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;