Subject: bin/6182 umount -R segfaults...
To: None <current-users@netbsd.org>
From: Matthew Orgass <darkstar@pgh.net>
List: current-users
Date: 05/01/1999 02:03:47
  Please apply the following patch to umount and pull it up to 1.4.  It
fixes the -R segfault as well as skipping things that should not be done
with the -a or -A flags (and updates the man page).

  Also, please apply the patches at the bottom of bin/3615 to -current.
While I don't think this is quite an "utterly critical" change, it seems
bad to need a special flag to be able to unmount some things that were
mounted with system utilities (such as mounting under a symlinked 
directory).

Thanks!

Matthew Orgass
darkstar@pgh.net

--- sbin/umount/umount.c.bak	Tue Apr 20 21:49:50 1999
+++ sbin/umount/umount.c	Fri Apr 30 18:21:13 1999
@@ -77,8 +77,9 @@
 int	 main __P((int, char *[]));
 int	 namematch __P((struct hostent *));
 int	 selected __P((int));
+int	 umountone __P((char *, char **));
 int	 umountall __P((char **));
-int	 umountfs __P((char *, char **));
+int	 umountfs __P((char *, char *, char *));
 void	 usage __P((void));
 int	 xdr_dir __P((XDR *, char *));
 
@@ -149,7 +150,9 @@
 		for (errs = 0, mnts--; mnts > 0; mnts--) {
 			if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
 				continue;
-			if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
+			if (umountfs(mntbuf[mnts].f_mntfromname,
+			    mntbuf[mnts].f_mntonname,
+			    mntbuf[mnts].f_fstypename) != 0)
 				errs = 1;
 		}
 		break;
@@ -160,13 +163,71 @@
 		break;
 	case 0:
 		for (errs = 0; *argv != NULL; ++argv)
-			if (umountfs(*argv, typelist) != 0)
+			if (umountone(*argv, typelist) != 0)
 				errs = 1;
 		break;
 	}
 	exit(errs);
 }
 
+int
+umountone(name, typelist)
+	char *name;
+	char **typelist;
+{
+	struct stat sb;
+	char *type, *mntpt, rname[MAXPATHLEN];
+	mntwhat what;
+
+	if (raw)
+		strncpy(rname, name, MAXPATHLEN)[MAXPATHLEN-1] = '\0';
+	else
+		if (realpath(name, rname) == NULL) {
+			warn("%s", rname);
+			return (1);
+		}
+
+	mntpt = name = rname;
+	what = MNTANY;
+
+	if (stat(name, &sb) == 0) {
+		if (S_ISBLK(sb.st_mode))
+			what = MNTON;
+		else if (S_ISDIR(sb.st_mode))
+			what = MNTFROM;
+	}
+
+	switch (what) {
+	case MNTON:
+		if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
+			warnx("%s: not currently mounted", name);
+			return (1);
+		}
+		break;
+	case MNTFROM:
+		if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
+			warnx("%s: not currently mounted", mntpt);
+			return (1);
+		}
+		break;
+	default:
+		if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
+			name = rname;
+			if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
+				warnx("%s: not currently mounted", name);
+				return (1);
+			}
+		}
+	}
+
+	if (checkvfsname(type, typelist))
+		return (1);
+
+	if (umountfs(name, mntpt, type) != 0)
+		return (1);
+
+	return (0);
+}
 
 int
 umountall(typelist)
@@ -189,94 +250,47 @@
 		if (checkvfsname(fs[n].f_fstypename, typelist))
 			continue;
 
-		if (umountfs(fs[n].f_mntonname, typelist))
+		if (umountfs(fs[n].f_mntfromname, fs[n].f_mntonname,
+		    fs[n].f_fstypename))
 			rval = 1;
 	}
 	return (rval);
 }
 
 int
-umountfs(name, typelist)
-	char *name;
-	char **typelist;
+umountfs(name, mntpt, type)
+	char *name;		/* for verbose */
+	char *mntpt;
+	char *type;
 {
 	enum clnt_stat clnt_stat;
 	struct hostent *hp;
 	struct sockaddr_in saddr;
-	struct stat sb;
 	struct timeval pertry, try;
 	CLIENT *clp;
 	int so;
-	char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
-	mntwhat what;
+	char *delimp, *hostp;
 
 	hp = NULL;
 	delimp = NULL;
 
-	if (raw) {
-		mntpt = name;
-	} else {
-
-		if (realpath(name, rname) == NULL) {
-			warn("%s", rname);
-			return (1);
-		}
-
-		what = MNTANY;
-		mntpt = name = rname;
-
-		if (stat(name, &sb) == 0) {
-			if (S_ISBLK(sb.st_mode))
-				what = MNTON;
-			else if (S_ISDIR(sb.st_mode))
-				what = MNTFROM;
+	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 = ':';
 		}
-
-		switch (what) {
-		case MNTON:
-			if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
-				warnx("%s: not currently mounted", name);
-				return (1);
-			}
-			break;
-		case MNTFROM:
-			if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
-				warnx("%s: not currently mounted", mntpt);
-				return (1);
-			}
-			break;
-		default:
-			if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
-				name = rname;
-				if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
-					warnx("%s: not currently mounted", name);
-					return (1);
-				}
-			}
-		}
-
-		if (checkvfsname(type, typelist))
-			return (1);
-
-		hp = NULL;
-		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 = ':';
-			}
-		}
-
-		if (!namematch(hp))
-			return (1);
 	}
+
+	if (!namematch(hp))
+		return (1);
 
 	if (verbose)
 		(void)printf("%s: unmount from %s\n", name, mntpt);
--- sbin/umount/umount.8.bak	Fri Apr 30 18:24:29 1999
+++ sbin/umount/umount.8	Fri Apr 30 18:29:54 1999
@@ -88,22 +88,14 @@
 .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.
+Do not attempt to resolve the path of
+.Ar special 
+or
+.Ar node .
+This option has no effect if used with 
+.Fl a 
+or
+.Fl A .
 .It Fl h Ar host
 Only filesystems mounted from the specified host will be
 unmounted.