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"
37 static const char *arg_dest = "/tmp";
38 static bool arg_enabled = true;
40 static int mount_find_pri(struct mntent *me, int *ret) {
47 pri = hasmntopt(me, "pri");
54 r = strtoul(pri, &end, 10);
58 if (end == pri || (*end != ',' && *end != 0))
65 static int add_swap(const char *what, struct mntent *me) {
66 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
67 _cleanup_fclose_ FILE *f = NULL;
74 r = mount_find_pri(me, &pri);
76 log_error("Failed to parse priority");
80 noauto = !!hasmntopt(me, "noauto");
82 name = unit_name_from_path(what, ".swap");
86 unit = strjoin(arg_dest, "/", name, NULL);
90 f = fopen(unit, "wxe");
93 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
95 log_error("Failed to create unit file %s: %m", unit);
100 "# Automatically generated by systemd-fstab-generator\n\n"
102 "SourcePath=/etc/fstab\n\n"
114 log_error("Failed to write unit file %s: %m", unit);
119 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
123 mkdir_parents_label(lnk, 0755);
124 if (symlink(unit, lnk) < 0) {
125 log_error("Failed to create symlink %s: %m", lnk);
133 static bool mount_is_network(struct mntent *me) {
137 hasmntopt(me, "_netdev") ||
138 fstype_is_network(me->mnt_type);
141 static bool mount_in_initrd(struct mntent *me) {
145 hasmntopt(me, "x-initrd.mount") ||
146 streq(me->mnt_dir, "/usr");
149 static int add_mount(
159 const char *source) {
161 *name = NULL, *unit = NULL, *lnk = NULL,
162 *automount_name = NULL, *automount_unit = NULL;
163 _cleanup_fclose_ FILE *f = NULL;
171 if (streq(type, "autofs"))
174 if (!is_path(where)) {
175 log_warning("Mount point %s is not a valid path, ignoring.", where);
179 if (mount_point_is_api(where) ||
180 mount_point_ignore(where))
183 name = unit_name_from_path(where, ".mount");
187 unit = strjoin(arg_dest, "/", name, NULL);
191 f = fopen(unit, "wxe");
194 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
196 log_error("Failed to create unit file %s: %m", unit);
201 "# Automatically generated by systemd-fstab-generator\n\n"
206 if (post && !noauto && !nofail && !automount)
212 if (streq(where, "/")) {
213 lnk = strjoin(arg_dest, "/", SPECIAL_LOCAL_FS_TARGET, ".wants/", "systemd-fsck-root.service", NULL);
217 mkdir_parents_label(lnk, 0755);
218 if (symlink("systemd-fsck-root.service", lnk) < 0) {
219 log_error("Failed to create symlink %s: %m", lnk);
223 _cleanup_free_ char *fsck = NULL;
225 fsck = unit_name_from_path_instance("systemd-fsck", what, ".service");
248 if (!isempty(opts) &&
249 !streq(opts, "defaults"))
256 log_error("Failed to write unit file %s: %m", unit);
263 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
267 mkdir_parents_label(lnk, 0755);
268 if (symlink(unit, lnk) < 0) {
269 log_error("Failed to create symlink %s: %m", lnk);
275 if (automount && !path_equal(where, "/")) {
276 automount_name = unit_name_from_path(where, ".automount");
280 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
285 f = fopen(automount_unit, "wxe");
287 log_error("Failed to create unit file %s: %m", automount_unit);
292 "# Automatically generated by systemd-fstab-generator\n\n"
309 log_error("Failed to write unit file %s: %m", automount_unit);
314 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
318 mkdir_parents_label(lnk, 0755);
319 if (symlink(automount_unit, lnk) < 0) {
320 log_error("Failed to create symlink %s: %m", lnk);
328 static int parse_fstab(const char *prefix, bool initrd) {
330 _cleanup_endmntent_ FILE *f;
334 fstab_path = strappenda(strempty(prefix), "/etc/fstab");
335 f = setmntent(fstab_path, "r");
340 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix));
344 while ((me = getmntent(f))) {
345 _cleanup_free_ char *where = NULL, *what = NULL;
348 if (initrd && !mount_in_initrd(me))
351 what = fstab_node_to_udev_node(me->mnt_fsname);
352 where = strjoin(strempty(prefix), me->mnt_dir, NULL);
357 path_kill_slashes(where);
359 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
361 if (streq(me->mnt_type, "swap"))
362 k = add_swap(what, me);
364 bool noauto, nofail, automount;
367 noauto = !!hasmntopt(me, "noauto");
368 nofail = !!hasmntopt(me, "nofail");
370 hasmntopt(me, "comment=systemd.automount") ||
371 hasmntopt(me, "x-systemd.automount");
374 post = SPECIAL_INITRD_FS_TARGET;
375 } else if (mount_in_initrd(me)) {
376 post = SPECIAL_INITRD_ROOT_FS_TARGET;
377 } else if (mount_is_network(me)) {
378 post = SPECIAL_REMOTE_FS_TARGET;
380 post = SPECIAL_LOCAL_FS_TARGET;
383 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
384 me->mnt_passno, noauto, nofail, automount,
395 static int parse_new_root_from_proc_cmdline(void) {
396 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
402 r = proc_cmdline(&line);
404 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
409 type = strdup("auto");
413 /* root= and roofstype= may occur more than once, the last instance should take precedence.
414 * In the case of multiple rootflags= the arguments should be concatenated */
415 FOREACH_WORD_QUOTED(w, l, line, state) {
416 _cleanup_free_ char *word;
418 word = strndup(w, l);
422 else if (startswith(word, "root=")) {
424 what = fstab_node_to_udev_node(word+5);
428 } else if (startswith(word, "rootfstype=")) {
430 type = strdup(word + 11);
434 } else if (startswith(word, "rootflags=")) {
437 o = strjoin(opts, ",", word + 10, NULL);
444 } else if (streq(word, "ro") || streq(word, "rw")) {
447 o = strjoin(opts, ",", word, NULL);
456 noauto = !!strstr(opts, "noauto");
457 nofail = !!strstr(opts, "nofail");
460 log_debug("Could not find a root= entry on the kernel commandline.");
464 if (what[0] != '/') {
465 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
469 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
470 r = add_mount(what, "/sysroot", type, opts, 1, noauto, nofail, false,
471 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
473 return (r < 0) ? r : 0;
476 static int parse_proc_cmdline(void) {
477 _cleanup_free_ char *line = NULL;
482 r = proc_cmdline(&line);
484 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
488 FOREACH_WORD_QUOTED(w, l, line, state) {
489 _cleanup_free_ char *word = NULL;
491 word = strndup(w, l);
495 if (startswith(word, "fstab=")) {
496 r = parse_boolean(word + 6);
498 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
502 } else if (startswith(word, "rd.fstab=")) {
505 r = parse_boolean(word + 9);
507 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9);
512 } else if (startswith(word, "fstab.") ||
513 (in_initrd() && startswith(word, "rd.fstab."))) {
515 log_warning("Unknown kernel switch %s. Ignoring.", word);
522 int main(int argc, char *argv[]) {
525 if (argc > 1 && argc != 4) {
526 log_error("This program takes three or no arguments.");
533 log_set_target(LOG_TARGET_SAFE);
534 log_parse_environment();
539 if (parse_proc_cmdline() < 0)
543 r = parse_new_root_from_proc_cmdline();
546 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
548 k = parse_fstab(NULL, false);
551 l = parse_fstab("/sysroot", true);
553 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;