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"
38 static const char *arg_dest = "/tmp";
39 static bool arg_fstab_enabled = true;
41 static int mount_find_pri(struct mntent *me, int *ret) {
48 pri = hasmntopt(me, "pri");
55 r = strtoul(pri, &end, 10);
59 if (end == pri || (*end != ',' && *end != 0))
66 static int add_swap(const char *what, struct mntent *me) {
67 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
68 _cleanup_fclose_ FILE *f = NULL;
75 r = mount_find_pri(me, &pri);
77 log_error("Failed to parse priority");
81 noauto = !!hasmntopt(me, "noauto");
83 name = unit_name_from_path(what, ".swap");
87 unit = strjoin(arg_dest, "/", name, NULL);
91 f = fopen(unit, "wxe");
94 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
96 log_error("Failed to create unit file %s: %m", unit);
101 "# Automatically generated by systemd-fstab-generator\n\n"
103 "SourcePath=/etc/fstab\n\n"
115 log_error("Failed to write unit file %s: %m", unit);
120 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
124 mkdir_parents_label(lnk, 0755);
125 if (symlink(unit, lnk) < 0) {
126 log_error("Failed to create symlink %s: %m", lnk);
134 static bool mount_is_network(struct mntent *me) {
138 hasmntopt(me, "_netdev") ||
139 fstype_is_network(me->mnt_type);
142 static bool mount_in_initrd(struct mntent *me) {
146 hasmntopt(me, "x-initrd.mount") ||
147 streq(me->mnt_dir, "/usr");
150 static int add_mount(
160 const char *source) {
163 *name = NULL, *unit = NULL, *lnk = NULL,
164 *automount_name = NULL, *automount_unit = NULL;
165 _cleanup_fclose_ FILE *f = NULL;
174 if (streq(type, "autofs"))
177 if (!is_path(where)) {
178 log_warning("Mount point %s is not a valid path, ignoring.", where);
182 if (mount_point_is_api(where) ||
183 mount_point_ignore(where))
186 if (path_equal(where, "/")) {
192 name = unit_name_from_path(where, ".mount");
196 unit = strjoin(arg_dest, "/", name, NULL);
200 f = fopen(unit, "wxe");
203 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
205 log_error("Failed to create unit file %s: %m", unit);
210 "# Automatically generated by systemd-fstab-generator\n\n"
215 if (post && !noauto && !nofail && !automount)
221 r = generator_write_fsck_deps(f, arg_dest, what, where, type);
236 if (!isempty(opts) && !streq(opts, "defaults"))
243 log_error("Failed to write unit file %s: %m", unit);
249 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
253 mkdir_parents_label(lnk, 0755);
254 if (symlink(unit, lnk) < 0) {
255 log_error("Failed to create symlink %s: %m", lnk);
262 automount_name = unit_name_from_path(where, ".automount");
266 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
271 f = fopen(automount_unit, "wxe");
273 log_error("Failed to create unit file %s: %m", automount_unit);
278 "# Automatically generated by systemd-fstab-generator\n\n"
295 log_error("Failed to write unit file %s: %m", automount_unit);
300 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
304 mkdir_parents_label(lnk, 0755);
305 if (symlink(automount_unit, lnk) < 0) {
306 log_error("Failed to create symlink %s: %m", lnk);
314 static int parse_fstab(bool initrd) {
315 _cleanup_endmntent_ FILE *f;
316 const char *fstab_path;
320 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
321 f = setmntent(fstab_path, "re");
326 log_error("Failed to open %s: %m", fstab_path);
330 while ((me = getmntent(f))) {
331 _cleanup_free_ char *where = NULL, *what = NULL;
334 if (initrd && !mount_in_initrd(me))
337 what = fstab_node_to_udev_node(me->mnt_fsname);
341 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
346 path_kill_slashes(where);
348 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
350 if (streq(me->mnt_type, "swap"))
351 k = add_swap(what, me);
353 bool noauto, nofail, automount;
356 noauto = !!hasmntopt(me, "noauto");
357 nofail = !!hasmntopt(me, "nofail");
359 hasmntopt(me, "comment=systemd.automount") ||
360 hasmntopt(me, "x-systemd.automount");
363 post = SPECIAL_INITRD_FS_TARGET;
364 else if (mount_in_initrd(me))
365 post = SPECIAL_INITRD_ROOT_FS_TARGET;
366 else if (mount_is_network(me))
367 post = SPECIAL_REMOTE_FS_TARGET;
369 post = SPECIAL_LOCAL_FS_TARGET;
371 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
372 me->mnt_passno, noauto, nofail, automount,
383 static int parse_new_root_from_proc_cmdline(void) {
384 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
390 r = proc_cmdline(&line);
392 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
397 type = strdup("auto");
401 /* root= and roofstype= may occur more than once, the last instance should take precedence.
402 * In the case of multiple rootflags= the arguments should be concatenated */
403 FOREACH_WORD_QUOTED(w, l, line, state) {
404 _cleanup_free_ char *word;
406 word = strndup(w, l);
410 else if (startswith(word, "root=")) {
412 what = fstab_node_to_udev_node(word+5);
416 } else if (startswith(word, "rootfstype=")) {
418 type = strdup(word + 11);
422 } else if (startswith(word, "rootflags=")) {
425 o = strjoin(opts, ",", word + 10, NULL);
432 } else if (streq(word, "ro") || streq(word, "rw")) {
435 o = strjoin(opts, ",", word, NULL);
444 noauto = !!strstr(opts, "noauto");
445 nofail = !!strstr(opts, "nofail");
448 log_debug("Could not find a root= entry on the kernel commandline.");
452 if (what[0] != '/') {
453 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
457 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
458 r = add_mount(what, "/sysroot", type, opts, 1, noauto, nofail, false,
459 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
461 return (r < 0) ? r : 0;
464 static int parse_proc_cmdline_word(const char *word) {
467 if (startswith(word, "fstab=")) {
469 r = parse_boolean(word + 6);
471 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
473 arg_fstab_enabled = r;
475 } else if (startswith(word, "rd.fstab=")) {
478 r = parse_boolean(word + 9);
480 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9);
482 arg_fstab_enabled = r;
485 } else if (startswith(word, "fstab.") ||
486 (in_initrd() && startswith(word, "rd.fstab."))) {
488 log_warning("Unknown kernel switch %s. Ignoring.", word);
494 int main(int argc, char *argv[]) {
497 if (argc > 1 && argc != 4) {
498 log_error("This program takes three or no arguments.");
505 log_set_target(LOG_TARGET_SAFE);
506 log_parse_environment();
511 if (parse_proc_cmdline(parse_proc_cmdline_word) < 0)
514 /* Always honour root= in the kernel command line if we are in an initrd */
516 r = parse_new_root_from_proc_cmdline();
518 /* Honour /etc/fstab only when that's enabled */
519 if (arg_fstab_enabled) {
522 /* Parse the local /etc/fstab, possibly from the initrd */
523 k = parse_fstab(false);
527 /* If running in the initrd also parse the /etc/fstab from the host */
529 k = parse_fstab(true);
535 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;