11558Srgrimes/*-
21558Srgrimes * Copyright (c) 1980, 1989, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
131558Srgrimes * 4. Neither the name of the University nor the names of its contributors
141558Srgrimes *    may be used to endorse or promote products derived from this software
151558Srgrimes *    without specific prior written permission.
161558Srgrimes *
171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271558Srgrimes * SUCH DAMAGE.
281558Srgrimes */
291558Srgrimes
301558Srgrimes#ifndef lint
3138041Scharnierstatic const char copyright[] =
321558Srgrimes"@(#) Copyright (c) 1980, 1989, 1993\n\
331558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
341558Srgrimes#endif /* not lint */
351558Srgrimes
361558Srgrimes#ifndef lint
3738041Scharnier#if 0
3826683Sbdestatic char sccsid[] = "@(#)umount.c	8.8 (Berkeley) 5/8/95";
3938041Scharnier#endif
4038041Scharnierstatic const char rcsid[] =
4150476Speter  "$FreeBSD$";
421558Srgrimes#endif /* not lint */
431558Srgrimes
441558Srgrimes#include <sys/param.h>
451558Srgrimes#include <sys/mount.h>
4674462Salfred#include <sys/socket.h>
47117794Siedowse#include <sys/stat.h>
481558Srgrimes
491558Srgrimes#include <netdb.h>
501558Srgrimes#include <rpc/rpc.h>
51194880Sdfr#include <rpcsvc/mount.h>
521558Srgrimes
53117742Siedowse#include <ctype.h>
541558Srgrimes#include <err.h>
55117132Siedowse#include <errno.h>
561558Srgrimes#include <fstab.h>
571558Srgrimes#include <stdio.h>
581558Srgrimes#include <stdlib.h>
591558Srgrimes#include <string.h>
601558Srgrimes#include <unistd.h>
611558Srgrimes
6253550Sdillon#include "mounttab.h"
6353550Sdillon
64117794Siedowsetypedef enum { FIND, REMOVE, CHECKUNIQUE } dowhat;
651558Srgrimes
66227081Sedstatic struct addrinfo *nfshost_ai = NULL;
67227081Sedstatic int	fflag, vflag;
68227081Sedstatic char	*nfshost;
691558Srgrimes
70117720Siedowsestruct statfs *checkmntlist(char *);
7152340Sgreenint	 checkvfsname (const char *, char **);
72117794Siedowsestruct statfs *getmntentry(const char *fromname, const char *onname,
73117794Siedowse	     fsid_t *fsid, dowhat what);
7452340Sgreenchar   **makevfslist (const char *);
7552340Sgreensize_t	 mntinfo (struct statfs **);
7674462Salfredint	 namematch (struct addrinfo *);
77117794Siedowseint	 parsehexfsid(const char *hex, fsid_t *fsid);
78201135Sdelphijint	 sacmp (void *, void *);
7952340Sgreenint	 umountall (char **);
8074462Salfredint	 checkname (char *, char **);
81117794Siedowseint	 umountfs(struct statfs *sfs);
8252340Sgreenvoid	 usage (void);
8352340Sgreenint	 xdr_dir (XDR *, char *);
8452340Sgreen
851558Srgrimesint
8652340Sgreenmain(int argc, char *argv[])
871558Srgrimes{
8874462Salfred	int all, errs, ch, mntsize, error;
89117712Siedowse	char **typelist = NULL;
90117712Siedowse	struct statfs *mntbuf, *sfs;
9174462Salfred	struct addrinfo hints;
921558Srgrimes
9352440Sgreen	all = errs = 0;
94113220Smdodd	while ((ch = getopt(argc, argv, "AaF:fh:t:v")) != -1)
951558Srgrimes		switch (ch) {
9626683Sbde		case 'A':
9726683Sbde			all = 2;
9826683Sbde			break;
991558Srgrimes		case 'a':
1001558Srgrimes			all = 1;
1011558Srgrimes			break;
102113220Smdodd		case 'F':
103113220Smdodd			setfstab(optarg);
104113220Smdodd			break;
1051558Srgrimes		case 'f':
1061558Srgrimes			fflag = MNT_FORCE;
1071558Srgrimes			break;
10826683Sbde		case 'h':	/* -h implies -A. */
10926683Sbde			all = 2;
1101558Srgrimes			nfshost = optarg;
1111558Srgrimes			break;
1121558Srgrimes		case 't':
11326683Sbde			if (typelist != NULL)
11452340Sgreen				err(1, "only one -t option may be specified");
11526683Sbde			typelist = makevfslist(optarg);
1161558Srgrimes			break;
1171558Srgrimes		case 'v':
1181558Srgrimes			vflag = 1;
1191558Srgrimes			break;
1201558Srgrimes		default:
1211558Srgrimes			usage();
1221558Srgrimes			/* NOTREACHED */
1231558Srgrimes		}
1241558Srgrimes	argc -= optind;
1251558Srgrimes	argv += optind;
1261558Srgrimes
127222466Srmacklem	/* Start disks transferring immediately. */
128222466Srmacklem	if ((fflag & MNT_FORCE) == 0)
129222466Srmacklem		sync();
130222466Srmacklem
13138041Scharnier	if ((argc == 0 && !all) || (argc != 0 && all))
1321558Srgrimes		usage();
1331558Srgrimes
1341558Srgrimes	/* -h implies "-t nfs" if no -t flag. */
1351558Srgrimes	if ((nfshost != NULL) && (typelist == NULL))
13626683Sbde		typelist = makevfslist("nfs");
1378871Srgrimes
13874462Salfred	if (nfshost != NULL) {
13974462Salfred		memset(&hints, 0, sizeof hints);
14074462Salfred		error = getaddrinfo(nfshost, NULL, &hints, &nfshost_ai);
14184868Siedowse		if (error)
14284868Siedowse			errx(1, "%s: %s", nfshost, gai_strerror(error));
14374462Salfred	}
14474462Salfred
14526683Sbde	switch (all) {
14626683Sbde	case 2:
14752340Sgreen		if ((mntsize = mntinfo(&mntbuf)) <= 0)
14826683Sbde			break;
14952340Sgreen		/*
15052340Sgreen		 * We unmount the nfs-mounts in the reverse order
15152340Sgreen		 * that they were mounted.
15252340Sgreen		 */
15352340Sgreen		for (errs = 0, mntsize--; mntsize > 0; mntsize--) {
154117712Siedowse			sfs = &mntbuf[mntsize];
155117712Siedowse			if (checkvfsname(sfs->f_fstypename, typelist))
15626683Sbde				continue;
157224040Smckusick			if (strcmp(sfs->f_mntonname, "/dev") == 0)
158224040Smckusick				continue;
159117794Siedowse			if (umountfs(sfs) != 0)
16026683Sbde				errs = 1;
16126683Sbde		}
16252340Sgreen		free(mntbuf);
16326683Sbde		break;
16426683Sbde	case 1:
1651558Srgrimes		if (setfsent() == 0)
166113220Smdodd			err(1, "%s", getfstab());
16726683Sbde		errs = umountall(typelist);
16826683Sbde		break;
16926683Sbde	case 0:
1701558Srgrimes		for (errs = 0; *argv != NULL; ++argv)
17174462Salfred			if (checkname(*argv, typelist) != 0)
17226683Sbde				errs = 1;
17326683Sbde		break;
17426683Sbde	}
1751558Srgrimes	exit(errs);
1761558Srgrimes}
1771558Srgrimes
1781558Srgrimesint
17952340Sgreenumountall(char **typelist)
1801558Srgrimes{
181101651Smux	struct xvfsconf vfc;
1821558Srgrimes	struct fstab *fs;
18338041Scharnier	int rval;
1841558Srgrimes	char *cp;
18552374Sgreen	static int firstcall = 1;
1861558Srgrimes
18752622Sgreen	if ((fs = getfsent()) != NULL)
18852374Sgreen		firstcall = 0;
18952622Sgreen	else if (firstcall)
19052622Sgreen		errx(1, "fstab reading failure");
19152622Sgreen	else
19252622Sgreen		return (0);
19352340Sgreen	do {
1941558Srgrimes		/* Ignore the root. */
1951558Srgrimes		if (strcmp(fs->fs_file, "/") == 0)
1961558Srgrimes			continue;
1971558Srgrimes		/*
1981558Srgrimes		 * !!!
1991558Srgrimes		 * Historic practice: ignore unknown FSTAB_* fields.
2001558Srgrimes		 */
2011558Srgrimes		if (strcmp(fs->fs_type, FSTAB_RW) &&
2021558Srgrimes		    strcmp(fs->fs_type, FSTAB_RO) &&
2031558Srgrimes		    strcmp(fs->fs_type, FSTAB_RQ))
2041558Srgrimes			continue;
205102231Strhodes		/* Ignore unknown file system types. */
20665525Sdes		if (getvfsbyname(fs->fs_vfstype, &vfc) == -1)
2071558Srgrimes			continue;
20826683Sbde		if (checkvfsname(fs->fs_vfstype, typelist))
2091558Srgrimes			continue;
2101558Srgrimes
2118871Srgrimes		/*
212102231Strhodes		 * We want to unmount the file systems in the reverse order
2131558Srgrimes		 * that they were mounted.  So, we save off the file name
2141558Srgrimes		 * in some allocated memory, and then call recursively.
2151558Srgrimes		 */
2161558Srgrimes		if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL)
21752340Sgreen			err(1, "malloc failed");
2181558Srgrimes		(void)strcpy(cp, fs->fs_file);
21926683Sbde		rval = umountall(typelist);
22074462Salfred		rval = checkname(cp, typelist) || rval;
22152374Sgreen		free(cp);
22252374Sgreen		return (rval);
22352340Sgreen	} while ((fs = getfsent()) != NULL);
2241558Srgrimes	return (0);
2251558Srgrimes}
2261558Srgrimes
22774462Salfred/*
228117794Siedowse * Do magic checks on mountpoint/device/fsid, and then call unmount(2).
22974462Salfred */
2301558Srgrimesint
231201135Sdelphijcheckname(char *mntname, char **typelist)
2321558Srgrimes{
233117794Siedowse	char buf[MAXPATHLEN];
234117794Siedowse	struct statfs sfsbuf;
235117794Siedowse	struct stat sb;
236117712Siedowse	struct statfs *sfs;
237117794Siedowse	char *delimp;
238117794Siedowse	dev_t dev;
239117794Siedowse	int len;
2401558Srgrimes
24152340Sgreen	/*
24252340Sgreen	 * 1. Check if the name exists in the mounttable.
24352340Sgreen	 */
244201135Sdelphij	sfs = checkmntlist(mntname);
24552340Sgreen	/*
24652340Sgreen	 * 2. Remove trailing slashes if there are any. After that
24752340Sgreen	 * we look up the name in the mounttable again.
24852340Sgreen	 */
249117132Siedowse	if (sfs == NULL) {
250201135Sdelphij		len = strlen(mntname);
251201135Sdelphij		while (len > 1 && mntname[len - 1] == '/')
252201135Sdelphij			mntname[--len] = '\0';
253201135Sdelphij		sfs = checkmntlist(mntname);
254117794Siedowse	}
255117794Siedowse	/*
256117794Siedowse	 * 3. Check if the deprecated NFS syntax with an '@' has been used
257117794Siedowse	 * and translate it to the ':' syntax. Look up the name in the
258117794Siedowse	 * mount table again.
259117794Siedowse	 */
260201135Sdelphij	if (sfs == NULL && (delimp = strrchr(mntname, '@')) != NULL) {
261201135Sdelphij		snprintf(buf, sizeof(buf), "%s:%.*s", delimp + 1,
262201135Sdelphij		    (int)(delimp - mntname), mntname);
263117794Siedowse		len = strlen(buf);
264121692Siedowse		while (len > 1 && buf[len - 1] == '/')
265117794Siedowse			buf[--len] = '\0';
266117794Siedowse		sfs = checkmntlist(buf);
267117794Siedowse	}
268117794Siedowse	/*
269117794Siedowse	 * 4. Resort to a statfs(2) call. This is the last check so that
270117794Siedowse	 * hung NFS filesystems for example can be unmounted without
271117794Siedowse	 * potentially blocking forever in statfs() as long as the
272117794Siedowse	 * filesystem is specified unambiguously. This covers all the
273117794Siedowse	 * hard cases such as symlinks and mismatches between the
274117794Siedowse	 * mount list and reality.
275117794Siedowse	 * We also do this if an ambiguous mount point was specified.
276117794Siedowse	 */
277201135Sdelphij	if (sfs == NULL || (getmntentry(NULL, mntname, NULL, FIND) != NULL &&
278201135Sdelphij	    getmntentry(NULL, mntname, NULL, CHECKUNIQUE) == NULL)) {
279201135Sdelphij		if (statfs(mntname, &sfsbuf) != 0) {
280201135Sdelphij			warn("%s: statfs", mntname);
281201135Sdelphij		} else if (stat(mntname, &sb) != 0) {
282201135Sdelphij			warn("%s: stat", mntname);
283117794Siedowse		} else if (S_ISDIR(sb.st_mode)) {
284201135Sdelphij			/* Check that `mntname' is the root directory. */
285117794Siedowse			dev = sb.st_dev;
286201135Sdelphij			snprintf(buf, sizeof(buf), "%s/..", mntname);
287117794Siedowse			if (stat(buf, &sb) != 0) {
288117794Siedowse				warn("%s: stat", buf);
289117794Siedowse			} else if (sb.st_dev == dev) {
290117794Siedowse				warnx("%s: not a file system root directory",
291201135Sdelphij				    mntname);
292117794Siedowse				return (1);
293117794Siedowse			} else
294117794Siedowse				sfs = &sfsbuf;
2951558Srgrimes		}
296117794Siedowse	}
297117794Siedowse	if (sfs == NULL) {
298201135Sdelphij		warnx("%s: unknown file system", mntname);
299117794Siedowse		return (1);
300117794Siedowse	}
301117720Siedowse	if (checkvfsname(sfs->f_fstypename, typelist))
30226683Sbde		return (1);
303117794Siedowse	return (umountfs(sfs));
30474462Salfred}
30574462Salfred
30674462Salfred/*
30774462Salfred * NFS stuff and unmount(2) call
30874462Salfred */
30974462Salfredint
310117794Siedowseumountfs(struct statfs *sfs)
31174462Salfred{
312117132Siedowse	char fsidbuf[64];
31374462Salfred	enum clnt_stat clnt_stat;
31474462Salfred	struct timeval try;
31574462Salfred	struct addrinfo *ai, hints;
31674462Salfred	int do_rpc;
31774462Salfred	CLIENT *clp;
31874462Salfred	char *nfsdirname, *orignfsdirname;
31974462Salfred	char *hostp, *delimp;
32074462Salfred
32174462Salfred	ai = NULL;
32280118Siedowse	do_rpc = 0;
32380118Siedowse	hostp = NULL;
32474462Salfred	nfsdirname = delimp = orignfsdirname = NULL;
32574462Salfred	memset(&hints, 0, sizeof hints);
32674462Salfred
327117794Siedowse	if (strcmp(sfs->f_fstypename, "nfs") == 0) {
328117794Siedowse		if ((nfsdirname = strdup(sfs->f_mntfromname)) == NULL)
32974462Salfred			err(1, "strdup");
33074462Salfred		orignfsdirname = nfsdirname;
331203490Sume		if (*nfsdirname == '[' &&
332203490Sume		    (delimp = strchr(nfsdirname + 1, ']')) != NULL &&
333203490Sume		    *(delimp + 1) == ':') {
334203490Sume			hostp = nfsdirname + 1;
335203490Sume			nfsdirname = delimp + 2;
336203490Sume		} else if ((delimp = strrchr(nfsdirname, ':')) != NULL) {
337203490Sume			hostp = nfsdirname;
338203490Sume			nfsdirname = delimp + 1;
339203490Sume		}
340203490Sume		if (hostp != NULL) {
34174462Salfred			*delimp = '\0';
34274462Salfred			getaddrinfo(hostp, NULL, &hints, &ai);
34374462Salfred			if (ai == NULL) {
34474462Salfred				warnx("can't get net id for host");
34574462Salfred			}
34674462Salfred		}
34780118Siedowse
34880118Siedowse		/*
34980118Siedowse		 * Check if we have to start the rpc-call later.
35080118Siedowse		 * If there are still identical nfs-names mounted,
35180118Siedowse		 * we skip the rpc-call. Obviously this has to
35280118Siedowse		 * happen before unmount(2), but it should happen
35380118Siedowse		 * after the previous namecheck.
35480118Siedowse		 * A non-NULL return means that this is the last
35580118Siedowse		 * mount from mntfromname that is still mounted.
35680118Siedowse		 */
357117794Siedowse		if (getmntentry(sfs->f_mntfromname, NULL, NULL,
358117794Siedowse		    CHECKUNIQUE) != NULL)
35980118Siedowse			do_rpc = 1;
36074462Salfred	}
36174462Salfred
362243082Seadler	if (!namematch(ai)) {
363243082Seadler		free(orignfsdirname);
36426683Sbde		return (1);
365243082Seadler	}
366117794Siedowse	/* First try to unmount using the file system ID. */
367117794Siedowse	snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", sfs->f_fsid.val[0],
368117794Siedowse	    sfs->f_fsid.val[1]);
369117794Siedowse	if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) {
370122804Siedowse		/* XXX, non-root users get a zero fsid, so don't warn. */
371122804Siedowse		if (errno != ENOENT || sfs->f_fsid.val[0] != 0 ||
372122804Siedowse		    sfs->f_fsid.val[1] != 0)
373122804Siedowse			warn("unmount of %s failed", sfs->f_mntonname);
374243082Seadler		if (errno != ENOENT) {
375243082Seadler			free(orignfsdirname);
376117794Siedowse			return (1);
377243082Seadler		}
378123160Siedowse		/* Compatibility for old kernels. */
379123160Siedowse		if (sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0)
380123160Siedowse			warnx("retrying using path instead of file system ID");
381117794Siedowse		if (unmount(sfs->f_mntonname, fflag) != 0) {
382117794Siedowse			warn("unmount of %s failed", sfs->f_mntonname);
383243082Seadler			free(orignfsdirname);
384117794Siedowse			return (1);
385117132Siedowse		}
386117132Siedowse	}
387117794Siedowse	/* Mark this this file system as unmounted. */
388117794Siedowse	getmntentry(NULL, NULL, &sfs->f_fsid, REMOVE);
38952340Sgreen	if (vflag)
390117794Siedowse		(void)printf("%s: unmount from %s\n", sfs->f_mntfromname,
391117794Siedowse		    sfs->f_mntonname);
39252340Sgreen	/*
39352340Sgreen	 * Report to mountd-server which nfsname
39452340Sgreen	 * has been unmounted.
39552340Sgreen	 */
39674462Salfred	if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) {
397270258Speter		clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS3, "udp");
39874462Salfred		if (clp  == NULL) {
39980118Siedowse			warnx("%s: %s", hostp,
400194880Sdfr			    clnt_spcreateerror("MOUNTPROG"));
401243082Seadler			free(orignfsdirname);
4021558Srgrimes			return (1);
4031558Srgrimes		}
40474462Salfred		clp->cl_auth = authsys_create_default();
4051558Srgrimes		try.tv_sec = 20;
4061558Srgrimes		try.tv_usec = 0;
407194880Sdfr		clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir,
408113216Smdodd		    nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try);
4091558Srgrimes		if (clnt_stat != RPC_SUCCESS) {
41080118Siedowse			warnx("%s: %s", hostp,
41180118Siedowse			    clnt_sperror(clp, "RPCMNT_UMOUNT"));
412243082Seadler			free(orignfsdirname);
4131558Srgrimes			return (1);
4141558Srgrimes		}
41553550Sdillon		/*
41653550Sdillon		 * Remove the unmounted entry from /var/db/mounttab.
41753550Sdillon		 */
41880146Siedowse		if (read_mtab()) {
41980146Siedowse			clean_mtab(hostp, nfsdirname, vflag);
42080146Siedowse			if(!write_mtab(vflag))
42180118Siedowse				warnx("cannot remove mounttab entry %s:%s",
42253550Sdillon				    hostp, nfsdirname);
42353550Sdillon			free_mtab();
42453550Sdillon		}
4251558Srgrimes		auth_destroy(clp->cl_auth);
4261558Srgrimes		clnt_destroy(clp);
4271558Srgrimes	}
428243082Seadler	free(orignfsdirname);
4291558Srgrimes	return (0);
4301558Srgrimes}
4311558Srgrimes
432117132Siedowsestruct statfs *
433117794Siedowsegetmntentry(const char *fromname, const char *onname, fsid_t *fsid, dowhat what)
4341558Srgrimes{
43526683Sbde	static struct statfs *mntbuf;
43652340Sgreen	static size_t mntsize = 0;
43752340Sgreen	static char *mntcheck = NULL;
438117794Siedowse	struct statfs *sfs, *foundsfs;
43952340Sgreen	int i, count;
4401558Srgrimes
44152340Sgreen	if (mntsize <= 0) {
44252340Sgreen		if ((mntsize = mntinfo(&mntbuf)) <= 0)
44352340Sgreen			return (NULL);
4441558Srgrimes	}
44552340Sgreen	if (mntcheck == NULL) {
446117794Siedowse		if ((mntcheck = calloc(mntsize + 1, sizeof(int))) == NULL)
44752340Sgreen			err(1, "calloc");
44852340Sgreen	}
44952340Sgreen	/*
450102231Strhodes	 * We want to get the file systems in the reverse order
451117794Siedowse	 * that they were mounted. Unmounted file systems are marked
452117794Siedowse	 * in a table called 'mntcheck'.
45352340Sgreen	 */
454117794Siedowse	count = 0;
455117794Siedowse	foundsfs = NULL;
456117794Siedowse	for (i = mntsize - 1; i >= 0; i--) {
457117794Siedowse		if (mntcheck[i])
458117794Siedowse			continue;
459117794Siedowse		sfs = &mntbuf[i];
460117794Siedowse		if (fromname != NULL && strcmp(sfs->f_mntfromname,
461117794Siedowse		    fromname) != 0)
462117794Siedowse			continue;
463117794Siedowse		if (onname != NULL && strcmp(sfs->f_mntonname, onname) != 0)
464117794Siedowse			continue;
465117794Siedowse		if (fsid != NULL && bcmp(&sfs->f_fsid, fsid,
466117794Siedowse		    sizeof(*fsid)) != 0)
467117794Siedowse			continue;
468117132Siedowse
469117794Siedowse		switch (what) {
470117794Siedowse		case CHECKUNIQUE:
471117794Siedowse			foundsfs = sfs;
472117794Siedowse			count++;
473117794Siedowse			continue;
474117794Siedowse		case REMOVE:
475117794Siedowse			mntcheck[i] = 1;
476117794Siedowse			break;
477117794Siedowse		default:
478117794Siedowse			break;
4791558Srgrimes		}
480117794Siedowse		return (sfs);
4811558Srgrimes	}
482117794Siedowse
483117794Siedowse	if (what == CHECKUNIQUE && count == 1)
484117794Siedowse		return (foundsfs);
485117794Siedowse	return (NULL);
4861558Srgrimes}
4871558Srgrimes
4881558Srgrimesint
489201135Sdelphijsacmp(void *sa1, void *sa2)
4901558Srgrimes{
49174462Salfred	void *p1, *p2;
49274462Salfred	int len;
4931558Srgrimes
494201135Sdelphij	if (((struct sockaddr *)sa1)->sa_family !=
495201135Sdelphij	    ((struct sockaddr *)sa2)->sa_family)
4961558Srgrimes		return (1);
4971558Srgrimes
498201135Sdelphij	switch (((struct sockaddr *)sa1)->sa_family) {
49974462Salfred	case AF_INET:
50074462Salfred		p1 = &((struct sockaddr_in *)sa1)->sin_addr;
50174462Salfred		p2 = &((struct sockaddr_in *)sa2)->sin_addr;
50274462Salfred		len = 4;
50374462Salfred		break;
50474462Salfred	case AF_INET6:
50574462Salfred		p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
50674462Salfred		p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
50774462Salfred		len = 16;
50874462Salfred		if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
50974462Salfred		    ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
51074462Salfred			return (1);
51174462Salfred		break;
51274462Salfred	default:
5131558Srgrimes		return (1);
51474462Salfred	}
5151558Srgrimes
51674462Salfred	return memcmp(p1, p2, len);
51774462Salfred}
51874462Salfred
51974462Salfredint
52074462Salfrednamematch(struct addrinfo *ai)
52174462Salfred{
52274462Salfred	struct addrinfo *aip;
52374462Salfred
52474462Salfred	if (nfshost == NULL || nfshost_ai == NULL)
52574462Salfred		return (1);
52674462Salfred
52774462Salfred	while (ai != NULL) {
52874462Salfred		aip = nfshost_ai;
52974462Salfred		while (aip != NULL) {
53074462Salfred			if (sacmp(ai->ai_addr, aip->ai_addr) == 0)
5311558Srgrimes				return (1);
53274462Salfred			aip = aip->ai_next;
5331558Srgrimes		}
53474462Salfred		ai = ai->ai_next;
5351558Srgrimes	}
53674462Salfred
5371558Srgrimes	return (0);
5381558Srgrimes}
5391558Srgrimes
540117132Siedowsestruct statfs *
541201135Sdelphijcheckmntlist(char *mntname)
54252340Sgreen{
543117132Siedowse	struct statfs *sfs;
544117794Siedowse	fsid_t fsid;
54552340Sgreen
546117794Siedowse	sfs = NULL;
547201135Sdelphij	if (parsehexfsid(mntname, &fsid) == 0)
548117794Siedowse		sfs = getmntentry(NULL, NULL, &fsid, FIND);
549117132Siedowse	if (sfs == NULL)
550201135Sdelphij		sfs = getmntentry(NULL, mntname, NULL, FIND);
551117742Siedowse	if (sfs == NULL)
552201135Sdelphij		sfs = getmntentry(mntname, NULL, NULL, FIND);
553117132Siedowse	return (sfs);
55452340Sgreen}
55552340Sgreen
55652340Sgreensize_t
55752340Sgreenmntinfo(struct statfs **mntbuf)
55852340Sgreen{
55952340Sgreen	static struct statfs *origbuf;
56052340Sgreen	size_t bufsize;
56152340Sgreen	int mntsize;
56252340Sgreen
56353550Sdillon	mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
56452340Sgreen	if (mntsize <= 0)
56552340Sgreen		return (0);
56652340Sgreen	bufsize = (mntsize + 1) * sizeof(struct statfs);
56752340Sgreen	if ((origbuf = malloc(bufsize)) == NULL)
56852340Sgreen		err(1, "malloc");
56952340Sgreen	mntsize = getfsstat(origbuf, (long)bufsize, MNT_NOWAIT);
57052340Sgreen	*mntbuf = origbuf;
57152340Sgreen	return (mntsize);
57252340Sgreen}
57352340Sgreen
574117794Siedowse/*
575123160Siedowse * Convert a hexadecimal filesystem ID to an fsid_t.
576117794Siedowse * Returns 0 on success.
577117794Siedowse */
578117794Siedowseint
579117794Siedowseparsehexfsid(const char *hex, fsid_t *fsid)
58052340Sgreen{
581117794Siedowse	char hexbuf[3];
582117794Siedowse	int i;
583117794Siedowse
584117794Siedowse	if (strlen(hex) != sizeof(*fsid) * 2)
585117794Siedowse		return (-1);
586117794Siedowse	hexbuf[2] = '\0';
587121692Siedowse	for (i = 0; i < (int)sizeof(*fsid); i++) {
588117794Siedowse		hexbuf[0] = hex[i * 2];
589117794Siedowse		hexbuf[1] = hex[i * 2 + 1];
590117794Siedowse		if (!isxdigit(hexbuf[0]) || !isxdigit(hexbuf[1]))
591117794Siedowse			return (-1);
592117794Siedowse		((u_char *)fsid)[i] = strtol(hexbuf, NULL, 16);
59352340Sgreen	}
594117794Siedowse	return (0);
59552340Sgreen}
59652340Sgreen
5971558Srgrimes/*
5981558Srgrimes * xdr routines for mount rpc's
5991558Srgrimes */
6001558Srgrimesint
60152340Sgreenxdr_dir(XDR *xdrsp, char *dirp)
6021558Srgrimes{
60352340Sgreen
604194880Sdfr	return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
6051558Srgrimes}
6061558Srgrimes
6071558Srgrimesvoid
608201252Sedusage(void)
6091558Srgrimes{
61052340Sgreen
61126742Scharnier	(void)fprintf(stderr, "%s\n%s\n",
612219955Sru	    "usage: umount [-fv] special ... | node ... | fsid ...",
613141611Sru	    "       umount -a | -A [-F fstab] [-fv] [-h host] [-t type]");
6141558Srgrimes	exit(1);
6151558Srgrimes}
616