xref: /freebsd/sbin/umount/umount.c (revision eddb48052afddb6c3670125eb6df5b4cfbe9cea4)
18fae3551SRodney W. Grimes /*-
28fae3551SRodney W. Grimes  * Copyright (c) 1980, 1989, 1993
38fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
48fae3551SRodney W. Grimes  *
58fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
68fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
78fae3551SRodney W. Grimes  * are met:
88fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
98fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
108fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
118fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
128fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
138fae3551SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
148fae3551SRodney W. Grimes  *    must display the following acknowledgement:
158fae3551SRodney W. Grimes  *	This product includes software developed by the University of
168fae3551SRodney W. Grimes  *	California, Berkeley and its contributors.
178fae3551SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
188fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
198fae3551SRodney W. Grimes  *    without specific prior written permission.
208fae3551SRodney W. Grimes  *
218fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
228fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
238fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
248fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
258fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
268fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
278fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
288fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
298fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
308fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
318fae3551SRodney W. Grimes  * SUCH DAMAGE.
328fae3551SRodney W. Grimes  */
338fae3551SRodney W. Grimes 
348fae3551SRodney W. Grimes #ifndef lint
35adb378ceSPhilippe Charnier static const char copyright[] =
368fae3551SRodney W. Grimes "@(#) Copyright (c) 1980, 1989, 1993\n\
378fae3551SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
388fae3551SRodney W. Grimes #endif /* not lint */
398fae3551SRodney W. Grimes 
408fae3551SRodney W. Grimes #ifndef lint
41adb378ceSPhilippe Charnier #if 0
42d499a0efSBruce Evans static char sccsid[] = "@(#)umount.c	8.8 (Berkeley) 5/8/95";
43adb378ceSPhilippe Charnier #endif
44adb378ceSPhilippe Charnier static const char rcsid[] =
457f3dea24SPeter Wemm   "$FreeBSD$";
468fae3551SRodney W. Grimes #endif /* not lint */
478fae3551SRodney W. Grimes 
488fae3551SRodney W. Grimes #include <sys/param.h>
498fae3551SRodney W. Grimes #include <sys/mount.h>
508360efbdSAlfred Perlstein #include <sys/socket.h>
51eddb4805SIan Dowse #include <sys/stat.h>
528fae3551SRodney W. Grimes 
538fae3551SRodney W. Grimes #include <netdb.h>
548fae3551SRodney W. Grimes #include <rpc/rpc.h>
558fae3551SRodney W. Grimes #include <nfs/rpcv2.h>
568fae3551SRodney W. Grimes 
5738f102c2SIan Dowse #include <ctype.h>
588fae3551SRodney W. Grimes #include <err.h>
59318f2fb4SIan Dowse #include <errno.h>
608fae3551SRodney W. Grimes #include <fstab.h>
618fae3551SRodney W. Grimes #include <stdio.h>
628fae3551SRodney W. Grimes #include <stdlib.h>
638fae3551SRodney W. Grimes #include <string.h>
648fae3551SRodney W. Grimes #include <unistd.h>
658fae3551SRodney W. Grimes 
66a69497d7SMatthew Dillon #include "mounttab.h"
67a69497d7SMatthew Dillon 
68eddb4805SIan Dowse typedef enum { FIND, REMOVE, CHECKUNIQUE } dowhat;
69bc70c172SBrian Feldman 
708360efbdSAlfred Perlstein struct  addrinfo *nfshost_ai = NULL;
710fe9a7daSBrian Feldman int	fflag, vflag;
728fae3551SRodney W. Grimes char   *nfshost;
738fae3551SRodney W. Grimes 
741add162cSIan Dowse struct statfs *checkmntlist(char *);
75bc70c172SBrian Feldman int	 checkvfsname (const char *, char **);
76eddb4805SIan Dowse struct statfs *getmntentry(const char *fromname, const char *onname,
77eddb4805SIan Dowse 	     fsid_t *fsid, dowhat what);
78bc70c172SBrian Feldman char   **makevfslist (const char *);
79bc70c172SBrian Feldman size_t	 mntinfo (struct statfs **);
808360efbdSAlfred Perlstein int	 namematch (struct addrinfo *);
81eddb4805SIan Dowse int	 parsehexfsid(const char *hex, fsid_t *fsid);
828360efbdSAlfred Perlstein int	 sacmp (struct sockaddr *, struct sockaddr *);
83bc70c172SBrian Feldman int	 umountall (char **);
848360efbdSAlfred Perlstein int	 checkname (char *, char **);
85eddb4805SIan Dowse int	 umountfs(struct statfs *sfs);
86bc70c172SBrian Feldman void	 usage (void);
87bc70c172SBrian Feldman int	 xdr_dir (XDR *, char *);
888fae3551SRodney W. Grimes 
898fae3551SRodney W. Grimes int
90bc70c172SBrian Feldman main(int argc, char *argv[])
918fae3551SRodney W. Grimes {
928360efbdSAlfred Perlstein 	int all, errs, ch, mntsize, error;
93f73d495fSIan Dowse 	char **typelist = NULL;
94f73d495fSIan Dowse 	struct statfs *mntbuf, *sfs;
958360efbdSAlfred Perlstein 	struct addrinfo hints;
968fae3551SRodney W. Grimes 
978fae3551SRodney W. Grimes 	/* Start disks transferring immediately. */
988fae3551SRodney W. Grimes 	sync();
998fae3551SRodney W. Grimes 
1000fe9a7daSBrian Feldman 	all = errs = 0;
101ef258dd9SMatthew N. Dodd 	while ((ch = getopt(argc, argv, "AaF:fh:t:v")) != -1)
1028fae3551SRodney W. Grimes 		switch (ch) {
103d499a0efSBruce Evans 		case 'A':
104d499a0efSBruce Evans 			all = 2;
105d499a0efSBruce Evans 			break;
1068fae3551SRodney W. Grimes 		case 'a':
1078fae3551SRodney W. Grimes 			all = 1;
1088fae3551SRodney W. Grimes 			break;
109ef258dd9SMatthew N. Dodd 		case 'F':
110ef258dd9SMatthew N. Dodd 			setfstab(optarg);
111ef258dd9SMatthew N. Dodd 			break;
1128fae3551SRodney W. Grimes 		case 'f':
1138fae3551SRodney W. Grimes 			fflag = MNT_FORCE;
1148fae3551SRodney W. Grimes 			break;
115d499a0efSBruce Evans 		case 'h':	/* -h implies -A. */
116d499a0efSBruce Evans 			all = 2;
1178fae3551SRodney W. Grimes 			nfshost = optarg;
1188fae3551SRodney W. Grimes 			break;
1198fae3551SRodney W. Grimes 		case 't':
120d499a0efSBruce Evans 			if (typelist != NULL)
121bc70c172SBrian Feldman 				err(1, "only one -t option may be specified");
122d499a0efSBruce Evans 			typelist = makevfslist(optarg);
1238fae3551SRodney W. Grimes 			break;
1248fae3551SRodney W. Grimes 		case 'v':
1258fae3551SRodney W. Grimes 			vflag = 1;
1268fae3551SRodney W. Grimes 			break;
1278fae3551SRodney W. Grimes 		default:
1288fae3551SRodney W. Grimes 			usage();
1298fae3551SRodney W. Grimes 			/* NOTREACHED */
1308fae3551SRodney W. Grimes 		}
1318fae3551SRodney W. Grimes 	argc -= optind;
1328fae3551SRodney W. Grimes 	argv += optind;
1338fae3551SRodney W. Grimes 
134adb378ceSPhilippe Charnier 	if ((argc == 0 && !all) || (argc != 0 && all))
1358fae3551SRodney W. Grimes 		usage();
1368fae3551SRodney W. Grimes 
1378fae3551SRodney W. Grimes 	/* -h implies "-t nfs" if no -t flag. */
1388fae3551SRodney W. Grimes 	if ((nfshost != NULL) && (typelist == NULL))
139d499a0efSBruce Evans 		typelist = makevfslist("nfs");
1408fae3551SRodney W. Grimes 
1418360efbdSAlfred Perlstein 	if (nfshost != NULL) {
1428360efbdSAlfred Perlstein 		memset(&hints, 0, sizeof hints);
1438360efbdSAlfred Perlstein 		error = getaddrinfo(nfshost, NULL, &hints, &nfshost_ai);
14421eff82fSIan Dowse 		if (error)
14513e2e1afSIan Dowse 			errx(1, "%s: %s", nfshost, gai_strerror(error));
1468360efbdSAlfred Perlstein 	}
1478360efbdSAlfred Perlstein 
148d499a0efSBruce Evans 	switch (all) {
149d499a0efSBruce Evans 	case 2:
150bc70c172SBrian Feldman 		if ((mntsize = mntinfo(&mntbuf)) <= 0)
151d499a0efSBruce Evans 			break;
152bc70c172SBrian Feldman 		/*
153bc70c172SBrian Feldman 		 * We unmount the nfs-mounts in the reverse order
154bc70c172SBrian Feldman 		 * that they were mounted.
155bc70c172SBrian Feldman 		 */
156bc70c172SBrian Feldman 		for (errs = 0, mntsize--; mntsize > 0; mntsize--) {
157f73d495fSIan Dowse 			sfs = &mntbuf[mntsize];
158f73d495fSIan Dowse 			if (checkvfsname(sfs->f_fstypename, typelist))
159d499a0efSBruce Evans 				continue;
160eddb4805SIan Dowse 			if (umountfs(sfs) != 0)
161d499a0efSBruce Evans 				errs = 1;
162d499a0efSBruce Evans 		}
163bc70c172SBrian Feldman 		free(mntbuf);
164d499a0efSBruce Evans 		break;
165d499a0efSBruce Evans 	case 1:
1668fae3551SRodney W. Grimes 		if (setfsent() == 0)
167ef258dd9SMatthew N. Dodd 			err(1, "%s", getfstab());
168d499a0efSBruce Evans 		errs = umountall(typelist);
169d499a0efSBruce Evans 		break;
170d499a0efSBruce Evans 	case 0:
1718fae3551SRodney W. Grimes 		for (errs = 0; *argv != NULL; ++argv)
1728360efbdSAlfred Perlstein 			if (checkname(*argv, typelist) != 0)
173d499a0efSBruce Evans 				errs = 1;
174d499a0efSBruce Evans 		break;
175d499a0efSBruce Evans 	}
1768fae3551SRodney W. Grimes 	exit(errs);
1778fae3551SRodney W. Grimes }
1788fae3551SRodney W. Grimes 
1798fae3551SRodney W. Grimes int
180bc70c172SBrian Feldman umountall(char **typelist)
1818fae3551SRodney W. Grimes {
1825965373eSMaxime Henrion 	struct xvfsconf vfc;
1838fae3551SRodney W. Grimes 	struct fstab *fs;
184adb378ceSPhilippe Charnier 	int rval;
1858fae3551SRodney W. Grimes 	char *cp;
1860602ee7cSBrian Feldman 	static int firstcall = 1;
1878fae3551SRodney W. Grimes 
18891a81678SBrian Feldman 	if ((fs = getfsent()) != NULL)
1890602ee7cSBrian Feldman 		firstcall = 0;
19091a81678SBrian Feldman 	else if (firstcall)
19191a81678SBrian Feldman 		errx(1, "fstab reading failure");
19291a81678SBrian Feldman 	else
19391a81678SBrian Feldman 		return (0);
194bc70c172SBrian Feldman 	do {
1958fae3551SRodney W. Grimes 		/* Ignore the root. */
1968fae3551SRodney W. Grimes 		if (strcmp(fs->fs_file, "/") == 0)
1978fae3551SRodney W. Grimes 			continue;
1988fae3551SRodney W. Grimes 		/*
1998fae3551SRodney W. Grimes 		 * !!!
2008fae3551SRodney W. Grimes 		 * Historic practice: ignore unknown FSTAB_* fields.
2018fae3551SRodney W. Grimes 		 */
2028fae3551SRodney W. Grimes 		if (strcmp(fs->fs_type, FSTAB_RW) &&
2038fae3551SRodney W. Grimes 		    strcmp(fs->fs_type, FSTAB_RO) &&
2048fae3551SRodney W. Grimes 		    strcmp(fs->fs_type, FSTAB_RQ))
2058fae3551SRodney W. Grimes 			continue;
206b6e55a05SDag-Erling Smørgrav 		/* Ignore unknown file system types. */
20781667275SDag-Erling Smørgrav 		if (getvfsbyname(fs->fs_vfstype, &vfc) == -1)
2088fae3551SRodney W. Grimes 			continue;
209d499a0efSBruce Evans 		if (checkvfsname(fs->fs_vfstype, typelist))
2108fae3551SRodney W. Grimes 			continue;
2118fae3551SRodney W. Grimes 
2128fae3551SRodney W. Grimes 		/*
2138fae3551SRodney W. Grimes 		 * We want to unmount the file systems in the reverse order
2148fae3551SRodney W. Grimes 		 * that they were mounted.  So, we save off the file name
2158fae3551SRodney W. Grimes 		 * in some allocated memory, and then call recursively.
2168fae3551SRodney W. Grimes 		 */
2178fae3551SRodney W. Grimes 		if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL)
218bc70c172SBrian Feldman 			err(1, "malloc failed");
2198fae3551SRodney W. Grimes 		(void)strcpy(cp, fs->fs_file);
220d499a0efSBruce Evans 		rval = umountall(typelist);
2218360efbdSAlfred Perlstein 		rval = checkname(cp, typelist) || rval;
222bc70c172SBrian Feldman 		free(cp);
2230602ee7cSBrian Feldman 		return (rval);
2240602ee7cSBrian Feldman 	} while ((fs = getfsent()) != NULL);
2258fae3551SRodney W. Grimes 	return (0);
2268fae3551SRodney W. Grimes }
2278fae3551SRodney W. Grimes 
2288360efbdSAlfred Perlstein /*
229eddb4805SIan Dowse  * Do magic checks on mountpoint/device/fsid, and then call unmount(2).
2308360efbdSAlfred Perlstein  */
2318fae3551SRodney W. Grimes int
2328360efbdSAlfred Perlstein checkname(char *name, char **typelist)
2338fae3551SRodney W. Grimes {
234eddb4805SIan Dowse 	char buf[MAXPATHLEN];
235eddb4805SIan Dowse 	struct statfs sfsbuf;
236eddb4805SIan Dowse 	struct stat sb;
237f73d495fSIan Dowse 	struct statfs *sfs;
238eddb4805SIan Dowse 	char *delimp;
239eddb4805SIan Dowse 	dev_t dev;
240eddb4805SIan Dowse 	int len;
2418fae3551SRodney W. Grimes 
242bc70c172SBrian Feldman 	/*
243bc70c172SBrian Feldman 	 * 1. Check if the name exists in the mounttable.
244bc70c172SBrian Feldman 	 */
2451add162cSIan Dowse 	sfs = checkmntlist(name);
246bc70c172SBrian Feldman 	/*
247bc70c172SBrian Feldman 	 * 2. Remove trailing slashes if there are any. After that
248bc70c172SBrian Feldman 	 * we look up the name in the mounttable again.
249bc70c172SBrian Feldman 	 */
250318f2fb4SIan Dowse 	if (sfs == NULL) {
251eddb4805SIan Dowse 		len = strlen(name);
252eddb4805SIan Dowse 		while (len > 0 && name[len - 1] == '/')
253eddb4805SIan Dowse 			name[--len] = '\0';
2541add162cSIan Dowse 		sfs = checkmntlist(name);
255bc70c172SBrian Feldman 	}
256bc70c172SBrian Feldman 	/*
257eddb4805SIan Dowse 	 * 3. Check if the deprecated NFS syntax with an '@' has been used
258eddb4805SIan Dowse 	 * and translate it to the ':' syntax. Look up the name in the
259eddb4805SIan Dowse 	 * mount table again.
260bc70c172SBrian Feldman 	 */
261eddb4805SIan Dowse 	if (sfs == NULL && (delimp = strrchr(name, '@')) != NULL) {
262eddb4805SIan Dowse 		snprintf(buf, sizeof(buf), "%s:%.*s", delimp + 1, delimp - name,
263eddb4805SIan Dowse 		    name);
264eddb4805SIan Dowse 		len = strlen(buf);
265eddb4805SIan Dowse 		while (len > 0 && buf[len - 1] == '/')
266eddb4805SIan Dowse 			buf[--len] = '\0';
267eddb4805SIan Dowse 		sfs = checkmntlist(buf);
268bc70c172SBrian Feldman 	}
269bc70c172SBrian Feldman 	/*
270eddb4805SIan Dowse 	 * 4. Resort to a statfs(2) call. This is the last check so that
271eddb4805SIan Dowse 	 * hung NFS filesystems for example can be unmounted without
272eddb4805SIan Dowse 	 * potentially blocking forever in statfs() as long as the
273eddb4805SIan Dowse 	 * filesystem is specified unambiguously. This covers all the
274eddb4805SIan Dowse 	 * hard cases such as symlinks and mismatches between the
275eddb4805SIan Dowse 	 * mount list and reality.
276eddb4805SIan Dowse 	 * We also do this if an ambiguous mount point was specified.
277bc70c172SBrian Feldman 	 */
278eddb4805SIan Dowse 	if (sfs == NULL || (getmntentry(NULL, name, NULL, FIND) != NULL &&
279eddb4805SIan Dowse 	    getmntentry(NULL, name, NULL, CHECKUNIQUE) == NULL)) {
280eddb4805SIan Dowse 		if (statfs(name, &sfsbuf) != 0) {
281eddb4805SIan Dowse 			warn("%s: statfs", name);
282eddb4805SIan Dowse 		} else if (stat(name, &sb) != 0) {
283eddb4805SIan Dowse 			warn("%s: stat", name);
284eddb4805SIan Dowse 		} else if (S_ISDIR(sb.st_mode)) {
285eddb4805SIan Dowse 			/* Check that `name' is the root directory. */
286eddb4805SIan Dowse 			dev = sb.st_dev;
287eddb4805SIan Dowse 			snprintf(buf, sizeof(buf), "%s/..", name);
288eddb4805SIan Dowse 			if (stat(buf, &sb) != 0) {
289eddb4805SIan Dowse 				warn("%s: stat", buf);
290eddb4805SIan Dowse 			} else if (sb.st_dev == dev) {
291eddb4805SIan Dowse 				warnx("%s: not a file system root directory",
292eddb4805SIan Dowse 				    name);
293eddb4805SIan Dowse 				return (1);
2948360efbdSAlfred Perlstein 			} else
295eddb4805SIan Dowse 				sfs = &sfsbuf;
296eddb4805SIan Dowse 		}
297eddb4805SIan Dowse 	}
298eddb4805SIan Dowse 	if (sfs == NULL) {
299eddb4805SIan Dowse 		warnx("%s: unknown file system", name);
3008fae3551SRodney W. Grimes 		return (1);
3018fae3551SRodney W. Grimes 	}
3021add162cSIan Dowse 	if (checkvfsname(sfs->f_fstypename, typelist))
303d499a0efSBruce Evans 		return (1);
304eddb4805SIan Dowse 	return (umountfs(sfs));
3058360efbdSAlfred Perlstein }
3068360efbdSAlfred Perlstein 
3078360efbdSAlfred Perlstein /*
3088360efbdSAlfred Perlstein  * NFS stuff and unmount(2) call
3098360efbdSAlfred Perlstein  */
3108360efbdSAlfred Perlstein int
311eddb4805SIan Dowse umountfs(struct statfs *sfs)
3128360efbdSAlfred Perlstein {
313318f2fb4SIan Dowse 	char fsidbuf[64];
3148360efbdSAlfred Perlstein 	enum clnt_stat clnt_stat;
3158360efbdSAlfred Perlstein 	struct timeval try;
3168360efbdSAlfred Perlstein 	struct addrinfo *ai, hints;
3178360efbdSAlfred Perlstein 	int do_rpc;
3188360efbdSAlfred Perlstein 	CLIENT *clp;
3198360efbdSAlfred Perlstein 	char *nfsdirname, *orignfsdirname;
3208360efbdSAlfred Perlstein 	char *hostp, *delimp;
3218360efbdSAlfred Perlstein 
3228360efbdSAlfred Perlstein 	ai = NULL;
32313e2e1afSIan Dowse 	do_rpc = 0;
32413e2e1afSIan Dowse 	hostp = NULL;
3258360efbdSAlfred Perlstein 	nfsdirname = delimp = orignfsdirname = NULL;
3268360efbdSAlfred Perlstein 	memset(&hints, 0, sizeof hints);
3278360efbdSAlfred Perlstein 
328eddb4805SIan Dowse 	if (strcmp(sfs->f_fstypename, "nfs") == 0) {
329eddb4805SIan Dowse 		if ((nfsdirname = strdup(sfs->f_mntfromname)) == NULL)
3308360efbdSAlfred Perlstein 			err(1, "strdup");
3318360efbdSAlfred Perlstein 		orignfsdirname = nfsdirname;
3328360efbdSAlfred Perlstein 		if ((delimp = strrchr(nfsdirname, ':')) != NULL) {
3338360efbdSAlfred Perlstein 			*delimp = '\0';
3348360efbdSAlfred Perlstein 			hostp = nfsdirname;
3358360efbdSAlfred Perlstein 			getaddrinfo(hostp, NULL, &hints, &ai);
3368360efbdSAlfred Perlstein 			if (ai == NULL) {
3378360efbdSAlfred Perlstein 				warnx("can't get net id for host");
3388360efbdSAlfred Perlstein 			}
3398360efbdSAlfred Perlstein 			nfsdirname = delimp + 1;
3408360efbdSAlfred Perlstein 		}
34113e2e1afSIan Dowse 
342bc70c172SBrian Feldman 		/*
343bc70c172SBrian Feldman 		 * Check if we have to start the rpc-call later.
344bc70c172SBrian Feldman 		 * If there are still identical nfs-names mounted,
345bc70c172SBrian Feldman 		 * we skip the rpc-call. Obviously this has to
346bc70c172SBrian Feldman 		 * happen before unmount(2), but it should happen
347bc70c172SBrian Feldman 		 * after the previous namecheck.
34813e2e1afSIan Dowse 		 * A non-NULL return means that this is the last
34913e2e1afSIan Dowse 		 * mount from mntfromname that is still mounted.
350bc70c172SBrian Feldman 		 */
351eddb4805SIan Dowse 		if (getmntentry(sfs->f_mntfromname, NULL, NULL,
352eddb4805SIan Dowse 		    CHECKUNIQUE) != NULL)
3530fe9a7daSBrian Feldman 			do_rpc = 1;
35413e2e1afSIan Dowse 	}
3558360efbdSAlfred Perlstein 
3568360efbdSAlfred Perlstein 	if (!namematch(ai))
357d499a0efSBruce Evans 		return (1);
358eddb4805SIan Dowse 	/* First try to unmount using the file system ID. */
359eddb4805SIan Dowse 	snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", sfs->f_fsid.val[0],
360eddb4805SIan Dowse 	    sfs->f_fsid.val[1]);
361318f2fb4SIan Dowse 	if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) {
362eddb4805SIan Dowse 		warn("unmount of %s failed", sfs->f_mntonname);
363318f2fb4SIan Dowse 		if (errno != ENOENT)
364318f2fb4SIan Dowse 			return (1);
365318f2fb4SIan Dowse 		/* Compatability for old kernels. */
366318f2fb4SIan Dowse 		warnx("retrying using path instead of file system ID");
367eddb4805SIan Dowse 		if (unmount(sfs->f_mntonname, fflag) != 0) {
368eddb4805SIan Dowse 			warn("unmount of %s failed", sfs->f_mntonname);
3698fae3551SRodney W. Grimes 			return (1);
3708fae3551SRodney W. Grimes 		}
371eddb4805SIan Dowse 	}
372eddb4805SIan Dowse 	/* Mark this this file system as unmounted. */
373eddb4805SIan Dowse 	getmntentry(NULL, NULL, &sfs->f_fsid, REMOVE);
374bc70c172SBrian Feldman 	if (vflag)
375eddb4805SIan Dowse 		(void)printf("%s: unmount from %s\n", sfs->f_mntfromname,
376eddb4805SIan Dowse 		    sfs->f_mntonname);
377bc70c172SBrian Feldman 	/*
378bc70c172SBrian Feldman 	 * Report to mountd-server which nfsname
379bc70c172SBrian Feldman 	 * has been unmounted.
380bc70c172SBrian Feldman 	 */
3818360efbdSAlfred Perlstein 	if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) {
3828360efbdSAlfred Perlstein 		clp = clnt_create(hostp, RPCPROG_MNT, RPCMNT_VER1, "udp");
3838360efbdSAlfred Perlstein 		if (clp  == NULL) {
38413e2e1afSIan Dowse 			warnx("%s: %s", hostp,
38513e2e1afSIan Dowse 			    clnt_spcreateerror("RPCPROG_MNT"));
3868fae3551SRodney W. Grimes 			return (1);
3878fae3551SRodney W. Grimes 		}
3888360efbdSAlfred Perlstein 		clp->cl_auth = authsys_create_default();
3898fae3551SRodney W. Grimes 		try.tv_sec = 20;
3908fae3551SRodney W. Grimes 		try.tv_usec = 0;
3915c514aeeSMatthew N. Dodd 		clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, (xdrproc_t)xdr_dir,
3925c514aeeSMatthew N. Dodd 		    nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try);
3938fae3551SRodney W. Grimes 		if (clnt_stat != RPC_SUCCESS) {
39413e2e1afSIan Dowse 			warnx("%s: %s", hostp,
39513e2e1afSIan Dowse 			    clnt_sperror(clp, "RPCMNT_UMOUNT"));
3968fae3551SRodney W. Grimes 			return (1);
3978fae3551SRodney W. Grimes 		}
398a69497d7SMatthew Dillon 		/*
399a69497d7SMatthew Dillon 		 * Remove the unmounted entry from /var/db/mounttab.
400a69497d7SMatthew Dillon 		 */
401afe1ef24SIan Dowse 		if (read_mtab()) {
402afe1ef24SIan Dowse 			clean_mtab(hostp, nfsdirname, vflag);
403afe1ef24SIan Dowse 			if(!write_mtab(vflag))
40413e2e1afSIan Dowse 				warnx("cannot remove mounttab entry %s:%s",
405a69497d7SMatthew Dillon 				    hostp, nfsdirname);
406a69497d7SMatthew Dillon 			free_mtab();
407a69497d7SMatthew Dillon 		}
408bc70c172SBrian Feldman 		free(orignfsdirname);
4098fae3551SRodney W. Grimes 		auth_destroy(clp->cl_auth);
4108fae3551SRodney W. Grimes 		clnt_destroy(clp);
4118fae3551SRodney W. Grimes 	}
4128fae3551SRodney W. Grimes 	return (0);
4138fae3551SRodney W. Grimes }
4148fae3551SRodney W. Grimes 
415318f2fb4SIan Dowse struct statfs *
416eddb4805SIan Dowse getmntentry(const char *fromname, const char *onname, fsid_t *fsid, dowhat what)
4178fae3551SRodney W. Grimes {
418d499a0efSBruce Evans 	static struct statfs *mntbuf;
419bc70c172SBrian Feldman 	static size_t mntsize = 0;
420bc70c172SBrian Feldman 	static char *mntcheck = NULL;
421eddb4805SIan Dowse 	struct statfs *sfs, *foundsfs;
422bc70c172SBrian Feldman 	int i, count;
4238fae3551SRodney W. Grimes 
424bc70c172SBrian Feldman 	if (mntsize <= 0) {
425bc70c172SBrian Feldman 		if ((mntsize = mntinfo(&mntbuf)) <= 0)
4268fae3551SRodney W. Grimes 			return (NULL);
4278fae3551SRodney W. Grimes 	}
428bc70c172SBrian Feldman 	if (mntcheck == NULL) {
429eddb4805SIan Dowse 		if ((mntcheck = calloc(mntsize + 1, sizeof(int))) == NULL)
430bc70c172SBrian Feldman 			err(1, "calloc");
431bc70c172SBrian Feldman 	}
432bc70c172SBrian Feldman 	/*
433bc70c172SBrian Feldman 	 * We want to get the file systems in the reverse order
434eddb4805SIan Dowse 	 * that they were mounted. Unmounted file systems are marked
435eddb4805SIan Dowse 	 * in a table called 'mntcheck'.
436bc70c172SBrian Feldman 	 */
437eddb4805SIan Dowse 	count = 0;
438eddb4805SIan Dowse 	foundsfs = NULL;
439bc70c172SBrian Feldman 	for (i = mntsize - 1; i >= 0; i--) {
440eddb4805SIan Dowse 		if (mntcheck[i])
441eddb4805SIan Dowse 			continue;
442eddb4805SIan Dowse 		sfs = &mntbuf[i];
443eddb4805SIan Dowse 		if (fromname != NULL && strcmp(sfs->f_mntfromname,
444eddb4805SIan Dowse 		    fromname) != 0)
445eddb4805SIan Dowse 			continue;
446eddb4805SIan Dowse 		if (onname != NULL && strcmp(sfs->f_mntonname, onname) != 0)
447eddb4805SIan Dowse 			continue;
448eddb4805SIan Dowse 		if (fsid != NULL && bcmp(&sfs->f_fsid, fsid,
449eddb4805SIan Dowse 		    sizeof(*fsid)) != 0)
450eddb4805SIan Dowse 			continue;
451eddb4805SIan Dowse 
45238f102c2SIan Dowse 		switch (what) {
453eddb4805SIan Dowse 		case CHECKUNIQUE:
454eddb4805SIan Dowse 			foundsfs = sfs;
455eddb4805SIan Dowse 			count++;
45638f102c2SIan Dowse 			continue;
457eddb4805SIan Dowse 		case REMOVE:
458eddb4805SIan Dowse 			mntcheck[i] = 1;
45938f102c2SIan Dowse 			break;
460eddb4805SIan Dowse 		default:
46138f102c2SIan Dowse 			break;
46238f102c2SIan Dowse 		}
463eddb4805SIan Dowse 		return (sfs);
4648fae3551SRodney W. Grimes 	}
465318f2fb4SIan Dowse 
466eddb4805SIan Dowse 	if (what == CHECKUNIQUE && count == 1)
467eddb4805SIan Dowse 		return (foundsfs);
4688fae3551SRodney W. Grimes 	return (NULL);
4698fae3551SRodney W. Grimes }
4708fae3551SRodney W. Grimes 
4718fae3551SRodney W. Grimes int
4728360efbdSAlfred Perlstein sacmp(struct sockaddr *sa1, struct sockaddr *sa2)
4738fae3551SRodney W. Grimes {
4748360efbdSAlfred Perlstein 	void *p1, *p2;
4758360efbdSAlfred Perlstein 	int len;
4768fae3551SRodney W. Grimes 
4778360efbdSAlfred Perlstein 	if (sa1->sa_family != sa2->sa_family)
4788fae3551SRodney W. Grimes 		return (1);
4798fae3551SRodney W. Grimes 
4808360efbdSAlfred Perlstein 	switch (sa1->sa_family) {
4818360efbdSAlfred Perlstein 	case AF_INET:
4828360efbdSAlfred Perlstein 		p1 = &((struct sockaddr_in *)sa1)->sin_addr;
4838360efbdSAlfred Perlstein 		p2 = &((struct sockaddr_in *)sa2)->sin_addr;
4848360efbdSAlfred Perlstein 		len = 4;
4858360efbdSAlfred Perlstein 		break;
4868360efbdSAlfred Perlstein 	case AF_INET6:
4878360efbdSAlfred Perlstein 		p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
4888360efbdSAlfred Perlstein 		p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
4898360efbdSAlfred Perlstein 		len = 16;
4908360efbdSAlfred Perlstein 		if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
4918360efbdSAlfred Perlstein 		    ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
4928360efbdSAlfred Perlstein 			return (1);
4938360efbdSAlfred Perlstein 		break;
4948360efbdSAlfred Perlstein 	default:
4958360efbdSAlfred Perlstein 		return (1);
4968360efbdSAlfred Perlstein 	}
4978360efbdSAlfred Perlstein 
4988360efbdSAlfred Perlstein 	return memcmp(p1, p2, len);
4998360efbdSAlfred Perlstein }
5008360efbdSAlfred Perlstein 
5018360efbdSAlfred Perlstein int
5028360efbdSAlfred Perlstein namematch(struct addrinfo *ai)
5038360efbdSAlfred Perlstein {
5048360efbdSAlfred Perlstein 	struct addrinfo *aip;
5058360efbdSAlfred Perlstein 
5068360efbdSAlfred Perlstein 	if (nfshost == NULL || nfshost_ai == NULL)
5078fae3551SRodney W. Grimes 		return (1);
5088fae3551SRodney W. Grimes 
5098360efbdSAlfred Perlstein 	while (ai != NULL) {
5108360efbdSAlfred Perlstein 		aip = nfshost_ai;
5118360efbdSAlfred Perlstein 		while (aip != NULL) {
5128360efbdSAlfred Perlstein 			if (sacmp(ai->ai_addr, aip->ai_addr) == 0)
5138fae3551SRodney W. Grimes 				return (1);
5148360efbdSAlfred Perlstein 			aip = aip->ai_next;
5158fae3551SRodney W. Grimes 		}
5168360efbdSAlfred Perlstein 		ai = ai->ai_next;
5178fae3551SRodney W. Grimes 	}
5188360efbdSAlfred Perlstein 
5198fae3551SRodney W. Grimes 	return (0);
5208fae3551SRodney W. Grimes }
5218fae3551SRodney W. Grimes 
522318f2fb4SIan Dowse struct statfs *
5231add162cSIan Dowse checkmntlist(char *name)
524bc70c172SBrian Feldman {
525318f2fb4SIan Dowse 	struct statfs *sfs;
526eddb4805SIan Dowse 	fsid_t fsid;
527bc70c172SBrian Feldman 
528eddb4805SIan Dowse 	sfs = NULL;
529eddb4805SIan Dowse 	if (parsehexfsid(name, &fsid) == 0)
530eddb4805SIan Dowse 		sfs = getmntentry(NULL, NULL, &fsid, FIND);
53138f102c2SIan Dowse 	if (sfs == NULL)
532eddb4805SIan Dowse 		sfs = getmntentry(NULL, name, NULL, FIND);
533318f2fb4SIan Dowse 	if (sfs == NULL)
534eddb4805SIan Dowse 		sfs = getmntentry(name, NULL, NULL, FIND);
535318f2fb4SIan Dowse 	return (sfs);
536bc70c172SBrian Feldman }
537bc70c172SBrian Feldman 
538bc70c172SBrian Feldman size_t
539bc70c172SBrian Feldman mntinfo(struct statfs **mntbuf)
540bc70c172SBrian Feldman {
541bc70c172SBrian Feldman 	static struct statfs *origbuf;
542bc70c172SBrian Feldman 	size_t bufsize;
543bc70c172SBrian Feldman 	int mntsize;
544bc70c172SBrian Feldman 
545a69497d7SMatthew Dillon 	mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
546bc70c172SBrian Feldman 	if (mntsize <= 0)
547bc70c172SBrian Feldman 		return (0);
548bc70c172SBrian Feldman 	bufsize = (mntsize + 1) * sizeof(struct statfs);
549bc70c172SBrian Feldman 	if ((origbuf = malloc(bufsize)) == NULL)
550bc70c172SBrian Feldman 		err(1, "malloc");
551bc70c172SBrian Feldman 	mntsize = getfsstat(origbuf, (long)bufsize, MNT_NOWAIT);
552bc70c172SBrian Feldman 	*mntbuf = origbuf;
553bc70c172SBrian Feldman 	return (mntsize);
554bc70c172SBrian Feldman }
555bc70c172SBrian Feldman 
556eddb4805SIan Dowse /*
557eddb4805SIan Dowse  * Convert a hexidecimal filesystem ID to an fsid_t.
558eddb4805SIan Dowse  * Returns 0 on success.
559eddb4805SIan Dowse  */
560eddb4805SIan Dowse int
561eddb4805SIan Dowse parsehexfsid(const char *hex, fsid_t *fsid)
562bc70c172SBrian Feldman {
563eddb4805SIan Dowse 	char hexbuf[3];
564eddb4805SIan Dowse 	int i;
565bc70c172SBrian Feldman 
566eddb4805SIan Dowse 	if (strlen(hex) != sizeof(*fsid) * 2)
567eddb4805SIan Dowse 		return (-1);
568eddb4805SIan Dowse 	hexbuf[2] = '\0';
569eddb4805SIan Dowse 	for (i = 0; i < sizeof(*fsid); i++) {
570eddb4805SIan Dowse 		hexbuf[0] = hex[i * 2];
571eddb4805SIan Dowse 		hexbuf[1] = hex[i * 2 + 1];
572eddb4805SIan Dowse 		if (!isxdigit(hexbuf[0]) || !isxdigit(hexbuf[1]))
573eddb4805SIan Dowse 			return (-1);
574eddb4805SIan Dowse 		((u_char *)fsid)[i] = strtol(hexbuf, NULL, 16);
575bc70c172SBrian Feldman 	}
576eddb4805SIan Dowse 	return (0);
577bc70c172SBrian Feldman }
578bc70c172SBrian Feldman 
5798fae3551SRodney W. Grimes /*
5808fae3551SRodney W. Grimes  * xdr routines for mount rpc's
5818fae3551SRodney W. Grimes  */
5828fae3551SRodney W. Grimes int
583bc70c172SBrian Feldman xdr_dir(XDR *xdrsp, char *dirp)
5848fae3551SRodney W. Grimes {
585bc70c172SBrian Feldman 
5868fae3551SRodney W. Grimes 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
5878fae3551SRodney W. Grimes }
5888fae3551SRodney W. Grimes 
5898fae3551SRodney W. Grimes void
5908fae3551SRodney W. Grimes usage()
5918fae3551SRodney W. Grimes {
592bc70c172SBrian Feldman 
593210a5dc8SPhilippe Charnier 	(void)fprintf(stderr, "%s\n%s\n",
594210a5dc8SPhilippe Charnier 	    "usage: umount [-fv] special | node",
595ef258dd9SMatthew N. Dodd 	    "       umount -a | -A [ -F fstab] [-fv] [-h host] [-t type]");
5968fae3551SRodney W. Grimes 	exit(1);
5978fae3551SRodney W. Grimes }
598