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 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
84 _cleanup_fclose_ FILE *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", f);
121 if (!noauto && !nofail)
122 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
137 log_error("Failed to write unit file %s: %m", unit);
142 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
146 mkdir_parents_label(lnk, 0755);
147 if (symlink(unit, lnk) < 0) {
148 log_error("Failed to create symlink %s: %m", lnk);
152 r = device_name(what, &device);
158 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
162 mkdir_parents_label(lnk, 0755);
163 if (symlink(unit, lnk) < 0) {
164 log_error("Failed to create symlink %s: %m", lnk);
173 static bool mount_is_network(struct mntent *me) {
177 hasmntopt(me, "_netdev") ||
178 fstype_is_network(me->mnt_type);
181 static bool mount_in_initrd(struct mntent *me) {
185 hasmntopt(me, "x-initrd.mount") ||
186 streq(me->mnt_dir, "/usr");
189 static int add_mount(
199 const char *source) {
201 *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL,
202 *automount_name = NULL, *automount_unit = NULL;
203 _cleanup_fclose_ FILE *f = NULL;
211 if (streq(type, "autofs"))
214 if (!is_path(where)) {
215 log_warning("Mount point %s is not a valid path, ignoring.", where);
219 if (mount_point_is_api(where) ||
220 mount_point_ignore(where))
223 name = unit_name_from_path(where, ".mount");
227 unit = strjoin(arg_dest, "/", name, NULL);
231 f = fopen(unit, "wxe");
234 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
236 log_error("Failed to create unit file %s: %m", unit);
241 "# Automatically generated by systemd-fstab-generator\n\n"
246 if (post && !noauto && !nofail && !automount)
263 if (!isempty(opts) &&
264 !streq(opts, "defaults"))
271 log_error("Failed to write unit file %s: %m", unit);
277 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
281 mkdir_parents_label(lnk, 0755);
282 if (symlink(unit, lnk) < 0) {
283 log_error("Failed to create symlink %s: %m", lnk);
289 if (automount && !path_equal(where, "/")) {
290 automount_name = unit_name_from_path(where, ".automount");
294 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
299 f = fopen(automount_unit, "wxe");
301 log_error("Failed to create unit file %s: %m", automount_unit);
306 "# Automatically generated by systemd-fstab-generator\n\n"
323 log_error("Failed to write unit file %s: %m", automount_unit);
328 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
332 mkdir_parents_label(lnk, 0755);
333 if (symlink(automount_unit, lnk) < 0) {
334 log_error("Failed to create symlink %s: %m", lnk);
342 static int parse_fstab(const char *prefix, bool initrd) {
343 _cleanup_free_ char *fstab_path = NULL;
348 fstab_path = strjoin(strempty(prefix), "/etc/fstab", NULL);
352 f = setmntent(fstab_path, "r");
357 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix));
361 while ((me = getmntent(f))) {
362 _cleanup_free_ char *where = NULL, *what = NULL;
365 if (initrd && !mount_in_initrd(me))
368 what = fstab_node_to_udev_node(me->mnt_fsname);
369 where = strjoin(strempty(prefix), me->mnt_dir, NULL);
370 if (!what || !where) {
376 path_kill_slashes(where);
378 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
380 if (streq(me->mnt_type, "swap"))
381 k = add_swap(what, me);
383 bool noauto, nofail, automount;
386 noauto = !!hasmntopt(me, "noauto");
387 nofail = !!hasmntopt(me, "nofail");
389 hasmntopt(me, "comment=systemd.automount") ||
390 hasmntopt(me, "x-systemd.automount");
393 post = SPECIAL_INITRD_FS_TARGET;
394 } else if (mount_in_initrd(me)) {
395 post = SPECIAL_INITRD_ROOT_FS_TARGET;
396 } else if (mount_is_network(me)) {
397 post = SPECIAL_REMOTE_FS_TARGET;
399 post = SPECIAL_LOCAL_FS_TARGET;
402 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
403 me->mnt_passno, noauto, nofail, automount,
416 static int parse_new_root_from_proc_cmdline(void) {
417 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
423 r = read_one_line_file("/proc/cmdline", &line);
425 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
430 type = strdup("auto");
434 /* root= and roofstype= may occur more than once, the last instance should take precedence.
435 * In the case of multiple rootflags= the arguments should be concatenated */
436 FOREACH_WORD_QUOTED(w, l, line, state) {
437 _cleanup_free_ char *word;
439 word = strndup(w, l);
443 else if (startswith(word, "root=")) {
445 what = fstab_node_to_udev_node(word+5);
449 } else if (startswith(word, "rootfstype=")) {
451 type = strdup(word + 11);
455 } else if (startswith(word, "rootflags=")) {
458 o = strjoin(opts, ",", word + 10, NULL);
465 } else if (streq(word, "ro") || streq(word, "rw")) {
468 o = strjoin(opts, ",", word, NULL);
477 noauto = !!strstr(opts, "noauto");
478 nofail = !!strstr(opts, "nofail");
481 log_debug("Could not find a root= entry on the kernel commandline.");
485 if (what[0] != '/') {
486 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
490 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
491 r = add_mount(what, "/sysroot", type, opts, 0, noauto, nofail, false,
492 SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
494 return (r < 0) ? r : 0;
497 static int parse_proc_cmdline(void) {
498 _cleanup_free_ char *line = NULL;
503 if (detect_container(NULL) > 0)
506 r = read_one_line_file("/proc/cmdline", &line);
508 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
512 FOREACH_WORD_QUOTED(w, l, line, state) {
513 _cleanup_free_ char *word = NULL;
515 word = strndup(w, l);
519 if (startswith(word, "fstab=")) {
520 r = parse_boolean(word + 6);
522 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
526 } else if (startswith(word, "rd.fstab=")) {
529 r = parse_boolean(word + 9);
531 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9);
536 } else if (startswith(word, "fstab.") ||
537 (in_initrd() && startswith(word, "rd.fstab."))) {
539 log_warning("Unknown kernel switch %s. Ignoring.", word);
546 int main(int argc, char *argv[]) {
549 if (argc > 1 && argc != 4) {
550 log_error("This program takes three or no arguments.");
557 log_set_target(LOG_TARGET_SAFE);
558 log_parse_environment();
563 if (parse_proc_cmdline() < 0)
567 r = parse_new_root_from_proc_cmdline();
570 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
572 k = parse_fstab(NULL, false);
575 l = parse_fstab("/sysroot", true);
577 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;