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_bind(struct mntent *me) {
177 hasmntopt(me, "bind") ||
178 streq(me->mnt_type, "bind") ||
179 hasmntopt(me, "rbind") ||
180 streq(me->mnt_type, "rbind");
183 static bool mount_is_network(struct mntent *me) {
187 hasmntopt(me, "_netdev") ||
188 fstype_is_network(me->mnt_type);
191 static bool mount_in_initrd(struct mntent *me) {
195 hasmntopt(me, "x-initrd.mount") ||
196 streq(me->mnt_dir, "/usr");
199 static int add_mount(
210 const char *source) {
212 *name = NULL, *unit = NULL, *lnk = NULL, *device = 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)
275 if (!isempty(opts) &&
276 !streq(opts, "defaults"))
283 log_error("Failed to write unit file %s: %m", unit);
289 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
293 mkdir_parents_label(lnk, 0755);
294 if (symlink(unit, lnk) < 0) {
295 log_error("Failed to create symlink %s: %m", lnk);
301 !path_equal(where, "/")) {
303 r = device_name(what, &device);
309 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
313 mkdir_parents_label(lnk, 0755);
314 if (symlink(unit, lnk) < 0) {
315 log_error("Failed to create symlink %s: %m", lnk);
322 if (automount && !path_equal(where, "/")) {
323 automount_name = unit_name_from_path(where, ".automount");
327 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
332 f = fopen(automount_unit, "wxe");
334 log_error("Failed to create unit file %s: %m", automount_unit);
339 "# Automatically generated by systemd-fstab-generator\n\n"
356 log_error("Failed to write unit file %s: %m", automount_unit);
361 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
365 mkdir_parents_label(lnk, 0755);
366 if (symlink(automount_unit, lnk) < 0) {
367 log_error("Failed to create symlink %s: %m", lnk);
375 static int parse_fstab(const char *prefix, bool initrd) {
376 _cleanup_free_ char *fstab_path = NULL;
381 fstab_path = strjoin(strempty(prefix), "/etc/fstab", NULL);
385 f = setmntent(fstab_path, "r");
390 log_error("Failed to open %s/etc/fstab: %m", strempty(prefix));
394 while ((me = getmntent(f))) {
395 _cleanup_free_ char *where = NULL, *what = NULL;
398 if (initrd && !mount_in_initrd(me))
401 what = fstab_node_to_udev_node(me->mnt_fsname);
402 where = strjoin(strempty(prefix), me->mnt_dir, NULL);
403 if (!what || !where) {
409 path_kill_slashes(where);
411 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
413 if (streq(me->mnt_type, "swap"))
414 k = add_swap(what, me);
416 bool noauto, nofail, automount, isbind;
419 noauto = !!hasmntopt(me, "noauto");
420 nofail = !!hasmntopt(me, "nofail");
422 hasmntopt(me, "comment=systemd.automount") ||
423 hasmntopt(me, "x-systemd.automount");
424 isbind = mount_is_bind(me);
427 post = SPECIAL_INITRD_FS_TARGET;
428 } else if (mount_in_initrd(me)) {
429 post = SPECIAL_INITRD_ROOT_FS_TARGET;
430 } else if (mount_is_network(me)) {
431 post = SPECIAL_REMOTE_FS_TARGET;
433 post = SPECIAL_LOCAL_FS_TARGET;
436 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
437 me->mnt_passno, noauto, nofail, automount,
438 isbind, post, fstab_path);
450 static int parse_new_root_from_proc_cmdline(void) {
451 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
457 r = read_one_line_file("/proc/cmdline", &line);
459 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
464 type = strdup("auto");
468 /* root= and roofstype= may occur more than once, the last instance should take precedence.
469 * In the case of multiple rootflags= the arguments should be concatenated */
470 FOREACH_WORD_QUOTED(w, l, line, state) {
471 _cleanup_free_ char *word;
473 word = strndup(w, l);
477 else if (startswith(word, "root=")) {
479 what = fstab_node_to_udev_node(word+5);
483 } else if (startswith(word, "rootfstype=")) {
485 type = strdup(word + 11);
489 } else if (startswith(word, "rootflags=")) {
492 o = strjoin(opts, ",", word + 10, NULL);
499 } else if (streq(word, "ro") || streq(word, "rw")) {
502 o = strjoin(opts, ",", word, NULL);
511 noauto = !!strstr(opts, "noauto");
512 nofail = !!strstr(opts, "nofail");
515 log_debug("Could not find a root= entry on the kernel commandline.");
519 if (what[0] != '/') {
520 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, type);
524 log_debug("Found entry what=%s where=/sysroot type=%s", what, type);
525 r = add_mount(what, "/sysroot", type, opts, 0, noauto, nofail, false,
526 false, SPECIAL_INITRD_ROOT_FS_TARGET, "/proc/cmdline");
528 return (r < 0) ? r : 0;
531 static int parse_proc_cmdline(void) {
532 _cleanup_free_ char *line = NULL;
537 if (detect_container(NULL) > 0)
540 r = read_one_line_file("/proc/cmdline", &line);
542 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
546 FOREACH_WORD_QUOTED(w, l, line, state) {
547 _cleanup_free_ char *word = NULL;
549 word = strndup(w, l);
553 if (startswith(word, "fstab=")) {
554 r = parse_boolean(word + 6);
556 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
560 } else if (startswith(word, "rd.fstab=")) {
563 r = parse_boolean(word + 9);
565 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 9);
570 } else if (startswith(word, "fstab.") ||
571 (in_initrd() && startswith(word, "rd.fstab."))) {
573 log_warning("Unknown kernel switch %s. Ignoring.", word);
580 int main(int argc, char *argv[]) {
583 if (argc > 1 && argc != 4) {
584 log_error("This program takes three or no arguments.");
591 log_set_target(LOG_TARGET_SAFE);
592 log_parse_environment();
597 if (parse_proc_cmdline() < 0)
601 r = parse_new_root_from_proc_cmdline();
604 return (r < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
606 k = parse_fstab(NULL, false);
609 l = parse_fstab("/sysroot", true);
611 return (r < 0) || (k < 0) || (l < 0) ? EXIT_FAILURE : EXIT_SUCCESS;