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;
47 static int mount_find_pri(struct mntent *me, int *ret) {
54 pri = hasmntopt(me, "pri");
61 r = strtoul(pri, &end, 10);
65 if (end == pri || (*end != ',' && *end != 0))
72 static int add_swap(const char *what, struct mntent *me) {
73 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
74 _cleanup_fclose_ FILE *f = NULL;
81 if (detect_container(NULL) > 0) {
82 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
86 r = mount_find_pri(me, &pri);
88 log_error("Failed to parse priority");
92 noauto = !!hasmntopt(me, "noauto");
94 name = unit_name_from_path(what, ".swap");
98 unit = strjoin(arg_dest, "/", name, NULL);
102 f = fopen(unit, "wxe");
105 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
107 log_error("Failed to create unit file %s: %m", unit);
112 "# Automatically generated by systemd-fstab-generator\n\n"
114 "SourcePath=/etc/fstab\n"
115 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
127 log_error("Failed to write unit file %s: %m", unit);
132 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
136 mkdir_parents_label(lnk, 0755);
137 if (symlink(unit, lnk) < 0) {
138 log_error("Failed to create symlink %s: %m", lnk);
146 static bool mount_is_network(struct mntent *me) {
150 hasmntopt(me, "_netdev") ||
151 fstype_is_network(me->mnt_type);
154 static bool mount_in_initrd(struct mntent *me) {
158 hasmntopt(me, "x-initrd.mount") ||
159 streq(me->mnt_dir, "/usr");
162 static int add_mount(
172 const char *source) {
175 *name = NULL, *unit = NULL, *lnk = NULL,
176 *automount_name = NULL, *automount_unit = NULL;
177 _cleanup_fclose_ FILE *f = NULL;
185 if (streq_ptr(fstype, "autofs"))
188 if (!is_path(where)) {
189 log_warning("Mount point %s is not a valid path, ignoring.", where);
193 if (mount_point_is_api(where) ||
194 mount_point_ignore(where))
197 if (path_equal(where, "/")) {
198 /* The root disk is not an option */
204 name = unit_name_from_path(where, ".mount");
208 unit = strjoin(arg_dest, "/", name, NULL);
212 f = fopen(unit, "wxe");
215 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
217 log_error("Failed to create unit file %s: %m", unit);
222 "# Automatically generated by systemd-fstab-generator\n\n"
225 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
228 if (post && !noauto && !nofail && !automount)
229 fprintf(f, "Before=%s\n", post);
232 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
245 if (!isempty(fstype) && !streq(fstype, "auto"))
246 fprintf(f, "Type=%s\n", fstype);
248 if (!isempty(opts) && !streq(opts, "defaults"))
249 fprintf(f, "Options=%s\n", opts);
253 log_error("Failed to write unit file %s: %m", unit);
257 if (!noauto && post) {
258 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
262 mkdir_parents_label(lnk, 0755);
263 if (symlink(unit, lnk) < 0) {
264 log_error("Failed to create symlink %s: %m", lnk);
270 automount_name = unit_name_from_path(where, ".automount");
274 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
279 f = fopen(automount_unit, "wxe");
281 log_error("Failed to create unit file %s: %m", automount_unit);
286 "# Automatically generated by systemd-fstab-generator\n\n"
289 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
304 log_error("Failed to write unit file %s: %m", automount_unit);
309 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
313 mkdir_parents_label(lnk, 0755);
314 if (symlink(automount_unit, lnk) < 0) {
315 log_error("Failed to create symlink %s: %m", lnk);
323 static int parse_fstab(bool initrd) {
324 _cleanup_endmntent_ FILE *f = NULL;
325 const char *fstab_path;
329 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
330 f = setmntent(fstab_path, "re");
335 log_error("Failed to open %s: %m", fstab_path);
339 while ((me = getmntent(f))) {
340 _cleanup_free_ char *where = NULL, *what = NULL;
343 if (initrd && !mount_in_initrd(me))
346 what = fstab_node_to_udev_node(me->mnt_fsname);
350 if (detect_container(NULL) > 0 && is_device_path(what)) {
351 log_info("Running in a container, ignoring fstab device entry for %s.", what);
355 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
360 path_kill_slashes(where);
362 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
364 if (streq(me->mnt_type, "swap"))
365 k = add_swap(what, me);
367 bool noauto, nofail, automount;
370 noauto = !!hasmntopt(me, "noauto");
371 nofail = !!hasmntopt(me, "nofail");
373 hasmntopt(me, "comment=systemd.automount") ||
374 hasmntopt(me, "x-systemd.automount");
377 post = SPECIAL_INITRD_FS_TARGET;
378 else if (mount_in_initrd(me))
379 post = SPECIAL_INITRD_ROOT_FS_TARGET;
380 else if (mount_is_network(me))
381 post = SPECIAL_REMOTE_FS_TARGET;
383 post = SPECIAL_LOCAL_FS_TARGET;
404 static int add_root_mount(void) {
405 _cleanup_free_ char *o = NULL, *what = NULL;
407 if (isempty(arg_root_what)) {
408 log_debug("Could not find a root= entry on the kernel commandline.");
412 what = fstab_node_to_udev_node(arg_root_what);
413 if (!path_is_absolute(what)) {
414 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
418 if (!arg_root_options)
419 o = strdup(arg_root_rw > 0 ? "rw" : "ro");
421 if (arg_root_rw >= 0 ||
422 (!mount_test_option(arg_root_options, "ro") &&
423 !mount_test_option(arg_root_options, "rw")))
424 o = strjoin(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro", NULL);
426 o = strdup(arg_root_options);
431 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
432 return add_mount(what,
440 SPECIAL_INITRD_ROOT_FS_TARGET,
444 static int parse_proc_cmdline_item(const char *key, const char *value) {
447 /* root= and roofstype= may occur more than once, the last
448 * instance should take precedence. In the case of multiple
449 * rootflags= the arguments should be concatenated */
451 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
453 r = parse_boolean(value);
455 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
457 arg_fstab_enabled = r;
459 } else if (streq(key, "root") && value) {
462 arg_root_what = strdup(value);
466 } else if (streq(key, "rootfstype") && value) {
468 free(arg_root_fstype);
469 arg_root_fstype = strdup(value);
470 if (!arg_root_fstype)
473 } else if (streq(key, "rootflags") && value) {
476 o = arg_root_options ?
477 strjoin(arg_root_options, ",", value, NULL) :
482 free(arg_root_options);
483 arg_root_options = o;
485 } else if (streq(key, "rw") && !value)
487 else if (streq(key, "ro") && !value)
489 else if (startswith(key, "fstab.") || startswith(key, "rd.fstab."))
490 log_warning("Unknown kernel switch %s. Ignoring.", key);
495 int main(int argc, char *argv[]) {
498 if (argc > 1 && argc != 4) {
499 log_error("This program takes three or no arguments.");
506 log_set_target(LOG_TARGET_SAFE);
507 log_parse_environment();
512 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
515 /* Always honour root= in the kernel command line if we are in an initrd */
517 r = add_root_mount();
519 /* Honour /etc/fstab only when that's enabled */
520 if (arg_fstab_enabled) {
523 /* Parse the local /etc/fstab, possibly from the initrd */
524 k = parse_fstab(false);
528 /* If running in the initrd also parse the /etc/fstab from the host */
530 k = parse_fstab(true);
536 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;