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;
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) {
162 *name = NULL, *unit = NULL, *lnk = NULL,
163 *automount_name = NULL, *automount_unit = NULL;
164 _cleanup_fclose_ FILE *f = NULL;
172 if (streq(type, "autofs"))
175 if (!is_path(where)) {
176 log_warning("Mount point %s is not a valid path, ignoring.", where);
180 if (mount_point_is_api(where) ||
181 mount_point_ignore(where))
184 name = unit_name_from_path(where, ".mount");
188 unit = strjoin(arg_dest, "/", name, NULL);
192 f = fopen(unit, "wxe");
195 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
197 log_error("Failed to create unit file %s: %m", unit);
202 "# Automatically generated by systemd-fstab-generator\n\n"
207 if (post && !noauto && !nofail && !automount)
213 if (streq(where, "/")) {
214 lnk = strjoin(arg_dest, "/", SPECIAL_LOCAL_FS_TARGET, ".wants/", "systemd-fsck-root.service", NULL);
218 mkdir_parents_label(lnk, 0755);
219 if (symlink("systemd-fsck-root.service", lnk) < 0) {
220 log_error("Failed to create symlink %s: %m", lnk);
224 _cleanup_free_ char *fsck = NULL;
226 fsck = unit_name_from_path_instance("systemd-fsck", what, ".service");
249 if (!isempty(opts) &&
250 !streq(opts, "defaults"))
257 log_error("Failed to write unit file %s: %m", unit);
264 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
268 mkdir_parents_label(lnk, 0755);
269 if (symlink(unit, lnk) < 0) {
270 log_error("Failed to create symlink %s: %m", lnk);
276 if (automount && !path_equal(where, "/")) {
277 automount_name = unit_name_from_path(where, ".automount");
281 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
286 f = fopen(automount_unit, "wxe");
288 log_error("Failed to create unit file %s: %m", automount_unit);
293 "# Automatically generated by systemd-fstab-generator\n\n"
310 log_error("Failed to write unit file %s: %m", automount_unit);
315 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
319 mkdir_parents_label(lnk, 0755);
320 if (symlink(automount_unit, lnk) < 0) {
321 log_error("Failed to create symlink %s: %m", lnk);
329 static int parse_fstab(const char *prefix, bool initrd) {
331 _cleanup_endmntent_ FILE *f;
335 fstab_path = strappenda(strempty(prefix), "/etc/fstab");
336 f = setmntent(fstab_path, "r");
341 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix));
345 while ((me = getmntent(f))) {
346 _cleanup_free_ char *where = NULL, *what = NULL;
349 if (initrd && !mount_in_initrd(me))
352 what = fstab_node_to_udev_node(me->mnt_fsname);
353 where = strjoin(strempty(prefix), me->mnt_dir, NULL);
358 path_kill_slashes(where);
360 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
362 if (streq(me->mnt_type, "swap"))
363 k = add_swap(what, me);
365 bool noauto, nofail, automount;
368 noauto = !!hasmntopt(me, "noauto");
369 nofail = !!hasmntopt(me, "nofail");
371 hasmntopt(me, "comment=systemd.automount") ||
372 hasmntopt(me, "x-systemd.automount");
375 post = SPECIAL_INITRD_FS_TARGET;
376 } else if (mount_in_initrd(me)) {
377 post = SPECIAL_INITRD_ROOT_FS_TARGET;
378 } else if (mount_is_network(me)) {
379 post = SPECIAL_REMOTE_FS_TARGET;
381 post = SPECIAL_LOCAL_FS_TARGET;
384 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
385 me->mnt_passno, noauto, nofail, automount,
396 static int parse_new_root_from_proc_cmdline(void) {
397 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
403 r = read_one_line_file("/proc/cmdline", &line);
405 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
410 type = strdup("auto");
414 /* root= and roofstype= may occur more than once, the last instance should take precedence.
415 * In the case of multiple rootflags= the arguments should be concatenated */
416 FOREACH_WORD_QUOTED(w, l, line, state) {
417 _cleanup_free_ char *word;
419 word = strndup(w, l);
423 else if (startswith(word, "root=")) {
425 what = fstab_node_to_udev_node(word+5);
429 } else if (startswith(word, "rootfstype=")) {
431 type = strdup(word + 11);
435 } else if (startswith(word, "rootflags=")) {
438 o = strjoin(opts, ",", word + 10, NULL);
445 } else if (streq(word, "ro") || streq(word, "rw")) {
448 o = strjoin(opts, ",", word, NULL);
457 noauto = !!strstr(opts, "noauto");
458 nofail = !!strstr(opts, "nofail");
461 log_debug("Could not find a root= entry on the kernel commandline.");
465 if (what[0] != '/') {
466 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
470 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
471 r = add_mount(what, "/sysroot", type, opts, 1, noauto, nofail, false,
472 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
474 return (r < 0) ? r : 0;
477 static int parse_proc_cmdline(void) {
478 _cleanup_free_ char *line = NULL;
483 if (detect_container(NULL) > 0)
486 r = read_one_line_file("/proc/cmdline", &line);
488 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
492 FOREACH_WORD_QUOTED(w, l, line, state) {
493 _cleanup_free_ char *word = NULL;
495 word = strndup(w, l);
499 if (startswith(word, "fstab=")) {
500 r = parse_boolean(word + 6);
502 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
506 } else if (startswith(word, "rd.fstab=")) {
509 r = parse_boolean(word + 9);
511 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9);
516 } else if (startswith(word, "fstab.") ||
517 (in_initrd() && startswith(word, "rd.fstab."))) {
519 log_warning("Unknown kernel switch %s. Ignoring.", word);
526 int main(int argc, char *argv[]) {
529 if (argc > 1 && argc != 4) {
530 log_error("This program takes three or no arguments.");
537 log_set_target(LOG_TARGET_SAFE);
538 log_parse_environment();
543 if (parse_proc_cmdline() < 0)
547 r = parse_new_root_from_proc_cmdline();
550 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
552 k = parse_fstab(NULL, false);
555 l = parse_fstab("/sysroot", true);
557 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;