Subject: Re: bin/441: mount can mount something umount can't unmount
To: None <gnats-bugs@gnats.netbsd.org>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: netbsd-bugs
Date: 04/21/1997 12:13:36
My PR 441, from August 1994 (1994?  I'm making myself feel old!), says
that
	/sbin/mount is willing to mount anything on top of a directory
	(or rather, mount_null and probably others are), but
	/sbin/umount refuses to attempt an unmount unless a directory
	(or a block special device) is given.  If the thing mounted
	doesn't stat() as a directory, it's impossible to unmount it.

I've now fixed this (and in the process documented the previous
undocumented -F flag to umount(8)).

Here's my fix, relative to

.\"     $NetBSD: umount.8,v 1.2 1995/03/18 15:01:35 cgd Exp $
/*      $NetBSD: umount.c,v 1.16 1996/05/11 14:13:55 mycroft Exp $      */

Both -current and 1.2 have those same version numbers for these two
files.

--- OLD/sbin/umount/umount.8	Thu Jan  1 00:00:00 1970
+++ NEW/sbin/umount/umount.8	Thu Jan  1 00:00:00 1970
@@ -41,11 +41,11 @@
 .Nd unmount file systems
 .Sh SYNOPSIS
 .Nm umount
-.Op Fl fv
+.Op Fl fvFR
 .Ar special | node
 .Nm umount
 .Fl a
-.Op Fl fv
+.Op Fl fvF
 .Op Fl h Ar host
 .Op Fl t Ar ufs | lfs | external_type
 .Sh DESCRIPTION
@@ -77,6 +77,29 @@
 Active special devices continue to work,
 but all other files return errors if further accesses are attempted.
 The root file system cannot be forcibly unmounted.
+.It Fl F
+Fake the unmount: perform all other processing but do not actually
+attempt the unmount.  (This is most useful in conjunction with
+.Fl v ,
+to see what
+.Nm
+would attempt to do.)
+.It Fl R
+Take the
+.Ar special | node
+argument as a path to be passed directly to
+.Xr unmount 2 ,
+bypassing all attempts to be smart about mechanically determining the
+correct path from the argument.  This option is incompatible with any
+option that potentially umounts more than one filesystem, such as
+.Fl a ,
+but it can be used with
+.Fl f
+and/or
+.Fl v .
+This is the only way to unmount something that does not appear as a
+directory (such as a nullfs mount of a plain file); there are probably
+other cases where it is necessary.
 .It Fl h Ar host
 Only filesystems mounted from the specified host will be
 unmounted.
--- OLD/sbin/umount/umount.c	Thu Jan  1 00:00:00 1970
+++ NEW/sbin/umount/umount.c	Thu Jan  1 00:00:00 1970
@@ -69,7 +69,7 @@
 
 typedef enum { MNTON, MNTFROM } mntwhat;
 
-int	fake, fflag, verbose;
+int	fake, fflag, verbose, raw;
 char	**typelist = NULL;
 char	*nfshost;
 
@@ -93,7 +93,7 @@
 	sync();
 
 	all = 0;
-	while ((ch = getopt(argc, argv, "aFfh:t:v")) != EOF)
+	while ((ch = getopt(argc, argv, "aFfh:Rt:v")) != EOF)
 		switch (ch) {
 		case 'a':
 			all = 1;
@@ -108,6 +108,9 @@
 			all = 1;
 			nfshost = optarg;
 			break;
+		case 'R':
+			raw = 1;
+			break;
 		case 't':
 			if (typelist != NULL)
 				errx(1, "only one -t option may be specified.");
@@ -123,7 +126,7 @@
 	argc -= optind;
 	argv += optind;
 
-	if (argc == 0 && !all || argc != 0 && all)
+	if (argc == 0 && !all || argc != 0 && all || all && raw)
 		usage();
 
 	/* -h implies "-t nfs" if no -t flag. */
@@ -178,55 +181,60 @@
 	int so;
 	char *delimp, *hostp, *mntpt, rname[MAXPATHLEN], type[MFSNAMELEN];
 
-	if (realpath(name, rname) == NULL) {
-		warn("%s", rname);
-		return (1);
-	}
-
-	mntpt = name = rname;
-
-	if (stat(name, &sb) < 0) {
-		if ((name = getmntname(mntpt, MNTFROM, type)) == NULL) {
-			name = rname;
+	hp = 0;
+	if (raw) {
+		mntpt = name;
+	} else {
+		if (realpath(name, rname) == NULL) {
+			warn("%s", rname);
+			return (1);
+		}
+		mntpt = name = rname;
+		if (stat(name, &sb) < 0) {
+			name = getmntname(mntpt, MNTFROM, type);
+			if (name == NULL) {
+				name = rname;
+				mntpt = getmntname(name, MNTON, type);
+				if (mntpt == NULL) {
+					warnx("%s: not currently mounted", name);
+					return (1);
+				}
+			}
+		} else if (S_ISBLK(sb.st_mode)) {
 			if ((mntpt = getmntname(name, MNTON, type)) == NULL) {
 				warnx("%s: not currently mounted", name);
 				return (1);
 			}
-		}
-	} else if (S_ISBLK(sb.st_mode)) {
-		if ((mntpt = getmntname(name, MNTON, type)) == NULL) {
-			warnx("%s: not currently mounted", name);
-			return (1);
-		}
-	} else if (S_ISDIR(sb.st_mode)) {
-		if ((name = getmntname(mntpt, MNTFROM, type)) == NULL) {
-			warnx("%s: not currently mounted", mntpt);
+		} else if (S_ISDIR(sb.st_mode)) {
+			if ((name = getmntname(mntpt, MNTFROM, type)) == NULL) {
+				warnx("%s: not currently mounted", mntpt);
+				return (1);
+			}
+		} else {
+			warnx("%s: not a directory or special device", name);
 			return (1);
 		}
-	} else {
-		warnx("%s: not a directory or special device", name);
-		return (1);
-	}
 
-	if (!selected(type))
-		return (1);
-
-	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
-		if ((delimp = strchr(name, '@')) != NULL) {
-			hostp = delimp + 1;
-			*delimp = '\0';
-			hp = gethostbyname(hostp);
-			*delimp = '@';
-		} else if ((delimp = strchr(name, ':')) != NULL) {
-			*delimp = '\0';
-			hostp = name;
-			hp = gethostbyname(hostp);
-			name = delimp + 1;
-			*delimp = ':';
-		} else
-			hp = NULL;
-		if (!namematch(hp))
+		if (!selected(type))
 			return (1);
+
+		if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
+			if ((delimp = strchr(name, '@')) != NULL) {
+				hostp = delimp + 1;
+				*delimp = '\0';
+				hp = gethostbyname(hostp);
+				*delimp = '@';
+			} else if ((delimp = strchr(name, ':')) != NULL) {
+				*delimp = '\0';
+				hostp = name;
+				hp = gethostbyname(hostp);
+				name = delimp + 1;
+				*delimp = ':';
+			} else
+				hp = NULL;
+			if (!namematch(hp))
+				return (1);
+		}
 	}
 
 	if (verbose)
@@ -398,7 +406,7 @@
 {
 	(void)fprintf(stderr,
 	    "usage: %s\n       %s\n",
-	    "umount [-fv] [-t fstypelist] special | node",
-	    "umount -a[fv] [-h host] [-t fstypelist]");
+	    "umount [-fvFR] [-t fstypelist] special | node",
+	    "umount -a[fvF] [-h host] [-t fstypelist]");
 	exit(1);
 }

					der Mouse

			       mouse@rodents.montreal.qc.ca
		     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B