summaryrefslogtreecommitdiffstats
path: root/mount
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:32 +0100
committerKarel Zak2006-12-07 00:25:32 +0100
commit6dbe3af945a63f025561abb83275cee9ff06c57b (patch)
tree19e59eac8ac465b5bc409b5adf815b582c92f633 /mount
downloadkernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.tar.gz
kernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.tar.xz
kernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.zip
Imported from util-linux-2.2 tarball.
Diffstat (limited to 'mount')
-rw-r--r--mount/Makefile93
-rw-r--r--mount/README.mount147
-rw-r--r--mount/fstab.5168
-rw-r--r--mount/fstab.c92
-rw-r--r--mount/fstab.h25
-rw-r--r--mount/lomount.c223
-rw-r--r--mount/loop.h77
-rw-r--r--mount/mount.8589
-rw-r--r--mount/mount.c734
-rw-r--r--mount/mount.h208
-rw-r--r--mount/mount.x161
-rw-r--r--mount/mount_clnt.c94
-rw-r--r--mount/mount_xdr.c150
-rw-r--r--mount/nfs.5209
-rw-r--r--mount/nfsmount.c475
-rw-r--r--mount/realpath.c178
-rw-r--r--mount/rpcsvc/mount.h208
-rw-r--r--mount/rpcsvc/mount.x161
-rw-r--r--mount/rpcsvc/mount_clnt.c94
-rw-r--r--mount/rpcsvc/mount_xdr.c150
-rw-r--r--mount/sundries.c283
-rw-r--r--mount/sundries.h90
-rw-r--r--mount/swapoff.81
-rw-r--r--mount/swapon.894
-rw-r--r--mount/swapon.c109
-rw-r--r--mount/umount.81
-rw-r--r--mount/umount.c353
-rw-r--r--mount/version.c1
28 files changed, 5168 insertions, 0 deletions
diff --git a/mount/Makefile b/mount/Makefile
new file mode 100644
index 000000000..737c716ab
--- /dev/null
+++ b/mount/Makefile
@@ -0,0 +1,93 @@
+# To make "ext" the default file system type for mount
+# (used when no other type is specified), replace \"minix\" by \"ext2\".
+DEFAULT_FSTYPE=\"minix\"
+
+# you need rpcgen and libc-4.2 or rpclib to compile in the NFS support
+DEFINES = -DHAVE_NFS -DFSTYPE_DEFAULT=$(DEFAULT_FSTYPE)
+
+include ../MCONFIG
+#CC = gcc
+#OPTFLAGS= -O2 -m486 -fomit-frame-pointer
+##OPTFLAGS= -O2 -fomit-frame-pointer # or change on make's command line
+#CFLAGS = -pipe $(OPTFLAGS)
+WARNFLAGS = -Wall -Wstrict-prototypes -Wmissing-prototypes
+#LDFLAGS = -s -N
+LDLIBS =
+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
+#prefix = /usr
+
+## for suid progs (mount, umount)
+#BINDIR = /bin
+## for nosuid progs (swapon)
+#SBINDIR = /etc
+
+# End of configuration section.
+
+COMPILE = $(CC) -c $(WARNFLAGS) $(CFLAGS) $(DEFINES)
+LINK = $(CC) $(LDFLAGS)
+
+SUID_PROGS = mount umount
+NOSUID_PROGS = swapon
+PROGS = $(SUID_PROGS) $(NOSUID_PROGS)
+MAN5 = fstab.5 nfs.5
+MAN8 = mount.8 swapoff.8 swapon.8 umount.8
+
+# comment these out if you are not compiling in NFS support
+NFS_OBJS = nfsmount.o mount_xdr.o mount_clnt.o
+# uncomment this if you don't have libc-4.2 but do have the rpclib
+GEN_FILES = mount.x mount.h mount_xdr.c mount_clnt.c
+
+# comment these out if you are not compiling in loop support
+LO_OBJS=lomount.o
+
+all: $(PROGS)
+
+install: $(PROGS)
+ $(INSTALLDIR) $(BINDIR) $(SBINDIR)
+ $(INSTALLSUID) -s $(SUID_PROGS) $(BINDIR)
+ $(INSTALLBIN) -s $(NOSUID_PROGS) $(SBINDIR)
+ (cd $(SBINDIR); ln -sf swapon swapoff)
+ $(INSTALLDIR) $(MAN5DIR) $(MAN8DIR)
+ $(INSTALLMAN) $(MAN5) $(MAN5DIR)
+ $(INSTALLMAN) $(MAN8) $(MAN8DIR)
+
+.c.o:
+ $(COMPILE) $<
+
+mount: mount.o fstab.o sundries.o version.o $(NFS_OBJS) $(LO_OBJS)
+ $(LINK) $^ $(LDLIBS) -o $@
+
+umount: umount.o fstab.o sundries.o version.o $(LO_OBJS)
+ $(LINK) $^ $(LDLIBS) -o $@
+
+swapon: swapon.o fstab.o version.o
+ $(LINK) $^ $(LDLIBS) -o $@
+
+nfsmount.o mount_xdr.o mount_clnt.o: mount.h
+
+mount_clnt.o: mount_clnt.c
+ $(COMPILE) $(RPC_CFLAGS) mount_clnt.c
+
+mount_xdr.o: mount_xdr.c
+ $(COMPILE) $(RPC_CFLAGS) mount_xdr.c
+
+mount.h mount_xdr.c mount_clnt.c: mount.x
+ rm -f mount.h mount_xdr.c mount_clnt.c
+ $(RPCGEN) -h -o mount.h mount.x
+ $(RPCGEN) -c -o mount_xdr.c mount.x
+ $(RPCGEN) -l -o mount_clnt.c mount.x
+
+mount.x:
+ cp $(RPCSVCDIR)/mount.x .
+
+clean:
+ rm -f a.out core *~ *.o $(PROGS)
+
+clobber: clean
+ rm -f $(PROGS) $(GEN_FILES)
diff --git a/mount/README.mount b/mount/README.mount
new file mode 100644
index 000000000..9bea2dc2e
--- /dev/null
+++ b/mount/README.mount
@@ -0,0 +1,147 @@
+mount/umount for Linux 0.99.14
+==============================
+
+Enhance nfsmount.c to allow the program number or port number
+to be specified for both the mount daemon and the nfs daemon.
+Also anticipate tcp and namelen support.
+
+Rewrite canonicalize in terms of realpath. Don't be obsessive about
+the path pre-existing for nfs, ifs, none, etc.
+
+Fix memory overwriting bug in the new remount code.
+
+Fix mtab handling in the new remount code so entries appear
+exactly once and in their proper mounting order.
+
+Fix defaults, remount and noauto so these options don't appear in the mtab.
+
+Repair extra options handling that got damaged with the remount code.
+
+Handle combining -o from the command line with options specified
+in /etc/mtab or /etc/fstab.
+
+Fix completely broken file-locking.
+
+Beautify the options field so it contains no duplicates or redundancies.
+
+Added long-style options to all programs.
+
+Added version and help options to all programs.
+
+Brought the Makefile up to GNU standards regarding CFLAGS and LDLFLAGS.
+
+Added support for the `user' option where mount and umount run suid to root.
+
+Rick Sladkey <jrs@world.std.com>
+
+mount/umount for Linux 0.99.10
+==============================
+
+[Stephen Tweedie <sct@dcs.ed.ac.uk>]
+
+A number of changes introduced to cater for new kernel facilities.
+mount can now remount an already-mounted filesystem, and umount
+attempts to unmount even root filesystems. Supercedes the [u]mount
+previously available in the bootutils-0.1 collection.
+
+Fixed a minor bug in canonicalise().
+
+mount/umount/swapon/swapoff(8) for Linux 0.99.6
+===============================================
+
+Here is a minor update to the previous version that fixes
+a longstanding "off by one" bug in parsing fs-specific
+options. No other real changes.
+
+mount/umount/swapon/swapoff(8) for Linux 0.99.2
+===============================================
+
+Here is a new version of Doug Quale's mount/umount package that
+includes support for mounting and unmount NFS filesystems. It is
+still possible to compile it without NFS support by modifying the
+Makefile. Even if you don't have rpcgen, but do have libc-4.2
+you can "cp -p" the pre-generated files in the rpcsvc directory
+into the mount source directory.
+
+The primary difference besides the actual NFS mounting code is that
+mount understands hostname:/path syntax for the "device" as well as
+the new keyword "none" which is useful for the proc filesystem. Also,
+umount had to be trained to specify the mount-point instead of the
+device when unmounting such filesystems. For compatibility,
+filesystems with true devices are unmounted using their device name
+which will still work with older kernels. However, all umounts could
+just as well be done by specifying the mount point instead of the
+device.
+
+Other changes since the beta NFS mount are:
+
+* incorportated H.J. Lu's changes for mtab permissions and errno handling
+* corrected the error message for unhandled errors from mount and umount
+* improved (a little :-) the reporting of handled mount and umount errors
+* added the ability to NFS mount from a IP address as well as a hostname
+* added a string error message instead of numeric for failed NFS mounts
+* changed 32 to _NSIG when setting all signals (should be using sigismember)
+* eliminated the obsolete HAVE_MOUNT5 and HAVE_SWAPOFF ifdefs
+* added support for the sync and async mount options
+* added the noauto option for fstab entries that shouldn't get mounted with -a
+* changed mount -a to check the mtab for already mounted filesystems
+* eliminated a few new warning messages from gcc 2.3.3
+* wrote an nfs man page
+
+Features still missing:
+
+* ability to background NFS mounts that have timed out
+* notify the NFS server of umounts (but addr=ip-addr support is in there)
+* add the possibility of interrupting an in-progress mount
+* man pages for the other Linux filesystem types
+
+Rick Sladkey
+jrs@world.std.com
+===============================================
+mount/umount/swapon/swapoff(8) for Linux 0.98.5
+===============================================
+
+This version fixed the umask of root. fchmod () is called
+before close /etc/mtab. This version should work with
+0.97.3 or above, although I only tested it under 0.98.5.
+I also fixed the error report.
+
+H.J. Lu
+hlu@eecs.wsu.edu
+11/25/92
+===============================================
+mount/umount/swapon/swapoff(8) for Linux 0.97.3
+===============================================
+
+The most significant improvement over the first release is the repair of
+at least a half dozen really dumb bugs, mostly involving null pointers.
+These bugs caused frequent core dumps and really made the code unusable.
+
+Some race conditions in the lock handling code have been removed.
+
+Swapoff is available for 0.97.3 and later kernels.
+
+Swapon supports multiple swap files. In particular, swapon -a will try
+to enable swapping on all the swap entries in /etc/fstab.
+
+File system specific mount options are now supported. This is of particular
+utility with Werner Almesberger's msdos fs.
+
+Umount -a now reads /etc/mtab instead of /etc/fstab (thanks to David
+Engel for a valuable discussion on this and other points). In addition,
+it umounts the entries in reverse order, ensuring that it tries to umount
+/usr/spool before /usr, for instance.
+
+Mount will now print mtab for ordinary users as well as for the superuser.
+Several people pointed out this deficiency, and it was a real no-brainer
+that broke it in the first release.
+
+Thanks to Linus, for another great release. 0.97.3 compiled the first time
+out and is working flawlessly. Thanks also to Ross Biro, for his work on
+Linux TCP/IP which has made it much easier to get this little thing off my
+machine. Special thanks to everyone who put up with my bugs.
+
+Brickbats etc. to
+
+Doug Quale
+quale@saavik.cs.wisc.edu
diff --git a/mount/fstab.5 b/mount/fstab.5
new file mode 100644
index 000000000..8f96ee3b8
--- /dev/null
+++ b/mount/fstab.5
@@ -0,0 +1,168 @@
+.\" Copyright (c) 1980, 1989, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fstab.5 6.5 (Berkeley) 5/10/91
+.\"
+.\" Modified Sat Mar 6 20:45:03 1993, faith@cs.unc.edu, for Linux
+.\" Sat Oct 9 10:07:10 1993: converted to man format by faith@cs.unc.edu
+.\" Sat Nov 20 20:47:38 1993: hpfs documentation added
+.\" Sat Nov 27 20:23:32 1993: Updated authorship information
+.\"
+.TH FSTAB 5 "27 November 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+fstab \- static information about the filesystems
+.SH SYNOPSIS
+.B #include <fstab.h>
+.SH DESCRIPTION
+The file
+.B fstab
+contains descriptive information about the various file systems.
+.B fstab
+is only read by programs, and not written; it is the duty of the system
+administrator to properly create and maintain this file. Each filesystem
+is described on a separate line; fields on each line are separated by tabs
+or spaces. The order of records in
+.B fstab
+is important because
+.BR fsck "(8), " mount "(8), and " umount "(8)
+sequentially iterate through
+.B fstab
+doing their thing.
+
+The first field,
+.RI ( fs_spec ),
+describes the block special device or
+remote filesystem to be mounted.
+
+The second field,
+.RI ( fs_file ),
+describes the mount point for the filesystem. For swap partitions, this
+field should be specified as ``none''.
+
+The third field,
+.RI ( fs_vfstype ),
+describes the type of the filesystem. The system currently supports three
+types of filesystems:
+.TP
+.I minix
+a local filesystem, supporting filenames of length 14 or 30 characters.
+.TP
+.I ext
+a local filesystem with longer filenames and larger inodes. This
+filesystem has been replaced by the
+.I ext2
+file system, and should no longer be used.
+.TP
+.I ext2
+a local filesystem with longer filenames, larger inodes, and lots of other
+features.
+.TP
+.I xiafs
+a local filesystem with longer filenames, larger inodes, and lots of other
+features.
+.TP
+.I msdos
+a local filesystem for MS-DOS partitions.
+.TP
+.I hpfs
+a local filesystem for HPFS partitions.
+.TP
+.I iso9660
+a local filesystem used for CD-ROM drives.
+.TP
+.I nfs
+a filesystem for mounting partitions from remote systems.
+.TP
+.I swap
+a disk partition to be used for swapping.
+.PP
+If
+.I vfs_fstype
+is specified as ``ignore'' the entry is ignored. This is useful to show
+disk partitions which are currently unused.
+
+The fourth field,
+.RI ( fs_mntops ),
+describes the mount options associated with the filesystem.
+
+It is formatted as a comma separated list of options. It contains at least
+the type of mount plus any additional options appropriate to the filesystem
+type. For documentation on all of the available options, see
+.BR mount (8).
+
+The fifth field,
+.RI ( fs_freq ),
+is used for these filesystems by the
+.BR dump (8)
+command to determine which filesystems need to be dumped. If the fifth
+field is not present, a value of zero is returned and
+.B dump
+will assume that the filesystem does not need to be dumped.
+
+The sixth field,
+.RI ( fs_passno ),
+is used by the
+.BR fsck (8)
+program to determine the order in which filesystem checks are done at
+reboot time. The root filesystem should be specified with a
+.I fs_passno
+of 1, and other filesystems should have a
+.I fs_passno
+of 2. Filesystems within a drive will be checked sequentially, but
+filesystems on different drives will be checked at the same time to utilize
+parallelism available in the hardware. If the sixth field is not present
+or zero, a value of zero is returned and
+.B fsck
+will assume that the filesystem does not need to be checked.
+
+The proper way to read records from
+.B fstab
+is to use the routines
+.BR getmntent (3).
+.SH FILES
+.I /etc/fstab
+The file
+.B fstab
+resides in
+.IR /etc .
+.SH BUGS
+Linux does not, currently, support the special fields for
+.BR dump " and " fsck .
+
+The documentation in
+.BR mount (8)
+is often more up-to-date.
+.SH "SEE ALSO"
+.BR getmntent "(3), " mount "(8), " swapon (8)
+.SH HISTORY
+The
+.B fstab
+file format appeared in 4.0BSD.
diff --git a/mount/fstab.c b/mount/fstab.c
new file mode 100644
index 000000000..95b0879e0
--- /dev/null
+++ b/mount/fstab.c
@@ -0,0 +1,92 @@
+/* /home/faith/cvs/util-linux/mount/fstab.c,v 1.1.1.1 1995/02/22 19:09:21 faith Exp */
+
+#include "fstab.h"
+#include <stdio.h>
+
+#define streq(s, t) (strcmp ((s), (t)) == 0)
+
+/* These routines are superceded by mntent(3), but I use them for
+ convenience. Mntent(3) is used in the implementation, so be
+ very careful about the static buffers that are returned. */
+
+
+static FILE *F_fstab = NULL;
+
+/* Open fstab or rewind if already open. */
+int
+setfsent (void)
+{
+ if (F_fstab)
+ return (fseek (F_fstab, 0L, SEEK_SET) == 0);
+
+ F_fstab = setmntent (_PATH_FSTAB, "r");
+ return (F_fstab != NULL);
+}
+
+/* Close fstab. */
+void
+endfsent (void)
+{
+ endmntent (F_fstab);
+}
+
+/* Return next entry in fstab, skipping ignore entries. I also put
+ in some ugly hacks here to skip comments and blank lines. */
+struct mntent *
+getfsent (void)
+{
+ struct mntent *fstab;
+
+ if (!F_fstab && !setfsent())
+ return 0;
+
+ for (;;)
+ {
+ fstab = getmntent (F_fstab);
+ if (fstab == NULL)
+ {
+ if (!feof (F_fstab) && !ferror (F_fstab))
+ continue;
+ else
+ break;
+ }
+ else if ((*fstab->mnt_fsname != '#')
+ && !streq (fstab->mnt_type, MNTTYPE_IGNORE))
+ break;
+ }
+ return fstab;
+}
+
+/* Find the dir FILE in fstab. */
+struct mntent *
+getfsfile (const char *file)
+{
+ struct mntent *fstab;
+
+ /* Open or rewind fstab. */
+ if (!setfsent ())
+ return 0;
+
+ while ((fstab = getfsent ()))
+ if (streq (fstab->mnt_dir, file))
+ break;
+
+ return fstab;
+}
+
+/* Find the device SPEC in fstab. */
+struct mntent *
+getfsspec (const char *spec)
+{
+ struct mntent *fstab;
+
+ /* Open or rewind fstab. */
+ if (!setfsent())
+ return 0;
+
+ while ((fstab = getfsent ()))
+ if (streq (fstab->mnt_fsname, spec))
+ break;
+
+ return fstab;
+}
diff --git a/mount/fstab.h b/mount/fstab.h
new file mode 100644
index 000000000..c3c48b9e4
--- /dev/null
+++ b/mount/fstab.h
@@ -0,0 +1,25 @@
+/* The fsent(3) routines are obsoleted by mntent(3). I use them for
+ convenience. Since the implementation uses mntent(3), be very
+ careful with the static buffers returned.
+ /home/faith/cvs/util-linux/mount/fstab.h,v 1.1.1.1 1995/02/22 19:09:21 faith Exp */
+
+#ifndef _FSTAB_H
+#include <stdio.h>
+#include <mntent.h>
+
+#define _PATH_FSTAB "/etc/fstab"
+
+/* Translate fsent(3) stuff into mntent(3) stuff.
+ In general this won't work, but it's good enough here. */
+#define fstab mntent
+#define fs_type mnt_type
+#define fs_spec mnt_fsname
+#define FSTAB_SW MNTTYPE_SWAP
+
+struct fstab *getfsent (void);
+struct fstab *getfsspec (const char *spec);
+struct fstab *getfsfile (const char *file);
+int setfsent (void);
+void endfsent (void);
+
+#endif /* _FSTAB_H */
diff --git a/mount/lomount.c b/mount/lomount.c
new file mode 100644
index 000000000..5dd02d8bb
--- /dev/null
+++ b/mount/lomount.c
@@ -0,0 +1,223 @@
+/* Taken from Ted's losetup.c - Mitch <m.dsouza@mrc-apu.cam.ac.uk> */
+
+/*
+ * losetup.c - setup and control loop devices
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include "loop.h"
+
+char *crypt_name (int);
+int crypt_type (char *);
+void show_loop (char *);
+int del_loop (const char *);
+int set_loop (const char *, const char *, int offset, char *);
+int lomount (const char *, const char *, const char *, char **,
+ int *, char **, char **);
+
+struct crypt_type_struct {
+ int id;
+ char *name;
+} crypt_type_tbl[] = {
+
+ {
+ LO_CRYPT_NONE, "no"
+ },
+ {
+ LO_CRYPT_NONE, "none"
+ },
+ {
+ LO_CRYPT_XOR, "xor"
+ },
+ {
+ LO_CRYPT_DES, "DES"
+ },
+ {
+ -1, NULL
+ }
+};
+
+char *
+crypt_name (int id)
+{
+ int i;
+
+ for (i = 0; crypt_type_tbl[i].id != -1; i++)
+ if (id == crypt_type_tbl[i].id)
+ return crypt_type_tbl[i].name;
+ return "undefined";
+}
+
+int
+crypt_type (char *name)
+{
+ int i;
+
+ for (i = 0; crypt_type_tbl[i].id != -1; i++)
+ if (!strcasecmp (name, crypt_type_tbl[i].name))
+ return crypt_type_tbl[i].id;
+ return -1;
+}
+
+void
+show_loop (char *device)
+{
+ struct loop_info loopinfo;
+ int fd;
+
+ if ((fd = open (device, O_RDWR)) < 0) {
+ fprintf(stderr, "loop: can't open device %s: %s\n",
+ device, strerror (errno));
+ return;
+ }
+ if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) < 0) {
+ fprintf(stderr, "loop: can't get info on device %s: %s\n",
+ device, strerror (errno));
+ close (fd);
+ return;
+ }
+ printf ("%s: [%04x]:%ld (%s) offset %d, %s encryption\n",
+ device, loopinfo.lo_device, loopinfo.lo_inode,
+ loopinfo.lo_name, loopinfo.lo_offset,
+ crypt_name (loopinfo.lo_encrypt_type));
+ close (fd);
+}
+
+int
+set_loop (const char *device, const char *file, int offset, char *encryption)
+{
+ struct loop_info loopinfo;
+ int fd,
+ ffd,
+ i;
+ char *pass;
+
+ if ((fd = open (device, O_RDWR)) < 0) {
+ perror (device);
+ return 1;
+ }
+ if ((ffd = open (file, O_RDWR)) < 0) {
+ perror (file);
+ return 1;
+ }
+ memset (&loopinfo, 0, sizeof (loopinfo));
+ strncpy (loopinfo.lo_name, file, LO_NAME_SIZE);
+ loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
+ if (encryption && (loopinfo.lo_encrypt_type = crypt_type (encryption))
+ < 0) {
+ fprintf (stderr, "Unsupported encryption type %s", encryption);
+ return 1;
+ }
+ loopinfo.lo_offset = offset;
+ switch (loopinfo.lo_encrypt_type) {
+ case LO_CRYPT_NONE:
+ loopinfo.lo_encrypt_key_size = 0;
+ break;
+ case LO_CRYPT_XOR:
+ pass = getpass ("Password: ");
+ strncpy (loopinfo.lo_encrypt_key, pass, LO_KEY_SIZE);
+ loopinfo.lo_encrypt_key[LO_KEY_SIZE - 1] = 0;
+ loopinfo.lo_encrypt_key_size = strlen (loopinfo.lo_encrypt_key);
+ break;
+ case LO_CRYPT_DES:
+ pass = getpass ("Password: ");
+ strncpy (loopinfo.lo_encrypt_key, pass, 8);
+ loopinfo.lo_encrypt_key[8] = 0;
+ loopinfo.lo_encrypt_key_size = 8;
+ pass = getpass ("Init (up to 16 hex digits): ");
+ for (i = 0; i < 16 && pass[i]; i++)
+ if (isxdigit (pass[i]))
+ loopinfo.lo_init[i >> 3] |= (pass[i] > '9' ?
+ (islower (pass[i]) ? toupper (pass[i]) :
+ pass[i]) - 'A' + 10 : pass[i] - '0') << (i & 7) * 4;
+ else {
+ fprintf (stderr, "Non-hex digit '%c'.\n", pass[i]);
+ return 1;
+ }
+ break;
+ default:
+ fprintf (stderr,
+ "Don't know how to get key for encryption system %d\n",
+ loopinfo.lo_encrypt_type);
+ return 1;
+ }
+ if (ioctl (fd, LOOP_SET_FD, ffd) < 0) {
+ perror ("ioctl: LOOP_SET_FD");
+ return 1;
+ }
+ if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
+ (void) ioctl (fd, LOOP_CLR_FD, 0);
+ perror ("ioctl: LOOP_SET_STATUS");
+ return 1;
+ }
+ close (fd);
+ close (ffd);
+ return 0;
+}
+
+int
+del_loop (const char *device)
+{
+ int fd;
+
+ if ((fd = open (device, O_RDONLY)) < 0) {
+ fprintf(stderr, "loop: can't delete device %s: %s\n",
+ device, strerror (errno));
+ return 1;
+ }
+ if (ioctl (fd, LOOP_CLR_FD, 0) < 0) {
+#if 0
+ perror ("ioctl: LOOP_CLR_FD");
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+lomount (const char *spec, const char *node, const char *device, char **type,
+ int *flags, char **extra_opts, char **mount_opts)
+{
+ char *opt,
+ *opteq;
+ int val;
+ char *encryption = NULL, *vfs = NULL;
+ int offset = 0, err;
+ char new_opts[1024];
+
+ for (opt = strtok (*extra_opts, ","); opt; opt = strtok (NULL, ",")) {
+ if ((opteq = strchr (opt, '='))) {
+ val = atoi (opteq + 1);
+ *opteq = '\0';
+ if (!strcmp (opt, "encryption"))
+ encryption = strdup(opteq + 1);
+ else if (!strcmp (opt, "vfs"))
+ vfs = strdup(opteq + 1);
+ else if (!strcmp (opt, "offset"))
+ offset = val;
+ else {
+ printf ("unknown loop mount parameter: "
+ "%s=%d (%s)\n", opt, val, opteq+1);
+ return 1;
+ }
+ } else {
+ printf ("unknown loop mount parameter: "
+ "%s\n", opt);
+ return 1;
+ }
+ }
+ err = set_loop (device, spec, offset, encryption);
+ sprintf(new_opts, "vfs=%s,offset=%d,encryption=%s",
+ *type = vfs ? vfs : FSTYPE_DEFAULT, offset,
+ encryption=crypt_type(encryption)<0?"none":encryption);
+ *extra_opts=strdup(new_opts);
+ return err;
+}
diff --git a/mount/loop.h b/mount/loop.h
new file mode 100644
index 000000000..81ee7611e
--- /dev/null
+++ b/mount/loop.h
@@ -0,0 +1,77 @@
+#ifndef _LINUX_LOOP_H
+#define _LINUX_LOOP_H
+
+/*
+ * include/linux/loop.h
+ *
+ * Written by Theodore Ts'o, 3/29/93.
+ *
+ * Copyright 1993 by Theodore Ts'o. Redistribution of this file is
+ * permitted under the GNU Public License.
+ */
+
+#define LO_NAME_SIZE 64
+#define LO_KEY_SIZE 32
+
+struct loop_device {
+ int lo_number;
+ struct inode *lo_inode;
+ int lo_refcnt;
+ dev_t lo_device;
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size;
+ int lo_flags;
+ int (*transfer)(struct loop_device *, int cmd,
+ char *raw_buf, char *loop_buf, int size);
+ char lo_name[LO_NAME_SIZE];
+ char lo_encrypt_key[LO_KEY_SIZE];
+#ifdef DES_AVAILABLE
+ des_key_schedule lo_des_key;
+ unsigned long lo_des_init[2];
+#endif
+};
+
+typedef int (* transfer_proc_t)(struct loop_device *, int cmd,
+ char *raw_buf, char *loop_buf, int size);
+
+/*
+ * Loop flags
+ */
+#define LO_FLAGS_DO_BMAP 0x00000001
+
+struct loop_info {
+ int lo_number; /* ioctl r/o */
+ dev_t lo_device; /* ioctl r/o */
+ unsigned long lo_inode; /* ioctl r/o */
+ dev_t lo_rdevice; /* ioctl r/o */
+ int lo_offset;
+ int lo_encrypt_type;
+ int lo_encrypt_key_size; /* ioctl w/o */
+ int lo_flags; /* ioctl r/o */
+ char lo_name[LO_NAME_SIZE];
+ unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+ unsigned long lo_init[2];
+ char reserved[4];
+};
+
+/*
+ * Loop encryption types --- LO_CRYPT_IDEA isn't supported yet
+ */
+
+#define LO_CRYPT_NONE 0
+#define LO_CRYPT_XOR 1
+#define LO_CRYPT_DES 2
+#define LO_CRYPT_IDEA 4
+#define MAX_LO_CRYPT 3
+
+/*
+ * IOCTL commands --- we will commandeer 0x4C ('L')
+ */
+
+#define LOOP_SET_FD 0x4C00
+#define LOOP_CLR_FD 0x4C01
+#define LOOP_SET_STATUS 0x4C02
+#define LOOP_GET_STATUS 0x4C03
+
+#endif
diff --git a/mount/mount.8 b/mount/mount.8
new file mode 100644
index 000000000..a47091dde
--- /dev/null
+++ b/mount/mount.8
@@ -0,0 +1,589 @@
+.\" Copyright (c) 1980, 1989, 1991 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mount.8 6.17 (Berkeley) 8/5/91
+.\"
+.\" When you change this file, please add an update notice to the ones below:
+.\"
+.\" Sun Dec 27 12:10:38 1992: Updated by faith@cs.unc.edu
+.\" Thu Jan 14 21:15:06 1993: Updated by faith@cs.unc.edu
+.\" Mon Feb 1 21:18:21 1993: Updated by faith@cs.unc.edu
+.\" Sat Mar 6 20:46:29 1993: Updated by faith@cs.unc.edu
+.\" Sat Oct 9 08:56:26 1993: Updated by faith@cs.unc.edu
+.\" based on changes by Stephen Tweedie (sct@dcs.ed.ac.uk)
+.\" Sat Oct 9 08:59:46 1993: Converted to man format by faith@cs.unc.edu
+.\" Sat Nov 27 20:04:28 1993: File-system specific options documented by Rik
+.\" Faith (faith@cs.unc.edu), using extensive additions taken from
+.\" documentation written by Werner Almesberger
+.\" (almesber@nessie.cs.id.ethz.ch), and email written by Eric
+.\" Youngdale (eric@tantalus.nrl.navy.mil) and Remy Card
+.\" (Remy.Card@masi.ibp.fr).
+.\" Sun Apr 24 19:25:59 1994: Updated per information supplied by Remy Card.
+.\" Thu Jul 14 07:44:36 1994: Updated absence of -t
+.\" option. (faith@cs.unc.edu)
+.\" Thu Jul 14 07:49:14 1994: Updated list of valid filesystems.
+.\" Wed Feb 8 09:25:48 1995: Updated man pages for Mike Grupenhoff's changes.
+.\"
+.TH MOUNT 8 "8 February 1995" "Linux 1.1" "Linux Programmer's Manual"
+.SH NAME
+mount, umount \- mount and dismount file systems
+.SH SYNOPSIS
+.BI "mount [\-afrwuvn] [\-t " vfstype ]
+.br
+.BI "mount [\-frwuvn] [\-o " remount " [,...]] " "special " | " node"
+.br
+.BI "mount [\-frwun] [\-t " vfstype "] [\-o " options "] " "special node"
+.br
+.BI "umount [\-an] [\-t " vfstype ]
+.br
+.BI "umount " "special " | " node"
+.\" " for hilit19
+.SH DESCRIPTION
+The
+.B mount
+command calls the
+.BR mount (2)
+system call to prepare and graft a
+.I special
+device on to the file system tree at the point
+.IR node .
+If either
+.IR special " or " node
+are not provided, the appropriate information is taken from the
+.BR fstab (5)
+file. The special keyword
+.I none
+can be used instead of a path or
+.I node
+specification. This is useful when mounting the
+.I proc
+file system.
+
+The system maintains a list of currently mounted file systems. If no
+arguments are given to
+.BR mount ,
+this list is printed.
+
+Options available for the
+.B mount
+command:
+.TP
+.B \-f
+Causes everything to be done except for the actual system call; if it's not
+obvious, this ``fakes'' mounting the file system. This option is useful in
+conjunction with the
+.B \-v
+flag to determine what the
+.B mount
+command is trying to do.
+.TP
+.B \-o
+Options are specified with a
+.B \-o
+flag followed by a comma separated string of options.
+.B N.B.,
+many of these options are only useful when they appear in the
+.I /etc/fstab
+file. The following options apply to any file system that is being
+mounted:
+.RS
+.TP
+.B async
+All I/O to the file system should be done asynchronously.
+.TP
+.B auto
+Can be mounted with the
+.B \-a
+option.
+.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 file system.
+.TP
+.B exec
+Permit execution of binaries.
+.TP
+.B noauto
+Can only be mounted explicitly (i.e., the
+.B \-a
+option will not cause the file system to be mounted).
+.TP
+.B nodev
+Do not interpret character or block special devices on the file
+system. This options is useful for a server that has file systems
+containing special devices for architectures other than its own.
+.TP
+.B noexec
+Do not allow execution of any binaries on the mounted file system.
+This options is useful for a server that has file systems containing
+binaries for architectures other than its own.
+.TP
+.B nosuid
+Do not allow set-user-identifier or set-group-identifier bits to take
+effect.
+.TP
+.B nouser
+Forbid an ordinary (i.e., non-root) user to mount the file system.
+.TP
+.B remount
+Attempt to remount an already-mounted file system. This is commonly
+used to change the mount flags for a file system, especially to make a
+readonly file system writeable.
+.TP
+.B ro
+Mount the file system read-only.
+.TP
+.B rw
+Mount the file system read-write.
+.TP
+.B suid
+Allow set-user-identifier or set-group-identifier bits to take
+effect.
+.TP
+.B sync
+All I/O to the file system should be done synchronously.
+.TP
+.B user
+Allow an ordinary user to mount the file system. Ordinary users always
+have the following options activated:
+.BR noexec ", " nosuid ", and " nodev
+(unless overridden by the superuser by using, for example, the following
+option line:
+.BR user,exec,dev,suid .
+.PP
+The following options apply only to certain file systems:
+.TP
+.BI case= value
+For the
+.I hpfs
+file system, specify case as
+.I lower
+or
+.IR asis .
+.TP
+.BI check= value
+Tells the
+.I ext2
+file sysem kernel code to do some more checks while the file system is
+mounted. Currently (0.99.15), the following values can be specified with
+this option:
+.RS
+.TP
+.I none
+no extra check is performed by the kernel code
+.TP
+.I normal
+The inodes and blocks bitmaps are checked when the file system is mounted
+(this is the default)
+.TP
+.I strict
+In addition to the
+.I normal
+checks, block deallocation checks that the block to free is in the data
+zone.
+.RE
+.TP
+.BI check= value
+For the
+.I msdos
+file system, three different levels of pickyness can be chosen:
+.RS
+.TP
+.I relaxed
+Upper and lower case are accepted and equivalent, long name parts are
+truncated (e.g. verlongname.foobar becomes verylong.foo), leading and
+embedded spaces are accepted in each name part (name and extension).
+.TP
+.I normal
+Like "relaxed", but many special characters (*, ?, <, spaces, etc.) are
+rejected. This is the default.
+.TP
+.I strict
+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 conv= value
+For the
+.IR msdos ,
+.IR hpfs ,
+and
+.I iso9660
+file systems, specify file conversion as
+.IR binary ", " text ", or " auto .
+The
+.I iso9660
+file system also allows
+.I value
+to be
+.IR mtext .
+
+The
+.I msdos
+file system can perform CRLF<-->NL (MS-DOS text format to UNIX text
+format) conversion in the kernel. The following conversion modes are
+available:
+.RS
+.TP
+.I binary
+no translation is performed. This is the default.
+.TP
+.I text
+CRLF<-->NL translation is performed on all files.
+.TP
+.I 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/msdos/misc.c
+(as of 09913r, 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,
+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.
+
+For file systems mounted in
+.B binary
+mode, a conversion tool (fromdos/todos) is available.
+.RE
+.TP
+.BI block= value
+For the
+.I iso9660
+file system, set the blocksize.
+.TP
+.B bsdgroups
+See
+.B grpid
+.TP
+.B cruft
+For the
+.I iso9660
+file system, set the
+.I cruft
+flag to 'y'. This option is available because there are buggy premastering
+programs out there that leave junk in the top byte of the file size. This
+option clears the top byte, but restricts files to 16Mb maximum in the
+process.
+.TP
+.B debug
+For the
+.I msdos
+file system, turn on the
+.I debug
+flag. A version string and a list of file system parameters will be
+printed (these data are also printed if the parameters appear to be
+inconsistent).
+.TP
+.B debug
+For the
+.I ext2fs
+file system, causes the kernel code to display the file system parameters
+when the file system is mounted.
+.TP
+.BI errors= value
+For the
+.I ext2fs
+file system, specifies the error behavior:
+.RS
+.TP
+.B continue
+No special action is taken on errors (except marking the file system as
+erroneous). This is the default.
+.TP
+.B remount
+.TP
+.B ro
+The file system is remounted read only, and subsequent writes are refused.
+.TP
+.B panic
+When an error is detected, the system panics.
+.RE
+.TP
+.BI fat= value
+For the
+.I msdos
+file system, specify either a 12 bit fat or a 16 bit fat. This overrides
+the automatic FAT type detection routine. Use with caution!
+.TP
+.BI gid= value
+For the
+.I msdos
+and
+.I hpfs
+file systems, give every file a gid equal to
+.IR value .
+.TP
+B grpid
+Causes the
+.I ext2fs
+to use the BSD behavior when creating files: file are created with the
+group id of their parent directory.
+.TP
+.BI map= value
+For the
+.I iso9660
+file system, specify mapping as
+.IR off " or " normal .
+In general, non-Rock Ridge discs have all of the filenames in upper case,
+and all of the filenames have a ";1" appended. The map option strips the
+";1" and makes the name lower case. C.f.
+.BR norock .
+.TP
+.B nocheck
+For the
+.IR ext2fs ,
+turns of checking (see
+.BR check=none ).
+.TP
+.B nogrpid
+Causes the
+.I ext2fs
+to use the System V behaviour when creating files: files are created with
+the group id of the creating process, unless the setgid bit is set on the
+parent directory. This is the default for all Linux file systems.
+.TP
+.B norock
+Normal
+.I iso9600
+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 file system (except
+that it is read-only, of course).
+
+The
+.B norock
+switch disables the use of Rock Ridge extensions, even if available. C.f.
+.BR map .
+.TP
+.B quiet
+For the
+.I msdos
+file system, turn on the
+.I quiet
+flag. Attempts to chown or chmod files do not yield errors, although they
+fail. Use with caution!
+.TP
+.BI sb= value
+For the
+.I ext2
+file system, use an alternate superblock located at block
+.IR value .
+.I value
+is numbered in 1024 bytes blocks. An
+.I ext2
+file system usually has backups of the super block at blocks 1, 8193, 16385
+and so on.
+.TP
+.BI sysvgroups
+See
+.B nogrpid
+.TP
+.BI uid= value
+For the
+.I msdos
+and
+.I hpfs
+file systems, give every file a uid equal to
+.IR value .
+.TP
+.BI umask= value
+For the
+.I msdos
+and
+.I hpfs
+file systems, give every file a umask of
+.IR value .
+The radix defaults to octal.
+.PP
+The full set of options applied is determined by first extracting the
+options for the file system from the
+.B fstab
+table, then applying any options specified by the
+.B \-o
+argument, and finally applying the
+.BR \-r " or " \-w
+option.
+
+If the
+.I msdos
+file system detects an inconsistency, it reports an error and sets the file
+system read-only. The file system can be made writeable again by remounting
+it.
+.RE
+.TP
+.B \-r
+The file system object is to be mounted read-only.
+.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 minux ", " ext ", " ext2 ", " xiafs ", " msdos ", " hpfs ,
+.IR proc ", " nfs ", " iso9660 ", " sysv ", " xenix ", " coherent .
+Note that that last three are equivalent and that "xenix" and "coherent"
+will be removed at some point in the future \(em use "sysv" instead.
+
+The type
+.I minix
+is the default. If no
+.B \-t
+option is given, the superblock is probed for the filesystem type (minix,
+ext, ext2, xia are supported). If this probe fails and
+.I /proc/filesystems
+exists, then all of the filesystems listed will be tried,
+.I except
+for those that are labeled "nodev" (e.g., "proc" and "nfs").
+
+For example, the
+.B mount
+command:
+.RS
+
+.RS
+mount -a -t nomsdos,ext
+.RE
+
+mounts all file systems except those of type
+.I msdos
+and
+.IR ext .
+.RE
+.TP
+.B \-v
+Verbose mode.
+.TP
+.B \-w
+The file system object is to be read and write.
+.TP
+.B \-n
+Mount without writing in
+.IR /etc/mtab .
+.PP
+.B Umount
+removes the
+.I special
+device grafted at point
+.I node
+from file system tree.
+
+Options for the
+.B umount
+command:
+.TP
+.B \-a
+All of the file systems described in
+.I /etc/mtab
+are unmounted.
+.TP
+.BI \-t " vfstype"
+Is used to indicate 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 ``no'' to specify
+the file system types on which no action should be taken. (See example
+above for the
+.B mount
+command.)
+
+.SH FILES
+.I /etc/fstab
+file system table
+.br
+.I /etc/mtab~
+lock file
+.br
+.I /etc/mtab.tmp
+temporary file
+.SH "SEE ALSO"
+.BR mount "(2), " umount "(2), " fstab "(5), " swapon (8)
+.SH BUGS
+It is possible for a corrupted file system to cause a crash.
+.PP
+Some Linux file systems don't support
+.BI \-o " synchronous"
+(the ext2fs
+.I does
+support synchronous updates (a la BSD) when mounted with the
+.B sync
+option).
+.PP
+The
+.BI \-o " remount"
+may not be able to change mount parameters (all
+.I ext2fs
+parameters, except
+.BR sb ,
+are changeable with a remount, for example, but you can't change
+.B gid
+or
+.B umask
+for the
+.IR dosfs ).
+.SH HISTORY
+A
+.B mount
+command appeared in Version 6 AT&T UNIX.
+.SH "AUTHORS AND CONTRIBUTORS"
+.na
+The Linux
+.B mount
+command has a long and continuing history. Major releases are noted below,
+with the name of the primary modifier noted:
+.sp
+0.97.3: Doug Quale (quale@saavik.cs.wisc.edu).
+.br
+0.98.5: H. J. Lu (hlu@eecs.wsu.edu).
+.br
+0.99.2: Rick Sladkey (jrs@world.std.com).
+.br
+0.99.6: Rick Sladkey (jrs@world.std.com).
+.br
+0.99.10: Stephen Tweedie (sct@dcs.ed.ac.uk).
+.br
+0.99.14: Rick Sladkey (jrs@world.std.com).
+.sp
+(File-system specific information added to man page on 27 November 1993 by
+Rik Faith with lots of information
+.I and text
+from the following file system authors: Werner Almesberger, Eric Youngdale,
+and Remy Card.)
diff --git a/mount/mount.c b/mount/mount.c
new file mode 100644
index 000000000..b6ffbcd67
--- /dev/null
+++ b/mount/mount.c
@@ -0,0 +1,734 @@
+/*
+ * 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 changed 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.
+ *
+ * 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.
+ *
+ */
+
+#include "sundries.h"
+
+#include <linux/fs.h>
+#include <linux/minix_fs.h>
+#include <linux/ext_fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/xia_fs.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int del_loop (const char *);
+
+/* True for fake mount (-f). */
+int fake = 0;
+
+/* Don't write a entry in /etc/mtab (-n). */
+int nomtab = 0;
+
+/* True for readonly (-r). */
+int readonly = 0;
+
+/* Nonzero for chatty (-v). */
+int verbose = 0;
+
+/* True for read/write (-w). */
+int readwrite = 0;
+
+/* True for all mount (-a). */
+int all = 0;
+
+/* True if ruid != euid. */
+int suid = 0;
+
+/* Map from -o and fstab option strings to the flag argument to mount(2). */
+struct opt_map
+{
+ const char *opt; /* option name */
+ int inv; /* true if flag value should be inverted */
+ int mask; /* flag mask value */
+};
+
+/* Custom mount options for our own purposes. */
+#define MS_NOAUTO 0x80000000
+#define MS_USER 0x40000000
+
+/* Options that we keep the mount system call from seeing. */
+#define MS_NOSYS (MS_NOAUTO|MS_USER)
+
+/* Options that we keep from appearing in the options field in the mtab. */
+#define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USER)
+
+/* OPTIONS that we make ordinary users have by default. */
+#define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
+
+const struct opt_map opt_map[] =
+{
+ { "defaults", 0, 0 }, /* default options */
+ { "ro", 0, MS_RDONLY }, /* read-only */
+ { "rw", 1, MS_RDONLY }, /* read-write */
+ { "exec", 1, MS_NOEXEC }, /* permit execution of binaries */
+ { "noexec", 0, MS_NOEXEC }, /* don't execute binaries */
+ { "suid", 1, MS_NOSUID }, /* honor suid executables */
+ { "nosuid", 0, MS_NOSUID }, /* don't honor suid executables */
+ { "dev", 1, MS_NODEV }, /* interpret device files */
+ { "nodev", 0, MS_NODEV }, /* don't interpret devices */
+ { "sync", 0, MS_SYNCHRONOUS}, /* synchronous I/O */
+ { "async", 1, MS_SYNCHRONOUS}, /* asynchronous I/O */
+ { "remount", 0, MS_REMOUNT }, /* Alter flags of mounted FS */
+ { "auto", 1, MS_NOAUTO }, /* Can be mounted using -a */
+ { "noauto", 0, MS_NOAUTO }, /* Can only be mounted explicitly */
+ { "user", 0, MS_USER }, /* Allow ordinary user to mount */
+ { "nouser", 1, MS_USER }, /* Forbid ordinary user to mount */
+ /* add new options here */
+#ifdef MS_NOSUB
+ { "sub", 1, MS_NOSUB }, /* allow submounts */
+ { "nosub", 0, MS_NOSUB }, /* don't allow submounts */
+#endif
+ { NULL, 0, 0 }
+};
+
+
+/* Report on a single mount. */
+static void
+print_one (const struct mntent *mnt)
+{
+ printf ("%s on %s", mnt->mnt_fsname, mnt->mnt_dir);
+ if ((mnt->mnt_type != NULL) && *mnt->mnt_type != '\0')
+ printf (" type %s", mnt->mnt_type);
+ if (mnt->mnt_opts != NULL)
+ printf (" (%s)", mnt->mnt_opts);
+ printf ("\n");
+}
+
+/* Report on everything in mtab (of the specified types if any). */
+static int
+print_all (string_list types)
+{
+ struct mntent *mnt;
+
+ open_mtab ("r");
+
+ while ((mnt = getmntent (F_mtab)) != NULL)
+ if (matching_type (mnt->mnt_type, types))
+ print_one (mnt);
+
+ if (ferror (F_mtab))
+ die (1, "mount: error reading %s: %s", MOUNTED, strerror (errno));
+
+ exit (0);
+}
+
+
+/* Look for OPT in opt_map table and return mask value. If OPT isn't found,
+ tack it onto extra_opts. */
+static inline void
+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 (om->inv)
+ *mask &= ~om->mask;
+ else
+ *mask |= om->mask;
+ if (om->mask == MS_USER)
+ *mask |= MS_SECURE;
+ return;
+ }
+ if (*extra_opts)
+ strcat(extra_opts, ",");
+ strcat(extra_opts, opt);
+}
+
+/* Take -o options list and compute 4th and 5th args to mount(2). flags
+ gets the standard options and extra_opts anything we don't recognize. */
+static void
+parse_opts (char *opts, int *flags, char **extra_opts)
+{
+ char *opt;
+
+ *flags = 0;
+ *extra_opts = NULL;
+
+ if (opts != NULL)
+ {
+ *extra_opts = xmalloc (strlen (opts) + 1);
+ **extra_opts = '\0';
+
+ for (opt = strtok (opts, ",");
+ opt != NULL;
+ opt = strtok (NULL, ","))
+ parse_opt (opt, flags, *extra_opts);
+ }
+
+ if (readonly)
+ *flags |= MS_RDONLY;
+ if (readwrite)
+ *flags &= ~MS_RDONLY;
+}
+
+/* Try to build a canonical options string. */
+static char *
+fix_opts_string (int flags, char *extra_opts)
+{
+ const struct opt_map *om;
+ char *new_opts;
+ char *tmp;
+
+ new_opts = (flags & MS_RDONLY) ? "ro" : "rw";
+ for (om = opt_map; om->opt != NULL; om++)
+ {
+ if (om->mask & MS_RDONLY)
+ continue;
+ if (om->inv || !om->mask || (flags & om->mask) != om->mask)
+ continue;
+ tmp = xmalloc(strlen(new_opts) + strlen(om->opt) + 2);
+ sprintf(tmp, "%s,%s", new_opts, om->opt);
+ new_opts = tmp;
+ flags &= ~om->mask;
+ }
+ if (extra_opts && *extra_opts)
+ {
+ tmp = xmalloc(strlen(new_opts) + strlen(extra_opts) + 2);
+ sprintf(tmp, "%s,%s", new_opts, extra_opts);
+ new_opts = tmp;
+ }
+ return new_opts;
+}
+
+
+/*
+ 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>.
+
+ Currently supports: minix, ext, ext2, xia
+*/
+
+static char *
+fstype(const char *device)
+{
+ int fd;
+
+ /* MINIX */
+ struct minix_super_block ms;
+ /* extended fs */
+ struct ext_super_block es;
+ /* 2nd extended fs */
+ struct ext2_super_block e2s;
+ /* xia fs */
+ struct xiafs_super_block xfs;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0) {
+ perror(device);
+ return 0;
+ }
+ lseek(fd, BLOCK_SIZE, SEEK_SET);
+ read(fd, (char *) &ms, sizeof(ms));
+ if (ms.s_magic == MINIX_SUPER_MAGIC || ms.s_magic == MINIX_SUPER_MAGIC2) {
+ close(fd);
+ return("minix");
+ }
+
+ lseek(fd, BLOCK_SIZE, SEEK_SET);
+ read(fd, (char *) &es, sizeof(es));
+ if (es.s_magic == EXT_SUPER_MAGIC) {
+ close(fd);
+ return("ext");
+ }
+
+ lseek(fd, BLOCK_SIZE, SEEK_SET);
+ read(fd, (char *) &e2s, sizeof(e2s));
+ if (e2s.s_magic == EXT2_SUPER_MAGIC || e2s.s_magic == EXT2_PRE_02B_MAGIC) {
+ close(fd);
+ return("ext2");
+ }
+
+ lseek(fd, 0, SEEK_SET);
+ read(fd, (char *) &xfs, sizeof(xfs));
+ if (xfs.s_magic == _XIAFS_SUPER_MAGIC) {
+ close(fd);
+ return("xiafs");
+ }
+
+ close(fd);
+
+ return(0);
+
+}
+
+
+/* Mount a single file system. Return status,
+ so don't exit on non-fatal errors. */
+
+static int
+try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) {
+ FILE *procfs_file;
+ char line[100];
+ char fsname[50];
+
+ if (*type) return mount5 (spec, node, *type, flags & ~MS_NOSYS, mount_opts);
+ if (( procfs_file = fopen("/proc/filesystems", "r")) == NULL) {
+ /* If /proc/filesystems is not available,
+ preserve the old behavior of mount. */
+ return mount5 (spec,
+ node,
+ FSTYPE_DEFAULT,
+ flags & ~MS_NOSYS, mount_opts);
+ }
+ while (fgets(line, sizeof(line), procfs_file)) {
+ if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
+ if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
+ if (mount5 (spec, node, fsname, flags & ~MS_NOSYS, mount_opts) == 0) {
+ *type=xstrdup(fsname);
+ fclose(procfs_file);
+ return 0;
+ }
+ }
+ fclose(procfs_file);
+ return -1;
+}
+
+
+static int
+mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass)
+{
+ struct mntent mnt;
+ int mnt_err;
+ int flags;
+ char *extra_opts;
+ char *mount_opts;
+ int anti_recurse = 0;
+ int loop=0;
+
+ if (type == NULL)
+ {
+ if (strchr (spec, ':') != NULL)
+ type = "nfs";
+ }
+
+ parse_opts (xstrdup (opts), &flags, &extra_opts);
+
+ /* root may allow certain types of mounts by ordinary users */
+ if (suid && !(flags & MS_USER))
+ die (3, "mount: only root can mount %s on %s", spec, node);
+
+ /* quietly succeed for fstab entries that don't get mounted automatically */
+ if (all && (flags & MS_NOAUTO))
+ return 0;
+
+ mount_opts = extra_opts;
+
+ if (!fake && type && strncmp("lo@", type, 3)==0) {
+ extern int lomount (char *, char *, char *, char **,
+ int *, char **, char **);
+ char *dev=type+3;
+
+ loop=1;
+ if (lomount (spec, node, dev, &type,
+ &flags, &opts, &mount_opts) != 0)
+ return 1;
+ spec=dev;
+ mount_opts=NULL;
+ }
+
+ if (!fake && type && streq (type, "nfs"))
+#ifdef HAVE_NFS
+ if (nfsmount (spec, node, &flags, &extra_opts, &mount_opts) != 0)
+ return 1;
+#else
+ die (1, "mount: this version doesn't support the type `nfs'");
+#endif
+
+ if (!type && !(type = fstype(spec)))
+ return 1;
+
+ block_signals (SIG_BLOCK);
+
+ if (fake
+ || (try_mount5 (spec, node, &type, flags & ~MS_NOSYS, mount_opts)) == 0)
+ /* Mount succeeded, write mtab entry. */
+ {
+ if (!nomtab)
+ {
+ mnt.mnt_fsname = canonicalize (spec);
+ mnt.mnt_dir = canonicalize (node);
+ mnt.mnt_type = loop?"loop":type;
+ mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB,
+ loop?opts:extra_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 (flags & MS_REMOUNT)
+ {
+ close_mtab ();
+ update_mtab (mnt.mnt_dir, &mnt);
+ open_mtab ("a+");
+ }
+ else
+ if ((addmntent (F_mtab, &mnt)) == 1)
+ die (1, "mount: error writing %s: %s",
+ MOUNTED, strerror (errno));
+ }
+
+ block_signals (SIG_UNBLOCK);
+ return 0;
+ }
+
+ if (loop)
+ del_loop(spec);
+
+ mnt_err = errno; /* work around for errno bug in sigprocmask */
+
+ block_signals (SIG_UNBLOCK);
+
+ /* Mount failed, complain, but don't die. */
+ switch (mnt_err)
+ {
+ case EPERM:
+ if (geteuid() == 0)
+ error ("mount: mount point %s is not a directory", node);
+ else
+ error ("mount: must be superuser to use mount");
+ break;
+ case EBUSY:
+ error ("mount: %s already mounted or %s busy", spec, node);
+ break;
+ case ENOENT:
+ { struct stat statbuf;
+ if (stat (node, &statbuf))
+ error ("mount: mount point %s does not exist", node);
+ else if (stat (spec, &statbuf))
+ error ("mount: special device %s does not exist", spec);
+ else {
+ errno = mnt_err;
+ perror("mount");
+ }
+ break;
+ }
+ case ENOTDIR:
+ error ("mount: mount point %s is not a directory", node); break;
+ case EINVAL:
+ error ("mount: wrong fs type or bad superblock on %s", spec); break;
+ case EMFILE:
+ error ("mount table full"); break;
+ case EIO:
+ error ("mount: %s: can't read superblock", spec); break;
+ case ENODEV:
+ error ("mount: fs type %s not supported by kernel", type); break;
+ case ENOTBLK:
+ error ("mount: %s is not a block device", spec); break;
+ case ENXIO:
+ error ("mount: %s is not a valid block device", spec); break;
+ case EACCES: /* pre-linux 1.1.38 */
+ case EROFS: /* linux 1.1.38 and later */
+ if (anti_recurse)
+ {
+ error ("mount: block device %s is not permitted on its filesystem", spec);
+ break;
+ }
+ else
+ {
+ anti_recurse++;
+ if (opts)
+ {
+ opts = realloc(xstrdup(opts), strlen(opts)+3);
+ strcat(opts, ",ro");
+ }
+ else
+ opts = "ro";
+ error ("mount: block device %s is write-protected, mounting read-only", spec);
+ return mount_one (spec, node, type, opts, freq, pass);
+ }
+ break;
+ default:
+ error ("mount: %s", strerror (mnt_err)); break;
+ }
+ return 1;
+}
+
+/* Check if an fsname/dir pair was already in the old mtab. */
+static int
+mounted (char *spec, char *node, string_list spec_list, string_list node_list)
+{
+ spec = canonicalize (spec);
+ node = canonicalize (node);
+
+ while (spec_list != NULL)
+ {
+ if (streq (spec, car (spec_list)) && streq (node, car (node_list)))
+ return 1;
+ spec_list = cdr (spec_list);
+ node_list = cdr (node_list);
+ }
+ return 0;
+}
+
+/* Mount all filesystems of the specified types except swap and root. */
+static int
+mount_all (string_list types)
+{
+ struct mntent *fstab;
+ struct mntent *mnt;
+ string_list spec_list = NULL;
+ string_list node_list = NULL;
+ int status;
+
+ rewind (F_mtab);
+
+ while ((mnt = getmntent (F_mtab)))
+ if (matching_type (mnt->mnt_type, types)
+ && !streq (mnt->mnt_dir, "/")
+ && !streq (mnt->mnt_dir, "root"))
+ {
+ spec_list = cons (xstrdup (mnt->mnt_fsname), spec_list);
+ node_list = cons (xstrdup (mnt->mnt_dir), node_list);
+ }
+
+ status = 0;
+ while ((fstab = getfsent ()) != NULL)
+ if (matching_type (fstab->mnt_type, types)
+ && !streq (fstab->mnt_dir, "/")
+ && !streq (fstab->mnt_dir, "root"))
+ if (mounted (fstab->mnt_fsname, fstab->mnt_dir, spec_list, node_list))
+ {
+ if (verbose)
+ printf("mount: %s already mounted on %s\n",
+ fstab->mnt_fsname, fstab->mnt_dir);
+ }
+ else
+ status |= mount_one (fstab->mnt_fsname, fstab->mnt_dir,
+ fstab->mnt_type, fstab->mnt_opts,
+ fstab->mnt_freq, fstab->mnt_passno);
+
+ return status;
+}
+
+/* Create mtab with a root entry. */
+static void
+create_mtab (void)
+{
+ struct mntent *fstab;
+ struct mntent mnt;
+ int flags;
+ char *extra_opts;
+
+ if ((F_mtab = setmntent (MOUNTED, "a+")) == NULL)
+ die (1, "mount: can't open %s for writing: %s", MOUNTED, strerror (errno));
+
+ /* Find the root entry by looking it up in fstab, which might be wrong.
+ We could statfs "/" followed by a slew of stats on /dev/ but then
+ we'd have to unparse the mount options as well.... */
+ if ((fstab = getfsfile ("/")) || (fstab = getfsfile ("root")))
+ {
+ parse_opts (xstrdup (fstab->mnt_opts), &flags, &extra_opts);
+ mnt = *fstab;
+ mnt.mnt_fsname = canonicalize (fstab->mnt_fsname);
+ mnt.mnt_dir = "/";
+ mnt.mnt_opts = fix_opts_string (flags, extra_opts);
+
+ if (addmntent (F_mtab, &mnt) == 1)
+ die (1, "mount: error writing %s: %s", MOUNTED, strerror (errno));
+ }
+ if (fchmod (fileno (F_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
+ die (1, "mount: error changing mode of %s: %s", MOUNTED, strerror (errno));
+ endmntent (F_mtab);
+}
+
+extern char version[];
+static struct option longopts[] =
+{
+ { "all", 0, 0, 'a' },
+ { "fake", 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' },
+ { "types", 1, 0, 't' },
+ { NULL, 0, 0, 0 }
+};
+
+const char *usage_string = "\
+usage: mount [-hV]\n\
+ mount -a [-nfrvw] [-t vfstypes]\n\
+ mount [-nfrvw] [-o options] special | node\n\
+ mount [-nfrvw] [-t vfstype] [-o options] special node\n\
+";
+
+static void
+usage (FILE *fp, int n)
+{
+ fprintf (fp, "%s", usage_string);
+ exit (n);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int c;
+ char *options = NULL;
+ string_list types = NULL;
+ struct mntent *fs;
+ char *spec;
+ int result = 0;
+ struct stat statbuf;
+
+ while ((c = getopt_long (argc, argv, "afhnrvVwt:o:", longopts, NULL)) != EOF)
+ switch (c)
+ {
+ case 'a': /* mount everything in fstab */
+ ++all;
+ break;
+ case 'f': /* fake (don't actually do mount(2) call) */
+ ++fake;
+ break;
+ case 'h': /* help */
+ usage (stdout, 0);
+ break;
+ case 'n': /* mount without writing in /etc/mtab */
+ ++nomtab;
+ break;
+ case 'r': /* mount readonly */
+ ++readonly;
+ readwrite = 0;
+ break;
+ case 'v': /* be chatty */
+ ++verbose;
+ break;
+ case 'V': /* version */
+ printf ("%s\n", version);
+ exit (0);
+ case 'w': /* mount read/write */
+ ++readwrite;
+ readonly = 0;
+ break;
+ case 't': /* specify file system types */
+ types = parse_list (optarg);
+ break;
+ case 'o': /* specify mount options */
+ options = optarg;
+ break;
+ case 0:
+ break;
+ case '?':
+ default:
+ usage (stderr, 1);
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ {
+ if (options)
+ usage (stderr, 1);
+ if (!all)
+ return print_all (types);
+ }
+
+ if (getuid () != geteuid ())
+ {
+ suid = 1;
+ if (types || options || readwrite || nomtab || all || fake || argc != 1)
+ die (2, "mount: only root can do that");
+ }
+
+ if (!nomtab)
+ {
+ lock_mtab ();
+ if (stat(MOUNTED, &statbuf) < 0)
+ create_mtab ();
+ open_mtab ("a+");
+ }
+ else if (stat(MOUNTED, &statbuf) >= 0)
+ open_mtab ("r");
+
+
+ switch (argc)
+ {
+ case 0:
+ /* mount -a */
+ result = mount_all (types);
+ break;
+
+ case 1:
+ /* mount [-nfrvw] [-o options] special | node */
+ if (types != NULL)
+ usage (stderr, 1);
+ /* Try to find the other pathname in fstab. */
+ spec = canonicalize (*argv);
+ if (!(fs = getmntfile (spec))
+ && !(fs = getfsspec (spec)) && !(fs = getfsfile (spec)))
+ die (2, "mount: can't find %s in %s or %s",
+ spec, MOUNTED, _PATH_FSTAB);
+ /* Merge the fstab and command line options. */
+ if (options == NULL)
+ options = fs->mnt_opts;
+ else
+ {
+ char *tmp = xmalloc(strlen(fs->mnt_opts) + strlen(options) + 2);
+
+ sprintf (tmp, "%s,%s", fs->mnt_opts, options);
+ options = tmp;
+ }
+ result = mount_one (xstrdup (fs->mnt_fsname), xstrdup (fs->mnt_dir),
+ xstrdup (fs->mnt_type), options,
+ fs->mnt_freq, fs->mnt_passno);
+ break;
+
+ case 2:
+ /* mount [-nfrvw] [-t vfstype] [-o options] special node */
+ if (types == NULL)
+ result = mount_one (argv[0], argv[1], NULL, options, 0, 0);
+ else if (cdr (types) == NULL)
+ result = mount_one (argv[0], argv[1], car (types), options, 0, 0);
+ else
+ usage (stderr, 2);
+ break;
+
+ default:
+ usage (stderr, 2);
+ }
+
+ if (!nomtab)
+ {
+ endmntent (F_mtab);
+ unlock_mtab ();
+ }
+
+ exit (result);
+}
diff --git a/mount/mount.h b/mount/mount.h
new file mode 100644
index 000000000..d70ccaf9d
--- /dev/null
+++ b/mount/mount.h
@@ -0,0 +1,208 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _MOUNT_H_RPCGEN
+#define _MOUNT_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+
+typedef char fhandle[FHSIZE];
+#ifdef __cplusplus
+extern "C" bool_t xdr_fhandle(XDR *, fhandle);
+#elif __STDC__
+extern bool_t xdr_fhandle(XDR *, fhandle);
+#else /* Old Style C */
+bool_t xdr_fhandle();
+#endif /* Old Style C */
+
+
+struct fhstatus {
+ u_int fhs_status;
+ union {
+ fhandle fhs_fhandle;
+ } fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+#ifdef __cplusplus
+extern "C" bool_t xdr_fhstatus(XDR *, fhstatus*);
+#elif __STDC__
+extern bool_t xdr_fhstatus(XDR *, fhstatus*);
+#else /* Old Style C */
+bool_t xdr_fhstatus();
+#endif /* Old Style C */
+
+
+typedef char *dirpath;
+#ifdef __cplusplus
+extern "C" bool_t xdr_dirpath(XDR *, dirpath*);
+#elif __STDC__
+extern bool_t xdr_dirpath(XDR *, dirpath*);
+#else /* Old Style C */
+bool_t xdr_dirpath();
+#endif /* Old Style C */
+
+
+typedef char *name;
+#ifdef __cplusplus
+extern "C" bool_t xdr_name(XDR *, name*);
+#elif __STDC__
+extern bool_t xdr_name(XDR *, name*);
+#else /* Old Style C */
+bool_t xdr_name();
+#endif /* Old Style C */
+
+
+typedef struct mountbody *mountlist;
+#ifdef __cplusplus
+extern "C" bool_t xdr_mountlist(XDR *, mountlist*);
+#elif __STDC__
+extern bool_t xdr_mountlist(XDR *, mountlist*);
+#else /* Old Style C */
+bool_t xdr_mountlist();
+#endif /* Old Style C */
+
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+#ifdef __cplusplus
+extern "C" bool_t xdr_mountbody(XDR *, mountbody*);
+#elif __STDC__
+extern bool_t xdr_mountbody(XDR *, mountbody*);
+#else /* Old Style C */
+bool_t xdr_mountbody();
+#endif /* Old Style C */
+
+
+typedef struct groupnode *groups;
+#ifdef __cplusplus
+extern "C" bool_t xdr_groups(XDR *, groups*);
+#elif __STDC__
+extern bool_t xdr_groups(XDR *, groups*);
+#else /* Old Style C */
+bool_t xdr_groups();
+#endif /* Old Style C */
+
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+#ifdef __cplusplus
+extern "C" bool_t xdr_groupnode(XDR *, groupnode*);
+#elif __STDC__
+extern bool_t xdr_groupnode(XDR *, groupnode*);
+#else /* Old Style C */
+bool_t xdr_groupnode();
+#endif /* Old Style C */
+
+
+typedef struct exportnode *exports;
+#ifdef __cplusplus
+extern "C" bool_t xdr_exports(XDR *, exports*);
+#elif __STDC__
+extern bool_t xdr_exports(XDR *, exports*);
+#else /* Old Style C */
+bool_t xdr_exports();
+#endif /* Old Style C */
+
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+#ifdef __cplusplus
+extern "C" bool_t xdr_exportnode(XDR *, exportnode*);
+#elif __STDC__
+extern bool_t xdr_exportnode(XDR *, exportnode*);
+#else /* Old Style C */
+bool_t xdr_exportnode();
+#endif /* Old Style C */
+
+
+#define MOUNTPROG ((u_long)100005)
+#define MOUNTVERS ((u_long)1)
+
+#ifdef __cplusplus
+#define MOUNTPROC_NULL ((u_long)0)
+extern "C" void * mountproc_null_1(void *, CLIENT *);
+extern "C" void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT ((u_long)1)
+extern "C" fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern "C" fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP ((u_long)2)
+extern "C" mountlist * mountproc_dump_1(void *, CLIENT *);
+extern "C" mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT ((u_long)3)
+extern "C" void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern "C" void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern "C" void * mountproc_umntall_1(void *, CLIENT *);
+extern "C" void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern "C" exports * mountproc_export_1(void *, CLIENT *);
+extern "C" exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern "C" exports * mountproc_exportall_1(void *, CLIENT *);
+extern "C" exports * mountproc_exportall_1_svc(void *, struct svc_req *);
+
+#elif __STDC__
+#define MOUNTPROC_NULL ((u_long)0)
+extern void * mountproc_null_1(void *, CLIENT *);
+extern void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT ((u_long)1)
+extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP ((u_long)2)
+extern mountlist * mountproc_dump_1(void *, CLIENT *);
+extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT ((u_long)3)
+extern void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern void * mountproc_umntall_1(void *, CLIENT *);
+extern void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern exports * mountproc_export_1(void *, CLIENT *);
+extern exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern exports * mountproc_exportall_1(void *, CLIENT *);
+extern exports * mountproc_exportall_1_svc(void *, struct svc_req *);
+
+#else /* Old Style C */
+#define MOUNTPROC_NULL ((u_long)0)
+extern void * mountproc_null_1();
+extern void * mountproc_null_1_svc();
+#define MOUNTPROC_MNT ((u_long)1)
+extern fhstatus * mountproc_mnt_1();
+extern fhstatus * mountproc_mnt_1_svc();
+#define MOUNTPROC_DUMP ((u_long)2)
+extern mountlist * mountproc_dump_1();
+extern mountlist * mountproc_dump_1_svc();
+#define MOUNTPROC_UMNT ((u_long)3)
+extern void * mountproc_umnt_1();
+extern void * mountproc_umnt_1_svc();
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern void * mountproc_umntall_1();
+extern void * mountproc_umntall_1_svc();
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern exports * mountproc_export_1();
+extern exports * mountproc_export_1_svc();
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern exports * mountproc_exportall_1();
+extern exports * mountproc_exportall_1_svc();
+#endif /* Old Style C */
+
+#endif /* !_MOUNT_H_RPCGEN */
diff --git a/mount/mount.x b/mount/mount.x
new file mode 100644
index 000000000..7e0d7f3ad
--- /dev/null
+++ b/mount/mount.x
@@ -0,0 +1,161 @@
+/* @(#)mount.x 2.1 88/08/01 4.0 RPCSRC */
+/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * Protocol description for the mount program
+ */
+
+
+const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */
+const MNTNAMLEN = 255; /* maximum bytes in a name argument */
+const FHSIZE = 32; /* size in bytes of a file handle */
+
+/*
+ * The fhandle is the file handle that the server passes to the client.
+ * All file operations are done using the file handles to refer to a file
+ * or a directory. The file handle can contain whatever information the
+ * server needs to distinguish an individual file.
+ */
+typedef opaque fhandle[FHSIZE];
+
+/*
+ * If a status of zero is returned, the call completed successfully, and
+ * a file handle for the directory follows. A non-zero status indicates
+ * some sort of error. The status corresponds with UNIX error numbers.
+ */
+union fhstatus switch (unsigned fhs_status) {
+case 0:
+ fhandle fhs_fhandle;
+default:
+ void;
+};
+
+/*
+ * The type dirpath is the pathname of a directory
+ */
+typedef string dirpath<MNTPATHLEN>;
+
+/*
+ * The type name is used for arbitrary names (hostnames, groupnames)
+ */
+typedef string name<MNTNAMLEN>;
+
+/*
+ * A list of who has what mounted
+ */
+typedef struct mountbody *mountlist;
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+
+/*
+ * A list of netgroups
+ */
+typedef struct groupnode *groups;
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+
+/*
+ * A list of what is exported and to whom
+ */
+typedef struct exportnode *exports;
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+
+program MOUNTPROG {
+ /*
+ * Version one of the mount protocol communicates with version two
+ * of the NFS protocol. The only connecting point is the fhandle
+ * structure, which is the same for both protocols.
+ */
+ version MOUNTVERS {
+ /*
+ * Does no work. It is made available in all RPC services
+ * to allow server reponse testing and timing
+ */
+ void
+ MOUNTPROC_NULL(void) = 0;
+
+ /*
+ * If fhs_status is 0, then fhs_fhandle contains the
+ * file handle for the directory. This file handle may
+ * be used in the NFS protocol. This procedure also adds
+ * a new entry to the mount list for this client mounting
+ * the directory.
+ * Unix authentication required.
+ */
+ fhstatus
+ MOUNTPROC_MNT(dirpath) = 1;
+
+ /*
+ * Returns the list of remotely mounted filesystems. The
+ * mountlist contains one entry for each hostname and
+ * directory pair.
+ */
+ mountlist
+ MOUNTPROC_DUMP(void) = 2;
+
+ /*
+ * Removes the mount list entry for the directory
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC_UMNT(dirpath) = 3;
+
+ /*
+ * Removes all of the mount list entries for this client
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC_UMNTALL(void) = 4;
+
+ /*
+ * Returns a list of all the exported filesystems, and which
+ * machines are allowed to import it.
+ */
+ exports
+ MOUNTPROC_EXPORT(void) = 5;
+
+ /*
+ * Identical to MOUNTPROC_EXPORT above
+ */
+ exports
+ MOUNTPROC_EXPORTALL(void) = 6;
+ } = 1;
+} = 100005;
diff --git a/mount/mount_clnt.c b/mount/mount_clnt.c
new file mode 100644
index 000000000..bc6e5122b
--- /dev/null
+++ b/mount/mount_clnt.c
@@ -0,0 +1,94 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include <memory.h> /* for memset */
+#include "mount.h"
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+void *
+mountproc_null_1(void *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_NULL, xdr_void, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+fhstatus *
+mountproc_mnt_1(dirpath *argp, CLIENT *clnt)
+{
+ static fhstatus clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_MNT, xdr_dirpath, argp, xdr_fhstatus, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+mountlist *
+mountproc_dump_1(void *argp, CLIENT *clnt)
+{
+ static mountlist clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_DUMP, xdr_void, argp, xdr_mountlist, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+void *
+mountproc_umnt_1(dirpath *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_UMNT, xdr_dirpath, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+void *
+mountproc_umntall_1(void *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_UMNTALL, xdr_void, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+exports *
+mountproc_export_1(void *argp, CLIENT *clnt)
+{
+ static exports clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_EXPORT, xdr_void, argp, xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+exports *
+mountproc_exportall_1(void *argp, CLIENT *clnt)
+{
+ static exports clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_EXPORTALL, xdr_void, argp, xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
diff --git a/mount/mount_xdr.c b/mount/mount_xdr.c
new file mode 100644
index 000000000..be5eb41f1
--- /dev/null
+++ b/mount/mount_xdr.c
@@ -0,0 +1,150 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "mount.h"
+
+bool_t
+xdr_fhandle(XDR *xdrs, fhandle objp)
+{
+
+ register long *buf;
+
+ if (!xdr_opaque(xdrs, objp, FHSIZE)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_fhstatus(XDR *xdrs, fhstatus *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_u_int(xdrs, &objp->fhs_status)) {
+ return (FALSE);
+ }
+ switch (objp->fhs_status) {
+ case 0:
+ if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) {
+ return (FALSE);
+ }
+ break;
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_dirpath(XDR *xdrs, dirpath *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_string(xdrs, objp, MNTPATHLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_name(XDR *xdrs, name *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_string(xdrs, objp, MNTNAMLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_mountlist(XDR *xdrs, mountlist *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct mountbody), (xdrproc_t)xdr_mountbody)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_mountbody(XDR *xdrs, mountbody *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_name(xdrs, &objp->ml_hostname)) {
+ return (FALSE);
+ }
+ if (!xdr_dirpath(xdrs, &objp->ml_directory)) {
+ return (FALSE);
+ }
+ if (!xdr_mountlist(xdrs, &objp->ml_next)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_groups(XDR *xdrs, groups *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct groupnode), (xdrproc_t)xdr_groupnode)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_groupnode(XDR *xdrs, groupnode *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_name(xdrs, &objp->gr_name)) {
+ return (FALSE);
+ }
+ if (!xdr_groups(xdrs, &objp->gr_next)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_exports(XDR *xdrs, exports *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct exportnode), (xdrproc_t)xdr_exportnode)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_exportnode(XDR *xdrs, exportnode *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_dirpath(xdrs, &objp->ex_dir)) {
+ return (FALSE);
+ }
+ if (!xdr_groups(xdrs, &objp->ex_groups)) {
+ return (FALSE);
+ }
+ if (!xdr_exports(xdrs, &objp->ex_next)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
diff --git a/mount/nfs.5 b/mount/nfs.5
new file mode 100644
index 000000000..ee5203f5a
--- /dev/null
+++ b/mount/nfs.5
@@ -0,0 +1,209 @@
+.\" nfs.5 "Rick Sladkey" <jrs@world.std.com>
+.\" Wed Feb 8 12:52:42 1995, faith@cs.unc.edu: updates for Ross Biro's
+.\" patches. "
+.TH NFS 5 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+nfs \- nfs fstab format and options
+.SH SYNOPSIS
+.B /etc/fstab
+.SH DESCRIPTION
+The
+.I fstab
+file contains information about which filesystems
+to mount where and with what options.
+For NFS mounts, it contains the server name and
+exported server directory to mount from,
+the local directory that is the mount point,
+and the NFS specific options that control
+the way the filesystem is mounted.
+.P
+Here is an example from an \fI/etc/fstab\fP file from an NFS mount.
+.sp
+.nf
+.ta 2.5i +0.75i +0.75i +1.0i
+server:/usr/local/pub /pub nfs timeo=14,intr
+.fi
+.DT
+.SS Options
+.TP 1.5i
+.I rsize=n
+The number of bytes NFS uses when reading files from an NFS server.
+The default value is dependent on the kernel, currently 1024 bytes.
+.TP 1.5i
+.I wsize=n
+The number of bytes NFS uses when writing files to an NFS server.
+The default value is dependent on the kernel, currently 1024 bytes.
+.TP 1.5i
+.I timeo=n
+The value in tenths of a second before sending the
+first retransmission after an RPC timeout.
+The default value is 7 tenths of a second. After the first timeout,
+the timeout is doubled after each successive timeout until a maximum
+timeout of 60 seconds is reached or the enough retransmissions
+have occured to cause a major timeout. Then, if the filesystem
+is hard mounted, each new timeout cascade restarts at twice the
+initial value of the previous cascade, again doubling at each
+retransmission. The maximum timeout is always 60 seconds.
+Better overall performance may be achieved by increasing the
+timeout when mounting on a busy network, to a slow server, or through
+several routers or gateways.
+.TP 1.5i
+.I retrans=n
+The number of minor timeouts and retransmissions that must occur before
+a major timeout occurs. The default is 3 timeouts. When a major timeout
+occurs, the file operation is either aborted or a "server not responding"
+message is printed on the console.
+.TP 1.5i
+.I acregmin=n
+The minimum time in seconds that attributes of a regular file should
+be cached before requesting fresh information from a server.
+The default is 3 seconds.
+.TP 1.5i
+.I acregmax=n
+The maximum time in seconds that attributes of a regular file can
+be cached before requesting fresh information from a server.
+The default is 60 seconds.
+.TP 1.5i
+.I acdirmin=n
+The minimum time in seconds that attributes of a directory should
+be cached before requesting fresh information from a server.
+The default is 30 seconds.
+.TP 1.5i
+.I acdirmax=n
+The maximum time in seconds that attributes of a directory can
+be cached before requesting fresh information from a server.
+The default is 60 seconds.
+.TP 1.5i
+.I actimeo=n
+Using actimeo sets all of
+.I acregmin,
+.I acregmax,
+.I acdirmin,
+and
+.I acdirmax
+to the same value.
+There is no default value.
+.TP 1.5i
+.I retry=n
+The number of times to retry a backgrounded NFS mount operation
+before giving up.
+The default value is 10000 times.
+.TP 1.5i
+.I namlen=n
+When an NFS server does not support version two of the
+RPC mount protocol, this option can be used to specify
+the maximum length of a filename that is supported on
+the remote filesystem. This is used to support the
+POSIX pathconf functions. The default is 255 characters.
+.TP 1.5i
+.I port=n
+The numeric value of the port to connect to the NFS server on.
+If the port number is 0 (the default) then query the
+remote host's portmapper for the port number to use.
+If the remote host's NFS daemon is not registered with
+its portmapper, the standard NFS port number 2049 is
+used instead.
+.TP 1.5i
+.I mountport=n
+The numeric value of the
+.B mountd
+port.
+.TP 1.5i
+.I mounthost=name
+The name of the host running
+.B mountd .
+.TP 1.5i
+.I mountprog=n
+Use an alternate RPC program number to contact the
+mount daemon on the remote host. This option is useful
+for hosts that can run multiple NFS servers.
+The default value is 100005 which is the standard RPC
+mount daemon program number.
+.TP 1.5i
+.I mountvers=n
+Use an alternate RPC version number to contact the
+mount daemon on the remote host. This option is useful
+for hosts that can run multiple NFS servers.
+The default value is version 1.
+.TP 1.5i
+.I nfsprog=n
+Use an alternate RPC program number to contact the
+NFS daemon on the remote host. This option is useful
+for hosts that can run multiple NFS servers.
+The default value is 100003 which is the standard RPC
+NFS daemon program number.
+.TP 1.5i
+.I nfsvers=n
+Use an alternate RPC version number to contact the
+NFS daemon on the remote host. This option is useful
+for hosts that can run multiple NFS servers.
+The default value is version 2.
+.TP 1.5i
+.I bg
+If the first NFS mount attempt times out, continue trying the mount
+in the background.
+The default is to not to background the mount on timeout but fail.
+.TP 1.5i
+.I fg
+If the first NFS mount attempt times out, fail immediately.
+This is the default.
+.TP 1.5i
+.I soft
+If an NFS file operation has a major timeout then report an I/O error to
+the calling program.
+The default is to continue retrying NFS file operations indefinitely.
+.TP 1.5i
+.I hard
+If an NFS file operation has a major timeout then report
+"server not responding" on the console and continue retrying indefinitely.
+This is the default.
+.TP 1.5i
+.I intr
+If an NFS file operation has a major timeout and it is hard mounted,
+then allow signals to interupt the file operation and cause it to
+return EINTR to the calling program. The default is to not
+allow file operations to be interrupted.
+.TP 1.5i
+.I posix
+Mount the NFS filesystem using POSIX semantics. This allows
+an NFS filesystem to properly support the POSIX pathconf
+command by querying the mount server for the maximum length
+of a filename. To do this, the remote host must support version
+two of the RPC mount protocol. Many NFS servers support only
+version one.
+.TP 1.5i
+.I nocto
+Supress the retrieval of new attributes when creating a file.
+.TP 1.5i
+.I noac
+Disable all forms of attribute caching entirely. This extracts a
+server performance penalty but it allows two different NFS clients
+to get reasonable good results when both clients are actively
+writing to common filesystem on the server.
+.TP 1.5i
+.I tcp
+Mount the NFS filesystem using the TCP protocol instead of the
+default UDP protocol. Many NFS severs only support UDP.
+.TP 1.5i
+.I udp
+Mount the NFS filesystem using the UDP protocol. This
+is the default.
+.P
+All of the non-value options have corresponding nooption forms.
+For example, nointr means don't allow file operations to be
+interrupted.
+.SH FILES
+.I /etc/fstab
+.SH "SEE ALSO"
+.BR fstab "(5), " mount "(8), " umount (8)
+.SH AUTHOR
+"Rick Sladkey" <jrs@world.std.com>
+.SH BUGS
+The bg, fg, retry, posix, and nocto options are parsed by mount
+but currently are silently ignored.
+.P
+The tcp and namlen options are implemented but are not currently
+supported by the Linux kernel.
+.P
+The umount command should notify the server
+when an NFS filesystem is unmounted.
diff --git a/mount/nfsmount.c b/mount/nfsmount.c
new file mode 100644
index 000000000..9be51be02
--- /dev/null
+++ b/mount/nfsmount.c
@@ -0,0 +1,475 @@
+/*
+ * nfsmount.c -- Linux NFS mount
+ * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
+ *
+ * This program is free software; 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, or (at your option)
+ * any later version.
+ *
+ * This program 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.
+ *
+ * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
+ * numbers to be specified on the command line.
+ */
+
+/*
+ * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ */
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <string.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include "sundries.h"
+
+#include "mount.h"
+
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/nfs_mount.h>
+
+static char *strndup (char *str, int n) {
+ char *ret;
+ ret = malloc (n+1);
+ if (ret == NULL) {
+ perror ("malloc");
+ return (NULL);
+ }
+ strncpy (ret, str, n);
+ return (ret);
+}
+
+static char *nfs_strerror(int stat);
+
+int nfsmount(const char *spec, const char *node, int *flags,
+ char **extra_opts, char **mount_opts)
+{
+ char hostdir[1024];
+ CLIENT *mclient;
+ char *hostname;
+ char *dirname;
+ char *old_opts;
+ char *mounthost=NULL;
+ char new_opts[1024];
+ fhandle root_fhandle;
+ struct timeval total_timeout;
+ enum clnt_stat clnt_stat;
+ static struct nfs_mount_data data;
+ char *opt, *opteq;
+ int val;
+ struct hostent *hp;
+ struct sockaddr_in server_addr;
+ struct sockaddr_in mount_server_addr;
+ int msock, fsock;
+ struct timeval pertry_timeout;
+ struct fhstatus status;
+ char *s;
+ int port;
+ int mountport;
+ int bg;
+ int soft;
+ int intr;
+ int posix;
+ int nocto;
+ int noac;
+ int retry;
+ int tcp;
+ int mountprog;
+ int mountvers;
+ int nfsprog;
+ int nfsvers;
+
+ msock = fsock = -1;
+ mclient = NULL;
+ strcpy(hostdir, spec);
+ if ((s = (strchr(hostdir, ':')))) {
+ hostname = hostdir;
+ dirname = s + 1;
+ *s = '\0';
+ }
+ else {
+ fprintf(stderr, "mount: "
+ "directory to mount not in host:dir format\n");
+ goto fail;
+ }
+
+ if (hostname[0] >= '0' && hostname[0] <= '9') {
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_addr.s_addr = inet_addr(hostname);
+ }
+ else if ((hp = gethostbyname(hostname)) == NULL) {
+ fprintf(stderr, "mount: can't get address for %s\n", hostname);
+ goto fail;
+ }
+ else {
+ server_addr.sin_family = AF_INET;
+ memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+ memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
+
+ /* add IP address to mtab options for use when unmounting */
+
+ old_opts = *extra_opts;
+ if (!old_opts)
+ old_opts = "";
+ sprintf(new_opts, "%s%saddr=%s",
+ old_opts, *old_opts ? "," : "",
+ inet_ntoa(server_addr.sin_addr));
+ *extra_opts = strdup(new_opts);
+
+ /* set default options */
+
+ data.rsize = 0; /* let kernel decide */
+ data.wsize = 0; /* let kernel decide */
+ data.timeo = 7;
+ data.retrans = 3;
+ data.acregmin = 3;
+ data.acregmax = 60;
+ data.acdirmin = 30;
+ data.acdirmax = 60;
+#if NFS_MOUNT_VERSION >= 2
+ data.namlen = NAME_MAX;
+#endif
+
+ bg = 0;
+ soft = 0;
+ intr = 0;
+ posix = 0;
+ nocto = 0;
+ noac = 0;
+ retry = 10000;
+ tcp = 0;
+
+ mountprog = MOUNTPROG;
+ mountvers = MOUNTVERS;
+ port = 0;
+ mountport = 0;
+ nfsprog = NFS_PROGRAM;
+ nfsvers = NFS_VERSION;
+
+ /* parse options */
+
+ for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
+ if ((opteq = strchr(opt, '='))) {
+ val = atoi(opteq + 1);
+ *opteq = '\0';
+ if (!strcmp(opt, "rsize"))
+ data.rsize = val;
+ else if (!strcmp(opt, "wsize"))
+ data.wsize = val;
+ else if (!strcmp(opt, "timeo"))
+ data.timeo = val;
+ else if (!strcmp(opt, "retrans"))
+ data.retrans = val;
+ else if (!strcmp(opt, "acregmin"))
+ data.acregmin = val;
+ else if (!strcmp(opt, "acregmax"))
+ data.acregmax = val;
+ else if (!strcmp(opt, "acdirmin"))
+ data.acdirmin = val;
+ else if (!strcmp(opt, "acdirmax"))
+ data.acdirmax = val;
+ else if (!strcmp(opt, "actimeo")) {
+ data.acregmin = val;
+ data.acregmax = val;
+ data.acdirmin = val;
+ data.acdirmax = val;
+ }
+ else if (!strcmp(opt, "retry"))
+ retry = val;
+ else if (!strcmp(opt, "port"))
+ port = val;
+ else if (!strcmp(opt, "mountport"))
+ mountport = val;
+ else if (!strcmp(opt, "mounthost"))
+ mounthost=strndup(opteq+1,
+ strcspn(opteq+1," \t\n\r,"));
+ else if (!strcmp(opt, "mountprog"))
+ mountprog = val;
+ else if (!strcmp(opt, "mountvers"))
+ mountvers = val;
+ else if (!strcmp(opt, "nfsprog"))
+ nfsprog = val;
+ else if (!strcmp(opt, "nfsvers"))
+ nfsvers = val;
+ else if (!strcmp(opt, "namlen")) {
+#if NFS_MOUNT_VERSION >= 2
+ data.namlen = val;
+#else
+ printf("Warning: Option namlen is not supported.\n");
+#endif
+ }
+ else if (!strcmp(opt, "addr"))
+ /* ignore */;
+ else {
+ printf("unknown nfs mount parameter: "
+ "%s=%d\n", opt, val);
+ goto fail;
+ }
+ }
+ else {
+ val = 1;
+ if (!strncmp(opt, "no", 2)) {
+ val = 0;
+ opt += 2;
+ }
+ if (!strcmp(opt, "bg"))
+ bg = val;
+ else if (!strcmp(opt, "fg"))
+ bg = !val;
+ else if (!strcmp(opt, "soft"))
+ soft = val;
+ else if (!strcmp(opt, "hard"))
+ soft = !val;
+ else if (!strcmp(opt, "intr"))
+ intr = val;
+ else if (!strcmp(opt, "posix"))
+ posix = val;
+ else if (!strcmp(opt, "cto"))
+ nocto = !val;
+ else if (!strcmp(opt, "ac"))
+ noac = !val;
+ else if (!strcmp(opt, "tcp"))
+ tcp = val;
+ else if (!strcmp(opt, "udp"))
+ tcp = !val;
+ else {
+ printf("unknown nfs mount option: "
+ "%s%s\n", val ? "" : "no", opt);
+ goto fail;
+ }
+ }
+ }
+ data.flags = (soft ? NFS_MOUNT_SOFT : 0)
+ | (intr ? NFS_MOUNT_INTR : 0)
+ | (posix ? NFS_MOUNT_POSIX : 0)
+ | (nocto ? NFS_MOUNT_NOCTO : 0)
+ | (noac ? NFS_MOUNT_NOAC : 0);
+#if NFS_MOUNT_VERSION >= 2
+ data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
+#endif
+
+#ifdef NFS_MOUNT_DEBUG
+ printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
+ data.rsize, data.wsize, data.timeo, data.retrans);
+ printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
+ data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
+ printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
+ port, bg, retry, data.flags);
+ printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
+ mountprog, mountvers, nfsprog, nfsvers);
+ printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
+ (data.flags & NFS_MOUNT_SOFT) != 0,
+ (data.flags & NFS_MOUNT_INTR) != 0,
+ (data.flags & NFS_MOUNT_POSIX) != 0,
+ (data.flags & NFS_MOUNT_NOCTO) != 0,
+ (data.flags & NFS_MOUNT_NOAC) != 0);
+#if NFS_MOUNT_VERSION >= 2
+ printf("tcp = %d\n",
+ (data.flags & NFS_MOUNT_TCP) != 0);
+#endif
+#if 0
+ goto fail;
+#endif
+#endif
+
+ data.version = NFS_MOUNT_VERSION;
+ *mount_opts = (char *) &data;
+
+ if (*flags & MS_REMOUNT)
+ return 0;
+
+ /* create mount deamon client */
+ /* See if the nfs host = mount host. */
+ if (mounthost) {
+ if (mounthost[0] >= '0' && mounthost[0] <= '9') {
+ mount_server_addr.sin_family = AF_INET;
+ mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
+ }
+ else if ((hp = gethostbyname(mounthost)) == NULL) {
+ fprintf(stderr, "mount: can't get address for %s\n", hostname);
+ goto fail;
+ }
+ else {
+ mount_server_addr.sin_family = AF_INET;
+ memcpy(&mount_server_addr.sin_addr, hp->h_addr, hp->h_length);
+ }
+ }
+
+ mount_server_addr.sin_port = htons(mountport);
+ msock = RPC_ANYSOCK;
+ if ((mclient = clnttcp_create(&mount_server_addr,
+ mountprog, mountvers, &msock, 0, 0)) == NULL) {
+ mount_server_addr.sin_port = htons(mountport);
+ msock = RPC_ANYSOCK;
+ pertry_timeout.tv_sec = 3;
+ pertry_timeout.tv_usec = 0;
+ if ((mclient = clntudp_create(&mount_server_addr,
+ mountprog, mountvers, pertry_timeout, &msock)) == NULL) {
+ clnt_pcreateerror("mount clntudp_create");
+ goto fail;
+ }
+#ifdef NFS_MOUNT_DEBUG
+ printf("using UDP for mount deamon\n");
+#endif
+ }
+#ifdef NFS_MOUNT_DEBUG
+ else
+ printf("using TCP for mount deamon\n");
+#endif
+ mclient->cl_auth = authunix_create_default();
+ total_timeout.tv_sec = 20;
+ total_timeout.tv_usec = 0;
+
+ /* try to mount hostname:dirname */
+
+ clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
+ xdr_dirpath, &dirname,
+ xdr_fhstatus, &status,
+ total_timeout);
+ if (clnt_stat != RPC_SUCCESS) {
+ clnt_perror(mclient, "rpc mount");
+ goto fail;
+ }
+ if (status.fhs_status != 0) {
+ fprintf(stderr,
+ "mount: %s:%s failed, reason given by server: %s\n",
+ hostname, dirname, nfs_strerror(status.fhs_status));
+ goto fail;
+ }
+ memcpy((char *) &root_fhandle, (char *) status.fhstatus_u.fhs_fhandle,
+ sizeof (root_fhandle));
+
+ /* create nfs socket for kernel */
+
+ if (tcp) {
+#if NFS_MOUNT_VERSION >= 2
+ fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+#else
+ printf("NFS over TCP is not supported.\n");
+ goto fail;
+#endif
+ }
+ else
+ fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (fsock < 0) {
+ perror("nfs socket");
+ goto fail;
+ }
+ if (bindresvport(fsock, 0) < 0) {
+ perror("nfs bindresvport");
+ goto fail;
+ }
+ if (port == 0) {
+ server_addr.sin_port = PMAPPORT;
+ port = pmap_getport(&server_addr, nfsprog, nfsvers,
+ tcp ? IPPROTO_TCP : IPPROTO_UDP);
+ if (port == 0)
+ port = NFS_PORT;
+#ifdef NFS_MOUNT_DEBUG
+ else
+ printf("used portmapper to find NFS port\n");
+#endif
+ }
+#ifdef NFS_MOUNT_DEBUG
+ printf("using port %d for nfs deamon\n", port);
+#endif
+ server_addr.sin_port = htons(port);
+ if (connect(fsock, (struct sockaddr *) &server_addr,
+ sizeof (server_addr)) < 0) {
+ perror("nfs connect");
+ goto fail;
+ }
+
+ /* prepare data structure for kernel */
+
+ data.fd = fsock;
+ memcpy((char *) &data.root, (char *) &root_fhandle,
+ sizeof (root_fhandle));
+ memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
+ strncpy(data.hostname, hostname, sizeof(data.hostname));
+
+ /* clean up */
+
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ close(msock);
+ return 0;
+
+ /* abort */
+
+fail:
+ if (msock != -1) {
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ close(msock);
+ }
+ if (fsock != -1)
+ close(fsock);
+ return 1;}
+
+
+/*
+ * We need to translate between nfs status return values and
+ * the local errno values which may not be the same.
+ */
+
+#ifndef EDQUOT
+#define EDQUOT ENOSPC
+#endif
+
+static struct {
+ enum nfs_stat stat;
+ int errno;
+} nfs_errtbl[] = {
+ { NFS_OK, 0 },
+ { NFSERR_PERM, EPERM },
+ { NFSERR_NOENT, ENOENT },
+ { NFSERR_IO, EIO },
+ { NFSERR_NXIO, ENXIO },
+ { NFSERR_ACCES, EACCES },
+ { NFSERR_EXIST, EEXIST },
+ { NFSERR_NODEV, ENODEV },
+ { NFSERR_NOTDIR, ENOTDIR },
+ { NFSERR_ISDIR, EISDIR },
+#ifdef NFSERR_INVAL
+ { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
+#endif
+ { NFSERR_FBIG, EFBIG },
+ { NFSERR_NOSPC, ENOSPC },
+ { NFSERR_ROFS, EROFS },
+ { NFSERR_NAMETOOLONG, ENAMETOOLONG },
+ { NFSERR_NOTEMPTY, ENOTEMPTY },
+ { NFSERR_DQUOT, EDQUOT },
+ { NFSERR_STALE, ESTALE },
+#ifdef EWFLUSH
+ { NFSERR_WFLUSH, EWFLUSH },
+#endif
+ { -1, EIO }
+};
+
+static char *nfs_strerror(int stat)
+{
+ int i;
+ static char buf[256];
+
+ for (i = 0; nfs_errtbl[i].stat != -1; i++) {
+ if (nfs_errtbl[i].stat == stat)
+ return strerror(nfs_errtbl[i].errno);
+ }
+ sprintf(buf, "unknown nfs status return value: %d", stat);
+ return buf;
+}
+
diff --git a/mount/realpath.c b/mount/realpath.c
new file mode 100644
index 000000000..4ea46a311
--- /dev/null
+++ b/mount/realpath.c
@@ -0,0 +1,178 @@
+/*
+ * realpath.c -- canonicalize pathname by removing symlinks
+ * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program 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 Library Public License for more details.
+ */
+
+/*
+ * realpath.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ */
+
+#ifdef __linux__
+extern char *realpath(const char *path, char *resolved_path);
+#define HAVE_UNISTD_H
+#define HAVE_STRING_H
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#if defined(HAVE_UNISTD_H) || defined(STDC_HEADERS)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#ifdef _POSIX_VERSION
+#include <limits.h> /* for PATH_MAX */
+#else
+#include <sys/param.h> /* for MAXPATHLEN */
+#endif
+#include <errno.h>
+#ifndef STDC_HEADERS
+extern int errno;
+#endif
+
+#include <sys/stat.h> /* for S_IFLNK */
+
+#ifndef PATH_MAX
+#ifdef _POSIX_VERSION
+#define PATH_MAX _POSIX_PATH_MAX
+#else
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+#endif
+
+#define MAX_READLINKS 32
+
+#ifdef __STDC__
+char *realpath(const char *path, char *resolved_path)
+#else
+char *realpath(path, resolved_path)
+const char *path;
+char *resolved_path;
+#endif
+{
+ char copy_path[PATH_MAX];
+ char link_path[PATH_MAX];
+ char *new_path = resolved_path;
+ char *max_path;
+ int readlinks = 0;
+ int n;
+
+ /* Make a copy of the source path since we may need to modify it. */
+ strcpy(copy_path, path);
+ path = copy_path;
+ max_path = copy_path + PATH_MAX - 2;
+ /* If it's a relative pathname use getwd for starters. */
+ if (*path != '/') {
+#ifdef HAVE_GETCWD
+ getcwd(new_path, PATH_MAX - 1);
+#else
+ getwd(new_path);
+#endif
+ new_path += strlen(new_path);
+ if (new_path[-1] != '/')
+ *new_path++ = '/';
+ }
+ else {
+ *new_path++ = '/';
+ path++;
+ }
+ /* Expand each slash-separated pathname component. */
+ while (*path != '\0') {
+ /* Ignore stray "/". */
+ if (*path == '/') {
+ path++;
+ continue;
+ }
+ if (*path == '.') {
+ /* Ignore ".". */
+ if (path[1] == '\0' || path[1] == '/') {
+ path++;
+ continue;
+ }
+ if (path[1] == '.') {
+ if (path[2] == '\0' || path[2] == '/') {
+ path += 2;
+ /* Ignore ".." at root. */
+ if (new_path == resolved_path + 1)
+ continue;
+ /* Handle ".." by backing up. */
+ while ((--new_path)[-1] != '/')
+ ;
+ continue;
+ }
+ }
+ }
+ /* Safely copy the next pathname component. */
+ while (*path != '\0' && *path != '/') {
+ if (path > max_path) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ *new_path++ = *path++;
+ }
+#ifdef S_IFLNK
+ /* Protect against infinite loops. */
+ if (readlinks++ > MAX_READLINKS) {
+ errno = ELOOP;
+ return NULL;
+ }
+ /* See if latest pathname component is a symlink. */
+ *new_path = '\0';
+ n = readlink(resolved_path, link_path, PATH_MAX - 1);
+ if (n < 0) {
+ /* EINVAL means the file exists but isn't a symlink. */
+ if (errno != EINVAL)
+ return NULL;
+ }
+ else {
+ /* Note: readlink doesn't add the null byte. */
+ link_path[n] = '\0';
+ if (*link_path == '/')
+ /* Start over for an absolute symlink. */
+ new_path = resolved_path;
+ else
+ /* Otherwise back up over this component. */
+ while (*(--new_path) != '/')
+ ;
+ /* Safe sex check. */
+ if (strlen(path) + n >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ /* Insert symlink contents into path. */
+ strcat(link_path, path);
+ strcpy(copy_path, link_path);
+ path = copy_path;
+ }
+#endif /* S_IFLNK */
+ *new_path++ = '/';
+ }
+ /* Delete trailing slash but don't whomp a lone slash. */
+ if (new_path != resolved_path + 1 && new_path[-1] == '/')
+ new_path--;
+ /* Make sure it's null terminated. */
+ *new_path = '\0';
+ return resolved_path;
+}
+
diff --git a/mount/rpcsvc/mount.h b/mount/rpcsvc/mount.h
new file mode 100644
index 000000000..d70ccaf9d
--- /dev/null
+++ b/mount/rpcsvc/mount.h
@@ -0,0 +1,208 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _MOUNT_H_RPCGEN
+#define _MOUNT_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+
+typedef char fhandle[FHSIZE];
+#ifdef __cplusplus
+extern "C" bool_t xdr_fhandle(XDR *, fhandle);
+#elif __STDC__
+extern bool_t xdr_fhandle(XDR *, fhandle);
+#else /* Old Style C */
+bool_t xdr_fhandle();
+#endif /* Old Style C */
+
+
+struct fhstatus {
+ u_int fhs_status;
+ union {
+ fhandle fhs_fhandle;
+ } fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+#ifdef __cplusplus
+extern "C" bool_t xdr_fhstatus(XDR *, fhstatus*);
+#elif __STDC__
+extern bool_t xdr_fhstatus(XDR *, fhstatus*);
+#else /* Old Style C */
+bool_t xdr_fhstatus();
+#endif /* Old Style C */
+
+
+typedef char *dirpath;
+#ifdef __cplusplus
+extern "C" bool_t xdr_dirpath(XDR *, dirpath*);
+#elif __STDC__
+extern bool_t xdr_dirpath(XDR *, dirpath*);
+#else /* Old Style C */
+bool_t xdr_dirpath();
+#endif /* Old Style C */
+
+
+typedef char *name;
+#ifdef __cplusplus
+extern "C" bool_t xdr_name(XDR *, name*);
+#elif __STDC__
+extern bool_t xdr_name(XDR *, name*);
+#else /* Old Style C */
+bool_t xdr_name();
+#endif /* Old Style C */
+
+
+typedef struct mountbody *mountlist;
+#ifdef __cplusplus
+extern "C" bool_t xdr_mountlist(XDR *, mountlist*);
+#elif __STDC__
+extern bool_t xdr_mountlist(XDR *, mountlist*);
+#else /* Old Style C */
+bool_t xdr_mountlist();
+#endif /* Old Style C */
+
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+#ifdef __cplusplus
+extern "C" bool_t xdr_mountbody(XDR *, mountbody*);
+#elif __STDC__
+extern bool_t xdr_mountbody(XDR *, mountbody*);
+#else /* Old Style C */
+bool_t xdr_mountbody();
+#endif /* Old Style C */
+
+
+typedef struct groupnode *groups;
+#ifdef __cplusplus
+extern "C" bool_t xdr_groups(XDR *, groups*);
+#elif __STDC__
+extern bool_t xdr_groups(XDR *, groups*);
+#else /* Old Style C */
+bool_t xdr_groups();
+#endif /* Old Style C */
+
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+#ifdef __cplusplus
+extern "C" bool_t xdr_groupnode(XDR *, groupnode*);
+#elif __STDC__
+extern bool_t xdr_groupnode(XDR *, groupnode*);
+#else /* Old Style C */
+bool_t xdr_groupnode();
+#endif /* Old Style C */
+
+
+typedef struct exportnode *exports;
+#ifdef __cplusplus
+extern "C" bool_t xdr_exports(XDR *, exports*);
+#elif __STDC__
+extern bool_t xdr_exports(XDR *, exports*);
+#else /* Old Style C */
+bool_t xdr_exports();
+#endif /* Old Style C */
+
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+#ifdef __cplusplus
+extern "C" bool_t xdr_exportnode(XDR *, exportnode*);
+#elif __STDC__
+extern bool_t xdr_exportnode(XDR *, exportnode*);
+#else /* Old Style C */
+bool_t xdr_exportnode();
+#endif /* Old Style C */
+
+
+#define MOUNTPROG ((u_long)100005)
+#define MOUNTVERS ((u_long)1)
+
+#ifdef __cplusplus
+#define MOUNTPROC_NULL ((u_long)0)
+extern "C" void * mountproc_null_1(void *, CLIENT *);
+extern "C" void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT ((u_long)1)
+extern "C" fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern "C" fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP ((u_long)2)
+extern "C" mountlist * mountproc_dump_1(void *, CLIENT *);
+extern "C" mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT ((u_long)3)
+extern "C" void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern "C" void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern "C" void * mountproc_umntall_1(void *, CLIENT *);
+extern "C" void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern "C" exports * mountproc_export_1(void *, CLIENT *);
+extern "C" exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern "C" exports * mountproc_exportall_1(void *, CLIENT *);
+extern "C" exports * mountproc_exportall_1_svc(void *, struct svc_req *);
+
+#elif __STDC__
+#define MOUNTPROC_NULL ((u_long)0)
+extern void * mountproc_null_1(void *, CLIENT *);
+extern void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT ((u_long)1)
+extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP ((u_long)2)
+extern mountlist * mountproc_dump_1(void *, CLIENT *);
+extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT ((u_long)3)
+extern void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern void * mountproc_umntall_1(void *, CLIENT *);
+extern void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern exports * mountproc_export_1(void *, CLIENT *);
+extern exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern exports * mountproc_exportall_1(void *, CLIENT *);
+extern exports * mountproc_exportall_1_svc(void *, struct svc_req *);
+
+#else /* Old Style C */
+#define MOUNTPROC_NULL ((u_long)0)
+extern void * mountproc_null_1();
+extern void * mountproc_null_1_svc();
+#define MOUNTPROC_MNT ((u_long)1)
+extern fhstatus * mountproc_mnt_1();
+extern fhstatus * mountproc_mnt_1_svc();
+#define MOUNTPROC_DUMP ((u_long)2)
+extern mountlist * mountproc_dump_1();
+extern mountlist * mountproc_dump_1_svc();
+#define MOUNTPROC_UMNT ((u_long)3)
+extern void * mountproc_umnt_1();
+extern void * mountproc_umnt_1_svc();
+#define MOUNTPROC_UMNTALL ((u_long)4)
+extern void * mountproc_umntall_1();
+extern void * mountproc_umntall_1_svc();
+#define MOUNTPROC_EXPORT ((u_long)5)
+extern exports * mountproc_export_1();
+extern exports * mountproc_export_1_svc();
+#define MOUNTPROC_EXPORTALL ((u_long)6)
+extern exports * mountproc_exportall_1();
+extern exports * mountproc_exportall_1_svc();
+#endif /* Old Style C */
+
+#endif /* !_MOUNT_H_RPCGEN */
diff --git a/mount/rpcsvc/mount.x b/mount/rpcsvc/mount.x
new file mode 100644
index 000000000..7e0d7f3ad
--- /dev/null
+++ b/mount/rpcsvc/mount.x
@@ -0,0 +1,161 @@
+/* @(#)mount.x 2.1 88/08/01 4.0 RPCSRC */
+/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * Protocol description for the mount program
+ */
+
+
+const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */
+const MNTNAMLEN = 255; /* maximum bytes in a name argument */
+const FHSIZE = 32; /* size in bytes of a file handle */
+
+/*
+ * The fhandle is the file handle that the server passes to the client.
+ * All file operations are done using the file handles to refer to a file
+ * or a directory. The file handle can contain whatever information the
+ * server needs to distinguish an individual file.
+ */
+typedef opaque fhandle[FHSIZE];
+
+/*
+ * If a status of zero is returned, the call completed successfully, and
+ * a file handle for the directory follows. A non-zero status indicates
+ * some sort of error. The status corresponds with UNIX error numbers.
+ */
+union fhstatus switch (unsigned fhs_status) {
+case 0:
+ fhandle fhs_fhandle;
+default:
+ void;
+};
+
+/*
+ * The type dirpath is the pathname of a directory
+ */
+typedef string dirpath<MNTPATHLEN>;
+
+/*
+ * The type name is used for arbitrary names (hostnames, groupnames)
+ */
+typedef string name<MNTNAMLEN>;
+
+/*
+ * A list of who has what mounted
+ */
+typedef struct mountbody *mountlist;
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+
+/*
+ * A list of netgroups
+ */
+typedef struct groupnode *groups;
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+
+/*
+ * A list of what is exported and to whom
+ */
+typedef struct exportnode *exports;
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+
+program MOUNTPROG {
+ /*
+ * Version one of the mount protocol communicates with version two
+ * of the NFS protocol. The only connecting point is the fhandle
+ * structure, which is the same for both protocols.
+ */
+ version MOUNTVERS {
+ /*
+ * Does no work. It is made available in all RPC services
+ * to allow server reponse testing and timing
+ */
+ void
+ MOUNTPROC_NULL(void) = 0;
+
+ /*
+ * If fhs_status is 0, then fhs_fhandle contains the
+ * file handle for the directory. This file handle may
+ * be used in the NFS protocol. This procedure also adds
+ * a new entry to the mount list for this client mounting
+ * the directory.
+ * Unix authentication required.
+ */
+ fhstatus
+ MOUNTPROC_MNT(dirpath) = 1;
+
+ /*
+ * Returns the list of remotely mounted filesystems. The
+ * mountlist contains one entry for each hostname and
+ * directory pair.
+ */
+ mountlist
+ MOUNTPROC_DUMP(void) = 2;
+
+ /*
+ * Removes the mount list entry for the directory
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC_UMNT(dirpath) = 3;
+
+ /*
+ * Removes all of the mount list entries for this client
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC_UMNTALL(void) = 4;
+
+ /*
+ * Returns a list of all the exported filesystems, and which
+ * machines are allowed to import it.
+ */
+ exports
+ MOUNTPROC_EXPORT(void) = 5;
+
+ /*
+ * Identical to MOUNTPROC_EXPORT above
+ */
+ exports
+ MOUNTPROC_EXPORTALL(void) = 6;
+ } = 1;
+} = 100005;
diff --git a/mount/rpcsvc/mount_clnt.c b/mount/rpcsvc/mount_clnt.c
new file mode 100644
index 000000000..bc6e5122b
--- /dev/null
+++ b/mount/rpcsvc/mount_clnt.c
@@ -0,0 +1,94 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include <memory.h> /* for memset */
+#include "mount.h"
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+void *
+mountproc_null_1(void *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_NULL, xdr_void, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+fhstatus *
+mountproc_mnt_1(dirpath *argp, CLIENT *clnt)
+{
+ static fhstatus clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_MNT, xdr_dirpath, argp, xdr_fhstatus, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+mountlist *
+mountproc_dump_1(void *argp, CLIENT *clnt)
+{
+ static mountlist clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_DUMP, xdr_void, argp, xdr_mountlist, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+void *
+mountproc_umnt_1(dirpath *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_UMNT, xdr_dirpath, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+void *
+mountproc_umntall_1(void *argp, CLIENT *clnt)
+{
+ static char clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_UMNTALL, xdr_void, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return ((void *)&clnt_res);
+}
+
+exports *
+mountproc_export_1(void *argp, CLIENT *clnt)
+{
+ static exports clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_EXPORT, xdr_void, argp, xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
+
+exports *
+mountproc_exportall_1(void *argp, CLIENT *clnt)
+{
+ static exports clnt_res;
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, MOUNTPROC_EXPORTALL, xdr_void, argp, xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) {
+ return (NULL);
+ }
+ return (&clnt_res);
+}
diff --git a/mount/rpcsvc/mount_xdr.c b/mount/rpcsvc/mount_xdr.c
new file mode 100644
index 000000000..be5eb41f1
--- /dev/null
+++ b/mount/rpcsvc/mount_xdr.c
@@ -0,0 +1,150 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "mount.h"
+
+bool_t
+xdr_fhandle(XDR *xdrs, fhandle objp)
+{
+
+ register long *buf;
+
+ if (!xdr_opaque(xdrs, objp, FHSIZE)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_fhstatus(XDR *xdrs, fhstatus *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_u_int(xdrs, &objp->fhs_status)) {
+ return (FALSE);
+ }
+ switch (objp->fhs_status) {
+ case 0:
+ if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) {
+ return (FALSE);
+ }
+ break;
+ default:
+ break;
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_dirpath(XDR *xdrs, dirpath *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_string(xdrs, objp, MNTPATHLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_name(XDR *xdrs, name *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_string(xdrs, objp, MNTNAMLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_mountlist(XDR *xdrs, mountlist *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct mountbody), (xdrproc_t)xdr_mountbody)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_mountbody(XDR *xdrs, mountbody *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_name(xdrs, &objp->ml_hostname)) {
+ return (FALSE);
+ }
+ if (!xdr_dirpath(xdrs, &objp->ml_directory)) {
+ return (FALSE);
+ }
+ if (!xdr_mountlist(xdrs, &objp->ml_next)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_groups(XDR *xdrs, groups *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct groupnode), (xdrproc_t)xdr_groupnode)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_groupnode(XDR *xdrs, groupnode *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_name(xdrs, &objp->gr_name)) {
+ return (FALSE);
+ }
+ if (!xdr_groups(xdrs, &objp->gr_next)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_exports(XDR *xdrs, exports *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct exportnode), (xdrproc_t)xdr_exportnode)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_exportnode(XDR *xdrs, exportnode *objp)
+{
+
+ register long *buf;
+
+ if (!xdr_dirpath(xdrs, &objp->ex_dir)) {
+ return (FALSE);
+ }
+ if (!xdr_groups(xdrs, &objp->ex_groups)) {
+ return (FALSE);
+ }
+ if (!xdr_exports(xdrs, &objp->ex_next)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
diff --git a/mount/sundries.c b/mount/sundries.c
new file mode 100644
index 000000000..45e0e14d8
--- /dev/null
+++ b/mount/sundries.c
@@ -0,0 +1,283 @@
+/*
+ * Support functions. Exported functions are prototyped in sundries.h.
+ * sundries.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ */
+
+#include "sundries.h"
+
+/* File pointer for /etc/mtab. */
+FILE *F_mtab = NULL;
+
+/* File pointer for temp mtab. */
+FILE *F_temp = NULL;
+
+/* File descriptor for lock. Value tested in unlock_mtab() to remove race. */
+static int lock = -1;
+
+/* String list constructor. (car() and cdr() are defined in "sundries.h"). */
+string_list
+cons (char *a, const string_list b)
+{
+ string_list p;
+
+ p = xmalloc (sizeof *p);
+
+ car (p) = a;
+ cdr (p) = b;
+ return p;
+}
+
+void *
+xmalloc (size_t size)
+{
+ void *t;
+
+ if (size == 0)
+ return NULL;
+
+ t = malloc (size);
+ if (t == NULL)
+ die (2, "not enough memory");
+
+ return t;
+}
+
+char *
+xstrdup (const char *s)
+{
+ char *t;
+
+ if (s == NULL)
+ return NULL;
+
+ t = strdup (s);
+
+ if (t == NULL)
+ die (2, "not enough memory");
+
+ return t;
+}
+
+/* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock. */
+void
+block_signals (int how)
+{
+ sigset_t sigs;
+
+ sigfillset (&sigs);
+ sigprocmask (how, &sigs, (sigset_t *) 0);
+}
+
+
+/* Non-fatal error. Print message and return. */
+void
+error (const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+}
+
+/* Fatal error. Print message and exit. */
+void
+die (int err, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+
+ unlock_mtab ();
+ exit (err);
+}
+
+/* Ensure that the lock is released if we are interrupted. */
+static void
+handler (int sig)
+{
+ die (2, "%s", sys_siglist[sig]);
+}
+
+/* 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. */
+void
+lock_mtab (void)
+{
+ int sig = 0;
+ struct sigaction sa;
+
+ /* If this is the first time, ensure that the lock will be removed. */
+ if (lock < 0)
+ {
+ sa.sa_handler = handler;
+ sa.sa_flags = 0;
+ sigfillset (&sa.sa_mask);
+
+ while (sigismember (&sa.sa_mask, ++sig) != -1)
+ sigaction (sig, &sa, (struct sigaction *) 0);
+
+ if ((lock = open (MOUNTED_LOCK, O_WRONLY|O_CREAT|O_EXCL, 0)) < 0)
+ die (2, "can't create lock file %s: %s",
+ MOUNTED_LOCK, strerror (errno));
+ }
+}
+
+/* Remove lock file. */
+void
+unlock_mtab (void)
+{
+ if (lock != -1)
+ {
+ close( lock );
+ unlink (MOUNTED_LOCK);
+ }
+}
+
+/* Open mtab. */
+void
+open_mtab (const char *mode)
+{
+ if ((F_mtab = setmntent (MOUNTED, mode)) == NULL)
+ die (2, "can't open %s: %s", MOUNTED, strerror (errno));
+}
+
+/* Close mtab. */
+void
+close_mtab (void)
+{
+ if (fchmod (fileno (F_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
+ die (1, "mount: error changing mode of %s: %s", MOUNTED, strerror (errno));
+ endmntent (F_mtab);
+}
+
+/* Update the mtab by removing any DIR entries and replace it with INSTEAD. */
+void
+update_mtab (const char *dir, struct mntent *instead)
+{
+ struct mntent *mnt;
+ struct mntent *next;
+ int added = 0;
+
+ open_mtab ("r");
+
+ if ((F_temp = setmntent (MOUNTED_TEMP, "w")) == NULL)
+ die (2, "can't open %s: %s", MOUNTED_TEMP, strerror (errno));
+
+ while ((mnt = getmntent (F_mtab)))
+ {
+ next = streq (mnt->mnt_dir, dir) ? (added++, instead) : mnt;
+ if (next && addmntent(F_temp, next) == 1)
+ die (1, "error writing %s: %s", MOUNTED_TEMP, strerror (errno));
+ }
+ if (instead && !added)
+ addmntent(F_temp, instead);
+
+ endmntent (F_mtab);
+ if (fchmod (fileno (F_temp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
+ die (1, "error changing mode of %s: %s", MOUNTED_TEMP, strerror (errno));
+ endmntent (F_temp);
+
+ if (rename (MOUNTED_TEMP, MOUNTED) < 0)
+ die (1, "can't rename %s to %s: %s",
+ MOUNTED_TEMP, MOUNTED, strerror(errno));
+}
+
+/* Given the name FILE, try to find it in mtab. */
+struct mntent *
+getmntfile (const char *file)
+{
+ struct mntent *mnt;
+
+ if (!F_mtab)
+ return NULL;
+
+ rewind(F_mtab);
+
+ while ((mnt = getmntent (F_mtab)) != NULL)
+ {
+ if (streq (mnt->mnt_dir, file))
+ break;
+ if (streq (mnt->mnt_fsname, file))
+ break;
+ }
+
+ return mnt;
+}
+
+/* Parse a list of strings like str[,str]... into a string list. */
+string_list
+parse_list (char *strings)
+{
+ string_list list;
+ char *t;
+
+ if (strings == NULL)
+ return NULL;
+
+ list = cons (strtok (strings, ","), NULL);
+
+ while ((t = strtok (NULL, ",")) != NULL)
+ list = cons (t, list);
+
+ return list;
+}
+
+/* True if fstypes match. Null *TYPES means match anything,
+ except that swap types always return false. This routine
+ has some ugliness to deal with ``no'' types. */
+int
+matching_type (const char *type, string_list types)
+{
+ char *notype;
+ int no; /* true if a "no" type match, ie -t nominix */
+
+ if (streq (type, MNTTYPE_SWAP))
+ return 0;
+ if (types == NULL)
+ return 1;
+
+ if ((notype = alloca (strlen (type) + 3)) == NULL)
+ die (2, "mount: out of memory");
+ sprintf (notype, "no%s", type);
+ no = (car (types)[0] == 'n') && (car (types)[1] == 'o');
+
+ /* If we get a match and the user specified a positive match type (e.g.
+ "minix") we return true. If we match and a negative match type (e.g.
+ "nominix") was specified we return false. */
+ while (types != NULL)
+ if (streq (type, car (types)))
+ return !no;
+ else if (streq (notype, car (types)))
+ return 0; /* match with "nofoo" always returns false */
+ else
+ types = cdr (types);
+
+ /* No matches, so if the user specified a positive match type return false,
+ if a negative match type was specified, return true. */
+ return no;
+}
+
+/* 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 (const char *path)
+{
+ char *canonical = xmalloc (PATH_MAX + 1);
+
+ if (path == NULL)
+ return NULL;
+
+ if (realpath (path, canonical))
+ return canonical;
+
+ strcpy (canonical, path);
+ return canonical;
+}
diff --git a/mount/sundries.h b/mount/sundries.h
new file mode 100644
index 000000000..ba878c9b4
--- /dev/null
+++ b/mount/sundries.h
@@ -0,0 +1,90 @@
+/*
+ * Support function prototypes. Functions are in sundries.c.
+ * sundries.h,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ */
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <mntent.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "fstab.h"
+
+
+#define streq(s, t) (strcmp ((s), (t)) == 0)
+
+
+#define MOUNTED_LOCK "/etc/mtab~"
+#define MOUNTED_TEMP "/etc/mtab.tmp"
+#define _PATH_FSTAB "/etc/fstab"
+#define LOCK_BUSY 3
+
+/* File pointer for /etc/mtab. */
+extern FILE *F_mtab;
+
+/* File pointer for temp mtab. */
+extern FILE *F_temp;
+
+/* String list data structure. */
+typedef struct string_list
+{
+ char *hd;
+ struct string_list *tl;
+} *string_list;
+
+#define car(p) ((p) -> hd)
+#define cdr(p) ((p) -> tl)
+
+string_list cons (char *a, const string_list);
+
+/* Quiet compilation with -Wmissing-prototypes. */
+int main (int argc, char *argv[]);
+
+/* From mount_call.c. */
+int mount5 (const char *, const char *, const char *, int, void *);
+
+/* Functions in sundries.c that are used in mount.c and umount.c */
+void block_signals (int how);
+char *canonicalize (const char *path);
+char *realpath (const char *path, char *resolved_path);
+void close_mtab (void);
+void error (const char *fmt, ...);
+void lock_mtab (void);
+int matching_type (const char *type, string_list types);
+void open_mtab (const char *mode);
+string_list parse_list (char *strings);
+void unlock_mtab (void);
+void update_mtab (const char *special, struct mntent *with);
+struct mntent *getmntfile (const char *file);
+void *xmalloc (size_t size);
+char *xstrdup (const char *s);
+
+/* Here is some serious cruft. */
+#ifdef __GNUC__
+#if defined(__GNUC_MINOR__) && __GNUC__ == 2 && __GNUC_MINOR__ >= 5
+void die (int errcode, const char *fmt, ...) __attribute__ ((noreturn));
+#else /* GNUC < 2.5 */
+void volatile die (int errcode, const char *fmt, ...);
+#endif /* GNUC < 2.5 */
+#else /* !__GNUC__ */
+void die (int errcode, const char *fmt, ...);
+#endif /* !__GNUC__ */
+
+#ifdef HAVE_NFS
+int nfsmount (const char *spec, const char *node, int *flags,
+ char **orig_opts, char **opt_args);
+#endif
+
+#define mount5(special, dir, type, flags, data) \
+ mount (special, dir, type, 0xC0ED0000 | (flags), data)
+
diff --git a/mount/swapoff.8 b/mount/swapoff.8
new file mode 100644
index 000000000..1a06b7e8d
--- /dev/null
+++ b/mount/swapoff.8
@@ -0,0 +1 @@
+.so man8/swapon.8
diff --git a/mount/swapon.8 b/mount/swapon.8
new file mode 100644
index 000000000..44c841681
--- /dev/null
+++ b/mount/swapon.8
@@ -0,0 +1,94 @@
+.\" Copyright (c) 1980, 1991 Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)swapon.8 6.3 (Berkeley) 3/16/91
+.\"
+.\" Sun Dec 27 12:31:30 1992: Modified by faith@cs.unc.edu
+.\" Sat Mar 6 20:46:02 1993: Modified by faith@cs.unc.edu
+.\" Sat Oct 9 09:35:30 1993: Converted to man format by faith@cs.unc.edu
+.\" Sat Nov 27 20:22:42 1993: Updated authorship information, faith@cs.unc.edu
+.\"
+.TH SWAPON 8 "27 November 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+swapon, swapoff \- enable/disable devices and files for paging and swapping
+.SH SYNOPSIS
+.B /etc/swapon \-a
+.br
+.BI /etc/swapon " specialfile " ...
+.br
+.B /etc/swapoff \-a
+.br
+.BI /etc/swapoff " specialfile " ...
+.SH DESCRIPTION
+.B Swapon
+is used to specify devices on which paging and swapping are to take place.
+Calls to
+.B swapon
+normally occur in the system multi-user initialization file
+.I /etc/rc
+making all swap devices available, so that the paging and swapping activity
+is interleaved across several devices and files.
+
+Normally, the first form is used:
+.TP
+.B \-a
+All devices marked as ``sw'' swap devices in
+.I /etc/fstab
+are made available.
+.PP
+.B Swapoff
+disables swapping on the specified devices and files, or on all swap
+entries in
+.I /etc/fstab
+when the
+.B \-a
+flag is given.
+.SH SEE ALSO
+.BR swapon "(2), " swapoff "(2), " fstab "(5), " init "(8), " mkswap (8),
+.BR rc "(8), " mount (8)
+.SH FILES
+.I /dev/hd[ab]?
+standard paging devices
+.br
+.I /dev/sd[ab]?
+standard (SCSI) paging devices
+.br
+.I /etc/fstab
+ascii filesystem description table
+.SH HISTORY
+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
new file mode 100644
index 000000000..584033021
--- /dev/null
+++ b/mount/swapon.c
@@ -0,0 +1,109 @@
+/*
+ * A swapon(8)/swapoff(8) for Linux 0.99.
+ * swapon.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ */
+
+#include "sundries.h"
+
+/* Nonzero for chatty (-v). This is a nonstandard flag (not in BSD). */
+int verbose = 0;
+
+extern char version[];
+static char *program_name;
+static struct option longopts[] =
+{
+ { "all", 0, 0, 'a' },
+ { "help", 0, 0, 'h' },
+ { "verbose", 0, 0, 'v' },
+ { "version", 0, 0, 'V' },
+ { NULL, 0, 0, 0 }
+};
+
+const char *usage_string = "\
+usage: %s [-hV]\n\
+ %s -a [-v]\n\
+ %s [-v] special ...\n\
+";
+
+static void
+usage (FILE *fp, int n)
+{
+ fprintf (fp, usage_string, program_name, program_name, program_name);
+ exit (n);
+}
+
+static int
+swap (const char *special)
+{
+ int status;
+
+ if (verbose)
+ printf("%s on device %s\n", program_name, special);
+
+ if (streq (program_name, "swapon"))
+ status = swapon (special);
+ else
+ status = swapoff (special);
+
+ if (status < 0)
+ fprintf (stderr, "%s: %s: %s\n", program_name, special, strerror (errno));
+
+ return status;
+}
+
+int
+main (int argc, char *argv[])
+{
+ struct fstab *fstab;
+ int status;
+ int all = 0;
+ int c;
+
+ if (strrchr (argv[0], '/') != NULL)
+ program_name = strrchr (argv[0], '/') + 1;
+ else
+ program_name = argv[0];
+
+ while ((c = getopt_long (argc, argv, "ahvV", longopts, NULL)) != EOF)
+ switch (c)
+ {
+ case 'a': /* all */
+ ++all;
+ break;
+ case 'h': /* help */
+ usage (stdout, 0);
+ break;
+ case 'v': /* be chatty */
+ ++verbose;
+ break;
+ case 'V': /* version */
+ printf ("%s\n", version);
+ exit (0);
+ case 0:
+ break;
+ case '?':
+ default:
+ usage (stderr, 1);
+ }
+
+ argv += optind;
+
+ status = 0;
+
+ if (all)
+ {
+ while ((fstab = getfsent()) != NULL)
+ if (streq (fstab->fs_type, FSTAB_SW))
+ status |= swap (fstab->fs_spec);
+ }
+ else if (*argv == NULL)
+ {
+ usage (stderr, 2);
+ }
+ else
+ {
+ while (*argv != NULL)
+ status |= swap (*argv++);
+ }
+ return status;
+}
diff --git a/mount/umount.8 b/mount/umount.8
new file mode 100644
index 000000000..85425b487
--- /dev/null
+++ b/mount/umount.8
@@ -0,0 +1 @@
+.so man8/mount.8
diff --git a/mount/umount.c b/mount/umount.c
new file mode 100644
index 000000000..c3cfee71a
--- /dev/null
+++ b/mount/umount.c
@@ -0,0 +1,353 @@
+/*
+ * A umount(8) for Linux 0.99.
+ * umount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ *
+ * Wed Sep 14 22:43:54 1994: Sebastian Lederer
+ * (lederer@next-pc.informatik.uni-bonn.de) added support for sending an
+ * unmount RPC call to the server when an NFS-filesystem is unmounted.
+ */
+
+#include "sundries.h"
+
+#ifdef HAVE_NFS
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#include "mount.h"
+#include <arpa/inet.h>
+#endif
+
+
+#ifdef notyet
+/* Nonzero for force umount (-f). This needs kernel support we don't have. */
+int force = 0;
+#endif
+
+/* Nonzero for chatty (-v). This is a nonstandard flag (not in BSD). */
+int verbose = 0;
+
+/* True if ruid != euid. */
+int suid = 0;
+
+#ifdef HAVE_NFS
+static int xdr_dir(XDR *xdrsp, char *dirp)
+{
+ return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
+}
+#endif
+
+
+
+/* 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)
+{
+ int umnt_err;
+ int isroot;
+ struct mntent *mnt;
+
+#ifdef HAVE_NFS
+ char buffer[256];
+ register CLIENT *clp;
+ struct sockaddr_in saddr;
+ struct timeval pertry, try;
+ enum clnt_stat clnt_stat;
+ int so = RPC_ANYSOCK;
+ char *p;
+ struct hostent *hostp;
+ char hostname[MAXHOSTNAMELEN];
+ char dirname[1024];
+#endif /* HAVE_NFS */
+
+
+ /* 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"));
+
+#ifdef HAVE_NFS
+ strcpy(buffer,spec);
+ /* spec is constant so must use own buffer */
+ if((p=strchr(buffer,':')))
+ {
+ *p='\0';
+ strcpy(hostname,buffer);
+ strcpy(dirname,p+1);
+#ifdef DEBUG
+ printf("host: %s, directory: %s\n", hostname,dirname);
+#endif
+
+
+ if (hostname[0] >= '0' && hostname[0] <= '9')
+ {
+ saddr.sin_addr.s_addr = inet_addr(hostname);
+ }
+ else
+ if ((hostp = gethostbyname(hostname)) == NULL)
+ {
+ fprintf(stderr, "mount: can't get address for %s\n", hostname);
+ return(1);
+ }
+ else
+ {
+ memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length);
+ }
+
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = 0;
+ pertry.tv_sec = 3;
+ pertry.tv_usec = 0;
+ if ((clp = clntudp_create(&saddr, MOUNTPROG, MOUNTVERS,
+ pertry, &so)) == NULL)
+ {
+ clnt_pcreateerror("Cannot MOUNTPROG PRC");
+ return (1);
+ }
+ clp->cl_auth = authunix_create_default();
+ try.tv_sec = 20;
+ try.tv_usec = 0;
+ clnt_stat = clnt_call(clp, MOUNTPROC_UMNT,
+ xdr_dir, dirname,
+ xdr_void, (caddr_t)0,
+ try);
+
+ if (clnt_stat != RPC_SUCCESS)
+ {
+ clnt_perror(clp, "Bad UMNT RPC");
+ return (1);
+ }
+ auth_destroy(clp->cl_auth);
+ clnt_destroy(clp);
+ }
+#endif /* HAVE_NFS */
+
+ if (!isroot)
+ lock_mtab ();
+
+ if (umount (node) >= 0)
+ /* Umount succeeded, update mtab. */
+ {
+ if (verbose)
+ printf ("%s umounted\n", spec);
+
+ if (!isroot)
+ {
+ /* Special stuff for loop devices */
+ open_mtab("r");
+ if ((mnt = getmntfile (spec)) ||
+ (mnt = getmntfile (node))) {
+ if (mnt && streq(mnt->mnt_type, "loop")) {
+ extern int del_loop(const char *);
+
+ if (del_loop(spec))
+ goto fail;
+ }
+ }
+ close_mtab();
+
+ /* Non-loop stuff */
+ update_mtab (node, NULL);
+ unlock_mtab ();
+ }
+ return 0;
+ }
+
+fail:
+ /* Umount failed, complain, but don't die. */
+ umnt_err = errno;
+ if (!isroot)
+ unlock_mtab ();
+
+ switch (umnt_err)
+ {
+ case ENXIO:
+ error ("umount: %s: invalid block device", spec); break;
+ case EINVAL:
+ error ("umount: %s: not mounted", spec); break;
+ case EIO:
+ error ("umount: %s: can't write superblock", spec); break;
+ case EBUSY:
+ error ("umount: %s: device is busy", spec); break;
+ case ENOENT:
+ error ("umount: %s: not mounted", spec); break;
+ case EPERM:
+ error ("umount: %s: must be superuser to umount", spec); break;
+ case EACCES:
+ error ("umount: %s: block devices not permitted on fs", spec); break;
+ default:
+ error ("umount: %s: %s", spec, strerror (umnt_err)); break;
+ }
+ return 1;
+}
+
+/* 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
+ in any case it's important to umount mtab entries in reverse order
+ to umount, e.g. /usr/spool before /usr. */
+static int
+umount_all (string_list types)
+{
+ string_list spec_list = NULL;
+ string_list node_list = NULL;
+ struct mntent *mnt;
+ int errors;
+
+ open_mtab ("r");
+
+ while ((mnt = getmntent (F_mtab)))
+ if (matching_type (mnt->mnt_type, types))
+ {
+ spec_list = cons (xstrdup (mnt->mnt_fsname), spec_list);
+ node_list = cons (xstrdup (mnt->mnt_dir), node_list);
+ }
+
+ close_mtab ();
+
+ errors = 0;
+ while (spec_list != NULL)
+ {
+ errors |= umount_one (car (spec_list), car (node_list));
+ spec_list = cdr (spec_list);
+ node_list = cdr (node_list);
+ }
+
+ sync ();
+ return errors;
+}
+
+extern char version[];
+static struct option longopts[] =
+{
+ { "all", 0, 0, 'a' },
+ { "force", 0, 0, 'f' },
+ { "help", 0, 0, 'h' },
+ { "verbose", 0, 0, 'v' },
+ { "version", 0, 0, 'V' },
+ { "types", 1, 0, 't' },
+ { NULL, 0, 0, 0 }
+};
+
+char *usage_string = "\
+usage: umount [-hV]\n\
+ umount -a [-v] [-t vfstypes]\n\
+ umount [-v] special | node\n\
+";
+
+static void
+usage (FILE *fp, int n)
+{
+ fprintf (fp, "%s", usage_string);
+ exit (n);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int c;
+ int all = 0;
+ string_list types = NULL;
+ string_list options;
+ struct mntent *mnt;
+ struct mntent mntbuf;
+ struct mntent *fs;
+ char *file;
+ int result = 0;
+
+ while ((c = getopt_long (argc, argv, "afhvVt:", longopts, NULL)) != EOF)
+ switch (c)
+ {
+ case 'a': /* umount everything */
+ ++all;
+ break;
+ case 'f': /* force umount (needs kernel support) */
+#if 0
+ ++force;
+#else
+ die (2, "umount: forced umount not supported yet");
+#endif
+ break;
+ case 'h': /* help */
+ usage (stdout, 0);
+ break;
+ case 'v': /* make noise */
+ ++verbose;
+ break;
+ case 'V': /* version */
+ printf ("%s\n", version);
+ exit (0);
+ case 't': /* specify file system type */
+ types = parse_list (optarg);
+ break;
+ case 0:
+ break;
+ case '?':
+ default:
+ usage (stderr, 1);
+ }
+
+ if (getuid () != geteuid ())
+ {
+ suid = 1;
+ if (all || types)
+ die (2, "umount: only root can do that");
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (all)
+ result = umount_all (types);
+ else if (argc != 1)
+ usage (stderr, 2);
+ else
+ {
+ file = canonicalize (*argv); /* mtab paths are canonicalized */
+
+ open_mtab ("r");
+ mnt = getmntfile (file);
+ if (mnt)
+ {
+ /* Copy the structure and strings becuase they're in static areas. */
+ mntbuf = *mnt;
+ mnt = &mntbuf;
+ mnt->mnt_fsname = xstrdup (mnt->mnt_fsname);
+ mnt->mnt_dir = xstrdup (mnt->mnt_dir);
+ }
+ close_mtab ();
+
+ if (suid)
+ {
+ if (!mnt)
+ die (2, "umount: %s is not mounted", file);
+ if (!(fs = getfsspec (file)) && !(fs = getfsfile (file)))
+ die (2, "umount: %s is not in the fstab", file);
+ if (!streq (mnt->mnt_fsname, fs->mnt_fsname)
+ || !streq (mnt->mnt_dir, fs->mnt_dir))
+ die (2, "umount: %s mount disagrees with the fstab", file);
+ options = parse_list (fs->mnt_opts);
+ while (options)
+ {
+ if (streq (car (options), "user"))
+ break;
+ options = cdr (options);
+ }
+ if (!options)
+ die (2, "umount: only root can unmount %s from %s",
+ fs->mnt_fsname, fs->mnt_dir);
+ }
+
+ if (mnt)
+ result = umount_one (xstrdup (mnt->mnt_fsname), xstrdup(mnt->mnt_dir));
+ else
+ result = umount_one (*argv, *argv);
+ }
+ exit (result);
+}
diff --git a/mount/version.c b/mount/version.c
new file mode 100644
index 000000000..ece944d29
--- /dev/null
+++ b/mount/version.c
@@ -0,0 +1 @@
+char version[] = "(u)mount: version from util-linux-2.2";