summaryrefslogtreecommitdiffstats
path: root/mount
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:48 +0100
committerKarel Zak2006-12-07 00:25:48 +0100
commit364cda4857f7dd5e2b4e2eb7583a2eaa279ef4ed (patch)
treec60dfad813ca42bf619fe2ac8ce893d2331e508f /mount
parentImported from util-linux-2.11b tarball. (diff)
downloadkernel-qcow2-util-linux-364cda4857f7dd5e2b4e2eb7583a2eaa279ef4ed.tar.gz
kernel-qcow2-util-linux-364cda4857f7dd5e2b4e2eb7583a2eaa279ef4ed.tar.xz
kernel-qcow2-util-linux-364cda4857f7dd5e2b4e2eb7583a2eaa279ef4ed.zip
Imported from util-linux-2.11f tarball.
Diffstat (limited to 'mount')
-rw-r--r--mount/Makefile4
-rw-r--r--mount/linux_fs.h17
-rw-r--r--mount/mount.814
-rw-r--r--mount/mount.c124
-rw-r--r--mount/mount_by_label.c3
-rw-r--r--mount/mount_guess_fstype.c46
-rw-r--r--mount/nfs.54
-rw-r--r--mount/nfsmount.c94
-rw-r--r--mount/realpath.c20
-rw-r--r--mount/sundries.c79
-rw-r--r--mount/sundries.h18
-rw-r--r--mount/swapon.c15
-rw-r--r--mount/umount.c345
13 files changed, 433 insertions, 350 deletions
diff --git a/mount/Makefile b/mount/Makefile
index ef65601f7..453b640ae 100644
--- a/mount/Makefile
+++ b/mount/Makefile
@@ -44,11 +44,11 @@ install: $(PROGS)
mount: mount.o fstab.o sundries.o realpath.o mntent.o version.o \
mount_guess_fstype.o mount_by_label.o getusername.o \
- $(LIB)/setproctitle.o $(NFS_OBJS) $(LO_OBJS)
+ $(LIB)/setproctitle.o $(LIB)/env.o $(NFS_OBJS) $(LO_OBJS)
$(LINK) $^ -o $@
umount: umount.o fstab.o sundries.o realpath.o mntent.o getusername.o \
- version.o $(LO_OBJS)
+ version.o $(LIB)/env.o $(LO_OBJS)
$(LINK) $^ -o $@
swapon: swapon.o version.o
diff --git a/mount/linux_fs.h b/mount/linux_fs.h
index 043ac16a7..978573892 100644
--- a/mount/linux_fs.h
+++ b/mount/linux_fs.h
@@ -48,12 +48,18 @@ struct ext_super_block {
#define EXT2_PRE_02B_MAGIC 0xEF51
#define EXT2_SUPER_MAGIC 0xEF53
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
struct ext2_super_block {
- u_char s_dummy1[56];
- u_char s_magic[2];
- u_char s_dummy2[46];
- u_char s_uuid[16];
- u_char s_volume_name[16];
+ u_char s_dummy1[56];
+ u_char s_magic[2];
+ u_char s_dummy2[34];
+ u_char s_feature_compat[4];
+ u_char s_feature_incompat[4];
+ u_char s_feature_ro_compat[4];
+ u_char s_uuid[16];
+ u_char s_volume_name[16];
+ u_char s_dummy3[88];
+ u_char s_journal_inum[4]; /* ext3 only */
};
#define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8))
@@ -102,7 +108,6 @@ struct fat_super_block {
};
#define XFS_SUPER_MAGIC "XFSB"
-#define XFS_SUPER_MAGIC2 "BSFX"
struct xfs_super_block {
u_char s_magic[4];
u_char s_dummy[28];
diff --git a/mount/mount.8 b/mount/mount.8
index 42a7a4a72..6f96457df 100644
--- a/mount/mount.8
+++ b/mount/mount.8
@@ -221,11 +221,7 @@ option below). It is possible to replace
by a symbolic link to
.IR /proc/mounts ,
but some information is lost that way, and in particular
-working with the loop device will be less convenient. Also,
-pathnames containing spaces are handled correctly by
-.I /etc/mtab
-but not (yet) by
-.IR /proc/mounts .
+working with the loop device will be less convenient.
.SH OPTIONS
The full set of options used by an invocation of
@@ -442,7 +438,9 @@ flag followed by a comma separated string of options.
Some 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:
+mounted (but not every file system actually honors them - e.g., the
+.B sync
+option today has effect only for ext2 and ufs):
.RS
.TP
.B async
@@ -582,6 +580,8 @@ Give blocksize. Allowed values are 512, 1024, 2048, 4096.
.TP
.BR grpquota " / " noquota " / " quota " / " usrquota
These options are accepted but ignored.
+(However, quota utilities may react to such strings in
+.IR /etc/fstab .)
.SH "Mount options for coherent"
None.
@@ -1149,7 +1149,7 @@ UFS is a file system widely used in different operating systems.
The problem are differences among implementations. Features of some
implementations are undocumented, so its hard to recognize the
type of ufs automatically.
-That's why user must specify the type of ufs by mount option.
+That's why the user must specify the type of ufs by mount option.
Possible values are:
.RS
.TP
diff --git a/mount/mount.c b/mount/mount.c
index dc7e9823f..8d62087eb 100644
--- a/mount/mount.c
+++ b/mount/mount.c
@@ -66,6 +66,7 @@
#include "mount_guess_fstype.h"
#include "mount_by_label.h"
#include "getusername.h"
+#include "env.h"
#include "nls.h"
#define DO_PS_FIDDLING
@@ -244,7 +245,7 @@ print_one (const struct mntent *me) {
/* Report on everything in mtab (of the specified types if any). */
static int
-print_all (string_list types) {
+print_all (char *types) {
struct mntentchn *mc, *mc0;
mc0 = mtab_head();
@@ -452,33 +453,51 @@ do_mount_syscall (struct mountargs *args) {
* Mount a single file system. Guess the type when unknown.
* returns: 0: OK, -1: error in errno, 1: other error
* don't exit on non-fatal errors.
+ * on return types is filled with the type used.
*/
static int
-guess_fstype_and_mount (char *spec, char *node, char **type,
+guess_fstype_and_mount (char *spec, char *node, char **types,
int flags, char *mount_opts) {
struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts };
- if (*type && strcasecmp (*type, "auto") == 0)
- *type = NULL;
+ if (*types && strcasecmp (*types, "auto") == 0)
+ *types = NULL;
- if (!*type && (flags & (MS_BIND | MS_MOVE)))
- *type = "none"; /* random, but not "bind" */
+ if (!*types && (flags & (MS_BIND | MS_MOVE)))
+ *types = "none"; /* random, but not "bind" */
- if (!*type && !(flags & MS_REMOUNT)) {
- *type = guess_fstype_from_superblock(spec);
- if (*type && !strcmp(*type, "swap")) {
+ if (!*types && !(flags & MS_REMOUNT)) {
+ *types = guess_fstype_from_superblock(spec);
+ if (*types && !strcmp(*types, "swap")) {
error(_("%s looks like swapspace - not mounted"), spec);
- *type = NULL;
+ *types = NULL;
return 1;
}
}
- if (*type || (flags & MS_REMOUNT)) {
- args.type = *type;
+ /* Accept a comma-separated list of types, and try them one by one */
+ /* A list like "nonfs,.." indicates types not to use */
+ if (*types && strncmp(*types, "no", 2) && index(*types,',')) {
+ char *t = strdup(*types);
+ char *p;
+
+ while((p = index(t,',')) != NULL) {
+ *p = 0;
+ args.type = *types = t;
+ if(do_mount_syscall (&args) == 0)
+ return 0;
+ t = p+1;
+ }
+ /* do last type below */
+ *types = t;
+ }
+
+ if (*types || (flags & MS_REMOUNT)) {
+ args.type = *types;
return do_mount_syscall (&args);
}
- return procfsloop(do_mount_syscall, &args, type);
+ return procfsloop(do_mount_syscall, &args, types);
}
/*
@@ -715,7 +734,7 @@ check_special_mountprog(char *spec, char *node, char *type, int flags,
* return status from wait
*/
static int
-try_mount_one (const char *spec0, const char *node0, char *type0,
+try_mount_one (const char *spec0, const char *node0, char *types0,
const char *opts0, int freq, int pass, int bg, int ro) {
int res, status;
int mnt5_res = 0; /* only for gcc */
@@ -724,15 +743,16 @@ try_mount_one (const char *spec0, const char *node0, char *type0,
char *extra_opts; /* written in mtab */
char *mount_opts; /* actually used on system call */
const char *opts;
- char *spec, *node, *type;
+ char *spec, *node, *types;
char *user = 0;
int loop = 0;
char *loopdev = 0, *loopfile = 0;
struct stat statbuf;
+ int nfs_mount_version = 0; /* any version */
spec = xstrdup(spec0);
node = xstrdup(node0);
- type = xstrdup(type0);
+ types = xstrdup(types0);
opts = xstrdup(opts0);
parse_opts (xstrdup (opts), &flags, &extra_opts);
@@ -753,22 +773,27 @@ try_mount_one (const char *spec0, const char *node0, char *type0,
* stale assignments of files to loop devices. Nasty when used for
* encryption.
*/
- res = loop_check (&spec, &type, &flags, &loop, &loopdev, &loopfile);
+ res = loop_check (&spec, &types, &flags, &loop, &loopdev, &loopfile);
if (res)
return res;
}
/*
* Call mount.TYPE for types that require a separate mount program.
- * For the moment these types are ncp and smb.
+ * For the moment these types are ncp and smb. Maybe also vxfs.
+ * All such special things must occur isolated in the types string.
*/
- if (check_special_mountprog (spec, node, type, flags, extra_opts, &status))
+ if (check_special_mountprog (spec, node, types, flags, extra_opts, &status))
return status;
- if (!fake && type && streq (type, "nfs")) {
+ /*
+ * Also nfs requires a separate program, but it is built in.
+ */
+ if (!fake && types && streq (types, "nfs")) {
#ifdef HAVE_NFS
retry_nfs:
- mnt_err = nfsmount (spec, node, &flags, &extra_opts, &mount_opts, bg);
+ mnt_err = nfsmount (spec, node, &flags, &extra_opts, &mount_opts,
+ &nfs_mount_version, bg);
if (mnt_err)
return mnt_err;
#else
@@ -780,7 +805,7 @@ retry_nfs:
block_signals (SIG_BLOCK);
if (!fake)
- mnt5_res = guess_fstype_and_mount (spec, node, &type, flags & ~MS_NOSYS,
+ mnt5_res = guess_fstype_and_mount (spec, node, &types, flags & ~MS_NOSYS,
mount_opts);
if (fake || mnt5_res == 0) {
@@ -790,7 +815,7 @@ retry_nfs:
update_mtab_entry(loop ? loopfile : spec,
node,
- type ? type : "unknown",
+ types ? types : "unknown",
fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user),
flags,
freq,
@@ -808,8 +833,7 @@ retry_nfs:
block_signals (SIG_UNBLOCK);
#ifdef HAVE_NFS
- if (mnt_err && type && streq (type, "nfs")) {
- extern int nfs_mount_version;
+ if (mnt_err && types && streq (types, "nfs")) {
if (nfs_mount_version == 4) {
if (verbose)
printf(_("mount: failed with nfs mount version 4, trying 3..\n"));
@@ -821,7 +845,7 @@ retry_nfs:
/* Mount failed, complain, but don't die. */
- if (type == 0) {
+ if (types == 0) {
if (suid)
error (_("mount: I could not determine the filesystem type, "
"and none was specified"));
@@ -844,7 +868,7 @@ retry_nfs:
case EBUSY:
if (flags & MS_REMOUNT) {
error (_("mount: %s is busy"), node);
- } else if (!strcmp(type, "proc") && !strcmp(node, "/proc")) {
+ } else if (!strcmp(types, "proc") && !strcmp(node, "/proc")) {
/* heuristic: if /proc/version exists, then probably proc is mounted */
if (stat ("/proc/version", &statbuf)) /* proc mounted? */
error (_("mount: %s is busy"), node); /* no */
@@ -926,16 +950,16 @@ retry_nfs:
error (_("mount: %s: can't read superblock"), spec); break;
case ENODEV:
{ int pfs;
- if ((pfs = is_in_procfs(type)) == 1 || !strcmp(type, "guess"))
+ if ((pfs = is_in_procfs(types)) == 1 || !strcmp(types, "guess"))
error(_("mount: %s: unknown device"), spec);
else if (pfs == 0) {
char *lowtype, *p;
int u;
- error (_("mount: fs type %s not supported by kernel"), type);
+ error (_("mount: fs type %s not supported by kernel"), types);
/* maybe this loser asked for FAT or ISO9660 or isofs */
- lowtype = xstrdup(type);
+ lowtype = xstrdup(types);
u = 0;
for(p=lowtype; *p; p++) {
if(tolower(*p) != *p) {
@@ -950,7 +974,7 @@ retry_nfs:
free(lowtype);
} else
error (_("mount: %s has wrong device number or fs type %s not supported"),
- spec, type);
+ spec, types);
break;
}
case ENOTBLK:
@@ -981,7 +1005,7 @@ retry_nfs:
} else {
if (loop) {
opts = opts0;
- type = type0;
+ types = types0;
}
if (opts) {
char *opts1 = realloc(xstrdup(opts), strlen(opts)+4);
@@ -989,11 +1013,11 @@ retry_nfs:
opts = opts1;
} else
opts = "ro";
- if (type && !strcmp(type, "guess"))
- type = 0;
+ if (types && !strcmp(types, "guess"))
+ types = 0;
error (_("mount: %s%s is write-protected, mounting read-only"),
bd, spec0);
- return try_mount_one (spec0, node0, type, opts, freq, pass, bg, 1);
+ return try_mount_one (spec0, node0, types, opts, freq, pass, bg, 1);
}
break;
}
@@ -1051,7 +1075,7 @@ usersubst(const char *opts) {
* Return 0 for success (either mounted sth or -a and NOAUTO was given)
*/
static int
-mount_one (const char *spec, const char *node, char *type, const char *opts,
+mount_one (const char *spec, const char *node, char *types, const char *opts,
char *cmdlineopts, int freq, int pass) {
int status;
int status2;
@@ -1087,9 +1111,9 @@ mount_one (const char *spec, const char *node, char *type, const char *opts,
/* if -a then we may be rescued by a noauto option */
}
- if (type == NULL && !mounttype) {
+ if (types == NULL && !mounttype) {
if (strchr (spec, ':') != NULL) {
- type = "nfs";
+ types = "nfs";
if (verbose)
printf(_("mount: no type was given - "
"I'll assume nfs because of the colon\n"));
@@ -1100,7 +1124,7 @@ mount_one (const char *spec, const char *node, char *type, const char *opts,
* Try to mount the file system. When the exit status is EX_BG,
* we will retry in the background. Otherwise, we're done.
*/
- status = try_mount_one (spec, node, type, opts, freq, pass, 0, 0);
+ status = try_mount_one (spec, node, types, opts, freq, pass, 0, 0);
if (status != EX_BG)
return status;
@@ -1113,10 +1137,10 @@ mount_one (const char *spec, const char *node, char *type, const char *opts,
return 0; /* parent returns "success" */
spec = xstrdup(spec); /* arguments will be destroyed */
node = xstrdup(node); /* by set_proc_name() */
- type = xstrdup(type);
+ types = xstrdup(types);
opts = xstrdup(opts);
set_proc_name (spec); /* make a nice "ps" listing */
- status2 = try_mount_one (spec, node, type, opts, freq, pass, 1, 0);
+ status2 = try_mount_one (spec, node, types, opts, freq, pass, 1, 0);
if (verbose && status2)
printf (_("mount: giving up \"%s\"\n"), spec);
exit (0); /* child stops here */
@@ -1153,7 +1177,7 @@ mounted (char *spec, char *node) {
#define DISKMAJOR(m) (((int) m) & ~0xf)
static int
-mount_all (string_list types, char *options) {
+mount_all (char *types, char *options) {
struct mntentchn *mc, *mc0, *mtmp;
int status = 0;
struct stat statbuf;
@@ -1330,10 +1354,11 @@ main (int argc, char *argv[]) {
char *options = NULL, *spec, *node;
char *volumelabel = NULL;
char *uuid = NULL;
- string_list types = NULL;
+ char *types = NULL;
struct mntentchn *mc;
int fd;
+ sanitize_env();
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@@ -1387,7 +1412,7 @@ main (int argc, char *argv[]) {
sloppy = 1;
break;
case 't': /* specify file system types */
- types = parse_list (optarg);
+ types = optarg;
break;
case 'U':
uuid = optarg;
@@ -1472,7 +1497,7 @@ main (int argc, char *argv[]) {
/* mount -a */
result = mount_all (types, options);
if (result == 0 && verbose)
- error(_("not mounted anything"));
+ error(_("nothing was mounted"));
break;
case 1:
@@ -1524,14 +1549,7 @@ main (int argc, char *argv[]) {
spec = argv[0];
node = argv[1];
}
- if (types == NULL)
- result = mount_one (spec, node, NULL, NULL,
- options, 0, 0);
- else if (cdr (types) == NULL)
- result = mount_one (spec, node, car (types), NULL,
- options, 0, 0);
- else
- usage (stderr, EX_USAGE);
+ result = mount_one (spec, node, types, NULL, options, 0, 0);
break;
default:
diff --git a/mount/mount_by_label.c b/mount/mount_by_label.c
index ad3b5ebd2..18344e4bd 100644
--- a/mount/mount_by_label.c
+++ b/mount/mount_by_label.c
@@ -58,8 +58,7 @@ get_label_uuid(const char *device, char **label, char *uuid) {
}
else if (lseek(fd, 0, SEEK_SET) == 0
&& read(fd, (char *) &xfsb, sizeof(xfsb)) == sizeof(xfsb)
- && (strncmp((char *) &xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0 ||
- strncmp((char *) &xfsb.s_magic, XFS_SUPER_MAGIC2,4) == 0)) {
+ && (strncmp(xfsb.s_magic, XFS_SUPER_MAGIC, 4) == 0)) {
memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid));
namesize = sizeof(xfsb.s_fname);
if ((*label = calloc(namesize + 1, 1)) != NULL)
diff --git a/mount/mount_guess_fstype.c b/mount/mount_guess_fstype.c
index a87409295..8694213d0 100644
--- a/mount/mount_guess_fstype.c
+++ b/mount/mount_guess_fstype.c
@@ -57,6 +57,11 @@ swapped(unsigned short a) {
return (a>>8) | (a<<8);
}
+static inline int
+assemble4le(unsigned char *p) {
+ return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
+}
+
/*
char *guess_fstype_from_superblock(const char *device);
@@ -74,10 +79,11 @@ swapped(unsigned short a) {
Added a very weak heuristic for vfat - aeb
Added xfs - 2000-03-21 Martin K. Petersen <mkp@linuxcare.com>
Added cramfs, hfs, hpfs, adfs - Sepp Wijnands <mrrazz@garbage-coderz.net>
+ Added ext3 - Andrew Morton
*/
static char
*magic_known[] = {
- "adfs", "bfs", "cramfs", "ext", "ext2",
+ "adfs", "bfs", "cramfs", "ext", "ext2", "ext3",
"hfs", "hpfs", "iso9660", "minix", "ntfs",
"qnx4", "romfs", "swap", "udf", "ufs",
"xfs", "xiafs"
@@ -180,9 +186,16 @@ fstype(const char *device) {
PPC ext2 systems */
if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC
|| ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC
- || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC))
+ || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC)) {
type = "ext2";
+ /* maybe even ext3? */
+ if ((assemble4le(sb.e2s.s_feature_compat)
+ & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
+ assemble4le(sb.e2s.s_journal_inum) != 0)
+ type = "ext3,ext2";
+ }
+
else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC
|| minixmagic(sb.ms) == MINIX_SUPER_MAGIC2
|| minixmagic(sb.ms) == swapped(MINIX_SUPER_MAGIC2))
@@ -200,8 +213,7 @@ fstype(const char *device) {
type = "xiafs";
else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8))
type = "romfs";
- else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4) ||
- !strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC2, 4))
+ else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4))
type = "xfs";
else if(!strncmp(xsb.qnx4fs_magic+4, "QNX4FS", 6))
type = "qnx4fs";
@@ -216,7 +228,10 @@ fstype(const char *device) {
!strncmp(xsb.fatsb.s_os, "MSWIN", 5) ||
!strncmp(xsb.fatsb.s_os, "MTOOL", 5) ||
!strncmp(xsb.fatsb.s_os, "mkdosfs", 7) ||
- !strncmp(xsb.fatsb.s_os, "kmkdosfs", 8))
+ !strncmp(xsb.fatsb.s_os, "kmkdosfs", 8) ||
+ /* Michal Svec: created by fdformat, old msdos utility for
+ formatting large (1.7) floppy disks. */
+ !strncmp(xsb.fatsb.s_os, "CH-FOR18", 8))
&& (!strncmp(xsb.fatsb.s_fs, "FAT12 ", 8) ||
!strncmp(xsb.fatsb.s_fs, "FAT16 ", 8) ||
!strncmp(xsb.fatsb.s_fs2, "FAT32 ", 8)))
@@ -363,19 +378,28 @@ is_in_procfs(const char *type) {
return ret;
}
+/* Try all types in FILESYSTEMS, except those in *types,
+ in case *types starts with "no" */
/* return: 0: OK, -1: error in errno, 1: type not found */
-/* when 1 is returned, *type is NULL */
+/* when 0 or -1 is returned, *types contains the type used */
+/* when 1 is returned, *types is NULL */
int
procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args,
- char **type) {
+ char **types) {
char *files[2] = { ETC_FILESYSTEMS, PROC_FILESYSTEMS };
FILE *procfs;
char *fsname;
+ char *notypes = NULL;
+ int no = 0;
int ret = 1;
int errsv = 0;
int i;
- *type = NULL;
+ if (!strncmp(*types, "no", 2)) {
+ no = 1;
+ notypes = (*types) + 2;
+ }
+ *types = NULL;
/* Use PROC_FILESYSTEMS only when ETC_FILESYSTEMS does not exist.
In some cases trying a filesystem that the kernel knows about
@@ -396,18 +420,20 @@ procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args,
}
if (tested (fsname))
continue;
+ if (no && matching_type(fsname, notypes))
+ continue;
args->type = fsname;
if (verbose) {
printf(_("Trying %s\n"), fsname);
fflush(stdout);
}
if ((*mount_fn) (args) == 0) {
- *type = fsname;
+ *types = fsname;
ret = 0;
break;
} else if (errno != EINVAL &&
is_in_procfs(fsname) == 1) {
- *type = "guess";
+ *types = "guess";
ret = -1;
errsv = errno;
break;
diff --git a/mount/nfs.5 b/mount/nfs.5
index 6ffce6cdf..b29a8bdb0 100644
--- a/mount/nfs.5
+++ b/mount/nfs.5
@@ -143,6 +143,10 @@ 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 nolock
+Disable NFS locking. This has to be used with some old NFS servers
+that don't support locking.
+.TP 1.5i
.I bg
If the first NFS mount attempt times out, retry the mount
in the background.
diff --git a/mount/nfsmount.c b/mount/nfsmount.c
index 70298e0c6..d81c062e1 100644
--- a/mount/nfsmount.c
+++ b/mount/nfsmount.c
@@ -37,6 +37,7 @@
#include <string.h>
#include <errno.h>
#include <netdb.h>
+#include <time.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
@@ -86,11 +87,6 @@ linux_version_code(void) {
}
/*
- * nfs_mount_version according to the sources seen at compile time.
- */
-int nfs_mount_version = NFS_MOUNT_VERSION;
-
-/*
* Unfortunately, the kernel prints annoying console messages
* in case of an unexpected nfs mount version (instead of
* just returning some error). Therefore we'll have to try
@@ -100,14 +96,13 @@ int nfs_mount_version = NFS_MOUNT_VERSION;
* NFS_MOUNT_VERSION: these nfsmount sources at compile time
* nfs_mount_version: version this source and running kernel can handle
*/
-static void
+static int
find_kernel_nfs_mount_version(void) {
- static int kernel_version = 0;
+ static int kernel_version = -1;
+ int nfs_mount_version = NFS_MOUNT_VERSION;
- if (kernel_version)
- return;
-
- kernel_version = linux_version_code();
+ if (kernel_version == -1)
+ kernel_version = linux_version_code();
if (kernel_version) {
if (kernel_version < MAKE_VERSION(2,1,32))
@@ -123,6 +118,7 @@ find_kernel_nfs_mount_version(void) {
}
if (nfs_mount_version > NFS_MOUNT_VERSION)
nfs_mount_version = NFS_MOUNT_VERSION;
+ return nfs_mount_version;
}
static struct pmap *
@@ -130,7 +126,8 @@ get_mountport(struct sockaddr_in *server_addr,
long unsigned prog,
long unsigned version,
long unsigned proto,
- long unsigned port)
+ long unsigned port,
+ int nfs_mount_version)
{
struct pmaplist *pmap;
static struct pmap p = {0, 0, 0, 0};
@@ -174,20 +171,19 @@ get_mountport(struct sockaddr_in *server_addr,
}
int nfsmount(const char *spec, const char *node, int *flags,
- char **extra_opts, char **mount_opts, int running_bg)
+ char **extra_opts, char **mount_opts, int *nfs_mount_vers,
+ int running_bg)
{
static char *prev_bg_host;
char hostdir[1024];
CLIENT *mclient;
- char *hostname;
- char *dirname;
- char *old_opts;
- char *mounthost=NULL;
+ char *hostname, *dirname, *old_opts, *mounthost = NULL;
char new_opts[1024];
struct timeval total_timeout;
enum clnt_stat clnt_stat;
static struct nfs_mount_data data;
char *opt, *opteq;
+ int nfs_mount_version;
int val;
struct hostent *hp;
struct sockaddr_in server_addr;
@@ -201,29 +197,20 @@ int nfsmount(const char *spec, const char *node, int *flags,
} status;
struct stat statbuf;
char *s;
- int port;
- int mountport;
- int proto;
- int bg;
- int soft;
- int intr;
- int posix;
- int nocto;
- int noac;
- int nolock;
- int broken_suid;
- int retry;
- int tcp;
- int mountprog;
- int mountvers;
- int nfsprog;
- int nfsvers;
+ int port, mountport, proto, bg, soft, intr;
+ int posix, nocto, noac, nolock, broken_suid;
+ int retry, tcp;
+ int mountprog, mountvers, nfsprog, nfsvers;
int retval;
time_t t;
time_t prevt;
time_t timeout;
- find_kernel_nfs_mount_version();
+ /* The version to try is either specified or 0
+ In case it is 0 we tell the caller what we tried */
+ if (!*nfs_mount_vers)
+ *nfs_mount_vers = find_kernel_nfs_mount_version();
+ nfs_mount_version = *nfs_mount_vers;
retval = EX_FAIL;
msock = fsock = -1;
@@ -242,12 +229,14 @@ int nfsmount(const char *spec, const char *node, int *flags,
until they can be fully supported. (mack@sgi.com) */
if ((s = strchr(hostdir, ','))) {
*s = '\0';
- fprintf(stderr, _("mount: warning: "
- "multiple hostnames not supported\n"));
+ fprintf(stderr,
+ _("mount: warning: "
+ "multiple hostnames not supported\n"));
}
} else {
- fprintf(stderr, _("mount: "
- "directory to mount not in host:dir format\n"));
+ fprintf(stderr,
+ _("mount: "
+ "directory to mount not in host:dir format\n"));
goto fail;
}
@@ -380,15 +369,14 @@ int nfsmount(const char *spec, const char *node, int *flags,
else
#endif
printf(_("Warning: Option namlen is not supported.\n"));
- } else if (!strcmp(opt, "addr"))
+ } else if (!strcmp(opt, "addr")) {
/* ignore */;
- else {
+ } else {
printf(_("unknown nfs mount parameter: "
"%s=%d\n"), opt, val);
goto fail;
}
- }
- else {
+ } else {
val = 1;
if (!strncmp(opt, "no", 2)) {
val = 0;
@@ -459,9 +447,8 @@ int nfsmount(const char *spec, const char *node, int *flags,
}
if (nfsvers && !mountvers)
mountvers = (nfsvers < 3) ? 1 : nfsvers;
- if (nfsvers && nfsvers < mountvers) {
+ if (nfsvers && nfsvers < mountvers)
mountvers = nfsvers;
- }
/* Adjust options if none specified */
if (!data.timeo)
@@ -515,7 +502,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
} else {
if ((hp = gethostbyname(mounthost)) == NULL) {
fprintf(stderr, _("mount: can't get address for %s\n"),
- hostname);
+ mounthost);
goto fail;
} else {
if (hp->h_length > sizeof(struct in_addr)) {
@@ -573,7 +560,8 @@ int nfsmount(const char *spec, const char *node, int *flags,
mountprog,
mountvers,
proto,
- mountport);
+ mountport,
+ nfs_mount_version);
/* contact the mount daemon via TCP */
mount_server_addr.sin_port = htons(pm_mnt->pm_port);
@@ -724,6 +712,18 @@ int nfsmount(const char *spec, const char *node, int *flags,
server_addr.sin_port = PMAPPORT;
port = pmap_getport(&server_addr, nfsprog, nfsvers,
tcp ? IPPROTO_TCP : IPPROTO_UDP);
+#if 1
+ /* Here we check to see if user is mounting with the
+ * tcp option. If so, and if the portmap returns a
+ * '0' for port (service unavailable), we then exit,
+ * notifying the user, rather than hanging up mount.
+ */
+ if (port == 0 && tcp == 1) {
+ perror(_("nfs server reported service unavailable"));
+ goto fail;
+ }
+#endif
+
if (port == 0)
port = NFS_PORT;
#ifdef NFS_MOUNT_DEBUG
diff --git a/mount/realpath.c b/mount/realpath.c
index 374f8a3a2..61832efd2 100644
--- a/mount/realpath.c
+++ b/mount/realpath.c
@@ -13,12 +13,17 @@
* GNU Library Public License for more details.
*/
+#undef resolve_symlinks
+
/*
* This routine is part of libc. We include it nevertheless,
* since the libc version has some security flaws.
*/
#include <limits.h> /* for PATH_MAX */
+#ifndef PATH_MAX
+#define PATH_MAX 8192
+#endif
#include <unistd.h>
#include <string.h>
#include <errno.h>
@@ -30,10 +35,14 @@
/* this leaks some memory - unimportant for mount */
char *
myrealpath(const char *path, char *resolved_path, int maxreslth) {
- char *npath, *buf;
- char link_path[PATH_MAX+1];
int readlinks = 0;
- int m, n;
+ char *npath;
+ char link_path[PATH_MAX+1];
+ int n;
+#ifdef resolve_symlinks
+ char *buf;
+ int m;
+#endif
npath = resolved_path;
@@ -85,7 +94,7 @@ myrealpath(const char *path, char *resolved_path, int maxreslth) {
return NULL;
}
- /* See if latest pathname component is a symlink. */
+ /* See if last pathname component is a symlink. */
*npath = '\0';
n = readlink(resolved_path, link_path, PATH_MAX);
if (n < 0) {
@@ -93,6 +102,7 @@ myrealpath(const char *path, char *resolved_path, int maxreslth) {
if (errno != EINVAL)
return NULL;
} else {
+#ifdef resolve_symlinks /* Richard Gooch dislikes sl resolution */
/* Note: readlink doesn't add the null byte. */
link_path[n] = '\0';
if (*link_path == '/')
@@ -109,8 +119,8 @@ myrealpath(const char *path, char *resolved_path, int maxreslth) {
memcpy(buf, link_path, n);
memcpy(buf + n, path, m + 1);
path = buf;
+#endif
}
-
*npath++ = '/';
}
/* Delete trailing slash but don't whomp a lone slash. */
diff --git a/mount/sundries.c b/mount/sundries.c
index 1da3b666e..59b069678 100644
--- a/mount/sundries.c
+++ b/mount/sundries.c
@@ -18,17 +18,6 @@
#include "nfsmount.h"
#include "nls.h"
-/* 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;
@@ -157,57 +146,43 @@ die (int err, const char *fmt, ...) {
exit (err);
}
-/* Parse a list of strings like str[,str]... into a string list. */
-string_list
-parse_list (char *strings) {
- string_list list;
- char *s, *t;
-
- if (strings == NULL)
- return NULL;
-
- /* strtok() destroys its argument, so we have to use a copy */
- s = xstrdup(strings);
-
- list = cons (strtok (s, ","), 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.
- Fixed bug: the `no' part comes at the end - aeb, 970216 */
+ except that swap types always return false. */
+/* Accept nonfs,proc,devpts and nonfs,noproc,nodevpts
+ with the same meaning. */
int
-matching_type (const char *type, string_list types) {
- char *notype;
- int foundyes, foundno;
- int no; /* true if a "no" type match, eg -t nominix */
+matching_type (const char *type, const char *types) {
+ int no; /* negated types list */
+ int len;
+ const char *p;
if (streq (type, MNTTYPE_SWAP))
return 0;
if (types == NULL)
return 1;
- if ((notype = alloca (strlen (type) + 3)) == NULL)
- die (EX_SYSERR, _("%s: Out of memory!\n"), "mount");
- sprintf (notype, "no%s", type);
-
- foundyes = foundno = no = 0;
- while (types != NULL) {
- if (cdr (types) == NULL)
- no = (car (types)[0] == 'n') && (car (types)[1] == 'o');
- if (streq (type, car (types)))
- foundyes = 1;
- else if (streq (notype, car (types)))
- foundno = 1;
- types = cdr (types);
+ no = 0;
+ if (!strncmp(types, "no", 2)) {
+ no = 1;
+ types += 2;
}
- return (foundno ? 0 : (no ^ foundyes));
+ /* Does type occur in types, separated by commas? */
+ len = strlen(type);
+ p = types;
+ while(1) {
+ if (!strncmp(p, "no", 2) && !strncmp(p+2, type, len) &&
+ (p[len+2] == 0 || p[len+2] == ','))
+ return 0;
+ if (strncmp(p, type, len) == 0 &&
+ (p[len] == 0 || p[len] == ','))
+ return !no;
+ p = index(p,',');
+ if (!p)
+ break;
+ p++;
+ }
+ return no;
}
/* Make a canonical pathname from PATH. Returns a freshly malloced string.
diff --git a/mount/sundries.h b/mount/sundries.h
index 742d761f4..5b91ca1ee 100644
--- a/mount/sundries.h
+++ b/mount/sundries.h
@@ -19,26 +19,12 @@ extern int sloppy;
#define streq(s, t) (strcmp ((s), (t)) == 0)
-
-/* 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);
-
/* 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 error (const char *fmt, ...);
-int matching_type (const char *type, string_list types);
-string_list parse_list (char *strings);
+int matching_type (const char *type, const char *types);
void *xmalloc (size_t size);
char *xstrdup (const char *s);
char *xstrndup (const char *s, int n);
@@ -50,7 +36,7 @@ void die (int errcode, const char *fmt, ...);
#ifdef HAVE_NFS
int nfsmount (const char *spec, const char *node, int *flags,
- char **orig_opts, char **opt_args, int running_bg);
+ char **orig_opts, char **opt_args, int *version, int running_bg);
#endif
/* exit status - bits below are ORed */
diff --git a/mount/swapon.c b/mount/swapon.c
index 829acadd4..b87a021ae 100644
--- a/mount/swapon.c
+++ b/mount/swapon.c
@@ -90,15 +90,22 @@ swap (const char *special, int prio)
if (streq (program_name, "swapon")) {
if (stat(special, &st) < 0) {
int errsv = errno;
- fprintf (stderr, _("swapon: cannot stat %s: %s\n"), special, strerror (errsv));
+ fprintf (stderr, _("swapon: cannot stat %s: %s\n"),
+ special, strerror (errsv));
return -1;
}
/* people generally dislike this warning - now it is printed
only when `verbose' is set */
- if (verbose && (st.st_mode & 07077) != 0) {
- fprintf(stderr, _("swapon: warning: %s has insecure permissions %04o, "
- "0600 suggested\n"), special, st.st_mode & 07777);
+ if (verbose) {
+ int permMask = (S_ISBLK(st.st_mode) ? 07007 : 07077);
+
+ if ((st.st_mode & permMask) != 0) {
+ fprintf(stderr,
+ _("swapon: warning: %s has insecure permissions %04o, "
+ "%04o suggested\n"),
+ special, st.st_mode & 07777, ~permMask & 0666);
+ }
}
/* test for holes by LBT */
diff --git a/mount/umount.c b/mount/umount.c
index 1843e08e5..92400875a 100644
--- a/mount/umount.c
+++ b/mount/umount.c
@@ -39,6 +39,7 @@
#include "lomount.h"
#include "loop.h"
#include "fstab.h"
+#include "env.h"
#include "nls.h"
#ifdef HAVE_NFS
@@ -52,7 +53,7 @@
#include <arpa/inet.h>
#endif
-#if defined(MNT_FORCE) && !defined(__sparc__) && !defined(__arm__) && !defined(__mips__)
+#if defined(MNT_FORCE) && !defined(__sparc__) && !defined(__arm__)
/* Interesting ... it seems libc knows about MNT_FORCE and presumably
about umount2 as well -- need not do anything */
#else /* MNT_FORCE */
@@ -100,6 +101,16 @@ int verbose = 0;
/* True if ruid != euid. */
int suid = 0;
+#ifdef USE_SPECIAL_UMOUNTPROG
+/* unimplemented so far */
+static int
+check_special_umountprog() {
+ /* find type from command line or /etc/mtab;
+ stat /sbin/umount.%s
+ if it exists, use it */
+}
+#endif
+
#ifdef HAVE_NFS
static int xdr_dir(XDR *xdrsp, char *dirp)
{
@@ -236,7 +247,6 @@ umount_one (const char *spec, const char *node, const char *type,
nfs_umount_rpc_call(spec, opts);
#endif
-
umnt_err = umnt_err2 = 0;
if (force) {
/* completely untested;
@@ -383,7 +393,7 @@ umount_one_bw (const char *file, struct mntentchn *mc) {
in any case it's important to umount mtab entries in reverse order
to mount, e.g. /usr/spool before /usr. */
static int
-umount_all (string_list types) {
+umount_all (char *types) {
struct mntentchn *mc, *hd;
int errors = 0;
@@ -426,152 +436,195 @@ usage (FILE *fp, int n)
int mount_quiet = 0;
-int
-main (int argc, char *argv[])
-{
- int c;
- int all = 0;
- string_list types = NULL;
- string_list options;
- struct mntentchn *mc, *fs;
- char *file;
- int result = 0;
-
- setlocale(LC_ALL, "");
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
-
- while ((c = getopt_long (argc, argv, "afhnrt:vV",
- longopts, NULL)) != EOF)
- switch (c) {
- case 'a': /* umount everything */
- ++all;
- break;
- /* fall through? */
- case 'd': /* do losetup -d for unmounted loop devices */
- ++delloop;
- break;
- case 'f': /* force umount */
- ++force;
- break;
- case 'h': /* help */
- usage (stdout, 0);
- break;
- case 'n': /* do not write in /etc/mtab */
- ++nomtab;
- break;
- case 'r': /* remount read-only if umount fails */
- ++remount;
- break;
- case 'v': /* make noise */
- ++verbose;
- break;
- case 'V': /* version */
- printf ("umount: %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 || nomtab || force)
- die (2, _("umount: only root can do that"));
- }
-
- argc -= optind;
- argv += optind;
-
- if (all) {
- if (types == NULL)
- types = parse_list("noproc");
- result = umount_all (types);
- } else if (argc < 1) {
- usage (stderr, 2);
- } else while (argc--) {
- file = canonicalize (*argv); /* mtab paths are canonicalized */
- if (verbose > 1)
- printf(_("Trying to umount %s\n"), file);
-
- mc = getmntfilesbackward (file, NULL);
- if (!mc && verbose)
- printf(_("Could not find %s in mtab\n"), file);
-
- if (suid) {
- if (!mc)
- die (2, _("umount: %s is not mounted (according to mtab)"), file);
- if (getmntfilesbackward (file, mc))
- die (2, _("umount: it seems %s is mounted multiple times"), file);
-
- /* If fstab contains the two lines
- /dev/sda1 /mnt/zip auto user,noauto 0 0
- /dev/sda4 /mnt/zip auto user,noauto 0 0
- then "mount /dev/sda4" followed by "umount /mnt/zip"
- used to fail. So, we must not look for file, but for
- the pair (spec,file) in fstab. */
- fs = getfsspecfile(mc->m.mnt_fsname, mc->m.mnt_dir);
- if (!fs) {
- if (!getfsspec (file) && !getfsfile (file))
- die (2,
- _("umount: %s is not in the fstab (and you are not root)"),
- file);
- else
- die (2, _("umount: %s mount disagrees with the fstab"), file);
- }
+/*=======================================================================*/
+/* string list stuff - no longer used by mount - will disappear entirely */
+typedef struct string_list {
+ char *hd;
+ struct string_list *tl;
+} *string_list;
- /* User mounting and unmounting is allowed only
- if fstab contains the option `user' or `users' */
- /* The option `users' allows arbitrary users to mount
- and unmount - this may be a security risk. */
- /* The option `user' only allows unmounting by the user
- that mounted. */
- /* The option `owner' only allows (un)mounting by the owner. */
- /* A convenient side effect is that the user who mounted
- is visible in mtab. */
- options = parse_list (fs->m.mnt_opts);
- while (options) {
- if (streq (car (options), "user") ||
- streq (car (options), "users") ||
- streq (car (options), "owner"))
- break;
- options = cdr (options);
- }
- if (!options)
- die (2, _("umount: only root can unmount %s from %s"),
- fs->m.mnt_fsname, fs->m.mnt_dir);
- if (streq (car (options), "user") ||
- streq (car (options), "owner")) {
- char *user = getusername();
-
- options = parse_list (mc->m.mnt_opts);
- while (options) {
- char *co = car (options);
- if (!strncmp(co, "user=", 5)) {
- if (!user || !streq(co+5,user))
- die(2, _("umount: only %s can unmount %s from %s"),
- co+5, fs->m.mnt_fsname, fs->m.mnt_dir);
- break;
- }
- options = cdr (options);
- }
- }
- }
+#define car(p) ((p) -> hd)
+#define cdr(p) ((p) -> tl)
- if (mc)
- result = umount_one_bw (file, mc);
- else
- result = umount_one (*argv, *argv, *argv, *argv, NULL);
+static string_list
+cons (char *a, const string_list b) {
+ string_list p;
- argv++;
+ p = xmalloc (sizeof *p);
+ car (p) = a;
+ cdr (p) = b;
+ return p;
+}
+
+/* Parse a list of strings like str[,str]... into a string list. */
+static string_list
+parse_list (char *strings) {
+ string_list list;
+ char *s, *t;
+
+ if (strings == NULL)
+ return NULL;
+
+ /* strtok() destroys its argument, so we have to use a copy */
+ s = xstrdup(strings);
+
+ list = cons (strtok (s, ","), NULL);
+
+ while ((t = strtok (NULL, ",")) != NULL)
+ list = cons (t, list);
+
+ return list;
+}
+/*=======================================================================*/
+
+static int
+umount_file (char *arg) {
+ struct mntentchn *mc, *fs;
+ char *file;
+ string_list options;
+
+ file = canonicalize (arg); /* mtab paths are canonicalized */
+ if (verbose > 1)
+ printf(_("Trying to umount %s\n"), file);
+
+ mc = getmntfilesbackward (file, NULL);
+ if (!mc && verbose)
+ printf(_("Could not find %s in mtab\n"), file);
+
+ if (suid) {
+ if (!mc)
+ die (2, _("umount: %s is not mounted (according to mtab)"), file);
+ if (getmntfilesbackward (file, mc))
+ die (2, _("umount: it seems %s is mounted multiple times"), file);
+
+ /* If fstab contains the two lines
+ /dev/sda1 /mnt/zip auto user,noauto 0 0
+ /dev/sda4 /mnt/zip auto user,noauto 0 0
+ then "mount /dev/sda4" followed by "umount /mnt/zip"
+ used to fail. So, we must not look for file, but for
+ the pair (spec,file) in fstab. */
+ fs = getfsspecfile(mc->m.mnt_fsname, mc->m.mnt_dir);
+ if (!fs) {
+ if (!getfsspec (file) && !getfsfile (file))
+ die (2,
+ _("umount: %s is not in the fstab (and you are not root)"),
+ file);
+ else
+ die (2, _("umount: %s mount disagrees with the fstab"), file);
+ }
+
+ /* User mounting and unmounting is allowed only
+ if fstab contains the option `user' or `users' */
+ /* The option `users' allows arbitrary users to mount
+ and unmount - this may be a security risk. */
+ /* The option `user' only allows unmounting by the user
+ that mounted. */
+ /* The option `owner' only allows (un)mounting by the owner. */
+ /* A convenient side effect is that the user who mounted
+ is visible in mtab. */
+ options = parse_list (fs->m.mnt_opts);
+ while (options) {
+ if (streq (car (options), "user") ||
+ streq (car (options), "users") ||
+ streq (car (options), "owner"))
+ break;
+ options = cdr (options);
+ }
+ if (!options)
+ die (2, _("umount: only root can unmount %s from %s"),
+ fs->m.mnt_fsname, fs->m.mnt_dir);
+ if (streq (car (options), "user") ||
+ streq (car (options), "owner")) {
+ char *user = getusername();
+
+ options = parse_list (mc->m.mnt_opts);
+ while (options) {
+ char *co = car (options);
+ if (!strncmp(co, "user=", 5)) {
+ if (!user || !streq(co+5,user))
+ die(2, _("umount: only %s can unmount %s from %s"),
+ co+5, fs->m.mnt_fsname, fs->m.mnt_dir);
+ break;
+ }
+ options = cdr (options);
+ }
+ }
+ }
+
+ if (mc)
+ return umount_one_bw (file, mc);
+ else
+ return umount_one (arg, arg, arg, arg, NULL);
- }
- exit (result);
}
+int
+main (int argc, char *argv[]) {
+ int c;
+ int all = 0;
+ char *types = NULL;
+ int result = 0;
+
+ sanitize_env();
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ while ((c = getopt_long (argc, argv, "adfhnrt:vV",
+ longopts, NULL)) != EOF)
+ switch (c) {
+ case 'a': /* umount everything */
+ ++all;
+ break;
+ /* fall through? */
+ case 'd': /* do losetup -d for unmounted loop devices */
+ ++delloop;
+ break;
+ case 'f': /* force umount */
+ ++force;
+ break;
+ case 'h': /* help */
+ usage (stdout, 0);
+ break;
+ case 'n': /* do not write in /etc/mtab */
+ ++nomtab;
+ break;
+ case 'r': /* remount read-only if umount fails */
+ ++remount;
+ break;
+ case 'v': /* make noise */
+ ++verbose;
+ break;
+ case 'V': /* version */
+ printf ("umount: %s\n", version);
+ exit (0);
+ case 't': /* specify file system type */
+ types = optarg;
+ break;
+ case 0:
+ break;
+ case '?':
+ default:
+ usage (stderr, 1);
+ }
+
+ if (getuid () != geteuid ()) {
+ suid = 1;
+ if (all || types || nomtab || force)
+ die (2, _("umount: only root can do that"));
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (all) {
+ if (types == NULL)
+ types = "noproc";
+ result = umount_all (types);
+ } else if (argc < 1) {
+ usage (stderr, 2);
+ } else while (argc--) {
+ result += umount_file(*argv++);
+ }
+ exit (result); /* nonzero on at least one failure */
+}