summaryrefslogtreecommitdiffstats
path: root/mount-deprecated
diff options
context:
space:
mode:
authorKarel Zak2012-05-30 17:16:11 +0200
committerKarel Zak2012-06-26 20:48:22 +0200
commitd2feb47fb1ddc0d8ac946328e77ed86ea6937bef (patch)
tree3333ca26eb3b4f5df76714f93c41e7e300b45c66 /mount-deprecated
parentbuild-sys: convert login-utils/ to module (diff)
downloadkernel-qcow2-util-linux-d2feb47fb1ddc0d8ac946328e77ed86ea6937bef.tar.gz
kernel-qcow2-util-linux-d2feb47fb1ddc0d8ac946328e77ed86ea6937bef.tar.xz
kernel-qcow2-util-linux-d2feb47fb1ddc0d8ac946328e77ed86ea6937bef.zip
build-sys: convert mount/ to module, rename to mount-deprecated/
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'mount-deprecated')
-rw-r--r--mount-deprecated/.gitignore3
-rw-r--r--mount-deprecated/Makemodule.am99
-rw-r--r--mount-deprecated/devname.c14
-rw-r--r--mount-deprecated/devname.h6
-rw-r--r--mount-deprecated/fsprobe.c141
-rw-r--r--mount-deprecated/fsprobe.h27
-rw-r--r--mount-deprecated/fstab.c1170
-rw-r--r--mount-deprecated/fstab.h44
-rw-r--r--mount-deprecated/getusername.c14
-rw-r--r--mount-deprecated/getusername.h1
-rw-r--r--mount-deprecated/mount.82857
-rw-r--r--mount-deprecated/mount.c2799
-rw-r--r--mount-deprecated/mount_constants.h73
-rw-r--r--mount-deprecated/mount_mntent.c165
-rw-r--r--mount-deprecated/mount_mntent.h28
-rw-r--r--mount-deprecated/sundries.c300
-rw-r--r--mount-deprecated/sundries.h55
-rw-r--r--mount-deprecated/umount.8179
-rw-r--r--mount-deprecated/umount.c878
19 files changed, 8853 insertions, 0 deletions
diff --git a/mount-deprecated/.gitignore b/mount-deprecated/.gitignore
new file mode 100644
index 000000000..8be9aceb7
--- /dev/null
+++ b/mount-deprecated/.gitignore
@@ -0,0 +1,3 @@
+mount
+mtab_lock_test
+umount
diff --git a/mount-deprecated/Makemodule.am b/mount-deprecated/Makemodule.am
new file mode 100644
index 000000000..03fe51341
--- /dev/null
+++ b/mount-deprecated/Makemodule.am
@@ -0,0 +1,99 @@
+if BUILD_MOUNT
+
+bin_PROGRAMS += mount umount
+dist_man_MANS += \
+ mount-deprecated/mount.8 \
+ mount-deprecated/umount.8
+
+mount_common_sources = \
+ mount-deprecated/sundries.c \
+ mount-deprecated/sundries.h \
+ mount-deprecated/fstab.h \
+ mount-deprecated/mount_mntent.h \
+ mount-deprecated/mount_constants.h \
+ mount-deprecated/getusername.h \
+ mount-deprecated/fsprobe.h \
+ mount-deprecated/devname.c \
+ mount-deprecated/devname.h \
+ mount-deprecated/fstab.c \
+ mount-deprecated/getusername.c \
+ mount-deprecated/mount_mntent.c \
+ mount-deprecated/fsprobe.c \
+ \
+ lib/canonicalize.c \
+ lib/at.c \
+ lib/blkdev.c \
+ lib/env.c \
+ lib/linux_version.c \
+ lib/loopdev.c \
+ lib/mangle.c \
+ lib/strutils.c \
+ lib/xgetpass.c \
+ lib/sysfs.c
+
+mount_SOURCES = \
+ mount-deprecated/mount.c \
+ $(mount_common_sources) \
+ lib/setproctitle.c
+mount_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS) -I$(ul_libblkid_incdir)
+mount_LDFLAGS = $(SUID_LDFLAGS) $(AM_LDFLAGS)
+mount_LDADD = libblkid.la
+
+umount_SOURCES = \
+ mount-deprecated/umount.c \
+ $(mount_common_sources)
+umount_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS) -I$(ul_libblkid_incdir)
+umount_LDFLAGS = $(SUID_LDFLAGS) $(AM_LDFLAGS)
+umount_LDADD = libblkid.la
+
+
+
+mount_static_LDADD =
+
+if HAVE_STATIC_MOUNT
+bin_PROGRAMS += mount.static
+mount_static_SOURCES = $(mount_SOURCES)
+mount_static_CFLAGS = $(mount_CFLAGS)
+mount_static_LDFLAGS = -all-static
+mount_static_LDADD += libblkid.la
+endif
+
+if HAVE_STATIC_UMOUNT
+bin_PROGRAMS += umount.static
+umount_static_SOURCES = $(umount_SOURCES)
+umount_static_CFLAGS = $(umount_CFLAGS)
+umount_static_LDFLAGS = -all-static
+umount_static_LDADD = libblkid.la
+endif
+
+if HAVE_SELINUX
+mount_LDADD += $(SELINUX_LIBS)
+mount_static_LDADD += $(SELINUX_LIBS_STATIC)
+endif
+
+# hybrid mount -- old mount + new code from libmount for mtab management
+#
+if BUILD_LIBMOUNT_MOUNT
+mount_LDADD += libmount.la
+mount_CFLAGS += $(AM_CFLAGS) -I$(ul_libmount_incdir)
+umount_LDADD += libmount.la
+umount_CFLAGS += $(AM_CFLAGS) -I$(ul_libmount_incdir)
+if HAVE_STATIC_MOUNT
+mount_static_LDADD += libmount.la
+mount_static_CFLAGS += -I$(ul_libmount_incdir)
+endif
+if HAVE_STATIC_UMOUNT
+umount_static_LDADD += libmount.la
+umount_static_CFLAGS += -I$(ul_libmount_incdir)
+endif
+endif
+
+if MAKEINSTALL_DO_SETUID
+install-exec-hook-mount:
+ chmod 4755 $(DESTDIR)$(bindir)/mount
+ chmod 4755 $(DESTDIR)$(bindir)/umount
+
+INSTALL_EXEC_HOOKS += install-exec-hook-mount
+endif
+
+endif # BUILD_MOUNT
diff --git a/mount-deprecated/devname.c b/mount-deprecated/devname.c
new file mode 100644
index 000000000..76dfe91ef
--- /dev/null
+++ b/mount-deprecated/devname.c
@@ -0,0 +1,14 @@
+#include "fsprobe.h"
+
+#include "devname.h"
+#include "sundries.h" /* for xstrdup */
+
+const char *
+spec_to_devname(const char *spec)
+{
+ if (!spec)
+ return NULL;
+ if (nocanonicalize || is_pseudo_fs(spec))
+ return xstrdup(spec);
+ return fsprobe_get_devname_by_spec(spec);
+}
diff --git a/mount-deprecated/devname.h b/mount-deprecated/devname.h
new file mode 100644
index 000000000..d6adeff7d
--- /dev/null
+++ b/mount-deprecated/devname.h
@@ -0,0 +1,6 @@
+#ifndef MOUNT_DEVNAME_H
+#define MOUNT_DEVNAME_H
+
+extern const char *spec_to_devname(const char *spec);
+
+#endif
diff --git a/mount-deprecated/fsprobe.c b/mount-deprecated/fsprobe.c
new file mode 100644
index 000000000..80c25669f
--- /dev/null
+++ b/mount-deprecated/fsprobe.c
@@ -0,0 +1,141 @@
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include <blkid.h>
+
+#include "blkdev.h"
+#include "canonicalize.h"
+#include "pathnames.h"
+#include "fsprobe.h"
+
+/*
+ * THIS IS DEPRECATED -- use blkid_evaluate_* API rather than this extra layer
+ */
+
+
+static blkid_cache blcache;
+static blkid_probe blprobe;
+
+void
+fsprobe_init(void)
+{
+ blcache = NULL;
+ blprobe = NULL;
+}
+
+void
+fsprobe_exit(void)
+{
+ if (blprobe)
+ blkid_free_probe(blprobe);
+ if (blcache)
+ blkid_put_cache(blcache);
+}
+
+/*
+ * Parses NAME=value, returns -1 on parse error, 0 success. The success is also
+ * when the 'spec' doesn't contain name=value pair (because the spec could be
+ * a devname too). In particular case the pointer 'name' is set to NULL.
+ */
+int
+fsprobe_parse_spec(const char *spec, char **name, char **value)
+{
+ *name = NULL;
+ *value = NULL;
+
+ if (strchr(spec, '='))
+ return blkid_parse_tag_string(spec, name, value);
+
+ return 0;
+}
+
+char *
+fsprobe_get_devname_by_spec(const char *spec)
+{
+ return blkid_evaluate_spec(spec, &blcache);
+}
+
+int
+fsprobe_known_fstype(const char *fstype)
+{
+ return blkid_known_fstype(fstype);
+}
+
+
+/* returns device LABEL, UUID, FSTYPE, ... by low-level
+ * probing interface
+ */
+static char *
+fsprobe_get_value(const char *name, const char *devname, int *ambi)
+{
+ int fd, rc;
+ const char *data = NULL;
+
+ if (!devname || !name)
+ return NULL;
+ fd = open(devname, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (!blprobe)
+ blprobe = blkid_new_probe();
+ if (!blprobe)
+ goto done;
+ if (blkid_probe_set_device(blprobe, fd, 0, 0))
+ goto done;
+
+ blkid_probe_enable_superblocks(blprobe, 1);
+
+ blkid_probe_set_superblocks_flags(blprobe,
+ BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | BLKID_SUBLKS_TYPE);
+
+ rc = blkid_do_safeprobe(blprobe);
+ if (ambi)
+ *ambi = rc == -2 ? 1 : 0; /* ambivalent probing result */
+ if (!rc)
+ blkid_probe_lookup_value(blprobe, name, &data, NULL);
+done:
+ close(fd);
+ return data ? strdup((char *) data) : NULL;
+}
+
+char *
+fsprobe_get_label_by_devname(const char *devname)
+{
+ return fsprobe_get_value("LABEL", devname, NULL);
+}
+
+char *
+fsprobe_get_uuid_by_devname(const char *devname)
+{
+ return fsprobe_get_value("UUID", devname, NULL);
+}
+
+char *
+fsprobe_get_fstype_by_devname(const char *devname)
+{
+ return fsprobe_get_value("TYPE", devname, NULL);
+}
+
+char *
+fsprobe_get_fstype_by_devname_ambi(const char *devname, int *ambi)
+{
+ return fsprobe_get_value("TYPE", devname, ambi);
+}
+
+char *
+fsprobe_get_devname_by_uuid(const char *uuid)
+{
+ return blkid_evaluate_tag("UUID", uuid, &blcache);
+}
+
+char *
+fsprobe_get_devname_by_label(const char *label)
+{
+ return blkid_evaluate_tag("LABEL", label, &blcache);
+}
diff --git a/mount-deprecated/fsprobe.h b/mount-deprecated/fsprobe.h
new file mode 100644
index 000000000..d9c1dc494
--- /dev/null
+++ b/mount-deprecated/fsprobe.h
@@ -0,0 +1,27 @@
+#ifndef FSPROBE_H
+#define FSPROBE_H
+/*
+ * THIS IS DEPRECATED -- use blkid_evaluate_* API rather than this extra layer
+ *
+ * This is the generic interface for filesystem guessing libraries.
+ * Implementations are provided by
+ */
+extern void fsprobe_init(void);
+extern void fsprobe_exit(void);
+
+extern int fsprobe_parse_spec(const char *spec, char **name, char **value);
+
+/* all routines return newly allocated string */
+extern char *fsprobe_get_devname_by_uuid(const char *uuid);
+extern char *fsprobe_get_devname_by_label(const char *label);
+extern char *fsprobe_get_devname_by_spec(const char *spec);
+
+extern char *fsprobe_get_label_by_devname(const char *devname);
+extern char *fsprobe_get_uuid_by_devname(const char *devname);
+extern char *fsprobe_get_fstype_by_devname(const char *devname);
+extern char *fsprobe_get_fstype_by_devname_ambi(const char *devname, int *ambi);
+
+
+extern int fsprobe_known_fstype(const char *fstype);
+
+#endif /* FSPROBE_H */
diff --git a/mount-deprecated/fstab.c b/mount-deprecated/fstab.c
new file mode 100644
index 000000000..90c8032fb
--- /dev/null
+++ b/mount-deprecated/fstab.c
@@ -0,0 +1,1170 @@
+/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * - fixed strerr(errno) in gettext calls
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <mntent.h>
+
+#include "mount_mntent.h"
+#include "fstab.h"
+#include "sundries.h"
+#include "fsprobe.h"
+#include "pathnames.h"
+#include "nls.h"
+#include "usleep.h"
+#include "strutils.h"
+
+#define streq(s, t) (strcmp ((s), (t)) == 0)
+
+/* Information about mtab. ------------------------------------*/
+static int have_mtab_info = 0;
+static int var_mtab_does_not_exist = 0;
+static int var_mtab_is_a_symlink = 0;
+
+static void
+get_mtab_info(void) {
+ if (!have_mtab_info) {
+ struct stat mtab_stat;
+
+ var_mtab_does_not_exist = 0;
+ var_mtab_is_a_symlink = 0;
+
+ if (lstat(_PATH_MOUNTED, &mtab_stat))
+ var_mtab_does_not_exist = 1;
+ else if (S_ISLNK(mtab_stat.st_mode))
+ var_mtab_is_a_symlink = 1;
+ have_mtab_info = 1;
+ }
+}
+
+void
+reset_mtab_info(void) {
+ have_mtab_info = 0;
+}
+
+int
+mtab_does_not_exist(void) {
+ get_mtab_info();
+ return var_mtab_does_not_exist;
+}
+
+int
+mtab_is_a_symlink(void) {
+ get_mtab_info();
+ return var_mtab_is_a_symlink;
+}
+
+int
+mtab_is_writable() {
+ int fd;
+
+ /* Should we write to /etc/mtab upon an update?
+ Probably not if it is a symlink to /proc/mounts, since that
+ would create a file /proc/mounts in case the proc filesystem
+ is not mounted. */
+ if (mtab_is_a_symlink())
+ return 0;
+
+ fd = open(_PATH_MOUNTED, O_RDWR | O_CREAT, 0644);
+ if (fd >= 0) {
+ close(fd);
+ return 1;
+ } else
+ return 0;
+}
+
+/* Contents of mtab and fstab ---------------------------------*/
+
+struct mntentchn mounttable, fstab;
+static int got_mtab = 0;
+static int got_fstab = 0;
+
+static void read_mounttable(void), read_fstab(void);
+
+struct mntentchn *
+mtab_head() {
+ if (!got_mtab)
+ read_mounttable();
+ return &mounttable;
+}
+
+struct mntentchn *
+fstab_head() {
+ if (!got_fstab)
+ read_fstab();
+ return &fstab;
+}
+
+static void
+my_free_mc(struct mntentchn *mc) {
+ if (mc) {
+ my_free(mc->m.mnt_fsname);
+ my_free(mc->m.mnt_dir);
+ my_free(mc->m.mnt_type);
+ my_free(mc->m.mnt_opts);
+ free(mc);
+ }
+}
+
+
+static void
+discard_mntentchn(struct mntentchn *mc0) {
+ struct mntentchn *mc, *mc1;
+
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc1) {
+ mc1 = mc->nxt;
+ my_free_mc(mc);
+ }
+}
+
+static void
+read_mntentchn(mntFILE *mfp, const char *fnam, struct mntentchn *mc0) {
+ struct mntentchn *mc = mc0;
+ struct my_mntent *mnt;
+
+ while ((mnt = my_getmntent(mfp)) != NULL) {
+ if (!streq(mnt->mnt_type, MNTTYPE_IGNORE)) {
+ mc->nxt = (struct mntentchn *) xmalloc(sizeof(*mc));
+ mc->nxt->prev = mc;
+ mc = mc->nxt;
+ mc->m = *mnt;
+ mc->nxt = mc0;
+ }
+ }
+ mc0->prev = mc;
+ if (ferror(mfp->mntent_fp)) {
+ int errsv = errno;
+ error(_("warning: error reading %s: %s"),
+ fnam, strerror (errsv));
+ mc0->nxt = mc0->prev = NULL;
+ }
+ my_endmntent(mfp);
+}
+
+#ifdef HAVE_LIBMOUNT_MOUNT
+
+#define USE_UNSTABLE_LIBMOUNT_API
+#include <libmount.h> /* libmount */
+
+static void read_mounttable()
+{
+ struct mntentchn *mc0 = &mounttable, *mc = mc0;
+ struct libmnt_table *tb = mnt_new_table();
+ struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
+ struct libmnt_fs *fs;
+
+ got_mtab = 1;
+ mc->nxt = mc->prev = NULL;
+
+ if (!tb || !itr)
+ goto err;
+ if (mnt_table_parse_mtab(tb, NULL))
+ goto err;
+
+ while(mnt_table_next_fs(tb, itr, &fs) == 0) {
+ const char *type = mnt_fs_get_fstype(fs);
+ struct my_mntent *mnt = NULL;
+
+ if (type && strcmp(type, MNTTYPE_IGNORE) == 0)
+ continue;
+ if (mnt_fs_to_mntent(fs, (struct mntent **) &mnt))
+ goto err;
+ mc->nxt = xmalloc(sizeof(*mc));
+ mc->nxt->prev = mc;
+ mc = mc->nxt;
+ mc->m = *mnt;
+ mc->nxt = mc0;
+ }
+
+ mc0->prev = mc;
+ return;
+err:
+ error(_("warning: failed to read mtab"));
+ mnt_free_table(tb);
+ mnt_free_iter(itr);
+ mc->nxt = mc->prev = NULL;
+}
+
+#else /* !HAVE_LIBMOUNT_MOUNT */
+
+/*
+ * Read /etc/mtab. If that fails, try /proc/mounts.
+ * This produces a linked list. The list head mounttable is a dummy.
+ */
+static void
+read_mounttable() {
+ mntFILE *mfp;
+ const char *fnam;
+ struct mntentchn *mc = &mounttable;
+
+ got_mtab = 1;
+ mc->nxt = mc->prev = NULL;
+
+ fnam = _PATH_MOUNTED;
+ mfp = my_setmntent (fnam, "r");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
+ int errsv = errno;
+ fnam = _PATH_PROC_MOUNTS;
+ mfp = my_setmntent (fnam, "r");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
+ error(_("warning: can't open %s: %s"),
+ _PATH_MOUNTED, strerror (errsv));
+ return;
+ }
+ if (verbose)
+ printf (_("mount: could not open %s - "
+ "using %s instead\n"),
+ _PATH_MOUNTED, _PATH_PROC_MOUNTS);
+ }
+ read_mntentchn(mfp, fnam, mc);
+}
+#endif /* HAVE_LIBMOUNT_MOUNT */
+
+static void
+read_fstab() {
+ mntFILE *mfp = NULL;
+ const char *fnam;
+ struct mntentchn *mc = &fstab;
+
+ got_fstab = 1;
+ mc->nxt = mc->prev = NULL;
+
+ fnam = _PATH_MNTTAB;
+ mfp = my_setmntent (fnam, "r");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
+ int errsv = errno;
+ error(_("warning: can't open %s: %s"),
+ _PATH_MNTTAB, strerror (errsv));
+ return;
+ }
+ read_mntentchn(mfp, fnam, mc);
+}
+
+
+/* Given the name NAME, try to find it in mtab. */
+struct mntentchn *
+getmntfile (const char *name) {
+ struct mntentchn *mc, *mc0;
+
+ mc0 = mtab_head();
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+ if (streq(mc->m.mnt_dir, name) ||
+ streq(mc->m.mnt_fsname, name))
+ return mc;
+ return NULL;
+}
+
+/*
+ * Given the name NAME, and the place MCPREV we found it last time,
+ * try to find it in mtab.
+ */
+struct mntentchn *
+getmntfilebackward (const char *name, struct mntentchn *mcprev) {
+ struct mntentchn *mc, *mc0;
+
+ mc0 = mtab_head();
+ if (!mcprev)
+ mcprev = mc0;
+
+ for (mc = mcprev->prev; mc && mc != mc0; mc = mc->prev)
+ if (streq(mc->m.mnt_dir, name))
+ return mc;
+
+ for (mc = mcprev->prev; mc && mc != mc0; mc = mc->prev)
+ if (streq(mc->m.mnt_fsname, name))
+ return mc;
+
+ return NULL;
+}
+
+/*
+ * Given the directory name NAME, and the place MCPREV we found it last time,
+ * try to find more occurrences.
+ */
+struct mntentchn *
+getmntdirbackward (const char *name, struct mntentchn *mcprev) {
+ struct mntentchn *mc, *mc0;
+
+ mc0 = mtab_head();
+ if (!mcprev)
+ mcprev = mc0;
+ for (mc = mcprev->prev; mc && mc != mc0; mc = mc->prev)
+ if (streq(mc->m.mnt_dir, name))
+ return mc;
+ return NULL;
+}
+
+/*
+ * Given the device name NAME, and the place MCPREV we found it last time,
+ * try to find more occurrences.
+ */
+struct mntentchn *
+getmntdevbackward (const char *name, struct mntentchn *mcprev) {
+ struct mntentchn *mc, *mc0;
+
+ mc0 = mtab_head();
+ if (!mcprev)
+ mcprev = mc0;
+
+ /* canonical names in mtab */
+ for (mc = mcprev->prev; mc && mc != mc0; mc = mc->prev) {
+ if (streq(mc->m.mnt_fsname, name))
+ return mc;
+ }
+
+ /* non-canonical names in mtab (this is BAD THING!) */
+ for (mc = mcprev->prev; mc && mc != mc0; mc = mc->prev) {
+ char *cn = canonicalize(mc->m.mnt_fsname);
+ int res = cn ? streq(cn, name) : 0;
+
+ free(cn);
+ if (res)
+ return mc;
+ }
+
+ return NULL;
+}
+
+/*
+ * Given the name NAME, check that it occurs precisely once as dir or dev.
+ */
+int
+is_mounted_once(const char *name) {
+ struct mntentchn *mc, *mc0;
+ int ct = 0;
+
+ mc0 = mtab_head();
+ for (mc = mc0->prev; mc && mc != mc0; mc = mc->prev)
+ if (streq(mc->m.mnt_dir, name) ||
+ streq(mc->m.mnt_fsname, name))
+ ct++;
+ return (ct == 1);
+}
+
+/* Given the name FILE, try to find the option "loop=FILE" in mtab. */
+struct mntentchn *
+getmntoptfile (const char *file) {
+ struct mntentchn *mc, *mc0;
+ const char *opts, *s;
+ int l;
+
+ if (!file)
+ return NULL;
+
+ l = strlen(file);
+
+ mc0 = mtab_head();
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+ if ((opts = mc->m.mnt_opts) != NULL
+ && (s = strstr(opts, "loop="))
+ && !strncmp(s+5, file, l)
+ && (s == opts || s[-1] == ',')
+ && (s[l+5] == 0 || s[l+5] == ','))
+ return mc;
+ return NULL;
+}
+
+/* compares "quoted" or 'quoted' with unquoted */
+static int
+streq_quoted(const char *quoted, const char *unquoted)
+{
+ if (*quoted == '"' || *quoted == '\'')
+ return !strncmp(quoted + 1, unquoted, strlen(quoted) - 2);
+
+ return streq(quoted, unquoted);
+}
+
+static int
+has_label(const char *device, const char *label) {
+ const char *devlabel;
+ int ret;
+
+ devlabel = fsprobe_get_label_by_devname(device);
+ if (!devlabel)
+ return 0;
+
+ ret = streq_quoted(label, devlabel);
+ my_free(devlabel);
+ return ret;
+}
+
+static int
+has_uuid(const char *device, const char *uuid){
+ const char *devuuid;
+ int ret;
+
+ devuuid = fsprobe_get_uuid_by_devname(device);
+ if (!devuuid)
+ return 0;
+
+ ret = streq_quoted(uuid, devuuid);
+ my_free(devuuid);
+ return ret;
+}
+
+/* Find the entry (DEV,DIR) in fstab -- spec and dir must be canonicalized! */
+struct mntentchn *
+getfs_by_devdir (const char *dev, const char *dir) {
+ struct mntentchn *mc, *mc0;
+
+ mc0 = fstab_head();
+
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
+ int ok = 1;
+
+ /* dir */
+ if (!streq(mc->m.mnt_dir, dir)) {
+ char *dr = canonicalize(mc->m.mnt_dir);
+ ok = streq(dr, dir);
+ my_free(dr);
+ }
+
+ /* spec */
+ if (ok && !streq(mc->m.mnt_fsname, dev)) {
+ const char *fs = mc->m.mnt_fsname;
+
+ if (strncmp (fs, "LABEL=", 6) == 0) {
+ ok = has_label(dev, fs + 6);
+ } else if (strncmp (fs, "UUID=", 5) == 0) {
+ ok = has_uuid(dev, fs + 5);
+ } else {
+ fs = canonicalize_spec(mc->m.mnt_fsname);
+ ok = streq_except_trailing_slash(fs, dev);
+ my_free(fs);
+ }
+ }
+ if (ok)
+ return mc;
+ }
+
+ return NULL;
+}
+
+/* Find the dir DIR in fstab. */
+struct mntentchn *
+getfs_by_dir (const char *dir) {
+ struct mntentchn *mc, *mc0;
+ char *cdir;
+
+ mc0 = fstab_head();
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+ if (streq(mc->m.mnt_dir, dir))
+ return mc;
+
+ cdir = canonicalize(dir);
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
+ int ok = streq(mc->m.mnt_dir, cdir);
+ if (!ok) {
+ char *dr = canonicalize(mc->m.mnt_dir);
+ ok = dr ? streq(dr, cdir) : 0;
+ free(dr);
+ }
+ if (ok) {
+ free(cdir);
+ return mc;
+ }
+ }
+ free(cdir);
+ return NULL;
+}
+
+/* Find the device SPEC in fstab. */
+struct mntentchn *
+getfs_by_spec (const char *spec) {
+ char *name = NULL, *value = NULL, *cspec;
+ struct mntentchn *mc = NULL;
+
+ if (!spec)
+ return NULL;
+
+ if (fsprobe_parse_spec(spec, &name, &value) != 0)
+ return NULL; /* parse error */
+
+ if (name) {
+ if (!strcmp(name,"LABEL"))
+ mc = getfs_by_label (value);
+ else if (!strcmp(name,"UUID"))
+ mc = getfs_by_uuid (value);
+
+ free(name);
+ free(value);
+ return mc;
+ }
+
+ cspec = canonicalize_spec(spec);
+ mc = getfs_by_devname(cspec);
+ free(cspec);
+
+ if (!mc)
+ /* noncanonical name like /dev/cdrom */
+ mc = getfs_by_devname(spec);
+
+ return mc;
+}
+
+/* Find the device in fstab. */
+struct mntentchn *
+getfs_by_devname (const char *devname) {
+ struct mntentchn *mc, *mc0;
+
+ mc0 = fstab_head();
+
+ /* canonical devname in fstab */
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+ if (streq(mc->m.mnt_fsname, devname))
+ return mc;
+
+ /* noncanonical devname in fstab */
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
+ char *fs;
+
+ if (strncmp(mc->m.mnt_fsname, "LABEL=", 6) == 0 ||
+ strncmp(mc->m.mnt_fsname, "UUID=", 5) == 0)
+ continue;
+
+ fs = canonicalize_spec(mc->m.mnt_fsname);
+ if (streq(fs, devname)) {
+ free(fs);
+ return mc;
+ }
+ free(fs);
+ }
+
+ return NULL;
+}
+
+
+/* Find the uuid UUID in fstab. */
+struct mntentchn *
+getfs_by_uuid (const char *uuid) {
+ struct mntentchn *mc, *mc0;
+
+ mc0 = fstab_head();
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+ if (strncmp (mc->m.mnt_fsname, "UUID=", 5) == 0
+ && streq_quoted(mc->m.mnt_fsname + 5, uuid))
+ return mc;
+ return NULL;
+}
+
+/* Find the label LABEL in fstab. */
+struct mntentchn *
+getfs_by_label (const char *label) {
+ struct mntentchn *mc, *mc0;
+
+ mc0 = fstab_head();
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+ if (strncmp (mc->m.mnt_fsname, "LABEL=", 6) == 0
+ && streq_quoted(mc->m.mnt_fsname + 6, label))
+ return mc;
+ return NULL;
+}
+
+/* Updating mtab ----------------------------------------------*/
+
+/* Flag for already existing lock file. */
+static int we_created_lockfile = 0;
+static int lockfile_fd = -1;
+
+/* Flag to indicate that signals have been set up. */
+static int signals_have_been_setup = 0;
+
+/* Ensure that the lock is released if we are interrupted. */
+#ifndef HAVE_STRSIGNAL_DECL
+extern char *strsignal(int sig); /* not always in <string.h> */
+#endif
+
+static void
+handler (int sig) {
+ die(EX_USER, "%s", strsignal(sig));
+}
+
+static void
+setlkw_timeout (int sig __attribute__ ((__unused__))) {
+ /* nothing, fcntl will fail anyway */
+}
+
+/* Remove lock file. */
+void
+unlock_mtab (void) {
+ if (we_created_lockfile) {
+ close(lockfile_fd);
+ lockfile_fd = -1;
+ unlink (_PATH_MOUNTED_LOCK);
+ we_created_lockfile = 0;
+ }
+}
+
+/* Create the lock file.
+ The lock file will be removed if we catch a signal or when we exit. */
+/* The old code here used flock on a lock file /etc/mtab~ and deleted
+ this lock file afterwards. However, as rgooch remarks, that has a
+ race: a second mount may be waiting on the lock and proceed as
+ soon as the lock file is deleted by the first mount, and immediately
+ afterwards a third mount comes, creates a new /etc/mtab~, applies
+ flock to that, and also proceeds, so that the second and third mount
+ now both are scribbling in /etc/mtab.
+ The new code uses a link() instead of a creat(), where we proceed
+ only if it was us that created the lock, and hence we always have
+ to delete the lock afterwards. Now the use of flock() is in principle
+ superfluous, but avoids an arbitrary sleep(). */
+
+/* Where does the link point to? Obvious choices are mtab and mtab~~.
+ HJLu points out that the latter leads to races. Right now we use
+ mtab~.<pid> instead. Use 20 as upper bound for the length of %d. */
+#define MOUNTLOCK_LINKTARGET _PATH_MOUNTED_LOCK "%d"
+#define MOUNTLOCK_LINKTARGET_LTH (sizeof(_PATH_MOUNTED_LOCK)+20)
+
+/*
+ * The original mount locking code has used sleep(1) between attempts and
+ * maximal number of attemps has been 5.
+ *
+ * There was very small number of attempts and extremely long waiting (1s)
+ * that is useless on machines with large number of concurret mount processes.
+ *
+ * Now we wait few thousand microseconds between attempts and we have global
+ * time limit (30s) rather than limit for number of attempts. The advantage
+ * is that this method also counts time which we spend in fcntl(F_SETLKW) and
+ * number of attempts is not so much restricted.
+ *
+ * -- kzak@redhat.com [2007-Mar-2007]
+ */
+
+/* maximum seconds between first and last attempt */
+#define MOUNTLOCK_MAXTIME 30
+
+/* sleep time (in microseconds, max=999999) between attempts */
+#define MOUNTLOCK_WAITTIME 5000
+
+void
+lock_mtab (void) {
+ int i;
+ struct timespec waittime;
+ struct timeval maxtime;
+ char linktargetfile[MOUNTLOCK_LINKTARGET_LTH];
+
+ if (!signals_have_been_setup) {
+ int sig = 0;
+ struct sigaction sa;
+
+ sa.sa_handler = handler;
+ sa.sa_flags = 0;
+ sigfillset (&sa.sa_mask);
+
+ while (sigismember (&sa.sa_mask, ++sig) != -1
+ && sig != SIGCHLD) {
+ if (sig == SIGALRM)
+ sa.sa_handler = setlkw_timeout;
+ else
+ sa.sa_handler = handler;
+ sigaction (sig, &sa, (struct sigaction *) 0);
+ }
+ signals_have_been_setup = 1;
+ }
+
+ sprintf(linktargetfile, MOUNTLOCK_LINKTARGET, getpid ());
+
+ i = open (linktargetfile, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
+ if (i < 0) {
+ int errsv = errno;
+ /* linktargetfile does not exist (as a file)
+ and we cannot create it. Read-only filesystem?
+ Too many files open in the system?
+ Filesystem full? */
+ die (EX_FILEIO, _("can't create lock file %s: %s "
+ "(use -n flag to override)"),
+ linktargetfile, strerror (errsv));
+ }
+ close(i);
+
+ gettimeofday(&maxtime, NULL);
+ maxtime.tv_sec += MOUNTLOCK_MAXTIME;
+
+ waittime.tv_sec = 0;
+ waittime.tv_nsec = (1000 * MOUNTLOCK_WAITTIME);
+
+ /* Repeat until it was us who made the link */
+ while (!we_created_lockfile) {
+ struct timeval now;
+ struct flock flock;
+ int errsv, j;
+
+ j = link(linktargetfile, _PATH_MOUNTED_LOCK);
+ errsv = errno;
+
+ if (j == 0)
+ we_created_lockfile = 1;
+
+ if (j < 0 && errsv != EEXIST) {
+ (void) unlink(linktargetfile);
+ die (EX_FILEIO, _("can't link lock file %s: %s "
+ "(use -n flag to override)"),
+ _PATH_MOUNTED_LOCK, strerror (errsv));
+ }
+
+ lockfile_fd = open (_PATH_MOUNTED_LOCK, O_WRONLY);
+
+ if (lockfile_fd < 0) {
+ /* Strange... Maybe the file was just deleted? */
+ int errsv = errno;
+ gettimeofday(&now, NULL);
+ if (errno == ENOENT && now.tv_sec < maxtime.tv_sec) {
+ we_created_lockfile = 0;
+ continue;
+ }
+ (void) unlink(linktargetfile);
+ die (EX_FILEIO, _("can't open lock file %s: %s "
+ "(use -n flag to override)"),
+ _PATH_MOUNTED_LOCK, strerror (errsv));
+ }
+
+ flock.l_type = F_WRLCK;
+ flock.l_whence = SEEK_SET;
+ flock.l_start = 0;
+ flock.l_len = 0;
+
+ if (j == 0) {
+ /* We made the link. Now claim the lock. */
+ if (fcntl (lockfile_fd, F_SETLK, &flock) == -1) {
+ if (verbose) {
+ int errsv = errno;
+ printf(_("Can't lock lock file %s: %s\n"),
+ _PATH_MOUNTED_LOCK, strerror (errsv));
+ }
+ /* proceed, since it was us who created the lockfile anyway */
+ }
+ (void) unlink(linktargetfile);
+ } else {
+ /* Someone else made the link. Wait. */
+ gettimeofday(&now, NULL);
+ if (now.tv_sec < maxtime.tv_sec) {
+ alarm(maxtime.tv_sec - now.tv_sec);
+ if (fcntl (lockfile_fd, F_SETLKW, &flock) == -1) {
+ int errsv = errno;
+ (void) unlink(linktargetfile);
+ die (EX_FILEIO, _("can't lock lock file %s: %s"),
+ _PATH_MOUNTED_LOCK, (errno == EINTR) ?
+ _("timed out") : strerror (errsv));
+ }
+ alarm(0);
+
+ nanosleep(&waittime, NULL);
+ } else {
+ (void) unlink(linktargetfile);
+ die (EX_FILEIO, _("Cannot create link %s\n"
+ "Perhaps there is a stale lock file?\n"),
+ _PATH_MOUNTED_LOCK);
+ }
+ close(lockfile_fd);
+ }
+ }
+}
+
+/* returns whole option with name @optname from @src list */
+char *
+get_option(const char *optname, const char *src, size_t *len)
+{
+ char *opt, *end;
+ size_t sz;
+
+ if (!src)
+ return NULL;
+
+ opt = strstr(src, optname);
+ if (!opt)
+ return NULL;
+
+ end = strchr(opt, ',');
+ sz = end && end > opt ? (size_t) (end - opt) : strlen(opt);
+
+ if (len)
+ *len = sz;
+
+ if ((opt == src || *(opt - 1) == ',') &&
+ (*(opt + sz) == '\0' || *(opt + sz) == ','))
+ return opt;
+
+ return NULL;
+}
+
+ /* If @list contains "user=peter" and @s is "user=", return "peter" */
+char *
+get_option_value(const char *list, const char *s)
+{
+ const char *t;
+ size_t n = strlen(s);
+
+ while (list && *list) {
+ if (strncmp(list, s, n) == 0) {
+ s = t = list + n;
+ while (*s && *s != ',')
+ s++;
+ return xstrndup(t, s-t);
+ }
+ while (*list && *list++ != ',') ;
+ }
+ return NULL;
+}
+
+static int
+cpy_option(const char *optname, char *dest, const char *src)
+{
+ char *opt;
+ size_t sz;
+
+ opt = get_option(optname, src, &sz);
+ if (!opt)
+ /* the option doesn't exist */
+ return 0;
+
+ if (get_option(optname, dest, NULL))
+ /* the options is already in dest */
+ return 0;
+
+ if (*dest) {
+ dest = dest + strlen(dest);
+ *dest++ = ','; /* separator */
+ }
+ memcpy(dest, opt, sz); /* copy option */
+ *(dest + sz) = '\0'; /* terminator */
+
+ return 1;
+}
+
+/* Generates (and allocates) new options for remount
+ *
+ * We cannot blindly replace the old options, otherwise we will lost some
+ * internally generated stuff (e.g loop=).
+ */
+static char *
+mk_remount_opts(const char *old, const char *instead)
+{
+ char *new;
+ size_t sz;
+
+ if (old == NULL && instead == NULL)
+ return NULL;
+ if (!old)
+ return xstrdup(instead);
+
+ /* max size of new options is:
+ * old + new + '\0' + separator (for each copied option)
+ */
+ sz = strlen(old) + (instead ? strlen(instead) : 0) + 2;
+ new = xmalloc(sz);
+ if (instead && *instead)
+ strncpy(new, instead, sz);
+ else
+ *new = '\0';
+
+ cpy_option("loop=", new, old);
+
+ return new;
+}
+
+/*
+ * Update the mtab.
+ * Used by umount with null INSTEAD: remove the last DIR entry.
+ * Used by mount upon a remount: update option part,
+ * and complain if a wrong device or type was given.
+ * [Note that often a remount will be a rw remount of /
+ * where there was no entry before, and we'll have to believe
+ * the values given in INSTEAD.]
+ */
+
+void
+update_mtab (const char *dir, struct my_mntent *instead) {
+ mntFILE *mfp, *mftmp;
+ const char *fnam = _PATH_MOUNTED;
+ struct mntentchn mtabhead; /* dummy */
+ struct mntentchn *mc, *mc0 = NULL, *absent = NULL;
+ struct stat sbuf;
+ int fd;
+
+ if (mtab_does_not_exist() || !mtab_is_writable())
+ return;
+
+ lock_mtab();
+
+ /* having locked mtab, read it again */
+ mc0 = mc = &mtabhead;
+ mc->nxt = mc->prev = NULL;
+
+ mfp = my_setmntent(fnam, "r");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
+ int errsv = errno;
+ error (_("cannot open %s (%s) - mtab not updated"),
+ fnam, strerror (errsv));
+ goto leave;
+ }
+
+ read_mntentchn(mfp, fnam, mc);
+
+ /* find last occurrence of dir */
+ if (dir) {
+ for (mc = mc0->prev; mc && mc != mc0; mc = mc->prev)
+ if (streq(mc->m.mnt_dir, dir))
+ break;
+ }
+ if (dir && mc && mc != mc0) {
+ if (instead == NULL) {
+ /* An umount - remove entry */
+ if (mc && mc != mc0) {
+ mc->prev->nxt = mc->nxt;
+ mc->nxt->prev = mc->prev;
+ my_free_mc(mc);
+ }
+ } else if (!strcmp(mc->m.mnt_dir, instead->mnt_dir)) {
+ /* A remount */
+ char *opts = mk_remount_opts(mc->m.mnt_opts,
+ instead->mnt_opts);
+ my_free(mc->m.mnt_opts);
+ mc->m.mnt_opts = opts;
+ } else {
+ /* A move */
+ my_free(mc->m.mnt_dir);
+ mc->m.mnt_dir = xstrdup(instead->mnt_dir);
+ }
+ } else if (instead) {
+ /* not found, add a new entry */
+ absent = xmalloc(sizeof(*absent));
+ absent->m.mnt_fsname = xstrdup(instead->mnt_fsname);
+ absent->m.mnt_dir = xstrdup(instead->mnt_dir);
+ absent->m.mnt_type = xstrdup(instead->mnt_type);
+ absent->m.mnt_opts = xstrdup(instead->mnt_opts);
+ absent->m.mnt_freq = instead->mnt_freq;
+ absent->m.mnt_passno = instead->mnt_passno;
+ absent->nxt = mc0;
+ if (mc0->prev != NULL) {
+ absent->prev = mc0->prev;
+ mc0->prev->nxt = absent;
+ } else {
+ absent->prev = mc0;
+ }
+ mc0->prev = absent;
+ if (mc0->nxt == NULL)
+ mc0->nxt = absent;
+ }
+
+ /* write chain to mtemp */
+ mftmp = my_setmntent (_PATH_MOUNTED_TMP, "w");
+ if (mftmp == NULL || mftmp->mntent_fp == NULL) {
+ int errsv = errno;
+ error (_("cannot open %s (%s) - mtab not updated"),
+ _PATH_MOUNTED_TMP, strerror (errsv));
+ goto leave;
+ }
+
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
+ if (my_addmntent(mftmp, &(mc->m)) == 1) {
+ int errsv = errno;
+ error(_("error writing %s: %s"),
+ _PATH_MOUNTED_TMP, strerror (errsv));
+ goto leave;
+ }
+ }
+
+ discard_mntentchn(mc0);
+ mc0 = NULL;
+
+ /*
+ * We have to be paranoid with write() to avoid incomplete
+ * /etc/mtab. Users are able to control writing by RLIMIT_FSIZE.
+ */
+ if (fflush(mftmp->mntent_fp) != 0) {
+ int errsv = errno;
+ error (_("%s: cannot fflush changes: %s"),
+ _PATH_MOUNTED_TMP, strerror (errsv));
+ goto leave;
+ }
+
+ fd = fileno(mftmp->mntent_fp);
+
+ /*
+ * It seems that better is incomplete and broken /etc/mtab that
+ * /etc/mtab that is writeable for non-root users.
+ *
+ * We always skip rename() when chown() and chmod() failed.
+ * -- kzak, 11-Oct-2007
+ */
+
+ if (fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
+ int errsv = errno;
+ fprintf(stderr, _("error changing mode of %s: %s\n"),
+ _PATH_MOUNTED_TMP, strerror (errsv));
+ goto leave;
+ }
+
+ /*
+ * If mount is setuid and some non-root user mounts sth,
+ * then mtab.tmp might get the group of this user. Copy uid/gid
+ * from the present mtab before renaming.
+ */
+ if (stat(_PATH_MOUNTED, &sbuf) == 0) {
+ if (fchown(fd, sbuf.st_uid, sbuf.st_gid) < 0) {
+ int errsv = errno;
+ fprintf (stderr, _("error changing owner of %s: %s\n"),
+ _PATH_MOUNTED_TMP, strerror(errsv));
+ goto leave;
+ }
+ }
+
+ my_endmntent (mftmp);
+
+ /* rename mtemp to mtab */
+ if (rename (_PATH_MOUNTED_TMP, _PATH_MOUNTED) < 0) {
+ int errsv = errno;
+ fprintf(stderr, _("can't rename %s to %s: %s\n"),
+ _PATH_MOUNTED_TMP, _PATH_MOUNTED, strerror(errsv));
+ }
+
+ leave:
+ if (mc0)
+ discard_mntentchn(mc0);
+ unlink(_PATH_MOUNTED_TMP);
+ unlock_mtab();
+}
+
+
+#ifdef MAIN_TEST_MTABLOCK
+
+/*
+ * This is mtab locking code test for:
+ *
+ * - performance (how many concurrent processes)
+ *
+ * - lock reliability (is possible to see corrupted data if more
+ * concurrent processes modify a same file)
+ *
+ * The test is very simple -- it reads a number from locked file, increments the
+ * number and writes the number back to the file.
+ */
+/* dummy */
+char *fsprobe_get_label_by_devname(const char *spec __attribute__((__unused__)))
+{
+ return NULL;
+}
+char *fsprobe_get_uuid_by_devname(const char *spec __attribute__((__unused__)))
+{
+ return NULL;
+}
+int fsprobe_parse_spec(const char *spec __attribute__((__unused__)),
+ char **name __attribute__((__unused__)),
+ char **value __attribute__((__unused__)))
+{
+ return 0;
+}
+struct my_mntent *my_getmntent (mntFILE *mfp __attribute__((__unused__)))
+{
+ return NULL;
+}
+mntFILE *my_setmntent (const char *file __attribute__((__unused__)),
+ char *mode __attribute__((__unused__)))
+{
+ return NULL;
+}
+void my_endmntent (mntFILE *mfp __attribute__((__unused__)))
+{
+ /* nothing */
+}
+int my_addmntent (mntFILE *mfp __attribute__((__unused__)),
+ struct my_mntent *mnt __attribute__((__unused__)))
+{
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ time_t synctime;
+ char *filename;
+ int nloops, id, i;
+ pid_t pid = getpid();
+ unsigned int usecs;
+ struct timeval tv;
+ struct stat st;
+ long last = 0;
+
+ progname = argv[0];
+
+ if (argc < 3)
+ die(EXIT_FAILURE,
+ "usage: %s <id> <synctime> <file> <nloops>\n",
+ progname);
+
+ id = atoi(argv[1]);
+ synctime = (time_t) atol(argv[2]);
+ filename = argv[3];
+ nloops = atoi(argv[4]);
+
+ if (stat(filename, &st) < -1)
+ die(EXIT_FAILURE, "%s: %m\n", filename);
+
+ fprintf(stderr, "%05d (pid=%05d): START\n", id, pid);
+
+ gettimeofday(&tv, NULL);
+ if (synctime && synctime - tv.tv_sec > 1) {
+ usecs = ((synctime - tv.tv_sec) * 1000000UL) -
+ (1000000UL - tv.tv_usec);
+ usleep(usecs);
+ }
+
+ for (i = 0; i < nloops; i++) {
+ FILE *f;
+ long num;
+ char buf[256];
+
+ lock_mtab();
+
+ if (!(f = fopen(filename, "r"))) {
+ unlock_mtab();
+ die(EXIT_FAILURE, "ERROR: %d (pid=%d, loop=%d): "
+ "open for read failed\n", id, pid, i);
+ }
+ if (!fgets(buf, sizeof(buf), f)) {
+ unlock_mtab();
+ die(EXIT_FAILURE, "ERROR: %d (pid=%d, loop=%d): "
+ "read failed\n", id, pid, i);
+ }
+ fclose(f);
+
+ num = atol(buf) + 1;
+
+ if (!(f = fopen(filename, "w"))) {
+ unlock_mtab();
+ die(EXIT_FAILURE, "ERROR: %d (pid=%d, loop=%d): "
+ "open for write failed\n", id, pid, i);
+ }
+ fprintf(f, "%ld", num);
+ fclose(f);
+
+ unlock_mtab();
+
+ gettimeofday(&tv, NULL);
+
+ fprintf(stderr, "%010ld.%06ld %04d (pid=%05d, loop=%05d): "
+ "num=%09ld last=%09ld\n",
+ tv.tv_sec, tv.tv_usec, id,
+ pid, i, num, last);
+ last = num;
+
+ /* The mount command usually finish after mtab update. We
+ * simulate this via short sleep -- it's also enough to make
+ * concurrent processes happy.
+ */
+ usleep(50000);
+ }
+
+ fprintf(stderr, "%05d (pid=%05d): DONE\n", id, pid);
+
+ exit(EXIT_SUCCESS);
+}
+#endif
diff --git a/mount-deprecated/fstab.h b/mount-deprecated/fstab.h
new file mode 100644
index 000000000..bbef33b51
--- /dev/null
+++ b/mount-deprecated/fstab.h
@@ -0,0 +1,44 @@
+#ifndef MOUNT_FSTAB_H
+#define MOUNT_FSTAB_H
+
+#include "mount_mntent.h"
+
+#ifdef HAVE_LIBMOUNT_MOUNT
+#define USE_UNSTABLE_LIBMOUNT_API
+#include <libmount.h>
+#endif
+
+int mtab_is_writable(void);
+int mtab_is_a_symlink(void);
+int mtab_does_not_exist(void);
+void reset_mtab_info(void);
+int is_mounted_once(const char *name);
+
+struct mntentchn {
+ struct mntentchn *nxt, *prev;
+ struct my_mntent m;
+};
+
+struct mntentchn *mtab_head (void);
+struct mntentchn *getmntfile (const char *name);
+struct mntentchn *getmntfilebackward (const char *name, struct mntentchn *mcprev);
+struct mntentchn *getmntoptfile (const char *file);
+struct mntentchn *getmntdirbackward (const char *dir, struct mntentchn *mc);
+struct mntentchn *getmntdevbackward (const char *dev, struct mntentchn *mc);
+
+struct mntentchn *fstab_head (void);
+struct mntentchn *getfs_by_dir (const char *dir);
+struct mntentchn *getfs_by_spec (const char *spec);
+struct mntentchn *getfs_by_devname (const char *devname);
+struct mntentchn *getfs_by_devdir (const char *dev, const char *dir);
+struct mntentchn *getfs_by_uuid (const char *uuid);
+struct mntentchn *getfs_by_label (const char *label);
+
+void lock_mtab (void);
+void unlock_mtab (void);
+void update_mtab (const char *special, struct my_mntent *with);
+
+char *get_option(const char *optname, const char *src, size_t *len);
+char *get_option_value(const char *list, const char *s);
+
+#endif /* MOUNT_FSTAB_H */
diff --git a/mount-deprecated/getusername.c b/mount-deprecated/getusername.c
new file mode 100644
index 000000000..9835768ca
--- /dev/null
+++ b/mount-deprecated/getusername.c
@@ -0,0 +1,14 @@
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include "getusername.h"
+
+char *
+getusername() {
+ char *user = 0;
+ struct passwd *pw = getpwuid(getuid());
+
+ if (pw)
+ user = pw->pw_name;
+ return user;
+}
diff --git a/mount-deprecated/getusername.h b/mount-deprecated/getusername.h
new file mode 100644
index 000000000..808ac9b88
--- /dev/null
+++ b/mount-deprecated/getusername.h
@@ -0,0 +1 @@
+extern char *getusername(void);
diff --git a/mount-deprecated/mount.8 b/mount-deprecated/mount.8
new file mode 100644
index 000000000..91dcc24f2
--- /dev/null
+++ b/mount-deprecated/mount.8
@@ -0,0 +1,2857 @@
+.\" Copyright (c) 1996-2004 Andries Brouwer
+.\"
+.\" This page is somewhat derived from a page that was
+.\" (c) 1980, 1989, 1991 The Regents of the University of California
+.\" and had been heavily modified by Rik Faith and myself.
+.\" (Probably no BSD text remains.)
+.\" Fragments of text were written by Werner Almesberger, Remy Card,
+.\" Stephen Tweedie and Eric Youngdale.
+.\"
+.\" This is free documentation; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License as
+.\" published by the Free Software Foundation; either version 2 of
+.\" the License, or (at your option) any later version.
+.\"
+.\" The GNU General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+.\"
+.\" 960705, aeb: version for mount-2.7g
+.\" 970114, aeb: xiafs and ext are dead; romfs is new
+.\" 970623, aeb: -F option
+.\" 970914, reg: -s option
+.\" 981111, K.Garloff: /etc/filesystems
+.\" 990111, aeb: documented /sbin/mount.smbfs
+.\" 990730, Yann Droneaud <lch@multimania.com>: updated page
+.\" 991214, Elrond <Elrond@Wunder-Nett.org>: added some docs on devpts
+.\" 010714, Michael K. Johnson <johnsonm@redhat.com> added -O
+.\" 010725, Nikita Danilov <NikitaDanilov@Yahoo.COM>: reiserfs options
+.\" 011124, Karl Eichwalder <ke@gnu.franken.de>: tmpfs options
+.\"
+.TH MOUNT 8 "December 2004" "util-linux" "System Administration"
+.SH NAME
+mount \- mount a filesystem
+.SH SYNOPSIS
+.B mount
+.RB [ \-lhV ]
+.LP
+.BI "mount \-a
+.RB [ \-fFnrsvw ]
+.RB [ \-t
+.IR vfstype ]
+.RB [ \-O
+.IR optlist ]
+.LP
+.B mount
+.RB [ \-fnrsvw ]
+.RB [ \-o
+.IR option [ \fB,\fPoption ]...]
+.IR device | dir
+.LP
+.B mount
+.RB [ \-fnrsvw ]
+.RB [ \-t
+.IB vfstype ]
+.RB [ \-o
+.IR options ]
+.I device dir
+.SH DESCRIPTION
+All files accessible in a Unix system are arranged in one big
+tree, the file hierarchy, rooted at
+.BR / .
+These files can be spread out over several devices. The
+.B mount
+command serves to attach the filesystem found on some device
+to the big file tree. Conversely, the
+.BR umount (8)
+command will detach it again.
+
+The standard form of the
+.B mount
+command, is
+.RS
+
+.br
+.BI "mount \-t" " type device dir"
+.br
+
+.RE
+This tells the kernel to attach the filesystem found on
+.I device
+(which is of type
+.IR type )
+at the directory
+.IR dir .
+The previous contents (if any) and owner and mode of
+.I dir
+become invisible, and as long as this filesystem remains mounted,
+the pathname
+.I dir
+refers to the root of the filesystem on
+.IR device .
+
+If only directory or device is given, for example:
+.RS
+
+.br
+.BI "mount /dir"
+.br
+
+.RE
+then mount looks for a mountpoint and if not found then for a device in the
+/etc/fstab file.
+
+.B The listing and help.
+.RS
+Three forms of invocation do not actually mount anything:
+.TP
+.B "mount \-h"
+prints a help message
+.TP
+.B "mount \-V"
+prints a version string
+.TP
+.BR "mount " [ -l "] [" "-t \fItype\fP" ]
+lists all mounted filesystems (of type
+.IR type ).
+The option \-l adds the labels in this listing.
+See below.
+.RE
+
+.B The device indication.
+.RS
+Most devices are indicated by a file name (of a block special device), like
+.IR /dev/sda1 ,
+but there are other possibilities. For example, in the case of an NFS mount,
+.I device
+may look like
+.IR knuth.cwi.nl:/dir .
+It is possible to indicate a block special device using its
+volume
+.B LABEL
+or
+.B UUID
+(see the \-L and \-U options below).
+
+The recommended setup is to use LABEL=<label> or UUID=<uuid> tags rather than
+.B /dev/disk/by-{label,uuid}
+udev symlinks in the /etc/fstab file. The tags are
+more readable, robust and portable. The
+.BR mount (8)
+command internally uses udev
+symlinks, so use the symlinks in /etc/fstab has no advantage over LABEL=/UUID=.
+For more details see
+.BR libblkid (3).
+
+Note that
+.BR mount (8)
+uses UUIDs as strings. The UUIDs from command line or
+.BR fstab (5)
+are not converted to internal binary representation. The string representation
+of the UUID should be based on lower case characters.
+
+The
+.I proc
+filesystem is not associated with a special device, and when
+mounting it, an arbitrary keyword, such as
+.I proc
+can be used instead of a device specification.
+(The customary choice
+.I none
+is less fortunate: the error message `none busy' from
+.B umount
+can be confusing.)
+.RE
+
+.B The /etc/fstab, /etc/mtab and /proc/mounts files.
+.RS
+The file
+.I /etc/fstab
+(see
+.BR fstab (5)),
+may contain lines describing what devices are usually
+mounted where, using which options.
+.LP
+The command
+.RS
+.sp
+.B mount \-a
+.RB [ \-t
+.IR type ]
+.RB [ \-O
+.IR optlist ]
+.sp
+.RE
+(usually given in a bootscript) causes all filesystems mentioned in
+.I fstab
+(of the proper type and/or having or not having the proper options)
+to be mounted as indicated, except for those whose line contains the
+.B noauto
+keyword. Adding the
+.B \-F
+option will make mount fork, so that the
+filesystems are mounted simultaneously.
+.LP
+When mounting a filesystem mentioned in
+.IR fstab
+or
+.IR mtab ,
+it suffices to give only the device, or only the mount point.
+
+
+The programs
+.B mount
+and
+.B umount
+maintain a list of currently mounted filesystems in the file
+.IR /etc/mtab .
+If no arguments are given to
+.BR mount ,
+this list is printed.
+
+The
+.B mount
+program does not read the
+.I /etc/fstab
+file if
+.I device
+(or LABEL/UUID) and
+.I dir
+are specified. For example:
+.RS
+.sp
+.B "mount /dev/foo /dir"
+.sp
+.RE
+If you want to override mount options from
+.I /etc/fstab
+you have to use:
+.RS
+.sp
+.B "mount device|dir -o <options>"
+.sp
+.RE
+and then the mount options from command line will be appended to
+the list of options from
+.IR /etc/fstab .
+The usual behaviour is that the last option wins if there is more duplicated
+options.
+
+When the
+.I proc
+filesystem is mounted (say at
+.IR /proc ),
+the files
+.I /etc/mtab
+and
+.I /proc/mounts
+have very similar contents. The former has somewhat
+more information, such as the mount options used,
+but is not necessarily up-to-date (cf. the
+.B \-n
+option below). It is possible to replace
+.I /etc/mtab
+by a symbolic link to
+.IR /proc/mounts ,
+and especially when you have very large numbers of mounts
+things will be much faster with that symlink,
+but some information is lost that way, and in particular
+using the "user" option will fail.
+.RE
+
+.B The non-superuser mounts.
+.RS
+Normally, only the superuser can mount filesystems.
+However, when
+.I fstab
+contains the
+.B user
+option on a line, anybody can mount the corresponding system.
+.LP
+Thus, given a line
+.RS
+.sp
+.B "/dev/cdrom /cd iso9660 ro,user,noauto,unhide"
+.sp
+.RE
+any user can mount the iso9660 filesystem found on his CDROM
+using the command
+.RS
+.sp
+.B "mount /dev/cdrom"
+.sp
+.RE
+or
+.RS
+.sp
+.B "mount /cd"
+.sp
+.RE
+For more details, see
+.BR fstab (5).
+Only the user that mounted a filesystem can unmount it again.
+If any user should be able to unmount, then use
+.B users
+instead of
+.B user
+in the
+.I fstab
+line.
+The
+.B owner
+option is similar to the
+.B user
+option, with the restriction that the user must be the owner
+of the special file. This may be useful e.g. for
+.I /dev/fd
+if a login script makes the console user owner of this device.
+The
+.B group
+option is similar, with the restriction that the user must be
+member of the group of the special file.
+.RE
+
+
+.B The bind mounts.
+.RS
+.\" In fact since 2.3.99. At first the syntax was mount -t bind.
+Since Linux 2.4.0 it is possible to remount part of the
+file hierarchy somewhere else. The call is
+.RS
+.br
+.B mount --bind
+.I olddir newdir
+.RE
+or shortoption
+.RS
+.br
+.B mount -B
+.I olddir newdir
+.RE
+or fstab entry is:
+.RS
+.br
+.I /olddir
+.I /newdir
+.B none bind
+.RE
+
+After this call the same contents is accessible in two places.
+One can also remount a single file (on a single file). It's also
+possible to use the bind mount to create a mountpoint from a regular
+directory, for example:
+
+.RS
+.br
+.B mount --bind
+.I foo foo
+.RE
+
+The bind mount call attaches only (part of) a single filesystem, not possible
+submounts. The entire file hierarchy including submounts is attached
+a second place using
+
+.RS
+.br
+.B mount --rbind
+.I olddir newdir
+.RE
+
+or shortoption
+
+.RS
+.br
+.B mount -R
+.I olddir newdir
+.RE
+.\" available since Linux 2.4.11.
+
+Note that the filesystem mount options will remain the same as those
+on the original mount point, and cannot be changed by passing the -o
+option along with --bind/--rbind. The mount options can be
+changed by a separate remount command, for example:
+
+.RS
+.br
+.B mount --bind
+.I olddir newdir
+.br
+.B mount -o remount,ro
+.I newdir
+.RE
+
+Note that behavior of the remount operation depends on the /etc/mtab file. The
+first command stores the 'bind' flag to the /etc/mtab file and the second
+command reads the flag from the file. If you have a system without the
+/etc/mtab file or if you explicitly define source and target for the remount
+command (then mount(8) does not read /etc/mtab), then you have to use bind flag
+(or option) for the remount command too. For example:
+
+.RS
+.br
+.B mount --bind
+.I olddir newdir
+.br
+.B mount -o remount,ro,bind
+.I olddir newdir
+.RE
+.RE
+
+.B The move operation.
+.RS
+Since Linux 2.5.1 it is possible to atomically move a
+.B mounted tree
+to another place. The call is
+.RS
+.br
+.B mount --move
+.I olddir newdir
+.RE
+or shortoption
+.RS
+.br
+.B mount -M
+.I olddir newdir
+.RE
+This will cause the contents which previously appeared under olddir to be
+accessed under newdir. The physical location of the files is not changed.
+Note that the
+.I olddir
+has to be a mountpoint.
+.RE
+
+.B The shared subtrees operations.
+.RS
+Since Linux 2.6.15 it is possible to mark a mount and its submounts as shared,
+private, slave or unbindable. A shared mount provides ability to create mirrors
+of that mount such that mounts and umounts within any of the mirrors propagate
+to the other mirror. A slave mount receives propagation from its master, but
+any not vice-versa. A private mount carries no propagation abilities. A
+unbindable mount is a private mount which cannot be cloned through a bind
+operation. Detailed semantics is documented in Documentation/filesystems/sharedsubtree.txt
+file in the kernel source tree.
+
+.RS
+.nf
+.BI "mount --make-shared " mountpoint
+.BI "mount --make-slave " mountpoint
+.BI "mount --make-private " mountpoint
+.BI "mount --make-unbindable " mountpoint
+.fi
+.RE
+
+The following commands allows one to recursively change the type of all the
+mounts under a given mountpoint.
+
+.RS
+.nf
+.BI "mount --make-rshared " mountpoint
+.BI "mount --make-rslave " mountpoint
+.BI "mount --make-rprivate " mountpoint
+.BI "mount --make-runbindable " mountpoint
+.fi
+.RE
+.RE
+
+.SH COMMAND LINE OPTIONS
+The full set of mount options used by an invocation of
+.B mount
+is determined by first extracting the
+mount options for the filesystem from the
+.I fstab
+table, then applying any options specified by the
+.B \-o
+argument, and finally applying a
+.BR \-r " or " \-w
+option, when present.
+
+Command line options available for the
+.B mount
+command:
+.IP "\fB\-V, \-\-version\fP"
+Output version.
+.IP "\fB\-h, \-\-help\fP"
+Print a help message.
+.IP "\fB\-v, \-\-verbose\fP"
+Verbose mode.
+.IP "\fB\-a, \-\-all\fP"
+Mount all filesystems (of the given types) mentioned in
+.IR fstab .
+.IP "\fB\-F, \-\-fork\fP"
+(Used in conjunction with
+.BR \-a .)
+Fork off a new incarnation of mount for each device.
+This will do the mounts on different devices or different NFS servers
+in parallel.
+This has the advantage that it is faster; also NFS timeouts go in
+parallel. A disadvantage is that the mounts are done in undefined order.
+Thus, you cannot use this option if you want to mount both
+.I /usr
+and
+.IR /usr/spool .
+.IP "\fB\-f, \-\-fake\fP"
+Causes everything to be done except for the actual system call; if it's not
+obvious, this ``fakes'' mounting the filesystem. This option is useful in
+conjunction with the
+.B \-v
+flag to determine what the
+.B mount
+command is trying to do. It can also be used to add entries for devices
+that were mounted earlier with the -n option. The -f option checks for
+existing record in /etc/mtab and fails when the record already
+exists (with regular non-fake mount, this check is done by kernel).
+.IP "\fB\-i, \-\-internal\-only\fP"
+Don't call the /sbin/mount.<filesystem> helper even if it exists.
+.IP "\fB\-l\fP"
+Add the labels in the mount output. Mount must have
+permission to read the disk device (e.g. be suid root) for this to work.
+One can set such a label for ext2, ext3 or ext4 using the
+.BR e2label (8)
+utility, or for XFS using
+.BR xfs_admin (8),
+or for reiserfs using
+.BR reiserfstune (8).
+.IP "\fB\-n, \-\-no\-mtab\fP"
+Mount without writing in
+.IR /etc/mtab .
+This is necessary for example when
+.I /etc
+is on a read-only filesystem.
+.IP "\fB\-\-no\-canonicalize\fP"
+Don't canonicalize paths. The mount command canonicalizes all paths
+(from command line or fstab) and stores canonicalized paths to the
+.IR /etc/mtab
+file. This option can be used together with the
+.B \-f
+flag for already canonicalized absolut paths.
+.IP "\fB\-p, \-\-pass\-fd \fInum\fP"
+In case of a loop mount with encryption, read the passphrase from
+file descriptor
+.I num
+instead of from the terminal.
+.IP "\fB\-s\fP"
+Tolerate sloppy mount options rather than failing. This will ignore
+mount options not supported by a filesystem type. Not all filesystems
+support this option. This option exists for support of the Linux
+autofs\-based automounter.
+.IP "\fB\-r, \-\-read\-only\fP"
+Mount the filesystem read-only. A synonym is
+.BR "\-o ro" .
+
+Note that, depending on the filesystem type, state and kernel behavior, the
+system may still write to the device. For example, Ext3 or ext4 will replay its
+journal if the filesystem is dirty. To prevent this kind of write access, you
+may want to mount ext3 or ext4 filesystem with "ro,noload" mount options or
+set the block device to read-only mode, see command
+.BR blockdev (8).
+.IP "\fB\-w, \-\-rw\fP"
+Mount the filesystem read/write. This is the default. A synonym is
+.BR "\-o rw" .
+.IP "\fB\-L \fIlabel\fP"
+Mount the partition that has the specified
+.IR label .
+.IP "\fB\-U \fIuuid\fP"
+Mount the partition that has the specified
+.IR uuid .
+These two options require the file
+.I /proc/partitions
+(present since Linux 2.1.116) to exist.
+.IP "\fB\-t, \-\-types \fIvfstype\fP"
+The argument following the
+.B \-t
+is used to indicate the filesystem type. The filesystem types which are
+currently supported include:
+.IR adfs ,
+.IR affs ,
+.IR autofs ,
+.IR cifs ,
+.IR coda ,
+.IR coherent ,
+.IR cramfs ,
+.IR debugfs ,
+.IR devpts ,
+.IR efs ,
+.IR ext ,
+.IR ext2 ,
+.IR ext3 ,
+.IR ext4 ,
+.IR hfs ,
+.IR hfsplus ,
+.IR hpfs ,
+.IR iso9660 ,
+.IR jfs ,
+.IR minix ,
+.IR msdos ,
+.IR ncpfs ,
+.IR nfs ,
+.IR nfs4 ,
+.IR ntfs ,
+.IR proc ,
+.IR qnx4 ,
+.IR ramfs ,
+.IR reiserfs ,
+.IR romfs ,
+.IR squashfs ,
+.IR smbfs ,
+.IR sysv ,
+.IR tmpfs ,
+.IR ubifs ,
+.IR udf ,
+.IR ufs ,
+.IR umsdos ,
+.IR usbfs ,
+.IR vfat ,
+.IR xenix ,
+.IR xfs ,
+.IR xiafs .
+Note that coherent, sysv and xenix are equivalent and that
+.I xenix
+and
+.I coherent
+will be removed at some point in the future \(em use
+.I sysv
+instead. Since kernel version 2.1.21 the types
+.I ext
+and
+.I xiafs
+do not exist anymore. Earlier,
+.I usbfs
+was known as
+.IR usbdevfs .
+Note, the real list of all supported filesystems depends on your
+kernel.
+
+The programs
+.B mount
+and
+.B umount
+support filesystem subtypes. The subtype is defined by '.subtype' suffix. For
+example 'fuse.sshfs'. It's recommended to use subtype notation rather than add
+any prefix to the mount source (for example 'sshfs#example.com' is
+depreacated).
+
+For most types all the
+.B mount
+program has to do is issue a simple
+.IR mount (2)
+system call, and no detailed knowledge of the filesystem type is required.
+For a few types however (like nfs, nfs4, cifs, smbfs, ncpfs) ad hoc code is
+necessary. The nfs, nfs4, cifs, smbfs, and ncpfs filesystems
+have a separate mount program. In order to make it possible to
+treat all types in a uniform way, mount will execute the program
+.BI /sbin/mount. TYPE
+(if that exists) when called with type
+.IR TYPE .
+Since various versions of the
+.B smbmount
+program have different calling conventions,
+.B /sbin/mount.smbfs
+may have to be a shell script that sets up the desired call.
+
+If no
+.B \-t
+option is given, or if the
+.B auto
+type is specified, mount will try to guess the desired type.
+Mount uses the blkid library for guessing the filesystem
+type; if that does not turn up anything that looks familiar,
+mount will try to read the file
+.IR /etc/filesystems ,
+or, if that does not exist,
+.IR /proc/filesystems .
+All of the filesystem types listed there will be tried,
+except for those that are labeled "nodev" (e.g.,
+.IR devpts ,
+.I proc
+and
+.IR nfs ).
+If
+.I /etc/filesystems
+ends in a line with a single * only, mount will read
+.I /proc/filesystems
+afterwards.
+
+The
+.B auto
+type may be useful for user-mounted floppies.
+Creating a file
+.I /etc/filesystems
+can be useful to change the probe order (e.g., to try vfat before msdos
+or ext3 before ext2) or if you use a kernel module autoloader.
+
+More than one type may be specified in a comma separated
+list. The list of filesystem types can be prefixed with
+.B no
+to specify the filesystem types on which no action should be taken.
+(This can be meaningful with the
+.B \-a
+option.) For example, the command:
+.RS
+.RS
+.sp
+.B "mount \-a \-t nomsdos,ext"
+.sp
+.RE
+mounts all filesystems except those of type
+.I msdos
+and
+.IR ext .
+.RE
+.IP "\fB\-O, \-\-test-opts \fIopts\fP"
+Used in conjunction with
+.BR \-a ,
+to limit the set of filesystems to which the
+.B \-a
+is applied. Like
+.B \-t
+in this regard except that it is useless except in the context of
+.BR \-a .
+For example, the command:
+.RS
+.RS
+.sp
+.B "mount \-a \-O no_netdev"
+.sp
+.RE
+mounts all filesystems except those which have the option
+.I _netdev
+specified in the options field in the
+.I /etc/fstab
+file.
+
+It is different from
+.B \-t
+in that each option is matched exactly; a leading
+.B no
+at the beginning of one option does not negate the rest.
+
+The
+.B \-t
+and
+.B \-O
+options are cumulative in effect; that is, the command
+.RS
+.sp
+.B "mount \-a \-t ext2 \-O _netdev"
+.sp
+.RE
+mounts all ext2 filesystems with the _netdev option, not all filesystems
+that are either ext2 or have the _netdev option specified.
+.RE
+.IP "\fB\-o, \-\-options \fIopts\fP"
+Options are specified with a
+.B \-o
+flag followed by a comma separated string of options. For example:
+.RS
+.RS
+.sp
+.B "mount LABEL=mydisk \-o noatime,nouser"
+.sp
+.RE
+
+For more details, see
+.B FILESYSTEM INDEPENDENT MOUNT OPTIONS
+and
+.B FILESYSTEM SPECIFIC MOUNT OPTIONS
+sections.
+.RE
+.IP "\fB\-B, \-\-bind\fP"
+Remount a subtree somewhere else (so that its contents are available
+in both places). See above.
+.IP "\fB\-R, \-\-rbind\fP"
+Remount a subtree and all possible submounts somewhere else (so that its
+contents are available in both places). See above.
+.IP "\fB\-M, \-\-move\fP"
+Move a subtree to some other place. See above.
+
+.SH FILESYSTEM INDEPENDENT MOUNT OPTIONS
+Some of these options are only useful when they appear in the
+.I /etc/fstab
+file.
+
+Some of these options could be enabled or disabled by default
+in the system kernel. To check the current setting see the options
+in /proc/mounts.
+
+The following options apply to any filesystem that is being
+mounted (but not every filesystem actually honors them - e.g., the
+.B sync
+option today has effect only for ext2, ext3, fat, vfat and ufs):
+
+.TP
+.B async
+All I/O to the filesystem should be done asynchronously. (See also the
+.B sync
+option.)
+.TP
+.B atime
+Do not use noatime feature, then the inode access time is controlled by kernel
+defaults. See also the description for
+.B strictatime
+and
+.B relatime
+mount options.
+.TP
+.B noatime
+Do not update inode access times on this filesystem (e.g., for faster
+access on the news spool to speed up news servers).
+.TP
+.B auto
+Can be mounted with the
+.B \-a
+option.
+.TP
+.B noauto
+Can only be mounted explicitly (i.e., the
+.B \-a
+option will not cause the filesystem to be mounted).
+.TP
+\fBcontext=\fP\fIcontext\fP, \fBfscontext=\fP\fIcontext\fP, \fBdefcontext=\fP\fIcontext\fP and \fBrootcontext=\fP\fIcontext\fP
+The
+.BR context=
+option is useful when mounting filesystems that do not support
+extended attributes, such as a floppy or hard disk formatted with VFAT, or
+systems that are not normally running under SELinux, such as an ext3 formatted
+disk from a non-SELinux workstation. You can also use
+.BR context=
+on filesystems you do not trust, such as a floppy. It also helps in compatibility with
+xattr-supporting filesystems on earlier 2.4.<x> kernel versions. Even where
+xattrs are supported, you can save time not having to label every file by
+assigning the entire disk one security context.
+
+A commonly used option for removable media is
+.BR context="system_u:object_r:removable_t" .
+
+Two other options are
+.BR fscontext=
+and
+.BR defcontext= ,
+both of which are mutually exclusive of the context option. This means you
+can use fscontext and defcontext with each other, but neither can be used with
+context.
+
+The
+.BR fscontext=
+option works for all filesystems, regardless of their xattr
+support. The fscontext option sets the overarching filesystem label to a
+specific security context. This filesystem label is separate from the
+individual labels on the files. It represents the entire filesystem for
+certain kinds of permission checks, such as during mount or file creation.
+Individual file labels are still obtained from the xattrs on the files
+themselves. The context option actually sets the aggregate context that
+fscontext provides, in addition to supplying the same label for individual
+files.
+
+You can set the default security context for unlabeled files using
+.BR defcontext=
+option. This overrides the value set for unlabeled files in the policy and requires a
+filesystem that supports xattr labeling.
+
+The
+.BR rootcontext=
+option allows you to explicitly label the root inode of a FS being mounted
+before that FS or inode because visible to userspace. This was found to be
+useful for things like stateless linux.
+
+Note that kernel rejects any remount request that includes the context
+option even if unchanged from the current context.
+
+.B Warning that \fIcontext\fP value might contains comma
+and in this case the value has to be properly quoted otherwise
+.BR mount (8)
+will interpret the comma as separator between mount options. Don't forget that
+shell strips off quotes and
+.BR "double quoting is required" ,
+for example:
+.RS
+.RS
+.sp
+mount -t tmpfs none /mnt \-o 'context="system_u:object_r:tmp_t:s0:c127,c456",noexec'
+.sp
+.RE
+
+For more details, see
+.BR selinux (8)
+.RE
+
+.TP
+.B defaults
+Use default options:
+.BR rw ", " suid ", " dev ", " exec ", " auto ", " nouser ", and " async.
+.TP
+.B dev
+Interpret character or block special devices on the filesystem.
+.TP
+.B nodev
+Do not interpret character or block special devices on the file
+system.
+.TP
+.B diratime
+Update directory inode access times on this filesystem. This is the default.
+.TP
+.B nodiratime
+Do not update directory inode access times on this filesystem.
+.TP
+.B dirsync
+All directory updates within the filesystem should be done synchronously.
+This affects the following system calls: creat, link, unlink, symlink,
+mkdir, rmdir, mknod and rename.
+.TP
+.B exec
+Permit execution of binaries.
+.TP
+.B noexec
+Do not allow direct execution of any binaries on the mounted filesystem.
+(Until recently it was possible to run binaries anyway using a command like
+/lib/ld*.so /mnt/binary. This trick fails since Linux 2.4.25 / 2.6.0.)
+.TP
+.B group
+Allow an ordinary (i.e., non-root) user to mount the filesystem if one
+of his groups matches the group of the device.
+This option implies the options
+.BR nosuid " and " nodev
+(unless overridden by subsequent options, as in the option line
+.BR group,dev,suid ).
+.TP
+.B iversion
+Every time the inode is modified, the i_version field will be incremented.
+.TP
+.B noiversion
+Do not increment the i_version inode field.
+.TP
+.B mand
+Allow mandatory locks on this filesystem. See
+.BR fcntl (2).
+.TP
+.B nomand
+Do not allow mandatory locks on this filesystem.
+.TP
+.B _netdev
+The filesystem resides on a device that requires network access
+(used to prevent the system from attempting to mount these filesystems
+until the network has been enabled on the system).
+.TP
+.B nofail
+Do not report errors for this device if it does not exist.
+.TP
+.B relatime
+Update inode access times relative to modify or change time. Access
+time is only updated if the previous access time was earlier than the
+current modify or change time. (Similar to noatime, but doesn't break
+mutt or other applications that need to know if a file has been read
+since the last time it was modified.)
+
+Since Linux 2.6.30, the kernel defaults to the behavior provided by this
+option (unless
+.B noatime
+was specified), and the
+.B strictatime
+option is required to obtain traditional semantics. In addition, since Linux
+2.6.30, the file's last access time is always updated if it is more than 1
+day old.
+.TP
+.B norelatime
+Do not use
+.B relatime
+feature. See also the
+.B strictatime
+mount option.
+.TP
+.B strictatime
+Allows to explicitly requesting full atime updates. This makes it
+possible for kernel to defaults to
+.B relatime
+or
+.B noatime
+but still allow userspace to override it. For more details about the default
+system mount options see /proc/mounts.
+.TP
+.B nostrictatime
+Use the kernel's default behaviour for inode access time updates.
+.TP
+.B suid
+Allow set-user-identifier or set-group-identifier bits to take
+effect.
+.TP
+.B nosuid
+Do not allow set-user-identifier or set-group-identifier bits to take
+effect. (This seems safe, but is in fact rather unsafe if you have
+suidperl(1) installed.)
+.TP
+.B silent
+Turn on the silent flag.
+.TP
+.B loud
+Turn off the silent flag.
+.TP
+.B owner
+Allow an ordinary (i.e., non-root) user to mount the filesystem if he
+is the owner of the device.
+This option implies the options
+.BR nosuid " and " nodev
+(unless overridden by subsequent options, as in the option line
+.BR owner,dev,suid ).
+.TP
+.B remount
+Attempt to remount an already-mounted filesystem. This is commonly
+used to change the mount flags for a filesystem, especially to make a
+readonly filesystem writable. It does not change device or mount point.
+
+The remount functionality follows the standard way how the mount command works
+with options from fstab. It means the mount command doesn't read fstab (or
+mtab) only when a
+.IR device
+and
+.IR dir
+are fully specified.
+
+.BR "mount -o remount,rw /dev/foo /dir"
+
+After this call all old mount options are replaced and arbitrary stuff from
+fstab is ignored, except the loop= option which is internally generated and
+maintained by the mount command.
+
+.BR "mount -o remount,rw /dir"
+
+After this call mount reads fstab (or mtab) and merges these options with
+options from command line (
+.B -o
+).
+.TP
+.B ro
+Mount the filesystem read-only.
+.TP
+.B rw
+Mount the filesystem read-write.
+.TP
+.B sync
+All I/O to the filesystem should be done synchronously. In case of media with limited number of write cycles
+(e.g. some flash drives) "sync" may cause life-cycle shortening.
+.TP
+.B user
+Allow an ordinary user to mount the filesystem.
+The name of the mounting user is written to mtab so that he can unmount
+the filesystem again.
+This option implies the options
+.BR noexec ", " nosuid ", and " nodev
+(unless overridden by subsequent options, as in the option line
+.BR user,exec,dev,suid ).
+.TP
+.B nouser
+Forbid an ordinary (i.e., non-root) user to mount the filesystem.
+This is the default.
+.TP
+.B users
+Allow every user to mount and unmount the filesystem.
+This option implies the options
+.BR noexec ", " nosuid ", and " nodev
+(unless overridden by subsequent options, as in the option line
+.BR users,exec,dev,suid ).
+
+.SH "FILESYSTEM SPECIFIC MOUNT OPTIONS"
+The following options apply only to certain filesystems.
+We sort them by filesystem. They all follow the
+.B \-o
+flag.
+
+What options are supported depends a bit on the running kernel.
+More info may be found in the kernel source subdirectory
+.IR Documentation/filesystems .
+
+.SH "Mount options for adfs"
+.TP
+\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP
+Set the owner and group of the files in the filesystem (default: uid=gid=0).
+.TP
+\fBownmask=\fP\fIvalue\fP and \fBothmask=\fP\fIvalue\fP
+Set the permission mask for ADFS 'owner' permissions and 'other' permissions,
+respectively (default: 0700 and 0077, respectively).
+See also
+.IR /usr/src/linux/Documentation/filesystems/adfs.txt .
+.SH "Mount options for affs"
+.TP
+\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP
+Set the owner and group of the root of the filesystem (default: uid=gid=0,
+but with option
+.B uid
+or
+.B gid
+without specified value, the uid and gid of the current process are taken).
+.TP
+\fBsetuid=\fP\fIvalue\fP and \fBsetgid=\fP\fIvalue\fP
+Set the owner and group of all files.
+.TP
+.BI mode= value
+Set the mode of all files to
+.IR value " & 0777"
+disregarding the original permissions.
+Add search permission to directories that have read permission.
+The value is given in octal.
+.TP
+.B protect
+Do not allow any changes to the protection bits on the filesystem.
+.TP
+.B usemp
+Set uid and gid of the root of the filesystem to the uid and gid
+of the mount point upon the first sync or umount, and then
+clear this option. Strange...
+.TP
+.B verbose
+Print an informational message for each successful mount.
+.TP
+.BI prefix= string
+Prefix used before volume name, when following a link.
+.TP
+.BI volume= string
+Prefix (of length at most 30) used before '/' when following a symbolic link.
+.TP
+.BI reserved= value
+(Default: 2.) Number of unused blocks at the start of the device.
+.TP
+.BI root= value
+Give explicitly the location of the root block.
+.TP
+.BI bs= value
+Give blocksize. Allowed values are 512, 1024, 2048, 4096.
+.TP
+.BR grpquota | noquota | quota | usrquota
+These options are accepted but ignored.
+(However, quota utilities may react to such strings in
+.IR /etc/fstab .)
+
+.SH "Mount options for cifs"
+See the options section of the
+.BR mount.cifs (8)
+man page (cifs-utils package must be installed).
+
+.SH "Mount options for coherent"
+None.
+
+.SH "Mount options for debugfs"
+The debugfs filesystem is a pseudo filesystem, traditionally mounted on
+.IR /sys/kernel/debug .
+.\" or just /debug
+.\" present since 2.6.11
+There are no mount options.
+
+.SH "Mount options for devpts"
+The devpts filesystem is a pseudo filesystem, traditionally mounted on
+.IR /dev/pts .
+In order to acquire a pseudo terminal, a process opens
+.IR /dev/ptmx ;
+the number of the pseudo terminal is then made available to the process
+and the pseudo terminal slave can be accessed as
+.IR /dev/pts/ <number>.
+.TP
+\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP
+This sets the owner or the group of newly created PTYs to
+the specified values. When nothing is specified, they will
+be set to the UID and GID of the creating process.
+For example, if there is a tty group with GID 5, then
+.B gid=5
+will cause newly created PTYs to belong to the tty group.
+.TP
+.BI mode= value
+Set the mode of newly created PTYs to the specified value.
+The default is 0600.
+A value of
+.B mode=620
+and
+.B gid=5
+makes "mesg y" the default on newly created PTYs.
+.TP
+\fBnewinstance
+Create a private instance of devpts filesystem, such that
+indices of ptys allocated in this new instance are
+independent of indices created in other instances of devpts.
+
+All mounts of devpts without this
+.B newinstance
+option share the same set of pty indices (i.e legacy mode).
+Each mount of devpts with the
+.B newinstance
+option has a private set of pty indices.
+
+This option is mainly used to support containers in the
+linux kernel. It is implemented in linux kernel versions
+starting with 2.6.29. Further, this mount option is valid
+only if CONFIG_DEVPTS_MULTIPLE_INSTANCES is enabled in the
+kernel configuration.
+
+To use this option effectively,
+.IR /dev/ptmx
+must be a symbolic link to
+.IR pts/ptmx.
+See
+.IR Documentation/filesystems/devpts.txt
+in the linux kernel source tree for details.
+.TP
+.BI ptmxmode= value
+
+Set the mode for the new
+.IR ptmx
+device node in the devpts filesystem.
+
+With the support for multiple instances of devpts (see
+.B newinstance
+option above), each instance has a private
+.IR ptmx
+node in the root of the devpts filesystem (typically
+.IR /dev/pts/ptmx).
+
+For compatibility with older versions of the kernel, the
+default mode of the new
+.IR ptmx
+node is 0000.
+.BI ptmxmode= value
+specifies a more useful mode for the
+.IR ptmx
+node and is highly recommended when the
+.B newinstance
+option is specified.
+
+This option is only implemented in linux kernel versions
+starting with 2.6.29. Further this option is valid only if
+CONFIG_DEVPTS_MULTIPLE_INSTANCES is enabled in the kernel
+configuration.
+
+.SH "Mount options for ext"
+None.
+Note that the `ext' filesystem is obsolete. Don't use it.
+Since Linux version 2.1.21 extfs is no longer part of the kernel source.
+
+.SH "Mount options for ext2"
+The `ext2' filesystem is the standard Linux filesystem.
+.\" Due to a kernel bug, it may be mounted with random mount options
+.\" (fixed in Linux 2.0.4).
+Since Linux 2.5.46, for most mount options the default
+is determined by the filesystem superblock. Set them with
+.BR tune2fs (8).
+.TP
+.BR acl | noacl
+Support POSIX Access Control Lists (or not).
+.\" requires CONFIG_EXT2_FS_POSIX_ACL
+.TP
+.BR bsddf | minixdf
+Set the behaviour for the
+.I statfs
+system call. The
+.B minixdf
+behaviour is to return in the
+.I f_blocks
+field the total number of blocks of the filesystem, while the
+.B bsddf
+behaviour (which is the default) is to subtract the overhead blocks
+used by the ext2 filesystem and not available for file storage. Thus
+.nf
+
+% mount /k -o minixdf; df /k; umount /k
+Filesystem 1024-blocks Used Available Capacity Mounted on
+/dev/sda6 2630655 86954 2412169 3% /k
+% mount /k -o bsddf; df /k; umount /k
+Filesystem 1024-blocks Used Available Capacity Mounted on
+/dev/sda6 2543714 13 2412169 0% /k
+
+.fi
+(Note that this example shows that one can add command line options
+to the options given in
+.IR /etc/fstab .)
+
+.TP
+.BR check=none " or " nocheck
+No checking is done at mount time. This is the default. This is fast.
+It is wise to invoke
+.BR e2fsck (8)
+every now and then, e.g. at boot time. The non-default behavior is unssuported
+(check=normal and check=strict options have been removed). Note that these mount options
+don't have to be supported if ext4 kernel driver is used for ext2 and ext3 filesystems.
+.TP
+.B debug
+Print debugging info upon each (re)mount.
+.TP
+.BR errors= { continue | remount-ro | panic }
+Define the behaviour when an error is encountered.
+(Either ignore errors and just mark the filesystem erroneous and continue,
+or remount the filesystem read-only, or panic and halt the system.)
+The default is set in the filesystem superblock, and can be
+changed using
+.BR tune2fs (8).
+.TP
+.BR grpid | bsdgroups " and " nogrpid | sysvgroups
+These options define what group id a newly created file gets.
+When
+.BR grpid
+is set, it takes the group id of the directory in which it is created;
+otherwise (the default) it takes the fsgid of the current process, unless
+the directory has the setgid bit set, in which case it takes the gid
+from the parent directory, and also gets the setgid bit set
+if it is a directory itself.
+.TP
+.BR grpquota | noquota | quota | usrquota
+These options are accepted but ignored.
+.TP
+.BR nouid32
+Disables 32-bit UIDs and GIDs. This is for interoperability with older
+kernels which only store and expect 16-bit values.
+.TP
+.BR oldalloc " or " orlov
+Use old allocator or Orlov allocator for new inodes. Orlov is default.
+.TP
+\fBresgid=\fP\fIn\fP and \fBresuid=\fP\fIn\fP
+The ext2 filesystem reserves a certain percentage of the available
+space (by default 5%, see
+.BR mke2fs (8)
+and
+.BR tune2fs (8)).
+These options determine who can use the reserved blocks.
+(Roughly: whoever has the specified uid, or belongs to the specified group.)
+.TP
+.BI sb= n
+Instead of block 1, use block
+.I n
+as superblock. This could be useful when the filesystem has been damaged.
+(Earlier, copies of the superblock would be made every 8192 blocks: in
+block 1, 8193, 16385, ... (and one got thousands of copies on
+a big filesystem). Since version 1.08,
+.B mke2fs
+has a \-s (sparse superblock) option to reduce the number of backup
+superblocks, and since version 1.15 this is the default. Note
+that this may mean that ext2 filesystems created by a recent
+.B mke2fs
+cannot be mounted r/w under Linux 2.0.*.)
+The block number here uses 1k units. Thus, if you want to use logical
+block 32768 on a filesystem with 4k blocks, use "sb=131072".
+.TP
+.BR user_xattr | nouser_xattr
+Support "user." extended attributes (or not).
+.\" requires CONFIG_EXT2_FS_XATTR
+
+
+.SH "Mount options for ext3"
+The ext3 filesystem is a version of the ext2 filesystem which has been
+enhanced with journalling. It supports the same options as ext2 as
+well as the following additions:
+.\" .TP
+.\" .BR abort
+.\" Mount the filesystem in abort mode, as if a fatal error has occurred.
+.TP
+.BR journal=update
+Update the ext3 filesystem's journal to the current format.
+.TP
+.BR journal=inum
+When a journal already exists, this option is ignored. Otherwise, it
+specifies the number of the inode which will represent the ext3 filesystem's
+journal file; ext3 will create a new journal, overwriting the old contents
+of the file whose inode number is
+.IR inum .
+.TP
+.BR journal_dev=devnum
+When the external journal device's major/minor numbers
+have changed, this option allows the user to specify
+the new journal location. The journal device is
+identified through its new major/minor numbers encoded
+in devnum.
+.TP
+.BR norecovery / noload
+Don't load the journal on mounting. Note that
+if the filesystem was not unmounted cleanly,
+skipping the journal replay will lead to the
+filesystem containing inconsistencies that can
+lead to any number of problems.
+.TP
+.BR data= { journal | ordered | writeback }
+Specifies the journalling mode for file data. Metadata is always journaled.
+To use modes other than
+.B ordered
+on the root filesystem, pass the mode to the kernel as boot parameter, e.g.
+.IR rootflags=data=journal .
+.RS
+.TP
+.B journal
+All data is committed into the journal prior to being written into the
+main filesystem.
+.TP
+.B ordered
+This is the default mode. All data is forced directly out to the main file
+system prior to its metadata being committed to the journal.
+.TP
+.B writeback
+Data ordering is not preserved - data may be written into the main
+filesystem after its metadata has been committed to the journal.
+This is rumoured to be the highest-throughput option. It guarantees
+internal filesystem integrity, however it can allow old data to appear
+in files after a crash and journal recovery.
+.RE
+.TP
+.BR barrier=0 " / " barrier=1 "
+This enables/disables barriers. barrier=0 disables it, barrier=1 enables it.
+Write barriers enforce proper on-disk ordering of journal commits, making
+volatile disk write caches safe to use, at some performance penalty. The ext3
+filesystem does not enable write barriers by default. Be sure to enable
+barriers unless your disks are battery-backed one way or another. Otherwise
+you risk filesystem corruption in case of power failure.
+.TP
+.BI commit= nrsec
+Sync all data and metadata every
+.I nrsec
+seconds. The default value is 5 seconds. Zero means default.
+.TP
+.BR user_xattr
+Enable Extended User Attributes. See the
+.BR attr (5)
+manual page.
+.TP
+.BR acl
+Enable POSIX Access Control Lists. See the
+.BR acl (5)
+manual page.
+
+.SH "Mount options for ext4"
+The ext4 filesystem is an advanced level of the ext3 filesystem which
+incorporates scalability and reliability enhancements for supporting large
+filesystem.
+
+The options
+.B journal_dev, noload, data, commit, orlov, oldalloc, [no]user_xattr
+.B [no]acl, bsddf, minixdf, debug, errors, data_err, grpid, bsdgroups, nogrpid
+.B sysvgroups, resgid, resuid, sb, quota, noquota, grpquota and usrquota
+are backwardly compatible with ext3 or ext2.
+.TP
+.BR journal_checksum
+Enable checksumming of the journal transactions. This will allow the recovery
+code in e2fsck and the kernel to detect corruption in the kernel. It is a
+compatible change and will be ignored by older kernels.
+.TP
+.BR journal_async_commit
+Commit block can be written to disk without waiting for descriptor blocks. If
+enabled older kernels cannot mount the device.
+This will enable 'journal_checksum' internally.
+.TP
+.BR journal=update
+Update the ext4 filesystem's journal to the current format.
+.TP
+.BR barrier=0 " / " barrier=1 " / " barrier " / " nobarrier
+This enables/disables the use of write barriers in the jbd code. barrier=0
+disables, barrier=1 enables. This also requires an IO stack which can support
+barriers, and if jbd gets an error on a barrier write, it will disable again
+with a warning. Write barriers enforce proper on-disk ordering of journal
+commits, making volatile disk write caches safe to use, at some performance
+penalty. If your disks are battery-backed in one way or another, disabling
+barriers may safely improve performance. The mount options "barrier" and
+"nobarrier" can also be used to enable or disable barriers, for consistency
+with other ext4 mount options.
+
+The ext4 filesystem enables write barriers by default.
+.TP
+.BI inode_readahead= n
+This tuning parameter controls the maximum number of inode table blocks that
+ext4's inode table readahead algorithm will pre-read into the buffer cache.
+The default value is 32 blocks.
+.TP
+.BI stripe= n
+Number of filesystem blocks that mballoc will try to use for allocation size
+and alignment. For RAID5/6 systems this should be the number of data disks *
+RAID chunk size in filesystem blocks.
+.TP
+.BR delalloc
+Deferring block allocation until write-out time.
+.TP
+.BR nodelalloc
+Disable delayed allocation. Blocks are allocated when data is copied from user
+to page cache.
+.TP
+.BI max_batch_time= usec
+Maximum amount of time ext4 should wait for additional filesystem operations to
+be batch together with a synchronous write operation. Since a synchronous
+write operation is going to force a commit and then a wait for the I/O
+complete, it doesn't cost much, and can be a huge throughput win, we wait for a
+small amount of time to see if any other transactions can piggyback on the
+synchronous write. The algorithm used is designed to automatically tune for
+the speed of the disk, by measuring the amount of time (on average) that it
+takes to finish committing a transaction. Call this time the "commit time".
+If the time that the transaction has been running is less than the commit time,
+ext4 will try sleeping for the commit time to see if other operations will join
+the transaction. The commit time is capped by the max_batch_time, which
+defaults to 15000us (15ms). This optimization can be turned off entirely by
+setting max_batch_time to 0.
+.TP
+.BI min_batch_time= usec
+This parameter sets the commit time (as described above) to be at least
+min_batch_time. It defaults to zero microseconds. Increasing this parameter
+may improve the throughput of multi-threaded, synchronous workloads on very
+fast disks, at the cost of increasing latency.
+.TP
+.BI journal_ioprio= prio
+The I/O priority (from 0 to 7, where 0 is the highest priorty) which should be
+used for I/O operations submitted by kjournald2 during a commit operation.
+This defaults to 3, which is a slightly higher priority than the default I/O
+priority.
+.TP
+.BR abort
+Simulate the effects of calling ext4_abort() for
+debugging purposes. This is normally used while
+remounting a filesystem which is already mounted.
+.TP
+.BR auto_da_alloc | noauto_da_alloc
+Many broken applications don't use fsync() when
+replacing existing files via patterns such as
+
+fd = open("foo.new")/write(fd,..)/close(fd)/ rename("foo.new", "foo")
+
+or worse yet
+
+fd = open("foo", O_TRUNC)/write(fd,..)/close(fd).
+
+If auto_da_alloc is enabled, ext4 will detect the replace-via-rename and
+replace-via-truncate patterns and force that any delayed allocation blocks are
+allocated such that at the next journal commit, in the default data=ordered
+mode, the data blocks of the new file are forced to disk before the rename()
+operation is committed. This provides roughly the same level of guarantees as
+ext3, and avoids the "zero-length" problem that can happen when a system
+crashes before the delayed allocation blocks are forced to disk.
+.TP
+.BR discard / nodiscard
+Controls whether ext4 should issue discard/TRIM commands to the underlying
+block device when blocks are freed. This is useful for SSD devices and
+sparse/thinly-provisioned LUNs, but it is off by default until sufficient
+testing has been done.
+.TP
+.BR nouid32
+Disables 32-bit UIDs and GIDs. This is for
+interoperability with older kernels which only
+store and expect 16-bit values.
+.TP
+.BR resize
+Allows to resize filesystem to the end of the last
+existing block group, further resize has to be done
+with resize2fs either online, or offline. It can be
+used only with conjunction with remount.
+.TP
+.BR block_validity / noblock_validity
+This options allows to enables/disables the in-kernel facility for tracking
+filesystem metadata blocks within internal data structures. This allows multi-
+block allocator and other routines to quickly locate extents which might
+overlap with filesystem metadata blocks. This option is intended for debugging
+purposes and since it negatively affects the performance, it is off by default.
+.TP
+.BR dioread_lock / dioread_nolock
+Controls whether or not ext4 should use the DIO read locking. If the
+dioread_nolock option is specified ext4 will allocate uninitialized extent
+before buffer write and convert the extent to initialized after IO completes.
+This approach allows ext4 code to avoid using inode mutex, which improves
+scalability on high speed storages. However this does not work with data
+journaling and dioread_nolock option will be ignored with kernel warning.
+Note that dioread_nolock code path is only used for extent-based files.
+Because of the restrictions this options comprises it is off by default
+(e.g. dioread_lock).
+.TP
+.BR i_version
+Enable 64-bit inode version support. This option is off by default.
+
+.SH "Mount options for fat"
+(Note:
+.I fat
+is not a separate filesystem, but a common part of the
+.IR msdos ,
+.I umsdos
+and
+.I vfat
+filesystems.)
+.TP
+.BR blocksize= { 512 | 1024 | 2048 }
+Set blocksize (default 512). This option is obsolete.
+.TP
+\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP
+Set the owner and group of all files.
+(Default: the uid and gid of the current process.)
+.TP
+.BI umask= value
+Set the umask (the bitmask of the permissions that are
+.B not
+present). The default is the umask of the current process.
+The value is given in octal.
+.TP
+.BI dmask= value
+Set the umask applied to directories only.
+The default is the umask of the current process.
+The value is given in octal.
+.\" Present since Linux 2.5.43.
+.TP
+.BI fmask= value
+Set the umask applied to regular files only.
+The default is the umask of the current process.
+The value is given in octal.
+.\" Present since Linux 2.5.43.
+.TP
+.BI allow_utime= value
+This option controls the permission check of mtime/atime.
+.RS
+.TP
+.B 20
+If current process is in group of file's group ID, you can change timestamp.
+.TP
+.B 2
+Other users can change timestamp.
+.PP
+The default is set from `dmask' option. (If the directory is writable,
+.B utime(2)
+is also allowed. I.e. ~dmask & 022)
+
+Normally
+.B utime(2)
+checks current process is owner of the file, or it has
+CAP_FOWNER capability. But FAT filesystem doesn't have uid/gid on disk, so
+normal check is too unflexible. With this option you can relax it.
+.RE
+.TP
+.BI check= value
+Three different levels of pickyness can be chosen:
+.RS
+.TP
+.BR r [ elaxed ]
+Upper and lower case are accepted and equivalent, long name parts are
+truncated (e.g.
+.I verylongname.foobar
+becomes
+.IR verylong.foo ),
+leading and embedded spaces are accepted in each name part (name and extension).
+.TP
+.BR n [ ormal ]
+Like "relaxed", but many special characters (*, ?, <, spaces, etc.) are
+rejected. This is the default.
+.TP
+.BR s [ trict ]
+Like "normal", but names may not contain long parts and special characters
+that are sometimes used on Linux, but are not accepted by MS-DOS are
+rejected. (+, =, spaces, etc.)
+.RE
+.TP
+.BI codepage= value
+Sets the codepage for converting to shortname characters on FAT
+and VFAT filesystems. By default, codepage 437 is used.
+.TP
+.BR conv= {b [ inary ]| t [ ext ]| a [ uto ]}
+The
+.I fat
+filesystem can perform CRLF<-->NL (MS-DOS text format to UNIX text
+format) conversion in the kernel. The following conversion modes are
+available:
+.RS
+.TP
+.B binary
+no translation is performed. This is the default.
+.TP
+.B text
+CRLF<-->NL translation is performed on all files.
+.TP
+.B auto
+CRLF<-->NL translation is performed on all files that don't have a
+"well-known binary" extension. The list of known extensions can be found at
+the beginning of
+.I fs/fat/misc.c
+(as of 2.0, the list is: exe, com, bin, app, sys, drv, ovl, ovr, obj,
+lib, dll, pif, arc, zip, lha, lzh, zoo, tar, z, arj, tz, taz, tzp, tpz,
+gz, tgz, deb, gif, bmp, tif, gl, jpg, pcx, tfm, vf, gf, pk, pxl, dvi).
+.PP
+Programs that do computed lseeks won't like in-kernel text conversion.
+Several people have had their data ruined by this translation. Beware!
+
+For filesystems mounted in binary mode, a conversion tool
+(fromdos/todos) is available. This option is obsolete.
+.RE
+.TP
+.BI cvf_format= module
+Forces the driver to use the CVF (Compressed Volume File) module
+.RI cvf_ module
+instead of auto-detection. If the kernel supports kmod, the
+cvf_format=xxx option also controls on-demand CVF module loading.
+This option is obsolete.
+.TP
+.BI cvf_option= option
+Option passed to the CVF module. This option is obsolete.
+.TP
+.B debug
+Turn on the
+.I debug
+flag. A version string and a list of filesystem parameters will be
+printed (these data are also printed if the parameters appear to be
+inconsistent).
+.TP
+.BR fat= {12 | 16 | 32 }
+Specify a 12, 16 or 32 bit fat. This overrides
+the automatic FAT type detection routine. Use with caution!
+.TP
+.BI iocharset= value
+Character set to use for converting between 8 bit characters
+and 16 bit Unicode characters. The default is iso8859-1.
+Long filenames are stored on disk in Unicode format.
+.TP
+.BI tz=UTC
+This option disables the conversion of timestamps
+between local time (as used by Windows on FAT) and UTC
+(which Linux uses internally). This is particularly
+useful when mounting devices (like digital cameras)
+that are set to UTC in order to avoid the pitfalls of
+local time.
+.TP
+.B quiet
+Turn on the
+.I quiet
+flag. Attempts to chown or chmod files do not return errors,
+although they fail. Use with caution!
+.TP
+.B showexec
+If set, the execute permission bits of the file will be allowed only if
+the extension part of the name is .EXE, .COM, or .BAT. Not set by default.
+.TP
+.B sys_immutable
+If set, ATTR_SYS attribute on FAT is handled as IMMUTABLE flag on Linux.
+Not set by default.
+.TP
+.B flush
+If set, the filesystem will try to flush to disk more early than normal.
+Not set by default.
+.TP
+.B usefree
+Use the "free clusters" value stored on FSINFO. It'll
+be used to determine number of free clusters without
+scanning disk. But it's not used by default, because
+recent Windows don't update it correctly in some
+case. If you are sure the "free clusters" on FSINFO is
+correct, by this option you can avoid scanning disk.
+.TP
+.BR dots ", " nodots ", " dotsOK= [ yes | no ]
+Various misguided attempts to force Unix or DOS conventions
+onto a FAT filesystem.
+
+.SH "Mount options for hfs"
+.TP
+.BI creator= cccc ", type=" cccc
+Set the creator/type values as shown by the MacOS finder
+used for creating new files. Default values: '????'.
+.TP
+.BI uid= n ", gid=" n
+Set the owner and group of all files.
+(Default: the uid and gid of the current process.)
+.TP
+.BI dir_umask= n ", file_umask=" n ", umask=" n
+Set the umask used for all directories, all regular files, or all
+files and directories. Defaults to the umask of the current process.
+.TP
+.BI session= n
+Select the CDROM session to mount.
+Defaults to leaving that decision to the CDROM driver.
+This option will fail with anything but a CDROM as underlying device.
+.TP
+.BI part= n
+Select partition number n from the device.
+Only makes sense for CDROMs.
+Defaults to not parsing the partition table at all.
+.TP
+.B quiet
+Don't complain about invalid mount options.
+
+.SH "Mount options for hpfs"
+.TP
+\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP
+Set the owner and group of all files. (Default: the uid and gid
+of the current process.)
+.TP
+.BI umask= value
+Set the umask (the bitmask of the permissions that are
+.B not
+present). The default is the umask of the current process.
+The value is given in octal.
+.TP
+.BR case= { lower | asis }
+Convert all files names to lower case, or leave them.
+(Default:
+.BR case=lower .)
+.TP
+.BR conv= { binary | text | auto }
+For
+.BR conv=text ,
+delete some random CRs (in particular, all followed by NL)
+when reading a file.
+For
+.BR conv=auto ,
+choose more or less at random between
+.BR conv=binary " and " conv=text .
+For
+.BR conv=binary ,
+just read what is in the file. This is the default.
+.TP
+.B nocheck
+Do not abort mounting when certain consistency checks fail.
+
+.SH "Mount options for iso9660"
+ISO 9660 is a standard describing a filesystem structure to be used
+on CD-ROMs. (This filesystem type is also seen on some DVDs. See also the
+.I udf
+filesystem.)
+
+Normal
+.I iso9660
+filenames appear in a 8.3 format (i.e., DOS-like restrictions on filename
+length), and in addition all characters are in upper case. Also there is
+no field for file ownership, protection, number of links, provision for
+block/character devices, etc.
+
+Rock Ridge is an extension to iso9660 that provides all of these UNIX-like
+features. Basically there are extensions to each directory record that
+supply all of the additional information, and when Rock Ridge is in use,
+the filesystem is indistinguishable from a normal UNIX filesystem (except
+that it is read-only, of course).
+.TP
+.B norock
+Disable the use of Rock Ridge extensions, even if available. Cf.\&
+.BR map .
+.TP
+.B nojoliet
+Disable the use of Microsoft Joliet extensions, even if available. Cf.\&
+.BR map .
+.TP
+.BR check= { r [ elaxed ]| s [ trict ]}
+With
+.BR check=relaxed ,
+a filename is first converted to lower case before doing the lookup.
+This is probably only meaningful together with
+.B norock
+and
+.BR map=normal .
+(Default:
+.BR check=strict .)
+.TP
+\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP
+Give all files in the filesystem the indicated user or group id,
+possibly overriding the information found in the Rock Ridge extensions.
+(Default:
+.BR uid=0,gid=0 .)
+.TP
+.BR map= { n [ ormal ]| o [ ff ]| a [ corn ]}
+For non-Rock Ridge volumes, normal name translation maps upper
+to lower case ASCII, drops a trailing `;1', and converts `;' to `.'.
+With
+.B map=off
+no name translation is done. See
+.BR norock .
+(Default:
+.BR map=normal .)
+.B map=acorn
+is like
+.BR map=normal
+but also apply Acorn extensions if present.
+.TP
+.BI mode= value
+For non-Rock Ridge volumes, give all files the indicated mode.
+(Default: read permission for everybody.)
+Since Linux 2.1.37 one no longer needs to specify the mode in
+decimal. (Octal is indicated by a leading 0.)
+.TP
+.B unhide
+Also show hidden and associated files.
+(If the ordinary files and the associated or hidden files have
+the same filenames, this may make the ordinary files inaccessible.)
+.TP
+.BR block= { 512 | 1024 | 2048 }
+Set the block size to the indicated value.
+(Default:
+.BR block=1024 .)
+.TP
+.BR conv= { a [ uto ]| b [ inary ]| m [ text ]| t [ ext ]}
+(Default:
+.BR conv=binary .)
+Since Linux 1.3.54 this option has no effect anymore.
+(And non-binary settings used to be very dangerous,
+possibly leading to silent data corruption.)
+.TP
+.B cruft
+If the high byte of the file length contains other garbage,
+set this mount option to ignore the high order bits of the file length.
+This implies that a file cannot be larger than 16MB.
+.TP
+.BI session= x
+Select number of session on multisession CD. (Since 2.3.4.)
+.TP
+.BI sbsector= xxx
+Session begins from sector xxx. (Since 2.3.4.)
+.LP
+The following options are the same as for vfat and specifying them only makes
+sense when using discs encoded using Microsoft's Joliet extensions.
+.TP
+.BI iocharset= value
+Character set to use for converting 16 bit Unicode characters on CD
+to 8 bit characters. The default is iso8859-1.
+.TP
+.B utf8
+Convert 16 bit Unicode characters on CD to UTF-8.
+
+.SH "Mount options for jfs"
+.TP
+.BI iocharset= name
+Character set to use for converting from Unicode to ASCII. The default is
+to do no conversion. Use
+.B iocharset=utf8
+for UTF8 translations. This requires CONFIG_NLS_UTF8 to be set in
+the kernel
+.I ".config"
+file.
+.TP
+.BI resize= value
+Resize the volume to
+.I value
+blocks. JFS only supports growing a volume, not shrinking it. This option
+is only valid during a remount, when the volume is mounted read-write. The
+.B resize
+keyword with no value will grow the volume to the full size of the partition.
+.TP
+.B nointegrity
+Do not write to the journal. The primary use of this option is to allow
+for higher performance when restoring a volume from backup media. The
+integrity of the volume is not guaranteed if the system abnormally abends.
+.TP
+.B integrity
+Default. Commit metadata changes to the journal. Use this option to remount
+a volume where the
+.B nointegrity
+option was previously specified in order to restore normal behavior.
+.TP
+.BR errors= { continue | remount-ro | panic }
+Define the behaviour when an error is encountered.
+(Either ignore errors and just mark the filesystem erroneous and continue,
+or remount the filesystem read-only, or panic and halt the system.)
+.TP
+.BR noquota | quota | usrquota | grpquota
+These options are accepted but ignored.
+
+.SH "Mount options for minix"
+None.
+
+.SH "Mount options for msdos"
+See mount options for fat.
+If the
+.I msdos
+filesystem detects an inconsistency, it reports an error and sets the file
+system read-only. The filesystem can be made writable again by remounting
+it.
+
+.SH "Mount options for ncpfs"
+Just like
+.IR nfs ", the " ncpfs
+implementation expects a binary argument (a
+.IR "struct ncp_mount_data" )
+to the mount system call. This argument is constructed by
+.BR ncpmount (8)
+and the current version of
+.B mount
+(2.12) does not know anything about ncpfs.
+
+.SH "Mount options for nfs and nfs4"
+See the options section of the
+.BR nfs (5)
+man page (nfs-utils package must be installed).
+
+The
+.IR nfs " and " nfs4
+implementation expects a binary argument (a
+.IR "struct nfs_mount_data" )
+to the mount system call. This argument is constructed by
+.BR mount.nfs (8)
+and the current version of
+.B mount
+(2.13) does not know anything about nfs and nfs4.
+
+.SH "Mount options for ntfs"
+.TP
+.BI iocharset= name
+Character set to use when returning file names.
+Unlike VFAT, NTFS suppresses names that contain
+nonconvertible characters. Deprecated.
+.\" since 2.5.11
+.TP
+.BI nls= name
+New name for the option earlier called
+.IR iocharset .
+.\" since 2.5.11
+.TP
+.BR utf8
+Use UTF-8 for converting file names.
+.TP
+.BR uni_xlate= { 0 | 1 | 2 }
+For 0 (or `no' or `false'), do not use escape sequences
+for unknown Unicode characters.
+For 1 (or `yes' or `true') or 2, use vfat-style 4-byte escape sequences
+starting with ":". Here 2 give a little-endian encoding
+and 1 a byteswapped bigendian encoding.
+.TP
+.B posix=[0|1]
+If enabled (posix=1), the filesystem distinguishes between
+upper and lower case. The 8.3 alias names are presented as
+hard links instead of being suppressed. This option is obsolete.
+.TP
+\fBuid=\fP\fIvalue\fP, \fBgid=\fP\fIvalue\fP and \fBumask=\fP\fIvalue\fP
+Set the file permission on the filesystem.
+The umask value is given in octal.
+By default, the files are owned by root and not readable by somebody else.
+
+.SH "Mount options for proc"
+.TP
+\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP
+These options are recognized, but have no effect as far as I can see.
+
+.SH "Mount options for ramfs"
+Ramfs is a memory based filesystem. Mount it and you have it. Unmount it
+and it is gone. Present since Linux 2.3.99pre4.
+There are no mount options.
+
+.SH "Mount options for reiserfs"
+Reiserfs is a journaling filesystem.
+.TP
+.BR conv
+Instructs version 3.6 reiserfs software to mount a version 3.5 filesystem,
+using the 3.6 format for newly created objects. This filesystem will no
+longer be compatible with reiserfs 3.5 tools.
+.TP
+.BR hash= { rupasov | tea | r5 | detect }
+Choose which hash function reiserfs will use to find files within directories.
+.RS
+.TP
+.B rupasov
+A hash invented by Yury Yu. Rupasov. It is fast and preserves locality,
+mapping lexicographically close file names to close hash values.
+This option should not be used, as it causes a high probability of hash
+collisions.
+.TP
+.B tea
+A Davis-Meyer function implemented by Jeremy Fitzhardinge.
+It uses hash permuting bits in the name. It gets high randomness
+and, therefore, low probability of hash collisions at some CPU cost.
+This may be used if EHASHCOLLISION errors are experienced with the r5 hash.
+.TP
+.B r5
+A modified version of the rupasov hash. It is used by default and is
+the best choice unless the filesystem has huge directories and
+unusual file-name patterns.
+.TP
+.B detect
+Instructs
+.IR mount
+to detect which hash function is in use by examining
+the filesystem being mounted, and to write this information into
+the reiserfs superblock. This is only useful on the first mount of
+an old format filesystem.
+.RE
+.TP
+.BR hashed_relocation
+Tunes the block allocator. This may provide performance improvements
+in some situations.
+.TP
+.BR no_unhashed_relocation
+Tunes the block allocator. This may provide performance improvements
+in some situations.
+.TP
+.BR noborder
+Disable the border allocator algorithm invented by Yury Yu. Rupasov.
+This may provide performance improvements in some situations.
+.TP
+.BR nolog
+Disable journalling. This will provide slight performance improvements in
+some situations at the cost of losing reiserfs's fast recovery from crashes.
+Even with this option turned on, reiserfs still performs all journalling
+operations, save for actual writes into its journalling area. Implementation
+of
+.IR nolog
+is a work in progress.
+.TP
+.BR notail
+By default, reiserfs stores small files and `file tails' directly into its
+tree. This confuses some utilities such as
+.BR LILO (8).
+This option is used to disable packing of files into the tree.
+.TP
+.BR replayonly
+Replay the transactions which are in the journal, but do not actually
+mount the filesystem. Mainly used by
+.IR reiserfsck .
+.TP
+.BI resize= number
+A remount option which permits online expansion of reiserfs partitions.
+Instructs reiserfs to assume that the device has
+.I number
+blocks.
+This option is designed for use with devices which are under logical
+volume management (LVM).
+There is a special
+.I resizer
+utility which can be obtained from
+.IR ftp://ftp.namesys.com/pub/reiserfsprogs .
+.TP
+.BR user_xattr
+Enable Extended User Attributes. See the
+.BR attr (5)
+manual page.
+.TP
+.BR acl
+Enable POSIX Access Control Lists. See the
+.BR acl (5)
+manual page.
+.TP
+.BR barrier=none " / " barrier=flush "
+This enables/disables the use of write barriers in the journaling code.
+barrier=none disables it, barrier=flush enables it. Write barriers enforce
+proper on-disk ordering of journal commits, making volatile disk write caches
+safe to use, at some performance penalty. The reiserfs filesystem does not
+enable write barriers by default. Be sure to enable barriers unless your disks
+are battery-backed one way or another. Otherwise you risk filesystem
+corruption in case of power failure.
+
+.SH "Mount options for romfs"
+None.
+
+.SH "Mount options for squashfs"
+None.
+
+.SH "Mount options for smbfs"
+Just like
+.IR nfs ", the " smbfs
+implementation expects a binary argument (a
+.IR "struct smb_mount_data" )
+to the mount system call. This argument is constructed by
+.BR smbmount (8)
+and the current version of
+.B mount
+(2.12) does not know anything about smbfs.
+
+.SH "Mount options for sysv"
+None.
+
+.SH "Mount options for tmpfs"
+.TP
+.BI size= nbytes
+Override default maximum size of the filesystem.
+The size is given in bytes, and rounded up to entire pages.
+The default is half of the memory. The size parameter also accepts a suffix %
+to limit this tmpfs instance to that percentage of your physical RAM:
+the default, when neither size nor nr_blocks is specified, is size=50%
+.TP
+.B nr_blocks=
+The same as size, but in blocks of PAGE_CACHE_SIZE
+.TP
+.B nr_inodes=
+The maximum number of inodes for this instance. The default
+is half of the number of your physical RAM pages, or (on a
+machine with highmem) the number of lowmem RAM pages,
+whichever is the lower.
+.PP
+The tmpfs mount options for sizing (
+.BR size ,
+.BR nr_blocks ,
+and
+.BR nr_inodes )
+accept a suffix
+.BR k ,
+.B m
+or
+.B g
+for Ki, Mi, Gi (binary kilo, mega and giga) and can be changed on remount.
+
+.TP
+.B mode=
+Set initial permissions of the root directory.
+.TP
+.B uid=
+The user id.
+.TP
+.B gid=
+The group id.
+.TP
+.B mpol=[default|prefer:Node|bind:NodeList|interleave|interleave:NodeList]
+Set the NUMA memory allocation policy for all files in that
+instance (if the kernel CONFIG_NUMA is enabled) - which can be adjusted on the
+fly via 'mount -o remount ...'
+.RS
+.TP
+.B default
+prefers to allocate memory from the local node
+.TP
+.B prefer:Node
+prefers to allocate memory from the given Node
+.TP
+.B bind:NodeList
+allocates memory only from nodes in NodeList
+.TP
+.B interleave
+prefers to allocate from each node in turn
+.TP
+.B interleave:NodeList
+allocates from each node of NodeList in turn.
+.PP
+The NodeList format is a comma-separated list of decimal numbers and ranges, a
+range being two hyphen-separated decimal numbers, the smallest and largest node
+numbers in the range. For example, mpol=bind:0-3,5,7,9-15
+
+Note that trying to mount a tmpfs with an mpol option will fail if the
+running kernel does not support NUMA; and will fail if its nodelist
+specifies a node which is not online. If your system relies on that
+tmpfs being mounted, but from time to time runs a kernel built without
+NUMA capability (perhaps a safe recovery kernel), or with fewer nodes
+online, then it is advisable to omit the mpol option from automatic
+mount options. It can be added later, when the tmpfs is already mounted
+on MountPoint, by 'mount -o remount,mpol=Policy:NodeList MountPoint'.
+
+.SH "Mount options for ubifs"
+UBIFS is a flash file system which works on top of UBI volumes. Note that
+.B
+atime
+is not supported and is always turned off.
+.TP
+The device name may be specified as
+.RS
+.B ubiX_Y
+UBI device number
+.BR X ,
+volume number
+.B Y
+.TP
+.B ubiY
+UBI device number
+.BR 0 ,
+volume number
+.B Y
+.TP
+.B ubiX:NAME
+UBI device number
+.BR X ,
+volume with name
+.B NAME
+.TP
+.B ubi:NAME
+UBI device number
+.BR 0 ,
+volume with name
+.B NAME
+.RE
+Alternative
+.B !
+separator may be used instead of
+.BR : .
+.TP
+The following mount options are available:
+.TP
+.BR bulk_read
+Enable bulk-read. VFS read-ahead is disabled because it slows down the file
+system. Bulk-Read is an internal optimization. Some flashes may read faster if
+the data are read at one go, rather than at several read requests. For
+example, OneNAND can do "read-while-load" if it reads more than one NAND page.
+.TP
+.BR no_bulk_read
+Do not bulk-read. This is the default.
+.TP
+.BR chk_data_crc
+Check data CRC-32 checksums. This is the default.
+.TP
+.BR no_chk_data_crc.
+Do not check data CRC-32 checksums. With this option, the filesystem does not
+check CRC-32 checksum for data, but it does check it for the internal indexing
+information. This option only affects reading, not writing. CRC-32 is always
+calculated when writing the data.
+.TP
+.BR compr= { none | lzo | zlib }
+Select the default compressor which is used when new files are written. It is
+still possible to read compressed files if mounted with the
+.B none
+option.
+
+.SH "Mount options for udf"
+udf is the "Universal Disk Format" filesystem defined by the Optical
+Storage Technology Association, and is often used for DVD-ROM.
+See also
+.IR iso9660 .
+.TP
+.B gid=
+Set the default group.
+.TP
+.B umask=
+Set the default umask.
+The value is given in octal.
+.TP
+.B uid=
+Set the default user.
+.TP
+.B unhide
+Show otherwise hidden files.
+.TP
+.B undelete
+Show deleted files in lists.
+.TP
+.B nostrict
+Unset strict conformance.
+.\" .TP
+.\" .B utf8
+.\" (unused).
+.TP
+.B iocharset
+Set the NLS character set.
+.TP
+.B bs=
+Set the block size. (May not work unless 2048.)
+.TP
+.B novrs
+Skip volume sequence recognition.
+.TP
+.B session=
+Set the CDROM session counting from 0. Default: last session.
+.TP
+.B anchor=
+Override standard anchor location. Default: 256.
+.TP
+.B volume=
+Override the VolumeDesc location. (unused)
+.TP
+.B partition=
+Override the PartitionDesc location. (unused)
+.TP
+.B lastblock=
+Set the last block of the filesystem.
+.TP
+.B fileset=
+Override the fileset block location. (unused)
+.TP
+.B rootdir=
+Override the root directory location. (unused)
+
+.SH "Mount options for ufs"
+.TP
+.BI ufstype= value
+UFS is a filesystem widely used in different operating systems.
+The problem are differences among implementations. Features of some
+implementations are undocumented, so its hard to recognize the
+type of ufs automatically.
+That's why the user must specify the type of ufs by mount option.
+Possible values are:
+.RS
+.TP
+.B old
+Old format of ufs, this is the default, read only.
+(Don't forget to give the \-r option.)
+.TP
+.B 44bsd
+For filesystems created by a BSD-like system (NetBSD,FreeBSD,OpenBSD).
+.TP
+.B ufs2
+Used in FreeBSD 5.x supported as read-write.
+.TP
+.B 5xbsd
+Synonym for ufs2.
+.TP
+.B sun
+For filesystems created by SunOS or Solaris on Sparc.
+.TP
+.B sunx86
+For filesystems created by Solaris on x86.
+.TP
+.B hp
+For filesystems created by HP-UX, read-only.
+.TP
+.B nextstep
+For filesystems created by NeXTStep (on NeXT station) (currently read only).
+.TP
+.B nextstep-cd
+For NextStep CDROMs (block_size == 2048), read-only.
+.TP
+.B openstep
+For filesystems created by OpenStep (currently read only).
+The same filesystem type is also used by Mac OS X.
+.RE
+
+.TP
+.BI onerror= value
+Set behaviour on error:
+.RS
+.TP
+.B panic
+If an error is encountered, cause a kernel panic.
+.TP
+.RB [ lock | umount | repair ]
+These mount options don't do anything at present;
+when an error is encountered only a console message is printed.
+.RE
+
+.SH "Mount options for umsdos"
+See mount options for msdos.
+The
+.B dotsOK
+option is explicitly killed by
+.IR umsdos .
+
+.SH "Mount options for vfat"
+First of all, the mount options for
+.I fat
+are recognized.
+The
+.B dotsOK
+option is explicitly killed by
+.IR vfat .
+Furthermore, there are
+.TP
+.B uni_xlate
+Translate unhandled Unicode characters to special escaped sequences.
+This lets you backup and restore filenames that are created with any
+Unicode characters. Without this option, a '?' is used when no
+translation is possible. The escape character is ':' because it is
+otherwise illegal on the vfat filesystem. The escape sequence
+that gets used, where u is the unicode character,
+is: ':', (u & 0x3f), ((u>>6) & 0x3f), (u>>12).
+.TP
+.B posix
+Allow two files with names that only differ in case.
+This option is obsolete.
+.TP
+.B nonumtail
+First try to make a short name without sequence number,
+before trying
+.IR name~num.ext .
+.TP
+.B utf8
+UTF8 is the filesystem safe 8-bit encoding of Unicode that is used by the
+console. It can be enabled for the filesystem with this option or disabled
+with utf8=0, utf8=no or utf8=false. If `uni_xlate' gets set, UTF8 gets
+disabled.
+.TP
+.BR shortname= { lower | win95 | winnt | mixed }
+
+Defines the behaviour for creation and display of filenames which fit into
+8.3 characters. If a long name for a file exists, it will always be
+preferred display. There are four modes:
+:
+.RS
+.TP
+.I lower
+Force the short name to lower case upon display; store a long name when
+the short name is not all upper case.
+.TP
+.I win95
+Force the short name to upper case upon display; store a long name when
+the short name is not all upper case.
+.TP
+.I winnt
+Display the shortname as is; store a long name when the short name is
+not all lower case or all upper case.
+.TP
+.I mixed
+Display the short name as is; store a long name when the short name is not
+all upper case. This mode is the default since Linux 2.6.32.
+.RE
+
+
+.SH "Mount options for usbfs"
+.TP
+\fBdevuid=\fP\fIuid\fP and \fBdevgid=\fP\fIgid\fP and \fBdevmode=\fP\fImode\fP
+Set the owner and group and mode of the device files in the usbfs filesystem
+(default: uid=gid=0, mode=0644). The mode is given in octal.
+.TP
+\fBbusuid=\fP\fIuid\fP and \fBbusgid=\fP\fIgid\fP and \fBbusmode=\fP\fImode\fP
+Set the owner and group and mode of the bus directories in the usbfs
+filesystem (default: uid=gid=0, mode=0555). The mode is given in octal.
+.TP
+\fBlistuid=\fP\fIuid\fP and \fBlistgid=\fP\fIgid\fP and \fBlistmode=\fP\fImode\fP
+Set the owner and group and mode of the file
+.I devices
+(default: uid=gid=0, mode=0444). The mode is given in octal.
+
+.SH "Mount options for xenix"
+None.
+
+.SH "Mount options for xfs"
+.TP
+.BI allocsize= size
+Sets the buffered I/O end-of-file preallocation size when
+doing delayed allocation writeout (default size is 64KiB).
+Valid values for this option are page size (typically 4KiB)
+through to 1GiB, inclusive, in power-of-2 increments.
+.TP
+.BR attr2 | noattr2
+The options enable/disable (default is enabled) an "opportunistic"
+improvement to be made in the way inline extended attributes are
+stored on-disk.
+When the new form is used for the first time (by setting or
+removing extended attributes) the on-disk superblock feature
+bit field will be updated to reflect this format being in use.
+.TP
+.B barrier
+Enables the use of block layer write barriers for writes into
+the journal and unwritten extent conversion. This allows for
+drive level write caching to be enabled, for devices that
+support write barriers.
+.TP
+.B dmapi
+Enable the DMAPI (Data Management API) event callouts.
+Use with the
+.B mtpt
+option.
+.TP
+.BR grpid | bsdgroups " and " nogrpid | sysvgroups
+These options define what group ID a newly created file gets.
+When grpid is set, it takes the group ID of the directory in
+which it is created; otherwise (the default) it takes the fsgid
+of the current process, unless the directory has the setgid bit
+set, in which case it takes the gid from the parent directory,
+and also gets the setgid bit set if it is a directory itself.
+.TP
+.BI ihashsize= value
+Sets the number of hash buckets available for hashing the
+in-memory inodes of the specified mount point. If a value
+of zero is used, the value selected by the default algorithm
+will be displayed in
+.IR /proc/mounts .
+.TP
+.BR ikeep | noikeep
+When inode clusters are emptied of inodes, keep them around
+on the disk (ikeep) - this is the traditional XFS behaviour
+and is still the default for now. Using the noikeep option,
+inode clusters are returned to the free space pool.
+.TP
+.B inode64
+Indicates that XFS is allowed to create inodes at any location
+in the filesystem, including those which will result in inode
+numbers occupying more than 32 bits of significance. This is
+provided for backwards compatibility, but causes problems for
+backup applications that cannot handle large inode numbers.
+.TP
+.BR largeio | nolargeio
+If
+.B nolargeio
+is specified, the optimal I/O reported in
+st_blksize by
+.BR stat (2)
+will be as small as possible to allow user
+applications to avoid inefficient read/modify/write I/O.
+If
+.B largeio
+is specified, a filesystem that has a
+.B swidth
+specified
+will return the
+.B swidth
+value (in bytes) in st_blksize. If the
+filesystem does not have a
+.B swidth
+specified but does specify
+an
+.B allocsize
+then
+.B allocsize
+(in bytes) will be returned
+instead.
+If neither of these two options are specified, then filesystem
+will behave as if
+.B nolargeio
+was specified.
+.TP
+.BI logbufs= value
+Set the number of in-memory log buffers. Valid numbers range
+from 2-8 inclusive.
+The default value is 8 buffers for any recent kernel.
+.TP
+.BI logbsize= value
+Set the size of each in-memory log buffer.
+Size may be specified in bytes, or in kilobytes with a "k" suffix.
+Valid sizes for version 1 and version 2 logs are 16384 (16k) and
+32768 (32k). Valid sizes for version 2 logs also include
+65536 (64k), 131072 (128k) and 262144 (256k).
+The default value for any recent kernel is 32768.
+.TP
+\fBlogdev=\fP\fIdevice\fP and \fBrtdev=\fP\fIdevice\fP
+Use an external log (metadata journal) and/or real-time device.
+An XFS filesystem has up to three parts: a data section, a log section,
+and a real-time section.
+The real-time section is optional, and the log section can be separate
+from the data section or contained within it.
+Refer to
+.BR xfs (5).
+.TP
+.BI mtpt= mountpoint
+Use with the
+.B dmapi
+option. The value specified here will be
+included in the DMAPI mount event, and should be the path of
+the actual mountpoint that is used.
+.TP
+.B noalign
+Data allocations will not be aligned at stripe unit boundaries.
+.TP
+.B noatime
+Access timestamps are not updated when a file is read.
+.TP
+.B norecovery
+The filesystem will be mounted without running log recovery.
+If the filesystem was not cleanly unmounted, it is likely to
+be inconsistent when mounted in
+.B norecovery
+mode.
+Some files or directories may not be accessible because of this.
+Filesystems mounted
+.B norecovery
+must be mounted read-only or the mount will fail.
+.TP
+.B nouuid
+Don't check for double mounted filesystems using the filesystem uuid.
+This is useful to mount LVM snapshot volumes.
+.TP
+.B osyncisosync
+Make O_SYNC writes implement true O_SYNC. WITHOUT this option,
+Linux XFS behaves as if an
+.B osyncisdsync
+option is used,
+which will make writes to files opened with the O_SYNC flag set
+behave as if the O_DSYNC flag had been used instead.
+This can result in better performance without compromising
+data safety.
+However if this option is not in effect, timestamp updates from
+O_SYNC writes can be lost if the system crashes.
+If timestamp updates are critical, use the
+.B osyncisosync
+option.
+.TP
+.BR uquota | usrquota | uqnoenforce | quota
+User disk quota accounting enabled, and limits (optionally)
+enforced. Refer to
+.BR xfs_quota (8)
+for further details.
+.TP
+.BR gquota | grpquota | gqnoenforce
+Group disk quota accounting enabled and limits (optionally)
+enforced. Refer to
+.BR xfs_quota (8)
+for further details.
+.TP
+.BR pquota | prjquota | pqnoenforce
+Project disk quota accounting enabled and limits (optionally)
+enforced. Refer to
+.BR xfs_quota (8)
+for further details.
+.TP
+\fBsunit=\fP\fIvalue\fP and \fBswidth=\fP\fIvalue\fP
+Used to specify the stripe unit and width for a RAID device or a stripe
+volume.
+.I value
+must be specified in 512-byte block units.
+If this option is not specified and the filesystem was made on a stripe
+volume or the stripe width or unit were specified for the RAID device at
+mkfs time, then the mount system call will restore the value from the
+superblock.
+For filesystems that are made directly on RAID devices, these options can be
+used to override the information in the superblock if the underlying disk
+layout changes after the filesystem has been created.
+The
+.B swidth
+option is required if the
+.B sunit
+option has been specified,
+and must be a multiple of the
+.B sunit
+value.
+.TP
+.B swalloc
+Data allocations will be rounded up to stripe width boundaries
+when the current end of file is being extended and the file
+size is larger than the stripe width size.
+
+.SH "Mount options for xiafs"
+None. Although nothing is wrong with xiafs, it is not used much,
+and is not maintained. Probably one shouldn't use it.
+Since Linux version 2.1.21 xiafs is no longer part of the kernel source.
+
+.SH "THE LOOP DEVICE"
+One further possible type is a mount via the loop device. For example,
+the command
+.RS
+.sp
+.B "mount /tmp/disk.img /mnt -t vfat -o loop=/dev/loop"
+.sp
+.RE
+will set up the loop device
+.I /dev/loop3
+to correspond to the file
+.IR /tmp/disk.img ,
+and then mount this device on
+.IR /mnt .
+
+If no explicit loop device is mentioned
+(but just an option `\fB\-o loop\fP' is given), then
+.B mount
+will try to find some unused loop device and use that, for example
+.RS
+.sp
+.B "mount /tmp/disk.img /mnt -o loop"
+.sp
+.RE
+The mount command
+.B automatically
+creates a loop device from a regular file if a filesystem type is
+not specified or the filesystem is known for libblkid, for example:
+.RS
+.sp
+.B "mount /tmp/disk.img /mnt"
+.sp
+.B "mount -t ext3 /tmp/disk.img /mnt"
+.sp
+.RE
+This type of mount knows about four options, namely
+.BR loop ", " offset ", " sizelimit " and " encryption ,
+that are really options to
+.BR \%losetup (8).
+(These options can be used in addition to those specific
+to the filesystem type.)
+
+Since Linux 2.6.25 is supported auto-destruction of loop devices and
+then any loop device allocated by
+.B mount
+will be freed by
+.B umount
+independently on
+.IR /etc/mtab .
+
+You can also free a loop device by hand, using `losetup -d' or `umount -d`.
+
+.SH RETURN CODES
+.B mount
+has the following return codes (the bits can be ORed):
+.TP
+.BR 0
+success
+.TP
+.BR 1
+incorrect invocation or permissions
+.TP
+.BR 2
+system error (out of memory, cannot fork, no more loop devices)
+.TP
+.BR 4
+internal
+.B mount
+bug
+.TP
+.BR 8
+user interrupt
+.TP
+.BR 16
+problems writing or locking /etc/mtab
+.TP
+.BR 32
+mount failure
+.TP
+.BR 64
+some mount succeeded
+
+.SH NOTES
+The syntax of external mount helpers is:
+
+.RS
+.BI /sbin/mount. <suffix>
+.I spec dir
+.RB [ \-sfnv ]
+.RB [ \-o
+.IR options ]
+.RB [ \-t
+.IR type.subtype ]
+.RE
+
+where the <type> is filesystem type and \-sfnvo options have same meaning like
+standard mount options. The \-t option is used for filesystems with subtypes
+support (for example /sbin/mount.fuse -t fuse.sshfs).
+
+.SH FILES
+.TP 18n
+.I /etc/fstab
+filesystem table
+.TP
+.I /etc/mtab
+table of mounted filesystems
+.TP
+.I /etc/mtab~
+lock file
+.TP
+.I /etc/mtab.tmp
+temporary file
+.TP
+.I /etc/filesystems
+a list of filesystem types to try
+
+.SH "SEE ALSO"
+.BR mount (2),
+.BR umount (2),
+.BR fstab (5),
+.BR umount (8),
+.BR swapon (8),
+.BR nfs (5),
+.BR xfs (5),
+.BR e2label (8),
+.BR xfs_admin (8),
+.BR mountd (8),
+.BR nfsd (8),
+.BR mke2fs (8),
+.BR tune2fs (8),
+.BR losetup (8)
+.SH BUGS
+It is possible for a corrupted filesystem to cause a crash.
+.PP
+Some Linux filesystems don't support
+.B "\-o sync and \-o dirsync"
+(the ext2, ext3, fat and vfat filesystems
+.I do
+support synchronous updates (a la BSD) when mounted with the
+.B sync
+option).
+.PP
+The
+.B "\-o remount"
+may not be able to change mount parameters (all
+.IR ext2fs -specific
+parameters, except
+.BR sb ,
+are changeable with a remount, for example, but you can't change
+.B gid
+or
+.B umask
+for the
+.IR fatfs ).
+.PP
+Mount by label or uuid will work only if your devices have the names listed in
+.IR /proc/partitions .
+In particular, it may well fail if the kernel was compiled with devfs
+but devfs is not mounted.
+.PP
+It is possible that files
+.IR /etc/mtab
+and
+.IR /proc/mounts
+don't match. The first file is based only on the mount command options, but the
+content of the second file also depends on the kernel and others settings (e.g.
+remote NFS server. In particular case the mount command may reports unreliable
+information about a NFS mount point and the /proc/mounts file usually contains
+more reliable information.)
+.PP
+Checking files on NFS filesystem referenced by file descriptors (i.e. the
+.BR fcntl
+and
+.BR ioctl
+families of functions) may lead to inconsistent result due to the lack of
+consistency check in kernel even if noac is used.
+.SH HISTORY
+A
+.B mount
+command existed in Version 5 AT&T UNIX.
+.SH AVAILABILITY
+The mount command is part of the util-linux package and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
diff --git a/mount-deprecated/mount.c b/mount-deprecated/mount.c
new file mode 100644
index 000000000..2e9b2a4e3
--- /dev/null
+++ b/mount-deprecated/mount.c
@@ -0,0 +1,2799 @@
+/*
+ * A mount(8) for Linux.
+ *
+ * Modifications by many people. Distributed under GPL.
+ */
+
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdio.h>
+
+#include <pwd.h>
+#include <grp.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+
+#include <mntent.h>
+
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#endif
+
+#include "pathnames.h"
+#include "fsprobe.h"
+#include "devname.h"
+#include "mount_constants.h"
+#include "sundries.h"
+#include "mount_mntent.h"
+#include "fstab.h"
+#include "loopdev.h"
+#include "linux_version.h"
+#include "getusername.h"
+#include "env.h"
+#include "nls.h"
+#include "blkdev.h"
+#include "strutils.h"
+#include "closestream.h"
+#include "xgetpass.h"
+
+#define DO_PS_FIDDLING
+
+#ifdef DO_PS_FIDDLING
+#include "setproctitle.h"
+#endif
+
+/* True for fake mount (-f). */
+static int fake = 0;
+
+/* True if we are allowed to call /sbin/mount.${FSTYPE} */
+static int external_allowed = 1;
+
+/* Don't write an entry in /etc/mtab (-n). */
+static int nomtab = 0;
+
+/* True for explicit readonly (-r). */
+static int readonly = 0;
+
+/* Nonzero for sloppy (-s). */
+static int sloppy = 0;
+
+/* True for explicit read/write (-w). */
+static int readwrite = 0;
+
+/* True for all mount (-a). */
+static int mount_all = 0;
+
+/* True for fork() during all mount (-F). */
+static int optfork = 0;
+
+/* Add volumelabel in a listing of mounted devices (-l). */
+static int list_with_volumelabel = 0;
+
+/* Nonzero for mount {bind|move|make-shared|make-private|
+ * make-unbindable|make-slave}
+ */
+static int mounttype = 0;
+
+/* True if (ruid != euid) or (0 != ruid), i.e. only "user" mounts permitted. */
+static int restricted = 1;
+
+/* Contains the fd to read the passphrase from, if any. */
+static int pfd = -1;
+
+#ifdef HAVE_LIBMOUNT_MOUNT
+static struct libmnt_update *mtab_update;
+static char *mtab_opts;
+static unsigned long mtab_flags;
+
+static void prepare_mtab_entry(const char *spec, const char *node,
+ const char *type, const char *opts, unsigned long flags);
+#endif
+
+/* mount(2) options */
+struct mountargs {
+ const char *spec;
+ const char *node;
+ const char *type;
+ int flags;
+ void *data;
+};
+
+/* Map from -o and fstab option strings to the flag argument to mount(2). */
+struct opt_map {
+ const char *opt; /* option name */
+ int skip; /* skip in mtab option string */
+ int inv; /* true if flag value should be inverted */
+ int mask; /* flag mask value */
+ int cmask; /* comments mask */
+};
+
+/* Custom mount options for our own purposes. */
+/* Maybe these should now be freed for kernel use again */
+#define MS_NOAUTO 0x80000000
+#define MS_USERS 0x40000000
+#define MS_USER 0x20000000
+#define MS_OWNER 0x10000000
+#define MS_GROUP 0x08000000
+#define MS_COMMENT 0x02000000
+#define MS_LOOP 0x00010000
+
+#define MS_COMMENT_NOFAIL (1 << 1)
+#define MS_COMMENT_NETDEV (1 << 2)
+
+/* Options that we keep the mount system call from seeing. */
+#define MS_NOSYS (MS_NOAUTO|MS_USERS|MS_USER|MS_COMMENT|MS_LOOP)
+
+/* Options that we keep from appearing in the options field in the mtab. */
+#define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER)
+
+#define MS_PROPAGATION (MS_SHARED|MS_SLAVE|MS_UNBINDABLE|MS_PRIVATE)
+
+/* Options that we make ordinary users have by default. */
+#define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
+
+/* Options that we make owner-mounted devices have by default */
+#define MS_OWNERSECURE (MS_NOSUID|MS_NODEV)
+
+static const struct opt_map opt_map[] = {
+ { "defaults", 0, 0, 0 }, /* default options */
+ { "ro", 1, 0, MS_RDONLY }, /* read-only */
+ { "rw", 1, 1, MS_RDONLY }, /* read-write */
+ { "exec", 0, 1, MS_NOEXEC }, /* permit execution of binaries */
+ { "noexec", 0, 0, MS_NOEXEC }, /* don't execute binaries */
+ { "suid", 0, 1, MS_NOSUID }, /* honor suid executables */
+ { "nosuid", 0, 0, MS_NOSUID }, /* don't honor suid executables */
+ { "dev", 0, 1, MS_NODEV }, /* interpret device files */
+ { "nodev", 0, 0, MS_NODEV }, /* don't interpret devices */
+ { "sync", 0, 0, MS_SYNCHRONOUS}, /* synchronous I/O */
+ { "async", 0, 1, MS_SYNCHRONOUS}, /* asynchronous I/O */
+ { "dirsync", 0, 0, MS_DIRSYNC}, /* synchronous directory modifications */
+ { "remount", 0, 0, MS_REMOUNT}, /* Alter flags of mounted FS */
+ { "bind", 0, 0, MS_BIND }, /* Remount part of tree elsewhere */
+ { "rbind", 0, 0, MS_BIND|MS_REC }, /* Idem, plus mounted subtrees */
+ { "auto", 0, 1, MS_NOAUTO }, /* Can be mounted using -a */
+ { "noauto", 0, 0, MS_NOAUTO }, /* Can only be mounted explicitly */
+ { "users", 0, 0, MS_USERS }, /* Allow ordinary user to mount */
+ { "nousers", 0, 1, MS_USERS }, /* Forbid ordinary user to mount */
+ { "user", 0, 0, MS_USER }, /* Allow ordinary user to mount */
+ { "nouser", 0, 1, MS_USER }, /* Forbid ordinary user to mount */
+ { "owner", 0, 0, MS_OWNER }, /* Let the owner of the device mount */
+ { "noowner", 0, 1, MS_OWNER }, /* Device owner has no special privs */
+ { "group", 0, 0, MS_GROUP }, /* Let the group of the device mount */
+ { "nogroup", 0, 1, MS_GROUP }, /* Device group has no special privs */
+ { "_netdev", 0, 0, MS_COMMENT, MS_COMMENT_NETDEV }, /* Device requires network */
+ { "comment", 0, 0, MS_COMMENT}, /* fstab comment only (kudzu,_netdev)*/
+
+ /* add new options here */
+#ifdef MS_NOSUB
+ { "sub", 0, 1, MS_NOSUB }, /* allow submounts */
+ { "nosub", 0, 0, MS_NOSUB }, /* don't allow submounts */
+#endif
+#ifdef MS_SILENT
+ { "silent", 0, 0, MS_SILENT }, /* be quiet */
+ { "loud", 0, 1, MS_SILENT }, /* print out messages. */
+#endif
+#ifdef MS_MANDLOCK
+ { "mand", 0, 0, MS_MANDLOCK }, /* Allow mandatory locks on this FS */
+ { "nomand", 0, 1, MS_MANDLOCK }, /* Forbid mandatory locks on this FS */
+#endif
+ { "loop", 1, 0, MS_LOOP }, /* use a loop device */
+#ifdef MS_NOATIME
+ { "atime", 0, 1, MS_NOATIME }, /* Update access time */
+ { "noatime", 0, 0, MS_NOATIME }, /* Do not update access time */
+#endif
+#ifdef MS_I_VERSION
+ { "iversion", 0, 0, MS_I_VERSION }, /* Update inode I_version time */
+ { "noiversion", 0, 1, MS_I_VERSION }, /* Don't update inode I_version time */
+#endif
+#ifdef MS_NODIRATIME
+ { "diratime", 0, 1, MS_NODIRATIME }, /* Update dir access times */
+ { "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */
+#endif
+#ifdef MS_RELATIME
+ { "relatime", 0, 0, MS_RELATIME }, /* Update access times relative to
+ mtime/ctime */
+ { "norelatime", 0, 1, MS_RELATIME }, /* Update access time without regard
+ to mtime/ctime */
+#endif
+#ifdef MS_STRICTATIME
+ { "strictatime", 0, 0, MS_STRICTATIME }, /* Strict atime semantics */
+ { "nostrictatime", 0, 1, MS_STRICTATIME }, /* kernel default atime */
+#endif
+ { "nofail", 0, 0, MS_COMMENT, MS_COMMENT_NOFAIL }, /* Do not fail if ENOENT on dev */
+ { NULL, 0, 0, 0 }
+};
+
+static int opt_nofail;
+static int invuser_flags;
+static int comment_flags;
+
+static const char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_sizelimit,
+ *opt_encryption, *opt_speed, *opt_comment, *opt_uhelper, *opt_helper;
+
+static int is_readonly(const char *node);
+static int mounted (const char *spec0, const char *node0, struct mntentchn *fstab_mc);
+static int check_special_mountprog(const char *spec, const char *node,
+ const char *type, int flags, char *extra_opts, int *status);
+
+static struct string_opt_map {
+ char *tag;
+ int skip;
+ const char **valptr;
+} string_opt_map[] = {
+ { "loop=", 0, &opt_loopdev },
+ { "vfs=", 1, &opt_vfstype },
+ { "offset=", 0, &opt_offset },
+ { "sizelimit=", 0, &opt_sizelimit },
+ { "encryption=", 0, &opt_encryption },
+ { "speed=", 0, &opt_speed },
+ { "comment=", 1, &opt_comment },
+ { "uhelper=", 0, &opt_uhelper },
+ { "helper=", 0, &opt_helper },
+ { NULL, 0, NULL }
+};
+
+static void
+clear_string_opts(void) {
+ struct string_opt_map *m;
+
+ for (m = &string_opt_map[0]; m->tag; m++)
+ *(m->valptr) = NULL;
+}
+
+static void
+clear_flags_opts(void) {
+ invuser_flags = 0;
+ comment_flags = 0;
+ opt_nofail = 0;
+}
+
+static int
+parse_string_opt(char *s) {
+ struct string_opt_map *m;
+ int lth;
+
+ for (m = &string_opt_map[0]; m->tag; m++) {
+ lth = strlen(m->tag);
+ if (!strncmp(s, m->tag, lth)) {
+ *(m->valptr) = xstrdup(s + lth);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Report on a single mount. */
+static void
+print_one (const struct my_mntent *me) {
+
+ char *fsname = NULL;
+
+ if (mount_quiet)
+ return;
+
+ /* users assume backing file name rather than /dev/loopN in
+ * mount(8) output if the device has been initialized by mount(8).
+ */
+ if (strncmp(me->mnt_fsname, "/dev/loop", 9) == 0 &&
+ loopdev_is_autoclear(me->mnt_fsname))
+ fsname = loopdev_get_backing_file(me->mnt_fsname);
+
+ if (!fsname)
+ fsname = (char *) me->mnt_fsname;
+
+ printf ("%s on %s", fsname, me->mnt_dir);
+ if (me->mnt_type != NULL && *(me->mnt_type) != '\0')
+ printf (" type %s", me->mnt_type);
+ if (me->mnt_opts != NULL)
+ printf (" (%s)", me->mnt_opts);
+ if (list_with_volumelabel && is_pseudo_fs(me->mnt_type) == 0) {
+ const char *devname = spec_to_devname(me->mnt_fsname);
+
+ if (devname) {
+ const char *label;
+
+ label = fsprobe_get_label_by_devname(devname);
+ my_free(devname);
+
+ if (label) {
+ printf (" [%s]", label);
+ my_free(label);
+ }
+ }
+ }
+ printf ("\n");
+}
+
+/* Report on everything in mtab (of the specified types if any). */
+static int
+print_all (char *types) {
+ struct mntentchn *mc, *mc0;
+
+ mc0 = mtab_head();
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
+ if (matching_type (mc->m.mnt_type, types))
+ print_one (&(mc->m));
+ }
+
+ if (!mtab_does_not_exist() && !mtab_is_a_symlink() && is_readonly(_PATH_MOUNTED))
+ printf(_("\n"
+ "mount: warning: /etc/mtab is not writable (e.g. read-only filesystem).\n"
+ " It's possible that information reported by mount(8) is not\n"
+ " up to date. For actual information about system mount points\n"
+ " check the /proc/mounts file.\n\n"));
+
+ exit (0);
+}
+
+/* reallocates its first arg */
+static char *
+append_opt(char *s, const char *opt, const char *val)
+{
+ if (!opt)
+ return s;
+ if (!s) {
+ if (!val)
+ return xstrdup(opt); /* opt */
+
+ return xstrconcat3(NULL, opt, val); /* opt=val */
+ }
+ if (!val)
+ return xstrconcat3(s, ",", opt); /* s,opt */
+
+ return xstrconcat4(s, ",", opt, val); /* s,opt=val */
+}
+
+static char *
+append_numopt(char *s, const char *opt, unsigned int num)
+{
+ char buf[32];
+
+ snprintf(buf, sizeof(buf), "%u", num);
+ return append_opt(s, opt, buf);
+}
+
+#ifdef HAVE_LIBSELINUX
+/* strip quotes from a "string"
+ * Warning: This function modify the "str" argument.
+ */
+static char *
+strip_quotes(char *str)
+{
+ char *end = NULL;
+
+ if (*str != '"')
+ return str;
+
+ end = strrchr(str, '"');
+ if (end == NULL || end == str)
+ die (EX_USAGE, _("mount: improperly quoted option string '%s'"), str);
+
+ *end = '\0';
+ return str+1;
+}
+
+/* translates SELinux context from human to raw format and
+ * appends it to the mount extra options.
+ *
+ * returns -1 on error and 0 on success
+ */
+static int
+append_context(const char *optname, char *optdata, char **extra_opts)
+{
+ security_context_t raw = NULL;
+ char *data = NULL;
+
+ if (is_selinux_enabled() != 1)
+ /* ignore the option if we running without selinux */
+ return 0;
+
+ if (optdata==NULL || *optdata=='\0' || optname==NULL)
+ return -1;
+
+ /* TODO: use strip_quotes() for all mount options? */
+ data = *optdata =='"' ? strip_quotes(optdata) : optdata;
+
+ if (selinux_trans_to_raw_context(
+ (security_context_t) data, &raw) == -1 ||
+ raw == NULL)
+ return -1;
+
+ if (verbose)
+ printf(_("mount: translated %s '%s' to '%s'\n"),
+ optname, data, (char *) raw);
+
+ *extra_opts = append_opt(*extra_opts, optname, NULL);
+ *extra_opts = xstrconcat4(*extra_opts, "\"", (char *) raw, "\"");
+
+ freecon(raw);
+ return 0;
+}
+
+/* returns newly allocated string without *context= options */
+static char *remove_context_options(char *opts)
+{
+ char *begin = NULL, *end = NULL, *p;
+ int open_quote = 0, changed = 0;
+
+ if (!opts)
+ return NULL;
+
+ opts = xstrdup(opts);
+
+ for (p = opts; p && *p; p++) {
+ if (!begin)
+ begin = p; /* begin of the option item */
+ if (*p == '"')
+ open_quote ^= 1; /* reverse the status */
+ if (open_quote)
+ continue; /* still in quoted block */
+ if (*p == ',')
+ end = p; /* terminate the option item */
+ else if (*(p + 1) == '\0')
+ end = p + 1; /* end of optstr */
+ if (!begin || !end)
+ continue;
+
+ if (strncmp(begin, "context=", 8) == 0 ||
+ strncmp(begin, "fscontext=", 10) == 0 ||
+ strncmp(begin, "defcontext=", 11) == 0 ||
+ strncmp(begin, "rootcontext=", 12) == 0 ||
+ strncmp(begin, "seclabel", 8) == 0) {
+ size_t sz;
+
+ if ((begin == opts || *(begin - 1) == ',') && *end == ',')
+ end++;
+ sz = strlen(end);
+
+ memmove(begin, end, sz + 1);
+ if (!*begin && *(begin - 1) == ',')
+ *(begin - 1) = '\0';
+
+ p = begin;
+ changed = 1;
+ }
+ begin = end = NULL;
+ }
+
+ if (changed && verbose)
+ printf (_("mount: SELinux *context= options are ignore on remount.\n"));
+
+ return opts;
+}
+
+static int has_context_option(char *opts)
+{
+ if (get_option("context=", opts, NULL) ||
+ get_option("fscontext=", opts, NULL) ||
+ get_option("defcontext=", opts, NULL) ||
+ get_option("rootcontext=", opts, NULL))
+ return 1;
+
+ return 0;
+}
+
+#endif
+
+/*
+ * Look for OPT in opt_map table and return mask value.
+ * If OPT isn't found, tack it onto extra_opts (which is non-NULL).
+ * For the options uid= and gid= replace user or group name by its value.
+ */
+static inline void
+parse_opt(char *opt, int *mask, int *inv_user, char **extra_opts) {
+ const struct opt_map *om;
+
+ for (om = opt_map; om->opt != NULL; om++)
+ if (streq (opt, om->opt)) {
+ if (om->inv)
+ *mask &= ~om->mask;
+ else
+ *mask |= om->mask;
+ if (om->inv && ((*mask & MS_USER) || (*mask & MS_USERS))
+ && (om->mask & MS_SECURE))
+ *inv_user |= om->mask;
+ if ((om->mask == MS_USER || om->mask == MS_USERS)
+ && !om->inv)
+ *mask |= MS_SECURE;
+ if ((om->mask == MS_OWNER || om->mask == MS_GROUP)
+ && !om->inv)
+ *mask |= MS_OWNERSECURE;
+#ifdef MS_SILENT
+ if (om->mask == MS_SILENT && om->inv) {
+ mount_quiet = 1;
+ verbose = 0;
+ }
+#endif
+ if (om->mask == MS_COMMENT) {
+ comment_flags |= om->cmask;
+ if (om->cmask == MS_COMMENT_NOFAIL)
+ opt_nofail = 1;
+ }
+ return;
+ }
+
+ /* convert nonnumeric ids to numeric */
+ if (!strncmp(opt, "uid=", 4) && !isdigit(opt[4])) {
+ struct passwd *pw = getpwnam(opt+4);
+
+ if (pw) {
+ *extra_opts = append_numopt(*extra_opts,
+ "uid=", pw->pw_uid);
+ return;
+ }
+ }
+ if (!strncmp(opt, "gid=", 4) && !isdigit(opt[4])) {
+ struct group *gr = getgrnam(opt+4);
+
+ if (gr) {
+ *extra_opts = append_numopt(*extra_opts,
+ "gid=", gr->gr_gid);
+ return;
+ }
+ }
+
+#ifdef HAVE_LIBSELINUX
+ if (strncmp(opt, "context=", 8) == 0 && *(opt+8)) {
+ if (append_context("context=", opt+8, extra_opts) == 0)
+ return;
+ }
+ if (strncmp(opt, "fscontext=", 10) == 0 && *(opt+10)) {
+ if (append_context("fscontext=", opt+10, extra_opts) == 0)
+ return;
+ }
+ if (strncmp(opt, "defcontext=", 11) == 0 && *(opt+11)) {
+ if (append_context("defcontext=", opt+11, extra_opts) == 0)
+ return;
+ }
+ if (strncmp(opt, "rootcontext=", 12) == 0 && *(opt+12)) {
+ if (append_context("rootcontext=", opt+12, extra_opts) == 0)
+ return;
+ }
+#endif
+ *extra_opts = append_opt(*extra_opts, opt, NULL);
+}
+
+
+/* Take -o options list and compute 4th and 5th args to mount(2). flags
+ gets the standard options (indicated by bits) and extra_opts all the rest */
+static void
+parse_opts (const char *options, int *flags, char **extra_opts) {
+ *flags = 0;
+ *extra_opts = NULL;
+
+ clear_string_opts();
+ clear_flags_opts();
+
+ if (options != NULL) {
+ char *opts = xstrdup(options);
+ int open_quote = 0;
+ char *opt, *p;
+
+ for (p=opts, opt=NULL; p && *p; p++) {
+ if (!opt)
+ opt = p; /* begin of the option item */
+ if (*p == '"')
+ open_quote ^= 1; /* reverse the status */
+ if (open_quote)
+ continue; /* still in quoted block */
+ if (*p == ',')
+ *p = '\0'; /* terminate the option item */
+ /* end of option item or last item */
+ if (*p == '\0' || *(p+1) == '\0') {
+ if (!parse_string_opt(opt))
+ parse_opt(opt, flags, &invuser_flags, extra_opts);
+ opt = NULL;
+ }
+ }
+ free(opts);
+ }
+
+ if (readonly)
+ *flags |= MS_RDONLY;
+ if (readwrite)
+ *flags &= ~MS_RDONLY;
+
+ *flags |= mounttype;
+
+ /* The propagation flags should not be used together with any
+ * other flags (except MS_REC and MS_SILENT) */
+ if (*flags & MS_PROPAGATION)
+ *flags &= (MS_PROPAGATION | MS_REC | MS_SILENT);
+}
+
+/* Try to build a canonical options string. */
+static char *
+fix_opts_string (int flags, const char *extra_opts,
+ const char *user, int inv_user)
+{
+ const struct opt_map *om;
+ const struct string_opt_map *m;
+ char *new_opts;
+
+ new_opts = append_opt(NULL, (flags & MS_RDONLY) ? "ro" : "rw", NULL);
+ for (om = opt_map; om->opt != NULL; om++) {
+ if (om->skip)
+ continue;
+ if (om->inv || !om->mask || (flags & om->mask) != om->mask)
+ continue;
+ if (om->mask == MS_COMMENT && !(comment_flags & om->cmask))
+ continue;
+ new_opts = append_opt(new_opts, om->opt, NULL);
+ flags &= ~om->mask;
+ }
+ for (m = &string_opt_map[0]; m->tag; m++) {
+ if (!m->skip && *(m->valptr))
+ new_opts = append_opt(new_opts, m->tag, *(m->valptr));
+ }
+ if (extra_opts && *extra_opts)
+ new_opts = append_opt(new_opts, extra_opts, NULL);
+
+ if (user)
+ new_opts = append_opt(new_opts, "user=", user);
+
+ if (inv_user) {
+ for (om = opt_map; om->opt != NULL; om++) {
+ if (om->mask && om->inv
+ && (inv_user & om->mask) == om->mask) {
+ new_opts = append_opt(new_opts, om->opt, NULL);
+ inv_user &= ~om->mask;
+ }
+ }
+ }
+
+ return new_opts;
+}
+
+static int
+already (const char *spec0, const char *node0) {
+ struct mntentchn *mc;
+ int ret = 1;
+ char *spec = canonicalize_spec(spec0);
+ char *node = canonicalize(node0);
+
+ if ((mc = getmntfile(node)) != NULL)
+ error (_("mount: according to mtab, "
+ "%s is already mounted on %s"),
+ mc->m.mnt_fsname, node);
+ else if (spec && strcmp (spec, "none") &&
+ (mc = getmntfile(spec)) != NULL)
+ error (_("mount: according to mtab, %s is mounted on %s"),
+ spec, mc->m.mnt_dir);
+ else
+ ret = 0;
+
+ free(spec);
+ free(node);
+
+ return ret;
+}
+
+/* Create mtab with a root entry. */
+static void
+create_mtab (void) {
+ struct mntentchn *fstab;
+ struct my_mntent mnt;
+ int flags;
+ mntFILE *mfp;
+
+ lock_mtab();
+
+ mfp = my_setmntent (_PATH_MOUNTED, "a+");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
+ int errsv = errno;
+ die (EX_FILEIO, _("mount: can't open %s for writing: %s"),
+ _PATH_MOUNTED, strerror (errsv));
+ }
+
+ /* Find the root entry by looking it up in fstab */
+ if ((fstab = getfs_by_dir ("/")) || (fstab = getfs_by_dir ("root"))) {
+ char *extra_opts;
+ parse_opts (fstab->m.mnt_opts, &flags, &extra_opts);
+ mnt.mnt_dir = "/";
+ mnt.mnt_fsname = spec_to_devname(fstab->m.mnt_fsname);
+ mnt.mnt_type = fstab->m.mnt_type;
+ mnt.mnt_opts = fix_opts_string (flags, extra_opts, NULL, 0);
+ mnt.mnt_freq = mnt.mnt_passno = 0;
+ free(extra_opts);
+
+ if (my_addmntent (mfp, &mnt) == 1) {
+ int errsv = errno;
+ die (EX_FILEIO, _("mount: error writing %s: %s"),
+ _PATH_MOUNTED, strerror (errsv));
+ }
+ }
+ if (fchmod (fileno (mfp->mntent_fp), 0644) < 0)
+ if (errno != EROFS) {
+ int errsv = errno;
+ die (EX_FILEIO,
+ _("mount: error changing mode of %s: %s"),
+ _PATH_MOUNTED, strerror (errsv));
+ }
+ my_endmntent (mfp);
+
+ unlock_mtab();
+
+ reset_mtab_info();
+}
+
+/* count successful mount system calls */
+static int mountcount = 0;
+
+/*
+ * do_mount_syscall()
+ * Mount a single file system. Keep track of successes.
+ * returns: 0: OK, -1: error in errno
+ */
+static int
+do_mount_syscall (struct mountargs *args) {
+ int flags = args->flags;
+
+ if ((flags & MS_MGC_MSK) == 0)
+ flags |= MS_MGC_VAL;
+
+ if (verbose > 2)
+ printf("mount: mount(2) syscall: source: \"%s\", target: \"%s\", "
+ "filesystemtype: \"%s\", mountflags: %d, data: %s\n",
+ args->spec, args->node, args->type, flags, (char *) args->data);
+
+ return mount (args->spec, args->node, args->type, flags, args->data);
+}
+
+/*
+ * do_mount()
+ * Mount a single file system, possibly invoking an external handler to
+ * do so. Keep track of successes.
+ * returns: 0: OK, -1: error in errno
+ */
+static int
+do_mount (struct mountargs *args, int *special, int *status) {
+ int ret;
+ if (check_special_mountprog(args->spec, args->node, args->type,
+ args->flags, args->data, status)) {
+ *special = 1;
+ ret = 0;
+ } else {
+#ifdef HAVE_LIBMOUNT_MOUNT
+ prepare_mtab_entry(args->spec, args->node, args->type,
+ mtab_opts, mtab_flags);
+#endif
+ ret = do_mount_syscall(args);
+ }
+ if (ret == 0)
+ mountcount++;
+ return ret;
+}
+
+/*
+ * check_special_mountprog()
+ * If there is a special mount program for this type, exec it.
+ * returns: 0: no exec was done, 1: exec was done, status has result
+ */
+static int
+check_special_mountprog(const char *spec, const char *node, const char *type, int flags,
+ char *extra_opts, int *status) {
+ char search_path[] = FS_SEARCH_PATH;
+ char *path, mountprog[150];
+ struct stat statbuf;
+ int res;
+
+ if (!external_allowed)
+ return 0;
+
+ if (type == NULL || strcmp(type, "none") == 0)
+ return 0;
+
+ path = strtok(search_path, ":");
+ while (path) {
+ int type_opt = 0;
+
+ res = snprintf(mountprog, sizeof(mountprog), "%s/mount.%s",
+ path, type);
+ path = strtok(NULL, ":");
+ if (res < 0 || (size_t) res >= sizeof(mountprog))
+ continue;
+
+ res = stat(mountprog, &statbuf);
+ if (res == -1 && errno == ENOENT && strchr(type, '.')) {
+ /* If type ends with ".subtype" try without it */
+ *strrchr(mountprog, '.') = '\0';
+ type_opt = 1;
+ res = stat(mountprog, &statbuf);
+ }
+ if (res)
+ continue;
+
+ if (verbose)
+ fflush(stdout);
+
+ switch (fork()) {
+ case 0: { /* child */
+ char *oo, *mountargs[12];
+ int i = 0;
+
+ if (setgid(getgid()) < 0)
+ die(EX_FAIL, _("mount: cannot set group id: %m"));
+
+ if (setuid(getuid()) < 0)
+ die(EX_FAIL, _("mount: cannot set user id: %m"));
+
+ oo = fix_opts_string(flags, extra_opts, NULL, invuser_flags);
+ mountargs[i++] = mountprog; /* 1 */
+ mountargs[i++] = (char *) spec; /* 2 */
+ mountargs[i++] = (char *) node; /* 3 */
+ if (sloppy && strncmp(type, "nfs", 3) == 0)
+ mountargs[i++] = "-s"; /* 4 */
+ if (fake)
+ mountargs[i++] = "-f"; /* 5 */
+ if (nomtab)
+ mountargs[i++] = "-n"; /* 6 */
+ if (verbose)
+ mountargs[i++] = "-v"; /* 7 */
+ if (oo && *oo) {
+ mountargs[i++] = "-o"; /* 8 */
+ mountargs[i++] = oo; /* 9 */
+ }
+ if (type_opt) {
+ mountargs[i++] = "-t"; /* 10 */
+ mountargs[i++] = (char *) type; /* 11 */
+ }
+ mountargs[i] = NULL; /* 12 */
+
+ if (verbose > 2) {
+ i = 0;
+ while (mountargs[i]) {
+ printf("mount: external mount: argv[%d] = \"%s\"\n",
+ i, mountargs[i]);
+ i++;
+ }
+ fflush(stdout);
+ }
+
+ execv(mountprog, mountargs);
+ exit(1); /* exec failed */
+ }
+
+ default: { /* parent */
+ int st;
+ wait(&st);
+ *status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR);
+ return 1;
+ }
+
+ case -1: { /* error */
+ int errsv = errno;
+ error(_("mount: cannot fork: %s"), strerror(errsv));
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* list of already tested filesystems by procfsloop_mount() */
+static struct tried {
+ struct tried *next;
+ char *type;
+} *tried = NULL;
+
+static int
+was_tested(const char *fstype) {
+ struct tried *t;
+
+ for (t = tried; t; t = t->next) {
+ if (!strcmp(t->type, fstype))
+ return 1;
+ }
+ return 0;
+}
+
+static void
+set_tested(const char *fstype) {
+ struct tried *t = xmalloc(sizeof(struct tried));
+
+ t->next = tried;
+ t->type = xstrdup(fstype);
+ tried = t;
+}
+
+static void
+free_tested(void) {
+ struct tried *t, *tt;
+
+ t = tried;
+ while(t) {
+ free(t->type);
+ tt = t->next;
+ free(t);
+ t = tt;
+ }
+ tried = NULL;
+}
+
+static char *
+procfsnext(FILE *procfs) {
+ char line[100];
+ char fsname[100];
+
+ while (fgets(line, sizeof(line), procfs)) {
+ if (sscanf (line, "nodev %[^#\n]\n", fsname) == 1) continue;
+ if (sscanf (line, " %[^# \n]\n", fsname) != 1) continue;
+ return xstrdup(fsname);
+ }
+ return 0;
+}
+
+/* Only use /proc/filesystems here, this is meant to test what
+ the kernel knows about, so /etc/filesystems is irrelevant.
+ Return: 1: yes, 0: no, -1: cannot open procfs */
+static int
+known_fstype_in_procfs(const char *type)
+{
+ FILE *procfs;
+ char *fsname;
+ int ret = -1;
+
+ procfs = fopen(_PATH_PROC_FILESYSTEMS, "r");
+ if (procfs) {
+ ret = 0;
+ while ((fsname = procfsnext(procfs)) != NULL)
+ if (!strcmp(fsname, type)) {
+ ret = 1;
+ break;
+ }
+ fclose(procfs);
+ procfs = NULL;
+ }
+ return ret;
+}
+
+/* Try all types in FILESYSTEMS, except those in *types,
+ in case *types starts with "no" */
+/* return: 0: OK, -1: error in errno, 1: type not found */
+/* when 0 or -1 is returned, *types contains the type used */
+/* when 1 is returned, *types is NULL */
+static int
+procfsloop_mount(int (*mount_fn)(struct mountargs *, int *, int *),
+ struct mountargs *args,
+ const char **types,
+ int *special, int *status)
+{
+ char *files[2] = { _PATH_FILESYSTEMS, _PATH_PROC_FILESYSTEMS };
+ FILE *procfs;
+ char *fsname;
+ const char *notypes = NULL;
+ int no = 0;
+ int ret = 1;
+ int errsv = 0;
+ int i;
+
+ if (*types && !strncmp(*types, "no", 2)) {
+ no = 1;
+ notypes = (*types) + 2;
+ }
+ *types = NULL;
+
+ /* Use _PATH_PROC_FILESYSTEMS only when _PATH_FILESYSTEMS
+ * (/etc/filesystems) does not exist. In some cases trying a
+ * filesystem that the kernel knows about on the wrong data will crash
+ * the kernel; in such cases _PATH_FILESYSTEMS can be used to list the
+ * filesystems that we are allowed to try, and in the order they should
+ * be tried. End _PATH_FILESYSTEMS with a line containing a single '*'
+ * only, if _PATH_PROC_FILESYSTEMS should be tried afterwards.
+ */
+ for (i=0; i<2; i++) {
+ procfs = fopen(files[i], "r");
+ if (!procfs)
+ continue;
+ while ((fsname = procfsnext(procfs)) != NULL) {
+ if (!strcmp(fsname, "*")) {
+ fclose(procfs);
+ goto nexti;
+ }
+ if (was_tested (fsname))
+ continue;
+ if (no && matching_type(fsname, notypes))
+ continue;
+ set_tested (fsname);
+ args->type = fsname;
+ if (verbose)
+ printf(_("Trying %s\n"), fsname);
+ if ((*mount_fn) (args, special, status) == 0) {
+ *types = fsname;
+ ret = 0;
+ break;
+ } else if (errno != EINVAL &&
+ known_fstype_in_procfs(fsname) == 1) {
+ *types = "guess";
+ ret = -1;
+ errsv = errno;
+ break;
+ }
+ }
+ free_tested();
+ fclose(procfs);
+ errno = errsv;
+ return ret;
+ nexti:;
+ }
+ return 1;
+}
+
+static const char *
+guess_fstype_by_devname(const char *devname, int *ambivalent)
+{
+ const char *type = fsprobe_get_fstype_by_devname_ambi(devname, ambivalent);
+
+ if (verbose) {
+ printf (_("mount: you didn't specify a filesystem type for %s\n"), devname);
+
+ if (!type)
+ printf (_(" I will try all types mentioned in %s or %s\n"),
+ _PATH_FILESYSTEMS, _PATH_PROC_FILESYSTEMS);
+ else if (!strcmp(type, MNTTYPE_SWAP))
+ printf (_(" and it looks like this is swapspace\n"));
+ else
+ printf (_(" I will try type %s\n"), type);
+ }
+ return type;
+}
+
+/*
+ * guess_fstype_and_mount()
+ * Mount a single file system. Guess the type when unknown.
+ * returns: 0: OK, -1: error in errno, 1: other error
+ * don't exit on non-fatal errors.
+ * on return types is filled with the type used.
+ */
+static int
+guess_fstype_and_mount(const char *spec, const char *node, const char **types,
+ int flags, char *mount_opts, int *special, int *status) {
+ struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts };
+ int ambivalent = 0;
+
+ if (*types && strcasecmp (*types, "auto") == 0)
+ *types = NULL;
+
+ if (!*types && !(flags & MS_REMOUNT)) {
+ *types = guess_fstype_by_devname(spec, &ambivalent);
+ if (*types) {
+ if (!strcmp(*types, MNTTYPE_SWAP)) {
+ error(_("%s looks like swapspace - not mounted"), spec);
+ *types = NULL;
+ return 1;
+ } else {
+ args.type = *types;
+ return do_mount (&args, special, status);
+ }
+ } else if (ambivalent) {
+ error(_("mount: %s: more filesystems detected. This should not happen,\n"
+ " use -t <type> to explicitly specify the filesystem type or\n"
+ " use wipefs(8) to clean up the device.\n"), spec);
+ return 1;
+ }
+ }
+
+ /* Accept a comma-separated list of types, and try them one by one */
+ /* A list like "nonfs,.." indicates types not to use */
+ if (*types && strncmp(*types, "no", 2) && strchr(*types,',')) {
+ char *t = strdup(*types);
+ char *p;
+
+ while((p = strchr(t,',')) != NULL) {
+ *p = 0;
+ args.type = *types = t;
+ if (do_mount (&args, special, status) == 0)
+ return 0;
+ t = p+1;
+ }
+ /* do last type below */
+ *types = t;
+ }
+
+ if (*types || (flags & MS_REMOUNT)) {
+ args.type = *types;
+ return do_mount (&args, special, status);
+ }
+
+ return procfsloop_mount(do_mount, &args, types, special, status);
+}
+
+/*
+ * restricted_check()
+ * Die if the user is not allowed to do this.
+ */
+static void
+restricted_check(const char *spec, const char *node, int *flags, char **user) {
+ if (restricted) {
+ /*
+ * MS_OWNER: Allow owners to mount when fstab contains
+ * the owner option. Note that this should never be used
+ * in a high security environment, but may be useful to give
+ * people at the console the possibility of mounting a floppy.
+ * MS_GROUP: Allow members of device group to mount. (Martin Dickopp)
+ */
+ if (*flags & (MS_OWNER | MS_GROUP)) {
+ struct stat sb;
+
+ if (!strncmp(spec, "/dev/", 5) && stat(spec, &sb) == 0) {
+
+ if (*flags & MS_OWNER) {
+ if (getuid() == sb.st_uid)
+ *flags |= MS_USER;
+ }
+
+ if (*flags & MS_GROUP) {
+ if (getgid() == sb.st_gid)
+ *flags |= MS_USER;
+ else {
+ int n = getgroups(0, NULL);
+
+ if (n > 0) {
+ gid_t *groups = xmalloc(n * sizeof(*groups));
+ if (getgroups(n, groups) == n) {
+ int i;
+ for (i = 0; i < n; i++) {
+ if (groups[i] == sb.st_gid) {
+ *flags |= MS_USER;
+ break;
+ }
+ }
+ }
+ free(groups);
+ }
+ }
+ }
+ }
+ }
+
+ /* James Kehl <mkehl@gil.com.au> came with a similar patch:
+ allow an arbitrary user to mount when he is the owner of
+ the mount-point and has write-access to the device.
+ This is even less secure. Let me skip it for the time being;
+ there should be an explicit fstab line allowing such things. */
+
+ if (!(*flags & (MS_USER | MS_USERS))) {
+ if (already (spec, node))
+ die (EX_USAGE, _("mount failed"));
+ else
+ die (EX_USAGE, _("mount: only root can mount %s on %s"), spec, node);
+ }
+ if (*flags & MS_USER)
+ *user = getusername();
+ }
+
+ *flags &= ~(MS_OWNER | MS_GROUP);
+}
+
+/* Check, if there already exists a mounted loop device on the mountpoint node
+ * with the same parameters.
+ */
+static int
+is_mounted_same_loopfile(const char *node0, const char *loopfile, unsigned long long offset)
+{
+ struct mntentchn *mnt = NULL;
+ char *node;
+ int res = 0;
+
+ node = canonicalize(node0);
+
+ /* Search for mountpoint node in mtab,
+ * procceed if any of these has the loop option set or
+ * the device is a loop device
+ */
+ mnt = getmntdirbackward(node, mnt);
+ if (!mnt) {
+ free(node);
+ return 0;
+ }
+ for(; mnt && res == 0; mnt = getmntdirbackward(node, mnt)) {
+ char *p;
+
+ if (strncmp(mnt->m.mnt_fsname, "/dev/loop", 9) == 0)
+ res = loopdev_is_used((char *) mnt->m.mnt_fsname,
+ loopfile, offset, LOOPDEV_FL_OFFSET);
+
+ else if (mnt->m.mnt_opts &&
+ (p = strstr(mnt->m.mnt_opts, "loop=")))
+ {
+ char *dev = xstrdup(p+5);
+ if ((p = strchr(dev, ',')))
+ *p = '\0';
+ res = loopdev_is_used(dev,
+ loopfile, offset, LOOPDEV_FL_OFFSET);
+ free(dev);
+ }
+ }
+
+ free(node);
+ return res;
+}
+
+static int
+parse_offset(const char **opt, uintmax_t *val)
+{
+ char *tmp;
+
+ if (strtosize(*opt, val))
+ return -1;
+
+ tmp = xmalloc(32);
+ snprintf(tmp, 32, "%jd", *val);
+ my_free(*opt);
+ *opt = tmp;
+ return 0;
+}
+
+static int
+loop_check(const char **spec, const char **type, int *flags,
+ int *loop, const char **loopdev, const char **loopfile,
+ const char *node) {
+ int looptype;
+ uintmax_t offset = 0, sizelimit = 0;
+ struct loopdev_cxt lc;
+ char *pwd = NULL;
+ int ret = EX_FAIL;
+
+ /*
+ * In the case of a loop mount, either type is of the form lo@/dev/loop5
+ * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
+ * mount just has to figure things out for itself from the fact that
+ * spec is not a block device. We do not test for a block device
+ * immediately: maybe later other types of mountable objects will occur.
+ */
+
+ *loopdev = opt_loopdev;
+
+ looptype = (*type && strncmp("lo@", *type, 3) == 0);
+ if (looptype) {
+ if (*loopdev)
+ error(_("mount: loop device specified twice"));
+ *loopdev = *type + 3;
+ *type = opt_vfstype;
+ } else if (opt_vfstype) {
+ if (*type)
+ error(_("mount: type specified twice"));
+ else
+ *type = opt_vfstype;
+ }
+
+ *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_sizelimit || opt_encryption);
+ *loopfile = *spec;
+
+ /* Automatically create a loop device from a regular file if a filesystem
+ * is not specified or the filesystem is known for libblkid (these
+ * filesystems work with block devices only).
+ *
+ * Note that there is not a restriction (on kernel side) that prevents regular
+ * file as a mount(2) source argument. A filesystem that is able to mount
+ * regular files could be implemented.
+ */
+ if (!*loop && !(*flags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) &&
+ (!*type || strcmp(*type, "auto") == 0 || fsprobe_known_fstype(*type))) {
+
+ struct stat st;
+ if (stat(*loopfile, &st) == 0)
+ *loop = S_ISREG(st.st_mode);
+ }
+
+ if (*loop) {
+ *flags |= MS_LOOP;
+ if (fake) {
+ if (verbose)
+ printf(_("mount: skipping the setup of a loop device\n"));
+ } else {
+ int loop_opts = 0;
+
+ /* since 2.6.37 we don't have to store backing filename to mtab
+ * because kernel provides the name in /sys
+ */
+ if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
+ mtab_is_writable() == 0) {
+
+ if (verbose)
+ printf(_("mount: enabling autoclear loopdev flag\n"));
+ loop_opts = LO_FLAGS_AUTOCLEAR;
+ }
+
+ if (*flags & MS_RDONLY)
+ loop_opts |= LO_FLAGS_READ_ONLY;
+
+ if (opt_offset && parse_offset(&opt_offset, &offset)) {
+ error(_("mount: invalid offset '%s' specified"), opt_offset);
+ return EX_FAIL;
+ }
+ if (opt_sizelimit && parse_offset(&opt_sizelimit, &sizelimit)) {
+ error(_("mount: invalid sizelimit '%s' specified"), opt_sizelimit);
+ return EX_FAIL;
+ }
+
+ if (is_mounted_same_loopfile(node, *loopfile, offset)) {
+ error(_("mount: according to mtab %s is already mounted on %s as loop"), *loopfile, node);
+ return EX_FAIL;
+ }
+
+ if (opt_encryption) {
+#ifdef MCL_FUTURE
+ if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
+ error(_("mount: couldn't lock into memory"));
+ return EX_FAIL;
+ }
+#endif
+ pwd = xgetpass(pfd, _("Password: "));
+ }
+
+ loopcxt_init(&lc, 0);
+ /*loopcxt_enable_debug(&lc, 1);*/
+
+ if (*loopdev && **loopdev)
+ loopcxt_set_device(&lc, *loopdev); /* use loop=<devname> */
+
+ do {
+ int rc;
+
+ if ((!*loopdev || !**loopdev) && loopcxt_find_unused(&lc) == 0)
+ *loopdev = loopcxt_strdup_device(&lc);
+
+ if (!*loopdev) {
+ error(_("mount: failed to found free loop device"));
+ loopcxt_deinit(&lc);
+ goto err; /* no more loop devices */
+ }
+ if (verbose)
+ printf(_("mount: going to use the loop device %s\n"), *loopdev);
+
+ rc = loopcxt_set_backing_file(&lc, *loopfile);
+
+ if (!rc && offset)
+ rc = loopcxt_set_offset(&lc, offset);
+ if (!rc && sizelimit)
+ rc = loopcxt_set_sizelimit(&lc, sizelimit);
+ if (!rc && opt_encryption && pwd)
+ loopcxt_set_encryption(&lc, opt_encryption, pwd);
+ if (!rc)
+ loopcxt_set_flags(&lc, loop_opts);
+
+ if (rc) {
+ error(_("mount: %s: failed to set loopdev attributes"), *loopdev);
+ loopcxt_deinit(&lc);
+ goto err;
+ }
+
+ /* setup the device */
+ rc = loopcxt_setup_device(&lc);
+ if (!rc)
+ break; /* success */
+
+ if (rc != -EBUSY) {
+ error(_("mount: %s: failed setting up loop device: %m"), *loopfile);
+ if (!opt_loopdev) {
+ my_free(*loopdev);
+ *loopdev = NULL;
+ }
+ loopcxt_deinit(&lc);
+ goto err;
+ }
+
+ if (!opt_loopdev) {
+ if (verbose)
+ printf(_("mount: stolen loop=%s ...trying again\n"), *loopdev);
+ my_free(*loopdev);
+ *loopdev = NULL;
+ continue;
+ }
+ error(_("mount: stolen loop=%s"), *loopdev);
+ loopcxt_deinit(&lc);
+ goto err;
+
+ } while (!*loopdev);
+
+ if (verbose > 1)
+ printf(_("mount: setup loop device successfully\n"));
+ *spec = *loopdev;
+
+ if (loopcxt_is_readonly(&lc))
+ *flags |= MS_RDONLY;
+
+ if (loopcxt_is_autoclear(&lc))
+ /* Prevent recording loop dev in mtab for cleanup on umount */
+ *loop = 0;
+
+ /* We have to keep the device open until mount(2), otherwise it will
+ * be auto-cleared by kernel (because LO_FLAGS_AUTOCLEAR) */
+ loopcxt_set_fd(&lc, -1, 0);
+ loopcxt_deinit(&lc);
+ }
+ }
+
+ ret = 0;
+err:
+ if (pwd) {
+ char *p = pwd;
+ while (*p)
+ *p++ = '\0';
+ free(pwd);
+ }
+ return ret;
+}
+
+
+#ifdef HAVE_LIBMOUNT_MOUNT
+static void
+verbose_mount_info(const char *spec, const char *node, const char *type,
+ const char *opts)
+{
+ struct my_mntent mnt;
+
+ mnt.mnt_fsname = is_pseudo_fs(type) ? spec : canonicalize(spec);
+ mnt.mnt_dir = canonicalize (node);
+ mnt.mnt_type = type;
+ mnt.mnt_opts = opts;
+
+ print_one (&mnt);
+
+ if (spec != mnt.mnt_fsname)
+ my_free(mnt.mnt_fsname);
+ my_free(mnt.mnt_dir);
+}
+
+static void
+prepare_mtab_entry(const char *spec, const char *node, const char *type,
+ const char *opts, unsigned long flags)
+{
+ struct libmnt_fs *fs = mnt_new_fs();
+ int rc = -1;
+
+ if (!mtab_update)
+ mtab_update = mnt_new_update();
+
+ if (mtab_update && fs) {
+ const char *cn_spec = is_pseudo_fs(type) ? spec : canonicalize(spec);
+ const char *cn_node = canonicalize(node);
+
+ mnt_fs_set_source(fs, cn_spec);
+ mnt_fs_set_target(fs, cn_node);
+ mnt_fs_set_fstype(fs, type);
+ mnt_fs_set_options(fs, opts);
+
+ rc = mnt_update_set_fs(mtab_update, flags, NULL, fs);
+
+ if (spec != cn_spec)
+ my_free(cn_spec);
+ my_free(cn_node);
+ }
+
+ mnt_free_fs(fs);
+
+ if (rc) {
+ mnt_free_update(mtab_update);
+ mtab_update = NULL;
+ }
+}
+
+static void update_mtab_entry(int flags)
+{
+ unsigned long fl;
+
+ if (!mtab_update)
+ return;
+
+ fl = mnt_update_get_mflags(mtab_update);
+
+ if ((flags & MS_RDONLY) != (fl & MS_RDONLY))
+ mnt_update_force_rdonly(mtab_update, flags & MS_RDONLY);
+
+ if (!nomtab) {
+ if (mtab_does_not_exist()) {
+ if (verbose > 1)
+ printf(_("mount: no %s found - creating it..\n"),
+ _PATH_MOUNTED);
+ create_mtab ();
+ }
+
+ mnt_update_table(mtab_update, NULL);
+ }
+
+ mnt_free_update(mtab_update);
+ mtab_update = NULL;
+}
+
+#else /*!HAVE_LIBMOUNT_MOUNT */
+static void
+update_mtab_entry(const char *spec, const char *node, const char *type,
+ const char *opts, int flags, int freq, int pass) {
+ struct my_mntent mnt;
+
+ mnt.mnt_fsname = is_pseudo_fs(type) ? xstrdup(spec) : canonicalize(spec);
+ mnt.mnt_dir = canonicalize (node);
+ mnt.mnt_type = type;
+ mnt.mnt_opts = opts;
+ mnt.mnt_freq = freq;
+ mnt.mnt_passno = pass;
+
+ /* We get chatty now rather than after the update to mtab since the
+ mount succeeded, even if the write to /etc/mtab should fail. */
+ if (verbose)
+ print_one (&mnt);
+
+ if (!nomtab && mtab_does_not_exist()) {
+ if (verbose > 1)
+ printf(_("mount: no %s found - creating it..\n"),
+ _PATH_MOUNTED);
+ create_mtab ();
+
+ }
+
+ if (!nomtab && mtab_is_writable()) {
+ if (flags & MS_REMOUNT)
+ update_mtab (mnt.mnt_dir, &mnt);
+ else if (flags & MS_MOVE)
+ update_mtab(mnt.mnt_fsname, &mnt);
+ else
+ update_mtab(NULL, &mnt);
+ }
+ my_free(mnt.mnt_fsname);
+ my_free(mnt.mnt_dir);
+}
+#endif /* !HAVE_LIBMOUNT_MOUNT */
+
+static void
+set_pfd(char *s) {
+ if (!isdigit(*s))
+ die(EX_USAGE,
+ _("mount: argument to -p or --pass-fd must be a number"));
+ pfd = atoi(optarg);
+}
+
+static void
+cdrom_setspeed(const char *spec) {
+#define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */
+ if (opt_speed) {
+ int cdrom;
+ int speed = atoi(opt_speed);
+
+ if ((cdrom = open(spec, O_RDONLY | O_NONBLOCK)) < 0)
+ die(EX_FAIL,
+ _("mount: cannot open %s for setting speed"),
+ spec);
+ if (ioctl(cdrom, CDROM_SELECT_SPEED, speed) < 0)
+ die(EX_FAIL, _("mount: cannot set speed: %m"));
+ close(cdrom);
+ }
+}
+
+/*
+ * Check if @path is on read-only filesystem independently on file permissions.
+ */
+static int
+is_readonly(const char *path)
+{
+ if (access(path, W_OK) == 0)
+ return 0;
+ if (errno == EROFS)
+ return 1;
+ if (errno != EACCES)
+ return 0;
+
+#ifdef HAVE_FUTIMENS
+ /*
+ * access(2) returns EACCES on read-only FS:
+ *
+ * - for set-uid application if one component of the path is not
+ * accessible for the current rUID. (Note that euidaccess(2) does not
+ * check for EROFS at all).
+ *
+ * - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind)
+ */
+ {
+ struct timespec times[2];
+
+ times[0].tv_nsec = UTIME_NOW; /* atime */
+ times[1].tv_nsec = UTIME_OMIT; /* mtime */
+
+ if (utimensat(AT_FDCWD, path, times, 0) == -1)
+ return errno == EROFS;
+ }
+#endif
+ return 0;
+}
+
+/*
+ * try_mount_one()
+ * Try to mount one file system.
+ *
+ * returns: 0: OK, EX_SYSERR, EX_FAIL, return code from nfsmount,
+ * return status from wait
+ */
+static int
+try_mount_one (const char *spec0, const char *node0, const char *types0,
+ const char *opts0, int freq, int pass, int ro) {
+ int res = 0, status = 0, special = 0;
+ int mnt5_res = 0; /* only for gcc */
+ int mnt_err;
+ int flags;
+ char *extra_opts; /* written in mtab */
+ char *mount_opts; /* actually used on system call */
+ const char *opts, *spec, *node, *types;
+ char *user = 0;
+ int loop = 0;
+ const char *loopdev = 0, *loopfile = 0;
+ struct stat statbuf;
+
+ /* copies for freeing on exit */
+ const char *opts1, *spec1, *node1, *types1;
+
+ if (verbose > 2) {
+ printf("mount: spec: \"%s\"\n", spec0);
+ printf("mount: node: \"%s\"\n", node0);
+ printf("mount: types: \"%s\"\n", types0);
+ printf("mount: opts: \"%s\"\n", opts0);
+ }
+
+ spec = spec1 = xstrdup(spec0);
+ node = node1 = xstrdup(node0);
+ types = types1 = xstrdup(types0);
+ opts = opts1 = xstrdup(opts0);
+
+ parse_opts (opts, &flags, &extra_opts);
+ mount_opts = xstrdup(extra_opts);
+
+ /* quietly succeed for fstab entries that don't get mounted automatically */
+ if (mount_all && (flags & MS_NOAUTO))
+ goto out;
+
+ restricted_check(spec, node, &flags, &user);
+
+ /* The "mount -f" checks for for existing record in /etc/mtab (with
+ * regular non-fake mount this is usually done by kernel)
+ */
+ if (!(flags & MS_REMOUNT) && fake && mounted (spec, node, NULL))
+ die(EX_USAGE, _("mount: according to mtab, "
+ "%s is already mounted on %s\n"),
+ spec, node);
+
+ if (opt_speed)
+ cdrom_setspeed(spec);
+
+ if (!(flags & MS_REMOUNT)) {
+ /*
+ * Don't set up a (new) loop device if we only remount - this left
+ * stale assignments of files to loop devices. Nasty when used for
+ * encryption.
+ */
+ res = loop_check(&spec, &types, &flags, &loop, &loopdev, &loopfile, node);
+ if (res)
+ goto out;
+ }
+
+ if (loop)
+ opt_loopdev = loopdev;
+
+ if (flags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
+ types = "none";
+
+#ifdef HAVE_LIBSELINUX
+ if (flags & MS_REMOUNT) {
+ /*
+ * Linux kernel does not accept any selinux context option on remount
+ */
+ if (mount_opts) {
+ char *tmp = mount_opts;
+ mount_opts = remove_context_options(mount_opts);
+ my_free(tmp);
+ }
+
+ } else if (types && strcmp(types, "tmpfs") == 0 && is_selinux_enabled() > 0 &&
+ !has_context_option(mount_opts)) {
+ /*
+ * Add rootcontext= mount option for tmpfs
+ * https://bugzilla.redhat.com/show_bug.cgi?id=476964
+ */
+ security_context_t sc = NULL;
+
+ if (getfilecon(node, &sc) > 0 && strcmp("unlabeled", sc))
+ append_context("rootcontext=", (char *) sc, &mount_opts);
+ freecon(sc);
+ }
+#endif
+
+ /*
+ * Call mount.TYPE for types that require a separate mount program.
+ * For the moment these types are ncpfs and smbfs. Maybe also vxfs.
+ * All such special things must occur isolated in the types string.
+ */
+ if (check_special_mountprog(spec, node, types, flags, mount_opts, &status)) {
+ res = status;
+ goto out;
+ }
+
+#ifdef HAVE_LIBMOUNT_MOUNT
+ mtab_opts = fix_opts_string(flags & ~MS_NOMTAB, extra_opts, user, 0);
+ mtab_flags = flags;
+
+ if (fake)
+ prepare_mtab_entry(spec, node, types, mtab_opts, mtab_flags);
+#endif
+
+ block_signals (SIG_BLOCK);
+
+ if (!fake) {
+ mnt5_res = guess_fstype_and_mount (spec, node, &types, flags & ~MS_NOSYS,
+ mount_opts, &special, &status);
+
+ if (special) {
+ block_signals (SIG_UNBLOCK);
+ res = status;
+ goto out;
+ }
+ }
+
+ /* Kernel allows to use MS_RDONLY for bind mounts, but the read-only request
+ * could be silently ignored. Check it to avoid 'ro' in mtab and 'rw' in
+ * /proc/mounts.
+ */
+ if (!fake && mnt5_res == 0 &&
+ (flags & MS_BIND) && (flags & MS_RDONLY) && !is_readonly(node)) {
+
+ printf(_("mount: warning: %s seems to be mounted read-write.\n"), node);
+ flags &= ~MS_RDONLY;
+ }
+
+ /* Kernel can silently add MS_RDONLY flag when mounting file system that
+ * does not have write support. Check this to avoid 'ro' in /proc/mounts
+ * and 'rw' in mtab.
+ */
+ if (!fake && mnt5_res == 0 &&
+ !(flags & (MS_RDONLY | MS_PROPAGATION | MS_MOVE)) &&
+ is_readonly(node)) {
+
+ printf(_("mount: warning: %s seems to be mounted read-only.\n"), node);
+ flags |= MS_RDONLY;
+ }
+
+ if (fake || mnt5_res == 0) {
+ char *mo = fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user, 0);
+ const char *tp = types ? types : "unknown";
+
+ /* Mount succeeded, report this (if verbose) and write mtab entry. */
+#ifdef HAVE_LIBMOUNT_MOUNT
+ update_mtab_entry(flags);
+ if (verbose)
+ verbose_mount_info(loop ? loopfile : spec, node, tp, mo);
+#else
+ if (!(mounttype & MS_PROPAGATION))
+ update_mtab_entry(loop ? loopfile : spec,
+ node,
+ tp,
+ mo,
+ flags,
+ freq,
+ pass);
+#endif
+ block_signals (SIG_UNBLOCK);
+ free(mo);
+
+ res = 0;
+ goto out;
+ }
+
+ mnt_err = errno;
+
+ if (loop)
+ loopdev_delete(spec);
+
+ block_signals (SIG_UNBLOCK);
+
+ /* Mount failed, complain, but don't die. */
+
+ if (types == 0) {
+ if (restricted)
+ error (_("mount: I could not determine the filesystem type, "
+ "and none was specified"));
+ else
+ error (_("mount: you must specify the filesystem type"));
+ } else if (mnt5_res != -1) {
+ /* should not happen */
+ error (_("mount: mount failed"));
+ } else {
+ switch (mnt_err) {
+ case EPERM:
+ if (geteuid() == 0) {
+ if (stat (node, &statbuf) || !S_ISDIR(statbuf.st_mode))
+ error (_("mount: mount point %s is not a directory"), node);
+ else
+ error (_("mount: permission denied"));
+ } else
+ error (_("mount: must be superuser to use mount"));
+ break;
+ case EBUSY:
+ if (flags & MS_REMOUNT) {
+ error (_("mount: %s is busy"), node);
+ } else if (!strcmp(types, "proc") && !strcmp(node, "/proc")) {
+ /* heuristic: if /proc/version exists, then probably proc is mounted */
+ if (stat ("/proc/version", &statbuf)) /* proc mounted? */
+ error (_("mount: %s is busy"), node); /* no */
+ else if (!mount_all || verbose) /* yes, don't mention it */
+ error (_("mount: proc already mounted"));
+ } else {
+ error (_("mount: %s already mounted or %s busy"), spec, node);
+ already (spec, node);
+ }
+ break;
+ case ENOENT:
+ if (lstat (node, &statbuf))
+ error (_("mount: mount point %s does not exist"), node);
+ else if (stat (node, &statbuf))
+ error (_("mount: mount point %s is a symbolic link to nowhere"),
+ node);
+ else if (stat (spec, &statbuf)) {
+ if (opt_nofail)
+ goto out;
+ error (_("mount: special device %s does not exist"), spec);
+ } else {
+ errno = mnt_err;
+ perror("mount");
+ }
+ break;
+ case ENOTDIR:
+ if (stat (node, &statbuf) || ! S_ISDIR(statbuf.st_mode))
+ error (_("mount: mount point %s is not a directory"), node);
+ else if (stat (spec, &statbuf) && errno == ENOTDIR) {
+ if (opt_nofail)
+ goto out;
+ error (_("mount: special device %s does not exist\n"
+ " (a path prefix is not a directory)\n"), spec);
+ } else {
+ errno = mnt_err;
+ perror("mount");
+ }
+ break;
+ case EINVAL:
+ { int fd;
+ unsigned long long size = 0;
+
+ if (flags & MS_REMOUNT) {
+ error (_("mount: %s not mounted or bad option"), node);
+ } else {
+ error (_("mount: wrong fs type, bad option, bad superblock on %s,\n"
+ " missing codepage or helper program, or other error"),
+ spec);
+
+ if (stat(spec, &statbuf) < 0) {
+ if (errno == ENOENT) /* network FS? */
+ error(_(
+ " (for several filesystems (e.g. nfs, cifs) you might\n"
+ " need a /sbin/mount.<type> helper program)"));
+
+ } else if (S_ISBLK(statbuf.st_mode)
+ && (fd = open(spec, O_RDONLY | O_NONBLOCK)) >= 0) {
+
+ if (blkdev_get_size(fd, &size) == 0) {
+ if (size == 0 && !loop)
+ error(_(
+ " (could this be the IDE device where you in fact use\n"
+ " ide-scsi so that sr0 or sda or so is needed?)"));
+
+ if (size && size <= 2)
+ error(_(
+ " (aren't you trying to mount an extended partition,\n"
+ " instead of some logical partition inside?)"));
+
+ close(fd);
+ }
+ }
+ error(_(
+ " In some cases useful info is found in syslog - try\n"
+ " dmesg | tail or so\n"));
+ }
+ break;
+ }
+ case EMFILE:
+ error (_("mount table full")); break;
+ case EIO:
+ error (_("mount: %s: can't read superblock"), spec); break;
+ case ENODEV:
+ {
+ int pfs = known_fstype_in_procfs(types);
+
+ if (pfs == 1 || !strcmp(types, "guess"))
+ error(_("mount: %s: unknown device"), spec);
+ else if (pfs == 0) {
+ char *lowtype, *p;
+ int u;
+
+ error (_("mount: unknown filesystem type '%s'"), types);
+
+ /* maybe this loser asked for FAT or ISO9660 or isofs */
+ lowtype = xstrdup(types);
+ u = 0;
+ for(p=lowtype; *p; p++) {
+ if(tolower(*p) != *p) {
+ *p = tolower(*p);
+ u++;
+ }
+ }
+ if (u && known_fstype_in_procfs(lowtype) == 1)
+ error (_("mount: probably you meant %s"), lowtype);
+ else if (!strncmp(lowtype, "iso", 3) &&
+ known_fstype_in_procfs("iso9660") == 1)
+ error (_("mount: maybe you meant 'iso9660'?"));
+ else if (!strncmp(lowtype, "fat", 3) &&
+ known_fstype_in_procfs("vfat") == 1)
+ error (_("mount: maybe you meant 'vfat'?"));
+ free(lowtype);
+ } else
+ error (_("mount: %s has wrong device number or fs type %s not supported"),
+ spec, types);
+ break;
+ }
+ case ENOTBLK:
+ if (opt_nofail)
+ goto out;
+ if (stat (spec, &statbuf)) /* strange ... */
+ error (_("mount: %s is not a block device, and stat fails?"), spec);
+ else if (S_ISBLK(statbuf.st_mode))
+ error (_("mount: the kernel does not recognize %s as a block device\n"
+ " (maybe `modprobe driver'?)"), spec);
+ else if (S_ISREG(statbuf.st_mode))
+ error (_("mount: %s is not a block device (maybe try `-o loop'?)"),
+ spec);
+ else
+ error (_("mount: %s is not a block device"), spec);
+ break;
+ case ENXIO:
+ if (opt_nofail)
+ goto out;
+ error (_("mount: %s is not a valid block device"), spec); break;
+ case EACCES: /* pre-linux 1.1.38, 1.1.41 and later */
+ case EROFS: /* linux 1.1.38 and later */
+ { char *bd = (loop ? "" : _("block device "));
+ if (ro || (flags & MS_RDONLY)) {
+ error (_("mount: cannot mount %s%s read-only"),
+ bd, spec);
+ break;
+ } else if (readwrite) {
+ error (_("mount: %s%s is write-protected but explicit `-w' flag given"),
+ bd, spec);
+ break;
+ } else if (flags & MS_REMOUNT) {
+ error (_("mount: cannot remount %s%s read-write, is write-protected"),
+ bd, spec);
+ break;
+ } else {
+ opts = opts0;
+ types = types0;
+
+ if (opts) {
+ char *opts2 = append_opt(xstrdup(opts), "ro", NULL);
+ my_free(opts1);
+ opts = opts1 = opts2;
+ } else
+ opts = "ro";
+ if (types && !strcmp(types, "guess"))
+ types = 0;
+ error (_("mount: %s%s is write-protected, mounting read-only"),
+ bd, spec0);
+ res = try_mount_one (spec0, node0, types, opts, freq, pass, 1);
+ goto out;
+ }
+ break;
+ }
+ case ENOMEDIUM:
+ error(_("mount: no medium found on %s"), spec);
+ break;
+ default:
+ error ("mount: %s", strerror (mnt_err)); break;
+ }
+ }
+ res = EX_FAIL;
+
+ out:
+
+#if defined(HAVE_LIBSELINUX) && defined(HAVE_SECURITY_GET_INITIAL_CONTEXT)
+ if (res != EX_FAIL && verbose && is_selinux_enabled() > 0) {
+ security_context_t raw = NULL, def = NULL;
+
+ if (getfilecon(node, &raw) > 0 &&
+ security_get_initial_context("file", &def) == 0) {
+
+ if (!selinux_file_context_cmp(raw, def))
+ printf(_("mount: %s does not contain SELinux labels.\n"
+ " You just mounted an file system that supports labels which does not\n"
+ " contain labels, onto an SELinux box. It is likely that confined\n"
+ " applications will generate AVC messages and not be allowed access to\n"
+ " this file system. For more details see restorecon(8) and mount(8).\n"),
+ node);
+ }
+ freecon(raw);
+ freecon(def);
+ }
+#endif
+
+ my_free(mount_opts);
+ my_free(extra_opts);
+ my_free(spec1);
+ my_free(node1);
+ my_free(opts1);
+ my_free(types1);
+
+ return res;
+}
+
+static char *
+subst_string(const char *s, const char *sub, int sublen, const char *repl) {
+ char *n;
+
+ n = (char *) xmalloc(strlen(s)-sublen+strlen(repl)+1);
+ strncpy (n, s, sub-s);
+ strcpy (n + (sub-s), repl);
+ strcat (n, sub+sublen);
+ return n;
+}
+
+static char *
+usersubst(const char *opts) {
+ char *s, *w;
+ char id[40];
+
+ if (!opts)
+ return NULL;
+
+ s = "uid=useruid";
+ if (opts && (w = strstr(opts, s)) != NULL) {
+ sprintf(id, "uid=%u", getuid());
+ opts = subst_string(opts, w, strlen(s), id);
+ }
+ s = "gid=usergid";
+ if (opts && (w = strstr(opts, s)) != NULL) {
+ sprintf(id, "gid=%u", getgid());
+ opts = subst_string(opts, w, strlen(s), id);
+ }
+ return xstrdup(opts);
+}
+
+static int
+is_existing_file (const char *s) {
+ struct stat statbuf;
+
+ return (stat(s, &statbuf) == 0);
+}
+
+/*
+ * Return 0 for success (either mounted sth or -a and NOAUTO was given)
+ */
+static int
+mount_one (const char *spec, const char *node, const char *types,
+ const char *fstabopts, char *cmdlineopts, int freq, int pass) {
+ const char *nspec = NULL;
+ char *opts;
+
+ /* Substitute values in opts, if required */
+ opts = usersubst(fstabopts);
+
+ /* Merge the fstab and command line options. */
+ opts = append_opt(opts, cmdlineopts, NULL);
+
+ if (types == NULL && !mounttype && !is_existing_file(spec)) {
+ if (strchr (spec, ':') != NULL) {
+ types = "nfs";
+ if (verbose)
+ printf(_("mount: no type was given - "
+ "I'll assume nfs because of "
+ "the colon\n"));
+ } else if(!strncmp(spec, "//", 2)) {
+ types = "cifs";
+ if (verbose)
+ printf(_("mount: no type was given - "
+ "I'll assume cifs because of "
+ "the // prefix\n"));
+ }
+ }
+
+ /* Handle possible LABEL= and UUID= forms of spec */
+ if (types == NULL || (strncmp(types, "9p", 2) &&
+ strncmp(types, "nfs", 3) &&
+ strncmp(types, "cifs", 4) &&
+ strncmp(types, "smbfs", 5))) {
+ if (!is_pseudo_fs(types))
+ nspec = spec_to_devname(spec);
+ if (nspec)
+ spec = nspec;
+ }
+
+ return try_mount_one (spec, node, types, opts, freq, pass, 0);
+}
+
+#ifdef HAVE_LIBMOUNT_MOUNT
+static struct libmnt_table *minfo; /* parsed mountinfo file */
+
+/* Check if an fsname/dir pair was already in the old mtab. */
+static int
+mounted (const char *spec0, const char *node0, struct mntentchn *fstab_mc) {
+#else
+static int
+mounted (const char *spec0, const char *node0,
+ struct mntentchn *fstab_mc __attribute__((__unused__))) {
+#endif
+ struct mntentchn *mc, *mc0;
+ const char *spec, *node;
+ int ret = 0;
+
+#ifdef HAVE_LIBMOUNT_MOUNT
+ /*
+ * Use libmount to check for already mounted bind mounts on systems
+ * without mtab.
+ */
+ if (fstab_mc && fstab_mc->m.mnt_opts &&
+ mtab_is_a_symlink() && strstr(fstab_mc->m.mnt_opts, "bind")) {
+
+ struct libmnt_fs *fs = mnt_new_fs();
+ int rc = fs ? 0 : -1;
+
+ if (!rc)
+ rc = mnt_fs_set_fstype(fs, fstab_mc->m.mnt_type);
+ if (!rc)
+ rc = mnt_fs_set_source(fs, fstab_mc->m.mnt_fsname);
+ if (!rc)
+ rc = mnt_fs_set_target(fs, fstab_mc->m.mnt_dir);
+ if (!rc)
+ rc = mnt_fs_set_options(fs, fstab_mc->m.mnt_opts);
+ if (!rc && !minfo)
+ minfo = mnt_new_table_from_file("/proc/self/mountinfo");
+ if (!rc && minfo)
+ rc = mnt_table_is_fs_mounted(minfo, fs);
+
+ mnt_free_fs(fs);
+ if (rc == 1)
+ return 1;
+ }
+#endif
+ /* Handle possible UUID= and LABEL= in spec */
+ spec = spec_to_devname(spec0);
+ if (!spec)
+ return ret;
+
+ node = canonicalize(node0);
+
+
+ mc0 = mtab_head();
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
+ if (streq (spec, mc->m.mnt_fsname) &&
+ streq (node, mc->m.mnt_dir)) {
+ ret = 1;
+ break;
+ }
+
+ my_free(spec);
+ my_free(node);
+
+ return ret;
+}
+
+/* returns 0 if not mounted, 1 if mounted and -1 in case of error */
+static int
+is_fstab_entry_mounted(struct mntentchn *mc, int verbose)
+{
+ struct stat st;
+
+ if (mounted(mc->m.mnt_fsname, mc->m.mnt_dir, mc))
+ goto yes;
+
+ /* extra care for loop devices */
+ if ((mc->m.mnt_opts && strstr(mc->m.mnt_opts, "loop=")) ||
+ (stat(mc->m.mnt_fsname, &st) == 0 && S_ISREG(st.st_mode))) {
+
+ char *p = get_option_value(mc->m.mnt_opts, "offset=");
+ uintmax_t offset = 0;
+
+ if (p && strtosize(p, &offset) != 0) {
+ if (verbose)
+ printf(_("mount: ignore %s "
+ "(unparsable offset= option)\n"),
+ mc->m.mnt_fsname);
+ return -1;
+ }
+ free(p);
+ if (is_mounted_same_loopfile(mc->m.mnt_dir, mc->m.mnt_fsname, offset))
+ goto yes;
+ }
+
+ return 0;
+yes:
+ if (verbose)
+ printf(_("mount: %s already mounted on %s\n"),
+ mc->m.mnt_fsname, mc->m.mnt_dir);
+ return 1;
+}
+
+/* avoid using stat() on things we are not going to mount anyway.. */
+static int
+has_noauto (const char *opts) {
+ char *s;
+
+ if (!opts)
+ return 0;
+ s = strstr(opts, "noauto");
+ if (!s)
+ return 0;
+ return (s == opts || s[-1] == ',') && (s[6] == 0 || s[6] == ',');
+}
+
+/* Mount all filesystems of the specified types except swap and root. */
+/* With the --fork option: fork and let different incarnations of
+ mount handle different filesystems. However, try to avoid several
+ simultaneous mounts on the same physical disk, since that is very slow. */
+#define DISKMAJOR(m) (((int) m) & ~0xf)
+
+static int
+do_mount_all (char *types, char *options, char *test_opts) {
+ struct mntentchn *mc, *mc0, *mtmp;
+ int status = 0;
+ struct stat statbuf;
+ struct child {
+ pid_t pid;
+ char *group;
+ struct mntentchn *mec;
+ struct mntentchn *meclast;
+ struct child *nxt;
+ } childhead, *childtail, *cp;
+ char major[22];
+ char *g, *colon;
+
+ /* build a chain of what we have to do, or maybe
+ several chains, one for each major or NFS host */
+ childhead.nxt = 0;
+ childtail = &childhead;
+ mc0 = fstab_head();
+ for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
+ if (has_noauto (mc->m.mnt_opts))
+ continue;
+ if (matching_type (mc->m.mnt_type, types)
+ && matching_opts (mc->m.mnt_opts, test_opts)
+ && !streq (mc->m.mnt_dir, "/")
+ && !streq (mc->m.mnt_dir, "root")
+ && !is_fstab_entry_mounted(mc, verbose)) {
+
+ mtmp = (struct mntentchn *) xmalloc(sizeof(*mtmp));
+ *mtmp = *mc;
+ mtmp->nxt = 0;
+ g = NULL;
+ if (optfork) {
+ if (stat(mc->m.mnt_fsname, &statbuf) == 0 &&
+ S_ISBLK(statbuf.st_mode)) {
+ sprintf(major, "#%x",
+ DISKMAJOR(statbuf.st_rdev));
+ g = major;
+ }
+ if (strcmp(mc->m.mnt_type, "nfs") == 0) {
+ g = xstrdup(mc->m.mnt_fsname);
+ colon = strchr(g, ':');
+ if (colon)
+ *colon = '\0';
+ }
+ }
+ if (g) {
+ for (cp = childhead.nxt; cp; cp = cp->nxt)
+ if (cp->group &&
+ strcmp(cp->group, g) == 0) {
+ cp->meclast->nxt = mtmp;
+ cp->meclast = mtmp;
+ goto fnd;
+ }
+ }
+ cp = (struct child *) xmalloc(sizeof *cp);
+ cp->nxt = 0;
+ cp->mec = cp->meclast = mtmp;
+ cp->group = xstrdup(g);
+ cp->pid = 0;
+ childtail->nxt = cp;
+ childtail = cp;
+ fnd:;
+
+ }
+ }
+
+ /* now do everything */
+ for (cp = childhead.nxt; cp; cp = cp->nxt) {
+ pid_t p = -1;
+ if (optfork) {
+ p = fork();
+ if (p == -1) {
+ int errsv = errno;
+ error(_("mount: cannot fork: %s"),
+ strerror (errsv));
+ }
+ else if (p != 0)
+ cp->pid = p;
+ }
+
+ /* if child, or not forked, do the mounting */
+ if (p == 0 || p == -1) {
+ for (mc = cp->mec; mc; mc = mc->nxt) {
+ status |= mount_one (mc->m.mnt_fsname,
+ mc->m.mnt_dir,
+ mc->m.mnt_type,
+ mc->m.mnt_opts,
+ options, 0, 0);
+ }
+ if (mountcount)
+ status |= EX_SOMEOK;
+ if (p == 0)
+ exit(status);
+ }
+ }
+
+ /* wait for children, if any */
+ while ((cp = childhead.nxt) != NULL) {
+ childhead.nxt = cp->nxt;
+ if (cp->pid) {
+ int ret;
+ keep_waiting:
+ if(waitpid(cp->pid, &ret, 0) == -1) {
+ if (errno == EINTR)
+ goto keep_waiting;
+ perror("waitpid");
+ } else if (WIFEXITED(ret))
+ status |= WEXITSTATUS(ret);
+ else
+ status |= EX_SYSERR;
+ }
+ }
+ if (mountcount)
+ status |= EX_SOMEOK;
+ return status;
+}
+
+static struct option longopts[] = {
+ { "all", 0, 0, 'a' },
+ { "fake", 0, 0, 'f' },
+ { "fork", 0, 0, 'F' },
+ { "help", 0, 0, 'h' },
+ { "no-mtab", 0, 0, 'n' },
+ { "read-only", 0, 0, 'r' },
+ { "ro", 0, 0, 'r' },
+ { "verbose", 0, 0, 'v' },
+ { "version", 0, 0, 'V' },
+ { "read-write", 0, 0, 'w' },
+ { "rw", 0, 0, 'w' },
+ { "options", 1, 0, 'o' },
+ { "test-opts", 1, 0, 'O' },
+ { "pass-fd", 1, 0, 'p' },
+ { "types", 1, 0, 't' },
+ { "bind", 0, 0, 'B' },
+ { "move", 0, 0, 'M' },
+ { "guess-fstype", 1, 0, 134 },
+ { "rbind", 0, 0, 'R' },
+ { "make-shared", 0, 0, 136 },
+ { "make-slave", 0, 0, 137 },
+ { "make-private", 0, 0, 138 },
+ { "make-unbindable", 0, 0, 139 },
+ { "make-rshared", 0, 0, 140 },
+ { "make-rslave", 0, 0, 141 },
+ { "make-rprivate", 0, 0, 142 },
+ { "make-runbindable", 0, 0, 143 },
+ { "no-canonicalize", 0, 0, 144 },
+ { "internal-only", 0, 0, 'i' },
+ { NULL, 0, 0, 0 }
+};
+
+/* Keep the usage message at max 22 lines, each at most 70 chars long.
+ The user should not need a pager to read it. */
+static void
+usage (FILE *fp, int n) {
+ fprintf(fp, _(
+ "Usage: mount -V : print version\n"
+ " mount -h : print this help\n"
+ " mount : list mounted filesystems\n"
+ " mount -l : idem, including volume labels\n"
+ "So far the informational part. Next the mounting.\n"
+ "The command is `mount [-t fstype] something somewhere'.\n"
+ "Details found in /etc/fstab may be omitted.\n"
+ " mount -a [-t|-O] ... : mount all stuff from /etc/fstab\n"
+ " mount device : mount device at the known place\n"
+ " mount directory : mount known device here\n"
+ " mount -t type dev dir : ordinary mount command\n"
+ "Note that one does not really mount a device, one mounts\n"
+ "a filesystem (of the given type) found on the device.\n"
+ "One can also mount an already visible directory tree elsewhere:\n"
+ " mount --bind olddir newdir\n"
+ "or move a subtree:\n"
+ " mount --move olddir newdir\n"
+ "One can change the type of mount containing the directory dir:\n"
+ " mount --make-shared dir\n"
+ " mount --make-slave dir\n"
+ " mount --make-private dir\n"
+ " mount --make-unbindable dir\n"
+ "One can change the type of all the mounts in a mount subtree\n"
+ "containing the directory dir:\n"
+ " mount --make-rshared dir\n"
+ " mount --make-rslave dir\n"
+ " mount --make-rprivate dir\n"
+ " mount --make-runbindable dir\n"
+ "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n"
+ "or by label, using -L label or by uuid, using -U uuid .\n"
+ "Other options: [-nfFrsvw] [-o options] [-p passwdfd].\n"
+ "For many more details, say man 8 mount .\n"
+ ));
+
+ unlock_mtab();
+ exit (n);
+}
+
+/* returns mount entry from fstab */
+static struct mntentchn *
+getfs(const char *spec, const char *uuid, const char *label)
+{
+ struct mntentchn *mc = NULL;
+ const char *devname = NULL;
+
+ if (!spec && !uuid && !label)
+ return NULL;
+
+ /*
+ * A) 99% of all cases, the spec on cmdline matches
+ * with spec in fstab
+ */
+ if (uuid)
+ mc = getfs_by_uuid(uuid);
+ else if (label)
+ mc = getfs_by_label(label);
+ else {
+ mc = getfs_by_dir(spec);
+
+ if (!mc)
+ mc = getfs_by_spec(spec);
+ }
+ if (mc)
+ return mc;
+
+ /*
+ * B) UUID or LABEL on cmdline, but devname in fstab
+ */
+ if (uuid)
+ devname = fsprobe_get_devname_by_uuid(uuid);
+ else if (label)
+ devname = fsprobe_get_devname_by_label(label);
+ else
+ devname = spec_to_devname(spec);
+
+ if (devname)
+ mc = getfs_by_devname(devname);
+
+ /*
+ * C) mixed
+ */
+ if (!mc && devname) {
+ const char *id = NULL;
+
+ if (!label && (!spec || strncmp(spec, "LABEL=", 6))) {
+ id = fsprobe_get_label_by_devname(devname);
+ if (id)
+ mc = getfs_by_label(id);
+ }
+ if (!mc && !uuid && (!spec || strncmp(spec, "UUID=", 5))) {
+ id = fsprobe_get_uuid_by_devname(devname);
+ if (id)
+ mc = getfs_by_uuid(id);
+ }
+ my_free(id);
+
+ if (mc) {
+ /* use real device name to avoid repetitional
+ * conversion from LABEL/UUID to devname
+ */
+ my_free(mc->m.mnt_fsname);
+ mc->m.mnt_fsname = xstrdup(devname);
+ }
+ }
+
+ /*
+ * D) remount -- try /etc/mtab
+ * Earlier mtab was tried first, but this would sometimes try the
+ * wrong mount in case mtab had the root device entry wrong. Try
+ * the last occurrence first, since that is the visible mount.
+ */
+ if (!mc && (devname || spec))
+ mc = getmntfilebackward (devname ? devname : spec, NULL);
+
+ my_free(devname);
+ return mc;
+}
+
+
+static void
+print_version(int rc) {
+ printf( "mount from %s (with "
+#ifdef HAVE_LIBBLKID
+ "libblkid"
+#else
+ "libvolume_id"
+#endif
+#ifdef HAVE_LIBSELINUX
+ " and selinux"
+#endif
+ " support)\n", PACKAGE_STRING);
+ exit(rc);
+}
+
+int
+main(int argc, char *argv[]) {
+ int c, result = 0, specseen;
+ char *options = NULL, *test_opts = NULL, *node;
+ const char *spec = NULL;
+ char *label = NULL;
+ char *uuid = NULL;
+ char *types = NULL;
+ char *p;
+ struct mntentchn *mc;
+ int fd;
+
+ sanitize_env();
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+ atexit(close_stdout);
+
+ progname = argv[0];
+ if ((p = strrchr(progname, '/')) != NULL)
+ progname = p+1;
+
+ umask(022);
+
+ /* People report that a mount called from init without console
+ writes error messages to /etc/mtab
+ Let us try to avoid getting fd's 0,1,2 */
+ while((fd = open("/dev/null", O_RDWR)) == 0 || fd == 1 || fd == 2) ;
+ if (fd > 2)
+ close(fd);
+
+ fsprobe_init();
+
+#ifdef DO_PS_FIDDLING
+ initproctitle(argc, argv);
+#endif
+
+ while ((c = getopt_long (argc, argv, "aBfFhilL:Mno:O:p:rRsU:vVwt:",
+ longopts, NULL)) != -1) {
+ switch (c) {
+ case 'a': /* mount everything in fstab */
+ ++mount_all;
+ break;
+ case 'B': /* bind */
+ mounttype = MS_BIND;
+ break;
+ case 'f': /* fake: don't actually call mount(2) */
+ ++fake;
+ break;
+ case 'F':
+ ++optfork;
+ break;
+ case 'h': /* help */
+ usage (stdout, 0);
+ break;
+ case 'i':
+ external_allowed = 0;
+ break;
+ case 'l':
+ list_with_volumelabel = 1;
+ break;
+ case 'L':
+ label = optarg;
+ break;
+ case 'M': /* move */
+ mounttype = MS_MOVE;
+ break;
+ case 'n': /* do not write /etc/mtab */
+ ++nomtab;
+ break;
+ case 'o': /* specify mount options */
+ options = append_opt(options, optarg, NULL);
+ break;
+ case 'O': /* with -t: mount only if (not) opt */
+ test_opts = append_opt(test_opts, optarg, NULL);
+ break;
+ case 'p': /* fd on which to read passwd */
+ set_pfd(optarg);
+ break;
+ case 'r': /* mount readonly */
+ readonly = 1;
+ readwrite = 0;
+ break;
+ case 'R': /* rbind */
+ mounttype = (MS_BIND | MS_REC);
+ break;
+ case 's': /* allow sloppy mount options */
+ sloppy = 1;
+ break;
+ case 't': /* specify file system types */
+ types = optarg;
+ break;
+ case 'U':
+ uuid = optarg;
+ break;
+ case 'v': /* be chatty - more so if repeated */
+ ++verbose;
+ break;
+ case 'V': /* version */
+ print_version(EXIT_SUCCESS);
+ break;
+ case 'w': /* mount read/write */
+ readwrite = 1;
+ readonly = 0;
+ break;
+ case 0:
+ break;
+
+ case 134:
+ /* undocumented, may go away again:
+ call: mount --guess-fstype device
+ use only for testing purposes -
+ the guessing is not reliable at all */
+ {
+ const char *fstype;
+ fstype = fsprobe_get_fstype_by_devname(optarg);
+ printf("%s\n", fstype ? fstype : "unknown");
+ exit(fstype ? 0 : EX_FAIL);
+ }
+
+ case 136:
+ mounttype = MS_SHARED;
+ break;
+
+ case 137:
+ mounttype = MS_SLAVE;
+ break;
+
+ case 138:
+ mounttype = MS_PRIVATE;
+ break;
+
+ case 139:
+ mounttype = MS_UNBINDABLE;
+ break;
+
+ case 140:
+ mounttype = (MS_SHARED | MS_REC);
+ break;
+
+ case 141:
+ mounttype = (MS_SLAVE | MS_REC);
+ break;
+
+ case 142:
+ mounttype = (MS_PRIVATE | MS_REC);
+ break;
+
+ case 143:
+ mounttype = (MS_UNBINDABLE | MS_REC);
+ break;
+ case 144:
+ nocanonicalize = 1;
+ break;
+ case '?':
+ default:
+ usage (stderr, EX_USAGE);
+ }
+ }
+
+ if (verbose > 2) {
+ printf("mount: fstab path: \"%s\"\n", _PATH_MNTTAB);
+ printf("mount: mtab path: \"%s\"\n", _PATH_MOUNTED);
+ printf("mount: lock path: \"%s\"\n", _PATH_MOUNTED_LOCK);
+ printf("mount: temp path: \"%s\"\n", _PATH_MOUNTED_TMP);
+ printf("mount: UID: %u\n", getuid());
+ printf("mount: eUID: %u\n", geteuid());
+ }
+
+#ifdef HAVE_LIBMOUNT_MOUNT
+ mnt_init_debug(0);
+#endif
+ argc -= optind;
+ argv += optind;
+
+ specseen = (uuid || label) ? 1 : 0; /* yes, .. i know */
+
+ if (argc+specseen == 0 && !mount_all) {
+ if (options || mounttype)
+ usage (stderr, EX_USAGE);
+ return print_all (types);
+ }
+
+ {
+ const uid_t ruid = getuid();
+ const uid_t euid = geteuid();
+
+ /* if we're really root and aren't running setuid */
+ if (((uid_t)0 == ruid) && (ruid == euid)) {
+ restricted = 0;
+ }
+
+ if (restricted &&
+ (types || options || readwrite || nomtab || mount_all ||
+ nocanonicalize || fake || mounttype ||
+ (argc + specseen) != 1)) {
+
+ if (ruid == 0 && euid != 0)
+ /* user is root, but setuid to non-root */
+ die (EX_USAGE, _("mount: only root can do that "
+ "(effective UID is %u)"), euid);
+
+ die (EX_USAGE, _("mount: only root can do that"));
+ }
+ }
+
+ atexit(unlock_mtab);
+
+ switch (argc+specseen) {
+ case 0:
+ /* mount -a */
+ result = do_mount_all (types, options, test_opts);
+ if (result == 0 && verbose && !fake)
+ error(_("nothing was mounted"));
+ break;
+
+ case 1:
+ /* mount [-nfrvw] [-o options] special | node
+ * mount -L label (or -U uuid)
+ * (/etc/fstab is necessary)
+ */
+ if (types != NULL)
+ usage (stderr, EX_USAGE);
+
+ if (uuid || label)
+ mc = getfs(NULL, uuid, label);
+ else
+ mc = getfs(*argv, NULL, NULL);
+
+ if (!mc) {
+ if (uuid || label)
+ die (EX_USAGE, _("mount: no such partition found"));
+
+ die (EX_USAGE,
+ _("mount: can't find %s in %s or %s"),
+ *argv, _PATH_MNTTAB, _PATH_MOUNTED);
+ }
+
+ result = mount_one (xstrdup (mc->m.mnt_fsname),
+ xstrdup (mc->m.mnt_dir),
+ xstrdup (mc->m.mnt_type),
+ mc->m.mnt_opts, options, 0, 0);
+ break;
+
+ case 2:
+ /* mount special node (/etc/fstab is not necessary) */
+ if (specseen) {
+ /* mount -L label node (or -U uuid) */
+ spec = uuid ? fsprobe_get_devname_by_uuid(uuid) :
+ fsprobe_get_devname_by_label(label);
+ node = argv[0];
+ } else {
+ /* mount special node */
+ spec = argv[0];
+ node = argv[1];
+ }
+ if (!spec)
+ die (EX_USAGE, _("mount: no such partition found"));
+
+ result = mount_one (spec, node, types, NULL, options, 0, 0);
+ break;
+
+ default:
+ usage (stderr, EX_USAGE);
+ }
+
+ if (result == EX_SOMEOK)
+ result = 0;
+
+ fsprobe_exit();
+
+ exit (result);
+}
diff --git a/mount-deprecated/mount_constants.h b/mount-deprecated/mount_constants.h
new file mode 100644
index 000000000..ce51887dd
--- /dev/null
+++ b/mount-deprecated/mount_constants.h
@@ -0,0 +1,73 @@
+#ifndef MS_RDONLY
+#define MS_RDONLY 1 /* Mount read-only */
+#endif
+#ifndef MS_NOSUID
+#define MS_NOSUID 2 /* Ignore suid and sgid bits */
+#endif
+#ifndef MS_NODEV
+#define MS_NODEV 4 /* Disallow access to device special files */
+#endif
+#ifndef MS_NOEXEC
+#define MS_NOEXEC 8 /* Disallow program execution */
+#endif
+#ifndef MS_SYNCHRONOUS
+#define MS_SYNCHRONOUS 16 /* Writes are synced at once */
+#endif
+#ifndef MS_REMOUNT
+#define MS_REMOUNT 32 /* Alter flags of a mounted FS */
+#endif
+#ifndef MS_MANDLOCK
+#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
+#endif
+#ifndef MS_DIRSYNC
+#define MS_DIRSYNC 128 /* Directory modifications are synchronous */
+#endif
+#ifndef MS_NOATIME
+#define MS_NOATIME 0x400 /* 1024: Do not update access times. */
+#endif
+#ifndef MS_NODIRATIME
+#define MS_NODIRATIME 0x800 /* 2048: Don't update directory access times */
+#endif
+#ifndef MS_BIND
+#define MS_BIND 0x1000 /* 4096: Mount existing tree also elsewhere */
+#endif
+#ifndef MS_MOVE
+#define MS_MOVE 0x2000 /* 8192: Atomically move tree */
+#endif
+#ifndef MS_REC
+#define MS_REC 0x4000 /* 16384: Recursive loopback */
+#endif
+#ifndef MS_SILENT
+#define MS_SILENT 0x8000 /* 32768 (was MS_VERBOSE) */
+#endif
+#ifndef MS_RELATIME
+#define MS_RELATIME 0x200000 /* 200000: Update access times relative
+ to mtime/ctime */
+#endif
+#ifndef MS_UNBINDABLE
+#define MS_UNBINDABLE (1<<17) /* 131072 unbindable*/
+#endif
+#ifndef MS_PRIVATE
+#define MS_PRIVATE (1<<18) /* 262144 Private*/
+#endif
+#ifndef MS_SLAVE
+#define MS_SLAVE (1<<19) /* 524288 Slave*/
+#endif
+#ifndef MS_SHARED
+#define MS_SHARED (1<<20) /* 1048576 Shared*/
+#endif
+#ifndef MS_I_VERSION
+#define MS_I_VERSION (1<<23) /* update inode I_version field */
+#endif
+#ifndef MS_STRICTATIME
+#define MS_STRICTATIME (1<<24) /* strict atime semantics */
+#endif
+/*
+ * Magic mount flag number. Had to be or-ed to the flag values.
+ */
+#ifndef MS_MGC_VAL
+#define MS_MGC_VAL 0xC0ED0000 /* magic flag number to indicate "new" flags */
+#endif
+#ifndef MS_MGC_MSK
+#define MS_MGC_MSK 0xffff0000 /* magic flag number mask */
+#endif
diff --git a/mount-deprecated/mount_mntent.c b/mount-deprecated/mount_mntent.c
new file mode 100644
index 000000000..88dab1025
--- /dev/null
+++ b/mount-deprecated/mount_mntent.c
@@ -0,0 +1,165 @@
+/* Private version of the libc *mntent() routines. */
+/* Note slightly different prototypes. */
+
+/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ */
+
+#include <stdio.h>
+#include <string.h> /* for index */
+#include <ctype.h> /* for isdigit */
+#include <sys/stat.h> /* for umask */
+
+#include "mount_mntent.h"
+#include "sundries.h" /* for xmalloc */
+#include "nls.h"
+#include "mangle.h"
+#include "closestream.h"
+
+static int
+is_space_or_tab (char c) {
+ return (c == ' ' || c == '\t');
+}
+
+static char *
+skip_spaces(char *s) {
+ while (is_space_or_tab(*s))
+ s++;
+ return s;
+}
+
+/*
+ * fstat'ing the file and allocating a buffer holding all of it
+ * may be a bad idea: if the file is /proc/mounts, the stat
+ * returns 0.
+ * (On the other hand, mangling and unmangling is meaningless
+ * for /proc/mounts.)
+ */
+
+mntFILE *
+my_setmntent (const char *file, char *mode) {
+ mntFILE *mfp = xmalloc(sizeof(*mfp));
+ mode_t old_umask = umask(077);
+
+ mfp->mntent_fp = fopen(file, mode);
+ umask(old_umask);
+ mfp->mntent_file = xstrdup(file);
+ mfp->mntent_errs = (mfp->mntent_fp == NULL);
+ mfp->mntent_softerrs = 0;
+ mfp->mntent_lineno = 0;
+ return mfp;
+}
+
+void
+my_endmntent(mntFILE * mfp) {
+ if (mfp) {
+ if (mfp->mntent_fp)
+ if (close_stream(mfp->mntent_fp))
+ fprintf(stderr, _("write error"));
+ free(mfp->mntent_file);
+ free(mfp);
+ }
+}
+
+int
+my_addmntent (mntFILE *mfp, struct my_mntent *mnt) {
+ char *m1, *m2, *m3, *m4;
+ int res;
+
+ if (fseek (mfp->mntent_fp, 0, SEEK_END))
+ return 1; /* failure */
+
+ m1 = mangle(mnt->mnt_fsname);
+ m2 = mangle(mnt->mnt_dir);
+ m3 = mangle(mnt->mnt_type);
+ m4 = mnt->mnt_opts ? mangle(mnt->mnt_opts) : "rw";
+
+ res = fprintf (mfp->mntent_fp, "%s %s %s %s %d %d\n",
+ m1, m2, m3, m4, mnt->mnt_freq, mnt->mnt_passno);
+
+ free(m1);
+ free(m2);
+ free(m3);
+ if (mnt->mnt_opts)
+ free(m4);
+ return (res < 0) ? 1 : 0;
+}
+
+/* Read the next entry from the file fp. Stop reading at an incorrect entry. */
+struct my_mntent *
+my_getmntent (mntFILE *mfp) {
+ static char buf[4096];
+ static struct my_mntent me;
+ char *s;
+
+ again:
+ if (mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX)
+ return NULL;
+
+ /* read the next non-blank non-comment line */
+ do {
+ if (fgets (buf, sizeof(buf), mfp->mntent_fp) == NULL)
+ return NULL;
+
+ mfp->mntent_lineno++;
+ s = strchr (buf, '\n');
+ if (s == NULL) {
+ /* Missing final newline? Otherwise extremely */
+ /* long line - assume file was corrupted */
+ if (feof(mfp->mntent_fp)) {
+ fprintf(stderr, _("[mntent]: warning: no final "
+ "newline at the end of %s\n"),
+ mfp->mntent_file);
+ s = strchr (buf, 0);
+ } else {
+ mfp->mntent_errs = 1;
+ goto err;
+ }
+ }
+ *s = 0;
+ if (--s >= buf && *s == '\r')
+ *s = 0;
+ s = skip_spaces(buf);
+ } while (*s == '\0' || *s == '#');
+
+ me.mnt_fsname = unmangle(s, &s);
+ s = skip_spaces(s);
+ me.mnt_dir = unmangle(s, &s);
+ s = skip_spaces(s);
+ me.mnt_type = unmangle(s, &s);
+ s = skip_spaces(s);
+ me.mnt_opts = unmangle(s, &s);
+ s = skip_spaces(s);
+
+ if (!me.mnt_fsname || !me.mnt_dir || !me.mnt_type)
+ goto err;
+
+ if (isdigit(*s)) {
+ me.mnt_freq = atoi(s);
+ while(isdigit(*s)) s++;
+ } else
+ me.mnt_freq = 0;
+ if(*s && !is_space_or_tab(*s))
+ goto err;
+
+ s = skip_spaces(s);
+ if(isdigit(*s)) {
+ me.mnt_passno = atoi(s);
+ while(isdigit(*s)) s++;
+ } else
+ me.mnt_passno = 0;
+ if(*s && !is_space_or_tab(*s))
+ goto err;
+
+ /* allow more stuff, e.g. comments, on this line */
+
+ return &me;
+
+ err:
+ mfp->mntent_softerrs++;
+ fprintf(stderr, _("[mntent]: line %d in %s is bad%s\n"),
+ mfp->mntent_lineno, mfp->mntent_file,
+ (mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX) ?
+ _("; rest of file ignored") : "");
+ goto again;
+}
diff --git a/mount-deprecated/mount_mntent.h b/mount-deprecated/mount_mntent.h
new file mode 100644
index 000000000..3b7421535
--- /dev/null
+++ b/mount-deprecated/mount_mntent.h
@@ -0,0 +1,28 @@
+#ifndef MOUNT_MNTENT_H
+#define MOUNT_MNTENT_H
+
+struct my_mntent {
+ const char *mnt_fsname;
+ const char *mnt_dir;
+ const char *mnt_type;
+ const char *mnt_opts;
+ int mnt_freq;
+ int mnt_passno;
+};
+
+#define ERR_MAX 5
+
+typedef struct mntFILEstruct {
+ FILE *mntent_fp;
+ char *mntent_file;
+ int mntent_lineno;
+ int mntent_errs;
+ int mntent_softerrs;
+} mntFILE;
+
+mntFILE *my_setmntent (const char *file, char *mode);
+void my_endmntent (mntFILE *mfp);
+int my_addmntent (mntFILE *mfp, struct my_mntent *mnt);
+struct my_mntent *my_getmntent (mntFILE *mfp);
+
+#endif /* MOUNT_MNTENT_H */
diff --git a/mount-deprecated/sundries.c b/mount-deprecated/sundries.c
new file mode 100644
index 000000000..9bff99753
--- /dev/null
+++ b/mount-deprecated/sundries.c
@@ -0,0 +1,300 @@
+/*
+ * Support functions. Exported functions are prototyped in sundries.h.
+ *
+ * added fcntl locking by Kjetil T. (kjetilho@math.uio.no) - aeb, 950927
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ *
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <mntent.h> /* for MNTTYPE_SWAP */
+
+#include "canonicalize.h"
+
+#include "sundries.h"
+#include "nls.h"
+
+int mount_quiet;
+int verbose;
+int nocanonicalize;
+char *progname;
+
+char *
+xstrndup (const char *s, int n) {
+ char *t;
+
+ if (s == NULL)
+ die (EX_SOFTWARE, _("bug in xstrndup call"));
+
+ t = xmalloc(n+1);
+ strncpy(t,s,n);
+ t[n] = 0;
+
+ return t;
+}
+
+/* reallocates its first arg - typical use: s = xstrconcat3(s,t,u); */
+char *
+xstrconcat3 (char *s, const char *t, const char *u) {
+ size_t len = 0;
+
+ len = (s ? strlen(s) : 0) + (t ? strlen(t) : 0) + (u ? strlen(u) : 0);
+
+ if (!len)
+ return NULL;
+ if (!s) {
+ s = xmalloc(len + 1);
+ *s = '\0';
+ }
+ else
+ s = xrealloc(s, len + 1);
+ if (t)
+ strcat(s, t);
+ if (u)
+ strcat(s, u);
+ return s;
+}
+
+/* frees its first arg - typical use: s = xstrconcat4(s,t,u,v); */
+char *
+xstrconcat4 (char *s, const char *t, const char *u, const char *v) {
+ size_t len = 0;
+
+ len = (s ? strlen(s) : 0) + (t ? strlen(t) : 0) +
+ (u ? strlen(u) : 0) + (v ? strlen(v) : 0);
+
+ if (!len)
+ return NULL;
+ if (!s) {
+ s = xmalloc(len + 1);
+ *s = '\0';
+ }
+ else
+ s = xrealloc(s, len + 1);
+ if (t)
+ strcat(s, t);
+ if (u)
+ strcat(s, u);
+ if (v)
+ strcat(s, v);
+ return s;
+
+
+}
+
+/* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock. */
+void
+block_signals (int how) {
+ sigset_t sigs;
+
+ sigfillset (&sigs);
+ sigdelset(&sigs, SIGTRAP);
+ sigdelset(&sigs, SIGSEGV);
+ sigprocmask (how, &sigs, (sigset_t *) 0);
+}
+
+
+/* Non-fatal error. Print message and return. */
+/* (print the message in a single printf, in an attempt
+ to avoid mixing output of several threads) */
+void
+error (const char *fmt, ...) {
+ va_list args;
+
+ if (mount_quiet)
+ return;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end (args);
+ fputc('\n', stderr);
+}
+
+/* Fatal error. Print message and exit. */
+void __attribute__ ((noreturn)) die(int err, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+
+ exit(err);
+}
+
+/* True if fstypes match. Null *TYPES means match anything,
+ except that swap types always return false. */
+/* Accept nonfs,proc,devpts and nonfs,noproc,nodevpts
+ with the same meaning. */
+int
+matching_type (const char *type, const char *types) {
+ int no; /* negated types list */
+ int len;
+ const char *p;
+
+ if (streq (type, MNTTYPE_SWAP))
+ return 0;
+ if (types == NULL)
+ return 1;
+
+ no = 0;
+ if (!strncmp(types, "no", 2)) {
+ no = 1;
+ types += 2;
+ }
+
+ /* Does type occur in types, separated by commas? */
+ len = strlen(type);
+ p = types;
+ while(1) {
+ if (!strncmp(p, "no", 2) && !strncmp(p+2, type, len) &&
+ (p[len+2] == 0 || p[len+2] == ','))
+ return 0;
+ if (strncmp(p, type, len) == 0 &&
+ (p[len] == 0 || p[len] == ','))
+ return !no;
+ p = strchr(p,',');
+ if (!p)
+ break;
+ p++;
+ }
+ return no;
+}
+
+/* Returns 1 if needle found or noneedle not found in haystack
+ * Otherwise returns 0
+ */
+static int
+check_option(const char *haystack, const char *needle) {
+ const char *p, *r;
+ int len, needle_len, this_len;
+ int no;
+
+ no = 0;
+ if (!strncmp(needle, "no", 2)) {
+ no = 1;
+ needle += 2;
+ }
+ needle_len = strlen(needle);
+ len = strlen(haystack);
+
+ for (p = haystack; p < haystack+len; p++) {
+ r = strchr(p, ',');
+ if (r) {
+ this_len = r-p;
+ } else {
+ this_len = strlen(p);
+ }
+ if (this_len != needle_len) {
+ p += this_len;
+ continue;
+ }
+ if (strncmp(p, needle, this_len) == 0)
+ return !no; /* foo or nofoo was found */
+ p += this_len;
+ }
+
+ return no; /* foo or nofoo was not found */
+}
+
+
+/* Returns 1 if each of the test_opts options agrees with the entire
+ * list of options.
+ * Returns 0 if any noopt is found in test_opts and opt is found in options.
+ * Returns 0 if any opt is found in test_opts but is not found in options.
+ * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
+ * DIFFERENT meanings; each option is matched explicitly as specified.
+ */
+int
+matching_opts (const char *options, const char *test_opts) {
+ const char *p, *r;
+ char *q;
+ int len, this_len;
+
+ if (test_opts == NULL)
+ return 1;
+ if (options == NULL)
+ options = "";
+
+ len = strlen(test_opts);
+ q = alloca(len+1);
+ if (q == NULL)
+ die (EX_SYSERR, _("not enough memory"));
+
+ for (p = test_opts; p < test_opts+len; p++) {
+ r = strchr(p, ',');
+ if (r) {
+ this_len = r-p;
+ } else {
+ this_len = strlen(p);
+ }
+ if (!this_len) continue; /* if two ',' appear in a row */
+ strncpy(q, p, this_len);
+ q[this_len] = '\0';
+ if (!check_option(options, q))
+ return 0; /* any match failure means failure */
+ p += this_len;
+ }
+
+ /* no match failures in list means success */
+ return 1;
+}
+
+int
+is_pseudo_fs(const char *type)
+{
+ if (type == NULL || *type == '/')
+ return 0;
+ if (streq(type, "none") ||
+ streq(type, "proc") ||
+ streq(type, "tmpfs") ||
+ streq(type, "sysfs") ||
+ streq(type, "usbfs") ||
+ streq(type, "cgroup") ||
+ streq(type, "cpuset") ||
+ streq(type, "rpc_pipefs") ||
+ streq(type, "devpts") ||
+ streq(type, "securityfs") ||
+ streq(type, "debugfs"))
+ return 1;
+ return 0;
+}
+
+/* Make a canonical pathname from PATH. Returns a freshly malloced string.
+ It is up the *caller* to ensure that the PATH is sensible. i.e.
+ canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
+ is not a legal pathname for ``/dev/fd0''. Anything we cannot parse
+ we return unmodified. */
+char *
+canonicalize_spec (const char *path)
+{
+ char *res;
+
+ if (!path)
+ return NULL;
+ if (nocanonicalize || is_pseudo_fs(path))
+ return xstrdup(path);
+
+ res = canonicalize_path(path);
+ if (!res)
+ die(EX_SYSERR, _("not enough memory"));
+ return res;
+}
+
+char *canonicalize (const char *path)
+{
+ char *res;
+
+ if (!path)
+ return NULL;
+ else if (nocanonicalize)
+ return xstrdup(path);
+
+ res = canonicalize_path(path);
+ if (!res)
+ die(EX_SYSERR, _("not enough memory"));
+ return res;
+}
diff --git a/mount-deprecated/sundries.h b/mount-deprecated/sundries.h
new file mode 100644
index 000000000..e58fa4975
--- /dev/null
+++ b/mount-deprecated/sundries.h
@@ -0,0 +1,55 @@
+/*
+ * sundries.h
+ * Support function prototypes. Functions are in sundries.c.
+ */
+#ifndef SUNDRIES_H
+#define SUNDRIES_H
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define XALLOC_EXIT_CODE 2 /* same as EX_SYSERR, for backwards compatibility */
+#include "xalloc.h"
+
+/* global mount, umount, and losetup variables */
+extern int mount_quiet;
+extern int verbose;
+extern int nocanonicalize;
+extern char *progname;
+
+#define streq(s, t) (strcmp ((s), (t)) == 0)
+#define my_free(_p) free((void *) _p)
+
+void block_signals (int how);
+
+void error (const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 1, 2)));
+void die(int err, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
+
+int matching_type (const char *type, const char *types);
+int matching_opts (const char *options, const char *test_opts);
+char *xstrndup (const char *s, int n);
+char *xstrconcat3 (char *, const char *, const char *);
+char *xstrconcat4 (char *, const char *, const char *, const char *);
+
+int is_pseudo_fs(const char *type);
+
+char *canonicalize (const char *path);
+char *canonicalize_spec (const char *path);
+
+/* exit status - bits below are ORed */
+#define EX_USAGE 1 /* incorrect invocation or permission */
+#define EX_SYSERR 2 /* out of memory, cannot fork, ... */
+#define EX_SOFTWARE 4 /* internal mount bug or wrong version */
+#define EX_USER 8 /* user interrupt */
+#define EX_FILEIO 16 /* problems writing, locking, ... mtab/fstab */
+#define EX_FAIL 32 /* mount failure */
+#define EX_SOMEOK 64 /* some mount succeeded */
+
+#endif /* SUNDRIES_H */
diff --git a/mount-deprecated/umount.8 b/mount-deprecated/umount.8
new file mode 100644
index 000000000..1c7d59aa7
--- /dev/null
+++ b/mount-deprecated/umount.8
@@ -0,0 +1,179 @@
+.\" Copyright (c) 1996 Andries Brouwer
+.\" This page is somewhat derived from a page that was
+.\" (c) 1980, 1989, 1991 The Regents of the University of California
+.\" and had been heavily modified by Rik Faith and myself.
+.\"
+.\" This is free documentation; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License as
+.\" published by the Free Software Foundation; either version 2 of
+.\" the License, or (at your option) any later version.
+.\"
+.\" The GNU General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License along
+.\" with this program; if not, write to the Free Software Foundation, Inc.,
+.\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+.\"
+.TH UMOUNT 8 "March 2010" "util-linux" "System Administration"
+.SH NAME
+umount \- unmount file systems
+.SH SYNOPSIS
+.B umount
+.RB [ \-hV ]
+.LP
+.B umount \-a
+.RB [ \-dflnrv ]
+.RB [ \-t
+.IR vfstype ]
+.RB [ \-O
+.IR options ]
+.br
+.B umount
+.RB [ \-dflnrv ]
+.RI { dir | device }...
+.SH DESCRIPTION
+The
+.B umount
+command detaches the file system(s) mentioned from the file hierarchy.
+A file system is specified by giving the directory where it
+has been mounted. Giving the special device on which the file system lives
+may also work, but is obsolete, mainly because it will fail
+in case this device was mounted on more than one directory.
+
+Note that a file system cannot be unmounted when it is `busy' -
+for example, when there are open files on it, or when some process
+has its working directory there, or when a swap file on it is in use.
+The offending process could even be
+.B umount
+itself - it opens libc, and libc in its turn may open for example
+locale files.
+A lazy unmount avoids this problem.
+
+Options for the
+.B umount
+command:
+.TP
+.B \-V
+Print version and exit.
+.TP
+.B \-h
+Print help message and exit.
+.TP
+.B \-v
+Verbose mode.
+.TP
+.B \-n
+Unmount without writing in
+.IR /etc/mtab .
+.TP
+.B \-r
+In case unmounting fails, try to remount read-only.
+.TP
+.B \-d
+In case the unmounted device was a loop device, also
+free this loop device.
+.TP
+.B \-i
+Don't call the /sbin/umount.<filesystem> helper even if it exists. By default /sbin/umount.<filesystem> helper is called if one exists.
+.TP
+.B \-a
+All of the file systems described in
+.I /etc/mtab
+are unmounted. (With
+.B umount
+version 2.7 and later: the
+.I proc
+filesystem is not unmounted.)
+.TP
+.BI \-t " vfstype"
+Indicate that the actions should only be taken on file systems of the
+specified type. More than one type may be specified in a comma separated
+list. The list of file system types can be prefixed with
+.B no
+to specify the file system types on which no action should be taken.
+.TP
+.BI \-O " options"
+Indicate that the actions should only be taken on file systems with
+the specified options in
+.IR /etc/fstab .
+More than one option type may be specified in a comma separated
+list. Each option can be prefixed with
+.B no
+to specify options for which no action should be taken.
+.TP
+.B \-f
+Force unmount (in case of an unreachable NFS system).
+(Requires kernel 2.1.116 or later.)
+.TP
+.B \-l
+Lazy unmount. Detach the filesystem from the filesystem hierarchy now,
+and cleanup all references to the filesystem as soon as it is not busy
+anymore.
+(Requires kernel 2.4.11 or later.)
+.IP "\fB\-\-no\-canonicalize\fP"
+Don't canonicalize paths. For more details about this option see the
+.B mount(8)
+man page.
+.IP "\fB\-\-fake\fP"
+Causes everything to be done except for the actual system call; this
+``fakes'' unmounting the filesystem. It can be used to remove
+entries from
+.I /etc/mtab
+that were unmounted earlier with the -n option.
+
+.SH "THE LOOP DEVICE"
+The
+.B umount
+command will free the loop device (if any) associated
+with the mount, in case it finds the option `loop=...' in
+.IR /etc/mtab ,
+or when the \-d option was given.
+Any pending loop devices can be freed using `losetup -d', see
+.BR losetup (8).
+
+.SH NOTES
+The syntax of external umount helpers is:
+
+.br
+.BI /sbin/umount. <suffix>
+.RI { dir | device }
+.RB [ \-nlfvr ]
+.RB [ \-t
+.IR type.subtype ]
+.br
+
+where the <suffix> is filesystem type or a value from "uhelper=" or "helper="
+mtab option. The \-t option is used for filesystems with subtypes support
+(for example /sbin/mount.fuse -t fuse.sshfs).
+
+The uhelper= (unprivileged umount helper) is possible to use when non-root user
+wants to umount a mountpoint which is not defined in the /etc/fstab file (e.g
+devices mounted by udisk).
+
+The helper= mount option redirects all umount requests to the
+/sbin/umount.<helper> independently on UID.
+
+.SH FILES
+.I /etc/mtab
+table of mounted file systems
+
+.SH "SEE ALSO"
+.BR umount (2),
+.BR mount (8),
+.BR losetup (8).
+
+.SH HISTORY
+A
+.B umount
+command appeared in Version 6 AT&T UNIX.
+.SH AVAILABILITY
+The umount command is part of the util-linux package and is available from
+ftp://ftp.kernel.org/pub/linux/utils/util-linux/.
diff --git a/mount-deprecated/umount.c b/mount-deprecated/umount.c
new file mode 100644
index 000000000..d3375df83
--- /dev/null
+++ b/mount-deprecated/umount.c
@@ -0,0 +1,878 @@
+/*
+ * umount(8) for Linux 0.99 - jrs, 1993
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+
+#include "mount_constants.h"
+#include "sundries.h"
+#include "getusername.h"
+#include "pathnames.h"
+#include "loopdev.h"
+#include "fstab.h"
+#include "env.h"
+#include "nls.h"
+#include "strutils.h"
+#include "closestream.h"
+
+#if defined(MNT_FORCE)
+/* Interesting ... it seems libc knows about MNT_FORCE and presumably
+ about umount2 as well -- need not do anything */
+#else /* MNT_FORCE */
+
+/* Does the present kernel source know about umount2? */
+#include <linux/unistd.h>
+#ifdef __NR_umount2
+
+static int umount2(const char *path, int flags);
+
+_syscall2(int, umount2, const char *, path, int, flags);
+
+#else /* __NR_umount2 */
+
+static int
+umount2(const char *path, int flags) {
+ fprintf(stderr, _("umount: compiled without support for -f\n"));
+ errno = ENOSYS;
+ return -1;
+}
+#endif /* __NR_umount2 */
+
+#ifndef MNT_FORCE
+# define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
+#endif
+
+#endif /* MNT_FORCE */
+
+#ifndef MNT_DETACH
+# define MNT_DETACH 0x00000002 /* Just detach from the tree */
+#endif
+
+#ifndef UMOUNT_NOFOLLOW
+# define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
+#endif
+
+#ifndef UMOUNT_UNUSED
+# define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
+#endif
+
+
+/* True if we are allowed to call /sbin/umount.${FSTYPE} */
+int external_allowed = 1;
+
+/* Nonzero for force umount (-f). There is kernel support since 2.1.116. */
+int force = 0;
+
+/* Nonzero for lazy umount (-l). There is kernel support since 2.4.11. */
+int lazy = 0;
+
+/* When umount fails, attempt a read-only remount (-r). */
+int remount = 0;
+
+/* Don't write a entry in /etc/mtab (-n). */
+int nomtab = 0;
+
+/* Call losetup -d for each unmounted loop device. */
+int delloop = 0;
+
+/* True if (ruid != euid) or (0 != ruid), i.e. only "user" umounts permitted. */
+int restricted = 1;
+
+/* Last error message */
+int complained_err = 0;
+char *complained_dev = NULL;
+
+/* True for fake umount (--fake). */
+static int fake = 0;
+
+/*
+ * check_special_umountprog()
+ * If there is a special umount program for this type, exec it.
+ * returns: 0: no exec was done, 1: exec was done, status has result
+ */
+static int
+check_special_umountprog(const char *node,
+ const char *type, int *status) {
+ char search_path[] = FS_SEARCH_PATH;
+ char *path, umountprog[150];
+ struct stat statbuf;
+ int res;
+
+ if (!external_allowed)
+ return 0;
+
+ if (type == NULL || strcmp(type, "none") == 0)
+ return 0;
+
+ path = strtok(search_path, ":");
+ while (path) {
+ int type_opt = 0;
+
+ res = snprintf(umountprog, sizeof(umountprog), "%s/umount.%s",
+ path, type);
+ path = strtok(NULL, ":");
+ if (res < 0 || (size_t) res >= sizeof(umountprog))
+ continue;
+
+ res = stat(umountprog, &statbuf);
+ if (res == -1 && errno == ENOENT && strchr(type, '.')) {
+ /* If type ends with ".subtype" try without it */
+ *strrchr(umountprog, '.') = '\0';
+ type_opt = 1;
+ res = stat(umountprog, &statbuf);
+ }
+ if (res == 0) {
+ res = fork();
+ if (res == 0) {
+ char *umountargs[10];
+ int i = 0;
+
+ if(setgid(getgid()) < 0)
+ die(EX_FAIL, _("umount: cannot set group id: %m"));
+
+ if(setuid(getuid()) < 0)
+ die(EX_FAIL, _("umount: cannot set user id: %m"));
+
+ umountargs[i++] = umountprog;
+ umountargs[i++] = xstrdup(node);
+ if (nomtab)
+ umountargs[i++] = "-n";
+ if (lazy)
+ umountargs[i++] = "-l";
+ if (force)
+ umountargs[i++] = "-f";
+ if (verbose)
+ umountargs[i++] = "-v";
+ if (remount)
+ umountargs[i++] = "-r";
+ if (type_opt) {
+ umountargs[i++] = "-t";
+ umountargs[i++] = (char *) type;
+ }
+ umountargs[i] = NULL;
+ execv(umountprog, umountargs);
+ exit(1); /* exec failed */
+ } else if (res != -1) {
+ int st;
+ wait(&st);
+ *status = (WIFEXITED(st) ? WEXITSTATUS(st)
+ : EX_SYSERR);
+ return 1;
+ } else {
+ int errsv = errno;
+ error(_("umount: cannot fork: %s"),
+ strerror(errsv));
+ }
+ }
+ }
+ return 0;
+}
+
+/* complain about a failed umount */
+static void complain(int err, const char *dev) {
+
+ if (complained_err == err && complained_dev && dev &&
+ strcmp(dev, complained_dev) == 0)
+ return;
+
+ complained_err = err;
+ free(complained_dev);
+ complained_dev = xstrdup(dev);
+
+ switch (err) {
+ case ENXIO:
+ error (_("umount: %s: invalid block device"), dev); break;
+ case EINVAL:
+ error (_("umount: %s: not mounted"), dev); break;
+ case EIO:
+ error (_("umount: %s: can't write superblock"), dev); break;
+ case EBUSY:
+ /* Let us hope fstab has a line "proc /proc ..."
+ and not "none /proc ..."*/
+ error (_("umount: %s: device is busy.\n"
+ " (In some cases useful info about processes that use\n"
+ " the device is found by lsof(8) or fuser(1))"), dev);
+ break;
+ case ENOENT:
+ error (_("umount: %s: not found"), dev); break;
+ case EPERM:
+ error (_("umount: %s: must be superuser to umount"), dev); break;
+ case EACCES:
+ error (_("umount: %s: block devices not permitted on fs"), dev); break;
+ default:
+ error (_("umount: %s: %s"), dev, strerror (err)); break;
+ }
+}
+
+/* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
+static int umount_nofollow_support(void)
+{
+ int res = umount2("", UMOUNT_UNUSED);
+ if (res != -1 || errno != EINVAL)
+ return 0;
+
+ res = umount2("", UMOUNT_NOFOLLOW);
+ if (res != -1 || errno != ENOENT)
+ return 0;
+
+ return 1;
+}
+
+static const char *chdir_to_parent(const char *node, char **resbuf)
+{
+ char *tmp, *res;
+ const char *parent;
+ char buf[65536];
+
+ *resbuf = xstrdup(node);
+
+ tmp = strrchr(*resbuf, '/');
+ if (!tmp)
+ die (2, _("umount: internal error: invalid abs path: %s"), node);
+
+ if (tmp != *resbuf) {
+ *tmp = '\0';
+ res = tmp + 1;
+ parent = *resbuf;
+ } else if (tmp[1] != '\0') {
+ res = tmp + 1;
+ parent = "/";
+ } else {
+ res = ".";
+ parent = "/";
+ }
+
+ if (chdir(parent) == -1)
+ die (2, _("umount: failed to chdir to %s: %m"), parent);
+
+ if (!getcwd(buf, sizeof(buf)))
+ die (2, _("umount: failed to obtain current directory: %m"));
+
+ if (strcmp(buf, parent) != 0)
+ die (2, _("umount: mountpoint moved (%s -> %s)"), parent, buf);
+
+ if (verbose)
+ printf(_("current directory moved to %s\n"), res);
+
+ return res;
+}
+
+/* Umount a single device. Return a status code, so don't exit
+ on a non-fatal error. We lock/unlock around each umount. */
+static int
+umount_one (const char *spec, const char *node, const char *type,
+ struct mntentchn *mc) {
+ int umnt_err = 0;
+ int isroot;
+ int res = 0;
+ int status;
+ int extra_flags = 0;
+ const char *loopdev, *target = node;
+ char *targetbuf = NULL;
+
+ /* Special case for root. As of 0.99pl10 we can (almost) unmount root;
+ the kernel will remount it readonly so that we can carry on running
+ afterwards. The readonly remount is illegal if any files are opened
+ for writing at the time, so we can't update mtab for an unmount of
+ root. As it is only really a remount, this doesn't matter too
+ much. [sct May 29, 1993] */
+ isroot = (streq (node, "/") || streq (node, "root")
+ || streq (node, "rootfs"));
+ if (isroot)
+ nomtab++;
+
+ /*
+ * Call umount.TYPE for types that require a separate umount program.
+ * All such special things must occur isolated in the types string.
+ */
+ if (check_special_umountprog(node, type, &status))
+ return status;
+
+ block_signals(SIG_BLOCK);
+
+ /* Skip the actual umounting for --fake */
+ if (fake)
+ goto writemtab;
+
+ if (restricted) {
+ if (umount_nofollow_support())
+ extra_flags |= UMOUNT_NOFOLLOW;
+
+ /* call umount(2) with relative path to avoid races */
+ target = chdir_to_parent(node, &targetbuf);
+ }
+
+ if (lazy) {
+ res = umount2 (target, MNT_DETACH | extra_flags);
+ if (res < 0)
+ umnt_err = errno;
+ goto writemtab;
+ }
+
+ if (force) { /* only supported for NFS */
+ res = umount2 (target, MNT_FORCE | extra_flags);
+ if (res == -1) {
+ int errsv = errno;
+ perror("umount2");
+ errno = errsv;
+ if (errno == ENOSYS) {
+ if (verbose)
+ printf(_("no umount2, trying umount...\n"));
+ res = umount (target);
+ }
+ }
+ } else if (extra_flags)
+ res = umount2 (target, extra_flags);
+ else
+ res = umount (target);
+
+ free(targetbuf);
+
+ if (res < 0)
+ umnt_err = errno;
+
+ if (res < 0 && remount && umnt_err == EBUSY) {
+ /* Umount failed - let us try a remount */
+ res = mount(spec, node, NULL,
+ MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
+ if (res == 0) {
+ fprintf(stderr,
+ _("umount: %s busy - remounted read-only\n"),
+ spec);
+ if (mc && !nomtab) {
+ /* update mtab if the entry is there */
+ struct my_mntent remnt;
+ remnt.mnt_fsname = mc->m.mnt_fsname;
+ remnt.mnt_dir = mc->m.mnt_dir;
+ remnt.mnt_type = mc->m.mnt_type;
+ remnt.mnt_opts = "ro";
+ remnt.mnt_freq = 0;
+ remnt.mnt_passno = 0;
+ update_mtab(node, &remnt);
+ }
+ block_signals(SIG_UNBLOCK);
+ return 0;
+ } else if (errno != EBUSY) { /* hmm ... */
+ perror("remount");
+ fprintf(stderr,
+ _("umount: could not remount %s read-only\n"),
+ spec);
+ }
+ }
+
+ loopdev = 0;
+ if (res >= 0) {
+ /* Umount succeeded */
+ if (verbose)
+ printf (_("%s has been unmounted\n"), spec);
+
+ /* Free any loop devices that we allocated ourselves */
+ if (mc) {
+ char *optl;
+
+ /* old style mtab line? */
+ if (streq(mc->m.mnt_type, "loop")) {
+ loopdev = spec;
+ goto gotloop;
+ }
+
+ /* new style mtab line? */
+ optl = mc->m.mnt_opts ? xstrdup(mc->m.mnt_opts) : "";
+ for (optl = strtok (optl, ","); optl;
+ optl = strtok (NULL, ",")) {
+ if (!strncmp(optl, "loop=", 5)) {
+ loopdev = optl+5;
+ goto gotloop;
+ }
+ }
+ } else {
+ /*
+ * If option "-o loop=spec" occurs in mtab,
+ * note the mount point, and delete mtab line.
+ */
+ if ((mc = getmntoptfile (spec)) != NULL)
+ node = mc->m.mnt_dir;
+ }
+
+ /* Also free loop devices when -d flag is given */
+ if (delloop)
+ loopdev = spec;
+ }
+ gotloop:
+ if (loopdev) {
+ struct loopdev_cxt lc;
+
+ loopcxt_init(&lc, 0);
+ loopcxt_set_device(&lc, loopdev);
+
+ if (loopcxt_get_backing_file(&lc)
+ && loopcxt_is_autoclear(&lc) == 0)
+ loopcxt_delete_device(&lc);
+ loopcxt_deinit(&lc);
+ }
+
+ writemtab:
+ if (!nomtab &&
+ (umnt_err == 0 || umnt_err == EINVAL || umnt_err == ENOENT)) {
+#ifdef HAVE_LIBMOUNT_MOUNT
+ struct libmnt_update *upd = mnt_new_update();
+
+ if (upd && !mnt_update_set_fs(upd, 0, node, NULL))
+ mnt_update_table(upd, NULL);
+
+ mnt_free_update(upd);
+#else
+ update_mtab (node, NULL);
+#endif
+ }
+
+ block_signals(SIG_UNBLOCK);
+
+ if (res >= 0)
+ return 0;
+ if (umnt_err)
+ complain(umnt_err, node);
+ return 1;
+}
+
+/*
+ * umount_one_bw: unmount FILE that has last occurrence MC0
+ *
+ * Why this loop?
+ * 1. People who boot a system with a bad fstab root entry
+ * will get an incorrect "/dev/foo on /" in mtab.
+ * If later /dev/foo is actually mounted elsewhere,
+ * it will occur twice in mtab.
+ * 2. With overmounting one can get the situation that
+ * the same filename is used as mount point twice.
+ * In both cases, it is best to try the last occurrence first.
+ */
+static int
+umount_one_bw (const char *file, struct mntentchn *mc0) {
+ struct mntentchn *mc;
+ int res = 1;
+
+ mc = mc0;
+ while (res && mc) {
+ res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir,
+ mc->m.mnt_type, mc);
+ mc = getmntdirbackward(file, mc);
+ }
+ mc = mc0;
+ while (res && mc) {
+ res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir,
+ mc->m.mnt_type, mc);
+ mc = getmntdevbackward(file, mc);
+ }
+ return res;
+}
+
+/* Unmount all filesystems of type VFSTYPES found in mtab. Since we are
+ concurrently updating mtab after every successful umount, we have to
+ slurp in the entire file before we start. This isn't too bad, because
+ in any case it's important to umount mtab entries in reverse order
+ to mount, e.g. /usr/spool before /usr. */
+static int
+umount_all (char *types, char *test_opts) {
+ struct mntentchn *mc, *hd;
+ int errors = 0;
+
+ hd = mtab_head();
+ if (!hd->prev)
+ die (2, _("umount: cannot find list of filesystems to unmount"));
+ for (mc = hd->prev; mc != hd; mc = mc->prev) {
+ if (matching_type (mc->m.mnt_type, types)
+ && matching_opts (mc->m.mnt_opts, test_opts)) {
+ errors |= umount_one (mc->m.mnt_fsname, mc->m.mnt_dir,
+ mc->m.mnt_type, mc);
+ }
+ }
+
+ return errors;
+}
+
+static struct option longopts[] =
+{
+ { "all", 0, 0, 'a' },
+ { "force", 0, 0, 'f' },
+ { "help", 0, 0, 'h' },
+ { "no-mtab", 0, 0, 'n' },
+ { "test-opts", 1, 0, 'O' },
+ { "verbose", 0, 0, 'v' },
+ { "version", 0, 0, 'V' },
+ { "read-only", 0, 0, 'r' },
+ { "types", 1, 0, 't' },
+
+ { "no-canonicalize", 0, 0, 144 },
+ { "fake", 0, 0, 145 },
+ { NULL, 0, 0, 0 }
+};
+
+static void
+usage (FILE *fp, int n)
+{
+ fprintf (fp, _("Usage: umount -h | -V\n"
+ " umount -a [-d] [-f] [-r] [-n] [-v] [-t vfstypes] [-O opts]\n"
+ " umount [-d] [-f] [-r] [-n] [-v] special | node...\n"));
+ exit (n);
+}
+
+/*
+ * Look for an option in a comma-separated list
+ */
+static int
+contains(const char *list, const char *s) {
+ int n = strlen(s);
+
+ while (list && *list) {
+ if (strncmp(list, s, n) == 0 &&
+ (list[n] == 0 || list[n] == ','))
+ return 1;
+ while (*list && *list++ != ',') ;
+ }
+ return 0;
+}
+
+/* check if @mc contains a loop device which is associated
+ * with the @file in fs
+ */
+static int
+is_valid_loop(struct mntentchn *mc, struct mntentchn *fs)
+{
+ uintmax_t offset = 0;
+ char *p;
+
+ /* check if it begins with /dev/loop */
+ if (strncmp(mc->m.mnt_fsname, _PATH_DEV_LOOP,
+ sizeof(_PATH_DEV_LOOP) - 1))
+ return 0;
+
+ /* check for loop option in fstab */
+ if (!contains(fs->m.mnt_opts, "loop"))
+ return 0;
+
+ /* check for offset option in fstab */
+ p = get_option_value(fs->m.mnt_opts, "offset=");
+ if (p && strtosize(p, &offset)) {
+ if (verbose > 1)
+ printf(_("failed to parse 'offset=%s' options\n"), p);
+ return 0;
+ }
+
+ /* check association */
+ if (loopdev_is_used((char *) mc->m.mnt_fsname, fs->m.mnt_fsname,
+ offset, LOOPDEV_FL_OFFSET) == 1) {
+ if (verbose > 1)
+ printf(_("device %s is associated with %s\n"),
+ mc->m.mnt_fsname, fs->m.mnt_fsname);
+ return 1;
+ }
+
+ if (verbose > 1)
+ printf(_("device %s is not associated with %s\n"),
+ mc->m.mnt_fsname, fs->m.mnt_fsname);
+ return 0;
+}
+
+/*
+ * umount helper call based on {u,p}helper= mount option
+ */
+static int check_helper_umountprog(const char *node,
+ const char *opts, const char *name,
+ int *status)
+{
+ char *helper;
+
+ if (!external_allowed || !opts)
+ return 0;
+
+ helper = get_option_value(opts, name);
+ if (helper)
+ return check_special_umountprog(node, helper, status);
+
+ return 0;
+}
+
+static int
+umount_file (char *arg) {
+ struct mntentchn *mc, *fs;
+ const char *file, *options;
+ int fstab_has_user, fstab_has_users, fstab_has_owner, fstab_has_group;
+ int ok, status = 0;
+ struct stat statbuf;
+ char *loopdev = NULL;
+
+ if (!*arg) { /* "" would be expanded to `pwd` */
+ die(2, _("Cannot unmount \"\"\n"));
+ return 0;
+ }
+
+ file = canonicalize(arg); /* mtab paths are canonicalized */
+
+try_loopdev:
+ if (verbose > 1)
+ printf(_("Trying to unmount %s\n"), file);
+
+ mc = getmntdirbackward(file, NULL);
+ if (!mc) {
+ mc = getmntdevbackward(file, NULL);
+ if (mc) {
+ struct mntentchn *mc1;
+ char *cn;
+
+ mc1 = getmntdirbackward(mc->m.mnt_dir, NULL);
+ if (!mc1)
+ /* 'mc1' must exist, though not necessarily
+ equals to `mc'. Otherwise we go mad. */
+ die(EX_SOFTWARE,
+ _("umount: confused when analyzing mtab"));
+
+ cn = canonicalize(mc1->m.mnt_fsname);
+ if (cn && strcmp(file, cn)) {
+ /* Something was stacked over `file' on the
+ same mount point. */
+ die(EX_FAIL, _("umount: cannot unmount %s -- %s is "
+ "mounted over it on the same point"),
+ file, mc1->m.mnt_fsname);
+ }
+ free(cn);
+ }
+ }
+ if (!mc && verbose)
+ printf(_("Could not find %s in mtab\n"), file);
+
+ /* not found in mtab - check if it is associated with some loop device
+ * (only if it is a regular file)
+ */
+ if (!mc && !loopdev && !stat(file, &statbuf) && S_ISREG(statbuf.st_mode)) {
+ int count = loopdev_count_by_backing_file(file, &loopdev);
+
+ if (count == 1) {
+ if (verbose)
+ printf(_("%s is associated with %s\n"),
+ arg, loopdev);
+ file = loopdev;
+ goto try_loopdev;
+
+ } else if (count > 1)
+ fprintf(stderr, _("umount: warning: %s is associated "
+ "with more than one loop device\n"), arg);
+ }
+
+ if (mc) {
+ /*
+ * helper - umount helper (e.g. pam_mount)
+ */
+ if (check_helper_umountprog(arg, mc->m.mnt_opts,
+ "helper=", &status))
+ return status;
+ }
+
+ if (restricted) {
+ char *mtab_user = NULL;
+
+ if (!mc)
+ die(2,
+ _("umount: %s is not mounted (according to mtab)"),
+ file);
+ /*
+ * uhelper - unprivileged umount helper (e.g. HAL/udisks mounts)
+ */
+ if (check_helper_umountprog(arg, mc->m.mnt_opts,
+ "uhelper=", &status))
+ return status;
+
+ /* The 2.4 kernel will generally refuse to mount the same
+ filesystem on the same mount point, but will accept NFS.
+ So, unmounting must be possible. */
+ if (!is_mounted_once(file) && strcmp(mc->m.mnt_type,"nfs"))
+ die(2,
+ _("umount: it seems %s is mounted multiple times"),
+ file);
+
+ /* If fstab contains the two lines
+ /dev/sda1 /mnt/zip auto user,noauto 0 0
+ /dev/sda4 /mnt/zip auto user,noauto 0 0
+ then "mount /dev/sda4" followed by "umount /mnt/zip"
+ used to fail. So, we must not look for file, but for
+ the pair (dev,file) in fstab. */
+ fs = getfs_by_devdir(mc->m.mnt_fsname, mc->m.mnt_dir);
+ if (!fs) {
+ fs = getfs_by_dir(file);
+ if (!fs && !getfs_by_spec(file))
+ die (2,
+ _("umount: %s is not in the fstab "
+ "(and you are not root)"),
+ file);
+
+ /* spec could be a file which is loop mounted */
+ if (!fs || !is_valid_loop(mc, fs))
+ die (2, _("umount: %s mount disagrees with "
+ "the fstab"), file);
+ }
+
+ /*
+ * User mounting and unmounting is allowed only
+ * if fstab contains one of the options `user',
+ * `users' or `owner' or `group'.
+ *
+ * The option `users' allows arbitrary users to mount
+ * and unmount - this may be a security risk.
+ *
+ * The options `user', `owner' and `group' only allow
+ * unmounting by the user that mounted (visible in mtab).
+ */
+
+ options = fs->m.mnt_opts;
+ if (!options)
+ options = "";
+ fstab_has_user = contains(options, "user");
+ fstab_has_users = contains(options, "users");
+ fstab_has_owner = contains(options, "owner");
+ fstab_has_group = contains(options, "group");
+ ok = 0;
+
+ if (fstab_has_users)
+ ok = 1;
+
+ if (!ok && (fstab_has_user || fstab_has_owner ||
+ fstab_has_group)) {
+ char *user = getusername();
+
+ options = mc->m.mnt_opts;
+ if (!options)
+ options = "";
+ mtab_user = get_option_value(options, "user=");
+
+ if (user && mtab_user && streq (user, mtab_user))
+ ok = 1;
+ }
+ if (!ok)
+ die (2, _("umount: only %s can unmount %s from %s"),
+ mtab_user ? mtab_user : "root",
+ fs->m.mnt_fsname, fs->m.mnt_dir);
+
+ }
+
+ if (mc)
+ return umount_one_bw (file, mc);
+ else
+ return umount_one (arg, arg, arg, NULL);
+}
+
+int
+main (int argc, char *argv[]) {
+ int c;
+ int all = 0;
+ char *types = NULL, *test_opts = NULL, *p;
+ int result = 0;
+
+ sanitize_env();
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+ atexit(close_stdout);
+
+ progname = argv[0];
+ if ((p = strrchr(progname, '/')) != NULL)
+ progname = p+1;
+
+ umask(022);
+
+ while ((c = getopt_long (argc, argv, "adfhlnrit:O:vV",
+ longopts, NULL)) != -1)
+ switch (c) {
+ case 'a': /* umount everything */
+ ++all;
+ break;
+ /* fall through? */
+ case 'd': /* do losetup -d for unmounted loop devices */
+ ++delloop;
+ break;
+ case 'f': /* force umount */
+ ++force;
+ break;
+ case 'h': /* help */
+ usage (stdout, 0);
+ break;
+ case 'l': /* lazy umount */
+ ++lazy;
+ break;
+ case 'n': /* do not write in /etc/mtab */
+ ++nomtab;
+ break;
+ case 'O': /* specify file system options */
+ test_opts = optarg;
+ break;
+ case 'r': /* remount read-only if umount fails */
+ ++remount;
+ break;
+ case 'v': /* make noise */
+ ++verbose;
+ break;
+ case 'V': /* version */
+ printf ("umount (%s)\n", PACKAGE_STRING);
+ exit (0);
+ case 't': /* specify file system type */
+ types = optarg;
+ break;
+ case 'i':
+ external_allowed = 0;
+ break;
+ case 144:
+ nocanonicalize = 1;
+ break;
+ case 145:
+ fake = 1;
+ break;
+ case 0:
+ break;
+ case '?':
+ default:
+ usage (stderr, 1);
+ }
+
+ {
+ const uid_t ruid = getuid();
+ const uid_t euid = geteuid();
+
+ /* if we're really root and aren't running setuid */
+ if (((uid_t)0 == ruid) && (ruid == euid)) {
+ restricted = 0;
+ }
+ }
+
+ if (restricted &&
+ (all || types || nomtab || force || remount || nocanonicalize ||
+ fake)) {
+ die (2, _("umount: only root can do that"));
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ atexit(unlock_mtab);
+
+#ifdef HAVE_LIBMOUNT_MOUNT
+ mnt_init_debug(0);
+#endif
+ if (all) {
+ /* nodev stuff: sysfs, usbfs, oprofilefs, ... */
+ if (types == NULL)
+ types = "noproc,nodevfs,nodevpts,nosysfs,norpc_pipefs,nonfsd";
+ result = umount_all (types, test_opts);
+ } else if (argc < 1) {
+ usage (stderr, 2);
+ } else while (argc--) {
+ result += umount_file(*argv++);
+ }
+ exit (result); /* nonzero on at least one failure */
+}