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 #ifdef CONFIG_TIZEN_WIP
49 #define COMMENT_HASFS "comment=havefs-"
51 static bool hasfs_comment(
57 char *comment, *fs, *opt, *end;
59 /* comment=havefs-foo-opt=1 */
61 comment = strstr(mntopts, COMMENT_HASFS);
66 *comment_start = comment;
68 end = index(comment, ',');
71 *comment_end = end ? end + 1 : comment + strlen(comment);
73 fs = comment + strlen(COMMENT_HASFS);
85 *fs_new = strndup(fs, opt - fs - 1);
97 static int mount_find_pri(struct mntent *me, int *ret) {
104 pri = hasmntopt(me, "pri");
111 r = strtoul(pri, &end, 10);
115 if (end == pri || (*end != ',' && *end != 0))
122 static int add_swap(const char *what, struct mntent *me) {
123 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
124 _cleanup_fclose_ FILE *f = NULL;
131 if (detect_container(NULL) > 0) {
132 log_info("Running in a container, ignoring fstab swap entry for %s.", what);
136 r = mount_find_pri(me, &pri);
138 log_error("Failed to parse priority");
142 noauto = !!hasmntopt(me, "noauto");
144 name = unit_name_from_path(what, ".swap");
148 unit = strjoin(arg_dest, "/", name, NULL);
152 f = fopen(unit, "wxe");
155 log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
157 log_error("Failed to create unit file %s: %m", unit);
162 "# Automatically generated by systemd-fstab-generator\n\n"
164 "SourcePath=/etc/fstab\n"
165 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
177 log_error("Failed to write unit file %s: %m", unit);
181 /* use what as where, to have a nicer error message */
182 r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
187 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
191 mkdir_parents_label(lnk, 0755);
192 if (symlink(unit, lnk) < 0) {
193 log_error("Failed to create symlink %s: %m", lnk);
201 static bool mount_is_network(struct mntent *me) {
205 hasmntopt(me, "_netdev") ||
206 fstype_is_network(me->mnt_type);
209 static bool mount_in_initrd(struct mntent *me) {
213 hasmntopt(me, "x-initrd.mount") ||
214 streq(me->mnt_dir, "/usr");
217 static int add_mount(
227 const char *source) {
230 *name = NULL, *unit = NULL, *lnk = NULL,
231 *automount_name = NULL, *automount_unit = NULL,
233 _cleanup_fclose_ FILE *f = NULL;
241 if (streq_ptr(fstype, "autofs"))
244 if (!is_path(where)) {
245 log_warning("Mount point %s is not a valid path, ignoring.", where);
249 if (mount_point_is_api(where) ||
250 mount_point_ignore(where))
253 if (path_equal(where, "/")) {
254 /* The root disk is not an option */
260 name = unit_name_from_path(where, ".mount");
264 unit = strjoin(arg_dest, "/", name, NULL);
268 f = fopen(unit, "wxe");
271 log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
273 log_error("Failed to create unit file %s: %m", unit);
278 "# Automatically generated by systemd-fstab-generator\n\n"
281 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
284 if (post && !noauto && !nofail && !automount)
285 fprintf(f, "Before=%s\n", post);
288 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
301 if (!isempty(fstype) && !streq(fstype, "auto"))
302 fprintf(f, "Type=%s\n", fstype);
304 r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
308 if (!isempty(filtered) && !streq(filtered, "defaults"))
309 fprintf(f, "Options=%s\n", filtered);
313 log_error("Failed to write unit file %s: %m", unit);
317 if (!noauto && post) {
318 lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
322 mkdir_parents_label(lnk, 0755);
323 if (symlink(unit, lnk) < 0) {
324 log_error("Failed to create symlink %s: %m", lnk);
330 automount_name = unit_name_from_path(where, ".automount");
334 automount_unit = strjoin(arg_dest, "/", automount_name, NULL);
339 f = fopen(automount_unit, "wxe");
341 log_error("Failed to create unit file %s: %m", automount_unit);
346 "# Automatically generated by systemd-fstab-generator\n\n"
349 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
364 log_error("Failed to write unit file %s: %m", automount_unit);
369 lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
373 mkdir_parents_label(lnk, 0755);
374 if (symlink(automount_unit, lnk) < 0) {
375 log_error("Failed to create symlink %s: %m", lnk);
383 static int parse_fstab(bool initrd) {
384 _cleanup_endmntent_ FILE *f = NULL;
385 const char *fstab_path;
389 fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
390 f = setmntent(fstab_path, "re");
395 log_error("Failed to open %s: %m", fstab_path);
399 while ((me = getmntent(f))) {
400 _cleanup_free_ char *where = NULL, *what = NULL;
403 if (initrd && !mount_in_initrd(me))
406 what = fstab_node_to_udev_node(me->mnt_fsname);
410 if (detect_container(NULL) > 0 && is_device_path(what)) {
411 log_info("Running in a container, ignoring fstab device entry for %s.", what);
415 where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
420 path_kill_slashes(where);
422 log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
424 if (streq(me->mnt_type, "swap"))
425 k = add_swap(what, me);
427 bool noauto, nofail, automount;
429 #ifdef CONFIG_TIZEN_WIP
430 _cleanup_free_ char *opts = NULL;
433 noauto = !!hasmntopt(me, "noauto");
434 nofail = !!hasmntopt(me, "nofail");
436 hasmntopt(me, "comment=systemd.automount") ||
437 hasmntopt(me, "x-systemd.automount");
439 #ifdef CONFIG_TIZEN_WIP
441 /* Tizen is now using switch-able smack
442 * feature. On feature enabled, different
443 * mount option is needed for tmpfs. This
444 * problematic problem is solved in recent
445 * util-linux. But we are not using mount of
446 * util-linux. So to compat the both case, the
447 * smackfsroot=* option will be conditionally
448 * be parsed by fstab.
451 _cleanup_free_ char *fs_new = NULL;
452 char *comment_start, *comment_end, *opt;
455 opts = strdup(me->mnt_opts);
458 if (hasfs_comment(opts, &comment_start, &comment_end, &opt, &fs_new)) {
459 if (fs_new && use_smack())
460 memmove(comment_start, opt, strlen(opt) + 1);
462 memmove(comment_start, comment_end, strlen(comment_end) + 1);
465 if (n > 0 && opts[n - 1] == ',')
473 post = SPECIAL_INITRD_FS_TARGET;
474 else if (mount_in_initrd(me))
475 post = SPECIAL_INITRD_ROOT_FS_TARGET;
476 else if (mount_is_network(me))
477 post = SPECIAL_REMOTE_FS_TARGET;
479 post = SPECIAL_LOCAL_FS_TARGET;
484 #ifdef CONFIG_TIZEN_WIP
504 static int add_root_mount(void) {
505 _cleanup_free_ char *what = NULL;
508 if (isempty(arg_root_what)) {
509 log_debug("Could not find a root= entry on the kernel commandline.");
513 what = fstab_node_to_udev_node(arg_root_what);
514 if (!path_is_absolute(what)) {
515 log_debug("Skipping entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
519 if (!arg_root_options)
520 opts = arg_root_rw > 0 ? "rw" : "ro";
521 else if (arg_root_rw >= 0 ||
522 (!mount_test_option(arg_root_options, "ro") &&
523 !mount_test_option(arg_root_options, "rw")))
524 opts = strappenda(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro");
526 opts = arg_root_options;
528 log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
529 return add_mount(what,
537 SPECIAL_INITRD_ROOT_FS_TARGET,
541 static int parse_proc_cmdline_item(const char *key, const char *value) {
544 /* root= and roofstype= may occur more than once, the last
545 * instance should take precedence. In the case of multiple
546 * rootflags= the arguments should be concatenated */
548 if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
550 r = parse_boolean(value);
552 log_warning("Failed to parse fstab switch %s. Ignoring.", value);
554 arg_fstab_enabled = r;
556 } else if (streq(key, "root") && value) {
559 arg_root_what = strdup(value);
563 } else if (streq(key, "rootfstype") && value) {
565 free(arg_root_fstype);
566 arg_root_fstype = strdup(value);
567 if (!arg_root_fstype)
570 } else if (streq(key, "rootflags") && value) {
573 o = arg_root_options ?
574 strjoin(arg_root_options, ",", value, NULL) :
579 free(arg_root_options);
580 arg_root_options = o;
582 } else if (streq(key, "rw") && !value)
584 else if (streq(key, "ro") && !value)
590 int main(int argc, char *argv[]) {
593 if (argc > 1 && argc != 4) {
594 log_error("This program takes three or no arguments.");
601 log_set_target(LOG_TARGET_SAFE);
602 log_parse_environment();
607 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
610 /* Always honour root= in the kernel command line if we are in an initrd */
612 r = add_root_mount();
614 /* Honour /etc/fstab only when that's enabled */
615 if (arg_fstab_enabled) {
618 log_debug("Parsing /etc/fstab");
620 /* Parse the local /etc/fstab, possibly from the initrd */
621 k = parse_fstab(false);
625 /* If running in the initrd also parse the /etc/fstab from the host */
627 log_debug("Parsing /sysroot/etc/fstab");
629 k = parse_fstab(true);
637 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;