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))
77 static int add_swap(const char *what, struct mntent *me) {
78 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
79 _cleanup_fclose_ FILE *f = NULL;
87 if (detect_container(NULL) > 0) {
88 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
92 r = mount_find_pri(me, &pri);
94 log_error("Failed to parse priority");
98 noauto = !!hasmntopt(me, "noauto");
100 name = unit_name_from_path(what, ".swap");
104 unit = strjoin(arg_dest, "/", name, NULL);
108 f = fopen(unit, "wxe");
111 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
113 log_error("Failed to create unit file %s: %m", unit);
118 "# Automatically generated by systemd-fstab-generator\n\n"
120 "SourcePath=/etc/fstab\n"
121 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
126 /* Note that we currently pass the priority field twice, once
127 * in Priority=, and once in Options= */
129 fprintf(f, "Priority=%i\n", pri);
131 if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults"))
132 fprintf(f, "Options=%s\n", me->mnt_opts);
134 r = fflush_and_check(f);
136 log_error("Failed to write unit file %s: %s", unit, strerror(-r));
140 /* use what as where, to have a nicer error message */
141 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
146 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", 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;
362 if (initrd && !mount_in_initrd(me))
365 what = fstab_node_to_udev_node(me->mnt_fsname);
369 if (detect_container(NULL) > 0 && is_device_path(what)) {
370 log_info("Running in a container, ignoring fstab device entry for %s.", what);
374 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
379 path_kill_slashes(where);
381 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
383 if (streq(me->mnt_type, "swap"))
384 k = add_swap(what, me);
386 bool noauto, nofail, automount;
389 noauto = !!hasmntopt(me, "noauto");
390 nofail = !!hasmntopt(me, "nofail");
392 hasmntopt(me, "comment=systemd.automount") ||
393 hasmntopt(me, "x-systemd.automount");
396 post = SPECIAL_INITRD_FS_TARGET;
397 else if (mount_in_initrd(me))
398 post = SPECIAL_INITRD_ROOT_FS_TARGET;
399 else if (mount_is_network(me))
400 post = SPECIAL_REMOTE_FS_TARGET;
402 post = SPECIAL_LOCAL_FS_TARGET;
423 static int add_root_mount(void) {
424 _cleanup_free_ char *what = NULL;
427 if (isempty(arg_root_what)) {
428 log_debug("Could not find a root= entry on the kernel commandline.");
432 what = fstab_node_to_udev_node(arg_root_what);
433 if (!path_is_absolute(what)) {
434 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
438 if (!arg_root_options)
439 opts = arg_root_rw > 0 ? "rw" : "ro";
440 else if (arg_root_rw >= 0 ||
441 (!mount_test_option(arg_root_options, "ro") &&
442 !mount_test_option(arg_root_options, "rw")))
443 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
445 opts = arg_root_options;
447 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
448 return add_mount(what,
456 SPECIAL_INITRD_ROOT_FS_TARGET,
460 static int add_usr_mount(void) {
461 _cleanup_free_ char *what = NULL;
464 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
467 if (arg_root_what && !arg_usr_what) {
468 arg_usr_what = strdup(arg_root_what);
474 if (arg_root_fstype && !arg_usr_fstype) {
475 arg_usr_fstype = strdup(arg_root_fstype);
481 if (arg_root_options && !arg_usr_options) {
482 arg_usr_options = strdup(arg_root_options);
484 if (!arg_usr_options)
488 if (!arg_usr_what || !arg_usr_options)
491 what = fstab_node_to_udev_node(arg_usr_what);
492 if (!path_is_absolute(what)) {
493 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
497 opts = arg_usr_options;
499 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
500 return add_mount(what,
508 SPECIAL_INITRD_ROOT_FS_TARGET,
512 static int parse_proc_cmdline_item(const char *key, const char *value) {
515 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
516 * instance should take precedence. In the case of multiple rootflags=
517 * or usrflags= the arguments should be concatenated */
519 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
521 r = parse_boolean(value);
523 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
525 arg_fstab_enabled = r;
527 } else if (streq(key, "root") && value) {
529 if (free_and_strdup(&arg_root_what, value) < 0)
532 } else if (streq(key, "rootfstype") && value) {
534 if (free_and_strdup(&arg_root_fstype, value) < 0)
537 } else if (streq(key, "rootflags") && value) {
540 o = arg_root_options ?
541 strjoin(arg_root_options, ",", value, NULL) :
546 free(arg_root_options);
547 arg_root_options = o;
549 } else if (streq(key, "mount.usr") && value) {
551 if (free_and_strdup(&arg_usr_what, value) < 0)
554 } else if (streq(key, "mount.usrfstype") && value) {
556 if (free_and_strdup(&arg_usr_fstype, value) < 0)
559 } else if (streq(key, "mount.usrflags") && value) {
562 o = arg_usr_options ?
563 strjoin(arg_usr_options, ",", value, NULL) :
568 free(arg_usr_options);
571 } else if (streq(key, "rw") && !value)
573 else if (streq(key, "ro") && !value)
579 int main(int argc, char *argv[]) {
582 if (argc > 1 && argc != 4) {
583 log_error("This program takes three or no arguments.");
590 log_set_target(LOG_TARGET_SAFE);
591 log_parse_environment();
596 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
599 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
601 r = add_root_mount();
606 /* Honour /etc/fstab only when that's enabled */
607 if (arg_fstab_enabled) {
610 log_debug("Parsing /etc/fstab");
612 /* Parse the local /etc/fstab, possibly from the initrd */
613 k = parse_fstab(false);
617 /* If running in the initrd also parse the /etc/fstab from the host */
619 log_debug("Parsing /sysroot/etc/fstab");
621 k = parse_fstab(true);
629 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;