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"
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;
48 static int mount_find_pri(struct mntent *me, int *ret) {
55 opt = hasmntopt(me, "pri");
65 r = strtoul(opt + 1, &end, 10);
69 if (end == opt + 1 || (*end != ',' && *end != 0))
76 static int mount_find_discard(struct mntent *me, char **ret) {
83 opt = hasmntopt(me, "discard");
87 opt += strlen("discard");
89 if (*opt == ',' || *opt == '\0')
95 len = strcspn(opt + 1, ",");
99 ans = strndup(opt + 1, len);
109 static int add_swap(const char *what, struct mntent *me) {
110 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
111 _cleanup_fclose_ FILE *f = NULL;
112 _cleanup_free_ char *discard = NULL;
120 if (detect_container(NULL) > 0) {
121 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
125 r = mount_find_pri(me, &pri);
127 log_error("Failed to parse priority");
131 r = mount_find_discard(me, &discard);
133 log_error("Failed to parse discard");
137 noauto = !!hasmntopt(me, "noauto");
139 name = unit_name_from_path(what, ".swap");
143 unit = strjoin(arg_dest, "/", name, NULL);
147 f = fopen(unit, "wxe");
150 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
152 log_error("Failed to create unit file %s: %m", unit);
157 "# Automatically generated by systemd-fstab-generator\n\n"
159 "SourcePath=/etc/fstab\n"
160 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
166 fprintf(f, "Priority=%i\n", pri);
169 fprintf(f, "Discard=%s\n", discard);
173 log_error("Failed to write unit file %s: %m", unit);
177 /* use what as where, to have a nicer error message */
178 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
183 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
187 mkdir_parents_label(lnk, 0755);
188 if (symlink(unit, lnk) < 0) {
189 log_error("Failed to create symlink %s: %m", lnk);
197 static bool mount_is_network(struct mntent *me) {
201 hasmntopt(me, "_netdev") ||
202 fstype_is_network(me->mnt_type);
205 static bool mount_in_initrd(struct mntent *me) {
209 hasmntopt(me, "x-initrd.mount") ||
210 streq(me->mnt_dir, "/usr");
213 static int add_mount(
223 const char *source) {
226 *name = NULL, *unit = NULL, *lnk = NULL,
227 *automount_name = NULL, *automount_unit = NULL,
229 _cleanup_fclose_ FILE *f = NULL;
237 if (streq_ptr(fstype, "autofs"))
240 if (!is_path(where)) {
241 log_warning("Mount point %s is not a valid path, ignoring.", where);
245 if (mount_point_is_api(where) ||
246 mount_point_ignore(where))
249 if (path_equal(where, "/")) {
250 /* The root disk is not an option */
256 name = unit_name_from_path(where, ".mount");
260 unit = strjoin(arg_dest, "/", name, NULL);
264 f = fopen(unit, "wxe");
267 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
269 log_error("Failed to create unit file %s: %m", unit);
274 "# Automatically generated by systemd-fstab-generator\n\n"
277 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
280 if (post && !noauto && !nofail && !automount)
281 fprintf(f, "Before=%s\n", post);
284 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
297 if (!isempty(fstype) && !streq(fstype, "auto"))
298 fprintf(f, "Type=%s\n", fstype);
300 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
304 if (!isempty(filtered) && !streq(filtered, "defaults"))
305 fprintf(f, "Options=%s\n", filtered);
309 log_error("Failed to write unit file %s: %m", unit);
313 if (!noauto && post) {
314 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
318 mkdir_parents_label(lnk, 0755);
319 if (symlink(unit, lnk) < 0) {
320 log_error("Failed to create symlink %s: %m", lnk);
326 automount_name = unit_name_from_path(where, ".automount");
330 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
335 f = fopen(automount_unit, "wxe");
337 log_error("Failed to create unit file %s: %m", automount_unit);
342 "# Automatically generated by systemd-fstab-generator\n\n"
345 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
360 log_error("Failed to write unit file %s: %m", automount_unit);
365 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
369 mkdir_parents_label(lnk, 0755);
370 if (symlink(automount_unit, lnk) < 0) {
371 log_error("Failed to create symlink %s: %m", lnk);
379 static int parse_fstab(bool initrd) {
380 _cleanup_endmntent_ FILE *f = NULL;
381 const char *fstab_path;
385 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
386 f = setmntent(fstab_path, "re");
391 log_error("Failed to open %s: %m", fstab_path);
395 while ((me = getmntent(f))) {
396 _cleanup_free_ char *where = NULL, *what = NULL;
399 if (initrd && !mount_in_initrd(me))
402 what = fstab_node_to_udev_node(me->mnt_fsname);
406 if (detect_container(NULL) > 0 && is_device_path(what)) {
407 log_info("Running in a container, ignoring fstab device entry for %s.", what);
411 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
416 path_kill_slashes(where);
418 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
420 if (streq(me->mnt_type, "swap"))
421 k = add_swap(what, me);
423 bool noauto, nofail, automount;
426 noauto = !!hasmntopt(me, "noauto");
427 nofail = !!hasmntopt(me, "nofail");
429 hasmntopt(me, "comment=systemd.automount") ||
430 hasmntopt(me, "x-systemd.automount");
433 post = SPECIAL_INITRD_FS_TARGET;
434 else if (mount_in_initrd(me))
435 post = SPECIAL_INITRD_ROOT_FS_TARGET;
436 else if (mount_is_network(me))
437 post = SPECIAL_REMOTE_FS_TARGET;
439 post = SPECIAL_LOCAL_FS_TARGET;
460 static int add_root_mount(void) {
461 _cleanup_free_ char *what = NULL;
464 if (isempty(arg_root_what)) {
465 log_debug("Could not find a root= entry on the kernel commandline.");
469 what = fstab_node_to_udev_node(arg_root_what);
470 if (!path_is_absolute(what)) {
471 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
475 if (!arg_root_options)
476 opts = arg_root_rw > 0 ? "rw" : "ro";
477 else if (arg_root_rw >= 0 ||
478 (!mount_test_option(arg_root_options, "ro") &&
479 !mount_test_option(arg_root_options, "rw")))
480 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
482 opts = arg_root_options;
484 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
485 return add_mount(what,
493 SPECIAL_INITRD_ROOT_FS_TARGET,
497 static int parse_proc_cmdline_item(const char *key, const char *value) {
500 /* root= and roofstype= may occur more than once, the last
501 * instance should take precedence. In the case of multiple
502 * rootflags= the arguments should be concatenated */
504 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
506 r = parse_boolean(value);
508 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
510 arg_fstab_enabled = r;
512 } else if (streq(key, "root") && value) {
515 arg_root_what = strdup(value);
519 } else if (streq(key, "rootfstype") && value) {
521 free(arg_root_fstype);
522 arg_root_fstype = strdup(value);
523 if (!arg_root_fstype)
526 } else if (streq(key, "rootflags") && value) {
529 o = arg_root_options ?
530 strjoin(arg_root_options, ",", value, NULL) :
535 free(arg_root_options);
536 arg_root_options = o;
538 } else if (streq(key, "rw") && !value)
540 else if (streq(key, "ro") && !value)
546 int main(int argc, char *argv[]) {
549 if (argc > 1 && argc != 4) {
550 log_error("This program takes three or no arguments.");
557 log_set_target(LOG_TARGET_SAFE);
558 log_parse_environment();
563 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
566 /* Always honour root= in the kernel command line if we are in an initrd */
568 r = add_root_mount();
570 /* Honour /etc/fstab only when that's enabled */
571 if (arg_fstab_enabled) {
574 log_debug("Parsing /etc/fstab");
576 /* Parse the local /etc/fstab, possibly from the initrd */
577 k = parse_fstab(false);
581 /* If running in the initrd also parse the /etc/fstab from the host */
583 log_debug("Parsing /sysroot/etc/fstab");
585 k = parse_fstab(true);
593 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;