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 _cleanup_free_ *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL;
83 FILE _cleanup_fclose_ *f = 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");
103 unit = strjoin(arg_dest, "/", name, NULL);
107 f = fopen(unit, "wxe");
110 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
112 log_error("Failed to create unit file %s: %m", unit);
116 fputs("# Automatically generated by systemd-fstab-generator\n\n"
118 "SourcePath=/etc/fstab\n"
119 "DefaultDependencies=no\n"
120 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
121 "Before=" SPECIAL_UMOUNT_TARGET "\n", f);
123 if (!noauto && !nofail)
124 fputs("Before=" SPECIAL_SWAP_TARGET "\n", f);
139 log_error("Failed to write unit file %s: %m", unit);
144 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
148 mkdir_parents_label(lnk, 0755);
149 if (symlink(unit, lnk) < 0) {
150 log_error("Failed to create symlink %s: %m", lnk);
154 r = device_name(what, &device);
160 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
164 mkdir_parents_label(lnk, 0755);
165 if (symlink(unit, lnk) < 0) {
166 log_error("Failed to create symlink %s: %m", lnk);
175 static bool mount_is_bind(struct mntent *me) {
179 hasmntopt(me, "bind") ||
180 streq(me->mnt_type, "bind");
183 static bool mount_is_network(struct mntent *me) {
187 hasmntopt(me, "_netdev") ||
188 fstype_is_network(me->mnt_type);
191 static int add_mount(const char *what, const char *where, const char *type, const char *opts,
192 int passno, bool wait, bool noauto, bool nofail, bool automount, bool isbind, bool isnetwork,
193 const char *source) {
195 *name = NULL, *unit = NULL, *lnk = NULL, *device = NULL,
196 *automount_name = NULL, *automount_unit = NULL;
197 FILE _cleanup_fclose_ *f = NULL;
199 const char *post, *pre;
207 if (streq(type, "autofs"))
210 if (!is_path(where)) {
211 log_warning("Mount point %s is not a valid path, ignoring.", where);
215 if (mount_point_is_api(where) ||
216 mount_point_ignore(where))
220 post = SPECIAL_REMOTE_FS_TARGET;
221 pre = SPECIAL_REMOTE_FS_PRE_TARGET;
223 post = SPECIAL_LOCAL_FS_TARGET;
224 pre = SPECIAL_LOCAL_FS_PRE_TARGET;
227 name = unit_name_from_path(where, ".mount");
231 unit = strjoin(arg_dest, "/", name, NULL);
235 f = fopen(unit, "wxe");
238 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
240 log_error("Failed to create unit file %s: %m", unit);
245 "# Automatically generated by systemd-fstab-generator\n\n"
248 "DefaultDependencies=no\n",
251 if (!path_equal(where, "/"))
255 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
256 "Before=" SPECIAL_UMOUNT_TARGET "\n",
261 if (!noauto && !nofail && !automount)
278 if (!isempty(opts) &&
279 !streq(opts, "defaults"))
290 log_error("Failed to write unit file %s: %m", unit);
295 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
299 mkdir_parents_label(lnk, 0755);
300 if (symlink(unit, lnk) < 0) {
301 log_error("Failed to create symlink %s: %m", lnk);
306 !path_equal(where, "/")) {
308 r = device_name(what, &device);
314 lnk = strjoin(arg_dest, "/", device, ".wants/", name, NULL);
318 mkdir_parents_label(lnk, 0755);
319 if (symlink(unit, lnk) < 0) {
320 log_error("Failed to create symlink %s: %m", lnk);
327 if (automount && !path_equal(where, "/")) {
328 automount_name = unit_name_from_path(where, ".automount");
332 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
337 f = fopen(automount_unit, "wxe");
339 log_error("Failed to create unit file %s: %m", automount_unit);
344 "# Automatically generated by systemd-fstab-generator\n\n"
346 "SourcePath=/etc/fstab\n"
347 "DefaultDependencies=no\n"
348 "Conflicts=" SPECIAL_UMOUNT_TARGET "\n"
349 "Before=" SPECIAL_UMOUNT_TARGET " %s\n"
358 log_error("Failed to write unit file %s: %m", automount_unit);
363 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
367 mkdir_parents_label(lnk, 0755);
368 if (symlink(automount_unit, lnk) < 0) {
369 log_error("Failed to create symlink %s: %m", lnk);
377 static int parse_fstab(void) {
383 f = setmntent("/etc/fstab", "r");
388 log_error("Failed to open /etc/fstab: %m");
392 while ((me = getmntent(f))) {
393 char _cleanup_free_ *where = NULL, *what = NULL;
396 what = fstab_node_to_udev_node(me->mnt_fsname);
397 where = strdup(me->mnt_dir);
398 if (!what || !where) {
404 path_kill_slashes(where);
406 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
408 if (streq(me->mnt_type, "swap"))
409 k = add_swap(what, me);
411 bool noauto, nofail, automount, isbind, isnetwork;
413 noauto = !!hasmntopt(me, "noauto");
414 nofail = !!hasmntopt(me, "nofail");
416 hasmntopt(me, "comment=systemd.automount") ||
417 hasmntopt(me, "x-systemd.automount");
418 isbind = mount_is_bind(me);
419 isnetwork = mount_is_network(me);
421 k = add_mount(what, where, me->mnt_type, me->mnt_opts,
422 me->mnt_passno, false, noauto, nofail,
423 automount, isbind, isnetwork,
436 static int parse_new_root_from_proc_cmdline(void) {
438 _cleanup_free_ char *what = NULL, *type = NULL, *opts = NULL, *line = NULL;
443 r = read_one_line_file("/proc/cmdline", &line);
445 log_error("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
449 opts = strdup("defaults");
450 type = strdup("auto");
454 /* root= and roofstype= may occur more than once, the last instance should take precedence.
455 * In the case of multiple rootflags= the arguments should be concatenated */
456 FOREACH_WORD_QUOTED(w, l, line, state) {
457 char *word, *tmp_word;
459 word = strndup(w, l);
463 else if (startswith(word, "root=")) {
465 what = fstab_node_to_udev_node(word+5);
469 } else if (startswith(word, "rootfstype=")) {
471 type = strdup(word + 11);
475 } else if (startswith(word, "rootflags=")) {
477 opts = strjoin(opts, ",", word + 10, NULL);
482 } else if (streq(word, "ro") || streq(word, "rw")) {
484 opts = strjoin(opts, ",", word, NULL);
489 } else if (streq(word, "rootwait"))
497 log_debug("Found entry what=%s where=/new_root type=%s", what, type);
498 r = add_mount(what, "/new_root", type, opts, 0, wait, false, false,
499 false, false, false, "/proc/cmdline");
504 log_error("Could not find a root= entry on the kernel commandline.");
509 static int parse_proc_cmdline(void) {
510 char _cleanup_free_ *line = NULL;
515 if (detect_container(NULL) > 0)
518 r = read_one_line_file("/proc/cmdline", &line);
520 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
524 FOREACH_WORD_QUOTED(w, l, line, state) {
525 char _cleanup_free_ *word = NULL;
527 word = strndup(w, l);
531 if (startswith(word, "fstab=")) {
532 r = parse_boolean(word + 6);
534 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
538 } else if (startswith(word, "rd.fstab=")) {
541 r = parse_boolean(word + 6);
543 log_warning("Failed to parse fstab switch %s. Ignoring.", word + 6);
548 } else if (startswith(word, "fstab.") ||
549 (in_initrd() && startswith(word, "rd.fstab."))) {
551 log_warning("Unknown kernel switch %s. Ignoring.", word);
558 int main(int argc, char *argv[]) {
561 if (argc > 1 && argc != 4) {
562 log_error("This program takes three or no arguments.");
569 log_set_target(LOG_TARGET_SAFE);
570 log_parse_environment();
575 if (parse_proc_cmdline() < 0)
579 k = parse_new_root_from_proc_cmdline();
586 return (r < 0) || (k < 0) ? EXIT_FAILURE : EXIT_SUCCESS;