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 "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;
50 static int mount_find_pri(struct mntent *me, int *ret) {
57 opt = hasmntopt(me, "pri");
66 r = strtoul(opt + 1, &end, 10);
70 if (end == opt + 1 || (*end != ',' && *end != 0))
83 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
84 _cleanup_fclose_ FILE *f = NULL;
90 if (detect_container(NULL) > 0) {
91 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
95 r = mount_find_pri(me, &pri);
97 log_error("Failed to parse priority");
101 name = unit_name_from_path(what, ".swap");
105 unit = strjoin(arg_dest, "/", name, NULL);
109 f = fopen(unit, "wxe");
112 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
114 log_error("Failed to create unit file %s: %m", unit);
119 "# Automatically generated by systemd-fstab-generator\n\n"
121 "SourcePath=/etc/fstab\n"
122 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
127 /* Note that we currently pass the priority field twice, once
128 * in Priority=, and once in Options= */
130 fprintf(f, "Priority=%i\n", pri);
132 if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults"))
133 fprintf(f, "Options=%s\n", me->mnt_opts);
135 r = fflush_and_check(f);
137 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
139 /* use what as where, to have a nicer error message */
140 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
145 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
146 nofail ? ".wants/" : ".requires/", name, NULL);
150 mkdir_parents_label(lnk, 0755);
151 if (symlink(unit, lnk) < 0) {
152 log_error("Failed to create symlink %s: %m", lnk);
160 static bool mount_is_network(struct mntent *me) {
164 hasmntopt(me, "_netdev") ||
165 fstype_is_network(me->mnt_type);
168 static bool mount_in_initrd(struct mntent *me) {
172 hasmntopt(me, "x-initrd.mount") ||
173 streq(me->mnt_dir, "/usr");
176 static int add_mount(
186 const char *source) {
189 *name = NULL, *unit = NULL, *lnk = NULL,
190 *automount_name = NULL, *automount_unit = NULL,
192 _cleanup_fclose_ FILE *f = NULL;
200 if (streq_ptr(fstype, "autofs"))
203 if (!is_path(where)) {
204 log_warning("Mount point %s is not a valid path, ignoring.", where);
208 if (mount_point_is_api(where) ||
209 mount_point_ignore(where))
212 if (path_equal(where, "/")) {
213 /* The root disk is not an option */
219 name = unit_name_from_path(where, ".mount");
223 unit = strjoin(arg_dest, "/", name, NULL);
227 f = fopen(unit, "wxe");
230 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
232 log_error("Failed to create unit file %s: %m", unit);
237 "# Automatically generated by systemd-fstab-generator\n\n"
240 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
243 if (post && !noauto && !nofail && !automount)
244 fprintf(f, "Before=%s\n", post);
247 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
260 if (!isempty(fstype) && !streq(fstype, "auto"))
261 fprintf(f, "Type=%s\n", fstype);
263 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
267 if (!isempty(filtered) && !streq(filtered, "defaults"))
268 fprintf(f, "Options=%s\n", filtered);
272 log_error("Failed to write unit file %s: %m", unit);
276 if (!noauto && post) {
277 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
281 mkdir_parents_label(lnk, 0755);
282 if (symlink(unit, lnk) < 0) {
283 log_error("Failed to create symlink %s: %m", lnk);
289 automount_name = unit_name_from_path(where, ".automount");
293 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
298 f = fopen(automount_unit, "wxe");
300 log_error("Failed to create unit file %s: %m", automount_unit);
305 "# Automatically generated by systemd-fstab-generator\n\n"
308 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
323 log_error("Failed to write unit file %s: %m", automount_unit);
328 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
332 mkdir_parents_label(lnk, 0755);
333 if (symlink(automount_unit, lnk) < 0) {
334 log_error("Failed to create symlink %s: %m", lnk);
342 static int parse_fstab(bool initrd) {
343 _cleanup_endmntent_ FILE *f = NULL;
344 const char *fstab_path;
348 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
349 f = setmntent(fstab_path, "re");
354 log_error("Failed to open %s: %m", fstab_path);
358 while ((me = getmntent(f))) {
359 _cleanup_free_ char *where = NULL, *what = NULL;
363 if (initrd && !mount_in_initrd(me))
366 what = fstab_node_to_udev_node(me->mnt_fsname);
370 if (detect_container(NULL) > 0 && is_device_path(what)) {
371 log_info("Running in a container, ignoring fstab device entry for %s.", what);
375 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
380 path_kill_slashes(where);
382 noauto = !!hasmntopt(me, "noauto");
383 nofail = !!hasmntopt(me, "nofail");
384 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
385 what, where, me->mnt_type,
386 yes_no(noauto), yes_no(nofail));
388 if (streq(me->mnt_type, "swap"))
389 k = add_swap(what, me, noauto, nofail);
395 hasmntopt(me, "comment=systemd.automount") ||
396 hasmntopt(me, "x-systemd.automount");
399 post = SPECIAL_INITRD_FS_TARGET;
400 else if (mount_in_initrd(me))
401 post = SPECIAL_INITRD_ROOT_FS_TARGET;
402 else if (mount_is_network(me))
403 post = SPECIAL_REMOTE_FS_TARGET;
405 post = SPECIAL_LOCAL_FS_TARGET;
426 static int add_root_mount(void) {
427 _cleanup_free_ char *what = NULL;
430 if (isempty(arg_root_what)) {
431 log_debug("Could not find a root= entry on the kernel command line.");
435 what = fstab_node_to_udev_node(arg_root_what);
436 if (!path_is_absolute(what)) {
437 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
441 if (!arg_root_options)
442 opts = arg_root_rw > 0 ? "rw" : "ro";
443 else if (arg_root_rw >= 0 ||
444 (!mount_test_option(arg_root_options, "ro") &&
445 !mount_test_option(arg_root_options, "rw")))
446 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
448 opts = arg_root_options;
450 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
451 return add_mount(what,
459 SPECIAL_INITRD_ROOT_FS_TARGET,
463 static int add_usr_mount(void) {
464 _cleanup_free_ char *what = NULL;
467 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
470 if (arg_root_what && !arg_usr_what) {
471 arg_usr_what = strdup(arg_root_what);
477 if (arg_root_fstype && !arg_usr_fstype) {
478 arg_usr_fstype = strdup(arg_root_fstype);
484 if (arg_root_options && !arg_usr_options) {
485 arg_usr_options = strdup(arg_root_options);
487 if (!arg_usr_options)
491 if (!arg_usr_what || !arg_usr_options)
494 what = fstab_node_to_udev_node(arg_usr_what);
495 if (!path_is_absolute(what)) {
496 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
500 opts = arg_usr_options;
502 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
503 return add_mount(what,
511 SPECIAL_INITRD_ROOT_FS_TARGET,
515 static int parse_proc_cmdline_item(const char *key, const char *value) {
518 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
519 * instance should take precedence. In the case of multiple rootflags=
520 * or usrflags= the arguments should be concatenated */
522 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
524 r = parse_boolean(value);
526 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
528 arg_fstab_enabled = r;
530 } else if (streq(key, "root") && value) {
532 if (free_and_strdup(&arg_root_what, value) < 0)
535 } else if (streq(key, "rootfstype") && value) {
537 if (free_and_strdup(&arg_root_fstype, value) < 0)
540 } else if (streq(key, "rootflags") && value) {
543 o = arg_root_options ?
544 strjoin(arg_root_options, ",", value, NULL) :
549 free(arg_root_options);
550 arg_root_options = o;
552 } else if (streq(key, "mount.usr") && value) {
554 if (free_and_strdup(&arg_usr_what, value) < 0)
557 } else if (streq(key, "mount.usrfstype") && value) {
559 if (free_and_strdup(&arg_usr_fstype, value) < 0)
562 } else if (streq(key, "mount.usrflags") && value) {
565 o = arg_usr_options ?
566 strjoin(arg_usr_options, ",", value, NULL) :
571 free(arg_usr_options);
574 } else if (streq(key, "rw") && !value)
576 else if (streq(key, "ro") && !value)
582 int main(int argc, char *argv[]) {
585 if (argc > 1 && argc != 4) {
586 log_error("This program takes three or no arguments.");
593 log_set_target(LOG_TARGET_SAFE);
594 log_parse_environment();
599 r = parse_proc_cmdline(parse_proc_cmdline_item);
601 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
603 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
605 r = add_root_mount();
610 /* Honour /etc/fstab only when that's enabled */
611 if (arg_fstab_enabled) {
614 log_debug("Parsing /etc/fstab");
616 /* Parse the local /etc/fstab, possibly from the initrd */
617 k = parse_fstab(false);
621 /* If running in the initrd also parse the /etc/fstab from the host */
623 log_debug("Parsing /sysroot/etc/fstab");
625 k = parse_fstab(true);
633 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;