xref: /netbsd-src/sbin/umount/umount.c (revision 4efd5405d6ef0924d647f92b100c80f6f2220b32)
1*4efd5405Schristos /*	$NetBSD: umount.c,v 1.53 2020/04/23 04:21:13 christos Exp $	*/
20114e805Scgd 
361f28255Scgd /*-
4bab81812Smycroft  * Copyright (c) 1980, 1989, 1993
5bab81812Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15276d62f6Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
32788a7903Slukem #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
346543a91fSlukem __COPYRIGHT("@(#) Copyright (c) 1980, 1989, 1993\
356543a91fSlukem  The Regents of the University of California.  All rights reserved.");
3661f28255Scgd #endif /* not lint */
3761f28255Scgd 
3861f28255Scgd #ifndef lint
390114e805Scgd #if 0
4056638e9dSlukem static char sccsid[] = "@(#)umount.c	8.8 (Berkeley) 5/8/95";
410114e805Scgd #else
42*4efd5405Schristos __RCSID("$NetBSD: umount.c,v 1.53 2020/04/23 04:21:13 christos Exp $");
430114e805Scgd #endif
4461f28255Scgd #endif /* not lint */
4561f28255Scgd 
4661f28255Scgd #include <sys/param.h>
4761f28255Scgd #include <sys/stat.h>
4861f28255Scgd #include <sys/mount.h>
4961f28255Scgd #include <sys/time.h>
50ba0b3992Schristos #ifndef SMALL
5161f28255Scgd #include <sys/socket.h>
52bab81812Smycroft 
5361f28255Scgd #include <netdb.h>
5461f28255Scgd #include <rpc/rpc.h>
5561f28255Scgd #include <rpc/pmap_clnt.h>
5661f28255Scgd #include <rpc/pmap_prot.h>
5761f28255Scgd #include <nfs/rpcv2.h>
58958c0aacSchristos #include <nfs/nfsmount.h>
59ba0b3992Schristos #endif /* !SMALL */
6061f28255Scgd 
615334ad51Scgd #include <err.h>
624cc121caSdholland #include <errno.h>
6361f28255Scgd #include <fstab.h>
6461f28255Scgd #include <stdio.h>
655334ad51Scgd #include <stdlib.h>
66bab81812Smycroft #include <string.h>
675334ad51Scgd #include <unistd.h>
68*4efd5405Schristos #include <util.h>
6961f28255Scgd 
7098bd013cSpk typedef enum { MNTANY, MNTON, MNTFROM } mntwhat;
7161f28255Scgd 
72ba0b3992Schristos #ifndef SMALL
7399fed726Spooka #include "mountprog.h"
7461f28255Scgd 
75ba0b3992Schristos static int	 fake, verbose;
76ba0b3992Schristos static char	*nfshost;
77ba0b3992Schristos static struct addrinfo *nfshost_ai = NULL;
78ba0b3992Schristos 
79ba0b3992Schristos static int	 namematch(const struct addrinfo *);
80ba0b3992Schristos static int	 sacmp(const struct sockaddr *, const struct sockaddr *);
81ba0b3992Schristos static int	 xdr_dir(XDR *, char *);
82da960e08Schristos static const char *getmntproto(const char *);
83ba0b3992Schristos #endif /* !SMALL */
84ba0b3992Schristos 
85a3b206f6Schs static int	 fflag;
86ba0b3992Schristos static char	*getmntname(const char *, mntwhat, char **);
87a3b206f6Schs static int	 umountfs(const char *, const char **, int);
888b0f9554Sperry static void	 usage(void) __dead;
89ba0b3992Schristos 
905334ad51Scgd int
main(int argc,char * argv[])91ff49552bSdsl main(int argc, char *argv[])
9261f28255Scgd {
93a3b206f6Schs 	int ch, errs, all = 0, raw = 0;
94*4efd5405Schristos 	char mntfromname[MAXPATHLEN];
95ba0b3992Schristos #ifndef SMALL
96ba0b3992Schristos 	int mnts;
976bd1d6d4Schristos 	struct statvfs *mntbuf;
98d6548209Sfvdl 	struct addrinfo hints;
99ba0b3992Schristos #endif /* SMALL */
100ba0b3992Schristos 	const char **typelist = NULL;
10161f28255Scgd 
102ba0b3992Schristos #ifdef SMALL
103a432762dSerh #define OPTS "fR"
104ba0b3992Schristos #else
105ba0b3992Schristos #define OPTS "AaFfh:Rt:v"
106ba0b3992Schristos #endif
107ba0b3992Schristos 	while ((ch = getopt(argc, argv, OPTS)) != -1)
108bab81812Smycroft 		switch (ch) {
109ba0b3992Schristos 		case 'f':
110ba0b3992Schristos 			fflag = MNT_FORCE;
111ba0b3992Schristos 			break;
112ba0b3992Schristos 		case 'R':
113ba0b3992Schristos 			raw = 1;
114ba0b3992Schristos 			break;
115ba0b3992Schristos #ifndef SMALL
11656638e9dSlukem 		case 'A':
117bab81812Smycroft 		case 'a':
118bab81812Smycroft 			all = 1;
119bab81812Smycroft 			break;
120bab81812Smycroft 		case 'F':
121bab81812Smycroft 			fake = 1;
12261f28255Scgd 			break;
12356638e9dSlukem 		case 'h':	/* -h implies -A. */
12409218270Schs 			all = 1;
125bab81812Smycroft 			nfshost = optarg;
12661f28255Scgd 			break;
12761f28255Scgd 		case 't':
12863292a1aSmycroft 			if (typelist != NULL)
12963292a1aSmycroft 				errx(1, "only one -t option may be specified.");
13056638e9dSlukem 			typelist = makevfslist(optarg);
13161f28255Scgd 			break;
132bab81812Smycroft 		case 'v':
13363292a1aSmycroft 			verbose = 1;
13461f28255Scgd 			break;
135ba0b3992Schristos #endif /* !SMALL */
13661f28255Scgd 		default:
13761f28255Scgd 			usage();
13861f28255Scgd 			/* NOTREACHED */
13961f28255Scgd 		}
14061f28255Scgd 	argc -= optind;
14161f28255Scgd 	argv += optind;
14261f28255Scgd 
1439fc45bafSfair 	if ((argc == 0 && !all) || (argc != 0 && all) || (all && raw))
14461f28255Scgd 		usage();
145bab81812Smycroft 
146ba0b3992Schristos #ifndef SMALL
147bab81812Smycroft 	/* -h implies "-t nfs" if no -t flag. */
148bab81812Smycroft 	if ((nfshost != NULL) && (typelist == NULL))
14956638e9dSlukem 		typelist = makevfslist("nfs");
150bab81812Smycroft 
151d6548209Sfvdl 	if (nfshost != NULL) {
152d6548209Sfvdl 		memset(&hints, 0, sizeof hints);
153ece47fa3Sdholland 		if (getaddrinfo(nfshost, NULL, &hints, &nfshost_ai) != 0) {
154ece47fa3Sdholland 			nfshost_ai = NULL;
155ece47fa3Sdholland 		}
156d6548209Sfvdl 	}
157d6548209Sfvdl 
15856638e9dSlukem 	errs = 0;
15909218270Schs 	if (all) {
160ba0b3992Schristos 		if ((mnts = getmntinfo(&mntbuf, ST_NOWAIT)) == 0) {
16156638e9dSlukem 			warn("getmntinfo");
162bab81812Smycroft 			errs = 1;
16356638e9dSlukem 		}
16456638e9dSlukem 		for (errs = 0, mnts--; mnts > 0; mnts--) {
16556638e9dSlukem 			if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
16656638e9dSlukem 				continue;
167a3b206f6Schs 			if (umountfs(mntbuf[mnts].f_mntonname, typelist,
168a432762dSerh 			             1) != 0)
16956638e9dSlukem 				errs = 1;
17056638e9dSlukem 		}
171ba0b3992Schristos 	} else
172ba0b3992Schristos #endif /* !SMALL */
173*4efd5405Schristos 		for (errs = 0; *argv != NULL; ++argv) {
174*4efd5405Schristos 			if (getfsspecname(mntfromname, sizeof(mntfromname),
175*4efd5405Schristos 			    *argv) == NULL)
176*4efd5405Schristos 				err(EXIT_FAILURE, "%s", mntfromname);
177*4efd5405Schristos 			if (umountfs(mntfromname, typelist, raw) != 0)
17856638e9dSlukem 				errs = 1;
179*4efd5405Schristos 		}
180ba0b3992Schristos 	return errs;
18161f28255Scgd }
18261f28255Scgd 
183ba0b3992Schristos static int
umountfs(const char * name,const char ** typelist,int raw)184a3b206f6Schs umountfs(const char *name, const char **typelist, int raw)
18561f28255Scgd {
186ba0b3992Schristos #ifndef SMALL
18761f28255Scgd 	enum clnt_stat clnt_stat;
188d6548209Sfvdl 	struct timeval try;
189bab81812Smycroft 	CLIENT *clp;
190ba0b3992Schristos 	char *hostp = NULL;
191ba0b3992Schristos 	struct addrinfo *ai = NULL, hints;
192b8a7bdb6Schristos 	const char *proto = NULL;
193ba0b3992Schristos #endif /* !SMALL */
1948cc28b4bSdsl 	const char *mntpt;
1954cc121caSdholland 	char *type, rname[MAXPATHLEN], umountprog[MAXPATHLEN];
196ba0b3992Schristos 	mntwhat what;
197ba0b3992Schristos 	struct stat sb;
1989fc45bafSfair 
1999fc45bafSfair 	if (raw) {
2009fc45bafSfair 		mntpt = name;
2019fc45bafSfair 	} else {
2029fc45bafSfair 
20398bd013cSpk 		what = MNTANY;
204b4712500Sdsl 		if (realpath(name, rname) != NULL) {
205b4712500Sdsl 			name = rname;
206bab81812Smycroft 
20798bd013cSpk 			if (stat(name, &sb) == 0) {
20898bd013cSpk 				if (S_ISBLK(sb.st_mode))
20998bd013cSpk 					what = MNTON;
21098bd013cSpk 				else if (S_ISDIR(sb.st_mode))
21198bd013cSpk 					what = MNTFROM;
21298bd013cSpk 			}
213b4712500Sdsl 		}
214ba0b3992Schristos #ifdef SMALL
215ba0b3992Schristos 		else {
21675cbf5e1Sdholland  			warn("%s", name);
217ba0b3992Schristos  			return 1;
218ba0b3992Schristos 		}
219ba0b3992Schristos #endif /* SMALL */
220b4712500Sdsl 		mntpt = name;
22198bd013cSpk 
22298bd013cSpk 		switch (what) {
22398bd013cSpk 		case MNTON:
22456638e9dSlukem 			if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
225bab81812Smycroft 				warnx("%s: not currently mounted", name);
226bab81812Smycroft 				return (1);
227bab81812Smycroft 			}
22898bd013cSpk 			break;
22998bd013cSpk 		case MNTFROM:
23056638e9dSlukem 			if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
231bab81812Smycroft 				warnx("%s: not currently mounted", mntpt);
232bab81812Smycroft 				return (1);
23361f28255Scgd 			}
23498bd013cSpk 			break;
23598bd013cSpk 		default:
23656638e9dSlukem 			if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
237b4712500Sdsl 				name = mntpt;
23856638e9dSlukem 				if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
239655f1af4Spk 					warnx("%s: not currently mounted", name);
240ba0b3992Schristos 					return 1;
24161f28255Scgd 				}
242655f1af4Spk 			}
243655f1af4Spk 		}
24461f28255Scgd 
245ba0b3992Schristos #ifndef SMALL
24656638e9dSlukem 		if (checkvfsname(type, typelist))
247ba0b3992Schristos 			return 1;
248bab81812Smycroft 
249ba0b3992Schristos 		(void)memset(&hints, 0, sizeof hints);
25027e0d2b7Schristos 		if (!strncmp(type, MOUNT_NFS,
25127e0d2b7Schristos 		    sizeof(((struct statvfs *)NULL)->f_fstypename))) {
2528cc28b4bSdsl 			char *delimp;
253958c0aacSchristos 			proto = getmntproto(mntpt);
254b4712500Sdsl 			/* look for host:mountpoint */
255b4712500Sdsl 			if ((delimp = strrchr(name, ':')) != NULL) {
2568cc28b4bSdsl 				int len = delimp - name;
2578cc28b4bSdsl 				hostp = malloc(len + 1);
2588cc28b4bSdsl 				if (hostp == NULL)
2598cc28b4bSdsl 				    	return 1;
2608cc28b4bSdsl 				memcpy(hostp, name, len);
2618cc28b4bSdsl 				hostp[len] = 0;
2628cc28b4bSdsl 				name += len + 1;
263ece47fa3Sdholland 				if (getaddrinfo(hostp, NULL, &hints, &ai) != 0)
264ece47fa3Sdholland 					ai = NULL;
26556638e9dSlukem 			}
26656638e9dSlukem 		}
26756638e9dSlukem 
268d6548209Sfvdl 		if (!namematch(ai))
269ba0b3992Schristos 			return 1;
270ba0b3992Schristos #endif /* ! SMALL */
2714cc121caSdholland 		snprintf(umountprog, sizeof(umountprog), "umount_%s", type);
272383d022fSdholland 	}
2734cc121caSdholland 
274ba0b3992Schristos #ifndef SMALL
2754cc121caSdholland 	if (verbose) {
276bab81812Smycroft 		(void)printf("%s: unmount from %s\n", name, mntpt);
2774cc121caSdholland 		/* put this before the test of FAKE */
2784cc121caSdholland 		if (!raw) {
2794cc121caSdholland 			(void)printf("Trying unmount program %s\n",
2804cc121caSdholland 			    umountprog);
2814cc121caSdholland 		}
2824cc121caSdholland 	}
283bab81812Smycroft 	if (fake)
284ba0b3992Schristos 		return 0;
285ba0b3992Schristos #endif /* ! SMALL */
286bab81812Smycroft 
2874cc121caSdholland 	if (!raw) {
2884cc121caSdholland 		/*
2894cc121caSdholland 		 * The only options that need to be passed on are -f
2904cc121caSdholland 		 * and -v.
2914cc121caSdholland 		 */
2924cc121caSdholland 		char *args[3];
2934cc121caSdholland 		unsigned nargs = 0;
2944cc121caSdholland 
2954cc121caSdholland 		args[nargs++] = umountprog;
2964cc121caSdholland 		if (fflag == MNT_FORCE) {
2974cc121caSdholland 			args[nargs++] = __UNCONST("-f");
2984cc121caSdholland 		}
2994cc121caSdholland #ifndef SMALL
3004cc121caSdholland 		if (verbose) {
3014cc121caSdholland 			args[nargs++] = __UNCONST("-v");
3024cc121caSdholland 		}
3034cc121caSdholland #endif
3044cc121caSdholland 		execvp(umountprog, args);
3054cc121caSdholland 		if (errno != ENOENT) {
3064cc121caSdholland 			warn("%s: execvp", umountprog);
3074cc121caSdholland 		}
3084cc121caSdholland 	}
3094cc121caSdholland 
3104cc121caSdholland #ifndef SMALL
3114cc121caSdholland 	if (verbose)
3124cc121caSdholland 		(void)printf("(No separate unmount program.)\n");
3134cc121caSdholland #endif
3144cc121caSdholland 
315704e0753Spooka 	if (unmount(mntpt, fflag) == -1) {
316bab81812Smycroft 		warn("%s", mntpt);
317ba0b3992Schristos 		return 1;
318bab81812Smycroft 	}
319bab81812Smycroft 
320ba0b3992Schristos #ifndef SMALL
3218cc28b4bSdsl 	if (ai != NULL && !(fflag & MNT_FORCE)) {
322958c0aacSchristos 		clp = clnt_create(hostp, RPCPROG_MNT, RPCMNT_VER1, proto);
323d6548209Sfvdl 		if (clp  == NULL) {
32461f28255Scgd 			clnt_pcreateerror("Cannot MNT PRC");
325ba0b3992Schristos 			return 1;
32661f28255Scgd 		}
327d6548209Sfvdl 		clp->cl_auth = authsys_create_default();
32861f28255Scgd 		try.tv_sec = 20;
32961f28255Scgd 		try.tv_usec = 0;
3302c6eadc9Schristos 		clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir,
3312c6eadc9Schristos 		    __UNCONST(name), xdr_void, NULL, try);
33261f28255Scgd 		if (clnt_stat != RPC_SUCCESS) {
33361f28255Scgd 			clnt_perror(clp, "Bad MNT RPC");
334ba0b3992Schristos 			return 1;
33561f28255Scgd 		}
33661f28255Scgd 		auth_destroy(clp->cl_auth);
33761f28255Scgd 		clnt_destroy(clp);
33861f28255Scgd 	}
339ba0b3992Schristos #endif /* ! SMALL */
340ba0b3992Schristos 	return 0;
34161f28255Scgd }
34261f28255Scgd 
343ba0b3992Schristos static char *
getmntname(const char * name,mntwhat what,char ** type)344ff49552bSdsl getmntname(const char *name, mntwhat what, char **type)
34561f28255Scgd {
3466bd1d6d4Schristos 	static struct statvfs *mntbuf;
34756638e9dSlukem 	static int mntsize;
348*4efd5405Schristos 	static char mntfromname[MAXPATHLEN];
34956638e9dSlukem 	int i;
35061f28255Scgd 
35156638e9dSlukem 	if (mntbuf == NULL &&
35256638e9dSlukem 	    (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
353bab81812Smycroft 		warn("getmntinfo");
354bab81812Smycroft 		return (NULL);
35561f28255Scgd 	}
3566403c86cSdrochner 	for (i = mntsize - 1; i >= 0; i--) {
357bab81812Smycroft 		if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
358bab81812Smycroft 			if (type)
35956638e9dSlukem 				*type = mntbuf[i].f_fstypename;
36061f28255Scgd 			return (mntbuf[i].f_mntonname);
36161f28255Scgd 		}
362bab81812Smycroft 		if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
363bab81812Smycroft 			if (type)
36456638e9dSlukem 				*type = mntbuf[i].f_fstypename;
365*4efd5405Schristos 			if (getfsspecname(mntfromname, sizeof(mntfromname),
366*4efd5405Schristos 			    mntbuf[i].f_mntfromname) == NULL)
367*4efd5405Schristos 				err(EXIT_FAILURE, "%s", mntfromname);
368*4efd5405Schristos 			return mntfromname;
36961f28255Scgd 		}
37061f28255Scgd 	}
371bab81812Smycroft 	return (NULL);
37261f28255Scgd }
37361f28255Scgd 
374ba0b3992Schristos #ifndef SMALL
375ba0b3992Schristos static int
sacmp(const struct sockaddr * sa1,const struct sockaddr * sa2)376ff49552bSdsl sacmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
37761f28255Scgd {
3782c6eadc9Schristos 	const void *p1, *p2;
3792c6eadc9Schristos 	size_t len;
38061f28255Scgd 
381d6548209Sfvdl 	if (sa1->sa_family != sa2->sa_family)
382d6548209Sfvdl 		return 1;
383d6548209Sfvdl 
384d6548209Sfvdl 	switch (sa1->sa_family) {
385d6548209Sfvdl 	case AF_INET:
3862c6eadc9Schristos 		p1 = &((const struct sockaddr_in *)sa1)->sin_addr;
3872c6eadc9Schristos 		p2 = &((const struct sockaddr_in *)sa2)->sin_addr;
388d6548209Sfvdl 		len = 4;
389d6548209Sfvdl 		break;
390d6548209Sfvdl 	case AF_INET6:
3912c6eadc9Schristos 		p1 = &((const struct sockaddr_in6 *)sa1)->sin6_addr;
3922c6eadc9Schristos 		p2 = &((const struct sockaddr_in6 *)sa2)->sin6_addr;
393d6548209Sfvdl 		len = 16;
3942c6eadc9Schristos 		if (((const struct sockaddr_in6 *)sa1)->sin6_scope_id !=
3952c6eadc9Schristos 		    ((const struct sockaddr_in6 *)sa2)->sin6_scope_id)
396d6548209Sfvdl 			return 1;
397d6548209Sfvdl 		break;
398d6548209Sfvdl 	default:
399d6548209Sfvdl 		return 1;
400d6548209Sfvdl 	}
401d6548209Sfvdl 
402d6548209Sfvdl 	return memcmp(p1, p2, len);
403d6548209Sfvdl }
404d6548209Sfvdl 
405ba0b3992Schristos static int
namematch(const struct addrinfo * ai)406ff49552bSdsl namematch(const struct addrinfo *ai)
407d6548209Sfvdl {
408d6548209Sfvdl 	struct addrinfo *aip;
409d6548209Sfvdl 
410d6548209Sfvdl 	if (nfshost == NULL || nfshost_ai == NULL)
41161f28255Scgd 		return (1);
412bab81812Smycroft 
413d6548209Sfvdl 	while (ai != NULL) {
414d6548209Sfvdl 		aip = nfshost_ai;
415d6548209Sfvdl 		while (aip != NULL) {
416d6548209Sfvdl 			if (sacmp(ai->ai_addr, aip->ai_addr) == 0)
417d6548209Sfvdl 				return 1;
418d6548209Sfvdl 			aip = aip->ai_next;
419d6548209Sfvdl 		}
420d6548209Sfvdl 		ai = ai->ai_next;
421d6548209Sfvdl 	}
422bab81812Smycroft 
423d6548209Sfvdl 	return 0;
42461f28255Scgd }
42561f28255Scgd 
42661f28255Scgd /*
42761f28255Scgd  * xdr routines for mount rpc's
42861f28255Scgd  */
429ba0b3992Schristos static int
xdr_dir(XDR * xdrsp,char * dirp)430ff49552bSdsl xdr_dir(XDR *xdrsp, char *dirp)
43161f28255Scgd {
432ba0b3992Schristos 	return xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN);
43361f28255Scgd }
434da960e08Schristos 
435da960e08Schristos static const char *
getmntproto(const char * name)436958c0aacSchristos getmntproto(const char *name)
437da960e08Schristos {
438da960e08Schristos 	struct nfs_args nfsargs;
439958c0aacSchristos 	struct sockaddr_storage ss;
440da960e08Schristos 
441958c0aacSchristos 	nfsargs.sotype = SOCK_DGRAM;
442958c0aacSchristos 	nfsargs.addr = (struct sockaddr *)&ss;
443958c0aacSchristos 	nfsargs.addrlen = sizeof(ss);
444958c0aacSchristos 	(void)mount("nfs", name, MNT_GETARGS, &nfsargs, sizeof(nfsargs));
445958c0aacSchristos 	return nfsargs.sotype == SOCK_STREAM ? "tcp" : "udp";
446da960e08Schristos }
447ba0b3992Schristos #endif /* !SMALL */
448bab81812Smycroft 
449ba0b3992Schristos static void
usage(void)450ff49552bSdsl usage(void)
451bab81812Smycroft {
452ba0b3992Schristos #ifdef SMALL
453bab81812Smycroft 	(void)fprintf(stderr,
454ba0b3992Schristos 	    "Usage: %s [-fR]  special | node\n", getprogname());
455ba0b3992Schristos #else
456ba0b3992Schristos 	(void)fprintf(stderr,
457ba0b3992Schristos 	    "Usage: %s [-fvFR] [-t fstypelist] special | node\n"
458ba0b3992Schristos 	    "\t %s -a[fvF] [-h host] [-t fstypelist]\n", getprogname(),
459ba0b3992Schristos 	    getprogname());
460ba0b3992Schristos #endif /* SMALL */
461bab81812Smycroft 	exit(1);
462bab81812Smycroft }
463