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"
38 static const char *arg_dest = "/tmp";
39 static bool arg_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, *device = NULL;
68 _cleanup_fclose_ FILE *f = NULL;
74 r = mount_find_pri(me, &pri);
76 log_error("Failed to parse priority");
80 name = unit_name_from_path(what, ".swap");
84 unit = strjoin(arg_dest, "/", name, NULL);
88 f = fopen(unit, "wxe");
91 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
93 log_error("Failed to create unit file %s: %m", unit);
98 "# Automatically generated by systemd-fstab-generator\n\n"
100 "SourcePath=/etc/fstab\n"
113 log_error("Failed to write unit file %s: %m", unit);
120 static bool mount_is_network(struct mntent *me) {
124 hasmntopt(me, "_netdev") ||
125 fstype_is_network(me->mnt_type);
128 static bool mount_in_initrd(struct mntent *me) {
132 hasmntopt(me, "x-initrd.mount") ||
133 streq(me->mnt_dir, "/usr");
136 static int add_mount(
146 const char *source) {
148 *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL,
149 *automount_name = NULL, *automount_unit = NULL;
150 _cleanup_fclose_ FILE *f = NULL;
158 if (streq(type, "autofs"))
161 if (!is_path(where)) {
162 log_warning("Mount point %s is not a valid path, ignoring.", where);
166 if (mount_point_is_api(where) ||
167 mount_point_ignore(where))
170 name = unit_name_from_path(where, ".mount");
174 unit = strjoin(arg_dest, "/", name, NULL);
178 f = fopen(unit, "wxe");
181 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
183 log_error("Failed to create unit file %s: %m", unit);
188 "# Automatically generated by systemd-fstab-generator\n\n"
193 if (post && !noauto && !nofail && !automount)
210 if (!isempty(opts) &&
211 !streq(opts, "defaults"))
218 log_error("Failed to write unit file %s: %m", unit);
224 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
228 mkdir_parents_label(lnk, 0755);
229 if (symlink(unit, lnk) < 0) {
230 log_error("Failed to create symlink %s: %m", lnk);
236 if (automount && !path_equal(where, "/")) {
237 automount_name = unit_name_from_path(where, ".automount");
241 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
246 f = fopen(automount_unit, "wxe");
248 log_error("Failed to create unit file %s: %m", automount_unit);
253 "# Automatically generated by systemd-fstab-generator\n\n"
270 log_error("Failed to write unit file %s: %m", automount_unit);
275 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
279 mkdir_parents_label(lnk, 0755);
280 if (symlink(automount_unit, lnk) < 0) {
281 log_error("Failed to create symlink %s: %m", lnk);
289 static int parse_fstab(const char *prefix, bool initrd) {
290 _cleanup_free_ char *fstab_path = NULL;
295 fstab_path = strjoin(strempty(prefix), "/etc/fstab", NULL);
299 f = setmntent(fstab_path, "r");
304 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix));
308 while ((me = getmntent(f))) {
309 _cleanup_free_ char *where = NULL, *what = NULL;
312 if (initrd && !mount_in_initrd(me))
315 what = fstab_node_to_udev_node(me->mnt_fsname);
316 where = strjoin(strempty(prefix), me->mnt_dir, NULL);
317 if (!what || !where) {
323 path_kill_slashes(where);
325 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
327 if (streq(me->mnt_type, "swap"))
328 k = add_swap(what, me);
330 bool noauto, nofail, automount;
333 noauto = !!hasmntopt(me, "noauto");
334 nofail = !!hasmntopt(me, "nofail");
336 hasmntopt(me, "comment=systemd.automount") ||
337 hasmntopt(me, "x-systemd.automount");
340 post = SPECIAL_INITRD_FS_TARGET;
341 } else if (mount_in_initrd(me)) {
342 post = SPECIAL_INITRD_ROOT_FS_TARGET;
343 } else if (mount_is_network(me)) {
344 post = SPECIAL_REMOTE_FS_TARGET;
346 post = SPECIAL_LOCAL_FS_TARGET;
349 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
350 me->mnt_passno, noauto, nofail, automount,
363 static int parse_new_root_from_proc_cmdline(void) {
364 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
370 r = read_one_line_file("/proc/cmdline", &line);
372 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
377 type = strdup("auto");
381 /* root= and roofstype= may occur more than once, the last instance should take precedence.
382 * In the case of multiple rootflags= the arguments should be concatenated */
383 FOREACH_WORD_QUOTED(w, l, line, state) {
384 _cleanup_free_ char *word;
386 word = strndup(w, l);
390 else if (startswith(word, "root=")) {
392 what = fstab_node_to_udev_node(word+5);
396 } else if (startswith(word, "rootfstype=")) {
398 type = strdup(word + 11);
402 } else if (startswith(word, "rootflags=")) {
405 o = strjoin(opts, ",", word + 10, NULL);
412 } else if (streq(word, "ro") || streq(word, "rw")) {
415 o = strjoin(opts, ",", word, NULL);
424 noauto = !!strstr(opts, "noauto");
425 nofail = !!strstr(opts, "nofail");
428 log_debug("Could not find a root= entry on the kernel commandline.");
432 if (what[0] != '/') {
433 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
437 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
438 r = add_mount(what, "/sysroot", type, opts, 0, noauto, nofail, false,
439 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
441 return (r < 0) ? r : 0;
444 static int parse_proc_cmdline(void) {
445 _cleanup_free_ char *line = NULL;
450 if (detect_container(NULL) > 0)
453 r = read_one_line_file("/proc/cmdline", &line);
455 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
459 FOREACH_WORD_QUOTED(w, l, line, state) {
460 _cleanup_free_ char *word = NULL;
462 word = strndup(w, l);
466 if (startswith(word, "fstab=")) {
467 r = parse_boolean(word + 6);
469 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
473 } else if (startswith(word, "rd.fstab=")) {
476 r = parse_boolean(word + 9);
478 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9);
483 } else if (startswith(word, "fstab.") ||
484 (in_initrd() && startswith(word, "rd.fstab."))) {
486 log_warning("Unknown kernel switch %s. Ignoring.", word);
493 int main(int argc, char *argv[]) {
496 if (argc > 1 && argc != 4) {
497 log_error("This program takes three or no arguments.");
504 log_set_target(LOG_TARGET_SAFE);
505 log_parse_environment();
510 if (parse_proc_cmdline() < 0)
514 r = parse_new_root_from_proc_cmdline();
517 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
519 k = parse_fstab(NULL, false);
522 l = parse_fstab("/sysroot", true);
524 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;