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 (access("/proc/swaps", F_OK) < 0) {
91 log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
95 if (detect_container(NULL) > 0) {
96 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
100 r = mount_find_pri(me, &pri);
102 log_error("Failed to parse priority");
106 name = unit_name_from_path(what, ".swap");
110 unit = strjoin(arg_dest, "/", name, NULL);
114 f = fopen(unit, "wxe");
117 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
119 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
124 "# Automatically generated by systemd-fstab-generator\n\n"
126 "SourcePath=/etc/fstab\n"
127 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
132 /* Note that we currently pass the priority field twice, once
133 * in Priority=, and once in Options= */
135 fprintf(f, "Priority=%i\n", pri);
137 if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults"))
138 fprintf(f, "Options=%s\n", me->mnt_opts);
140 r = fflush_and_check(f);
142 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
144 /* use what as where, to have a nicer error message */
145 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
150 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
151 nofail ? ".wants/" : ".requires/", name, NULL);
155 mkdir_parents_label(lnk, 0755);
156 if (symlink(unit, lnk) < 0)
157 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
163 static bool mount_is_network(struct mntent *me) {
167 hasmntopt(me, "_netdev") ||
168 fstype_is_network(me->mnt_type);
171 static bool mount_in_initrd(struct mntent *me) {
175 hasmntopt(me, "x-initrd.mount") ||
176 streq(me->mnt_dir, "/usr");
179 static int add_mount(
189 const char *source) {
192 *name = NULL, *unit = NULL, *lnk = NULL,
193 *automount_name = NULL, *automount_unit = NULL,
195 _cleanup_fclose_ FILE *f = NULL;
203 if (streq_ptr(fstype, "autofs"))
206 if (!is_path(where)) {
207 log_warning("Mount point %s is not a valid path, ignoring.", where);
211 if (mount_point_is_api(where) ||
212 mount_point_ignore(where))
215 if (path_equal(where, "/")) {
216 /* The root disk is not an option */
222 name = unit_name_from_path(where, ".mount");
226 unit = strjoin(arg_dest, "/", name, NULL);
230 f = fopen(unit, "wxe");
233 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
235 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
240 "# Automatically generated by systemd-fstab-generator\n\n"
243 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
246 if (post && !noauto && !nofail && !automount)
247 fprintf(f, "Before=%s\n", post);
250 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
263 if (!isempty(fstype) && !streq(fstype, "auto"))
264 fprintf(f, "Type=%s\n", fstype);
266 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
270 if (!isempty(filtered) && !streq(filtered, "defaults"))
271 fprintf(f, "Options=%s\n", filtered);
275 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
277 if (!noauto && post) {
278 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
282 mkdir_parents_label(lnk, 0755);
283 if (symlink(unit, lnk) < 0)
284 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
288 automount_name = unit_name_from_path(where, ".automount");
292 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
297 f = fopen(automount_unit, "wxe");
299 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
302 "# Automatically generated by systemd-fstab-generator\n\n"
305 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
320 return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
323 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
327 mkdir_parents_label(lnk, 0755);
328 if (symlink(automount_unit, lnk) < 0)
329 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
335 static int parse_fstab(bool initrd) {
336 _cleanup_endmntent_ FILE *f = NULL;
337 const char *fstab_path;
341 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
342 f = setmntent(fstab_path, "re");
347 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
351 while ((me = getmntent(f))) {
352 _cleanup_free_ char *where = NULL, *what = NULL;
356 if (initrd && !mount_in_initrd(me))
359 what = fstab_node_to_udev_node(me->mnt_fsname);
363 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
364 log_info("Running in a container, ignoring fstab device entry for %s.", what);
368 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
373 path_kill_slashes(where);
375 noauto = !!hasmntopt(me, "noauto");
376 nofail = !!hasmntopt(me, "nofail");
377 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
378 what, where, me->mnt_type,
379 yes_no(noauto), yes_no(nofail));
381 if (streq(me->mnt_type, "swap"))
382 k = add_swap(what, me, noauto, nofail);
388 hasmntopt(me, "comment=systemd.automount") ||
389 hasmntopt(me, "x-systemd.automount");
392 post = SPECIAL_INITRD_FS_TARGET;
393 else if (mount_in_initrd(me))
394 post = SPECIAL_INITRD_ROOT_FS_TARGET;
395 else if (mount_is_network(me))
396 post = SPECIAL_REMOTE_FS_TARGET;
398 post = SPECIAL_LOCAL_FS_TARGET;
419 static int add_root_mount(void) {
420 _cleanup_free_ char *what = NULL;
423 if (isempty(arg_root_what)) {
424 log_debug("Could not find a root= entry on the kernel command line.");
428 what = fstab_node_to_udev_node(arg_root_what);
429 if (!path_is_absolute(what)) {
430 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
434 if (!arg_root_options)
435 opts = arg_root_rw > 0 ? "rw" : "ro";
436 else if (arg_root_rw >= 0 ||
437 (!mount_test_option(arg_root_options, "ro") &&
438 !mount_test_option(arg_root_options, "rw")))
439 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
441 opts = arg_root_options;
443 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
444 return add_mount(what,
452 SPECIAL_INITRD_ROOT_FS_TARGET,
456 static int add_usr_mount(void) {
457 _cleanup_free_ char *what = NULL;
460 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
463 if (arg_root_what && !arg_usr_what) {
464 arg_usr_what = strdup(arg_root_what);
470 if (arg_root_fstype && !arg_usr_fstype) {
471 arg_usr_fstype = strdup(arg_root_fstype);
477 if (arg_root_options && !arg_usr_options) {
478 arg_usr_options = strdup(arg_root_options);
480 if (!arg_usr_options)
487 what = fstab_node_to_udev_node(arg_usr_what);
488 if (!path_is_absolute(what)) {
489 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
493 if (!arg_usr_options)
494 opts = arg_root_rw > 0 ? "rw" : "ro";
495 else if (!mount_test_option(arg_usr_options, "ro") &&
496 !mount_test_option(arg_usr_options, "rw"))
497 opts = strappenda(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
499 opts = arg_usr_options;
501 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
502 return add_mount(what,
510 SPECIAL_INITRD_ROOT_FS_TARGET,
514 static int parse_proc_cmdline_item(const char *key, const char *value) {
517 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
518 * instance should take precedence. In the case of multiple rootflags=
519 * or usrflags= the arguments should be concatenated */
521 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
523 r = parse_boolean(value);
525 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
527 arg_fstab_enabled = r;
529 } else if (streq(key, "root") && value) {
531 if (free_and_strdup(&arg_root_what, value) < 0)
534 } else if (streq(key, "rootfstype") && value) {
536 if (free_and_strdup(&arg_root_fstype, value) < 0)
539 } else if (streq(key, "rootflags") && value) {
542 o = arg_root_options ?
543 strjoin(arg_root_options, ",", value, NULL) :
548 free(arg_root_options);
549 arg_root_options = o;
551 } else if (streq(key, "mount.usr") && value) {
553 if (free_and_strdup(&arg_usr_what, value) < 0)
556 } else if (streq(key, "mount.usrfstype") && value) {
558 if (free_and_strdup(&arg_usr_fstype, value) < 0)
561 } else if (streq(key, "mount.usrflags") && value) {
564 o = arg_usr_options ?
565 strjoin(arg_usr_options, ",", value, NULL) :
570 free(arg_usr_options);
573 } else if (streq(key, "rw") && !value)
575 else if (streq(key, "ro") && !value)
581 int main(int argc, char *argv[]) {
584 if (argc > 1 && argc != 4) {
585 log_error("This program takes three or no arguments.");
592 log_set_target(LOG_TARGET_SAFE);
593 log_parse_environment();
598 r = parse_proc_cmdline(parse_proc_cmdline_item);
600 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
602 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
604 r = add_root_mount();
609 /* Honour /etc/fstab only when that's enabled */
610 if (arg_fstab_enabled) {
613 log_debug("Parsing /etc/fstab");
615 /* Parse the local /etc/fstab, possibly from the initrd */
616 k = parse_fstab(false);
620 /* If running in the initrd also parse the /etc/fstab from the host */
622 log_debug("Parsing /sysroot/etc/fstab");
624 k = parse_fstab(true);
631 free(arg_root_fstype);
632 free(arg_root_options);
635 free(arg_usr_fstype);
636 free(arg_usr_options);
638 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;