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_fsck(FILE *f, const char *what, const char *where, const char *type, int passno) {
155 if (type && !streq(type, "auto")) {
159 checker = strappenda("/sbin/fsck.", type);
160 r = access(checker, X_OK);
162 log_warning("Checking was requested for %s, but %s cannot be used: %m", what, checker);
164 /* treat missing check as essentially OK */
165 return errno == ENOENT ? 0 : -errno;
169 if (streq(where, "/")) {
172 lnk = strappenda(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
173 mkdir_parents_label(lnk, 0755);
174 if (symlink("systemd-fsck-root.service", lnk) < 0) {
175 log_error("Failed to create symlink %s: %m", lnk);
179 _cleanup_free_ char *fsck = NULL;
181 fsck = unit_name_from_path_instance("systemd-fsck", what, ".service");
186 "RequiresOverridable=%s\n"
195 static int add_mount(
205 const char *source) {
207 *name = NULL, *unit = NULL, *lnk = NULL,
208 *automount_name = NULL, *automount_unit = NULL;
209 _cleanup_fclose_ FILE *f = NULL;
218 if (streq(type, "autofs"))
221 if (!is_path(where)) {
222 log_warning("Mount point %s is not a valid path, ignoring.", where);
226 if (mount_point_is_api(where) ||
227 mount_point_ignore(where))
230 name = unit_name_from_path(where, ".mount");
234 unit = strjoin(arg_dest, "/", name, NULL);
238 f = fopen(unit, "wxe");
241 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
243 log_error("Failed to create unit file %s: %m", unit);
248 "# Automatically generated by systemd-fstab-generator\n\n"
253 if (post && !noauto && !nofail && !automount)
258 r = add_fsck(f, what, where, type, passno);
272 if (!isempty(opts) &&
273 !streq(opts, "defaults"))
280 log_error("Failed to write unit file %s: %m", unit);
286 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
290 mkdir_parents_label(lnk, 0755);
291 if (symlink(unit, lnk) < 0) {
292 log_error("Failed to create symlink %s: %m", lnk);
298 if (automount && !path_equal(where, "/")) {
299 automount_name = unit_name_from_path(where, ".automount");
303 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
308 f = fopen(automount_unit, "wxe");
310 log_error("Failed to create unit file %s: %m", automount_unit);
315 "# Automatically generated by systemd-fstab-generator\n\n"
332 log_error("Failed to write unit file %s: %m", automount_unit);
337 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
341 mkdir_parents_label(lnk, 0755);
342 if (symlink(automount_unit, lnk) < 0) {
343 log_error("Failed to create symlink %s: %m", lnk);
351 static int parse_fstab(const char *prefix, bool initrd) {
353 _cleanup_endmntent_ FILE *f;
357 fstab_path = strappenda(strempty(prefix), "/etc/fstab");
358 f = setmntent(fstab_path, "r");
363 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix));
367 while ((me = getmntent(f))) {
368 _cleanup_free_ char *where = NULL, *what = NULL;
371 if (initrd && !mount_in_initrd(me))
374 what = fstab_node_to_udev_node(me->mnt_fsname);
375 where = strjoin(strempty(prefix), me->mnt_dir, NULL);
380 path_kill_slashes(where);
382 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
384 if (streq(me->mnt_type, "swap"))
385 k = add_swap(what, me);
387 bool noauto, nofail, automount;
390 noauto = !!hasmntopt(me, "noauto");
391 nofail = !!hasmntopt(me, "nofail");
393 hasmntopt(me, "comment=systemd.automount") ||
394 hasmntopt(me, "x-systemd.automount");
397 post = SPECIAL_INITRD_FS_TARGET;
398 } else if (mount_in_initrd(me)) {
399 post = SPECIAL_INITRD_ROOT_FS_TARGET;
400 } else if (mount_is_network(me)) {
401 post = SPECIAL_REMOTE_FS_TARGET;
403 post = SPECIAL_LOCAL_FS_TARGET;
406 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
407 me->mnt_passno, noauto, nofail, automount,
418 static int parse_new_root_from_proc_cmdline(void) {
419 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
425 r = proc_cmdline(&line);
427 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
432 type = strdup("auto");
436 /* root= and roofstype= may occur more than once, the last instance should take precedence.
437 * In the case of multiple rootflags= the arguments should be concatenated */
438 FOREACH_WORD_QUOTED(w, l, line, state) {
439 _cleanup_free_ char *word;
441 word = strndup(w, l);
445 else if (startswith(word, "root=")) {
447 what = fstab_node_to_udev_node(word+5);
451 } else if (startswith(word, "rootfstype=")) {
453 type = strdup(word + 11);
457 } else if (startswith(word, "rootflags=")) {
460 o = strjoin(opts, ",", word + 10, NULL);
467 } else if (streq(word, "ro") || streq(word, "rw")) {
470 o = strjoin(opts, ",", word, NULL);
479 noauto = !!strstr(opts, "noauto");
480 nofail = !!strstr(opts, "nofail");
483 log_debug("Could not find a root= entry on the kernel commandline.");
487 if (what[0] != '/') {
488 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
492 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
493 r = add_mount(what, "/sysroot", type, opts, 1, noauto, nofail, false,
494 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
496 return (r < 0) ? r : 0;
499 static int parse_proc_cmdline(void) {
500 _cleanup_free_ char *line = NULL;
505 r = proc_cmdline(&line);
507 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
511 FOREACH_WORD_QUOTED(w, l, line, state) {
512 _cleanup_free_ char *word = NULL;
514 word = strndup(w, l);
518 if (startswith(word, "fstab=")) {
519 r = parse_boolean(word + 6);
521 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
525 } else if (startswith(word, "rd.fstab=")) {
528 r = parse_boolean(word + 9);
530 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9);
535 } else if (startswith(word, "fstab.") ||
536 (in_initrd() && startswith(word, "rd.fstab."))) {
538 log_warning("Unknown kernel switch %s. Ignoring.", word);
545 int main(int argc, char *argv[]) {
548 if (argc > 1 && argc != 4) {
549 log_error("This program takes three or no arguments.");
556 log_set_target(LOG_TARGET_SAFE);
557 log_parse_environment();
562 if (parse_proc_cmdline() < 0)
566 r = parse_new_root_from_proc_cmdline();
569 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
571 k = parse_fstab(NULL, false);
574 l = parse_fstab("/sysroot", true);
576 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;