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\n"
116 log_error("Failed to write unit file %s: %m", unit);
121 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
125 mkdir_parents_label(lnk, 0755);
126 if (symlink(unit, lnk) < 0) {
127 log_error("Failed to create symlink %s: %m", lnk);
135 static bool mount_is_network(struct mntent *me) {
139 hasmntopt(me, "_netdev") ||
140 fstype_is_network(me->mnt_type);
143 static bool mount_in_initrd(struct mntent *me) {
147 hasmntopt(me, "x-initrd.mount") ||
148 streq(me->mnt_dir, "/usr");
151 static int add_mount(
161 const char *source) {
164 *name = NULL, *unit = NULL, *lnk = NULL,
165 *automount_name = NULL, *automount_unit = NULL;
166 _cleanup_fclose_ FILE *f = NULL;
175 if (streq(type, "autofs"))
178 if (!is_path(where)) {
179 log_warning("Mount point %s is not a valid path, ignoring.", where);
183 if (mount_point_is_api(where) ||
184 mount_point_ignore(where))
187 if (path_equal(where, "/")) {
193 name = unit_name_from_path(where, ".mount");
197 unit = strjoin(arg_dest, "/", name, NULL);
201 f = fopen(unit, "wxe");
204 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
206 log_error("Failed to create unit file %s: %m", unit);
211 "# Automatically generated by systemd-fstab-generator\n\n"
216 if (post && !noauto && !nofail && !automount)
222 r = generator_write_fsck_deps(f, arg_dest, what, where, type);
237 if (!isempty(opts) && !streq(opts, "defaults"))
244 log_error("Failed to write unit file %s: %m", unit);
250 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
254 mkdir_parents_label(lnk, 0755);
255 if (symlink(unit, lnk) < 0) {
256 log_error("Failed to create symlink %s: %m", lnk);
263 automount_name = unit_name_from_path(where, ".automount");
267 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
272 f = fopen(automount_unit, "wxe");
274 log_error("Failed to create unit file %s: %m", automount_unit);
279 "# Automatically generated by systemd-fstab-generator\n\n"
296 log_error("Failed to write unit file %s: %m", automount_unit);
301 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
305 mkdir_parents_label(lnk, 0755);
306 if (symlink(automount_unit, lnk) < 0) {
307 log_error("Failed to create symlink %s: %m", lnk);
315 static int parse_fstab(bool initrd) {
316 _cleanup_endmntent_ FILE *f;
317 const char *fstab_path;
321 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
322 f = setmntent(fstab_path, "re");
327 log_error("Failed to open %s: %m", fstab_path);
331 while ((me = getmntent(f))) {
332 _cleanup_free_ char *where = NULL, *what = NULL;
335 if (initrd && !mount_in_initrd(me))
338 what = fstab_node_to_udev_node(me->mnt_fsname);
342 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
347 path_kill_slashes(where);
349 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
351 if (streq(me->mnt_type, "swap"))
352 k = add_swap(what, me);
354 bool noauto, nofail, automount;
357 noauto = !!hasmntopt(me, "noauto");
358 nofail = !!hasmntopt(me, "nofail");
360 hasmntopt(me, "comment=systemd.automount") ||
361 hasmntopt(me, "x-systemd.automount");
364 post = SPECIAL_INITRD_FS_TARGET;
365 else if (mount_in_initrd(me))
366 post = SPECIAL_INITRD_ROOT_FS_TARGET;
367 else if (mount_is_network(me))
368 post = SPECIAL_REMOTE_FS_TARGET;
370 post = SPECIAL_LOCAL_FS_TARGET;
372 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
373 me->mnt_passno, noauto, nofail, automount,
384 static int parse_new_root_from_proc_cmdline(void) {
385 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
391 r = proc_cmdline(&line);
393 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
398 type = strdup("auto");
402 /* root= and roofstype= may occur more than once, the last instance should take precedence.
403 * In the case of multiple rootflags= the arguments should be concatenated */
404 FOREACH_WORD_QUOTED(w, l, line, state) {
405 _cleanup_free_ char *word;
407 word = strndup(w, l);
411 else if (startswith(word, "root=")) {
413 what = fstab_node_to_udev_node(word+5);
417 } else if (startswith(word, "rootfstype=")) {
419 type = strdup(word + 11);
423 } else if (startswith(word, "rootflags=")) {
426 o = strjoin(opts, ",", word + 10, NULL);
433 } else if (streq(word, "ro") || streq(word, "rw")) {
436 o = strjoin(opts, ",", word, NULL);
445 noauto = !!strstr(opts, "noauto");
446 nofail = !!strstr(opts, "nofail");
449 log_debug("Could not find a root= entry on the kernel commandline.");
453 if (what[0] != '/') {
454 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
458 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
459 r = add_mount(what, "/sysroot", type, opts, 1, noauto, nofail, false,
460 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
462 return (r < 0) ? r : 0;
465 static int parse_proc_cmdline_item(const char *key, const char *value) {
468 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
470 r = parse_boolean(value);
472 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
474 arg_fstab_enabled = r;
476 } else if (startswith(key, "fstab.") || startswith(key, "rd.fstab."))
477 log_warning("Unknown kernel switch %s. Ignoring.", key);
482 int main(int argc, char *argv[]) {
485 if (argc > 1 && argc != 4) {
486 log_error("This program takes three or no arguments.");
493 log_set_target(LOG_TARGET_SAFE);
494 log_parse_environment();
499 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
502 /* Always honour root= in the kernel command line if we are in an initrd */
504 r = parse_new_root_from_proc_cmdline();
506 /* Honour /etc/fstab only when that's enabled */
507 if (arg_fstab_enabled) {
510 /* Parse the local /etc/fstab, possibly from the initrd */
511 k = parse_fstab(false);
515 /* If running in the initrd also parse the /etc/fstab from the host */
517 k = parse_fstab(true);
523 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;