xref: /freebsd/sbin/mount_nfs/mount_nfs.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
1 /*
2  * Copyright (c) 1992, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 static char copyright[] =
39 "@(#) Copyright (c) 1992, 1993, 1994\n\
40 	The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42 
43 #ifndef lint
44 static char sccsid[] = "@(#)mount_nfs.c	8.3 (Berkeley) 3/27/94";
45 #endif /* not lint */
46 
47 #include <sys/param.h>
48 #include <sys/mount.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/stat.h>
52 #include <sys/syslog.h>
53 
54 #include <rpc/rpc.h>
55 #include <rpc/pmap_clnt.h>
56 #include <rpc/pmap_prot.h>
57 
58 #ifdef ISO
59 #include <netiso/iso.h>
60 #endif
61 
62 #ifdef KERBEROS
63 #include <kerberosIV/des.h>
64 #include <kerberosIV/krb.h>
65 #endif
66 
67 #include <nfs/rpcv2.h>
68 #include <nfs/nfsv2.h>
69 #define KERNEL
70 #include <nfs/nfs.h>
71 #undef KERNEL
72 #include <nfs/nqnfs.h>
73 
74 #include <arpa/inet.h>
75 
76 #include <ctype.h>
77 #include <err.h>
78 #include <errno.h>
79 #include <fcntl.h>
80 #include <netdb.h>
81 #include <signal.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <strings.h>
85 #include <unistd.h>
86 
87 #include "mntopts.h"
88 
89 #define	ALTF_BG		0x1
90 #define ALTF_NOCONN	0x2
91 #define ALTF_DUMBTIMR	0x4
92 #define ALTF_INTR	0x8
93 #define ALTF_KERB	0x10
94 #define ALTF_NQLOOKLSE	0x20
95 #define ALTF_RDIRALOOK	0x40
96 #define	ALTF_MYWRITE	0x80
97 #define ALTF_RESVPORT	0x100
98 #define ALTF_SEQPACKET	0x200
99 #define ALTF_NQNFS	0x400
100 #define ALTF_SOFT	0x800
101 #define ALTF_TCP	0x1000
102 
103 struct mntopt mopts[] = {
104 	MOPT_STDOPTS,
105 	MOPT_FORCE,
106 	MOPT_UPDATE,
107 	{ "bg", 0, ALTF_BG, 1 },
108 	{ "conn", 1, ALTF_NOCONN, 1 },
109 	{ "dumbtimer", 0, ALTF_DUMBTIMR, 1 },
110 	{ "intr", 0, ALTF_INTR, 1 },
111 #ifdef KERBEROS
112 	{ "kerb", 0, ALTF_KERB, 1 },
113 #endif
114 	{ "nqlooklease", 0, ALTF_NQLOOKLSE, 1 },
115 	{ "rdiralook", 0, ALTF_RDIRALOOK, 1 },
116 	{ "mywrite", 0, ALTF_MYWRITE, 1 },
117 	{ "resvport", 0, ALTF_RESVPORT, 1 },
118 #ifdef ISO
119 	{ "seqpacket", 0, ALTF_SEQPACKET, 1 },
120 #endif
121 	{ "nqnfs", 0, ALTF_NQNFS, 1 },
122 	{ "soft", 0, ALTF_SOFT, 1 },
123 	{ "tcp", 0, ALTF_TCP, 1 },
124 	{ NULL }
125 };
126 
127 struct nfs_args nfsdefargs = {
128 	(struct sockaddr *)0,
129 	sizeof (struct sockaddr_in),
130 	SOCK_DGRAM,
131 	0,
132 	(nfsv2fh_t *)0,
133 	0,
134 	NFS_WSIZE,
135 	NFS_RSIZE,
136 	NFS_TIMEO,
137 	NFS_RETRANS,
138 	NFS_MAXGRPS,
139 	NFS_DEFRAHEAD,
140 	NQ_DEFLEASE,
141 	NQ_DEADTHRESH,
142 	(char *)0,
143 };
144 
145 struct nfhret {
146 	u_long	stat;
147 	nfsv2fh_t nfh;
148 };
149 #define	DEF_RETRY	10000
150 #define	BGRND	1
151 #define	ISBGRND	2
152 int retrycnt = DEF_RETRY;
153 int opflags = 0;
154 
155 #ifdef KERBEROS
156 char inst[INST_SZ];
157 char realm[REALM_SZ];
158 KTEXT_ST kt;
159 #endif
160 
161 int	getnfsargs __P((char *, struct nfs_args *));
162 #ifdef ISO
163 struct	iso_addr *iso_addr __P((const char *));
164 #endif
165 void	set_rpc_maxgrouplist __P((int));
166 __dead	void usage __P((void));
167 int	xdr_dir __P((XDR *, char *));
168 int	xdr_fh __P((XDR *, struct nfhret *));
169 
170 int
171 main(argc, argv)
172 	int argc;
173 	char *argv[];
174 {
175 	register int c;
176 	register struct nfs_args *nfsargsp;
177 	struct nfs_args nfsargs;
178 	struct nfsd_cargs ncd;
179 	int mntflags, altflags, i, nfssvc_flag, num;
180 	char *name, *p, *spec;
181 	struct vfsconf *vfc;
182 #ifdef KERBEROS
183 	uid_t last_ruid;
184 #endif
185 
186 #ifdef KERBEROS
187 	last_ruid = -1;
188 	(void)strcpy(realm, KRB_REALM);
189 #endif
190 	retrycnt = DEF_RETRY;
191 
192 	mntflags = 0;
193 	altflags = 0;
194 	nfsargs = nfsdefargs;
195 	nfsargsp = &nfsargs;
196 	while ((c = getopt(argc, argv,
197 	    "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF)
198 		switch (c) {
199 		case 'a':
200 			num = strtol(optarg, &p, 10);
201 			if (*p || num < 0)
202 				errx(1, "illegal -a value -- %s", optarg);
203 			nfsargsp->readahead = num;
204 			nfsargsp->flags |= NFSMNT_READAHEAD;
205 			break;
206 		case 'b':
207 			opflags |= BGRND;
208 			break;
209 		case 'c':
210 			nfsargsp->flags |= NFSMNT_NOCONN;
211 			break;
212 		case 'D':
213 			num = strtol(optarg, &p, 10);
214 			if (*p || num <= 0)
215 				errx(1, "illegal -D value -- %s", optarg);
216 			nfsargsp->deadthresh = num;
217 			nfsargsp->flags |= NFSMNT_DEADTHRESH;
218 			break;
219 		case 'd':
220 			nfsargsp->flags |= NFSMNT_DUMBTIMR;
221 			break;
222 		case 'g':
223 			num = strtol(optarg, &p, 10);
224 			if (*p || num <= 0)
225 				errx(1, "illegal -g value -- %s", optarg);
226 			set_rpc_maxgrouplist(num);
227 			nfsargsp->maxgrouplist = num;
228 			nfsargsp->flags |= NFSMNT_MAXGRPS;
229 			break;
230 		case 'i':
231 			nfsargsp->flags |= NFSMNT_INT;
232 			break;
233 #ifdef KERBEROS
234 		case 'K':
235 			nfsargsp->flags |= NFSMNT_KERB;
236 			break;
237 #endif
238 		case 'k':
239 			nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
240 			break;
241 		case 'L':
242 			num = strtol(optarg, &p, 10);
243 			if (*p || num < 2)
244 				errx(1, "illegal -L value -- %s", optarg);
245 			nfsargsp->leaseterm = num;
246 			nfsargsp->flags |= NFSMNT_LEASETERM;
247 			break;
248 		case 'l':
249 			nfsargsp->flags |= NFSMNT_RDIRALOOK;
250 			break;
251 		case 'M':
252 			nfsargsp->flags |= NFSMNT_MYWRITE;
253 			break;
254 #ifdef KERBEROS
255 		case 'm':
256 			(void)strncpy(realm, optarg, REALM_SZ - 1);
257 			realm[REALM_SZ - 1] = '\0';
258 			break;
259 #endif
260 		case 'o':
261 			getmntopts(optarg, mopts, &mntflags, &altflags);
262 			if(altflags & ALTF_BG)
263 				opflags |= BGRND;
264 			if(altflags & ALTF_NOCONN)
265 				nfsargsp->flags |= NFSMNT_NOCONN;
266 			if(altflags & ALTF_DUMBTIMR)
267 				nfsargsp->flags |= NFSMNT_DUMBTIMR;
268 			if(altflags & ALTF_INTR)
269 				nfsargsp->flags |= NFSMNT_INT;
270 #ifdef KERBEROS
271 			if(altflags & ALTF_KERB)
272 				nfsargsp->flags |= NFSMNT_KERB;
273 #endif
274 			if(altflags & ALTF_NQLOOKLSE)
275 				nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
276 			if(altflags & ALTF_RDIRALOOK)
277 				nfsargsp->flags |= NFSMNT_RDIRALOOK;
278 			if(altflags & ALTF_MYWRITE)
279 				nfsargsp->flags |= NFSMNT_MYWRITE;
280 			if(altflags & ALTF_RESVPORT)
281 				nfsargsp->flags |= NFSMNT_RESVPORT;
282 #ifdef ISO
283 			if(altflags & ALTF_SEQPACKET)
284 				nfsargsp->sotype = SOCK_SEQPACKET;
285 #endif
286 			if(altflags & ALTF_NQNFS)
287 				nfsargsp->flags |= NFSMNT_NQNFS;
288 			if(altflags & ALTF_SOFT)
289 				nfsargsp->flags |= NFSMNT_SOFT;
290 			if(altflags & ALTF_TCP)
291 				nfsargsp->sotype = SOCK_STREAM;
292 			altflags = 0;
293 			break;
294 		case 'P':
295 			nfsargsp->flags |= NFSMNT_RESVPORT;
296 			break;
297 #ifdef ISO
298 		case 'p':
299 			nfsargsp->sotype = SOCK_SEQPACKET;
300 			break;
301 #endif
302 		case 'q':
303 			nfsargsp->flags |= NFSMNT_NQNFS;
304 			break;
305 		case 'R':
306 			num = strtol(optarg, &p, 10);
307 			if (*p || num <= 0)
308 				errx(1, "illegal -R value -- %s", optarg);
309 			retrycnt = num;
310 			break;
311 		case 'r':
312 			num = strtol(optarg, &p, 10);
313 			if (*p || num <= 0)
314 				errx(1, "illegal -r value -- %s", optarg);
315 			nfsargsp->rsize = num;
316 			nfsargsp->flags |= NFSMNT_RSIZE;
317 			break;
318 		case 's':
319 			nfsargsp->flags |= NFSMNT_SOFT;
320 			break;
321 		case 'T':
322 			nfsargsp->sotype = SOCK_STREAM;
323 			break;
324 		case 't':
325 			num = strtol(optarg, &p, 10);
326 			if (*p || num <= 0)
327 				errx(1, "illegal -t value -- %s", optarg);
328 			nfsargsp->timeo = num;
329 			nfsargsp->flags |= NFSMNT_TIMEO;
330 			break;
331 		case 'w':
332 			num = strtol(optarg, &p, 10);
333 			if (*p || num <= 0)
334 				errx(1, "illegal -w value -- %s", optarg);
335 			nfsargsp->wsize = num;
336 			nfsargsp->flags |= NFSMNT_WSIZE;
337 			break;
338 		case 'x':
339 			num = strtol(optarg, &p, 10);
340 			if (*p || num <= 0)
341 				errx(1, "illegal -x value -- %s", optarg);
342 			nfsargsp->retrans = num;
343 			nfsargsp->flags |= NFSMNT_RETRANS;
344 			break;
345 		default:
346 			usage();
347 			break;
348 		}
349 	argc -= optind;
350 	argv += optind;
351 
352 	if (argc != 2)
353 		usage();
354 
355 	spec = *argv++;
356 	name = *argv;
357 
358 	if (!getnfsargs(spec, nfsargsp))
359 		exit(1);
360 
361 	vfc = getvfsbyname("nfs");
362 	if(!vfc && vfsisloadable("nfs")) {
363 		if(vfsload("nfs"))
364 			err(1, "vfsload(nfs)");
365 		endvfsent();	/* flush cache */
366 		vfc = getvfsbyname("nfs");
367 	}
368 
369 	if (mount(vfc ? vfc->vfc_index : MOUNT_NFS, name, mntflags, nfsargsp))
370 		err(1, "%s", name);
371 	if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
372 		if ((opflags & ISBGRND) == 0) {
373 			if (i = fork()) {
374 				if (i == -1)
375 					err(1, "nqnfs 1");
376 				exit(0);
377 			}
378 			(void) setsid();
379 			(void) close(STDIN_FILENO);
380 			(void) close(STDOUT_FILENO);
381 			(void) close(STDERR_FILENO);
382 			(void) chdir("/");
383 		}
384 		openlog("mount_nfs:", LOG_PID, LOG_DAEMON);
385 		nfssvc_flag = NFSSVC_MNTD;
386 		ncd.ncd_dirp = name;
387 		while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) {
388 			if (errno != ENEEDAUTH) {
389 				syslog(LOG_ERR, "nfssvc err %m");
390 				continue;
391 			}
392 			nfssvc_flag =
393 			    NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
394 #ifdef KERBEROS
395 			/*
396 			 * Set up as ncd_authuid for the kerberos call.
397 			 * Must set ruid to ncd_authuid and reset the
398 			 * ticket name iff ncd_authuid is not the same
399 			 * as last time, so that the right ticket file
400 			 * is found.
401 			 */
402 			if (ncd.ncd_authuid != last_ruid) {
403 				char buf[512];
404 				(void)sprintf(buf, "%s%d",
405 					      TKT_ROOT, ncd.ncd_authuid);
406 				krb_set_tkt_string(buf);
407 				last_ruid = ncd.ncd_authuid;
408 			}
409 			if (krb_mk_req(&kt, "rcmd", inst, realm, 0) ==
410 			    KSUCCESS &&
411 			    kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) {
412 				ncd.ncd_authtype = RPCAUTH_NQNFS;
413 				ncd.ncd_authlen = kt.length;
414 				ncd.ncd_authstr = (char *)kt.dat;
415 				nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
416 			}
417 #endif /* KERBEROS */
418 		}
419 	}
420 	exit(0);
421 }
422 
423 int
424 getnfsargs(spec, nfsargsp)
425 	char *spec;
426 	struct nfs_args *nfsargsp;
427 {
428 	register CLIENT *clp;
429 	struct hostent *hp;
430 	static struct sockaddr_in saddr;
431 #ifdef ISO
432 	static struct sockaddr_iso isoaddr;
433 	struct iso_addr *isop;
434 	int isoflag = 0;
435 #endif
436 	struct timeval pertry, try;
437 	enum clnt_stat clnt_stat;
438 	int so = RPC_ANYSOCK, i;
439 	char *hostp, *delimp;
440 #ifdef KERBEROS
441 	char *cp;
442 #endif
443 	u_short tport;
444 	static struct nfhret nfhret;
445 	static char nam[MNAMELEN + 1];
446 
447 	strncpy(nam, spec, MNAMELEN);
448 	nam[MNAMELEN] = '\0';
449 	if ((delimp = strchr(spec, '@')) != NULL) {
450 		hostp = delimp + 1;
451 	} else if ((delimp = strchr(spec, ':')) != NULL) {
452 		hostp = spec;
453 		spec = delimp + 1;
454 	} else {
455 		warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
456 		return (0);
457 	}
458 	*delimp = '\0';
459 	/*
460 	 * DUMB!! Until the mount protocol works on iso transport, we must
461 	 * supply both an iso and an inet address for the host.
462 	 */
463 #ifdef ISO
464 	if (!strncmp(hostp, "iso=", 4)) {
465 		u_short isoport;
466 
467 		hostp += 4;
468 		isoflag++;
469 		if ((delimp = strchr(hostp, '+')) == NULL) {
470 			warnx("no iso+inet address");
471 			return (0);
472 		}
473 		*delimp = '\0';
474 		if ((isop = iso_addr(hostp)) == NULL) {
475 			warnx("bad ISO address");
476 			return (0);
477 		}
478 		bzero((caddr_t)&isoaddr, sizeof (isoaddr));
479 		bcopy((caddr_t)isop, (caddr_t)&isoaddr.siso_addr,
480 			sizeof (struct iso_addr));
481 		isoaddr.siso_len = sizeof (isoaddr);
482 		isoaddr.siso_family = AF_ISO;
483 		isoaddr.siso_tlen = 2;
484 		isoport = htons(NFS_PORT);
485 		bcopy((caddr_t)&isoport, TSEL(&isoaddr), isoaddr.siso_tlen);
486 		hostp = delimp + 1;
487 	}
488 #endif /* ISO */
489 
490 	/*
491 	 * Handle an internet host address and reverse resolve it if
492 	 * doing Kerberos.
493 	 */
494 	if (isdigit(*hostp)) {
495 		if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) {
496 			warnx("bad net address %s", hostp);
497 			return (0);
498 		}
499 	} else if ((hp = gethostbyname(hostp)) != NULL) {
500 		bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length);
501 	} else {
502 		warnx("can't get net id for host");
503 		return (0);
504         }
505 #ifdef KERBEROS
506 	if ((nfsargsp->flags & NFSMNT_KERB)) {
507 		if ((hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
508 		    sizeof (u_long), AF_INET)) == (struct hostent *)0) {
509 			warnx("can't reverse resolve net address");
510 			return (0);
511 		}
512 		bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length);
513 		strncpy(inst, hp->h_name, INST_SZ);
514 		inst[INST_SZ - 1] = '\0';
515 		if (cp = strchr(inst, '.'))
516 			*cp = '\0';
517 	}
518 #endif /* KERBEROS */
519 
520 	nfhret.stat = EACCES;	/* Mark not yet successful */
521 	while (retrycnt > 0) {
522 		saddr.sin_family = AF_INET;
523 		saddr.sin_port = htons(PMAPPORT);
524 		if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
525 		    NFS_VER2, IPPROTO_UDP)) == 0) {
526 			if ((opflags & ISBGRND) == 0)
527 				clnt_pcreateerror("NFS Portmap");
528 		} else {
529 			saddr.sin_port = 0;
530 			pertry.tv_sec = 10;
531 			pertry.tv_usec = 0;
532 			if ((clp = clntudp_create(&saddr, RPCPROG_MNT,
533 			    RPCMNT_VER1, pertry, &so)) == NULL) {
534 				if ((opflags & ISBGRND) == 0)
535 					clnt_pcreateerror("Cannot MNT RPC");
536 			} else {
537 				clp->cl_auth = authunix_create_default();
538 				try.tv_sec = 10;
539 				try.tv_usec = 0;
540 				clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
541 				    xdr_dir, spec, xdr_fh, &nfhret, try);
542 				if (clnt_stat != RPC_SUCCESS) {
543 					if ((opflags & ISBGRND) == 0)
544 						warnx("%s", clnt_sperror(clp,
545 						    "bad MNT RPC"));
546 				} else {
547 					auth_destroy(clp->cl_auth);
548 					clnt_destroy(clp);
549 					retrycnt = 0;
550 				}
551 			}
552 		}
553 		if (--retrycnt > 0) {
554 			if (opflags & BGRND) {
555 				opflags &= ~BGRND;
556 				if (i = fork()) {
557 					if (i == -1)
558 						err(1, "nqnfs 2");
559 					exit(0);
560 				}
561 				(void) setsid();
562 				(void) close(STDIN_FILENO);
563 				(void) close(STDOUT_FILENO);
564 				(void) close(STDERR_FILENO);
565 				(void) chdir("/");
566 				opflags |= ISBGRND;
567 			}
568 			sleep(60);
569 		}
570 	}
571 	if (nfhret.stat) {
572 		if (opflags & ISBGRND)
573 			exit(1);
574 		errno = nfhret.stat;
575 		warn("can't access %s", spec);
576 		return (0);
577 	}
578 	saddr.sin_port = htons(tport);
579 #ifdef ISO
580 	if (isoflag) {
581 		nfsargsp->addr = (struct sockaddr *) &isoaddr;
582 		nfsargsp->addrlen = sizeof (isoaddr);
583 	} else
584 #endif /* ISO */
585 	{
586 		nfsargsp->addr = (struct sockaddr *) &saddr;
587 		nfsargsp->addrlen = sizeof (saddr);
588 	}
589 	nfsargsp->fh = &nfhret.nfh;
590 	nfsargsp->hostname = nam;
591 	return (1);
592 }
593 
594 /*
595  * xdr routines for mount rpc's
596  */
597 int
598 xdr_dir(xdrsp, dirp)
599 	XDR *xdrsp;
600 	char *dirp;
601 {
602 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
603 }
604 
605 int
606 xdr_fh(xdrsp, np)
607 	XDR *xdrsp;
608 	struct nfhret *np;
609 {
610 	if (!xdr_u_long(xdrsp, &(np->stat)))
611 		return (0);
612 	if (np->stat)
613 		return (1);
614 	return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH));
615 }
616 
617 __dead void
618 usage()
619 {
620 	(void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n",
621 "[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
622 "\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
623 "\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
624 "\trhost:path node");
625 	exit(1);
626 }
627