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 "fstab-util.h"
33 #include "mount-setup.h"
37 #include "generator.h"
41 static const char *arg_dest = "/tmp";
42 static bool arg_fstab_enabled = true;
43 static char *arg_root_what = NULL;
44 static char *arg_root_fstype = NULL;
45 static char *arg_root_options = NULL;
46 static int arg_root_rw = -1;
47 static char *arg_usr_what = NULL;
48 static char *arg_usr_fstype = NULL;
49 static char *arg_usr_options = NULL;
57 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
58 _cleanup_fclose_ FILE *f = NULL;
64 if (access("/proc/swaps", F_OK) < 0) {
65 log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
69 if (detect_container(NULL) > 0) {
70 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
74 r = fstab_find_pri(me->mnt_opts, &pri);
76 return log_error_errno(r, "Failed to parse priority: %m");
78 name = unit_name_from_path(what, ".swap");
82 unit = strjoin(arg_dest, "/", name, NULL);
86 f = fopen(unit, "wxe");
89 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
91 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
96 "# Automatically generated by systemd-fstab-generator\n\n"
98 "SourcePath=/etc/fstab\n"
99 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
104 /* Note that we currently pass the priority field twice, once
105 * in Priority=, and once in Options= */
107 fprintf(f, "Priority=%i\n", pri);
109 if (!isempty(me->mnt_opts) && !streq(me->mnt_opts, "defaults"))
110 fprintf(f, "Options=%s\n", me->mnt_opts);
112 r = fflush_and_check(f);
114 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
116 /* use what as where, to have a nicer error message */
117 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
122 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
123 nofail ? ".wants/" : ".requires/", name, NULL);
127 mkdir_parents_label(lnk, 0755);
128 if (symlink(unit, lnk) < 0)
129 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
135 static bool mount_is_network(struct mntent *me) {
139 hasmntopt(me, "_netdev") ||
140 fstype_is_network(me->mnt_type);
143 static bool mount_in_initrd(struct mntent *me) {
147 hasmntopt(me, "x-initrd.mount") ||
148 streq(me->mnt_dir, "/usr");
151 static int add_mount(
161 const char *source) {
164 *name = NULL, *unit = NULL, *lnk = NULL,
165 *automount_name = NULL, *automount_unit = NULL,
167 _cleanup_fclose_ FILE *f = NULL;
175 if (streq_ptr(fstype, "autofs"))
178 if (!is_path(where)) {
179 log_warning("Mount point %s is not a valid path, ignoring.", where);
183 if (mount_point_is_api(where) ||
184 mount_point_ignore(where))
187 if (path_equal(where, "/")) {
188 /* The root disk is not an option */
194 name = unit_name_from_path(where, ".mount");
198 unit = strjoin(arg_dest, "/", name, NULL);
202 f = fopen(unit, "wxe");
205 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
207 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
212 "# Automatically generated by systemd-fstab-generator\n\n"
215 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
218 if (post && !noauto && !nofail && !automount)
219 fprintf(f, "Before=%s\n", post);
222 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
235 if (!isempty(fstype) && !streq(fstype, "auto"))
236 fprintf(f, "Type=%s\n", fstype);
238 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
242 if (!isempty(filtered) && !streq(filtered, "defaults"))
243 fprintf(f, "Options=%s\n", filtered);
247 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
249 if (!noauto && post) {
250 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
254 mkdir_parents_label(lnk, 0755);
255 if (symlink(unit, lnk) < 0)
256 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
260 automount_name = unit_name_from_path(where, ".automount");
264 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
269 f = fopen(automount_unit, "wxe");
271 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
274 "# Automatically generated by systemd-fstab-generator\n\n"
277 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
292 return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
295 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
299 mkdir_parents_label(lnk, 0755);
300 if (symlink(automount_unit, lnk) < 0)
301 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
307 static int parse_fstab(bool initrd) {
308 _cleanup_endmntent_ FILE *f = NULL;
309 const char *fstab_path;
313 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
314 f = setmntent(fstab_path, "re");
319 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
323 while ((me = getmntent(f))) {
324 _cleanup_free_ char *where = NULL, *what = NULL;
328 if (initrd && !mount_in_initrd(me))
331 what = fstab_node_to_udev_node(me->mnt_fsname);
335 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
336 log_info("Running in a container, ignoring fstab device entry for %s.", what);
340 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
345 path_kill_slashes(where);
347 noauto = !!hasmntopt(me, "noauto");
348 nofail = !!hasmntopt(me, "nofail");
349 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
350 what, where, me->mnt_type,
351 yes_no(noauto), yes_no(nofail));
353 if (streq(me->mnt_type, "swap"))
354 k = add_swap(what, me, noauto, nofail);
360 hasmntopt(me, "comment=systemd.automount") ||
361 hasmntopt(me, "x-systemd.automount");
364 post = SPECIAL_INITRD_FS_TARGET;
365 else if (mount_in_initrd(me))
366 post = SPECIAL_INITRD_ROOT_FS_TARGET;
367 else if (mount_is_network(me))
368 post = SPECIAL_REMOTE_FS_TARGET;
370 post = SPECIAL_LOCAL_FS_TARGET;
391 static int add_root_mount(void) {
392 _cleanup_free_ char *what = NULL;
395 if (isempty(arg_root_what)) {
396 log_debug("Could not find a root= entry on the kernel command line.");
400 what = fstab_node_to_udev_node(arg_root_what);
401 if (!path_is_absolute(what)) {
402 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
406 if (!arg_root_options)
407 opts = arg_root_rw > 0 ? "rw" : "ro";
408 else if (arg_root_rw >= 0 ||
409 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
410 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
412 opts = arg_root_options;
414 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
415 return add_mount(what,
423 SPECIAL_INITRD_ROOT_FS_TARGET,
427 static int add_usr_mount(void) {
428 _cleanup_free_ char *what = NULL;
431 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
434 if (arg_root_what && !arg_usr_what) {
435 arg_usr_what = strdup(arg_root_what);
441 if (arg_root_fstype && !arg_usr_fstype) {
442 arg_usr_fstype = strdup(arg_root_fstype);
448 if (arg_root_options && !arg_usr_options) {
449 arg_usr_options = strdup(arg_root_options);
451 if (!arg_usr_options)
458 what = fstab_node_to_udev_node(arg_usr_what);
459 if (!path_is_absolute(what)) {
460 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
464 if (!arg_usr_options)
465 opts = arg_root_rw > 0 ? "rw" : "ro";
466 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
467 opts = strappenda(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
469 opts = arg_usr_options;
471 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
472 return add_mount(what,
480 SPECIAL_INITRD_ROOT_FS_TARGET,
484 static int parse_proc_cmdline_item(const char *key, const char *value) {
487 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
488 * instance should take precedence. In the case of multiple rootflags=
489 * or usrflags= the arguments should be concatenated */
491 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
493 r = parse_boolean(value);
495 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
497 arg_fstab_enabled = r;
499 } else if (streq(key, "root") && value) {
501 if (free_and_strdup(&arg_root_what, value) < 0)
504 } else if (streq(key, "rootfstype") && value) {
506 if (free_and_strdup(&arg_root_fstype, value) < 0)
509 } else if (streq(key, "rootflags") && value) {
512 o = arg_root_options ?
513 strjoin(arg_root_options, ",", value, NULL) :
518 free(arg_root_options);
519 arg_root_options = o;
521 } else if (streq(key, "mount.usr") && value) {
523 if (free_and_strdup(&arg_usr_what, value) < 0)
526 } else if (streq(key, "mount.usrfstype") && value) {
528 if (free_and_strdup(&arg_usr_fstype, value) < 0)
531 } else if (streq(key, "mount.usrflags") && value) {
534 o = arg_usr_options ?
535 strjoin(arg_usr_options, ",", value, NULL) :
540 free(arg_usr_options);
543 } else if (streq(key, "rw") && !value)
545 else if (streq(key, "ro") && !value)
551 int main(int argc, char *argv[]) {
554 if (argc > 1 && argc != 4) {
555 log_error("This program takes three or no arguments.");
562 log_set_target(LOG_TARGET_SAFE);
563 log_parse_environment();
568 r = parse_proc_cmdline(parse_proc_cmdline_item);
570 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
572 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
574 r = add_root_mount();
579 /* Honour /etc/fstab only when that's enabled */
580 if (arg_fstab_enabled) {
583 log_debug("Parsing /etc/fstab");
585 /* Parse the local /etc/fstab, possibly from the initrd */
586 k = parse_fstab(false);
590 /* If running in the initrd also parse the /etc/fstab from the host */
592 log_debug("Parsing /sysroot/etc/fstab");
594 k = parse_fstab(true);
601 free(arg_root_fstype);
602 free(arg_root_options);
605 free(arg_usr_fstype);
606 free(arg_usr_options);
608 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;