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 char _cleanup_free_ *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
84 FILE _cleanup_fclose_ *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"
120 "DefaultDependencies=no\n"
121 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
122 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
124 if (!noauto && !nofail)
125 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
140 log_error("Failed to write unit file %s: %m", unit);
145 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
149 mkdir_parents_label(lnk, 0755);
150 if (symlink(unit, lnk) < 0) {
151 log_error("Failed to create symlink %s: %m", lnk);
155 r = device_name(what, &device);
161 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
165 mkdir_parents_label(lnk, 0755);
166 if (symlink(unit, lnk) < 0) {
167 log_error("Failed to create symlink %s: %m", lnk);
176 static bool mount_is_bind(struct mntent *me) {
180 hasmntopt(me, "bind") ||
181 streq(me->mnt_type, "bind");
184 static bool mount_is_network(struct mntent *me) {
188 hasmntopt(me, "_netdev") ||
189 fstype_is_network(me->mnt_type);
192 static int add_mount(const char *what, const char *where, const char *type, const char *opts,
193 int passno, bool wait, bool noauto, bool nofail, bool automount, bool isbind, bool isnetwork,
194 const char *source) {
196 *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL,
197 *automount_name = NULL, *automount_unit = NULL;
198 FILE _cleanup_fclose_ *f = NULL;
200 const char *post, *pre;
208 if (streq(type, "autofs"))
211 if (!is_path(where)) {
212 log_warning("Mount point %s is not a valid path, ignoring.", where);
216 if (mount_point_is_api(where) ||
217 mount_point_ignore(where))
221 post = SPECIAL_REMOTE_FS_TARGET;
222 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
224 post = SPECIAL_LOCAL_FS_TARGET;
225 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
228 name = unit_name_from_path(where, ".mount");
232 unit = strjoin(arg_dest, "/", name, NULL);
236 f = fopen(unit, "wxe");
239 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
241 log_error("Failed to create unit file %s: %m", unit);
246 "# Automatically generated by systemd-fstab-generator\n\n"
249 "DefaultDependencies=no\n",
252 if (!path_equal(where, "/"))
256 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
257 "Before=" SPECIAL_UMOUNT_TARGET "\n",
262 if (!noauto && !nofail && !automount)
279 if (!isempty(opts) &&
280 !streq(opts, "defaults"))
291 log_error("Failed to write unit file %s: %m", unit);
296 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
300 mkdir_parents_label(lnk, 0755);
301 if (symlink(unit, lnk) < 0) {
302 log_error("Failed to create symlink %s: %m", lnk);
307 !path_equal(where, "/")) {
309 r = device_name(what, &device);
315 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
319 mkdir_parents_label(lnk, 0755);
320 if (symlink(unit, lnk) < 0) {
321 log_error("Failed to create symlink %s: %m", lnk);
328 if (automount && !path_equal(where, "/")) {
329 automount_name = unit_name_from_path(where, ".automount");
333 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
338 f = fopen(automount_unit, "wxe");
340 log_error("Failed to create unit file %s: %m", automount_unit);
345 "# Automatically generated by systemd-fstab-generator\n\n"
347 "SourcePath=/etc/fstab\n"
348 "DefaultDependencies=no\n"
349 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
350 "Before=" SPECIAL_UMOUNT_TARGET " %s\n"
359 log_error("Failed to write unit file %s: %m", automount_unit);
364 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
368 mkdir_parents_label(lnk, 0755);
369 if (symlink(automount_unit, lnk) < 0) {
370 log_error("Failed to create symlink %s: %m", lnk);
378 static int parse_fstab(void) {
384 f = setmntent("/etc/fstab", "r");
389 log_error("Failed to open /etc/fstab: %m");
393 while ((me = getmntent(f))) {
394 char _cleanup_free_ *where = NULL, *what = NULL;
397 what = fstab_node_to_udev_node(me->mnt_fsname);
398 where = strdup(me->mnt_dir);
399 if (!what || !where) {
405 path_kill_slashes(where);
407 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
409 if (streq(me->mnt_type, "swap"))
410 k = add_swap(what, me);
412 bool noauto, nofail, automount, isbind, isnetwork;
414 noauto = !!hasmntopt(me, "noauto");
415 nofail = !!hasmntopt(me, "nofail");
417 hasmntopt(me, "comment=systemd.automount") ||
418 hasmntopt(me, "x-systemd.automount");
419 isbind = mount_is_bind(me);
420 isnetwork = mount_is_network(me);
422 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
423 me->mnt_passno, false, noauto, nofail,
424 automount, isbind, isnetwork,
437 static int parse_new_root_from_proc_cmdline(void) {
439 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
444 r = read_one_line_file("/proc/cmdline", &line);
446 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
450 opts = strdup("defaults");
451 type = strdup("auto");
455 /* root= and roofstype= may occur more than once, the last instance should take precedence.
456 * In the case of multiple rootflags= the arguments should be concatenated */
457 FOREACH_WORD_QUOTED(w, l, line, state) {
458 char *word, *tmp_word;
460 word = strndup(w, l);
464 else if (startswith(word, "root=")) {
466 what = fstab_node_to_udev_node(word+5);
470 } else if (startswith(word, "rootfstype=")) {
472 type = strdup(word + 11);
476 } else if (startswith(word, "rootflags=")) {
478 opts = strjoin(opts, ",", word + 10, NULL);
483 } else if (streq(word, "ro") || streq(word, "rw")) {
485 opts = strjoin(opts, ",", word, NULL);
490 } else if (streq(word, "rootwait"))
498 log_debug("Found entry what=%s where=/new_root type=%s", what, type);
499 r = add_mount(what, "/new_root", type, opts, 0, wait, false, false,
500 false, false, false, "/proc/cmdline");
505 log_error("Could not find a root= entry on the kernel commandline.");
510 static int parse_proc_cmdline(void) {
511 char _cleanup_free_ *line = NULL;
516 if (detect_container(NULL) > 0)
519 r = read_one_line_file("/proc/cmdline", &line);
521 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
525 FOREACH_WORD_QUOTED(w, l, line, state) {
526 char _cleanup_free_ *word = NULL;
528 word = strndup(w, l);
532 if (startswith(word, "fstab=")) {
533 r = parse_boolean(word + 6);
535 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
539 } else if (startswith(word, "rd.fstab=")) {
542 r = parse_boolean(word + 6);
544 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
549 } else if (startswith(word, "fstab.") ||
550 (in_initrd() && startswith(word, "rd.fstab."))) {
552 log_warning("Unknown kernel switch %s. Ignoring.", word);
559 int main(int argc, char *argv[]) {
562 if (argc > 1 && argc != 4) {
563 log_error("This program takes three or no arguments.");
570 log_set_target(LOG_TARGET_SAFE);
571 log_parse_environment();
576 if (parse_proc_cmdline() < 0)
580 k = parse_new_root_from_proc_cmdline();
587 return (r < 0) || (k < 0) ? EXIT_FAILURE : EXIT_SUCCESS;