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;
42 static int mount_find_pri(struct mntent *me, int *ret) {
49 pri = hasmntopt(me, "pri");
56 r = strtoul(pri, &end, 10);
60 if (end == pri || (*end != ',' && *end != 0))
67 static int add_swap(const char *what, struct mntent *me) {
68 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
69 _cleanup_fclose_ FILE *f = NULL;
76 r = mount_find_pri(me, &pri);
78 log_error("Failed to parse priority");
82 noauto = !!hasmntopt(me, "noauto");
84 name = unit_name_from_path(what, ".swap");
88 unit = strjoin(arg_dest, "/", name, NULL);
92 f = fopen(unit, "wxe");
95 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
97 log_error("Failed to create unit file %s: %m", unit);
102 "# Automatically generated by systemd-fstab-generator\n\n"
104 "SourcePath=/etc/fstab\n"
105 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
117 log_error("Failed to write unit file %s: %m", unit);
122 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
126 mkdir_parents_label(lnk, 0755);
127 if (symlink(unit, lnk) < 0) {
128 log_error("Failed to create symlink %s: %m", lnk);
136 static bool mount_is_network(struct mntent *me) {
140 hasmntopt(me, "_netdev") ||
141 fstype_is_network(me->mnt_type);
144 static bool mount_in_initrd(struct mntent *me) {
148 hasmntopt(me, "x-initrd.mount") ||
149 streq(me->mnt_dir, "/usr");
152 static int add_mount(
162 const char *source) {
165 *name = NULL, *unit = NULL, *lnk = NULL,
166 *automount_name = NULL, *automount_unit = NULL;
167 _cleanup_fclose_ FILE *f = NULL;
176 if (streq(type, "autofs"))
179 if (!is_path(where)) {
180 log_warning("Mount point %s is not a valid path, ignoring.", where);
184 if (mount_point_is_api(where) ||
185 mount_point_ignore(where))
188 if (path_equal(where, "/")) {
194 name = unit_name_from_path(where, ".mount");
198 unit = strjoin(arg_dest, "/", name, NULL);
202 f = fopen(unit, "wxe");
205 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
207 log_error("Failed to create unit file %s: %m", unit);
212 "# Automatically generated by systemd-fstab-generator\n\n"
215 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
218 if (post && !noauto && !nofail && !automount)
224 r = generator_write_fsck_deps(f, arg_dest, what, where, type);
239 if (!isempty(opts) && !streq(opts, "defaults"))
246 log_error("Failed to write unit file %s: %m", unit);
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);
265 automount_name = unit_name_from_path(where, ".automount");
269 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
274 f = fopen(automount_unit, "wxe");
276 log_error("Failed to create unit file %s: %m", automount_unit);
281 "# Automatically generated by systemd-fstab-generator\n\n"
284 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
299 log_error("Failed to write unit file %s: %m", automount_unit);
304 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
308 mkdir_parents_label(lnk, 0755);
309 if (symlink(automount_unit, lnk) < 0) {
310 log_error("Failed to create symlink %s: %m", lnk);
318 static int parse_fstab(bool initrd) {
319 _cleanup_endmntent_ FILE *f;
320 const char *fstab_path;
324 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
325 f = setmntent(fstab_path, "re");
330 log_error("Failed to open %s: %m", fstab_path);
334 while ((me = getmntent(f))) {
335 _cleanup_free_ char *where = NULL, *what = NULL;
338 if (initrd && !mount_in_initrd(me))
341 what = fstab_node_to_udev_node(me->mnt_fsname);
345 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
350 path_kill_slashes(where);
352 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
354 if (streq(me->mnt_type, "swap"))
355 k = add_swap(what, me);
357 bool noauto, nofail, automount;
360 noauto = !!hasmntopt(me, "noauto");
361 nofail = !!hasmntopt(me, "nofail");
363 hasmntopt(me, "comment=systemd.automount") ||
364 hasmntopt(me, "x-systemd.automount");
367 post = SPECIAL_INITRD_FS_TARGET;
368 else if (mount_in_initrd(me))
369 post = SPECIAL_INITRD_ROOT_FS_TARGET;
370 else if (mount_is_network(me))
371 post = SPECIAL_REMOTE_FS_TARGET;
373 post = SPECIAL_LOCAL_FS_TARGET;
375 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
376 me->mnt_passno, noauto, nofail, automount,
387 static int parse_new_root_from_proc_cmdline(void) {
388 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
394 r = proc_cmdline(&line);
396 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
401 type = strdup("auto");
405 /* root= and roofstype= may occur more than once, the last instance should take precedence.
406 * In the case of multiple rootflags= the arguments should be concatenated */
407 FOREACH_WORD_QUOTED(w, l, line, state) {
408 _cleanup_free_ char *word;
410 word = strndup(w, l);
414 else if (startswith(word, "root=")) {
416 what = fstab_node_to_udev_node(word+5);
420 } else if (startswith(word, "rootfstype=")) {
422 type = strdup(word + 11);
426 } else if (startswith(word, "rootflags=")) {
429 o = strjoin(opts, ",", word + 10, NULL);
436 } else if (streq(word, "ro") || streq(word, "rw")) {
439 o = strjoin(opts, ",", word, NULL);
448 noauto = !!strstr(opts, "noauto");
449 nofail = !!strstr(opts, "nofail");
452 log_debug("Could not find a root= entry on the kernel commandline.");
456 if (what[0] != '/') {
457 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
461 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
462 r = add_mount(what, "/sysroot", type, opts, 1, noauto, nofail, false,
463 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
465 return (r < 0) ? r : 0;
468 static int parse_proc_cmdline_item(const char *key, const char *value) {
471 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
473 r = parse_boolean(value);
475 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
477 arg_fstab_enabled = r;
479 } else if (startswith(key, "fstab.") || startswith(key, "rd.fstab."))
480 log_warning("Unknown kernel switch %s. Ignoring.", key);
485 int main(int argc, char *argv[]) {
488 if (argc > 1 && argc != 4) {
489 log_error("This program takes three or no arguments.");
496 log_set_target(LOG_TARGET_SAFE);
497 log_parse_environment();
502 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
505 /* Always honour root= in the kernel command line if we are in an initrd */
507 r = parse_new_root_from_proc_cmdline();
509 /* Honour /etc/fstab only when that's enabled */
510 if (arg_fstab_enabled) {
513 /* Parse the local /etc/fstab, possibly from the initrd */
514 k = parse_fstab(false);
518 /* If running in the initrd also parse the /etc/fstab from the host */
520 k = parse_fstab(true);
526 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;