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"
39 static const char *arg_dest = "/tmp";
40 static bool arg_fstab_enabled = true;
41 static char *arg_root_what = NULL;
42 static char *arg_root_fstype = NULL;
43 static char *arg_root_options = NULL;
44 static int arg_root_rw = -1;
46 static int mount_find_pri(struct mntent *me, int *ret) {
53 pri = hasmntopt(me, "pri");
60 r = strtoul(pri, &end, 10);
64 if (end == pri || (*end != ',' && *end != 0))
71 static int add_swap(const char *what, struct mntent *me) {
72 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
73 _cleanup_fclose_ FILE *f = NULL;
80 r = mount_find_pri(me, &pri);
82 log_error("Failed to parse priority");
86 noauto = !!hasmntopt(me, "noauto");
88 name = unit_name_from_path(what, ".swap");
92 unit = strjoin(arg_dest, "/", name, NULL);
96 f = fopen(unit, "wxe");
99 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
101 log_error("Failed to create unit file %s: %m", unit);
106 "# Automatically generated by systemd-fstab-generator\n\n"
108 "SourcePath=/etc/fstab\n"
109 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
121 log_error("Failed to write unit file %s: %m", unit);
126 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
130 mkdir_parents_label(lnk, 0755);
131 if (symlink(unit, lnk) < 0) {
132 log_error("Failed to create symlink %s: %m", lnk);
140 static bool mount_is_network(struct mntent *me) {
144 hasmntopt(me, "_netdev") ||
145 fstype_is_network(me->mnt_type);
148 static bool mount_in_initrd(struct mntent *me) {
152 hasmntopt(me, "x-initrd.mount") ||
153 streq(me->mnt_dir, "/usr");
156 static int add_mount(
166 const char *source) {
169 *name = NULL, *unit = NULL, *lnk = NULL,
170 *automount_name = NULL, *automount_unit = NULL;
171 _cleanup_fclose_ FILE *f = NULL;
179 if (streq_ptr(fstype, "autofs"))
182 if (!is_path(where)) {
183 log_warning("Mount point %s is not a valid path, ignoring.", where);
187 if (mount_point_is_api(where) ||
188 mount_point_ignore(where))
191 if (path_equal(where, "/")) {
197 name = unit_name_from_path(where, ".mount");
201 unit = strjoin(arg_dest, "/", name, NULL);
205 f = fopen(unit, "wxe");
208 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
210 log_error("Failed to create unit file %s: %m", unit);
215 "# Automatically generated by systemd-fstab-generator\n\n"
218 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
221 if (post && !noauto && !nofail && !automount)
227 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
240 if (!isempty(fstype) && !streq(fstype, "auto"))
241 fprintf(f, "Type=%s\n", fstype);
243 if (!isempty(opts) && !streq(opts, "defaults"))
244 fprintf(f, "Options=%s\n", opts);
248 log_error("Failed to write unit file %s: %m", unit);
254 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
258 mkdir_parents_label(lnk, 0755);
259 if (symlink(unit, lnk) < 0) {
260 log_error("Failed to create symlink %s: %m", lnk);
267 automount_name = unit_name_from_path(where, ".automount");
271 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
276 f = fopen(automount_unit, "wxe");
278 log_error("Failed to create unit file %s: %m", automount_unit);
283 "# Automatically generated by systemd-fstab-generator\n\n"
286 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
301 log_error("Failed to write unit file %s: %m", automount_unit);
306 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
310 mkdir_parents_label(lnk, 0755);
311 if (symlink(automount_unit, lnk) < 0) {
312 log_error("Failed to create symlink %s: %m", lnk);
320 static int parse_fstab(bool initrd) {
321 _cleanup_endmntent_ FILE *f = NULL;
322 const char *fstab_path;
326 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
327 f = setmntent(fstab_path, "re");
332 log_error("Failed to open %s: %m", fstab_path);
336 while ((me = getmntent(f))) {
337 _cleanup_free_ char *where = NULL, *what = NULL;
340 if (initrd && !mount_in_initrd(me))
343 what = fstab_node_to_udev_node(me->mnt_fsname);
347 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
352 path_kill_slashes(where);
354 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
356 if (streq(me->mnt_type, "swap"))
357 k = add_swap(what, me);
359 bool noauto, nofail, automount;
362 noauto = !!hasmntopt(me, "noauto");
363 nofail = !!hasmntopt(me, "nofail");
365 hasmntopt(me, "comment=systemd.automount") ||
366 hasmntopt(me, "x-systemd.automount");
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 *o = NULL, *what = NULL;
400 if (isempty(arg_root_what)) {
401 log_debug("Could not find a root= entry on the kernel commandline.");
405 what = fstab_node_to_udev_node(arg_root_what);
406 if (!path_is_absolute(what)) {
407 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
411 if (!arg_root_options)
412 o = strdup(arg_root_rw > 0 ? "rw" : "ro");
414 if (arg_root_rw >= 0 ||
415 (!mount_test_option(arg_root_options, "ro") &&
416 !mount_test_option(arg_root_options, "rw")))
417 o = strjoin(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro", NULL);
419 o = strdup(arg_root_options);
424 noauto = mount_test_option(arg_root_options, "noauto");
425 nofail = mount_test_option(arg_root_options, "nofail");
427 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
428 return add_mount(what,
435 SPECIAL_INITRD_ROOT_FS_TARGET,
439 static int parse_proc_cmdline_item(const char *key, const char *value) {
442 /* root= and roofstype= may occur more than once, the last
443 * instance should take precedence. In the case of multiple
444 * rootflags= the arguments should be concatenated */
446 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
448 r = parse_boolean(value);
450 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
452 arg_fstab_enabled = r;
454 } else if (streq(key, "root") && value) {
457 arg_root_what = strdup(value);
461 } else if (streq(key, "rootfstype") && value) {
463 free(arg_root_fstype);
464 arg_root_fstype = strdup(value);
465 if (!arg_root_fstype)
468 } else if (streq(key, "rootflags") && value) {
471 o = arg_root_options ?
472 strjoin(arg_root_options, ",", value, NULL) :
477 free(arg_root_options);
478 arg_root_options = o;
480 } else if (streq(key, "rw") && !value)
482 else if (streq(key, "ro") && !value)
484 else if (startswith(key, "fstab.") || startswith(key, "rd.fstab."))
485 log_warning("Unknown kernel switch %s. Ignoring.", key);
490 int main(int argc, char *argv[]) {
493 if (argc > 1 && argc != 4) {
494 log_error("This program takes three or no arguments.");
501 log_set_target(LOG_TARGET_SAFE);
502 log_parse_environment();
507 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
510 /* Always honour root= in the kernel command line if we are in an initrd */
512 r = add_root_mount();
514 /* Honour /etc/fstab only when that's enabled */
515 if (arg_fstab_enabled) {
518 /* Parse the local /etc/fstab, possibly from the initrd */
519 k = parse_fstab(false);
523 /* If running in the initrd also parse the /etc/fstab from the host */
525 k = parse_fstab(true);
531 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;