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_errno(errno, "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 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
158 static bool mount_is_network(struct mntent *me) {
162 hasmntopt(me, "_netdev") ||
163 fstype_is_network(me->mnt_type);
166 static bool mount_in_initrd(struct mntent *me) {
170 hasmntopt(me, "x-initrd.mount") ||
171 streq(me->mnt_dir, "/usr");
174 static int add_mount(
184 const char *source) {
187 *name = NULL, *unit = NULL, *lnk = NULL,
188 *automount_name = NULL, *automount_unit = NULL,
190 _cleanup_fclose_ FILE *f = NULL;
198 if (streq_ptr(fstype, "autofs"))
201 if (!is_path(where)) {
202 log_warning("Mount point %s is not a valid path, ignoring.", where);
206 if (mount_point_is_api(where) ||
207 mount_point_ignore(where))
210 if (path_equal(where, "/")) {
211 /* The root disk is not an option */
217 name = unit_name_from_path(where, ".mount");
221 unit = strjoin(arg_dest, "/", name, NULL);
225 f = fopen(unit, "wxe");
228 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
230 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
235 "# Automatically generated by systemd-fstab-generator\n\n"
238 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
241 if (post && !noauto && !nofail && !automount)
242 fprintf(f, "Before=%s\n", post);
245 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
258 if (!isempty(fstype) && !streq(fstype, "auto"))
259 fprintf(f, "Type=%s\n", fstype);
261 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
265 if (!isempty(filtered) && !streq(filtered, "defaults"))
266 fprintf(f, "Options=%s\n", filtered);
270 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
272 if (!noauto && post) {
273 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
277 mkdir_parents_label(lnk, 0755);
278 if (symlink(unit, lnk) < 0)
279 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
283 automount_name = unit_name_from_path(where, ".automount");
287 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
292 f = fopen(automount_unit, "wxe");
294 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
297 "# Automatically generated by systemd-fstab-generator\n\n"
300 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
315 return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
318 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
322 mkdir_parents_label(lnk, 0755);
323 if (symlink(automount_unit, lnk) < 0)
324 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
330 static int parse_fstab(bool initrd) {
331 _cleanup_endmntent_ FILE *f = NULL;
332 const char *fstab_path;
336 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
337 f = setmntent(fstab_path, "re");
342 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
346 while ((me = getmntent(f))) {
347 _cleanup_free_ char *where = NULL, *what = NULL;
351 if (initrd && !mount_in_initrd(me))
354 what = fstab_node_to_udev_node(me->mnt_fsname);
358 if (detect_container(NULL) > 0 && is_device_path(what)) {
359 log_info("Running in a container, ignoring fstab device entry for %s.", what);
363 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
368 path_kill_slashes(where);
370 noauto = !!hasmntopt(me, "noauto");
371 nofail = !!hasmntopt(me, "nofail");
372 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
373 what, where, me->mnt_type,
374 yes_no(noauto), yes_no(nofail));
376 if (streq(me->mnt_type, "swap"))
377 k = add_swap(what, me, noauto, nofail);
383 hasmntopt(me, "comment=systemd.automount") ||
384 hasmntopt(me, "x-systemd.automount");
387 post = SPECIAL_INITRD_FS_TARGET;
388 else if (mount_in_initrd(me))
389 post = SPECIAL_INITRD_ROOT_FS_TARGET;
390 else if (mount_is_network(me))
391 post = SPECIAL_REMOTE_FS_TARGET;
393 post = SPECIAL_LOCAL_FS_TARGET;
414 static int add_root_mount(void) {
415 _cleanup_free_ char *what = NULL;
418 if (isempty(arg_root_what)) {
419 log_debug("Could not find a root= entry on the kernel command line.");
423 what = fstab_node_to_udev_node(arg_root_what);
424 if (!path_is_absolute(what)) {
425 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
429 if (!arg_root_options)
430 opts = arg_root_rw > 0 ? "rw" : "ro";
431 else if (arg_root_rw >= 0 ||
432 (!mount_test_option(arg_root_options, "ro") &&
433 !mount_test_option(arg_root_options, "rw")))
434 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
436 opts = arg_root_options;
438 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
439 return add_mount(what,
447 SPECIAL_INITRD_ROOT_FS_TARGET,
451 static int add_usr_mount(void) {
452 _cleanup_free_ char *what = NULL;
455 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
458 if (arg_root_what && !arg_usr_what) {
459 arg_usr_what = strdup(arg_root_what);
465 if (arg_root_fstype && !arg_usr_fstype) {
466 arg_usr_fstype = strdup(arg_root_fstype);
472 if (arg_root_options && !arg_usr_options) {
473 arg_usr_options = strdup(arg_root_options);
475 if (!arg_usr_options)
479 if (!arg_usr_what || !arg_usr_options)
482 what = fstab_node_to_udev_node(arg_usr_what);
483 if (!path_is_absolute(what)) {
484 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
488 opts = arg_usr_options;
490 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
491 return add_mount(what,
499 SPECIAL_INITRD_ROOT_FS_TARGET,
503 static int parse_proc_cmdline_item(const char *key, const char *value) {
506 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
507 * instance should take precedence. In the case of multiple rootflags=
508 * or usrflags= the arguments should be concatenated */
510 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
512 r = parse_boolean(value);
514 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
516 arg_fstab_enabled = r;
518 } else if (streq(key, "root") && value) {
520 if (free_and_strdup(&arg_root_what, value) < 0)
523 } else if (streq(key, "rootfstype") && value) {
525 if (free_and_strdup(&arg_root_fstype, value) < 0)
528 } else if (streq(key, "rootflags") && value) {
531 o = arg_root_options ?
532 strjoin(arg_root_options, ",", value, NULL) :
537 free(arg_root_options);
538 arg_root_options = o;
540 } else if (streq(key, "mount.usr") && value) {
542 if (free_and_strdup(&arg_usr_what, value) < 0)
545 } else if (streq(key, "mount.usrfstype") && value) {
547 if (free_and_strdup(&arg_usr_fstype, value) < 0)
550 } else if (streq(key, "mount.usrflags") && value) {
553 o = arg_usr_options ?
554 strjoin(arg_usr_options, ",", value, NULL) :
559 free(arg_usr_options);
562 } else if (streq(key, "rw") && !value)
564 else if (streq(key, "ro") && !value)
570 int main(int argc, char *argv[]) {
573 if (argc > 1 && argc != 4) {
574 log_error("This program takes three or no arguments.");
581 log_set_target(LOG_TARGET_SAFE);
582 log_parse_environment();
587 r = parse_proc_cmdline(parse_proc_cmdline_item);
589 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
591 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
593 r = add_root_mount();
598 /* Honour /etc/fstab only when that's enabled */
599 if (arg_fstab_enabled) {
602 log_debug("Parsing /etc/fstab");
604 /* Parse the local /etc/fstab, possibly from the initrd */
605 k = parse_fstab(false);
609 /* If running in the initrd also parse the /etc/fstab from the host */
611 log_debug("Parsing /sysroot/etc/fstab");
613 k = parse_fstab(true);
621 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;