xref: /freebsd/sbin/umount/umount.c (revision a505d435)
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  * 4. Neither the name of the University nor the names of its contributors
148fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
158fae3551SRodney W. Grimes  *    without specific prior written permission.
168fae3551SRodney W. Grimes  *
178fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
188fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
198fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
208fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
218fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
228fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
238fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
248fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
258fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
268fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
278fae3551SRodney W. Grimes  * SUCH DAMAGE.
288fae3551SRodney W. Grimes  */
298fae3551SRodney W. Grimes 
308fae3551SRodney W. Grimes #ifndef lint
31adb378ceSPhilippe Charnier static const char copyright[] =
328fae3551SRodney W. Grimes "@(#) Copyright (c) 1980, 1989, 1993\n\
338fae3551SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
348fae3551SRodney W. Grimes #endif /* not lint */
358fae3551SRodney W. Grimes 
368fae3551SRodney W. Grimes #ifndef lint
37adb378ceSPhilippe Charnier #if 0
38d499a0efSBruce Evans static char sccsid[] = "@(#)umount.c	8.8 (Berkeley) 5/8/95";
39adb378ceSPhilippe Charnier #endif
40adb378ceSPhilippe Charnier static const char rcsid[] =
417f3dea24SPeter Wemm   "$FreeBSD$";
428fae3551SRodney W. Grimes #endif /* not lint */
438fae3551SRodney W. Grimes 
448fae3551SRodney W. Grimes #include <sys/param.h>
458fae3551SRodney W. Grimes #include <sys/mount.h>
468360efbdSAlfred Perlstein #include <sys/socket.h>
47eddb4805SIan Dowse #include <sys/stat.h>
488fae3551SRodney W. Grimes 
498fae3551SRodney W. Grimes #include <netdb.h>
508fae3551SRodney W. Grimes #include <rpc/rpc.h>
510775314bSDoug Rabson #include <rpcsvc/mount.h>
528fae3551SRodney W. Grimes 
5338f102c2SIan Dowse #include <ctype.h>
548fae3551SRodney W. Grimes #include <err.h>
55318f2fb4SIan Dowse #include <errno.h>
568fae3551SRodney W. Grimes #include <fstab.h>
578fae3551SRodney W. Grimes #include <stdio.h>
588fae3551SRodney W. Grimes #include <stdlib.h>
598fae3551SRodney W. Grimes #include <string.h>
608fae3551SRodney W. Grimes #include <unistd.h>
618fae3551SRodney W. Grimes 
62a69497d7SMatthew Dillon #include "mounttab.h"
63a69497d7SMatthew Dillon 
64eddb4805SIan Dowse typedef enum { FIND, REMOVE, CHECKUNIQUE } dowhat;
65bc70c172SBrian Feldman 
668360efbdSAlfred Perlstein struct  addrinfo *nfshost_ai = NULL;
670fe9a7daSBrian Feldman int	fflag, vflag;
688fae3551SRodney W. Grimes char   *nfshost;
698fae3551SRodney W. Grimes 
701add162cSIan Dowse struct statfs *checkmntlist(char *);
71bc70c172SBrian Feldman int	 checkvfsname (const char *, char **);
72eddb4805SIan Dowse struct statfs *getmntentry(const char *fromname, const char *onname,
73eddb4805SIan Dowse 	     fsid_t *fsid, dowhat what);
74bc70c172SBrian Feldman char   **makevfslist (const char *);
75bc70c172SBrian Feldman size_t	 mntinfo (struct statfs **);
768360efbdSAlfred Perlstein int	 namematch (struct addrinfo *);
77eddb4805SIan Dowse int	 parsehexfsid(const char *hex, fsid_t *fsid);
787f471a32SXin LI int	 sacmp (void *, void *);
79bc70c172SBrian Feldman int	 umountall (char **);
808360efbdSAlfred Perlstein int	 checkname (char *, char **);
81eddb4805SIan Dowse int	 umountfs(struct statfs *sfs);
82bc70c172SBrian Feldman void	 usage (void);
83bc70c172SBrian Feldman int	 xdr_dir (XDR *, char *);
848fae3551SRodney W. Grimes 
858fae3551SRodney W. Grimes int
86bc70c172SBrian Feldman main(int argc, char *argv[])
878fae3551SRodney W. Grimes {
888360efbdSAlfred Perlstein 	int all, errs, ch, mntsize, error;
89f73d495fSIan Dowse 	char **typelist = NULL;
90f73d495fSIan Dowse 	struct statfs *mntbuf, *sfs;
918360efbdSAlfred Perlstein 	struct addrinfo hints;
928fae3551SRodney W. Grimes 
938fae3551SRodney W. Grimes 	/* Start disks transferring immediately. */
948fae3551SRodney W. Grimes 	sync();
958fae3551SRodney W. Grimes 
960fe9a7daSBrian Feldman 	all = errs = 0;
97ef258dd9SMatthew N. Dodd 	while ((ch = getopt(argc, argv, "AaF:fh:t:v")) != -1)
988fae3551SRodney W. Grimes 		switch (ch) {
99d499a0efSBruce Evans 		case 'A':
100d499a0efSBruce Evans 			all = 2;
101d499a0efSBruce Evans 			break;
1028fae3551SRodney W. Grimes 		case 'a':
1038fae3551SRodney W. Grimes 			all = 1;
1048fae3551SRodney W. Grimes 			break;
105ef258dd9SMatthew N. Dodd 		case 'F':
106ef258dd9SMatthew N. Dodd 			setfstab(optarg);
107ef258dd9SMatthew N. Dodd 			break;
1088fae3551SRodney W. Grimes 		case 'f':
1098fae3551SRodney W. Grimes 			fflag = MNT_FORCE;
1108fae3551SRodney W. Grimes 			break;
111d499a0efSBruce Evans 		case 'h':	/* -h implies -A. */
112d499a0efSBruce Evans 			all = 2;
1138fae3551SRodney W. Grimes 			nfshost = optarg;
1148fae3551SRodney W. Grimes 			break;
1158fae3551SRodney W. Grimes 		case 't':
116d499a0efSBruce Evans 			if (typelist != NULL)
117bc70c172SBrian Feldman 				err(1, "only one -t option may be specified");
118d499a0efSBruce Evans 			typelist = makevfslist(optarg);
1198fae3551SRodney W. Grimes 			break;
1208fae3551SRodney W. Grimes 		case 'v':
1218fae3551SRodney W. Grimes 			vflag = 1;
1228fae3551SRodney W. Grimes 			break;
1238fae3551SRodney W. Grimes 		default:
1248fae3551SRodney W. Grimes 			usage();
1258fae3551SRodney W. Grimes 			/* NOTREACHED */
1268fae3551SRodney W. Grimes 		}
1278fae3551SRodney W. Grimes 	argc -= optind;
1288fae3551SRodney W. Grimes 	argv += optind;
1298fae3551SRodney W. Grimes 
130adb378ceSPhilippe Charnier 	if ((argc == 0 && !all) || (argc != 0 && all))
1318fae3551SRodney W. Grimes 		usage();
1328fae3551SRodney W. Grimes 
1338fae3551SRodney W. Grimes 	/* -h implies "-t nfs" if no -t flag. */
1348fae3551SRodney W. Grimes 	if ((nfshost != NULL) && (typelist == NULL))
135d499a0efSBruce Evans 		typelist = makevfslist("nfs");
1368fae3551SRodney W. Grimes 
1378360efbdSAlfred Perlstein 	if (nfshost != NULL) {
1388360efbdSAlfred Perlstein 		memset(&hints, 0, sizeof hints);
1398360efbdSAlfred Perlstein 		error = getaddrinfo(nfshost, NULL, &hints, &nfshost_ai);
14021eff82fSIan Dowse 		if (error)
14113e2e1afSIan Dowse 			errx(1, "%s: %s", nfshost, gai_strerror(error));
1428360efbdSAlfred Perlstein 	}
1438360efbdSAlfred Perlstein 
144d499a0efSBruce Evans 	switch (all) {
145d499a0efSBruce Evans 	case 2:
146bc70c172SBrian Feldman 		if ((mntsize = mntinfo(&mntbuf)) <= 0)
147d499a0efSBruce Evans 			break;
148bc70c172SBrian Feldman 		/*
149bc70c172SBrian Feldman 		 * We unmount the nfs-mounts in the reverse order
150bc70c172SBrian Feldman 		 * that they were mounted.
151bc70c172SBrian Feldman 		 */
152bc70c172SBrian Feldman 		for (errs = 0, mntsize--; mntsize > 0; mntsize--) {
153f73d495fSIan Dowse 			sfs = &mntbuf[mntsize];
154f73d495fSIan Dowse 			if (checkvfsname(sfs->f_fstypename, typelist))
155d499a0efSBruce Evans 				continue;
156eddb4805SIan Dowse 			if (umountfs(sfs) != 0)
157d499a0efSBruce Evans 				errs = 1;
158d499a0efSBruce Evans 		}
159bc70c172SBrian Feldman 		free(mntbuf);
160d499a0efSBruce Evans 		break;
161d499a0efSBruce Evans 	case 1:
1628fae3551SRodney W. Grimes 		if (setfsent() == 0)
163ef258dd9SMatthew N. Dodd 			err(1, "%s", getfstab());
164d499a0efSBruce Evans 		errs = umountall(typelist);
165d499a0efSBruce Evans 		break;
166d499a0efSBruce Evans 	case 0:
1678fae3551SRodney W. Grimes 		for (errs = 0; *argv != NULL; ++argv)
1688360efbdSAlfred Perlstein 			if (checkname(*argv, typelist) != 0)
169d499a0efSBruce Evans 				errs = 1;
170d499a0efSBruce Evans 		break;
171d499a0efSBruce Evans 	}
1728fae3551SRodney W. Grimes 	exit(errs);
1738fae3551SRodney W. Grimes }
1748fae3551SRodney W. Grimes 
1758fae3551SRodney W. Grimes int
176bc70c172SBrian Feldman umountall(char **typelist)
1778fae3551SRodney W. Grimes {
1785965373eSMaxime Henrion 	struct xvfsconf vfc;
1798fae3551SRodney W. Grimes 	struct fstab *fs;
180adb378ceSPhilippe Charnier 	int rval;
1818fae3551SRodney W. Grimes 	char *cp;
1820602ee7cSBrian Feldman 	static int firstcall = 1;
1838fae3551SRodney W. Grimes 
18491a81678SBrian Feldman 	if ((fs = getfsent()) != NULL)
1850602ee7cSBrian Feldman 		firstcall = 0;
18691a81678SBrian Feldman 	else if (firstcall)
18791a81678SBrian Feldman 		errx(1, "fstab reading failure");
18891a81678SBrian Feldman 	else
18991a81678SBrian Feldman 		return (0);
190bc70c172SBrian Feldman 	do {
1918fae3551SRodney W. Grimes 		/* Ignore the root. */
1928fae3551SRodney W. Grimes 		if (strcmp(fs->fs_file, "/") == 0)
1938fae3551SRodney W. Grimes 			continue;
1948fae3551SRodney W. Grimes 		/*
1958fae3551SRodney W. Grimes 		 * !!!
1968fae3551SRodney W. Grimes 		 * Historic practice: ignore unknown FSTAB_* fields.
1978fae3551SRodney W. Grimes 		 */
1988fae3551SRodney W. Grimes 		if (strcmp(fs->fs_type, FSTAB_RW) &&
1998fae3551SRodney W. Grimes 		    strcmp(fs->fs_type, FSTAB_RO) &&
2008fae3551SRodney W. Grimes 		    strcmp(fs->fs_type, FSTAB_RQ))
2018fae3551SRodney W. Grimes 			continue;
202b6e55a05SDag-Erling Smørgrav 		/* Ignore unknown file system types. */
20381667275SDag-Erling Smørgrav 		if (getvfsbyname(fs->fs_vfstype, &vfc) == -1)
2048fae3551SRodney W. Grimes 			continue;
205d499a0efSBruce Evans 		if (checkvfsname(fs->fs_vfstype, typelist))
2068fae3551SRodney W. Grimes 			continue;
2078fae3551SRodney W. Grimes 
2088fae3551SRodney W. Grimes 		/*
2098fae3551SRodney W. Grimes 		 * We want to unmount the file systems in the reverse order
2108fae3551SRodney W. Grimes 		 * that they were mounted.  So, we save off the file name
2118fae3551SRodney W. Grimes 		 * in some allocated memory, and then call recursively.
2128fae3551SRodney W. Grimes 		 */
2138fae3551SRodney W. Grimes 		if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL)
214bc70c172SBrian Feldman 			err(1, "malloc failed");
2158fae3551SRodney W. Grimes 		(void)strcpy(cp, fs->fs_file);
216d499a0efSBruce Evans 		rval = umountall(typelist);
2178360efbdSAlfred Perlstein 		rval = checkname(cp, typelist) || rval;
218bc70c172SBrian Feldman 		free(cp);
2190602ee7cSBrian Feldman 		return (rval);
2200602ee7cSBrian Feldman 	} while ((fs = getfsent()) != NULL);
2218fae3551SRodney W. Grimes 	return (0);
2228fae3551SRodney W. Grimes }
2238fae3551SRodney W. Grimes 
2248360efbdSAlfred Perlstein /*
225eddb4805SIan Dowse  * Do magic checks on mountpoint/device/fsid, and then call unmount(2).
2268360efbdSAlfred Perlstein  */
2278fae3551SRodney W. Grimes int
2287f471a32SXin LI checkname(char *mntname, char **typelist)
2298fae3551SRodney W. Grimes {
230eddb4805SIan Dowse 	char buf[MAXPATHLEN];
231eddb4805SIan Dowse 	struct statfs sfsbuf;
232eddb4805SIan Dowse 	struct stat sb;
233f73d495fSIan Dowse 	struct statfs *sfs;
234eddb4805SIan Dowse 	char *delimp;
235eddb4805SIan Dowse 	dev_t dev;
236eddb4805SIan Dowse 	int len;
2378fae3551SRodney W. Grimes 
238bc70c172SBrian Feldman 	/*
239bc70c172SBrian Feldman 	 * 1. Check if the name exists in the mounttable.
240bc70c172SBrian Feldman 	 */
2417f471a32SXin LI 	sfs = checkmntlist(mntname);
242bc70c172SBrian Feldman 	/*
243bc70c172SBrian Feldman 	 * 2. Remove trailing slashes if there are any. After that
244bc70c172SBrian Feldman 	 * we look up the name in the mounttable again.
245bc70c172SBrian Feldman 	 */
246318f2fb4SIan Dowse 	if (sfs == NULL) {
2477f471a32SXin LI 		len = strlen(mntname);
2487f471a32SXin LI 		while (len > 1 && mntname[len - 1] == '/')
2497f471a32SXin LI 			mntname[--len] = '\0';
2507f471a32SXin LI 		sfs = checkmntlist(mntname);
251bc70c172SBrian Feldman 	}
252bc70c172SBrian Feldman 	/*
253eddb4805SIan Dowse 	 * 3. Check if the deprecated NFS syntax with an '@' has been used
254eddb4805SIan Dowse 	 * and translate it to the ':' syntax. Look up the name in the
255eddb4805SIan Dowse 	 * mount table again.
256bc70c172SBrian Feldman 	 */
2577f471a32SXin LI 	if (sfs == NULL && (delimp = strrchr(mntname, '@')) != NULL) {
2587f471a32SXin LI 		snprintf(buf, sizeof(buf), "%s:%.*s", delimp + 1,
2597f471a32SXin LI 		    (int)(delimp - mntname), mntname);
260eddb4805SIan Dowse 		len = strlen(buf);
2615fff0914SIan Dowse 		while (len > 1 && buf[len - 1] == '/')
262eddb4805SIan Dowse 			buf[--len] = '\0';
263eddb4805SIan Dowse 		sfs = checkmntlist(buf);
264bc70c172SBrian Feldman 	}
265bc70c172SBrian Feldman 	/*
266eddb4805SIan Dowse 	 * 4. Resort to a statfs(2) call. This is the last check so that
267eddb4805SIan Dowse 	 * hung NFS filesystems for example can be unmounted without
268eddb4805SIan Dowse 	 * potentially blocking forever in statfs() as long as the
269eddb4805SIan Dowse 	 * filesystem is specified unambiguously. This covers all the
270eddb4805SIan Dowse 	 * hard cases such as symlinks and mismatches between the
271eddb4805SIan Dowse 	 * mount list and reality.
272eddb4805SIan Dowse 	 * We also do this if an ambiguous mount point was specified.
273bc70c172SBrian Feldman 	 */
2747f471a32SXin LI 	if (sfs == NULL || (getmntentry(NULL, mntname, NULL, FIND) != NULL &&
2757f471a32SXin LI 	    getmntentry(NULL, mntname, NULL, CHECKUNIQUE) == NULL)) {
2767f471a32SXin LI 		if (statfs(mntname, &sfsbuf) != 0) {
2777f471a32SXin LI 			warn("%s: statfs", mntname);
2787f471a32SXin LI 		} else if (stat(mntname, &sb) != 0) {
2797f471a32SXin LI 			warn("%s: stat", mntname);
280eddb4805SIan Dowse 		} else if (S_ISDIR(sb.st_mode)) {
2817f471a32SXin LI 			/* Check that `mntname' is the root directory. */
282eddb4805SIan Dowse 			dev = sb.st_dev;
2837f471a32SXin LI 			snprintf(buf, sizeof(buf), "%s/..", mntname);
284eddb4805SIan Dowse 			if (stat(buf, &sb) != 0) {
285eddb4805SIan Dowse 				warn("%s: stat", buf);
286eddb4805SIan Dowse 			} else if (sb.st_dev == dev) {
287eddb4805SIan Dowse 				warnx("%s: not a file system root directory",
2887f471a32SXin LI 				    mntname);
289eddb4805SIan Dowse 				return (1);
2908360efbdSAlfred Perlstein 			} else
291eddb4805SIan Dowse 				sfs = &sfsbuf;
292eddb4805SIan Dowse 		}
293eddb4805SIan Dowse 	}
294eddb4805SIan Dowse 	if (sfs == NULL) {
2957f471a32SXin LI 		warnx("%s: unknown file system", mntname);
2968fae3551SRodney W. Grimes 		return (1);
2978fae3551SRodney W. Grimes 	}
2981add162cSIan Dowse 	if (checkvfsname(sfs->f_fstypename, typelist))
299d499a0efSBruce Evans 		return (1);
300eddb4805SIan Dowse 	return (umountfs(sfs));
3018360efbdSAlfred Perlstein }
3028360efbdSAlfred Perlstein 
3038360efbdSAlfred Perlstein /*
3048360efbdSAlfred Perlstein  * NFS stuff and unmount(2) call
3058360efbdSAlfred Perlstein  */
3068360efbdSAlfred Perlstein int
307eddb4805SIan Dowse umountfs(struct statfs *sfs)
3088360efbdSAlfred Perlstein {
309318f2fb4SIan Dowse 	char fsidbuf[64];
3108360efbdSAlfred Perlstein 	enum clnt_stat clnt_stat;
3118360efbdSAlfred Perlstein 	struct timeval try;
3128360efbdSAlfred Perlstein 	struct addrinfo *ai, hints;
3138360efbdSAlfred Perlstein 	int do_rpc;
3148360efbdSAlfred Perlstein 	CLIENT *clp;
3158360efbdSAlfred Perlstein 	char *nfsdirname, *orignfsdirname;
3168360efbdSAlfred Perlstein 	char *hostp, *delimp;
3178360efbdSAlfred Perlstein 
3188360efbdSAlfred Perlstein 	ai = NULL;
31913e2e1afSIan Dowse 	do_rpc = 0;
32013e2e1afSIan Dowse 	hostp = NULL;
3218360efbdSAlfred Perlstein 	nfsdirname = delimp = orignfsdirname = NULL;
3228360efbdSAlfred Perlstein 	memset(&hints, 0, sizeof hints);
3238360efbdSAlfred Perlstein 
324eddb4805SIan Dowse 	if (strcmp(sfs->f_fstypename, "nfs") == 0) {
325eddb4805SIan Dowse 		if ((nfsdirname = strdup(sfs->f_mntfromname)) == NULL)
3268360efbdSAlfred Perlstein 			err(1, "strdup");
3278360efbdSAlfred Perlstein 		orignfsdirname = nfsdirname;
328a505d435SHajimu UMEMOTO 		if (*nfsdirname == '[' &&
329a505d435SHajimu UMEMOTO 		    (delimp = strchr(nfsdirname + 1, ']')) != NULL &&
330a505d435SHajimu UMEMOTO 		    *(delimp + 1) == ':') {
331a505d435SHajimu UMEMOTO 			hostp = nfsdirname + 1;
332a505d435SHajimu UMEMOTO 			nfsdirname = delimp + 2;
333a505d435SHajimu UMEMOTO 		} else if ((delimp = strrchr(nfsdirname, ':')) != NULL) {
3348360efbdSAlfred Perlstein 			hostp = nfsdirname;
335a505d435SHajimu UMEMOTO 			nfsdirname = delimp + 1;
336a505d435SHajimu UMEMOTO 		}
337a505d435SHajimu UMEMOTO 		if (hostp != NULL) {
338a505d435SHajimu UMEMOTO 			*delimp = '\0';
3398360efbdSAlfred Perlstein 			getaddrinfo(hostp, NULL, &hints, &ai);
3408360efbdSAlfred Perlstein 			if (ai == NULL) {
3418360efbdSAlfred Perlstein 				warnx("can't get net id for host");
3428360efbdSAlfred Perlstein 			}
3438360efbdSAlfred Perlstein 		}
34413e2e1afSIan Dowse 
345bc70c172SBrian Feldman 		/*
346bc70c172SBrian Feldman 		 * Check if we have to start the rpc-call later.
347bc70c172SBrian Feldman 		 * If there are still identical nfs-names mounted,
348bc70c172SBrian Feldman 		 * we skip the rpc-call. Obviously this has to
349bc70c172SBrian Feldman 		 * happen before unmount(2), but it should happen
350bc70c172SBrian Feldman 		 * after the previous namecheck.
35113e2e1afSIan Dowse 		 * A non-NULL return means that this is the last
35213e2e1afSIan Dowse 		 * mount from mntfromname that is still mounted.
353bc70c172SBrian Feldman 		 */
354eddb4805SIan Dowse 		if (getmntentry(sfs->f_mntfromname, NULL, NULL,
355eddb4805SIan Dowse 		    CHECKUNIQUE) != NULL)
3560fe9a7daSBrian Feldman 			do_rpc = 1;
35713e2e1afSIan Dowse 	}
3588360efbdSAlfred Perlstein 
3598360efbdSAlfred Perlstein 	if (!namematch(ai))
360d499a0efSBruce Evans 		return (1);
361eddb4805SIan Dowse 	/* First try to unmount using the file system ID. */
362eddb4805SIan Dowse 	snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", sfs->f_fsid.val[0],
363eddb4805SIan Dowse 	    sfs->f_fsid.val[1]);
364318f2fb4SIan Dowse 	if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) {
3650ed25a9aSIan Dowse 		/* XXX, non-root users get a zero fsid, so don't warn. */
3660ed25a9aSIan Dowse 		if (errno != ENOENT || sfs->f_fsid.val[0] != 0 ||
3670ed25a9aSIan Dowse 		    sfs->f_fsid.val[1] != 0)
368eddb4805SIan Dowse 			warn("unmount of %s failed", sfs->f_mntonname);
369318f2fb4SIan Dowse 		if (errno != ENOENT)
370318f2fb4SIan Dowse 			return (1);
3718b918187SIan Dowse 		/* Compatibility for old kernels. */
3728b918187SIan Dowse 		if (sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0)
373318f2fb4SIan Dowse 			warnx("retrying using path instead of file system ID");
374eddb4805SIan Dowse 		if (unmount(sfs->f_mntonname, fflag) != 0) {
375eddb4805SIan Dowse 			warn("unmount of %s failed", sfs->f_mntonname);
3768fae3551SRodney W. Grimes 			return (1);
3778fae3551SRodney W. Grimes 		}
378eddb4805SIan Dowse 	}
379eddb4805SIan Dowse 	/* Mark this this file system as unmounted. */
380eddb4805SIan Dowse 	getmntentry(NULL, NULL, &sfs->f_fsid, REMOVE);
381bc70c172SBrian Feldman 	if (vflag)
382eddb4805SIan Dowse 		(void)printf("%s: unmount from %s\n", sfs->f_mntfromname,
383eddb4805SIan Dowse 		    sfs->f_mntonname);
384bc70c172SBrian Feldman 	/*
385bc70c172SBrian Feldman 	 * Report to mountd-server which nfsname
386bc70c172SBrian Feldman 	 * has been unmounted.
387bc70c172SBrian Feldman 	 */
3888360efbdSAlfred Perlstein 	if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) {
3890775314bSDoug Rabson 		clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS, "udp");
3908360efbdSAlfred Perlstein 		if (clp  == NULL) {
39113e2e1afSIan Dowse 			warnx("%s: %s", hostp,
3920775314bSDoug Rabson 			    clnt_spcreateerror("MOUNTPROG"));
3938fae3551SRodney W. Grimes 			return (1);
3948fae3551SRodney W. Grimes 		}
3958360efbdSAlfred Perlstein 		clp->cl_auth = authsys_create_default();
3968fae3551SRodney W. Grimes 		try.tv_sec = 20;
3978fae3551SRodney W. Grimes 		try.tv_usec = 0;
3980775314bSDoug Rabson 		clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir,
3995c514aeeSMatthew N. Dodd 		    nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try);
4008fae3551SRodney W. Grimes 		if (clnt_stat != RPC_SUCCESS) {
40113e2e1afSIan Dowse 			warnx("%s: %s", hostp,
40213e2e1afSIan Dowse 			    clnt_sperror(clp, "RPCMNT_UMOUNT"));
4038fae3551SRodney W. Grimes 			return (1);
4048fae3551SRodney W. Grimes 		}
405a69497d7SMatthew Dillon 		/*
406a69497d7SMatthew Dillon 		 * Remove the unmounted entry from /var/db/mounttab.
407a69497d7SMatthew Dillon 		 */
408afe1ef24SIan Dowse 		if (read_mtab()) {
409afe1ef24SIan Dowse 			clean_mtab(hostp, nfsdirname, vflag);
410afe1ef24SIan Dowse 			if(!write_mtab(vflag))
41113e2e1afSIan Dowse 				warnx("cannot remove mounttab entry %s:%s",
412a69497d7SMatthew Dillon 				    hostp, nfsdirname);
413a69497d7SMatthew Dillon 			free_mtab();
414a69497d7SMatthew Dillon 		}
415bc70c172SBrian Feldman 		free(orignfsdirname);
4168fae3551SRodney W. Grimes 		auth_destroy(clp->cl_auth);
4178fae3551SRodney W. Grimes 		clnt_destroy(clp);
4188fae3551SRodney W. Grimes 	}
4198fae3551SRodney W. Grimes 	return (0);
4208fae3551SRodney W. Grimes }
4218fae3551SRodney W. Grimes 
422318f2fb4SIan Dowse struct statfs *
423eddb4805SIan Dowse getmntentry(const char *fromname, const char *onname, fsid_t *fsid, dowhat what)
4248fae3551SRodney W. Grimes {
425d499a0efSBruce Evans 	static struct statfs *mntbuf;
426bc70c172SBrian Feldman 	static size_t mntsize = 0;
427bc70c172SBrian Feldman 	static char *mntcheck = NULL;
428eddb4805SIan Dowse 	struct statfs *sfs, *foundsfs;
429bc70c172SBrian Feldman 	int i, count;
4308fae3551SRodney W. Grimes 
431bc70c172SBrian Feldman 	if (mntsize <= 0) {
432bc70c172SBrian Feldman 		if ((mntsize = mntinfo(&mntbuf)) <= 0)
4338fae3551SRodney W. Grimes 			return (NULL);
4348fae3551SRodney W. Grimes 	}
435bc70c172SBrian Feldman 	if (mntcheck == NULL) {
436eddb4805SIan Dowse 		if ((mntcheck = calloc(mntsize + 1, sizeof(int))) == NULL)
437bc70c172SBrian Feldman 			err(1, "calloc");
438bc70c172SBrian Feldman 	}
439bc70c172SBrian Feldman 	/*
440bc70c172SBrian Feldman 	 * We want to get the file systems in the reverse order
441eddb4805SIan Dowse 	 * that they were mounted. Unmounted file systems are marked
442eddb4805SIan Dowse 	 * in a table called 'mntcheck'.
443bc70c172SBrian Feldman 	 */
444eddb4805SIan Dowse 	count = 0;
445eddb4805SIan Dowse 	foundsfs = NULL;
446bc70c172SBrian Feldman 	for (i = mntsize - 1; i >= 0; i--) {
447eddb4805SIan Dowse 		if (mntcheck[i])
448eddb4805SIan Dowse 			continue;
449eddb4805SIan Dowse 		sfs = &mntbuf[i];
450eddb4805SIan Dowse 		if (fromname != NULL && strcmp(sfs->f_mntfromname,
451eddb4805SIan Dowse 		    fromname) != 0)
452eddb4805SIan Dowse 			continue;
453eddb4805SIan Dowse 		if (onname != NULL && strcmp(sfs->f_mntonname, onname) != 0)
454eddb4805SIan Dowse 			continue;
455eddb4805SIan Dowse 		if (fsid != NULL && bcmp(&sfs->f_fsid, fsid,
456eddb4805SIan Dowse 		    sizeof(*fsid)) != 0)
457eddb4805SIan Dowse 			continue;
458eddb4805SIan Dowse 
45938f102c2SIan Dowse 		switch (what) {
460eddb4805SIan Dowse 		case CHECKUNIQUE:
461eddb4805SIan Dowse 			foundsfs = sfs;
462eddb4805SIan Dowse 			count++;
46338f102c2SIan Dowse 			continue;
464eddb4805SIan Dowse 		case REMOVE:
465eddb4805SIan Dowse 			mntcheck[i] = 1;
46638f102c2SIan Dowse 			break;
467eddb4805SIan Dowse 		default:
46838f102c2SIan Dowse 			break;
46938f102c2SIan Dowse 		}
470eddb4805SIan Dowse 		return (sfs);
4718fae3551SRodney W. Grimes 	}
472318f2fb4SIan Dowse 
473eddb4805SIan Dowse 	if (what == CHECKUNIQUE && count == 1)
474eddb4805SIan Dowse 		return (foundsfs);
4758fae3551SRodney W. Grimes 	return (NULL);
4768fae3551SRodney W. Grimes }
4778fae3551SRodney W. Grimes 
4788fae3551SRodney W. Grimes int
4797f471a32SXin LI sacmp(void *sa1, void *sa2)
4808fae3551SRodney W. Grimes {
4818360efbdSAlfred Perlstein 	void *p1, *p2;
4828360efbdSAlfred Perlstein 	int len;
4838fae3551SRodney W. Grimes 
4847f471a32SXin LI 	if (((struct sockaddr *)sa1)->sa_family !=
4857f471a32SXin LI 	    ((struct sockaddr *)sa2)->sa_family)
4868fae3551SRodney W. Grimes 		return (1);
4878fae3551SRodney W. Grimes 
4887f471a32SXin LI 	switch (((struct sockaddr *)sa1)->sa_family) {
4898360efbdSAlfred Perlstein 	case AF_INET:
4908360efbdSAlfred Perlstein 		p1 = &((struct sockaddr_in *)sa1)->sin_addr;
4918360efbdSAlfred Perlstein 		p2 = &((struct sockaddr_in *)sa2)->sin_addr;
4928360efbdSAlfred Perlstein 		len = 4;
4938360efbdSAlfred Perlstein 		break;
4948360efbdSAlfred Perlstein 	case AF_INET6:
4958360efbdSAlfred Perlstein 		p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
4968360efbdSAlfred Perlstein 		p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
4978360efbdSAlfred Perlstein 		len = 16;
4988360efbdSAlfred Perlstein 		if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
4998360efbdSAlfred Perlstein 		    ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
5008360efbdSAlfred Perlstein 			return (1);
5018360efbdSAlfred Perlstein 		break;
5028360efbdSAlfred Perlstein 	default:
5038360efbdSAlfred Perlstein 		return (1);
5048360efbdSAlfred Perlstein 	}
5058360efbdSAlfred Perlstein 
5068360efbdSAlfred Perlstein 	return memcmp(p1, p2, len);
5078360efbdSAlfred Perlstein }
5088360efbdSAlfred Perlstein 
5098360efbdSAlfred Perlstein int
5108360efbdSAlfred Perlstein namematch(struct addrinfo *ai)
5118360efbdSAlfred Perlstein {
5128360efbdSAlfred Perlstein 	struct addrinfo *aip;
5138360efbdSAlfred Perlstein 
5148360efbdSAlfred Perlstein 	if (nfshost == NULL || nfshost_ai == NULL)
5158fae3551SRodney W. Grimes 		return (1);
5168fae3551SRodney W. Grimes 
5178360efbdSAlfred Perlstein 	while (ai != NULL) {
5188360efbdSAlfred Perlstein 		aip = nfshost_ai;
5198360efbdSAlfred Perlstein 		while (aip != NULL) {
5208360efbdSAlfred Perlstein 			if (sacmp(ai->ai_addr, aip->ai_addr) == 0)
5218fae3551SRodney W. Grimes 				return (1);
5228360efbdSAlfred Perlstein 			aip = aip->ai_next;
5238fae3551SRodney W. Grimes 		}
5248360efbdSAlfred Perlstein 		ai = ai->ai_next;
5258fae3551SRodney W. Grimes 	}
5268360efbdSAlfred Perlstein 
5278fae3551SRodney W. Grimes 	return (0);
5288fae3551SRodney W. Grimes }
5298fae3551SRodney W. Grimes 
530318f2fb4SIan Dowse struct statfs *
5317f471a32SXin LI checkmntlist(char *mntname)
532bc70c172SBrian Feldman {
533318f2fb4SIan Dowse 	struct statfs *sfs;
534eddb4805SIan Dowse 	fsid_t fsid;
535bc70c172SBrian Feldman 
536eddb4805SIan Dowse 	sfs = NULL;
5377f471a32SXin LI 	if (parsehexfsid(mntname, &fsid) == 0)
538eddb4805SIan Dowse 		sfs = getmntentry(NULL, NULL, &fsid, FIND);
53938f102c2SIan Dowse 	if (sfs == NULL)
5407f471a32SXin LI 		sfs = getmntentry(NULL, mntname, NULL, FIND);
541318f2fb4SIan Dowse 	if (sfs == NULL)
5427f471a32SXin LI 		sfs = getmntentry(mntname, NULL, NULL, FIND);
543318f2fb4SIan Dowse 	return (sfs);
544bc70c172SBrian Feldman }
545bc70c172SBrian Feldman 
546bc70c172SBrian Feldman size_t
547bc70c172SBrian Feldman mntinfo(struct statfs **mntbuf)
548bc70c172SBrian Feldman {
549bc70c172SBrian Feldman 	static struct statfs *origbuf;
550bc70c172SBrian Feldman 	size_t bufsize;
551bc70c172SBrian Feldman 	int mntsize;
552bc70c172SBrian Feldman 
553a69497d7SMatthew Dillon 	mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
554bc70c172SBrian Feldman 	if (mntsize <= 0)
555bc70c172SBrian Feldman 		return (0);
556bc70c172SBrian Feldman 	bufsize = (mntsize + 1) * sizeof(struct statfs);
557bc70c172SBrian Feldman 	if ((origbuf = malloc(bufsize)) == NULL)
558bc70c172SBrian Feldman 		err(1, "malloc");
559bc70c172SBrian Feldman 	mntsize = getfsstat(origbuf, (long)bufsize, MNT_NOWAIT);
560bc70c172SBrian Feldman 	*mntbuf = origbuf;
561bc70c172SBrian Feldman 	return (mntsize);
562bc70c172SBrian Feldman }
563bc70c172SBrian Feldman 
564eddb4805SIan Dowse /*
5658b918187SIan Dowse  * Convert a hexadecimal filesystem ID to an fsid_t.
566eddb4805SIan Dowse  * Returns 0 on success.
567eddb4805SIan Dowse  */
568eddb4805SIan Dowse int
569eddb4805SIan Dowse parsehexfsid(const char *hex, fsid_t *fsid)
570bc70c172SBrian Feldman {
571eddb4805SIan Dowse 	char hexbuf[3];
572eddb4805SIan Dowse 	int i;
573bc70c172SBrian Feldman 
574eddb4805SIan Dowse 	if (strlen(hex) != sizeof(*fsid) * 2)
575eddb4805SIan Dowse 		return (-1);
576eddb4805SIan Dowse 	hexbuf[2] = '\0';
5775fff0914SIan Dowse 	for (i = 0; i < (int)sizeof(*fsid); i++) {
578eddb4805SIan Dowse 		hexbuf[0] = hex[i * 2];
579eddb4805SIan Dowse 		hexbuf[1] = hex[i * 2 + 1];
580eddb4805SIan Dowse 		if (!isxdigit(hexbuf[0]) || !isxdigit(hexbuf[1]))
581eddb4805SIan Dowse 			return (-1);
582eddb4805SIan Dowse 		((u_char *)fsid)[i] = strtol(hexbuf, NULL, 16);
583bc70c172SBrian Feldman 	}
584eddb4805SIan Dowse 	return (0);
585bc70c172SBrian Feldman }
586bc70c172SBrian Feldman 
5878fae3551SRodney W. Grimes /*
5888fae3551SRodney W. Grimes  * xdr routines for mount rpc's
5898fae3551SRodney W. Grimes  */
5908fae3551SRodney W. Grimes int
591bc70c172SBrian Feldman xdr_dir(XDR *xdrsp, char *dirp)
5928fae3551SRodney W. Grimes {
593bc70c172SBrian Feldman 
5940775314bSDoug Rabson 	return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
5958fae3551SRodney W. Grimes }
5968fae3551SRodney W. Grimes 
5978fae3551SRodney W. Grimes void
598ca25fa25SEd Schouten usage(void)
5998fae3551SRodney W. Grimes {
600bc70c172SBrian Feldman 
601210a5dc8SPhilippe Charnier 	(void)fprintf(stderr, "%s\n%s\n",
6028d646af5SRuslan Ermilov 	    "usage: umount [-fv] special | node | fsid",
603ef258dd9SMatthew N. Dodd 	    "       umount -a | -A [-F fstab] [-fv] [-h host] [-t type]");
6048fae3551SRodney W. Grimes 	exit(1);
6058fae3551SRodney W. Grimes }
606