summaryrefslogtreecommitdiffstats
path: root/mount
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:37 +0100
committerKarel Zak2006-12-07 00:25:37 +0100
commit5c36a0eb7cdb0360f9afd5d747c321f423b35984 (patch)
tree147599a77eaff2b5fbc0d389e89d2b51602326c0 /mount
parentImported from util-linux-2.8 tarball. (diff)
downloadkernel-qcow2-util-linux-5c36a0eb7cdb0360f9afd5d747c321f423b35984.tar.gz
kernel-qcow2-util-linux-5c36a0eb7cdb0360f9afd5d747c321f423b35984.tar.xz
kernel-qcow2-util-linux-5c36a0eb7cdb0360f9afd5d747c321f423b35984.zip
Imported from util-linux-2.9i tarball.
Diffstat (limited to 'mount')
-rw-r--r--mount/Makefile45
-rw-r--r--mount/Makefile.standalone50
-rw-r--r--mount/fstab.52
-rw-r--r--mount/fstab.c305
-rw-r--r--mount/fstab.h5
-rw-r--r--mount/getusername.c14
-rw-r--r--mount/getusername.h1
-rw-r--r--mount/linux_fs.h21
-rw-r--r--mount/losetup.c4
-rw-r--r--mount/mk_loop_h7
-rw-r--r--mount/mntent.c214
-rw-r--r--mount/mntent.h16
-rw-r--r--mount/mount.884
-rw-r--r--mount/mount.c534
-rw-r--r--mount/mount_by_label.c143
-rw-r--r--mount/mount_by_label.h2
-rw-r--r--mount/mount_constants.h20
-rw-r--r--mount/mount_guess_fstype.c252
-rw-r--r--mount/mount_guess_fstype.h15
-rw-r--r--mount/nfsmount.c24
-rw-r--r--mount/nfsmount_xdr.c49
-rw-r--r--mount/sundries.c12
-rw-r--r--mount/swap.configure22
-rw-r--r--mount/swap_constants.h15
-rw-r--r--mount/swapon.814
-rw-r--r--mount/swapon.c30
-rw-r--r--mount/umount.c145
-rw-r--r--mount/version.c3
28 files changed, 1494 insertions, 554 deletions
diff --git a/mount/Makefile b/mount/Makefile
index 32272a9b6..c61b4ae8c 100644
--- a/mount/Makefile
+++ b/mount/Makefile
@@ -3,18 +3,17 @@ include ../MCONFIG
endif
CC = gcc
-CFLAGS = -O2
+CFLAGS = -I$(LIB) $(OPT)
WARNFLAGS = -Wall -Wstrict-prototypes -Wmissing-prototypes
DEFINES = -DHAVE_NFS
-LDFLAGS =
RPCSVCDIR = rpcsvc
RPC_CFLAGS = -Wno-unused
RPCGEN = rpcgen
#INSTALL = install
-#INSTALL_SUID = $(INSTALL) -m 4755 -o root
-#INSTALL_PROG = $(INSTALL) -m 755
-#INSTALL_DATA = $(INSTALL) -m 644
+#INSTALLSUID = $(INSTALL) -m 4755 -o root
+#INSTALLPROG = $(INSTALL) -m 755
+#INSTALLDATA = $(INSTALL) -m 644
## for suid progs (mount, umount)
#BINDIR = /bin
@@ -54,32 +53,43 @@ install: $(PROGS)
%.o: %.c
$(COMPILE) $<
-mount: mount.o fstab.o sundries.o realpath.o version.o $(NFS_OBJS) $(LO_OBJS)
- $(LINK) $^ $(LDLIBS) -o $@
+mount: mount.o fstab.o sundries.o realpath.o mntent.o version.o \
+ mount_guess_fstype.o mount_by_label.o getusername.o \
+ $(LIB)/setproctitle.o $(NFS_OBJS) $(LO_OBJS)
+ $(LINK) $^ -o $@
-umount: umount.o fstab.o sundries.o realpath.o version.o $(LO_OBJS)
- $(LINK) $^ $(LDLIBS) -o $@
+umount: umount.o fstab.o sundries.o realpath.o mntent.o getusername.o \
+ version.o $(LO_OBJS)
+ $(LINK) $^ -o $@
swapon: swapon.o version.o
- $(LINK) $^ $(LDLIBS) -o $@
+ $(LINK) $^ -o $@
losetup: losetup.o
- $(LINK) $^ $(LDLIBS) -o $@
-
-mount.o: linux_fs.h
+ $(LINK) $^ -o $@
mount.o umount.o nfsmount.o losetup.o fstab.o sundries.o: sundries.h
mount.o umount.o fstab.o sundries.o: fstab.h
+mount.o fstab.o mntent.o: mntent.h
+
+mount.o mount_guess_fstype.o: mount_guess_fstype.h
+
+mount.o: $(LIB)/setproctitle.h
+
+mount.o umount.o getusername.o: getusername.h
+
mount.o umount.o losetup.o lomount.o: lomount.h loop.h
-swapon.o: swap.h swapargs.h
+swapon.o: swap_constants.h swapargs.h
sundries.o nfsmount.o nfsmount_xdr.o nfsmount_clnt.o: nfsmount.h
umount.o: mount_constants.h
+mount.o mount_by_label.o mount_guess_fstype.o: linux_fs.h
+
nfsmount_clnt.o: nfsmount_clnt.c
$(COMPILE) $(RPC_CFLAGS) nfsmount_clnt.c
@@ -109,11 +119,6 @@ nfs_mountversion.h:
echo '#define KERNEL_NFS_MOUNT_VERSION 0'; \
fi > nfs_mountversion.h
-SWAPH=/usr/include/linux/swap.h
-swap.h:
- rm -f swap.h
- if [ -f $(SWAPH) ]; then cp $(SWAPH) .; else touch swap.h; fi
-
swapargs.h:
sh swap.configure
@@ -122,7 +127,7 @@ loop.h:
clean:
rm -f a.out core *~ *.o swapargs.h $(PROGS) swapoff
- rm -f swap.h loop.h nfs_mountversion.h
+ rm -f loop.h nfs_mountversion.h
clobber distclean realclean: clean
# rm -f $(GEN_FILES)
diff --git a/mount/Makefile.standalone b/mount/Makefile.standalone
index 2cedcd235..1be375689 100644
--- a/mount/Makefile.standalone
+++ b/mount/Makefile.standalone
@@ -5,7 +5,7 @@
# For now: a standalone version
CC = gcc
-CFLAGS = -O2
+CFLAGS = -O2 -I../lib
#WARNFLAGS = -Wall -Wstrict-prototypes
# We really want
@@ -23,11 +23,11 @@ RPC_CFLAGS = -Wno-unused
RPCGEN = rpcgen
INSTALL = install
-INSTALL_SUID = $(INSTALL) -m 4755 -o root
-INSTALL_PROG = $(INSTALL) -m 755
-INSTALL_DATA = $(INSTALL) -m 644
-INSTALL_DIR = mkdir -p
-INSTALL_MAN = $(INSTALL_DATA)
+INSTALLSUID = $(INSTALL) -m 4755 -o root
+INSTALLPROG = $(INSTALL) -m 755
+INSTALLDATA = $(INSTALL) -m 644
+INSTALLDIR = mkdir -p
+INSTALLMAN = $(INSTALLDATA)
MANDIR = /usr/man
## for suid progs (mount, umount)
@@ -57,21 +57,22 @@ LO_OBJS=lomount.o
all: $(PROGS)
install: $(PROGS)
- $(INSTALL_DIR) $(BINDIR) $(SBINDIR)
- $(INSTALL_SUID) -s $(SUID_PROGS) $(BINDIR)
- $(INSTALL_PROG) -s $(NOSUID_PROGS) $(SBINDIR)
+ $(INSTALLDIR) $(BINDIR) $(SBINDIR)
+ $(INSTALLSUID) -s $(SUID_PROGS) $(BINDIR)
+ $(INSTALLPROG) -s $(NOSUID_PROGS) $(SBINDIR)
(cd $(SBINDIR); ln -sf swapon swapoff)
- $(INSTALL_DIR) $(MANDIR)/man5 $(MANDIR)/man8
- $(INSTALL_MAN) $(MAN5) $(MANDIR)/man5
- $(INSTALL_MAN) $(MAN8) $(MANDIR)/man8
+ $(INSTALLDIR) $(MANDIR)/man5 $(MANDIR)/man8
+ $(INSTALLMAN) $(MAN5) $(MANDIR)/man5
+ $(INSTALLMAN) $(MAN8) $(MANDIR)/man8
%.o: %.c
$(COMPILE) $<
-mount: mount.o fstab.o sundries.o realpath.o version.o $(NFS_OBJS) $(LO_OBJS)
+mount: mount.o fstab.o sundries.o realpath.o mntent.o version.o \
+ mount_guess_fstype.o mount_by_label.o ../lib/setproctitle.o $(NFS_OBJS) $(LO_OBJS)
$(LINK) $^ -o $@
-umount: umount.o fstab.o sundries.o realpath.o version.o $(LO_OBJS)
+umount: umount.o fstab.o sundries.o realpath.o mntent.o version.o $(LO_OBJS)
$(LINK) $^ -o $@
swapon: swapon.o version.o
@@ -84,14 +85,20 @@ mount.o umount.o nfsmount.o losetup.o fstab.o sundries.o: sundries.h
mount.o umount.o fstab.o sundries.o: fstab.h
-mount.o umount.o losetup.o: lomount.h loop.h
+mount.o fstab.o mntent.o: mntent.h
-swapon.o: swap.h swapargs.h
+mount.o mount_guess_fstype.o: mount_guess_fstype.h
+
+mount.o umount.o losetup.o lomount.o: lomount.h loop.h
+
+swapon.o: swap_constants.h swapargs.h
sundries.o nfsmount.o nfsmount_xdr.o nfsmount_clnt.o: nfsmount.h
umount.o: mount_constants.h
+mount.o mount_by_label.o mount_guess_fstype.o: linux_fs.h
+
nfsmount_clnt.o: nfsmount_clnt.c
$(COMPILE) $(RPC_CFLAGS) nfsmount_clnt.c
@@ -110,8 +117,6 @@ nfsmount.x:
nfsmount.o: nfs_mountversion.h nfs_mount3.h
NFSMOUNTH=/usr/include/linux/nfs_mount.h
-SWAPH=/usr/include/linux/swap.h
-LOOPH=/usr/include/linux/loop.h
nfs_mountversion.h:
rm -f nfs_mountversion.h
@@ -122,20 +127,15 @@ nfs_mountversion.h:
echo '#define KERNEL_NFS_MOUNT_VERSION 0'; \
fi > nfs_mountversion.h
-swap.h:
- rm -f swap.h
- if [ -f $(SWAPH) ]; then cp $(SWAPH) .; else touch swap.h; fi
-
swapargs.h:
sh swap.configure
loop.h:
- rm -f loop.h
- if [ -f $(LOOPH) ]; then cp $(LOOPH) .; else touch loop.h; fi
+ sh mk_loop_h
clean:
rm -f a.out core *~ *.o swapargs.h $(PROGS) swapoff
- rm -f swap.h loop.h nfs_mountversion.h
+ rm -f loop.h nfs_mountversion.h
clobber distclean realclean: clean
rm -f $(GEN_FILES)
diff --git a/mount/fstab.5 b/mount/fstab.5
index 8af521b2f..d343538db 100644
--- a/mount/fstab.5
+++ b/mount/fstab.5
@@ -111,7 +111,7 @@ a filesystem for mounting partitions from remote systems.
a disk partition to be used for swapping.
.PP
If
-.I vfs_fstype
+.I fs_vfstype
is specified as ``ignore'' the entry is ignored. This is useful to show
disk partitions which are currently unused.
diff --git a/mount/fstab.c b/mount/fstab.c
index 6a2adc657..a67316ee9 100644
--- a/mount/fstab.c
+++ b/mount/fstab.c
@@ -1,9 +1,9 @@
#include <unistd.h>
-#include <mntent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
+#include "mntent.h"
#include "fstab.h"
#include "sundries.h" /* for xmalloc() etc */
@@ -88,30 +88,28 @@ fstab_head() {
}
static void
-read_mntentchn(FILE *fp, const char *fnam, struct mntentchn *mc0) {
- struct mntentchn *mc = mc0;
- struct mntent *mnt;
-
- while (!feof(fp) && !ferror(fp)) {
- if ((mnt = getmntent (fp)) != NULL /* ignore blank lines */
- && *mnt->mnt_fsname != '#' /* and comment lines */
- && !streq (mnt->mnt_type, MNTTYPE_IGNORE)) {
- mc->nxt = (struct mntentchn *) xmalloc(sizeof(*mc));
- mc->nxt->prev = mc;
- mc = mc->nxt;
- mc->mnt_fsname = xstrdup(mnt->mnt_fsname);
- mc->mnt_dir = xstrdup(mnt->mnt_dir);
- mc->mnt_type = xstrdup(mnt->mnt_type);
- mc->mnt_opts = xstrdup(mnt->mnt_opts);
- mc->nxt = NULL;
- }
- }
- mc0->prev = mc;
- if (ferror (fp)) {
- error("warning: error reading %s: %s", fnam, strerror (errno));
- mc0->nxt = mc0->prev = NULL;
- }
- endmntent(fp);
+read_mntentchn(mntFILE *mfp, const char *fnam, struct mntentchn *mc0) {
+ struct mntentchn *mc = mc0;
+ struct 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->mnt_fsname = mnt->mnt_fsname;
+ mc->mnt_dir = mnt->mnt_dir;
+ mc->mnt_type = mnt->mnt_type;
+ mc->mnt_opts = mnt->mnt_opts;
+ mc->nxt = NULL;
+ }
+ }
+ mc0->prev = mc;
+ if (ferror (mfp->mntent_fp)) {
+ error("warning: error reading %s: %s", fnam, strerror (errno));
+ mc0->nxt = mc0->prev = NULL;
+ }
+ my_endmntent(mfp);
}
/*
@@ -121,7 +119,7 @@ read_mntentchn(FILE *fp, const char *fnam, struct mntentchn *mc0) {
*/
static void
read_mounttable() {
- FILE *fp = NULL;
+ mntFILE *mfp;
const char *fnam;
struct mntentchn *mc = &mounttable;
@@ -129,10 +127,12 @@ read_mounttable() {
mc->nxt = mc->prev = NULL;
fnam = MOUNTED;
- if ((fp = setmntent (fnam, "r")) == NULL) {
+ mfp = my_setmntent (fnam, "r");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
int errsv = errno;
fnam = PROC_MOUNTS;
- if ((fp = setmntent (fnam, "r")) == NULL) {
+ mfp = my_setmntent (fnam, "r");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
error("warning: can't open %s: %s", MOUNTED, strerror (errsv));
return;
}
@@ -140,12 +140,12 @@ read_mounttable() {
printf ("mount: could not open %s - using %s instead\n",
MOUNTED, PROC_MOUNTS);
}
- read_mntentchn(fp, fnam, mc);
+ read_mntentchn(mfp, fnam, mc);
}
static void
read_fstab() {
- FILE *fp = NULL;
+ mntFILE *mfp = NULL;
const char *fnam;
struct mntentchn *mc = &fstab;
@@ -153,11 +153,12 @@ read_fstab() {
mc->nxt = mc->prev = NULL;
fnam = _PATH_FSTAB;
- if ((fp = setmntent (fnam, "r")) == NULL) {
+ mfp = my_setmntent (fnam, "r");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
error("warning: can't open %s: %s", _PATH_FSTAB, strerror (errno));
return;
}
- read_mntentchn(fp, fnam, mc);
+ read_mntentchn(mfp, fnam, mc);
}
@@ -173,6 +174,24 @@ getmntfile (const char *name) {
return mc;
}
+/*
+ * Given the name NAME, and the place MCPREV we found it last time,
+ * try to find more occurrences.
+ */
+struct mntentchn *
+getmntfilesbackward (const char *name, struct mntentchn *mcprev) {
+ struct mntentchn *mc, *mh;
+
+ mh = mtab_head();
+ if (!mcprev)
+ mcprev = mh;
+ for (mc = mcprev->prev; mc && mc != mh; mc = mc->prev)
+ if (streq (mc->mnt_dir, name) || (streq (mc->mnt_fsname, name)))
+ return mc;
+
+ return NULL;
+}
+
/* Given the name FILE, try to find the option "loop=FILE" in mtab. */
struct mntentchn *
getmntoptfile (const char *file)
@@ -222,13 +241,41 @@ getfsspec (const char *spec)
return mc;
}
-/* Updating mtab ----------------------------------------------*/
+/* Find the uuid UUID in fstab. */
+struct mntentchn *
+getfsuuidspec (const char *uuid)
+{
+ struct mntentchn *mc;
+
+ for (mc = fstab_head()->nxt; mc; mc = mc->nxt)
+ if (strncmp (mc->mnt_fsname, "UUID=", 5) == 0
+ && streq(mc->mnt_fsname + 5, uuid))
+ break;
+
+ return mc;
+}
-/* File descriptor for lock. Value tested in unlock_mtab() to remove race. */
-static int lock = -1;
+/* Find the label LABEL in fstab. */
+struct mntentchn *
+getfsvolspec (const char *label)
+{
+ struct mntentchn *mc;
+
+ for (mc = fstab_head()->nxt; mc; mc = mc->nxt)
+ if (strncmp (mc->mnt_fsname, "LABEL=", 6) == 0
+ && streq(mc->mnt_fsname + 6, label))
+ break;
+
+ return mc;
+}
+
+/* Updating mtab ----------------------------------------------*/
/* Flag for already existing lock file. */
-static int old_lockfile = 1;
+static int we_created_lockfile = 0;
+
+/* 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. */
static void
@@ -241,69 +288,122 @@ setlkw_timeout (int sig) {
/* nothing, fcntl will fail anyway */
}
-/* Create the lock file. The lock file will be removed if we catch a signal
- or when we exit. The value of lock is tested to remove the race. */
+/* 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~~.
+ Maybe the latter is preferable. */
+#define MOUNTLOCK_LINKTARGET MOUNTED_LOCK "~"
+
void
lock_mtab (void) {
- int sig = 0;
- struct sigaction sa;
- struct flock flock;
-
- /* If this is the first time, ensure that the lock will be removed. */
- if (lock < 0) {
- struct stat st;
- 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);
- }
+ int tries = 3;
- /* This stat is performed so we know when not to be overly eager
- when cleaning up after signals. The window between stat and
- open is not significant. */
- if (lstat (MOUNTED_LOCK, &st) < 0 && errno == ENOENT)
- old_lockfile = 0;
-
- lock = open (MOUNTED_LOCK, O_WRONLY|O_CREAT, 0);
- if (lock < 0) {
- die (EX_FILEIO, "can't create lock file %s: %s "
- "(use -n flag to override)",
- MOUNTED_LOCK, strerror (errno));
- }
+ if (!signals_have_been_setup) {
+ int sig = 0;
+ struct sigaction sa;
- flock.l_type = F_WRLCK;
- flock.l_whence = SEEK_SET;
- flock.l_start = 0;
- flock.l_len = 0;
-
- alarm(LOCK_BUSY);
- if (fcntl (lock, F_SETLKW, &flock) < 0) {
- close (lock);
- /* The file should not be removed */
- lock = -1;
- die (EX_FILEIO, "can't lock lock file %s: %s",
- MOUNTED_LOCK,
- errno == EINTR ? "timed out" : strerror (errno));
- }
- /* We have now access to the lock, and it can always be removed */
- old_lockfile = 0;
- }
+ 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;
+ }
+
+ /* Repeat until it was us who made the link */
+ while (!we_created_lockfile) {
+ struct flock flock;
+ int errsv, fd, i, j;
+
+ i = open (MOUNTLOCK_LINKTARGET, O_WRONLY|O_CREAT, 0);
+ if (i < 0) {
+ /* MOUNTLOCK_LINKTARGET 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)",
+ MOUNTLOCK_LINKTARGET, strerror (errno));
+ }
+ close(i);
+
+ j = link(MOUNTLOCK_LINKTARGET, MOUNTED_LOCK);
+ errsv = errno;
+
+ (void) unlink(MOUNTLOCK_LINKTARGET);
+
+ if (j < 0 && errsv != EEXIST) {
+ die (EX_FILEIO, "can't link lock file %s: %s "
+ "(use -n flag to override)",
+ MOUNTED_LOCK, strerror (errsv));
+ }
+
+ fd = open (MOUNTED_LOCK, O_WRONLY);
+
+ if (fd < 0) {
+ /* Strange... Maybe the file was just deleted? */
+ if (errno == ENOENT && tries-- > 0)
+ continue;
+ die (EX_FILEIO, "can't open lock file %s: %s "
+ "(use -n flag to override)",
+ MOUNTED_LOCK, strerror (errno));
+ }
+
+ 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 (fd, F_SETLK, &flock) == -1) {
+ if (verbose)
+ printf("Can't lock lock file %s: %s\n",
+ MOUNTED_LOCK, strerror (errno));
+ /* proceed anyway */
+ }
+ we_created_lockfile = 1;
+ } else {
+ /* Someone else made the link. Wait. */
+ alarm(LOCK_TIMEOUT);
+ if (fcntl (fd, F_SETLKW, &flock) == -1) {
+ die (EX_FILEIO, "can't lock lock file %s: %s",
+ MOUNTED_LOCK, (errno == EINTR) ?
+ "timed out" : strerror (errno));
+ }
+ alarm(0);
+ /* Maybe limit the number of iterations? */
+ }
+
+ close(fd);
+ }
}
/* Remove lock file. */
void
unlock_mtab (void) {
- if (lock != -1) {
- close (lock);
- if (!old_lockfile)
- unlink (MOUNTED_LOCK);
- }
+ if (we_created_lockfile) {
+ unlink (MOUNTED_LOCK);
+ we_created_lockfile = 0;
+ }
}
/*
@@ -322,27 +422,32 @@ update_mtab (const char *dir, struct mntent *instead) {
struct mntent *next;
struct mntent remnt;
int added = 0;
- FILE *fp, *ftmp;
+ mntFILE *mfp, *mftmp;
if (mtab_does_not_exist() || mtab_is_a_symlink())
return;
lock_mtab();
- if ((fp = setmntent(MOUNTED, "r")) == NULL) {
+ mfp = my_setmntent(MOUNTED, "r");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
error ("cannot open %s (%s) - mtab not updated",
MOUNTED, strerror (errno));
goto leave;
}
- if ((ftmp = setmntent (MOUNTED_TEMP, "w")) == NULL) {
+ mftmp = my_setmntent (MOUNTED_TEMP, "w");
+ if (mftmp == NULL || mfp->mntent_fp == NULL) {
error ("can't open %s (%s) - mtab not updated",
MOUNTED_TEMP, strerror (errno));
goto leave;
}
- while ((mnt = getmntent (fp))) {
- if (streq (mnt->mnt_dir, dir)) {
+ while ((mnt = my_getmntent (mfp))) {
+ if (streq (mnt->mnt_dir, dir)
+ /* Matthew Wilcox <willy@odie.barnet.ac.uk> */
+ || (instead && instead->mnt_fsname &&
+ (streq (mnt->mnt_fsname, instead->mnt_fsname)))) {
added++;
if (instead) { /* a remount */
remnt = *instead;
@@ -362,19 +467,19 @@ update_mtab (const char *dir, struct mntent *instead) {
next = NULL;
} else
next = mnt;
- if (next && addmntent(ftmp, next) == 1)
+ if (next && my_addmntent(mftmp, next) == 1)
die (EX_FILEIO, "error writing %s: %s",
MOUNTED_TEMP, strerror (errno));
}
- if (instead && !added && addmntent(ftmp, instead) == 1)
+ if (instead && !added && my_addmntent(mftmp, instead) == 1)
die (EX_FILEIO, "error writing %s: %s",
MOUNTED_TEMP, strerror (errno));
- endmntent (fp);
- if (fchmod (fileno (ftmp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
+ my_endmntent (mfp);
+ if (fchmod (fileno (mftmp->mntent_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
fprintf(stderr, "error changing mode of %s: %s\n", MOUNTED_TEMP,
strerror (errno));
- endmntent (ftmp);
+ my_endmntent (mftmp);
if (rename (MOUNTED_TEMP, MOUNTED) < 0)
fprintf(stderr, "can't rename %s to %s: %s\n", MOUNTED_TEMP, MOUNTED,
diff --git a/mount/fstab.h b/mount/fstab.h
index f22f2e7cb..e0b3895c2 100644
--- a/mount/fstab.h
+++ b/mount/fstab.h
@@ -1,7 +1,7 @@
#define _PATH_FSTAB "/etc/fstab"
#define MOUNTED_LOCK "/etc/mtab~"
#define MOUNTED_TEMP "/etc/mtab.tmp"
-#define LOCK_BUSY 10
+#define LOCK_TIMEOUT 10
int mtab_is_writable(void);
int mtab_does_not_exist(void);
@@ -18,10 +18,13 @@ struct mntentchn {
struct mntentchn *mtab_head (void);
struct mntentchn *getmntfile (const char *name);
struct mntentchn *getmntoptfile (const char *file);
+struct mntentchn *getmntfilesbackward (const char *file, struct mntentchn *mc);
struct mntentchn *fstab_head (void);
struct mntentchn *getfsfile (const char *file);
struct mntentchn *getfsspec (const char *spec);
+struct mntentchn *getfsuuidspec (const char *uuid);
+struct mntentchn *getfsvolspec (const char *label);
#include <mntent.h>
void lock_mtab (void);
diff --git a/mount/getusername.c b/mount/getusername.c
new file mode 100644
index 000000000..9835768ca
--- /dev/null
+++ b/mount/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/getusername.h b/mount/getusername.h
new file mode 100644
index 000000000..808ac9b88
--- /dev/null
+++ b/mount/getusername.h
@@ -0,0 +1 @@
+extern char *getusername(void);
diff --git a/mount/linux_fs.h b/mount/linux_fs.h
index 4e73c3b04..bdc548c21 100644
--- a/mount/linux_fs.h
+++ b/mount/linux_fs.h
@@ -4,7 +4,13 @@
in case no filesystem type was given. */
#ifndef BLKGETSIZE
+#ifndef _IO
+/* pre-1.3.45 */
#define BLKGETSIZE 0x1260 /* return device size */
+#else
+/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */
+#define BLKGETSIZE _IO(0x12,96)
+#endif
#endif
#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
@@ -43,8 +49,11 @@ struct ext_super_block {
#define EXT2_PRE_02B_MAGIC 0xEF51
#define EXT2_SUPER_MAGIC 0xEF53
struct ext2_super_block {
- u_char s_dummy[56];
+ u_char s_dummy1[56];
u_char s_magic[2];
+ u_char s_dummy2[46];
+ u_char s_uuid[16];
+ u_char s_volume_name[16];
};
#define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8))
@@ -57,3 +66,13 @@ struct xiafs_super_block {
#define xiafsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \
(((uint) s.s_magic[2]) << 16) + \
(((uint) s.s_magic[3]) << 24))
+
+/* From jj@sunsite.ms.mff.cuni.cz Mon Mar 23 15:19:05 1998 */
+#define UFS_SUPER_MAGIC 0x00011954
+struct ufs_super_block {
+ u_char s_dummy[0x55c];
+ u_char s_magic[4];
+};
+#define ufsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \
+ (((uint) s.s_magic[2]) << 16) + \
+ (((uint) s.s_magic[3]) << 24))
diff --git a/mount/losetup.c b/mount/losetup.c
index 8f9dbe52b..8a75a9aef 100644
--- a/mount/losetup.c
+++ b/mount/losetup.c
@@ -202,12 +202,12 @@ int main(int argc, char **argv)
if ((delete && (argc != optind+1 || encryption || offset)) ||
(!delete && (argc < optind+1 || argc > optind+2)))
usage();
- if (argc == optind+1)
+ if (argc == optind+1) {
if (delete)
del_loop(argv[optind]);
else
show_loop(argv[optind]);
- else {
+ } else {
if (offset && sscanf(offset,"%d",&off) != 1)
usage();
set_loop(argv[optind],argv[optind+1],off,encryption,&ro);
diff --git a/mount/mk_loop_h b/mount/mk_loop_h
index 9351b57e0..0f8a1a617 100644
--- a/mount/mk_loop_h
+++ b/mount/mk_loop_h
@@ -8,11 +8,12 @@ rm -f loop.h
# Since 1.3.79 there is an include file <asm/posix_types.h>
# that defines __kernel_dev_t.
# (The file itself appeared in 1.3.78, but there it defined __dev_t.)
-# If it exists, we use it. Otherwise we guess that __kernel_dev_t
+# If it exists, we use it, or, rather, <linux/posix_types.h> which
+# avoids namespace pollution. Otherwise we guess that __kernel_dev_t
# is an unsigned short (which is true on i386, but false on alpha).
-if [ -f /usr/include/asm/posix_types.h ]; then
- echo '#include <asm/posix_types.h>' >> loop.h
+if [ -f /usr/include/linux/posix_types.h ]; then
+ echo '#include <linux/posix_types.h>' >> loop.h
echo '#define dev_t __kernel_dev_t' >> loop.h
else
echo '#define dev_t unsigned short' >> loop.h
diff --git a/mount/mntent.c b/mount/mntent.c
new file mode 100644
index 000000000..0be20e8ca
--- /dev/null
+++ b/mount/mntent.c
@@ -0,0 +1,214 @@
+/* Private version of the libc *mntent() routines. */
+/* Note slightly different prototypes. */
+
+#include <stdio.h>
+#include <string.h> /* for index */
+#include <ctype.h> /* for isdigit */
+#include "mntent.h"
+#include "sundries.h" /* for xmalloc */
+
+/* Unfortunately the classical Unix /etc/mtab and /etc/fstab
+ do not handle directory names containing spaces.
+ Here we mangle them, replacing a space by \040.
+ What do other Unices do? */
+
+static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
+
+static char *
+mangle(unsigned char *s) {
+ char *ss, *sp;
+ int n;
+
+ n = strlen(s);
+ ss = sp = xmalloc(4*n+1);
+ while(1) {
+ for (n = 0; n < sizeof(need_escaping); n++) {
+ if (*s == need_escaping[n]) {
+ *sp++ = '\\';
+ *sp++ = '0' + ((*s & 0300) >> 6);
+ *sp++ = '0' + ((*s & 070) >> 3);
+ *sp++ = '0' + (*s & 07);
+ goto next;
+ }
+ }
+ *sp++ = *s;
+ if (*s == 0)
+ break;
+ next:
+ s++;
+ }
+ return ss;
+}
+
+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;
+}
+
+static char *
+skip_nonspaces(char *s) {
+ while (*s && !is_space_or_tab(*s))
+ s++;
+ return s;
+}
+
+#define isoctal(a) (((a) & ~7) == '0')
+
+/* returns malloced pointer - no more strdup required */
+static char *
+unmangle(char *s) {
+ char *ret, *ss, *sp;
+
+ ss = skip_nonspaces(s);
+ ret = sp = xmalloc(ss-s+1);
+ while(s != ss) {
+ if (*s == '\\' && isoctal(s[1]) && isoctal(s[2]) && isoctal(s[3])) {
+ *sp++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7);
+ s += 4;
+ } else
+ *sp++ = *s++;
+ }
+ *sp = 0;
+ return ret;
+}
+
+/*
+ * fstat'ing the file and allocating a buffer holding all of it
+ * may be a bad idea: if the file is /proc/mounttab, the stat
+ * returns 0.
+ * (On the other hand, mangling and unmangling is meaningless
+ * for /proc/mounttab.)
+ */
+
+mntFILE *
+my_setmntent (const char *file, char *mode) {
+ mntFILE *mfp = xmalloc(sizeof(*mfp));
+
+ mfp->mntent_fp = fopen (file, mode);
+ 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)
+ fclose(mfp->mntent_fp);
+ if (mfp->mntent_file)
+ free(mfp->mntent_file);
+ free(mfp);
+ }
+}
+
+
+int
+my_addmntent (mntFILE *mfp, struct 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 = mangle(mnt->mnt_opts);
+
+ res = ((fprintf (mfp->mntent_fp, "%s %s %s %s %d %d\n",
+ m1, m2, m3, m4, mnt->mnt_freq, mnt->mnt_passno)
+ < 0) ? 1 : 0);
+
+ free(m1);
+ free(m2);
+ free(m3);
+ free(m4);
+ return res;
+}
+
+/* Read the next entry from the file fp. Stop reading at an incorrect entry. */
+struct mntent *
+my_getmntent (mntFILE *mfp) {
+ static char buf[4096];
+ static struct 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 = index (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 = index (buf, 0);
+ } else {
+ mfp->mntent_errs = 1;
+ goto err;
+ }
+ }
+ *s = 0;
+ s = skip_spaces(buf);
+ } while (*s == '\0' || *s == '#');
+
+ me.mnt_fsname = unmangle(s);
+ s = skip_nonspaces(s);
+ s = skip_spaces(s);
+ me.mnt_dir = unmangle(s);
+ s = skip_nonspaces(s);
+ s = skip_spaces(s);
+ me.mnt_type = unmangle(s);
+ s = skip_nonspaces(s);
+ s = skip_spaces(s);
+ me.mnt_opts = unmangle(s);
+ s = skip_nonspaces(s);
+ s = skip_spaces(s);
+
+ 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/mntent.h b/mount/mntent.h
new file mode 100644
index 000000000..9b46ba08d
--- /dev/null
+++ b/mount/mntent.h
@@ -0,0 +1,16 @@
+#include <mntent.h> /* for struct mntent */
+
+#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 mntent *mnt);
+struct mntent *my_getmntent (mntFILE *mfp);
diff --git a/mount/mount.8 b/mount/mount.8
index 097dee005..633671b19 100644
--- a/mount/mount.8
+++ b/mount/mount.8
@@ -31,6 +31,8 @@
.\" 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
.\"
.TH MOUNT 8 "14 September 1997" "Linux 2.0" "Linux Programmer's Manual"
.SH NAME
@@ -111,6 +113,8 @@ 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 label or UUID (see the \-L and \-U options below).
The file
.I /etc/fstab
@@ -163,6 +167,14 @@ or
.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 programs
.B mount
@@ -265,16 +277,46 @@ Mount the file system read-only. A synonym is
Mount the file system read/write. This is the default. A synonym is
.BR "\-o rw" .
.TP
+.BI \-L " label"
+Mount the partition that has the specified
+.IR label .
+.TP
+.BI \-U " uuid"
+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.
+.TP
.BI \-t " vfstype"
The argument following the
.B \-t
is used to indicate the file system type. The file system types which are
currently supported are listed in
.IR linux/fs/filesystems.c :
-.IR minix ", " ext ", " ext2 ", " xiafs ", " hpfs ,
-.IR msdos ", " umsdos ", " vfat ,
-.IR proc ", " nfs ", " iso9660 ", " smbfs ", " ncpfs ,
-.IR affs ", " ufs ", " romfs ,
+.IR minix ,
+.IR xiafs ,
+.IR ext ,
+.IR ext2 ,
+.IR msdos ,
+.IR umsdos ,
+.IR vfat ,
+.IR proc ,
+.IR autofs ,
+.IR devpts ,
+.IR nfs ,
+.IR iso9660 ,
+.IR smbfs ,
+.IR ncpfs ,
+.IR adfs ,
+.IR affs ,
+.IR coda ,
+.IR hfs ,
+.IR hpfs ,
+.IR ntfs ,
+.IR qnx4 ,
+.IR romfs ,
+.IR ufs ,
.IR sysv ", " xenix ", " coherent .
Note that the last three are equivalent and that
.I xenix
@@ -288,6 +330,23 @@ and
.I xiafs
do not exist anymore.
+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, smbfs, ncpfs) ad hoc code is
+necessary. The nfs ad hoc code is built in, but smbfs and ncpfs
+have a separate mount program. In order to make it possible to
+treat all types in a uniform way, mount will execute the program
+.I /sbin/mount.TYPE
+(if that exists) when called with type smb or ncp.
+Since various versions of the
+.I smbmount
+program have different calling conventions,
+.I /sbin/mount.smb
+may have to be a shell script that sets up the desired call.
+
The type
.I iso9660
is the default. If no
@@ -297,9 +356,11 @@ option is given, or if the
type is specified, the superblock is probed for the filesystem type
.RI ( minix ", " ext ", " ext2 ", " xiafs ", " iso9660 ", " romfs
are supported).
-If this probe fails and
-.I /proc/filesystems
-exists, then all of the filesystems listed there will be tried,
+If this probe fails, 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.,
.I proc
and
@@ -308,6 +369,10 @@ and
Note that 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 if you use a kernel module autoloader.
Warning: the probing uses a heuristic (the presence of appropriate `magic'),
and could recognize the wrong filesystem type.
@@ -381,7 +446,8 @@ binaries for architectures other than its own.
.TP
.B nosuid
Do not allow set-user-identifier or set-group-identifier bits to take
-effect.
+effect. (This seems safe, but is in fact rather unsafe if you have
+suidperl(1) installed.)
.TP
.B nouser
Forbid an ordinary (i.e., non-root) user to mount the file system.
@@ -1000,4 +1066,4 @@ for the
.SH HISTORY
A
.B mount
-command appeared in Version 6 AT&T UNIX.
+command existed in Version 5 AT&T UNIX.
diff --git a/mount/mount.c b/mount/mount.c
index 19c507640..5ee247daa 100644
--- a/mount/mount.c
+++ b/mount/mount.c
@@ -2,12 +2,6 @@
* A mount(8) for Linux 0.99.
* mount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
*
- * Thu Jul 14 07:32:40 1994: faith@cs.unc.edu added changes from Adam
- * J. Richter (adam@adam.yggdrasil.com) so that /proc/filesystems is used
- * if no -t option is given. I modified his patches so that, if
- * /proc/filesystems is not available, the behavior of mount is the same as
- * it was previously.
- *
* Wed Sep 14 22:43:00 1994: Mitchum DSouza
* (mitch@mrc-applied-psychology.cambridge.ac.uk) added support for mounting
* the "loop" device.
@@ -15,21 +9,22 @@
* Wed Sep 14 22:55:10 1994: Sander van Malssen (svm@kozmix.hacktic.nl)
* added support for remounting readonly file systems readonly.
*
- * Wed Feb 8 09:23:18 1995: Mike Grupenhoff <kashmir@umiacs.UMD.EDU> added
- * a probe of the superblock for the type before /proc/filesystems is
- * checked.
- *
* Wed Feb 8 12:27:00 1995: Andries.Brouwer@cwi.nl fixed up error messages.
* Sat Jun 3 20:44:38 1995: Patches from Andries.Brouwer@cwi.nl applied.
* Tue Sep 26 22:38:20 1995: aeb@cwi.nl, many changes
* Fri Feb 23 13:47:00 1996: aeb@cwi.nl, loop device related changes
*
- * Fri Apr 5 01:13:33 1996: quinlan@bucknell.edu, fixed up iso9660 autodetect
- *
* Since then, many changes - aeb.
*
* Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
* Implemented the "bg", "fg" and "retry" mount options for NFS.
+ *
+ * Tue Aug 4 15:54:31 1998: aeb@cwi.nl:
+ * Open fd 0,1,2 so that printf's do not clobber /etc/mtab or so.
+ * Mangle filenames with embedded spaces. Add ufsmagic. Add locking.
+ * Avoid unnecessary error messages about /proc.
+ * Improve support for noncanonical names in /etc/fstab.
+ * Add support for volume labels and UUIDs.
*/
#include <unistd.h>
@@ -47,22 +42,19 @@
#include "mount_constants.h"
#include "sundries.h"
+#include "mntent.h"
#include "fstab.h"
#include "lomount.h"
#include "loop.h"
-#include "linux_fs.h"
-
-#define PROC_FILESYSTEMS "/proc/filesystems"
-#define SIZE(a) (sizeof(a)/sizeof(a[0]))
+#include "linux_fs.h" /* for BLKGETSIZE */
+#include "mount_guess_fstype.h"
+#include "mount_by_label.h"
+#include "getusername.h"
#define DO_PS_FIDDLING
#ifdef DO_PS_FIDDLING
-#define PROC_NAME "mount: "
-static int argc0;
-static char** argv0;
-static char** envp0;
-extern char** environ;
+#include "setproctitle.h"
#endif
/* True for fake mount (-f). */
@@ -105,14 +97,15 @@ struct opt_map
/* We can use the high-order 16 bits, since the mount call
has MS_MGC_VAL there. */
#define MS_NOAUTO 0x80000000
-#define MS_USER 0x40000000
+#define MS_USERS 0x40000000
+#define MS_USER 0x20000000
#define MS_LOOP 0x00010000
/* Options that we keep the mount system call from seeing. */
-#define MS_NOSYS (MS_NOAUTO|MS_USER|MS_LOOP)
+#define MS_NOSYS (MS_NOAUTO|MS_USERS|MS_USER|MS_LOOP)
/* Options that we keep from appearing in the options field in the mtab. */
-#define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USER)
+#define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER)
/* OPTIONS that we make ordinary users have by default. */
#define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
@@ -132,6 +125,8 @@ const struct opt_map opt_map[] = {
{ "remount", 0, 0, MS_REMOUNT}, /* Alter flags of mounted FS */
{ "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 */
/* add new options here */
@@ -159,7 +154,7 @@ const struct opt_map opt_map[] = {
{ NULL, 0, 0, 0 }
};
-char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption;
+static char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption;
struct string_opt_map {
char *tag;
@@ -233,13 +228,12 @@ parse_opt (const char *opt, int *mask, char *extra_opts)
const struct opt_map *om;
for (om = opt_map; om->opt != NULL; om++)
- if (streq (opt, om->opt))
- {
+ if (streq (opt, om->opt)) {
if (om->inv)
*mask &= ~om->mask;
else
*mask |= om->mask;
- if (om->mask == MS_USER)
+ if (om->mask == MS_USER || om->mask == MS_USERS)
*mask |= MS_SECURE;
#ifdef MS_SILENT
if (om->mask == MS_SILENT && om->inv) {
@@ -284,8 +278,7 @@ parse_opts (char *opts, int *flags, char **extra_opts)
/* Try to build a canonical options string. */
static char *
-fix_opts_string (int flags, char *extra_opts)
-{
+fix_opts_string (int flags, const char *extra_opts, const char *user) {
const struct opt_map *om;
const struct string_opt_map *m;
char *new_opts;
@@ -306,167 +299,14 @@ fix_opts_string (int flags, char *extra_opts)
if (extra_opts && *extra_opts) {
new_opts = xstrconcat3(new_opts, ",", extra_opts);
}
+ if (user) {
+ new_opts = xstrconcat3(new_opts, ",user=", user);
+ }
return new_opts;
}
-/* Most file system types can be recognized by a `magic' number
- in the superblock. Note that the order of the tests is
- significant: by coincidence a filesystem can have the
- magic numbers for several file system types simultaneously.
- For example, the romfs magic lives in the 1st sector;
- xiafs does not touch the 1st sector and has its magic in
- the 2nd sector; ext2 does not touch the first two sectors. */
-
-static inline unsigned short
-swapped(unsigned short a) {
- return (a>>8) | (a<<8);
-}
-
-/*
- char *fstype(const char *device);
-
- Probes the device and attempts to determine the type of filesystem
- contained within.
-
- Original routine by <jmorriso@bogomips.ww.ubc.ca>; made into a function
- for mount(8) by Mike Grupenhoff <kashmir@umiacs.umd.edu>.
- Read the superblock only once - aeb
- Added a test for iso9660 - aeb
- Added a test for high sierra (iso9660) - quinlan@bucknell.edu
- Corrected the test for xiafs - aeb
- Added romfs - aeb
-
- Currently supports: minix, ext, ext2, xiafs, iso9660, romfs
-*/
-char *magic_known[] = { "minix", "ext", "ext2", "xiafs", "iso9660", "romfs" };
-
static int
-tested(const char *device) {
- char **m;
-
- for (m = magic_known; m - magic_known < SIZE(magic_known); m++)
- if (!strcmp(*m, device))
- return 1;
- return 0;
-}
-
-static char *
-fstype(const char *device)
-{
- int fd;
- char *type = NULL;
- union {
- struct minix_super_block ms;
- struct ext_super_block es;
- struct ext2_super_block e2s;
- } sb;
- union {
- struct xiafs_super_block xiasb;
- char romfs_magic[8];
- } xsb;
- union {
- struct iso_volume_descriptor iso;
- struct hs_volume_descriptor hs;
- } isosb;
- struct stat statbuf;
-
- /* opening and reading an arbitrary unknown path can have
- undesired side effects - first check that `device' refers
- to a block device */
- if (stat (device, &statbuf) || !S_ISBLK(statbuf.st_mode))
- return 0;
-
- fd = open(device, O_RDONLY);
- if (fd < 0)
- return 0;
-
- if (lseek(fd, 1024, SEEK_SET) != 1024
- || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb))
- goto io_error;
-
- if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC
- || ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC
- || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC))
- type = "ext2";
-
- else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC
- || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2)
- type = "minix";
-
- else if (extmagic(sb.es) == EXT_SUPER_MAGIC)
- type = "ext";
-
- if (!type) {
- if (lseek(fd, 0, SEEK_SET) != 0
- || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb))
- goto io_error;
-
- if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC)
- type = "xiafs";
- else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8))
- type = "romfs";
- }
-
- if (!type) {
- if (lseek(fd, 0x8000, SEEK_SET) != 0x8000
- || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb))
- goto io_error;
-
- if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0
- || strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0)
- type = "iso9660";
- }
-
- close (fd);
- return(type);
-
-io_error:
- perror(device);
- close(fd);
- return 0;
-}
-
-FILE *procfs;
-
-static void
-procclose(void) {
- if (procfs)
- fclose (procfs);
- procfs = 0;
-}
-
-static int
-procopen(void) {
- return ((procfs = fopen(PROC_FILESYSTEMS, "r")) != NULL);
-}
-
-static char *
-procnext(void) {
- char line[100];
- static char fsname[50];
-
- while (fgets(line, sizeof(line), procfs)) {
- if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
- if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
- return fsname;
- }
- return 0;
-}
-
-static int
-is_in_proc(char *type) {
- char *fsname;
-
- if (procopen()) {
- while ((fsname = procnext()) != NULL)
- if (!strcmp(fsname, type))
- return 1;
- }
- return 0;
-}
-
-static int
-already (char *spec, char *node) {
+already (const char *spec, const char *node) {
struct mntentchn *mc;
int ret = 1;
@@ -488,11 +328,12 @@ create_mtab (void) {
struct mntent mnt;
int flags;
char *extra_opts;
- FILE *fp;
+ mntFILE *mfp;
lock_mtab();
- if ((fp = setmntent (MOUNTED, "a+")) == NULL)
+ mfp = my_setmntent (MOUNTED, "a+");
+ if (mfp == NULL || mfp->mntent_fp == NULL)
die (EX_FILEIO, "mount: can't open %s for writing: %s",
MOUNTED, strerror (errno));
@@ -502,18 +343,18 @@ create_mtab (void) {
mnt.mnt_dir = "/";
mnt.mnt_fsname = canonicalize (fstab->mnt_fsname);
mnt.mnt_type = fstab->mnt_type;
- mnt.mnt_opts = fix_opts_string (flags, extra_opts);
+ mnt.mnt_opts = fix_opts_string (flags, extra_opts, NULL);
mnt.mnt_freq = mnt.mnt_passno = 0;
- if (addmntent (fp, &mnt) == 1)
+ if (my_addmntent (mfp, &mnt) == 1)
die (EX_FILEIO, "mount: error writing %s: %s",
MOUNTED, strerror (errno));
}
- if (fchmod (fileno (fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
+ if (fchmod (fileno (mfp->mntent_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
if (errno != EROFS)
die (EX_FILEIO, "mount: error changing mode of %s: %s",
MOUNTED, strerror (errno));
- endmntent (fp);
+ my_endmntent (mfp);
unlock_mtab();
}
@@ -522,8 +363,9 @@ create_mtab (void) {
static int mountcount = 0;
static int
-mount5 (char *special, char *dir, char *type, int flags, void *data) {
- int ret = mount (special, dir, type, 0xC0ED0000 | (flags), data);
+mount5 (struct mountargs *args) {
+ int ret = mount (args->spec, args->node, args->type,
+ MS_MGC_VAL | (args->flags), args->data);
if (ret == 0)
mountcount++;
return ret;
@@ -534,46 +376,20 @@ mount5 (char *special, char *dir, char *type, int flags, void *data) {
static int
try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) {
- char *fsname;
+ struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts };
if (*type && strcasecmp (*type, "auto") == 0)
*type = NULL;
- if (!*type && !(flags & MS_REMOUNT)) {
- *type = fstype(spec);
- if (verbose) {
- printf ("mount: you didn't specify a filesystem type for %s\n",
- spec);
- if (*type)
- printf (" I will try type %s\n", *type);
- else
- printf (" I will try all types mentioned in %s\n",
- PROC_FILESYSTEMS);
- }
- }
+ if (!*type && !(flags & MS_REMOUNT))
+ *type = guess_fstype_from_superblock(spec);
- if (*type || (flags & MS_REMOUNT))
- return mount5 (spec, node, *type, flags & ~MS_NOSYS, mount_opts);
-
- if (!procopen())
- return -1;
- while ((fsname = procnext()) != NULL) {
- if (tested (fsname))
- continue;
- if (mount5 (spec, node, fsname, flags & ~MS_NOSYS, mount_opts) == 0) {
- *type = xstrdup(fsname);
- procclose();
- return 0;
- } else if (errno != EINVAL) {
- *type = "guess";
- procclose();
- return 1;
- }
+ if (*type || (flags & MS_REMOUNT)) {
+ args.type = *type;
+ return mount5 (&args);
}
- procclose();
- *type = NULL;
- return -1;
+ return procfsloop(mount5, &args, type);
}
/*
@@ -584,9 +400,8 @@ try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) {
* background.
*/
static int
-try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
- int freq, int pass, int bg)
-{
+try_mount_one (const char *spec0, const char *node0, char *type0,
+ const char *opts0, int freq, int pass, int bg) {
struct mntentchn mcn;
struct mntent mnt;
int mnt_err;
@@ -595,7 +410,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
char *mount_opts; /* actually used on system call */
static int added_ro = 0;
int loop, looptype, offset;
- char *spec, *node, *type, *opts, *loopdev, *loopfile;
+ const char *opts;
+ char *spec, *node, *type, *loopdev, *loopfile;
+ char *user = 0;
struct stat statbuf;
spec = xstrdup(spec0);
@@ -606,11 +423,15 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
parse_opts (xstrdup (opts), &flags, &extra_opts);
/* root may allow certain types of mounts by ordinary users */
- if (suid && !(flags & MS_USER)) {
- if (already (spec, node))
- die (EX_USAGE, "mount failed");
- else
- die (EX_USAGE, "mount: only root can mount %s on %s", spec, node);
+ if (suid) {
+ 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();
}
/* quietly succeed for fstab entries that don't get mounted automatically */
@@ -661,8 +482,13 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
if (verbose)
printf("mount: going to use the loop device %s\n", loopdev);
offset = opt_offset ? strtoul(opt_offset, NULL, 0) : 0;
- if (set_loop (loopdev, loopfile, offset, opt_encryption, &loopro))
+ if (set_loop (loopdev, loopfile, offset, opt_encryption, &loopro)) {
+ if (verbose)
+ printf("mount: failed setting up loop device\n");
return EX_FAIL;
+ }
+ if (verbose > 1)
+ printf("mount: setup loop device successfully\n");
spec = loopdev;
if (loopro)
flags |= MS_RDONLY;
@@ -686,7 +512,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
*/
if (type)
#ifndef ALWAYS_STAT
- if (streq (type, "smb") || streq (type, "ncp"))
+ if (streq (type, "smb") || streq (type, "ncp")
+ /* || streq (type, "smbfs") || streq (type, "ncpfs") */
+ )
#else
if (strlen (type) < 100)
#endif
@@ -701,7 +529,7 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
setuid(getuid());
setgid(getgid());
- oo = fix_opts_string (flags, extra_opts);
+ oo = fix_opts_string (flags, extra_opts, NULL);
mountargs[i++] = mountprog;
mountargs[i++] = spec;
mountargs[i++] = node;
@@ -721,7 +549,7 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
wait(&status);
return status;
} else
- error("cannot fork: %s", strerror(errno));
+ error("mount: cannot fork: %s", strerror(errno));
}
}
@@ -737,7 +565,8 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
mcn.mnt_fsname = mnt.mnt_fsname = canonicalize (loop ? loopfile : spec);
mcn.mnt_dir = mnt.mnt_dir = canonicalize (node);
mcn.mnt_type = mnt.mnt_type = type ? type : "unknown";
- mcn.mnt_opts = mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB, extra_opts);
+ mcn.mnt_opts = mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB,
+ extra_opts, user);
mcn.nxt = 0;
mnt.mnt_freq = freq;
mnt.mnt_passno = pass;
@@ -751,16 +580,20 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
if (flags & MS_REMOUNT)
update_mtab (mnt.mnt_dir, &mnt);
else {
- FILE *fp = setmntent(MOUNTED, "a+");
- if (fp == NULL)
+ mntFILE *mfp;
+
+ lock_mtab();
+ mfp = my_setmntent(MOUNTED, "a+");
+ if (mfp == NULL || mfp->mntent_fp == NULL) {
error("mount: can't open %s: %s", MOUNTED,
strerror (errno));
- else {
- if ((addmntent (fp, &mnt)) == 1)
+ } else {
+ if ((my_addmntent (mfp, &mnt)) == 1)
error("mount: error writing %s: %s", MOUNTED,
strerror (errno));
- endmntent(fp);
+ my_endmntent(mfp);
}
+ unlock_mtab();
}
}
@@ -794,6 +627,12 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
case EBUSY:
if (flags & MS_REMOUNT) {
error ("mount: %s is busy", node);
+ } else if (!strcmp(type, "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(!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);
@@ -826,7 +665,7 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
spec);
if (stat (spec, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)
- && (fd = open(spec, O_RDONLY)) >= 0) {
+ && (fd = open(spec, O_RDONLY | O_NONBLOCK)) >= 0) {
if(ioctl(fd, BLKGETSIZE, &size) == 0 && size <= 2)
error (" (aren't you trying to mount an extended partition,\n"
" instead of some logical partition inside?)");
@@ -840,9 +679,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
case EIO:
error ("mount: %s: can't read superblock", spec); break;
case ENODEV:
- if (is_in_proc(type) || !strcmp(type, "guess"))
+ if (is_in_procfs(type) || !strcmp(type, "guess"))
error("mount: %s has wrong major or minor number", spec);
- else if (procfs) {
+ else if (have_procfs()) {
char *lowtype, *p;
int u;
@@ -857,9 +696,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
u++;
}
}
- if (u && is_in_proc(lowtype))
+ if (u && is_in_procfs(lowtype))
error ("mount: probably you meant %s", lowtype);
- else if (!strncmp(lowtype, "iso", 3) && is_in_proc("iso9660"))
+ else if (!strncmp(lowtype, "iso", 3) && is_in_procfs("iso9660"))
error ("mount: maybe you meant iso9660 ?");
free(lowtype);
} else
@@ -893,8 +732,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
type = type0;
}
if (opts) {
- opts = realloc(xstrdup(opts), strlen(opts)+4);
- strcat(opts, ",ro");
+ char *opts1 = realloc(xstrdup(opts), strlen(opts)+4);
+ strcat(opts1, ",ro");
+ opts = opts1;
} else
opts = "ro";
if (type && !strcmp(type, "guess"))
@@ -916,42 +756,56 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
* identified in a "ps" listing.
*/
static void
-set_proc_name (char *spec)
+set_proc_name (const char *spec)
{
#ifdef DO_PS_FIDDLING
- int i, l;
-
- /*
- * Move the environment so we can reuse the memory.
- * (Code borrowed from sendmail.)
- * WARNING: ugly assumptions on memory layout here; if this ever causes
- * problems, #undef DO_PS_FIDDLING
- */
- for (i = 0; envp0[i] != NULL; i++)
- continue;
- environ = (char **) xmalloc(sizeof(char *) * (i + 1));
- for (i = 0; envp0[i] != NULL; i++)
- environ[i] = xstrdup(envp0[i]);
- environ[i] = NULL;
-
- if (i > 0)
- l = envp0[i-1] + strlen(envp0[i-1]) - argv0[0];
- else
- l = argv0[argc0-1] + strlen(argv0[argc0-1]) - argv0[0];
- if (l > sizeof(PROC_NAME)) {
- strcpy(argv0[0], PROC_NAME);
- strncpy(argv0[0] + sizeof(PROC_NAME) - 1, spec, l - sizeof(PROC_NAME) - 1);
- argv0[1] = NULL;
- }
+ setproctitle ("mount", spec);
#endif
}
+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 const char *
+usersubst(const char *opts) {
+ char *s, *w;
+ char id[40];
+
+ s = "uid=useruid";
+ if (opts && (w = strstr(opts, s)) != NULL) {
+ sprintf(id, "uid=%d", getuid());
+ opts = subst_string(opts, w, strlen(s), id);
+ }
+ s = "gid=usergid";
+ if (opts && (w = strstr(opts, s)) != NULL) {
+ sprintf(id, "gid=%d", getgid());
+ opts = subst_string(opts, w, strlen(s), id);
+ }
+ return opts;
+}
+
+
+/*
+ * Return 0 for success (either mounted sth or -a and NOAUTO was given)
+ */
static int
-mount_one (char *spec, char *node, char *type, char *opts, char *cmdlineopts,
- int freq, int pass)
-{
+mount_one (const char *spec, const char *node, char *type, const char *opts,
+ char *cmdlineopts, int freq, int pass) {
int status;
int status2;
+ int specset = 0;
+ char *nspec;
+
+ /* Substitute values in opts, if required */
+ opts = usersubst(opts);
/* Merge the fstab and command line options. */
if (opts == NULL)
@@ -959,6 +813,26 @@ mount_one (char *spec, char *node, char *type, char *opts, char *cmdlineopts,
else if (cmdlineopts != NULL)
opts = xstrconcat3(opts, ",", cmdlineopts);
+ if (!strncmp(spec, "UUID=", 5)) {
+ nspec = get_spec_by_uuid(spec+5);
+ specset = 1;
+ } else if (!strncmp(spec, "LABEL=", 6)) {
+ nspec = get_spec_by_volume_label(spec+6);
+ specset = 2;
+ } else
+ nspec = 0; /* just for gcc */
+
+ if (specset) {
+ if (nspec) {
+ spec = nspec;
+ if (verbose)
+ printf("mount: consider mounting %s by %s\n", spec,
+ (specset==1) ? "UUID" : "label");
+ } else if(!all)
+ die (EX_USAGE, "mount: no such partition found");
+ /* if -a then we may be rescued by a noauto option */
+ }
+
if (type == NULL) {
if (strchr (spec, ':') != NULL) {
type = "nfs";
@@ -1146,10 +1020,11 @@ static struct option longopts[] =
};
const char *usage_string = "\
-usage: mount [-hV]\n\
+Usage: mount [-hV]\n\
mount -a [-nfFrsvw] [-t vfstypes]\n\
mount [-nfrsvw] [-o options] special | node\n\
mount [-nfrsvw] [-t vfstype] [-o options] special node\n\
+A special device can be indicated by -L label or -U uuid .
";
static void
@@ -1162,18 +1037,26 @@ usage (FILE *fp, int n)
int
main (int argc, char *argv[]) {
- int c, result = 0;
- char *options = NULL, *spec;
+ int c, result = 0, specseen;
+ char *options = NULL, *spec, *node;
+ char *volumelabel = NULL;
+ char *uuid = NULL;
string_list types = NULL;
struct mntentchn *mc;
+ int fd;
+
+ /* 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);
#ifdef DO_PS_FIDDLING
- argc0 = argc;
- argv0 = argv;
- envp0 = environ;
+ initproctitle(argc, argv);
#endif
- while ((c = getopt_long (argc, argv, "afFhno:rsvVwt:", longopts, NULL))
+ while ((c = getopt_long (argc, argv, "afFhL:no:rsU:vVwt:", longopts, NULL))
!= EOF)
switch (c) {
case 'a': /* mount everything in fstab */
@@ -1188,6 +1071,9 @@ main (int argc, char *argv[]) {
case 'h': /* help */
usage (stdout, 0);
break;
+ case 'L':
+ volumelabel = optarg;
+ break;
case 'n': /* mount without writing in /etc/mtab */
++nomtab;
break;
@@ -1207,6 +1093,9 @@ main (int argc, char *argv[]) {
case 't': /* specify file system types */
types = parse_list (optarg);
break;
+ case 'U':
+ uuid = optarg;
+ break;
case 'v': /* be chatty - very chatty if repeated */
++verbose;
break;
@@ -1227,7 +1116,9 @@ main (int argc, char *argv[]) {
argc -= optind;
argv += optind;
- if (argc == 0 && !all) {
+ specseen = (uuid || volumelabel) ? 1 : 0; /* yes, .. i know */
+
+ if (argc+specseen == 0 && !all) {
if (options)
usage (stderr, EX_USAGE);
return print_all (types);
@@ -1235,7 +1126,8 @@ main (int argc, char *argv[]) {
if (getuid () != geteuid ()) {
suid = 1;
- if (types || options || readwrite || nomtab || all || fake || argc != 1)
+ if (types || options || readwrite || nomtab || all || fake ||
+ (argc + specseen) != 1)
die (EX_USAGE, "mount: only root can do that");
}
@@ -1245,7 +1137,19 @@ main (int argc, char *argv[]) {
create_mtab ();
}
- switch (argc) {
+ if (specseen) {
+ if (uuid)
+ spec = get_spec_by_uuid(uuid);
+ else
+ spec = get_spec_by_volume_label(volumelabel);
+ if (!spec)
+ die (EX_USAGE, "mount: no such partition found");
+ if (verbose)
+ printf("mount: mounting %s\n", spec);
+ } else
+ spec = NULL; /* just for gcc */
+
+ switch (argc+specseen) {
case 0:
/* mount -a */
result = mount_all (types, options);
@@ -1257,13 +1161,32 @@ main (int argc, char *argv[]) {
/* mount [-nfrvw] [-o options] special | node */
if (types != NULL)
usage (stderr, EX_USAGE);
-
- /* Try to find the other pathname in fstab. */
- spec = canonicalize (*argv);
- if ((mc = getmntfile (spec)) == NULL &&
- (mc = getfsspec (spec)) == NULL && (mc = getfsfile (spec)) == NULL)
- die (EX_USAGE, "mount: can't find %s in %s or %s",
- spec, MOUNTED, _PATH_FSTAB);
+ if (specseen) {
+ /* We know the device. Where shall we mount it? */
+ mc = (uuid ? getfsuuidspec (uuid) : getfsvolspec (volumelabel));
+ if (mc == NULL)
+ mc = getfsspec (spec);
+ if (mc == NULL)
+ die (EX_USAGE, "mount: cannot find %s in %s",
+ spec, _PATH_FSTAB);
+ mc->mnt_fsname = spec;
+ } else {
+ /* Try to find the other pathname in fstab. */
+ spec = canonicalize (*argv);
+ if ((mc = getfsspec (spec)) == NULL &&
+ (mc = getfsfile (spec)) == NULL &&
+ /* Try noncanonical name in fstab
+ perhaps /dev/cdrom or /dos is a symlink */
+ (mc = getfsspec (*argv)) == NULL &&
+ (mc = getfsfile (*argv)) == NULL &&
+ /* Try mtab - maybe this was a remount */
+ (mc = getmntfile (spec)) == NULL)
+ die (EX_USAGE, "mount: can't find %s in %s or %s",
+ spec, _PATH_FSTAB, MOUNTED);
+ /* Earlier mtab was tried first, but this would
+ sometimes try the wrong mount in case mtab had
+ the root device entry wrong. */
+ }
result = mount_one (xstrdup (mc->mnt_fsname), xstrdup (mc->mnt_dir),
xstrdup (mc->mnt_type), mc->mnt_opts, options, 0, 0);
@@ -1271,12 +1194,17 @@ main (int argc, char *argv[]) {
case 2:
/* mount [-nfrvw] [-t vfstype] [-o options] special node */
+ if (specseen) {
+ /* we have spec already */
+ node = argv[0];
+ } else {
+ spec = argv[0];
+ node = argv[1];
+ }
if (types == NULL)
- result = mount_one (argv[0], argv[1],
- NULL, NULL, options, 0, 0);
+ result = mount_one (spec, node, NULL, NULL, options, 0, 0);
else if (cdr (types) == NULL)
- result = mount_one (argv[0], argv[1],
- car (types), NULL, options, 0, 0);
+ result = mount_one (spec, node, car (types), NULL, options, 0, 0);
else
usage (stderr, EX_USAGE);
break;
diff --git a/mount/mount_by_label.c b/mount/mount_by_label.c
new file mode 100644
index 000000000..a48c9de19
--- /dev/null
+++ b/mount/mount_by_label.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "sundries.h" /* for xstrdup */
+#include "linux_fs.h"
+#include "mount_by_label.h"
+
+#define PROC_PARTITIONS "/proc/partitions"
+#define DEVLABELDIR "/dev"
+
+static FILE *procpt;
+
+static void
+procptclose(void) {
+ if (procpt)
+ fclose (procpt);
+ procpt = 0;
+}
+
+static int
+procptopen(void) {
+ return ((procpt = fopen(PROC_PARTITIONS, "r")) != NULL);
+}
+
+static char *
+procptnext(void) {
+ char line[100];
+ char *s;
+ int ma, mi, sz;
+ static char ptname[100];
+
+ while (fgets(line, sizeof(line), procpt)) {
+ if (sscanf (line, " %d %d %d %[^\n]\n", &ma, &mi, &sz, ptname) != 4)
+ continue;
+
+ /* skip extended partitions (heuristic: size 1) */
+ if (sz == 1)
+ continue;
+
+ /* skip entire disk (minor 0, 64, ... on ide; 0, 16, ... on sd) */
+ /* heuristic: partition name ends in a digit */
+ for(s = ptname; *s; s++);
+ if (isdigit(s[-1]))
+ return ptname;
+ }
+ return 0;
+}
+
+#define UUID 1
+#define VOL 2
+
+/* for now, only ext2 is supported */
+static int
+has_right_label(const char *device, int n, const char *label) {
+
+ /* start with a test for ext2, taken from mount_guess_fstype */
+ /* should merge these later */
+ int fd;
+ char *s;
+ struct ext2_super_block e2sb;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ if (lseek(fd, 1024, SEEK_SET) != 1024
+ || read(fd, (char *) &e2sb, sizeof(e2sb)) != sizeof(e2sb)
+ || (ext2magic(e2sb) != EXT2_SUPER_MAGIC)) {
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+
+ /* superblock is ext2 - now what is its label? */
+ s = ((n == UUID) ? e2sb.s_uuid : e2sb.s_volume_name);
+ return (strncmp(s, label, 16) == 0);
+}
+
+static char *
+get_spec_by_x(int n, const char *t) {
+ char *pt;
+ char device[110];
+
+ if(!procptopen())
+ return NULL;
+ while((pt = procptnext()) != NULL) {
+ /* Note: this is a heuristic only - there is no reason
+ why these devices should live in /dev.
+ Perhaps this directory should be specifiable by option.
+ One might for example have /devlabel with links to /dev
+ for the devices that may be accessed in this way.
+ (This is useful, if the cdrom on /dev/hdc must not
+ be accessed.)
+ */
+ sprintf(device, "%s/%s", DEVLABELDIR, pt);
+ if (has_right_label(device, n, t)) {
+ procptclose();
+ return xstrdup(device);
+ }
+ }
+ procptclose();
+ return NULL;
+}
+
+static u_char
+fromhex(char c) {
+ if (isdigit(c))
+ return (c - '0');
+ else if (islower(c))
+ return (c - 'a' + 10);
+ else
+ return (c - 'A' + 10);
+}
+
+char *
+get_spec_by_uuid(const char *s) {
+ u_char uuid[16];
+ int i;
+
+ if (strlen(s) != 36 ||
+ s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-')
+ goto bad_uuid;
+ for (i=0; i<16; i++) {
+ if (*s == '-') s++;
+ if (!isxdigit(s[0]) || !isxdigit(s[1]))
+ goto bad_uuid;
+ uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1]));
+ s += 2;
+ }
+ return get_spec_by_x(UUID, uuid);
+
+ bad_uuid:
+ die(EX_USAGE, "mount: bad UUID");
+}
+
+char *
+get_spec_by_volume_label(const char *s) {
+ return get_spec_by_x(VOL, s);
+}
+
diff --git a/mount/mount_by_label.h b/mount/mount_by_label.h
new file mode 100644
index 000000000..21c2d844b
--- /dev/null
+++ b/mount/mount_by_label.h
@@ -0,0 +1,2 @@
+char *get_spec_by_uuid(const char *uuid);
+char *get_spec_by_volume_label(const char *volumelabel);
diff --git a/mount/mount_constants.h b/mount/mount_constants.h
index 5f033452d..aeb7edfb3 100644
--- a/mount/mount_constants.h
+++ b/mount/mount_constants.h
@@ -1,16 +1,36 @@
+#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_NOATIME
#define MS_NOATIME 1024 /* Do not update access times. */
+#endif
+#ifndef MS_NODIRATIME
#define MS_NODIRATIME 2048 /* Do not update directory access times */
+#endif
/*
* Magic mount flag number. Has 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/mount_guess_fstype.c b/mount/mount_guess_fstype.c
new file mode 100644
index 000000000..b6b9e6582
--- /dev/null
+++ b/mount/mount_guess_fstype.c
@@ -0,0 +1,252 @@
+/*
+ * Thu Jul 14 07:32:40 1994: faith@cs.unc.edu added changes from Adam
+ * J. Richter (adam@adam.yggdrasil.com) so that /proc/filesystems is used
+ * if no -t option is given. I modified his patches so that, if
+ * /proc/filesystems is not available, the behavior of mount is the same as
+ * it was previously.
+ *
+ * Wed Feb 8 09:23:18 1995: Mike Grupenhoff <kashmir@umiacs.UMD.EDU> added
+ * a probe of the superblock for the type before /proc/filesystems is
+ * checked.
+ *
+ * Fri Apr 5 01:13:33 1996: quinlan@bucknell.edu, fixed up iso9660 autodetect
+ *
+ * Wed Nov 11 11:33:55 1998: K.Garloff@ping.de, try /etc/filesystems before
+ * /proc/filesystems
+ *
+ * aeb - many changes.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "linux_fs.h"
+#include "mount_guess_fstype.h"
+#include "sundries.h" /* for xstrdup */
+
+#define ETC_FILESYSTEMS "/etc/filesystems"
+#define PROC_FILESYSTEMS "/proc/filesystems"
+
+#define SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/* Most file system types can be recognized by a `magic' number
+ in the superblock. Note that the order of the tests is
+ significant: by coincidence a filesystem can have the
+ magic numbers for several file system types simultaneously.
+ For example, the romfs magic lives in the 1st sector;
+ xiafs does not touch the 1st sector and has its magic in
+ the 2nd sector; ext2 does not touch the first two sectors. */
+
+static inline unsigned short
+swapped(unsigned short a) {
+ return (a>>8) | (a<<8);
+}
+
+/*
+ char *guess_fstype_from_superblock(const char *device);
+
+ Probes the device and attempts to determine the type of filesystem
+ contained within.
+
+ Original routine by <jmorriso@bogomips.ww.ubc.ca>; made into a function
+ for mount(8) by Mike Grupenhoff <kashmir@umiacs.umd.edu>.
+ Read the superblock only once - aeb
+ Added a test for iso9660 - aeb
+ Added a test for high sierra (iso9660) - quinlan@bucknell.edu
+ Corrected the test for xiafs - aeb
+ Added romfs - aeb
+ Added ufs from a patch by jj. But maybe there are several types of ufs?
+
+ Currently supports: minix, ext, ext2, xiafs, iso9660, romfs, ufs
+*/
+static char
+*magic_known[] = { "minix", "ext", "ext2", "xiafs", "iso9660", "romfs",
+ "ufs" };
+
+static int
+tested(const char *device) {
+ char **m;
+
+ for (m = magic_known; m - magic_known < SIZE(magic_known); m++)
+ if (!strcmp(*m, device))
+ return 1;
+ return 0;
+}
+
+static char *
+fstype(const char *device) {
+ int fd;
+ char *type = NULL;
+ union {
+ struct minix_super_block ms;
+ struct ext_super_block es;
+ struct ext2_super_block e2s;
+ } sb;
+ union {
+ struct xiafs_super_block xiasb;
+ char romfs_magic[8];
+ } xsb;
+ struct ufs_super_block ufssb;
+ union {
+ struct iso_volume_descriptor iso;
+ struct hs_volume_descriptor hs;
+ } isosb;
+ struct stat statbuf;
+
+ /* opening and reading an arbitrary unknown path can have
+ undesired side effects - first check that `device' refers
+ to a block device */
+ if (stat (device, &statbuf) || !S_ISBLK(statbuf.st_mode))
+ return 0;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ if (lseek(fd, 1024, SEEK_SET) != 1024
+ || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb))
+ goto io_error;
+
+ if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC
+ || ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC
+ || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC))
+ type = "ext2";
+
+ else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC
+ || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2)
+ type = "minix";
+
+ else if (extmagic(sb.es) == EXT_SUPER_MAGIC)
+ type = "ext";
+
+ if (!type) {
+ if (lseek(fd, 0, SEEK_SET) != 0
+ || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb))
+ goto io_error;
+
+ if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC)
+ type = "xiafs";
+ else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8))
+ type = "romfs";
+ }
+
+ if (!type) {
+ if (lseek(fd, 8192, SEEK_SET) != 8192
+ || read(fd, (char *) &ufssb, sizeof(ufssb)) != sizeof(ufssb))
+ goto io_error;
+
+ if (ufsmagic(ufssb) == UFS_SUPER_MAGIC) /* also test swapped version? */
+ type = "ufs";
+ }
+
+ if (!type) {
+ if (lseek(fd, 0x8000, SEEK_SET) != 0x8000
+ || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb))
+ goto io_error;
+
+ if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0
+ || strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0)
+ type = "iso9660";
+ }
+
+ close (fd);
+ return(type);
+
+io_error:
+ perror(device);
+ close(fd);
+ return 0;
+}
+
+char *
+guess_fstype_from_superblock(const char *spec) {
+ char *type = fstype(spec);
+ if (verbose) {
+ printf ("mount: you didn't specify a filesystem type for %s\n",
+ spec);
+ if (type)
+ printf (" I will try type %s\n", type);
+ else
+ printf (" I will try all types mentioned in %s or %s\n",
+ ETC_FILESYSTEMS, PROC_FILESYSTEMS);
+ }
+ return type;
+}
+
+static FILE *procfs;
+
+static void
+procfsclose(void) {
+ if (procfs)
+ fclose (procfs);
+ procfs = 0;
+}
+
+static int
+procfsopen(void) {
+ procfs = fopen(ETC_FILESYSTEMS, "r");
+ if (!procfs)
+ procfs = fopen(PROC_FILESYSTEMS, "r");
+ return (procfs != NULL);
+}
+
+static char *
+procfsnext(void) {
+ char line[100];
+ static char fsname[50];
+
+ while (fgets(line, sizeof(line), procfs)) {
+ if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
+ if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
+ return fsname;
+ }
+ return 0;
+}
+
+int
+is_in_procfs(const char *type) {
+ char *fsname;
+
+ if (procfsopen()) {
+ while ((fsname = procfsnext()) != NULL)
+ if (!strcmp(fsname, type))
+ return 1;
+ }
+ return 0;
+}
+
+int
+procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args,
+ char **type) {
+ char *fsname;
+
+ if (!procfsopen())
+ return -1;
+ while ((fsname = procfsnext()) != NULL) {
+ if (tested (fsname))
+ continue;
+ args->type = fsname;
+ if ((*mount_fn) (args) == 0) {
+ *type = xstrdup(fsname);
+ procfsclose();
+ return 0;
+ } else if (errno != EINVAL) {
+ *type = "guess";
+ procfsclose();
+ return 1;
+ }
+ }
+ procfsclose();
+ *type = NULL;
+
+ return -1;
+}
+
+int
+have_procfs(void) {
+ return procfs != NULL;
+}
diff --git a/mount/mount_guess_fstype.h b/mount/mount_guess_fstype.h
new file mode 100644
index 000000000..3663f74ca
--- /dev/null
+++ b/mount/mount_guess_fstype.h
@@ -0,0 +1,15 @@
+struct mountargs {
+ const char *spec;
+ const char *node;
+ const char *type;
+ int flags;
+ void *data;
+};
+
+extern int verbose;
+
+char *guess_fstype_from_superblock(const char *device);
+int procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args,
+ char **type);
+int is_in_procfs(const char *fstype);
+int have_procfs(void);
diff --git a/mount/nfsmount.c b/mount/nfsmount.c
index fd9364669..dd55d75a5 100644
--- a/mount/nfsmount.c
+++ b/mount/nfsmount.c
@@ -151,10 +151,17 @@ int nfsmount(const char *spec, const char *node, int *flags,
goto fail;
}
strcpy(hostdir, spec);
- if ((s = (strchr(hostdir, ':')))) {
+ if ((s = strchr(hostdir, ':'))) {
hostname = hostdir;
dirname = s + 1;
*s = '\0';
+ /* Ignore all but first hostname in replicated mounts
+ until they can be fully supported. (mack@sgi.com) */
+ if ((s = strchr(hostdir, ','))) {
+ *s = '\0';
+ fprintf(stderr, "mount: warning: "
+ "multiple hostnames not supported\n");
+ }
} else {
fprintf(stderr, "mount: "
"directory to mount not in host:dir format\n");
@@ -272,17 +279,24 @@ int nfsmount(const char *spec, const char *node, int *flags,
mountvers = val;
else if (!strcmp(opt, "nfsprog"))
nfsprog = val;
- else if (!strcmp(opt, "nfsvers"))
+ else if (!strcmp(opt, "nfsvers") ||
+ !strcmp(opt, "vers"))
nfsvers = val;
- else if (!strcmp(opt, "namlen")) {
+ else if (!strcmp(opt, "proto")) {
+ if (!strncmp(opteq+1, "tcp", 3))
+ tcp = 1;
+ else if (!strncmp(opteq+1, "udp", 3))
+ tcp = 0;
+ else
+ printf("Warning: Unrecognized proto= option.\n");
+ } else if (!strcmp(opt, "namlen")) {
#if NFS_MOUNT_VERSION >= 2
if (nfs_mount_version >= 2)
data.namlen = val;
else
#endif
printf("Warning: Option namlen is not supported.\n");
- }
- else if (!strcmp(opt, "addr"))
+ } else if (!strcmp(opt, "addr"))
/* ignore */;
else {
printf("unknown nfs mount parameter: "
diff --git a/mount/nfsmount_xdr.c b/mount/nfsmount_xdr.c
index 6f539c24f..91fbeec6a 100644
--- a/mount/nfsmount_xdr.c
+++ b/mount/nfsmount_xdr.c
@@ -3,6 +3,9 @@
* It was generated using rpcgen.
*/
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
#include "nfsmount.h"
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
@@ -40,9 +43,7 @@
/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */
bool_t
-xdr_fhandle(xdrs, objp)
- XDR *xdrs;
- fhandle objp;
+xdr_fhandle(XDR *xdrs, fhandle objp)
{
register long *buf;
@@ -54,9 +55,7 @@ xdr_fhandle(xdrs, objp)
}
bool_t
-xdr_fhstatus(xdrs, objp)
- XDR *xdrs;
- fhstatus *objp;
+xdr_fhstatus(XDR *xdrs, fhstatus *objp)
{
register long *buf;
@@ -70,14 +69,14 @@ xdr_fhstatus(xdrs, objp)
return (FALSE);
}
break;
+ default:
+ break;
}
return (TRUE);
}
bool_t
-xdr_dirpath(xdrs, objp)
- XDR *xdrs;
- dirpath *objp;
+xdr_dirpath(XDR *xdrs, dirpath *objp)
{
register long *buf;
@@ -89,9 +88,7 @@ xdr_dirpath(xdrs, objp)
}
bool_t
-xdr_name(xdrs, objp)
- XDR *xdrs;
- name *objp;
+xdr_name(XDR *xdrs, name *objp)
{
register long *buf;
@@ -103,9 +100,7 @@ xdr_name(xdrs, objp)
}
bool_t
-xdr_mountlist(xdrs, objp)
- XDR *xdrs;
- mountlist *objp;
+xdr_mountlist(XDR *xdrs, mountlist *objp)
{
register long *buf;
@@ -117,9 +112,7 @@ xdr_mountlist(xdrs, objp)
}
bool_t
-xdr_mountbody(xdrs, objp)
- XDR *xdrs;
- mountbody *objp;
+xdr_mountbody(XDR *xdrs, mountbody *objp)
{
register long *buf;
@@ -137,9 +130,7 @@ xdr_mountbody(xdrs, objp)
}
bool_t
-xdr_groups(xdrs, objp)
- XDR *xdrs;
- groups *objp;
+xdr_groups(XDR *xdrs, groups *objp)
{
register long *buf;
@@ -151,9 +142,7 @@ xdr_groups(xdrs, objp)
}
bool_t
-xdr_groupnode(xdrs, objp)
- XDR *xdrs;
- groupnode *objp;
+xdr_groupnode(XDR *xdrs, groupnode *objp)
{
register long *buf;
@@ -168,9 +157,7 @@ xdr_groupnode(xdrs, objp)
}
bool_t
-xdr_exports(xdrs, objp)
- XDR *xdrs;
- exports *objp;
+xdr_exports(XDR *xdrs, exports *objp)
{
register long *buf;
@@ -182,9 +169,7 @@ xdr_exports(xdrs, objp)
}
bool_t
-xdr_exportnode(xdrs, objp)
- XDR *xdrs;
- exportnode *objp;
+xdr_exportnode(XDR *xdrs, exportnode *objp)
{
register long *buf;
@@ -202,9 +187,7 @@ xdr_exportnode(xdrs, objp)
}
bool_t
-xdr_ppathcnf(xdrs, objp)
- XDR *xdrs;
- ppathcnf *objp;
+xdr_ppathcnf(XDR *xdrs, ppathcnf *objp)
{
register long *buf;
diff --git a/mount/sundries.c b/mount/sundries.c
index 4506924aa..d7ace1b2d 100644
--- a/mount/sundries.c
+++ b/mount/sundries.c
@@ -29,12 +29,12 @@ xmalloc (size_t size) {
void *t;
if (size == 0)
- return NULL;
+ return NULL;
t = malloc (size);
if (t == NULL)
- die (EX_SYSERR, "not enough memory");
-
+ die (EX_SYSERR, "not enough memory");
+
return t;
}
@@ -43,12 +43,12 @@ xstrdup (const char *s) {
char *t;
if (s == NULL)
- return NULL;
-
+ return NULL;
+
t = strdup (s);
if (t == NULL)
- die (EX_SYSERR, "not enough memory");
+ die (EX_SYSERR, "not enough memory");
return t;
}
diff --git a/mount/swap.configure b/mount/swap.configure
index a557e1871..ebd67ced6 100644
--- a/mount/swap.configure
+++ b/mount/swap.configure
@@ -1,24 +1,36 @@
# Find out whether we can include <sys/swap.h>
# and whether libc thinks that swapon() has two arguments.
-# Of course this will fail if <sys/swap.h> exists but belongs
-# to a libc that is not in use at present.
+
+# Prepare test
CC=${CC-cc}
compile="$CC -o conftest conftest.c >/dev/null 2>&1"
rm -f conftest conftest.c swapargs.h
+
+# What include files shall we try?
+# Unfortunately, recent versions of swap.h use PAGE_SIZE and hence need page.h
+# It is used only in mkswap, not in swapon/swapoff, so we might just pick any
+# random value (like #define PAGE_SIZE 4096) instead of including page.h.
SWAPH=
-if [ -f /usr/include/sys/swap.h ]; then SWAPH="#include <sys/swap.h>"; fi
-echo $SWAPH > conftest.c
+PAGEH=
+if [ -f /usr/include/sys/swap.h ]; then
+ SWAPH="#include <sys/swap.h>"
+ if [ -f /usr/include/asm/page.h ]; then
+ PAGEH="#include <asm/page.h>"
+ fi
+fi
+echo $PAGEH > conftest.c
+echo $SWAPH >> conftest.c
echo '#include <unistd.h>
main(){ exit(0); swapon("/dev/null", 0); }' >> conftest.c
eval $compile
if test -s conftest && ./conftest 2>/dev/null; then
echo "#define SWAPON_HAS_TWO_ARGS" > swapargs.h
+ echo $PAGEH >> swapargs.h
echo $SWAPH >> swapargs.h
else
echo > swapargs.h
echo "
Your libc thinks that swapon has 1 arg only.
-Define SWAPON_NEEDS_TWO_ARGS in swapon.c if you want to use priorities.
" 1>&2
fi
rm -f conftest conftest.c
diff --git a/mount/swap_constants.h b/mount/swap_constants.h
new file mode 100644
index 000000000..c7e8b4c7e
--- /dev/null
+++ b/mount/swap_constants.h
@@ -0,0 +1,15 @@
+/*
+ * It is too painful to get these out of <linux/swap.h>
+ * (which again requires <asm/page.h> etc).
+ * These exist since Linux 1.3.2.
+ */
+
+#ifndef SWAP_FLAG_PREFER
+#define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */
+#endif
+#ifndef SWAP_FLAG_PRIO_MASK
+#define SWAP_FLAG_PRIO_MASK 0x7fff
+#endif
+#ifndef SWAP_FLAG_PRIO_SHIFT
+#define SWAP_FLAG_PRIO_SHIFT 0
+#endif
diff --git a/mount/swapon.8 b/mount/swapon.8
index 0ebb450a8..74f61eea4 100644
--- a/mount/swapon.8
+++ b/mount/swapon.8
@@ -74,7 +74,10 @@ Provide help
Display version
.TP
.B \-s
-Display swap usage summary by device
+Display swap usage summary by device.
+This option is only available if
+.I /proc/swaps
+exists (probably not before kernel 2.1.25).
.TP
.B \-a
All devices marked as ``sw'' swap devices in
@@ -104,6 +107,10 @@ entries in
when the
.B \-a
flag is given.
+.SH NOTE
+You should not use
+.B swapon
+on a file with holes.
.SH SEE ALSO
.BR swapon "(2), " swapoff "(2), " fstab "(5), " init "(8), " mkswap (8),
.BR rc "(8), " mount (8)
@@ -120,8 +127,3 @@ ascii filesystem description table
The
.B swapon
command appeared in 4.0BSD.
-.SH AUTHORS
-See the Linux
-.BR mount (8)
-man page for a complete author list. Primary contributors include Doug
-Quale, H. J. Lu, Rick Sladkey, and Stephen Tweedie.
diff --git a/mount/swapon.c b/mount/swapon.c
index 5fdd15c5d..41d1f3fce 100644
--- a/mount/swapon.c
+++ b/mount/swapon.c
@@ -10,7 +10,8 @@
#include <string.h>
#include <mntent.h>
#include <errno.h>
-#include "swap.h"
+#include <sys/stat.h>
+#include "swap_constants.h"
#include "swapargs.h"
#define streq(s, t) (strcmp ((s), (t)) == 0)
@@ -18,7 +19,7 @@
#define _PATH_FSTAB "/etc/fstab"
#define PROC_SWAPS "/proc/swaps"
-/* #define SWAPON_NEEDS_TWO_ARGS */
+#define SWAPON_NEEDS_TWO_ARGS
/* Nonzero for chatty (-v). This is a nonstandard flag (not in BSD). */
int verbose = 0;
@@ -77,12 +78,34 @@ static int
swap (const char *special, int prio)
{
int status;
+ struct stat st;
if (verbose)
- printf("%s on device %s\n", program_name, special);
+ printf("%s on %s\n", program_name, special);
if (streq (program_name, "swapon")) {
+ if (stat(special, &st) < 0) {
+ fprintf (stderr, "swapon: cannot stat %s: %s\n", special, strerror (errno));
+ return -1;
+ }
+
+ if ((st.st_mode & 07077) != 0) {
+ fprintf(stderr, "swapon: warning: %s has insecure permissions %04o, "
+ "0600 suggested\n", special, st.st_mode & 07777);
+ }
+
+ /* test for holes by LBT */
+ if (S_ISREG(st.st_mode)) {
+ if (st.st_blocks * 512 < st.st_size) {
+ fprintf(stderr,
+ "swapon: Skipping file %s - it appears to have holes.\n",
+ special);
+ return -1;
+ }
+ }
+
#ifdef SWAPON_NEEDS_TWO_ARGS
+ {
int flags = 0;
#ifdef SWAP_FLAG_PREFER
@@ -94,6 +117,7 @@ swap (const char *special, int prio)
}
#endif
status = swapon (special, flags);
+ }
#else
status = swapon (special);
#endif
diff --git a/mount/umount.c b/mount/umount.c
index 6f28213b4..ac233a70b 100644
--- a/mount/umount.c
+++ b/mount/umount.c
@@ -18,6 +18,10 @@
* 960823: aeb - also try umount(spec) when umount(node) fails
* 970307: aeb - canonise names from fstab
* 970726: aeb - remount read-only in cases where umount fails
+ * 980810: aeb - umount2 support
+ * 981222: aeb - If mount point or special file occurs several times
+ * in mtab, try them all, with last one tried first
+ * - Differentiate "user" and "users" key words in fstab
*/
#include <unistd.h>
@@ -28,6 +32,7 @@
#include <sys/mount.h>
#include "mount_constants.h"
#include "sundries.h"
+#include "getusername.h"
#include "lomount.h"
#include "loop.h"
#include "fstab.h"
@@ -43,11 +48,33 @@
#include <arpa/inet.h>
#endif
+static int umount2(const char *path, int flags);
-#ifdef notyet
-/* Nonzero for force umount (-f). This needs kernel support we don't have. */
+#ifdef 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
+_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 */
+
+/* dare not try to include <linux/mount.h> -- lots of errors */
+#define MNT_FORCE 1
+
+#endif /* MNT_FORCE */
+
+/* Nonzero for force umount (-f). There is kernel support since 2.1.116. */
int force = 0;
-#endif
/* When umount fails, attempt a read-only remount (-r). */
int remount = 0;
@@ -169,7 +196,7 @@ static void complain(int err, const char *dev) {
on a non-fatal error. We lock/unlock around each umount. */
static int
umount_one (const char *spec, const char *node, const char *type,
- const char *opts)
+ const char *opts, struct mntentchn *mc)
{
int umnt_err, umnt_err2;
int isroot;
@@ -195,7 +222,22 @@ umount_one (const char *spec, const char *node, const char *type,
umnt_err = umnt_err2 = 0;
- res = umount (node);
+ if (force) {
+ /* completely untested - 2.1.116 only has some support in nfs case */
+ /* probably this won't work */
+ int flags = MNT_FORCE;
+
+ res = umount2 (node, flags);
+ if (res == -1) {
+ perror("umount2");
+ if (errno == ENOSYS) {
+ if (verbose)
+ printf("no umount2, trying umount...\n");
+ res = umount (node);
+ }
+ }
+ } else
+ res = umount (node);
if (res < 0) {
umnt_err = errno;
/* A device might have been mounted on a node that has since
@@ -238,11 +280,9 @@ umount_one (const char *spec, const char *node, const char *type,
printf ("%s umounted\n", spec);
if (!nomtab && mtab_is_writable()) {
- struct mntentchn *mc;
/* Special stuff for loop devices */
-
- if ((mc = getmntfile (spec)) || (mc = getmntfile (node))) {
- char *opts;
+ if (mc) {
+ char *optl;
/* old style mtab line? */
if (streq(mc->mnt_type, "loop"))
@@ -250,10 +290,10 @@ umount_one (const char *spec, const char *node, const char *type,
goto fail;
/* new style mtab line? */
- opts = mc->mnt_opts ? xstrdup(mc->mnt_opts) : "";
- for (opts = strtok (opts, ","); opts; opts = strtok (NULL, ",")) {
- if (!strncmp(opts, "loop=", 5)) {
- if (del_loop(opts+5))
+ optl = mc->mnt_opts ? xstrdup(mc->mnt_opts) : "";
+ for (optl = strtok (optl, ","); optl; optl = strtok (NULL, ",")) {
+ if (!strncmp(optl, "loop=", 5)) {
+ if (del_loop(optl+5))
goto fail;
break;
}
@@ -286,6 +326,28 @@ fail:
return 1;
}
+/*
+ * 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 *mc) {
+ int res = 1;
+
+ while (res && mc) {
+ res = umount_one(mc->mnt_fsname, mc->mnt_dir,
+ mc->mnt_type, mc->mnt_opts, mc);
+ mc = getmntfilesbackward (file, mc);
+ }
+ return res;
+}
+
/* Unmount all filesystems of type VFSTYPES found in mtab. Since we are
concurrently updating mtab after every succesful umount, we have to
slurp in the entire file before we start. This isn't too bad, because
@@ -302,7 +364,7 @@ umount_all (string_list types) {
for (mc = hd->prev; mc != hd; mc = mc->prev) {
if (matching_type (mc->mnt_type, types)) {
errors |= umount_one (mc->mnt_fsname, mc->mnt_dir,
- mc->mnt_type, mc->mnt_opts);
+ mc->mnt_type, mc->mnt_opts, mc);
}
}
@@ -325,9 +387,9 @@ static struct option longopts[] =
};
char *usage_string = "\
-usage: umount [-hV]\n\
- umount -a [-r] [-n] [-v] [-t vfstypes]\n\
- umount [-r] [-n] [-v] special | node...\n\
+Usage: umount [-hV]\n\
+ umount -a [-f] [-r] [-n] [-v] [-t vfstypes]\n\
+ umount [-f] [-r] [-n] [-v] special | node...\n\
";
static void
@@ -350,22 +412,19 @@ main (int argc, char *argv[])
char *file;
int result = 0;
- while ((c = getopt_long (argc, argv, "afhnrvVt:", longopts, NULL)) != EOF)
+ while ((c = getopt_long (argc, argv, "afhnrt:vV",
+ longopts, NULL)) != EOF)
switch (c) {
case 'a': /* umount everything */
++all;
break;
- case 'f': /* force umount (needs kernel support) */
-#if 0
+ case 'f': /* force umount */
++force;
-#else
- die (2, "umount: forced umount not supported yet");
-#endif
break;
case 'h': /* help */
usage (stdout, 0);
break;
- case 'n':
+ case 'n': /* do not write in /etc/mtab */
++nomtab;
break;
case 'r': /* remount read-only if umount fails */
@@ -390,7 +449,7 @@ main (int argc, char *argv[])
if (getuid () != geteuid ())
{
suid = 1;
- if (all || types || nomtab)
+ if (all || types || nomtab || force)
die (2, "umount: only root can do that");
}
@@ -408,13 +467,15 @@ main (int argc, char *argv[])
if (verbose > 1)
printf("Trying to umount %s\n", file);
- mc = getmntfile (file);
+ mc = getmntfilesbackward (file, NULL);
if (!mc && verbose)
printf("Could not find %s in mtab\n", file);
if (suid) {
if (!mc)
die (2, "umount: %s is not mounted (according to mtab)", file);
+ if (getmntfilesbackward (file, mc))
+ die (2, "umount: it seems %s is mounted multiple times", file);
if (!(fs = getfsspec (file)) && !(fs = getfsfile (file)))
die (2, "umount: %s is not in the fstab (and you are not root)",
file);
@@ -424,22 +485,46 @@ main (int argc, char *argv[])
!streq (mc->mnt_dir, canonicalize (fs->mnt_dir)))) {
die (2, "umount: %s mount disagrees with the fstab", file);
}
+
+ /* User mounting and unmounting is allowed only
+ if fstab contains the option `user' or `users' */
+ /* The option `users' allows arbitrary users to mount
+ and unmount - this may be a security risk. */
+ /* The option `user' only allows unmounting by the user
+ that mounted. */
+ /* A convenient side effect is that the user who mounted
+ is visible in mtab. */
options = parse_list (fs->mnt_opts);
while (options) {
- if (streq (car (options), "user"))
+ if (streq (car (options), "user") ||
+ streq (car (options), "users"))
break;
options = cdr (options);
}
if (!options)
die (2, "umount: only root can unmount %s from %s",
fs->mnt_fsname, fs->mnt_dir);
+ if (streq (car (options), "user")) {
+ char *user = getusername();
+
+ options = parse_list (mc->mnt_opts);
+ while (options) {
+ char *co = car (options);
+ if (!strncmp(co, "user=", 5)) {
+ if (!user || !streq(co+5,user))
+ die(2, "umount: only %s can unmount %s from %s",
+ co+5, fs->mnt_fsname, fs->mnt_dir);
+ break;
+ }
+ options = cdr (options);
+ }
+ }
}
if (mc)
- result = umount_one (xstrdup(mc->mnt_fsname), xstrdup(mc->mnt_dir),
- xstrdup(mc->mnt_type), xstrdup(mc->mnt_opts));
+ result = umount_one_bw (file, mc);
else
- result = umount_one (*argv, *argv, *argv, *argv);
+ result = umount_one (*argv, *argv, *argv, *argv, NULL);
argv++;
diff --git a/mount/version.c b/mount/version.c
index 0c9363d37..790c447bf 100644
--- a/mount/version.c
+++ b/mount/version.c
@@ -1 +1,2 @@
-char version[] = "mount-2.8";
+#include "../version.h"
+char version[] = "mount-" UTIL_LINUX_VERSION;