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"
36 #include "generator.h"
40 static const char *arg_dest = "/tmp";
41 static bool arg_fstab_enabled = true;
42 static char *arg_root_what = NULL;
43 static char *arg_root_fstype = NULL;
44 static char *arg_root_options = NULL;
45 static int arg_root_rw = -1;
46 static char *arg_usr_what = NULL;
47 static char *arg_usr_fstype = NULL;
48 static char *arg_usr_options = NULL;
56 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL, *filtered = NULL;
57 _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);
75 r = fstab_find_pri(opts, &pri);
77 log_error_errno(r, "Failed to parse priority, ignoring: %m");
79 /* Remove invalid pri field */
80 r = fstab_filter_options(opts, "pri\0", NULL, NULL, &filtered);
82 return log_error_errno(r, "Failed to parse options: %m");
86 name = unit_name_from_path(what, ".swap");
90 unit = strjoin(arg_dest, "/", name, NULL);
94 f = fopen(unit, "wxe");
97 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
99 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
104 "# Automatically generated by systemd-fstab-generator\n\n"
106 "SourcePath=/etc/fstab\n"
107 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
112 /* Note that we currently pass the priority field twice, once
113 * in Priority=, and once in Options= */
115 fprintf(f, "Priority=%i\n", pri);
117 if (!isempty(opts) && !streq(opts, "defaults"))
118 fprintf(f, "Options=%s\n", opts);
120 r = fflush_and_check(f);
122 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
124 /* use what as where, to have a nicer error message */
125 r = generator_write_timeouts(arg_dest, what, what, opts, NULL);
130 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
131 nofail ? ".wants/" : ".requires/", name, NULL);
135 mkdir_parents_label(lnk, 0755);
136 if (symlink(unit, lnk) < 0)
137 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
143 static bool mount_is_network(struct mntent *me) {
146 return fstab_test_option(me->mnt_opts, "_netdev\0") ||
147 fstype_is_network(me->mnt_type);
150 static bool mount_in_initrd(struct mntent *me) {
153 return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
154 streq(me->mnt_dir, "/usr");
157 static int add_mount(
167 const char *source) {
170 *name = NULL, *unit = NULL, *lnk = NULL,
171 *automount_name = NULL, *automount_unit = NULL,
173 _cleanup_fclose_ FILE *f = NULL;
181 if (streq_ptr(fstype, "autofs"))
184 if (!is_path(where)) {
185 log_warning("Mount point %s is not a valid path, ignoring.", where);
189 if (mount_point_is_api(where) ||
190 mount_point_ignore(where))
193 if (path_equal(where, "/")) {
194 /* The root disk is not an option */
200 name = unit_name_from_path(where, ".mount");
204 unit = strjoin(arg_dest, "/", name, NULL);
208 f = fopen(unit, "wxe");
211 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
213 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
218 "# Automatically generated by systemd-fstab-generator\n\n"
221 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
224 if (post && !noauto && !nofail && !automount)
225 fprintf(f, "Before=%s\n", post);
228 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
241 if (!isempty(fstype) && !streq(fstype, "auto"))
242 fprintf(f, "Type=%s\n", fstype);
244 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
248 if (!isempty(filtered) && !streq(filtered, "defaults"))
249 fprintf(f, "Options=%s\n", filtered);
253 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
255 if (!noauto && post) {
256 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
260 mkdir_parents_label(lnk, 0755);
261 if (symlink(unit, lnk) < 0)
262 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
266 automount_name = unit_name_from_path(where, ".automount");
270 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
275 f = fopen(automount_unit, "wxe");
277 return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
280 "# Automatically generated by systemd-fstab-generator\n\n"
283 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
298 return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
301 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
305 mkdir_parents_label(lnk, 0755);
306 if (symlink(automount_unit, lnk) < 0)
307 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
313 static int parse_fstab(bool initrd) {
314 _cleanup_endmntent_ FILE *f = NULL;
315 const char *fstab_path;
319 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
320 f = setmntent(fstab_path, "re");
325 log_error_errno(errno, "Failed to open %s: %m", fstab_path);
329 while ((me = getmntent(f))) {
330 _cleanup_free_ char *where = NULL, *what = NULL;
334 if (initrd && !mount_in_initrd(me))
337 what = fstab_node_to_udev_node(me->mnt_fsname);
341 if (is_device_path(what) && path_is_read_only_fs("sys") > 0) {
342 log_info("Running in a container, ignoring fstab device entry for %s.", what);
346 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
351 path_kill_slashes(where);
353 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
354 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
355 log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
356 what, where, me->mnt_type,
357 yes_no(noauto), yes_no(nofail));
359 if (streq(me->mnt_type, "swap"))
360 k = add_swap(what, me, noauto, nofail);
365 automount = fstab_test_option(me->mnt_opts,
366 "comment=systemd.automount\0"
367 "x-systemd.automount\0");
369 post = SPECIAL_INITRD_FS_TARGET;
370 else if (mount_in_initrd(me))
371 post = SPECIAL_INITRD_ROOT_FS_TARGET;
372 else if (mount_is_network(me))
373 post = SPECIAL_REMOTE_FS_TARGET;
375 post = SPECIAL_LOCAL_FS_TARGET;
396 static int add_root_mount(void) {
397 _cleanup_free_ char *what = NULL;
400 if (fstype_is_deviceless(arg_root_fstype)) {
401 if (free_and_strdup(&what, arg_root_what) < 0)
404 if (isempty(arg_root_what)) {
405 log_debug("Could not find a root= entry on the kernel command line.");
409 what = fstab_node_to_udev_node(arg_root_what);
410 if (!path_is_absolute(what)) {
411 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
416 if (!arg_root_options)
417 opts = arg_root_rw > 0 ? "rw" : "ro";
418 else if (arg_root_rw >= 0 ||
419 !fstab_test_option(arg_root_options, "ro\0" "rw\0"))
420 opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
422 opts = arg_root_options;
424 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
425 return add_mount(what,
433 SPECIAL_INITRD_ROOT_FS_TARGET,
437 static int add_usr_mount(void) {
438 _cleanup_free_ char *what = NULL;
441 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
444 if (arg_root_what && !arg_usr_what) {
445 arg_usr_what = strdup(arg_root_what);
451 if (arg_root_fstype && !arg_usr_fstype) {
452 arg_usr_fstype = strdup(arg_root_fstype);
458 if (arg_root_options && !arg_usr_options) {
459 arg_usr_options = strdup(arg_root_options);
461 if (!arg_usr_options)
468 what = fstab_node_to_udev_node(arg_usr_what);
469 if (!path_is_absolute(what)) {
470 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
474 if (!arg_usr_options)
475 opts = arg_root_rw > 0 ? "rw" : "ro";
476 else if (!fstab_test_option(arg_usr_options, "ro\0" "rw\0"))
477 opts = strjoina(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
479 opts = arg_usr_options;
481 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
482 return add_mount(what,
490 SPECIAL_INITRD_ROOT_FS_TARGET,
494 static int parse_proc_cmdline_item(const char *key, const char *value) {
497 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
498 * instance should take precedence. In the case of multiple rootflags=
499 * or usrflags= the arguments should be concatenated */
501 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
503 r = parse_boolean(value);
505 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
507 arg_fstab_enabled = r;
509 } else if (streq(key, "root") && value) {
511 if (free_and_strdup(&arg_root_what, value) < 0)
514 } else if (streq(key, "rootfstype") && value) {
516 if (free_and_strdup(&arg_root_fstype, value) < 0)
519 } else if (streq(key, "rootflags") && value) {
522 o = arg_root_options ?
523 strjoin(arg_root_options, ",", value, NULL) :
528 free(arg_root_options);
529 arg_root_options = o;
531 } else if (streq(key, "mount.usr") && value) {
533 if (free_and_strdup(&arg_usr_what, value) < 0)
536 } else if (streq(key, "mount.usrfstype") && value) {
538 if (free_and_strdup(&arg_usr_fstype, value) < 0)
541 } else if (streq(key, "mount.usrflags") && value) {
544 o = arg_usr_options ?
545 strjoin(arg_usr_options, ",", value, NULL) :
550 free(arg_usr_options);
553 } else if (streq(key, "rw") && !value)
555 else if (streq(key, "ro") && !value)
561 int main(int argc, char *argv[]) {
564 if (argc > 1 && argc != 4) {
565 log_error("This program takes three or no arguments.");
572 log_set_target(LOG_TARGET_SAFE);
573 log_parse_environment();
578 r = parse_proc_cmdline(parse_proc_cmdline_item);
580 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
582 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
584 r = add_root_mount();
589 /* Honour /etc/fstab only when that's enabled */
590 if (arg_fstab_enabled) {
593 log_debug("Parsing /etc/fstab");
595 /* Parse the local /etc/fstab, possibly from the initrd */
596 k = parse_fstab(false);
600 /* If running in the initrd also parse the /etc/fstab from the host */
602 log_debug("Parsing /sysroot/etc/fstab");
604 k = parse_fstab(true);
611 free(arg_root_fstype);
612 free(arg_root_options);
615 free(arg_usr_fstype);
616 free(arg_usr_options);
618 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;