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 device_name(const char *path, char **unit) {
46 if (!is_device_path(path))
49 p = unit_name_from_path(path, ".device");
57 static int mount_find_pri(struct mntent *me, int *ret) {
64 pri = hasmntopt(me, "pri");
71 r = strtoul(pri, &end, 10);
75 if (end == pri || (*end != ',' && *end != 0))
82 static int add_swap(const char *what, struct mntent *me) {
83 char _cleanup_free_ *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
84 FILE _cleanup_fclose_ *f = NULL;
91 r = mount_find_pri(me, &pri);
93 log_error("Failed to parse priority");
97 noauto = !!hasmntopt(me, "noauto");
98 nofail = !!hasmntopt(me, "nofail");
100 name = unit_name_from_path(what, ".swap");
104 unit = strjoin(arg_dest, "/", name, NULL);
108 f = fopen(unit, "wxe");
111 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
113 log_error("Failed to create unit file %s: %m", unit);
117 fputs("# Automatically generated by systemd-fstab-generator\n\n"
119 "SourcePath=/etc/fstab\n"
120 "DefaultDependencies=no\n"
121 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
122 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
124 if (!noauto && !nofail)
125 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
140 log_error("Failed to write unit file %s: %m", unit);
145 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
149 mkdir_parents_label(lnk, 0755);
150 if (symlink(unit, lnk) < 0) {
151 log_error("Failed to create symlink %s: %m", lnk);
155 r = device_name(what, &device);
161 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
165 mkdir_parents_label(lnk, 0755);
166 if (symlink(unit, lnk) < 0) {
167 log_error("Failed to create symlink %s: %m", lnk);
176 static bool mount_is_bind(struct mntent *me) {
180 hasmntopt(me, "bind") ||
181 streq(me->mnt_type, "bind") ||
182 hasmntopt(me, "rbind") ||
183 streq(me->mnt_type, "rbind");
186 static bool mount_is_network(struct mntent *me) {
190 hasmntopt(me, "_netdev") ||
191 fstype_is_network(me->mnt_type);
194 static bool mount_in_initrd(struct mntent *me) {
198 hasmntopt(me, "x-initrd.mount") ||
199 streq(me->mnt_dir, "/usr");
202 static bool mount_is_rootfs(struct mntent *me) {
205 return hasmntopt(me, "x-initrd.rootfs");
208 static int add_mount(const char *what, const char *where, const char *type, const char *opts,
209 int passno, bool noauto, bool nofail, bool automount, bool isbind,
210 const char *pre, const char *post, const char *source) {
212 *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL,
213 *automount_name = NULL, *automount_unit = NULL;
214 FILE _cleanup_fclose_ *f = NULL;
223 if (streq(type, "autofs"))
226 if (!is_path(where)) {
227 log_warning("Mount point %s is not a valid path, ignoring.", where);
231 if (mount_point_is_api(where) ||
232 mount_point_ignore(where))
235 name = unit_name_from_path(where, ".mount");
239 unit = strjoin(arg_dest, "/", name, NULL);
243 f = fopen(unit, "wxe");
246 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
248 log_error("Failed to create unit file %s: %m", unit);
253 "# Automatically generated by systemd-fstab-generator\n\n"
256 "DefaultDependencies=no\n",
259 if (!path_equal(where, "/")) {
267 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
268 "Before=" SPECIAL_UMOUNT_TARGET "\n");
271 if (post && !noauto && !nofail && !automount)
288 if (!isempty(opts) &&
289 !streq(opts, "defaults"))
296 log_error("Failed to write unit file %s: %m", unit);
302 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
306 mkdir_parents_label(lnk, 0755);
307 if (symlink(unit, lnk) < 0) {
308 log_error("Failed to create symlink %s: %m", lnk);
314 !path_equal(where, "/")) {
316 r = device_name(what, &device);
322 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
326 mkdir_parents_label(lnk, 0755);
327 if (symlink(unit, lnk) < 0) {
328 log_error("Failed to create symlink %s: %m", lnk);
335 if (automount && !path_equal(where, "/")) {
336 automount_name = unit_name_from_path(where, ".automount");
340 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
345 f = fopen(automount_unit, "wxe");
347 log_error("Failed to create unit file %s: %m", automount_unit);
352 "# Automatically generated by systemd-fstab-generator\n\n"
355 "DefaultDependencies=no\n"
356 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
357 "Before=" SPECIAL_UMOUNT_TARGET "\n",
372 log_error("Failed to write unit file %s: %m", automount_unit);
377 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
381 mkdir_parents_label(lnk, 0755);
382 if (symlink(automount_unit, lnk) < 0) {
383 log_error("Failed to create symlink %s: %m", lnk);
391 static int parse_fstab(const char *prefix, bool initrd) {
392 _cleanup_free_ char *fstab_path = NULL;
397 fstab_path = strjoin(strempty(prefix), "/etc/fstab", NULL);
401 f = setmntent(fstab_path, "r");
406 log_error("Failed to open %s/etc/fstab: %m", prefix);
410 while ((me = getmntent(f))) {
411 char _cleanup_free_ *where = NULL, *what = NULL;
414 if (initrd && !mount_in_initrd(me))
417 what = fstab_node_to_udev_node(me->mnt_fsname);
418 where = strjoin(prefix, me->mnt_dir, NULL);
419 if (!what || !where) {
425 path_kill_slashes(where);
427 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
429 if (streq(me->mnt_type, "swap"))
430 k = add_swap(what, me);
432 bool noauto, nofail, automount, isbind;
433 const char *pre, *post;
435 noauto = !!hasmntopt(me, "noauto");
436 nofail = !!hasmntopt(me, "nofail");
438 hasmntopt(me, "comment=systemd.automount") ||
439 hasmntopt(me, "x-systemd.automount");
440 isbind = mount_is_bind(me);
443 post = SPECIAL_INITRD_FS_TARGET;
445 } else if (mount_is_rootfs(me)) {
446 post = SPECIAL_INITRD_ROOT_FS_TARGET;
448 } else if (mount_is_network(me)) {
449 post = SPECIAL_REMOTE_FS_TARGET;
450 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
452 post = SPECIAL_LOCAL_FS_TARGET;
453 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
456 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
457 me->mnt_passno, noauto, nofail, automount,
458 isbind, pre, post, fstab_path);
470 static int parse_new_root_from_proc_cmdline(void) {
471 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
476 r = read_one_line_file("/proc/cmdline", &line);
478 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
483 type = strdup("auto");
487 /* root= and roofstype= may occur more than once, the last instance should take precedence.
488 * In the case of multiple rootflags= the arguments should be concatenated */
489 FOREACH_WORD_QUOTED(w, l, line, state) {
490 _cleanup_free_ char *word;
492 word = strndup(w, l);
496 else if (startswith(word, "root=")) {
498 what = fstab_node_to_udev_node(word+5);
502 } else if (startswith(word, "rootfstype=")) {
504 type = strdup(word + 11);
508 } else if (startswith(word, "rootflags=")) {
511 o = strjoin(opts, ",", word + 10, NULL);
518 } else if (streq(word, "ro") || streq(word, "rw")) {
521 o = strjoin(opts, ",", word, NULL);
531 log_error("Could not find a root= entry on the kernel commandline.");
535 if (what[0] != '/') {
536 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
540 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
541 r = add_mount(what, "/sysroot", type, opts, 0, false, false, false,
542 false, NULL, SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
544 return (r < 0) ? r : 0;
547 static int parse_proc_cmdline(void) {
548 char _cleanup_free_ *line = NULL;
553 if (detect_container(NULL) > 0)
556 r = read_one_line_file("/proc/cmdline", &line);
558 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
562 FOREACH_WORD_QUOTED(w, l, line, state) {
563 char _cleanup_free_ *word = NULL;
565 word = strndup(w, l);
569 if (startswith(word, "fstab=")) {
570 r = parse_boolean(word + 6);
572 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
576 } else if (startswith(word, "rd.fstab=")) {
579 r = parse_boolean(word + 6);
581 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
586 } else if (startswith(word, "fstab.") ||
587 (in_initrd() && startswith(word, "rd.fstab."))) {
589 log_warning("Unknown kernel switch %s. Ignoring.", word);
596 int main(int argc, char *argv[]) {
599 if (argc > 1 && argc != 4) {
600 log_error("This program takes three or no arguments.");
607 log_set_target(LOG_TARGET_SAFE);
608 log_parse_environment();
613 if (parse_proc_cmdline() < 0)
617 r = parse_new_root_from_proc_cmdline();
620 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
622 k = parse_fstab(NULL, false);
625 l = parse_fstab("/sysroot", true);
627 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;