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;
46 static char *arg_usr_what = NULL;
47 static char *arg_usr_fstype = NULL;
48 static char *arg_usr_options = NULL;
51 static int mount_find_pri(struct mntent *me, int *ret) {
58 opt = hasmntopt(me, "pri");
68 r = strtoul(opt + 1, &end, 10);
72 if (end == opt + 1 || (*end != ',' && *end != 0))
79 static int mount_find_discard(struct mntent *me, char **ret) {
86 opt = hasmntopt(me, "discard");
90 opt += strlen("discard");
92 if (*opt == ',' || *opt == '\0')
98 len = strcspn(opt + 1, ",");
102 ans = strndup(opt + 1, len);
112 static int add_swap(const char *what, struct mntent *me) {
113 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
114 _cleanup_fclose_ FILE *f = NULL;
115 _cleanup_free_ char *discard = NULL;
123 if (detect_container(NULL) > 0) {
124 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
128 r = mount_find_pri(me, &pri);
130 log_error("Failed to parse priority");
134 r = mount_find_discard(me, &discard);
136 log_error("Failed to parse discard");
140 noauto = !!hasmntopt(me, "noauto");
142 name = unit_name_from_path(what, ".swap");
146 unit = strjoin(arg_dest, "/", name, NULL);
150 f = fopen(unit, "wxe");
153 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
155 log_error("Failed to create unit file %s: %m", unit);
160 "# Automatically generated by systemd-fstab-generator\n\n"
162 "SourcePath=/etc/fstab\n"
163 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
169 fprintf(f, "Priority=%i\n", pri);
172 fprintf(f, "Discard=%s\n", discard);
176 log_error("Failed to write unit file %s: %m", unit);
180 /* use what as where, to have a nicer error message */
181 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
186 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
190 mkdir_parents_label(lnk, 0755);
191 if (symlink(unit, lnk) < 0) {
192 log_error("Failed to create symlink %s: %m", lnk);
200 static bool mount_is_network(struct mntent *me) {
204 hasmntopt(me, "_netdev") ||
205 fstype_is_network(me->mnt_type);
208 static bool mount_in_initrd(struct mntent *me) {
212 hasmntopt(me, "x-initrd.mount") ||
213 streq(me->mnt_dir, "/usr");
216 static int add_mount(
226 const char *source) {
229 *name = NULL, *unit = NULL, *lnk = NULL,
230 *automount_name = NULL, *automount_unit = NULL,
232 _cleanup_fclose_ FILE *f = NULL;
240 if (streq_ptr(fstype, "autofs"))
243 if (!is_path(where)) {
244 log_warning("Mount point %s is not a valid path, ignoring.", where);
248 if (mount_point_is_api(where) ||
249 mount_point_ignore(where))
252 if (path_equal(where, "/")) {
253 /* The root disk is not an option */
259 name = unit_name_from_path(where, ".mount");
263 unit = strjoin(arg_dest, "/", name, NULL);
267 f = fopen(unit, "wxe");
270 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
272 log_error("Failed to create unit file %s: %m", unit);
277 "# Automatically generated by systemd-fstab-generator\n\n"
280 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
283 if (post && !noauto && !nofail && !automount)
284 fprintf(f, "Before=%s\n", post);
287 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
300 if (!isempty(fstype) && !streq(fstype, "auto"))
301 fprintf(f, "Type=%s\n", fstype);
303 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
307 if (!isempty(filtered) && !streq(filtered, "defaults"))
308 fprintf(f, "Options=%s\n", filtered);
312 log_error("Failed to write unit file %s: %m", unit);
316 if (!noauto && post) {
317 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
321 mkdir_parents_label(lnk, 0755);
322 if (symlink(unit, lnk) < 0) {
323 log_error("Failed to create symlink %s: %m", lnk);
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"
348 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
363 log_error("Failed to write unit file %s: %m", automount_unit);
368 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
372 mkdir_parents_label(lnk, 0755);
373 if (symlink(automount_unit, lnk) < 0) {
374 log_error("Failed to create symlink %s: %m", lnk);
382 static int parse_fstab(bool initrd) {
383 _cleanup_endmntent_ FILE *f = NULL;
384 const char *fstab_path;
388 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
389 f = setmntent(fstab_path, "re");
394 log_error("Failed to open %s: %m", fstab_path);
398 while ((me = getmntent(f))) {
399 _cleanup_free_ char *where = NULL, *what = NULL;
402 if (initrd && !mount_in_initrd(me))
405 what = fstab_node_to_udev_node(me->mnt_fsname);
409 if (detect_container(NULL) > 0 && is_device_path(what)) {
410 log_info("Running in a container, ignoring fstab device entry for %s.", what);
414 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
419 path_kill_slashes(where);
421 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
423 if (streq(me->mnt_type, "swap"))
424 k = add_swap(what, me);
426 bool noauto, nofail, automount;
429 noauto = !!hasmntopt(me, "noauto");
430 nofail = !!hasmntopt(me, "nofail");
432 hasmntopt(me, "comment=systemd.automount") ||
433 hasmntopt(me, "x-systemd.automount");
436 post = SPECIAL_INITRD_FS_TARGET;
437 else if (mount_in_initrd(me))
438 post = SPECIAL_INITRD_ROOT_FS_TARGET;
439 else if (mount_is_network(me))
440 post = SPECIAL_REMOTE_FS_TARGET;
442 post = SPECIAL_LOCAL_FS_TARGET;
463 static int add_root_mount(void) {
464 _cleanup_free_ char *what = NULL;
467 if (isempty(arg_root_what)) {
468 log_debug("Could not find a root= entry on the kernel commandline.");
472 what = fstab_node_to_udev_node(arg_root_what);
473 if (!path_is_absolute(what)) {
474 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
478 if (!arg_root_options)
479 opts = arg_root_rw > 0 ? "rw" : "ro";
480 else if (arg_root_rw >= 0 ||
481 (!mount_test_option(arg_root_options, "ro") &&
482 !mount_test_option(arg_root_options, "rw")))
483 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
485 opts = arg_root_options;
487 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
488 return add_mount(what,
496 SPECIAL_INITRD_ROOT_FS_TARGET,
500 static int add_usr_mount(void) {
501 _cleanup_free_ char *what = NULL;
504 if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
507 if (arg_root_what && !arg_usr_what) {
508 arg_usr_what = strdup(arg_root_what);
514 if (arg_root_fstype && !arg_usr_fstype) {
515 arg_usr_fstype = strdup(arg_root_fstype);
521 if (arg_root_options && !arg_usr_options) {
522 arg_usr_options = strdup(arg_root_options);
524 if (!arg_usr_options)
528 if (!arg_usr_what || !arg_usr_options)
531 what = fstab_node_to_udev_node(arg_usr_what);
532 if (!path_is_absolute(what)) {
533 log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
537 opts = arg_usr_options;
539 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
540 return add_mount(what,
548 SPECIAL_INITRD_ROOT_FS_TARGET,
552 static int parse_proc_cmdline_item(const char *key, const char *value) {
555 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
556 * instance should take precedence. In the case of multiple rootflags=
557 * or usrflags= the arguments should be concatenated */
559 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
561 r = parse_boolean(value);
563 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
565 arg_fstab_enabled = r;
567 } else if (streq(key, "root") && value) {
569 if (free_and_strdup(&arg_root_what, value) < 0)
572 } else if (streq(key, "rootfstype") && value) {
574 if (free_and_strdup(&arg_root_fstype, value) < 0)
577 } else if (streq(key, "rootflags") && value) {
580 o = arg_root_options ?
581 strjoin(arg_root_options, ",", value, NULL) :
586 free(arg_root_options);
587 arg_root_options = o;
589 } else if (streq(key, "mount.usr") && value) {
591 if (free_and_strdup(&arg_usr_what, value) < 0)
594 } else if (streq(key, "mount.usrfstype") && value) {
596 if (free_and_strdup(&arg_usr_fstype, value) < 0)
599 } else if (streq(key, "mount.usrflags") && value) {
602 o = arg_usr_options ?
603 strjoin(arg_usr_options, ",", value, NULL) :
608 free(arg_usr_options);
611 } else if (streq(key, "rw") && !value)
613 else if (streq(key, "ro") && !value)
619 int main(int argc, char *argv[]) {
622 if (argc > 1 && argc != 4) {
623 log_error("This program takes three or no arguments.");
630 log_set_target(LOG_TARGET_SAFE);
631 log_parse_environment();
636 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
639 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
641 r = add_root_mount();
646 /* Honour /etc/fstab only when that's enabled */
647 if (arg_fstab_enabled) {
650 log_debug("Parsing /etc/fstab");
652 /* Parse the local /etc/fstab, possibly from the initrd */
653 k = parse_fstab(false);
657 /* If running in the initrd also parse the /etc/fstab from the host */
659 log_debug("Parsing /sysroot/etc/fstab");
661 k = parse_fstab(true);
669 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;