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;
48 static int mount_find_pri(struct mntent *me, int *ret) {
55 pri = hasmntopt(me, "pri");
62 r = strtoul(pri, &end, 10);
66 if (end == pri || (*end != ',' && *end != 0))
73 static int add_swap(const char *what, struct mntent *me) {
74 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
75 _cleanup_fclose_ FILE *f = NULL;
84 if (detect_container(NULL) > 0) {
85 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
89 r = mount_find_pri(me, &pri);
91 log_error("Failed to parse priority");
95 noauto = !!hasmntopt(me, "noauto");
97 name = unit_name_from_path(what, ".swap");
101 unit = strjoin(arg_dest, "/", name, NULL);
105 f = fopen(unit, "wxe");
108 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
110 log_error("Failed to create unit file %s: %m", unit);
115 "# Automatically generated by systemd-fstab-generator\n\n"
117 "SourcePath=/etc/fstab\n"
118 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
123 discard = mount_test_option(me->mnt_opts, "discard");
125 discard = strpbrk(discard, "=");
128 discard ? discard+1 : "all");
138 log_error("Failed to write unit file %s: %m", unit);
142 /* use what as where, to have a nicer error message */
143 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
148 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
152 mkdir_parents_label(lnk, 0755);
153 if (symlink(unit, lnk) < 0) {
154 log_error("Failed to create symlink %s: %m", lnk);
162 static bool mount_is_network(struct mntent *me) {
166 hasmntopt(me, "_netdev") ||
167 fstype_is_network(me->mnt_type);
170 static bool mount_in_initrd(struct mntent *me) {
174 hasmntopt(me, "x-initrd.mount") ||
175 streq(me->mnt_dir, "/usr");
178 static int add_mount(
188 const char *source) {
191 *name = NULL, *unit = NULL, *lnk = NULL,
192 *automount_name = NULL, *automount_unit = NULL,
194 _cleanup_fclose_ FILE *f = NULL;
202 if (streq_ptr(fstype, "autofs"))
205 if (!is_path(where)) {
206 log_warning("Mount point %s is not a valid path, ignoring.", where);
210 if (mount_point_is_api(where) ||
211 mount_point_ignore(where))
214 if (path_equal(where, "/")) {
215 /* The root disk is not an option */
221 name = unit_name_from_path(where, ".mount");
225 unit = strjoin(arg_dest, "/", name, NULL);
229 f = fopen(unit, "wxe");
232 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
234 log_error("Failed to create unit file %s: %m", unit);
239 "# Automatically generated by systemd-fstab-generator\n\n"
242 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
245 if (post && !noauto && !nofail && !automount)
246 fprintf(f, "Before=%s\n", post);
249 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
262 if (!isempty(fstype) && !streq(fstype, "auto"))
263 fprintf(f, "Type=%s\n", fstype);
265 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
269 if (!isempty(filtered) && !streq(filtered, "defaults"))
270 fprintf(f, "Options=%s\n", filtered);
274 log_error("Failed to write unit file %s: %m", unit);
278 if (!noauto && post) {
279 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
283 mkdir_parents_label(lnk, 0755);
284 if (symlink(unit, lnk) < 0) {
285 log_error("Failed to create symlink %s: %m", lnk);
291 automount_name = unit_name_from_path(where, ".automount");
295 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
300 f = fopen(automount_unit, "wxe");
302 log_error("Failed to create unit file %s: %m", automount_unit);
307 "# Automatically generated by systemd-fstab-generator\n\n"
310 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
325 log_error("Failed to write unit file %s: %m", automount_unit);
330 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
334 mkdir_parents_label(lnk, 0755);
335 if (symlink(automount_unit, lnk) < 0) {
336 log_error("Failed to create symlink %s: %m", lnk);
344 static int parse_fstab(bool initrd) {
345 _cleanup_endmntent_ FILE *f = NULL;
346 const char *fstab_path;
350 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
351 f = setmntent(fstab_path, "re");
356 log_error("Failed to open %s: %m", fstab_path);
360 while ((me = getmntent(f))) {
361 _cleanup_free_ char *where = NULL, *what = NULL;
364 if (initrd && !mount_in_initrd(me))
367 what = fstab_node_to_udev_node(me->mnt_fsname);
371 if (detect_container(NULL) > 0 && is_device_path(what)) {
372 log_info("Running in a container, ignoring fstab device entry for %s.", what);
376 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
381 path_kill_slashes(where);
383 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
385 if (streq(me->mnt_type, "swap"))
386 k = add_swap(what, me);
388 bool noauto, nofail, automount;
391 noauto = !!hasmntopt(me, "noauto");
392 nofail = !!hasmntopt(me, "nofail");
394 hasmntopt(me, "comment=systemd.automount") ||
395 hasmntopt(me, "x-systemd.automount");
398 post = SPECIAL_INITRD_FS_TARGET;
399 else if (mount_in_initrd(me))
400 post = SPECIAL_INITRD_ROOT_FS_TARGET;
401 else if (mount_is_network(me))
402 post = SPECIAL_REMOTE_FS_TARGET;
404 post = SPECIAL_LOCAL_FS_TARGET;
425 static int add_root_mount(void) {
426 _cleanup_free_ char *what = NULL;
429 if (isempty(arg_root_what)) {
430 log_debug("Could not find a root= entry on the kernel commandline.");
434 what = fstab_node_to_udev_node(arg_root_what);
435 if (!path_is_absolute(what)) {
436 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
440 if (!arg_root_options)
441 opts = arg_root_rw > 0 ? "rw" : "ro";
442 else if (arg_root_rw >= 0 ||
443 (!mount_test_option(arg_root_options, "ro") &&
444 !mount_test_option(arg_root_options, "rw")))
445 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
447 opts = arg_root_options;
449 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
450 return add_mount(what,
458 SPECIAL_INITRD_ROOT_FS_TARGET,
462 static int parse_proc_cmdline_item(const char *key, const char *value) {
465 /* root= and roofstype= may occur more than once, the last
466 * instance should take precedence. In the case of multiple
467 * rootflags= the arguments should be concatenated */
469 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
471 r = parse_boolean(value);
473 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
475 arg_fstab_enabled = r;
477 } else if (streq(key, "root") && value) {
480 arg_root_what = strdup(value);
484 } else if (streq(key, "rootfstype") && value) {
486 free(arg_root_fstype);
487 arg_root_fstype = strdup(value);
488 if (!arg_root_fstype)
491 } else if (streq(key, "rootflags") && value) {
494 o = arg_root_options ?
495 strjoin(arg_root_options, ",", value, NULL) :
500 free(arg_root_options);
501 arg_root_options = o;
503 } else if (streq(key, "rw") && !value)
505 else if (streq(key, "ro") && !value)
511 int main(int argc, char *argv[]) {
514 if (argc > 1 && argc != 4) {
515 log_error("This program takes three or no arguments.");
522 log_set_target(LOG_TARGET_SAFE);
523 log_parse_environment();
528 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
531 /* Always honour root= in the kernel command line if we are in an initrd */
533 r = add_root_mount();
535 /* Honour /etc/fstab only when that's enabled */
536 if (arg_fstab_enabled) {
539 log_debug("Parsing /etc/fstab");
541 /* Parse the local /etc/fstab, possibly from the initrd */
542 k = parse_fstab(false);
546 /* If running in the initrd also parse the /etc/fstab from the host */
548 log_debug("Parsing /sysroot/etc/fstab");
550 k = parse_fstab(true);
558 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;