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 (!is_device_path(what)) {
156 log_warning("Checking was requested for \"%s\", but it is not a device.", what);
160 if (type && !streq(type, "auto")) {
164 checker = strappenda("/sbin/fsck.", type);
165 r = access(checker, X_OK);
167 log_warning("Checking was requested for %s, but %s cannot be used: %m", what, checker);
169 /* treat missing check as essentially OK */
170 return errno == ENOENT ? 0 : -errno;
174 if (streq(where, "/")) {
177 lnk = strappenda(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
178 mkdir_parents_label(lnk, 0755);
179 if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0) {
180 log_error("Failed to create symlink %s: %m", lnk);
184 _cleanup_free_ char *fsck = NULL;
186 fsck = unit_name_from_path_instance("systemd-fsck", what, ".service");
191 "RequiresOverridable=%s\n"
200 static int add_mount(
210 const char *source) {
212 *name = NULL, *unit = NULL, *lnk = NULL,
213 *automount_name = NULL, *automount_unit = NULL;
214 _cleanup_fclose_ FILE *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"
258 if (post && !noauto && !nofail && !automount)
263 r = add_fsck(f, what, where, type, passno);
277 if (!isempty(opts) &&
278 !streq(opts, "defaults"))
285 log_error("Failed to write unit file %s: %m", unit);
291 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
295 mkdir_parents_label(lnk, 0755);
296 if (symlink(unit, lnk) < 0) {
297 log_error("Failed to create symlink %s: %m", lnk);
303 if (automount && !path_equal(where, "/")) {
304 automount_name = unit_name_from_path(where, ".automount");
308 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
313 f = fopen(automount_unit, "wxe");
315 log_error("Failed to create unit file %s: %m", automount_unit);
320 "# Automatically generated by systemd-fstab-generator\n\n"
337 log_error("Failed to write unit file %s: %m", automount_unit);
342 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
346 mkdir_parents_label(lnk, 0755);
347 if (symlink(automount_unit, lnk) < 0) {
348 log_error("Failed to create symlink %s: %m", lnk);
356 static int parse_fstab(const char *prefix, bool initrd) {
358 _cleanup_endmntent_ FILE *f;
362 fstab_path = strappenda(strempty(prefix), "/etc/fstab");
363 f = setmntent(fstab_path, "r");
368 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix));
372 while ((me = getmntent(f))) {
373 _cleanup_free_ char *where = NULL, *what = NULL;
376 if (initrd && !mount_in_initrd(me))
379 what = fstab_node_to_udev_node(me->mnt_fsname);
380 where = strjoin(strempty(prefix), me->mnt_dir, NULL);
385 path_kill_slashes(where);
387 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
389 if (streq(me->mnt_type, "swap"))
390 k = add_swap(what, me);
392 bool noauto, nofail, automount;
395 noauto = !!hasmntopt(me, "noauto");
396 nofail = !!hasmntopt(me, "nofail");
398 hasmntopt(me, "comment=systemd.automount") ||
399 hasmntopt(me, "x-systemd.automount");
402 post = SPECIAL_INITRD_FS_TARGET;
403 } else if (mount_in_initrd(me)) {
404 post = SPECIAL_INITRD_ROOT_FS_TARGET;
405 } else if (mount_is_network(me)) {
406 post = SPECIAL_REMOTE_FS_TARGET;
408 post = SPECIAL_LOCAL_FS_TARGET;
411 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
412 me->mnt_passno, noauto, nofail, automount,
423 static int parse_new_root_from_proc_cmdline(void) {
424 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
430 r = proc_cmdline(&line);
432 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
437 type = strdup("auto");
441 /* root= and roofstype= may occur more than once, the last instance should take precedence.
442 * In the case of multiple rootflags= the arguments should be concatenated */
443 FOREACH_WORD_QUOTED(w, l, line, state) {
444 _cleanup_free_ char *word;
446 word = strndup(w, l);
450 else if (startswith(word, "root=")) {
452 what = fstab_node_to_udev_node(word+5);
456 } else if (startswith(word, "rootfstype=")) {
458 type = strdup(word + 11);
462 } else if (startswith(word, "rootflags=")) {
465 o = strjoin(opts, ",", word + 10, NULL);
472 } else if (streq(word, "ro") || streq(word, "rw")) {
475 o = strjoin(opts, ",", word, NULL);
484 noauto = !!strstr(opts, "noauto");
485 nofail = !!strstr(opts, "nofail");
488 log_debug("Could not find a root= entry on the kernel commandline.");
492 if (what[0] != '/') {
493 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
497 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
498 r = add_mount(what, "/sysroot", type, opts, 1, noauto, nofail, false,
499 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
501 return (r < 0) ? r : 0;
504 static int parse_proc_cmdline_word(const char *word) {
507 if (startswith(word, "fstab=")) {
508 r = parse_boolean(word + 6);
510 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
514 } else if (startswith(word, "rd.fstab=")) {
517 r = parse_boolean(word + 9);
519 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9);
524 } else if (startswith(word, "fstab.") ||
525 (in_initrd() && startswith(word, "rd.fstab."))) {
527 log_warning("Unknown kernel switch %s. Ignoring.", word);
533 int main(int argc, char *argv[]) {
536 if (argc > 1 && argc != 4) {
537 log_error("This program takes three or no arguments.");
544 log_set_target(LOG_TARGET_SAFE);
545 log_parse_environment();
550 if (parse_proc_cmdline(parse_proc_cmdline_word) < 0)
554 r = parse_new_root_from_proc_cmdline();
557 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
559 k = parse_fstab(NULL, false);
562 l = parse_fstab("/sysroot", true);
564 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;