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 log_error_errno(r, "Failed to write unit file %s: %m", unit);
141 /* use what as where, to have a nicer error message */
142 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
147 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
148 nofail ? ".wants/" : ".requires/", 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;
365 if (initrd && !mount_in_initrd(me))
368 what = fstab_node_to_udev_node(me->mnt_fsname);
372 if (detect_container(NULL) > 0 && is_device_path(what)) {
373 log_info("Running in a container, ignoring fstab device entry for %s.", what);
377 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
382 path_kill_slashes(where);
384 noauto = !!hasmntopt(me, "noauto");
385 nofail = !!hasmntopt(me, "nofail");
386 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
387 what, where, me->mnt_type,
388 yes_no(noauto), yes_no(nofail));
390 if (streq(me->mnt_type, "swap"))
391 k = add_swap(what, me, noauto, nofail);
397 hasmntopt(me, "comment=systemd.automount") ||
398 hasmntopt(me, "x-systemd.automount");
401 post = SPECIAL_INITRD_FS_TARGET;
402 else if (mount_in_initrd(me))
403 post = SPECIAL_INITRD_ROOT_FS_TARGET;
404 else if (mount_is_network(me))
405 post = SPECIAL_REMOTE_FS_TARGET;
407 post = SPECIAL_LOCAL_FS_TARGET;
428 static int add_root_mount(void) {
429 _cleanup_free_ char *what = NULL;
432 if (isempty(arg_root_what)) {
433 log_debug("Could not find a root= entry on the kernel command line.");
437 what = fstab_node_to_udev_node(arg_root_what);
438 if (!path_is_absolute(what)) {
439 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
443 if (!arg_root_options)
444 opts = arg_root_rw > 0 ? "rw" : "ro";
445 else if (arg_root_rw >= 0 ||
446 (!mount_test_option(arg_root_options, "ro") &&
447 !mount_test_option(arg_root_options, "rw")))
448 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
450 opts = arg_root_options;
452 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
453 return add_mount(what,
461 SPECIAL_INITRD_ROOT_FS_TARGET,
465 static int add_usr_mount(void) {
466 _cleanup_free_ char *what = NULL;
469 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
472 if (arg_root_what && !arg_usr_what) {
473 arg_usr_what = strdup(arg_root_what);
479 if (arg_root_fstype && !arg_usr_fstype) {
480 arg_usr_fstype = strdup(arg_root_fstype);
486 if (arg_root_options && !arg_usr_options) {
487 arg_usr_options = strdup(arg_root_options);
489 if (!arg_usr_options)
493 if (!arg_usr_what || !arg_usr_options)
496 what = fstab_node_to_udev_node(arg_usr_what);
497 if (!path_is_absolute(what)) {
498 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
502 opts = arg_usr_options;
504 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
505 return add_mount(what,
513 SPECIAL_INITRD_ROOT_FS_TARGET,
517 static int parse_proc_cmdline_item(const char *key, const char *value) {
520 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
521 * instance should take precedence. In the case of multiple rootflags=
522 * or usrflags= the arguments should be concatenated */
524 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
526 r = parse_boolean(value);
528 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
530 arg_fstab_enabled = r;
532 } else if (streq(key, "root") && value) {
534 if (free_and_strdup(&arg_root_what, value) < 0)
537 } else if (streq(key, "rootfstype") && value) {
539 if (free_and_strdup(&arg_root_fstype, value) < 0)
542 } else if (streq(key, "rootflags") && value) {
545 o = arg_root_options ?
546 strjoin(arg_root_options, ",", value, NULL) :
551 free(arg_root_options);
552 arg_root_options = o;
554 } else if (streq(key, "mount.usr") && value) {
556 if (free_and_strdup(&arg_usr_what, value) < 0)
559 } else if (streq(key, "mount.usrfstype") && value) {
561 if (free_and_strdup(&arg_usr_fstype, value) < 0)
564 } else if (streq(key, "mount.usrflags") && value) {
567 o = arg_usr_options ?
568 strjoin(arg_usr_options, ",", value, NULL) :
573 free(arg_usr_options);
576 } else if (streq(key, "rw") && !value)
578 else if (streq(key, "ro") && !value)
584 int main(int argc, char *argv[]) {
587 if (argc > 1 && argc != 4) {
588 log_error("This program takes three or no arguments.");
595 log_set_target(LOG_TARGET_SAFE);
596 log_parse_environment();
601 r = parse_proc_cmdline(parse_proc_cmdline_item);
603 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
605 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
607 r = add_root_mount();
612 /* Honour /etc/fstab only when that's enabled */
613 if (arg_fstab_enabled) {
616 log_debug("Parsing /etc/fstab");
618 /* Parse the local /etc/fstab, possibly from the initrd */
619 k = parse_fstab(false);
623 /* If running in the initrd also parse the /etc/fstab from the host */
625 log_debug("Parsing /sysroot/etc/fstab");
627 k = parse_fstab(true);
635 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;