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;
82 if (detect_container(NULL) > 0) {
83 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
87 r = mount_find_pri(me, &pri);
89 log_error("Failed to parse priority");
93 noauto = !!hasmntopt(me, "noauto");
95 name = unit_name_from_path(what, ".swap");
99 unit = strjoin(arg_dest, "/", name, NULL);
103 f = fopen(unit, "wxe");
106 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
108 log_error("Failed to create unit file %s: %m", unit);
113 "# Automatically generated by systemd-fstab-generator\n\n"
115 "SourcePath=/etc/fstab\n"
116 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
128 log_error("Failed to write unit file %s: %m", unit);
133 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
137 mkdir_parents_label(lnk, 0755);
138 if (symlink(unit, lnk) < 0) {
139 log_error("Failed to create symlink %s: %m", lnk);
147 static bool mount_is_network(struct mntent *me) {
151 hasmntopt(me, "_netdev") ||
152 fstype_is_network(me->mnt_type);
155 static bool mount_in_initrd(struct mntent *me) {
159 hasmntopt(me, "x-initrd.mount") ||
160 streq(me->mnt_dir, "/usr");
163 static int add_mount(
173 const char *source) {
176 *name = NULL, *unit = NULL, *lnk = NULL,
177 *automount_name = NULL, *automount_unit = NULL,
179 _cleanup_fclose_ FILE *f = NULL;
187 if (streq_ptr(fstype, "autofs"))
190 if (!is_path(where)) {
191 log_warning("Mount point %s is not a valid path, ignoring.", where);
195 if (mount_point_is_api(where) ||
196 mount_point_ignore(where))
199 if (path_equal(where, "/")) {
200 /* The root disk is not an option */
206 name = unit_name_from_path(where, ".mount");
210 unit = strjoin(arg_dest, "/", name, NULL);
214 f = fopen(unit, "wxe");
217 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
219 log_error("Failed to create unit file %s: %m", unit);
224 "# Automatically generated by systemd-fstab-generator\n\n"
227 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
230 if (post && !noauto && !nofail && !automount)
231 fprintf(f, "Before=%s\n", post);
234 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
247 if (!isempty(fstype) && !streq(fstype, "auto"))
248 fprintf(f, "Type=%s\n", fstype);
250 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
254 if (!isempty(filtered) && !streq(filtered, "defaults"))
255 fprintf(f, "Options=%s\n", filtered);
259 log_error("Failed to write unit file %s: %m", unit);
263 if (!noauto && post) {
264 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
268 mkdir_parents_label(lnk, 0755);
269 if (symlink(unit, lnk) < 0) {
270 log_error("Failed to create symlink %s: %m", lnk);
276 automount_name = unit_name_from_path(where, ".automount");
280 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
285 f = fopen(automount_unit, "wxe");
287 log_error("Failed to create unit file %s: %m", automount_unit);
292 "# Automatically generated by systemd-fstab-generator\n\n"
295 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
310 log_error("Failed to write unit file %s: %m", automount_unit);
315 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
319 mkdir_parents_label(lnk, 0755);
320 if (symlink(automount_unit, lnk) < 0) {
321 log_error("Failed to create symlink %s: %m", lnk);
329 static int parse_fstab(bool initrd) {
330 _cleanup_endmntent_ FILE *f = NULL;
331 const char *fstab_path;
335 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
336 f = setmntent(fstab_path, "re");
341 log_error("Failed to open %s: %m", fstab_path);
345 while ((me = getmntent(f))) {
346 _cleanup_free_ char *where = NULL, *what = NULL;
349 if (initrd && !mount_in_initrd(me))
352 what = fstab_node_to_udev_node(me->mnt_fsname);
356 if (detect_container(NULL) > 0 && is_device_path(what)) {
357 log_info("Running in a container, ignoring fstab device entry for %s.", what);
361 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
366 path_kill_slashes(where);
368 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
370 if (streq(me->mnt_type, "swap"))
371 k = add_swap(what, me);
373 bool noauto, nofail, automount;
376 noauto = !!hasmntopt(me, "noauto");
377 nofail = !!hasmntopt(me, "nofail");
379 hasmntopt(me, "comment=systemd.automount") ||
380 hasmntopt(me, "x-systemd.automount");
383 post = SPECIAL_INITRD_FS_TARGET;
384 else if (mount_in_initrd(me))
385 post = SPECIAL_INITRD_ROOT_FS_TARGET;
386 else if (mount_is_network(me))
387 post = SPECIAL_REMOTE_FS_TARGET;
389 post = SPECIAL_LOCAL_FS_TARGET;
410 static int add_root_mount(void) {
411 _cleanup_free_ char *what = NULL;
414 if (isempty(arg_root_what)) {
415 log_debug("Could not find a root= entry on the kernel commandline.");
419 what = fstab_node_to_udev_node(arg_root_what);
420 if (!path_is_absolute(what)) {
421 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
425 if (!arg_root_options)
426 opts = arg_root_rw > 0 ? "rw" : "ro";
427 else if (arg_root_rw >= 0 ||
428 (!mount_test_option(arg_root_options, "ro") &&
429 !mount_test_option(arg_root_options, "rw")))
430 opts = strappenda3(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
432 opts = arg_root_options;
434 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
435 return add_mount(what,
443 SPECIAL_INITRD_ROOT_FS_TARGET,
447 static int parse_proc_cmdline_item(const char *key, const char *value) {
450 /* root= and roofstype= may occur more than once, the last
451 * instance should take precedence. In the case of multiple
452 * rootflags= the arguments should be concatenated */
454 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
456 r = parse_boolean(value);
458 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
460 arg_fstab_enabled = r;
462 } else if (streq(key, "root") && value) {
465 arg_root_what = strdup(value);
469 } else if (streq(key, "rootfstype") && value) {
471 free(arg_root_fstype);
472 arg_root_fstype = strdup(value);
473 if (!arg_root_fstype)
476 } else if (streq(key, "rootflags") && value) {
479 o = arg_root_options ?
480 strjoin(arg_root_options, ",", value, NULL) :
485 free(arg_root_options);
486 arg_root_options = o;
488 } else if (streq(key, "rw") && !value)
490 else if (streq(key, "ro") && !value)
496 int main(int argc, char *argv[]) {
499 if (argc > 1 && argc != 4) {
500 log_error("This program takes three or no arguments.");
507 log_set_target(LOG_TARGET_SAFE);
508 log_parse_environment();
513 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
516 /* Always honour root= in the kernel command line if we are in an initrd */
518 r = add_root_mount();
520 /* Honour /etc/fstab only when that's enabled */
521 if (arg_fstab_enabled) {
524 log_debug("Parsing /etc/fstab");
526 /* Parse the local /etc/fstab, possibly from the initrd */
527 k = parse_fstab(false);
531 /* If running in the initrd also parse the /etc/fstab from the host */
533 log_debug("Parsing /sysroot/etc/fstab");
535 k = parse_fstab(true);
541 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;