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 device_name(const char *path, char **unit) {
45 if (!is_device_path(path))
48 p = unit_name_from_path(path, ".device");
56 static int mount_find_pri(struct mntent *me, int *ret) {
63 pri = hasmntopt(me, "pri");
70 r = strtoul(pri, &end, 10);
74 if (end == pri || (*end != ',' && *end != 0))
81 static int add_swap(const char *what, struct mntent *me) {
82 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
90 r = mount_find_pri(me, &pri);
92 log_error("Failed to parse priority");
96 noauto = !!hasmntopt(me, "noauto");
97 nofail = !!hasmntopt(me, "nofail");
99 name = unit_name_from_path(what, ".swap");
105 unit = strjoin(arg_dest, "/", name, NULL);
111 f = fopen(unit, "wxe");
115 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
117 log_error("Failed to create unit file %s: %m", unit);
121 fputs("# Automatically generated by systemd-fstab-generator\n\n"
123 "SourcePath=/etc/fstab\n"
124 "DefaultDependencies=no\n"
125 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
126 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
128 if (!noauto && !nofail)
129 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
144 log_error("Failed to write unit file %s: %m", unit);
150 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
156 mkdir_parents_label(lnk, 0755);
157 if (symlink(unit, lnk) < 0) {
158 log_error("Failed to create symlink %s: %m", lnk);
163 r = device_name(what, &device);
169 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
175 mkdir_parents_label(lnk, 0755);
176 if (symlink(unit, lnk) < 0) {
177 log_error("Failed to create symlink %s: %m", lnk);
197 static bool mount_is_bind(struct mntent *me) {
201 hasmntopt(me, "bind") ||
202 streq(me->mnt_type, "bind");
205 static bool mount_is_network(struct mntent *me) {
209 hasmntopt(me, "_netdev") ||
210 fstype_is_network(me->mnt_type);
213 static int add_mount(const char *what, const char *where, const char *type, const char *opts,
214 int passno, bool wait, bool noauto, bool nofail, bool automount, bool isbind, bool isnetwork,
215 const char *source) {
216 char *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL, *automount_name = NULL, *automount_unit = NULL;
219 const char *post, *pre;
227 if (streq(type, "autofs"))
230 if (!is_path(where)) {
231 log_warning("Mount point %s is not a valid path, ignoring.", where);
235 if (mount_point_is_api(where) ||
236 mount_point_ignore(where))
240 post = SPECIAL_REMOTE_FS_TARGET;
241 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
243 post = SPECIAL_LOCAL_FS_TARGET;
244 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
247 name = unit_name_from_path(where, ".mount");
253 unit = strjoin(arg_dest, "/", name, NULL);
259 f = fopen(unit, "wxe");
263 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
265 log_error("Failed to create unit file %s: %m", unit);
270 "# Automatically generated by systemd-fstab-generator\n\n"
273 "DefaultDependencies=no\n",
276 if (!path_equal(where, "/"))
280 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
281 "Before=" SPECIAL_UMOUNT_TARGET "\n",
286 if (!noauto && !nofail && !automount)
303 if (!isempty(opts) &&
304 !streq(opts, "defaults"))
315 log_error("Failed to write unit file %s: %m", unit);
321 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
327 mkdir_parents_label(lnk, 0755);
328 if (symlink(unit, lnk) < 0) {
329 log_error("Failed to create symlink %s: %m", lnk);
335 !path_equal(where, "/")) {
337 r = device_name(what, &device);
343 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
349 mkdir_parents_label(lnk, 0755);
350 if (symlink(unit, lnk) < 0) {
351 log_error("Failed to create symlink %s: %m", lnk);
359 if (automount && !path_equal(where, "/")) {
360 automount_name = unit_name_from_path(where, ".automount");
366 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
367 if (!automount_unit) {
373 f = fopen(automount_unit, "wxe");
376 log_error("Failed to create unit file %s: %m", automount_unit);
381 "# Automatically generated by systemd-fstab-generator\n\n"
383 "SourcePath=/etc/fstab\n"
384 "DefaultDependencies=no\n"
385 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
386 "Before=" SPECIAL_UMOUNT_TARGET " %s\n"
395 log_error("Failed to write unit file %s: %m", automount_unit);
401 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
407 mkdir_parents_label(lnk, 0755);
408 if (symlink(automount_unit, lnk) < 0) {
409 log_error("Failed to create symlink %s: %m", lnk);
424 free(automount_name);
425 free(automount_unit);
430 static int parse_fstab(void) {
436 f = setmntent("/etc/fstab", "r");
441 log_error("Failed to open /etc/fstab: %m");
445 while ((me = getmntent(f))) {
449 what = fstab_node_to_udev_node(me->mnt_fsname);
455 where = strdup(me->mnt_dir);
463 path_kill_slashes(where);
465 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
467 if (streq(me->mnt_type, "swap"))
468 k = add_swap(what, me);
470 bool noauto, nofail, automount, isbind, isnetwork;
472 noauto = !!hasmntopt(me, "noauto");
473 nofail = !!hasmntopt(me, "nofail");
475 hasmntopt(me, "comment=systemd.automount") ||
476 hasmntopt(me, "x-systemd.automount");
477 isbind = mount_is_bind(me);
478 isnetwork = mount_is_network(me);
480 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
481 me->mnt_passno, false, noauto, nofail,
482 automount, isbind, isnetwork,
498 static int parse_new_root_from_proc_cmdline(void) {
500 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
505 r = read_one_line_file("/proc/cmdline", &line);
507 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
511 opts = strdup("defaults");
514 type = strdup("auto");
518 /* root= and roofstype= may occur more than once, the last instance should take precedence.
519 * In the case of multiple rootflags= the arguments should be concatenated */
520 FOREACH_WORD_QUOTED(w, l, line, state) {
521 char *word, *tmp_word;
523 word = strndup(w, l);
527 else if (startswith(word, "root=")) {
529 what = fstab_node_to_udev_node(word+5);
533 } else if (startswith(word, "rootfstype=")) {
535 type = strdup(word + 11);
539 } else if (startswith(word, "rootflags=")) {
541 opts = strjoin(opts, ",", word + 10, NULL);
546 } else if (streq(word, "ro") || streq(word, "rw")) {
548 opts = strjoin(opts, ",", word, NULL);
553 } else if (streq(word, "rootwait"))
561 log_debug("Found entry what=%s where=/new_root type=%s", what, type);
562 r = add_mount(what, "/new_root", type, opts, 0, wait, false, false,
563 false, false, false, "/proc/cmdline");
568 log_error("Could not find a root= entry on the kernel commandline.");
573 static int parse_proc_cmdline(void) {
574 char *line, *w, *state;
578 if (detect_container(NULL) > 0)
581 r = read_one_line_file("/proc/cmdline", &line);
583 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
587 FOREACH_WORD_QUOTED(w, l, line, state) {
590 word = strndup(w, l);
596 if (startswith(word, "fstab=")) {
597 r = parse_boolean(word + 6);
599 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
603 } else if (startswith(word, "rd.fstab=")) {
606 r = parse_boolean(word + 6);
608 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
613 } else if (startswith(word, "fstab.") ||
614 (in_initrd() && startswith(word, "rd.fstab."))) {
616 log_warning("Unknown kernel switch %s. Ignoring.", word);
629 int main(int argc, char *argv[]) {
632 if (argc > 1 && argc != 4) {
633 log_error("This program takes three or no arguments.");
640 log_set_target(LOG_TARGET_SAFE);
641 log_parse_environment();
646 if (parse_proc_cmdline() < 0)
650 k = parse_new_root_from_proc_cmdline();
657 return (r < 0) || (k < 0) ? EXIT_FAILURE : EXIT_SUCCESS;