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);
132 /* use what as where, to have a nicer error message */
133 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
138 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
142 mkdir_parents_label(lnk, 0755);
143 if (symlink(unit, lnk) < 0) {
144 log_error("Failed to create symlink %s: %m", lnk);
152 static bool mount_is_network(struct mntent *me) {
156 hasmntopt(me, "_netdev") ||
157 fstype_is_network(me->mnt_type);
160 static bool mount_in_initrd(struct mntent *me) {
164 hasmntopt(me, "x-initrd.mount") ||
165 streq(me->mnt_dir, "/usr");
168 static int add_mount(
178 const char *source) {
181 *name = NULL, *unit = NULL, *lnk = NULL,
182 *automount_name = NULL, *automount_unit = NULL,
184 _cleanup_fclose_ FILE *f = NULL;
192 if (streq_ptr(fstype, "autofs"))
195 if (!is_path(where)) {
196 log_warning("Mount point %s is not a valid path, ignoring.", where);
200 if (mount_point_is_api(where) ||
201 mount_point_ignore(where))
204 if (path_equal(where, "/")) {
205 /* The root disk is not an option */
211 name = unit_name_from_path(where, ".mount");
215 unit = strjoin(arg_dest, "/", name, NULL);
219 f = fopen(unit, "wxe");
222 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
224 log_error("Failed to create unit file %s: %m", unit);
229 "# Automatically generated by systemd-fstab-generator\n\n"
232 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
235 if (post && !noauto && !nofail && !automount)
236 fprintf(f, "Before=%s\n", post);
239 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
252 if (!isempty(fstype) && !streq(fstype, "auto"))
253 fprintf(f, "Type=%s\n", fstype);
255 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
259 if (!isempty(filtered) && !streq(filtered, "defaults"))
260 fprintf(f, "Options=%s\n", filtered);
264 log_error("Failed to write unit file %s: %m", unit);
268 if (!noauto && post) {
269 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
273 mkdir_parents_label(lnk, 0755);
274 if (symlink(unit, lnk) < 0) {
275 log_error("Failed to create symlink %s: %m", lnk);
281 automount_name = unit_name_from_path(where, ".automount");
285 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
290 f = fopen(automount_unit, "wxe");
292 log_error("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 log_error("Failed to write unit file %s: %m", automount_unit);
320 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
324 mkdir_parents_label(lnk, 0755);
325 if (symlink(automount_unit, lnk) < 0) {
326 log_error("Failed to create symlink %s: %m", lnk);
334 static int parse_fstab(bool initrd) {
335 _cleanup_endmntent_ FILE *f = NULL;
336 const char *fstab_path;
340 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
341 f = setmntent(fstab_path, "re");
346 log_error("Failed to open %s: %m", fstab_path);
350 while ((me = getmntent(f))) {
351 _cleanup_free_ char *where = NULL, *what = NULL;
354 if (initrd && !mount_in_initrd(me))
357 what = fstab_node_to_udev_node(me->mnt_fsname);
361 if (detect_container(NULL) > 0 && is_device_path(what)) {
362 log_info("Running in a container, ignoring fstab device entry for %s.", what);
366 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
371 path_kill_slashes(where);
373 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
375 if (streq(me->mnt_type, "swap"))
376 k = add_swap(what, me);
378 bool noauto, nofail, automount;
381 noauto = !!hasmntopt(me, "noauto");
382 nofail = !!hasmntopt(me, "nofail");
384 hasmntopt(me, "comment=systemd.automount") ||
385 hasmntopt(me, "x-systemd.automount");
388 post = SPECIAL_INITRD_FS_TARGET;
389 else if (mount_in_initrd(me))
390 post = SPECIAL_INITRD_ROOT_FS_TARGET;
391 else if (mount_is_network(me))
392 post = SPECIAL_REMOTE_FS_TARGET;
394 post = SPECIAL_LOCAL_FS_TARGET;
415 static int add_root_mount(void) {
416 _cleanup_free_ char *what = NULL;
419 if (isempty(arg_root_what)) {
420 log_debug("Could not find a root= entry on the kernel commandline.");
424 what = fstab_node_to_udev_node(arg_root_what);
425 if (!path_is_absolute(what)) {
426 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
430 if (!arg_root_options)
431 opts = arg_root_rw > 0 ? "rw" : "ro";
432 else if (arg_root_rw >= 0 ||
433 (!mount_test_option(arg_root_options, "ro") &&
434 !mount_test_option(arg_root_options, "rw")))
435 opts = strappenda3(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
437 opts = arg_root_options;
439 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
440 return add_mount(what,
448 SPECIAL_INITRD_ROOT_FS_TARGET,
452 static int parse_proc_cmdline_item(const char *key, const char *value) {
455 /* root= and roofstype= may occur more than once, the last
456 * instance should take precedence. In the case of multiple
457 * rootflags= the arguments should be concatenated */
459 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
461 r = parse_boolean(value);
463 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
465 arg_fstab_enabled = r;
467 } else if (streq(key, "root") && value) {
470 arg_root_what = strdup(value);
474 } else if (streq(key, "rootfstype") && value) {
476 free(arg_root_fstype);
477 arg_root_fstype = strdup(value);
478 if (!arg_root_fstype)
481 } else if (streq(key, "rootflags") && value) {
484 o = arg_root_options ?
485 strjoin(arg_root_options, ",", value, NULL) :
490 free(arg_root_options);
491 arg_root_options = o;
493 } else if (streq(key, "rw") && !value)
495 else if (streq(key, "ro") && !value)
501 int main(int argc, char *argv[]) {
504 if (argc > 1 && argc != 4) {
505 log_error("This program takes three or no arguments.");
512 log_set_target(LOG_TARGET_SAFE);
513 log_parse_environment();
518 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
521 /* Always honour root= in the kernel command line if we are in an initrd */
523 r = add_root_mount();
525 /* Honour /etc/fstab only when that's enabled */
526 if (arg_fstab_enabled) {
529 log_debug("Parsing /etc/fstab");
531 /* Parse the local /etc/fstab, possibly from the initrd */
532 k = parse_fstab(false);
536 /* If running in the initrd also parse the /etc/fstab from the host */
538 log_debug("Parsing /sysroot/etc/fstab");
540 k = parse_fstab(true);
548 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;