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"
39 static const char *arg_dest = "/tmp";
40 static bool arg_fstab_enabled = true;
41 static char *arg_root_what = NULL;
42 static char *arg_root_fstype = NULL;
43 static char *arg_root_options = NULL;
44 static int arg_root_rw = -1;
46 static int mount_find_pri(struct mntent *me, int *ret) {
53 pri = hasmntopt(me, "pri");
60 r = strtoul(pri, &end, 10);
64 if (end == pri || (*end != ',' && *end != 0))
71 static int add_swap(const char *what, struct mntent *me) {
72 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
73 _cleanup_fclose_ FILE *f = NULL;
80 r = mount_find_pri(me, &pri);
82 log_error("Failed to parse priority");
86 noauto = !!hasmntopt(me, "noauto");
88 name = unit_name_from_path(what, ".swap");
92 unit = strjoin(arg_dest, "/", name, NULL);
96 f = fopen(unit, "wxe");
99 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
101 log_error("Failed to create unit file %s: %m", unit);
106 "# Automatically generated by systemd-fstab-generator\n\n"
108 "SourcePath=/etc/fstab\n"
109 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
121 log_error("Failed to write unit file %s: %m", unit);
126 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
130 mkdir_parents_label(lnk, 0755);
131 if (symlink(unit, lnk) < 0) {
132 log_error("Failed to create symlink %s: %m", lnk);
140 static bool mount_is_network(struct mntent *me) {
144 hasmntopt(me, "_netdev") ||
145 fstype_is_network(me->mnt_type);
148 static bool mount_in_initrd(struct mntent *me) {
152 hasmntopt(me, "x-initrd.mount") ||
153 streq(me->mnt_dir, "/usr");
156 static int add_mount(
166 const char *source) {
169 *name = NULL, *unit = NULL, *lnk = NULL,
170 *automount_name = NULL, *automount_unit = NULL;
171 _cleanup_fclose_ FILE *f = NULL;
179 if (streq_ptr(fstype, "autofs"))
182 if (!is_path(where)) {
183 log_warning("Mount point %s is not a valid path, ignoring.", where);
187 if (mount_point_is_api(where) ||
188 mount_point_ignore(where))
191 if (path_equal(where, "/")) {
192 /* The root disk is not an option */
198 name = unit_name_from_path(where, ".mount");
202 unit = strjoin(arg_dest, "/", name, NULL);
206 f = fopen(unit, "wxe");
209 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
211 log_error("Failed to create unit file %s: %m", unit);
216 "# Automatically generated by systemd-fstab-generator\n\n"
219 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
222 if (post && !noauto && !nofail && !automount)
223 fprintf(f, "Before=%s\n", post);
226 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
239 if (!isempty(fstype) && !streq(fstype, "auto"))
240 fprintf(f, "Type=%s\n", fstype);
242 if (!isempty(opts) && !streq(opts, "defaults"))
243 fprintf(f, "Options=%s\n", opts);
247 log_error("Failed to write unit file %s: %m", unit);
251 if (!noauto && post) {
252 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
256 mkdir_parents_label(lnk, 0755);
257 if (symlink(unit, lnk) < 0) {
258 log_error("Failed to create symlink %s: %m", lnk);
264 automount_name = unit_name_from_path(where, ".automount");
268 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
273 f = fopen(automount_unit, "wxe");
275 log_error("Failed to create unit file %s: %m", automount_unit);
280 "# Automatically generated by systemd-fstab-generator\n\n"
283 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
298 log_error("Failed to write unit file %s: %m", automount_unit);
303 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
307 mkdir_parents_label(lnk, 0755);
308 if (symlink(automount_unit, lnk) < 0) {
309 log_error("Failed to create symlink %s: %m", lnk);
317 static int parse_fstab(bool initrd) {
318 _cleanup_endmntent_ FILE *f = NULL;
319 const char *fstab_path;
323 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
324 f = setmntent(fstab_path, "re");
329 log_error("Failed to open %s: %m", fstab_path);
333 while ((me = getmntent(f))) {
334 _cleanup_free_ char *where = NULL, *what = NULL;
337 if (initrd && !mount_in_initrd(me))
340 what = fstab_node_to_udev_node(me->mnt_fsname);
344 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
349 path_kill_slashes(where);
351 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
353 if (streq(me->mnt_type, "swap"))
354 k = add_swap(what, me);
356 bool noauto, nofail, automount;
359 noauto = !!hasmntopt(me, "noauto");
360 nofail = !!hasmntopt(me, "nofail");
362 hasmntopt(me, "comment=systemd.automount") ||
363 hasmntopt(me, "x-systemd.automount");
366 post = SPECIAL_INITRD_FS_TARGET;
367 else if (mount_in_initrd(me))
368 post = SPECIAL_INITRD_ROOT_FS_TARGET;
369 else if (mount_is_network(me))
370 post = SPECIAL_REMOTE_FS_TARGET;
372 post = SPECIAL_LOCAL_FS_TARGET;
393 static int add_root_mount(void) {
394 _cleanup_free_ char *o = NULL, *what = NULL;
396 if (isempty(arg_root_what)) {
397 log_debug("Could not find a root= entry on the kernel commandline.");
401 what = fstab_node_to_udev_node(arg_root_what);
402 if (!path_is_absolute(what)) {
403 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
407 if (!arg_root_options)
408 o = strdup(arg_root_rw > 0 ? "rw" : "ro");
410 if (arg_root_rw >= 0 ||
411 (!mount_test_option(arg_root_options, "ro") &&
412 !mount_test_option(arg_root_options, "rw")))
413 o = strjoin(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro", NULL);
415 o = strdup(arg_root_options);
420 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
421 return add_mount(what,
429 SPECIAL_INITRD_ROOT_FS_TARGET,
433 static int parse_proc_cmdline_item(const char *key, const char *value) {
436 /* root= and roofstype= may occur more than once, the last
437 * instance should take precedence. In the case of multiple
438 * rootflags= the arguments should be concatenated */
440 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
442 r = parse_boolean(value);
444 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
446 arg_fstab_enabled = r;
448 } else if (streq(key, "root") && value) {
451 arg_root_what = strdup(value);
455 } else if (streq(key, "rootfstype") && value) {
457 free(arg_root_fstype);
458 arg_root_fstype = strdup(value);
459 if (!arg_root_fstype)
462 } else if (streq(key, "rootflags") && value) {
465 o = arg_root_options ?
466 strjoin(arg_root_options, ",", value, NULL) :
471 free(arg_root_options);
472 arg_root_options = o;
474 } else if (streq(key, "rw") && !value)
476 else if (streq(key, "ro") && !value)
478 else if (startswith(key, "fstab.") || startswith(key, "rd.fstab."))
479 log_warning("Unknown kernel switch %s. Ignoring.", key);
484 int main(int argc, char *argv[]) {
487 if (argc > 1 && argc != 4) {
488 log_error("This program takes three or no arguments.");
495 log_set_target(LOG_TARGET_SAFE);
496 log_parse_environment();
501 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
504 /* Always honour root= in the kernel command line if we are in an initrd */
506 r = add_root_mount();
508 /* Honour /etc/fstab only when that's enabled */
509 if (arg_fstab_enabled) {
512 /* Parse the local /etc/fstab, possibly from the initrd */
513 k = parse_fstab(false);
517 /* If running in the initrd also parse the /etc/fstab from the host */
519 k = parse_fstab(true);
525 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;