xref: /titanic_50/usr/src/cmd/rexd/mount_nfs.c (revision 174bc6499d233e329ecd3d98a880a7b07df16bfa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 
29 /*
30  *  mount_nfs.c - procedural interface to the NFS mount operation
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 #define	NFSCLIENT
36 #include <sys/types.h>
37 #include <memory.h>
38 #include <netconfig.h>
39 #include <netdb.h>
40 #include <netdir.h>
41 #include <netinet/in.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <syslog.h>
48 
49 #include <rpc/rpc.h>
50 #include <rpc/clnt_soc.h>
51 #include <rpc/pmap_prot.h>
52 #include <nfs/nfs.h>
53 #include <nfs/mount.h>
54 #include <rpcsvc/mount.h>
55 #include <errno.h>
56 #include <sys/mntent.h>
57 #include <sys/mnttab.h>
58 #include <sys/mount.h>
59 #include <sys/param.h>
60 #include <sys/socket.h>
61 #include <sys/stat.h>
62 
63 #include <deflt.h>
64 
65 static struct knetconfig *get_knconf(struct netconfig *nconf);
66 static int bindudp_resvport(CLIENT *client);
67 static void free_knconf(struct knetconfig *k);
68 static void freemnttab(struct mnttab *mnt);
69 static enum clnt_stat pingnfs(char *hostname, rpcvers_t *versp);
70 static void netbuf_free(struct netbuf *nb);
71 static struct netbuf *get_addr(char *hostname, int prog, int vers,
72     struct netconfig **nconfp);
73 
74 extern void set_nfsv4_ephemeral_mount_to(void);
75 
76 #define	TIME_MAX	16
77 
78 extern	int	Debug;
79 extern  time_t	time_now;
80 
81 extern	FILE	*setmntent(char *, char *);
82 extern	void	errprintf(char *, char *, ...);
83 
84 FILE		*setmntent(char *, char *);
85 void		endmntent(FILE *);
86 enum clnt_stat	pingnfs(char *, rpcvers_t *);
87 struct netbuf	*get_addr(char *, int, int, struct netconfig **);
88 struct knetconfig *get_knconf(struct netconfig *);
89 void		netbuf_free(struct netbuf *);
90 void		free_knconf(struct knetconfig *);
91 
92 /*
93  * mount_nfs - mount a file system using NFS
94  *
95  * Returns: 0 if OK, 1 if error.
96  * 	The "error" string returns the error message.
97  */
98 int
99 mount_nfs(char *fsname, char *dir, char *error)
100 {
101 	struct sockaddr_in sin;
102 	struct hostent *hp;
103 	struct fhstatus fhs;
104 	char host[256];
105 	char *path;
106 	char opts[32];
107 	struct stat st;
108 	int s = -1;
109 	struct timeval timeout;
110 	CLIENT *client;
111 	enum clnt_stat rpc_stat;
112 	int printed1 = 0;
113 	int printed2 = 0;
114 	unsigned winks = 1;	/* seconds of sleep time */
115 	struct mnttab mnt;
116 	FILE *mnted;
117 	int flags;
118 	struct nfs_args args;
119 	struct netconfig *nconf, *udpnconf;
120 	char tbuf[TIME_MAX];
121 	rpcvers_t vers;
122 	rpcvers_t nfsvers;
123 	char *fstype;
124 	struct mountres3 res3;
125 	nfs_fh3 fh3;
126 	int *auths;
127 	int count;
128 
129 	if (Debug)
130 		printf("mount_nfs request: mount %s\tdir %s\n", fsname, dir);
131 
132 	if (Debug && errno)
133 		printf("ERRNO set on mount_nfs entry: %d\n", errno);
134 
135 	path = strchr(fsname, ':');
136 	if (path == NULL) {
137 		errprintf(error, "No host name in %s\n", fsname);
138 		return (1);
139 	}
140 	*path = '\0';
141 	strcpy(host, fsname);
142 	*path++ = ':';
143 	if (*path == '\0') {
144 		/*
145 		 * handle the special case of importing a root file system
146 		 */
147 		strcpy(path, "/");
148 	}
149 
150 	if (Debug) {
151 		printf("mount_nfs:\tpath == %s\n", path);
152 		printf("\t\tdir == %s\n", dir);
153 		printf("\t\tgethostbyname host == %s\n", host);
154 	}
155 
156 	/*
157 	 * Get server's address
158 	 */
159 	if ((hp = gethostbyname(host)) == NULL) {
160 		errprintf(error, "mount %s: %s not in hosts database\n",
161 		    fsname, host);
162 		return (1);
163 	}
164 
165 	if (Debug && errno)
166 		printf("ERRNO set after gethostbyname: %d\n", errno);
167 
168 	if (Debug) {
169 		fprintf(stderr, "gethostbyname:\n\th_name %s\n\t", hp->h_name);
170 		if (hp->h_aliases[0] && *hp->h_aliases[0])
171 			fprintf(stderr, "h_aliases %s\n\t", hp->h_aliases[0]);
172 		else
173 			fprintf(stderr, "h_aliases %s\n\t", "<none>");
174 		if (hp->h_addrtype == AF_INET)
175 			fprintf(stderr,
176 			    "h_addrtype AF_INET\n\th_adth_length %u\n\t",
177 			    hp->h_length);
178 		else
179 			fprintf(stderr, "h_addrtype %u\n\th_adth_length %u\n\t",
180 			    hp->h_addrtype, hp->h_length);
181 		if (hp->h_addr_list[0] && *hp->h_addr_list[0])
182 			fprintf(stderr, "h_addr_list <apparent list>\n");
183 		else
184 			fprintf(stderr, "h_addr_list %s\n", "<none>");
185 	}
186 
187 	if (pingnfs(host, &nfsvers) != RPC_SUCCESS) {
188 		errprintf(error, "host %s not responding to ping\n", host);
189 		return (1);
190 	}
191 
192 	if (Debug)
193 		printf("pingnfs: succeeds.\n");
194 
195 	vers = nfsvers;
196 
197 	if (Debug)
198 		printf("clnt_create for mountproc (%d)\n", errno);
199 
200 	client = clnt_create_vers(host, MOUNTPROG, &vers, MOUNTVERS, vers,
201 	    "udp");
202 	if (client == NULL) {
203 		errprintf(error, "%s %s\n", host,
204 		    clnt_spcreateerror("mount server not responding"));
205 		return (1);
206 	}
207 
208 	if (Debug)
209 		printf("call bindudp_resvport for mountproc (%d)\n", errno);
210 
211 	if (bindudp_resvport(client) < 0) {
212 		errprintf(error, "mount %s:%s: %s\n", host, path,
213 		    "Couldn't bind to reserved port");
214 		if (Debug)
215 			printf("could not bind to reserved port\n");
216 		clnt_destroy(client);
217 		return (1);
218 	}
219 
220 	if (client->cl_auth)
221 		auth_destroy(client->cl_auth);
222 	if ((client->cl_auth = authsys_create_default()) == NULL) {
223 		errprintf(error, "mount %s:%s: %s\n", host, path,
224 		    "Couldn't create authsys structure");
225 		if (Debug)
226 			printf("could not create authsys structure\n");
227 		clnt_destroy(client);
228 		return (1);
229 	}
230 /*
231  * #ifdef	NOWAY
232  *	if (Debug)
233  *		printf("authsys_create_default called for mountproc\n");
234  *	client->cl_auth = authsys_create_default();
235  * #endif
236  */
237 
238 	/* set mount args */
239 	memset(&args, 0, sizeof (args));
240 
241 	/* Get fhandle of remote path from server's mountd */
242 
243 	timeout.tv_usec = 0;
244 	timeout.tv_sec = 25;
245 
246 	switch (vers) {
247 	case MOUNTVERS:
248 	case MOUNTVERS_POSIX:
249 		rpc_stat = clnt_call(client, MOUNTPROC_MNT,
250 		    xdr_dirpath, (caddr_t)&path,
251 		    xdr_fhstatus, (caddr_t)&fhs, timeout);
252 
253 		if (rpc_stat != RPC_SUCCESS) {
254 			/*
255 			 * Given the way "clnt_sperror" works, the "%s"
256 			 * following the "not responding" is correct.
257 			 */
258 			errprintf(error, "mount server %s not responding %s\n",
259 			    host, clnt_sperror(client, ""));
260 			clnt_destroy(client);
261 			return (1);
262 		}
263 
264 		clnt_destroy(client);
265 
266 		if ((errno = fhs.fhs_status) != MNT_OK) {
267 			if (errno == EACCES) {
268 				errprintf(error,
269 				    "rexd mount: not in EXPORT list for %s\n",
270 				    fsname);
271 			} else {
272 				errprintf(error, "rexd mount: error %d %s\n",
273 				    errno, strerror(errno));
274 			}
275 			return (1);
276 		}
277 
278 		args.fh = (caddr_t)&fhs.fhstatus_u.fhs_fhandle;
279 		fstype = MNTTYPE_NFS;
280 		break;
281 	case MOUNTVERS3:
282 		memset((char *)&res3, '\0', sizeof (res3));
283 		rpc_stat = clnt_call(client, MOUNTPROC_MNT,
284 		    xdr_dirpath, (char *)&path,
285 		    xdr_mountres3, (char *)&res3, timeout);
286 
287 		if (rpc_stat != RPC_SUCCESS) {
288 			/*
289 			 * Given the way "clnt_sperror" works, the "%s"
290 			 * following the "not responding" is correct.
291 			 */
292 			errprintf(error, "mount server %s not responding %s\n",
293 			    host, clnt_sperror(client, ""));
294 			clnt_destroy(client);
295 			return (1);
296 		}
297 
298 		clnt_destroy(client);
299 
300 		if ((errno = res3.fhs_status) != MNT_OK) {
301 			if (errno == EACCES) {
302 				errprintf(error,
303 				    "rexd mount: not in EXPORT list for %s\n",
304 				    fsname);
305 			} else {
306 				errprintf(error, "rexd mount: error %d %s\n",
307 				    errno, strerror(errno));
308 			}
309 			return (1);
310 		}
311 
312 		auths =
313 		    res3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val;
314 		count =
315 		    res3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len;
316 		if (count > 0) {
317 			if (auths[0] == AUTH_DES)
318 				args.flags |= NFSMNT_SECURE;
319 		}
320 
321 		fh3.fh3_length =
322 		    res3.mountres3_u.mountinfo.fhandle.fhandle3_len;
323 		memcpy(fh3.fh3_u.data,
324 		    res3.mountres3_u.mountinfo.fhandle.fhandle3_val,
325 		    fh3.fh3_length);
326 		args.fh = (caddr_t)&fh3;
327 		fstype = MNTTYPE_NFS3;
328 		break;
329 	default:
330 		errprintf(error, "rexd mount: unknown MOUNT version %ld\n",
331 		    vers);
332 		return (1);
333 	}
334 
335 
336 	/*
337 	 * remote mount the fhandle on the local path.
338 	 */
339 
340 	args.hostname = host;
341 	args.flags = NFSMNT_HOSTNAME;
342 	args.flags |= NFSMNT_INT; /* default is "intr" */
343 
344 	args.addr = get_addr(host, NFS_PROGRAM, nfsvers, &nconf);
345 	if (args.addr == NULL) {
346 		errprintf(error, "%s: no NFS service", host);
347 		return (1);
348 	}
349 
350 	args.flags |=  NFSMNT_KNCONF;
351 	args.knconf = get_knconf(nconf);
352 	if (args.knconf == NULL) {
353 		netbuf_free(args.addr);
354 		return (1);
355 	}
356 
357 	if (Debug)
358 		printf("start mount system call (%d)\n", errno);
359 
360 	flags = MS_NOSUID | MS_DATA;
361 
362 	/*
363 	 * And make sure that we have the ephemeral mount_to
364 	 * set for this zone.
365 	 */
366 	set_nfsv4_ephemeral_mount_to();
367 
368 	/* Provide the mounted resource name when mounting. */
369 	if (mount(fsname, dir, flags, fstype, &args, sizeof (args)) < 0) {
370 		netbuf_free(args.addr);
371 		free_knconf(args.knconf);
372 		errprintf(error, "unable to mount %s on %s: %s\n",
373 		    fsname, dir, strerror(errno));
374 		return (1);
375 	}
376 
377 	if (Debug)
378 		printf("end mount system call (%d)\n", errno);
379 
380 	/*
381 	 * stat the new mount and get its dev
382 	 */
383 	if (stat(dir, &st) < 0) {
384 		errprintf(error, "couldn't stat %s\n", dir);
385 		return (1);
386 	}
387 
388 	if (Debug)
389 		printf("stat of new mount (%d)\n", errno);
390 
391 	(void) sprintf(opts, "rw,noquota,hard,intr,dev=%x", st.st_dev);
392 
393 	/*
394 	 * update /etc/mtab
395 	 */
396 
397 	mnt.mnt_special = fsname;
398 	mnt.mnt_mountp = dir;
399 	mnt.mnt_fstype = MNTTYPE_NFS;
400 	mnt.mnt_mntopts = opts;
401 	(void) sprintf(tbuf, "%ld", time(0L));
402 	mnt.mnt_time = tbuf;
403 
404 	return (0);
405 }
406 
407 #define	UNMOUNTTRIES 6
408 /*
409  * umount_nfs - unmount a file system when finished
410  */
411 int
412 umount_nfs(char *fsname, char *dir)
413 {
414 	char *p;
415 	char *hostname;
416 	int s = -1;
417 	struct timeval timeout;
418 	CLIENT *client;
419 	enum clnt_stat rpc_stat;
420 	int count = 0;
421 
422 	if (Debug)
423 		printf("umount: fsname %s dir %s\n", fsname, dir);
424 	/*
425 	 * Give the filesystem time to become un-busy when unmounting.
426 	 * If child aborted and is takes a core dump, we may receive the
427 	 * SIGCHLD before the core dump is completed.
428 	 */
429 	while (umount(dir) == -1) {
430 		if (errno != EBUSY) {
431 			perror(dir);
432 			return (1);
433 		}
434 
435 		if (++count > UNMOUNTTRIES)
436 			return (1);
437 		sleep(10);
438 	}
439 
440 	if (Debug)
441 		printf("umount_nfs: unmounting %s\n", dir);
442 
443 	if ((p = strchr(fsname, ':')) == NULL)
444 		return (1);
445 	*p++ = 0;
446 	hostname = fsname;
447 
448 
449 	if ((client = clnt_create(hostname, MOUNTPROG, MOUNTVERS, "udp"))
450 	    == NULL) {
451 		clnt_spcreateerror("Warning on umount create:");
452 		fprintf(stderr, "\n\r");
453 		return (1);
454 	}
455 	if (bindudp_resvport(client) < 0) {
456 		errprintf(NULL, "umount %s:%s:%s", hostname, p,
457 		    "Could not bind to reserved port\n");
458 		clnt_destroy(client);
459 		return (1);
460 	}
461 /*
462  * #ifdef		NOWAWY
463  * 	client->cl_auth = authunix_create_default();
464  * #endif
465  */
466 
467 	timeout.tv_usec = 0;
468 	timeout.tv_sec = 25;
469 
470 	rpc_stat = clnt_call(client, MOUNTPROC_UMNT, xdr_dirpath, (caddr_t)&p,
471 	    xdr_void, (char *)NULL, timeout);
472 
473 	clnt_destroy(client);
474 
475 	if (rpc_stat != RPC_SUCCESS) {
476 		clnt_perror(client, "Warning: umount:");
477 		fprintf(stderr, "\n\r");
478 		return (1);
479 	}
480 
481 	return (0);
482 }
483 
484 static struct mnttab *
485 dupmnttab(struct mnttab *mnt)
486 {
487 	struct mnttab *new;
488 	void freemnttab();
489 
490 	new = (struct mnttab *)malloc(sizeof (*new));
491 	if (new == NULL)
492 		goto alloc_failed;
493 	memset((char *)new, 0, sizeof (*new));
494 	new->mnt_special = strdup(mnt->mnt_special);
495 	if (new->mnt_special == NULL)
496 		goto alloc_failed;
497 	new->mnt_mountp = strdup(mnt->mnt_mountp);
498 	if (new->mnt_mountp == NULL)
499 		goto alloc_failed;
500 	new->mnt_fstype = strdup(mnt->mnt_fstype);
501 	if (new->mnt_fstype == NULL)
502 		goto alloc_failed;
503 	if (mnt->mnt_mntopts != NULL)
504 		if ((new->mnt_mntopts = strdup(mnt->mnt_mntopts)) == NULL)
505 			goto alloc_failed;
506 	if (mnt->mnt_time != NULL)
507 		if ((new->mnt_time = strdup(mnt->mnt_time)) == NULL)
508 			goto alloc_failed;
509 
510 	return (new);
511 
512 alloc_failed:
513 
514 	errprintf(NULL, "dupmnttab: memory allocation failed\n");
515 	freemnttab(new);
516 	return (NULL);
517 }
518 
519 
520 
521 /*
522  * Free a single mnttab structure
523  */
524 static void
525 freemnttab(struct mnttab *mnt)
526 {
527 	if (mnt) {
528 		if (mnt->mnt_special)
529 			free(mnt->mnt_special);
530 		if (mnt->mnt_mountp)
531 			free(mnt->mnt_mountp);
532 		if (mnt->mnt_fstype)
533 			free(mnt->mnt_fstype);
534 		if (mnt->mnt_mntopts)
535 			free(mnt->mnt_mntopts);
536 		if (mnt->mnt_time)
537 			free(mnt->mnt_time);
538 		free(mnt);
539 	}
540 }
541 
542 
543 /* the following structure is used to build a list of */
544 /* mnttab structures from /etc/mnttab. */
545 struct mntlist {
546 	struct mnttab *mntl_mnt;
547 	struct mntlist *mntl_next;
548 };
549 
550 
551 /*
552  * Free a list of mnttab structures
553  */
554 static void
555 freemntlist(struct mntlist *mntl)
556 {
557 	struct mntlist *mntl_tmp;
558 
559 	while (mntl) {
560 		freemnttab(mntl->mntl_mnt);
561 		mntl_tmp = mntl;
562 		mntl = mntl->mntl_next;
563 		free(mntl_tmp);
564 	}
565 }
566 
567 
568 /*
569  * parsefs - given a name of the form host:/path/name/for/file
570  *	connect to the give host and look for the exported file system
571  *	that matches.
572  * Returns: pointer to string containing the part of the pathname
573  *	within the exported directory.
574  *	Returns NULL on errors.
575  */
576 char *
577 parsefs(char *fullname, char *error)
578 {
579 	char	*dir, *subdir;
580 	struct exportnode	*ex = NULL;
581 	int	err;
582 	int	bestlen = 0;
583 	int	len, dirlen;
584 
585 	if (Debug && errno)
586 		printf("parsefs of %s entered with errno %d %s\n",
587 		    fullname, errno, strerror(errno));
588 
589 	dir = strchr(fullname, ':');
590 	if (dir == NULL) {
591 		errprintf(error, "No host name in %s\n", fullname);
592 		return (NULL);
593 	}
594 	*dir++ = '\0';
595 
596 	if (Debug)
597 		printf("parsefs before rpc_call: ERRNO:%d\n", errno);
598 
599 	if (err = rpc_call(fullname, MOUNTPROG, MOUNTVERS, MOUNTPROC_EXPORT,
600 	    xdr_void, 0, xdr_exports, (char *)&ex, "udp")) {
601 
602 		if (err == (int)RPC_TIMEDOUT)
603 			errprintf(error, "Host %s is not running mountd\n",
604 			    fullname);
605 		else
606 			errprintf(error, "RPC error %d with host %s (%s)\n",
607 			    err, fullname, clnt_sperrno(err));
608 
609 		if (Debug && errno) {
610 			printf("parsefs: mount call to %s returned %d %s\n",
611 			    fullname, err, clnt_sperrno(err));
612 			printf("with errno %d:\t%s\n",	errno, strerror(errno));
613 		}
614 		return (NULL);
615 	}
616 
617 	if (Debug)
618 		printf("parsefs after rpc_call: ERRNO:%d\n", errno);
619 
620 	dirlen = strlen(dir);
621 
622 	if (Debug && errno) {
623 		printf("parsefs: mount call to %s returned %d %s\n",
624 		    fullname, err, clnt_sperrno(err));
625 		printf("with errno %d:\t%s\n", errno, strerror(errno));
626 	}
627 
628 	if (Debug)
629 		printf("parsefs: checking export list:\n");
630 
631 	for (; ex; ex = ex->ex_next) {
632 		len = strlen(ex->ex_dir);
633 		if (len > bestlen && len <= dirlen &&
634 		    strncmp(dir, ex->ex_dir, len) == 0 &&
635 		    (dir[len] == '/' || dir[len] == '\0'))
636 			bestlen = len;
637 
638 		if (Debug)
639 			printf("\t%d\t%s\n", bestlen, ex->ex_dir);
640 	}
641 
642 	if (bestlen == 0) {
643 		errprintf(error, "%s not exported by %s\n",
644 		    dir, fullname);
645 		return (NULL);
646 	}
647 
648 	if (dir[bestlen] == '\0')
649 		subdir = &dir[bestlen];
650 	else {
651 		dir[bestlen] = '\0';
652 		subdir = &dir[bestlen+1];
653 	}
654 	*--dir = ':';
655 
656 	return (subdir);
657 }
658 
659 /*
660  * Get the network address for the service identified by "prog"
661  * and "vers" on "hostname".  The netconfig address is returned
662  * in the value of "nconfp".
663  * If the hostname is the same as the last call, then the same
664  * transport is used as last time (same netconfig entry).
665  */
666 static struct netbuf *
667 get_addr(char *hostname, int prog, int vers, struct netconfig **nconfp)
668 {
669 	static char prevhost[MAXHOSTNAMELEN+1];
670 	static struct netconfig *nconf;
671 	static NCONF_HANDLE *nc = NULL;
672 	struct netbuf *nb = NULL;
673 	struct t_bind *tbind = NULL;
674 	struct netconfig *getnetconfig();
675 	struct netconfig *getnetconfigent();
676 	enum clnt_stat cs;
677 	struct timeval tv;
678 	int fd = -1;
679 
680 	if (strcmp(hostname, prevhost) != 0) {
681 		if (nc)
682 			endnetconfig(nc);
683 		nc = setnetconfig();
684 		if (nc == NULL)
685 			goto done;
686 	retry:
687 		/*
688 		 * If the port number is specified then UDP is needed.
689 		 * Otherwise any connectionless transport will do.
690 		 */
691 		while (nconf = getnetconfig(nc)) {
692 			if ((nconf->nc_flag & NC_VISIBLE) &&
693 			    nconf->nc_semantics == NC_TPI_CLTS) {
694 				break;
695 			}
696 		}
697 		if (nconf == NULL)
698 			goto done;
699 		(void) strcpy(prevhost, hostname);
700 	}
701 
702 	fd = t_open(nconf->nc_device, O_RDWR, NULL);
703 	if (fd < 0)
704 		goto done;
705 
706 	tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
707 	if (tbind == NULL)
708 		goto done;
709 
710 	if (rpcb_getaddr(prog, vers, nconf, &tbind->addr, hostname) == 0) {
711 		t_free((char *)tbind, T_BIND);
712 		tbind = NULL;
713 		goto retry;
714 	}
715 	*nconfp = nconf;
716 
717 	/*
718 	 * Make a copy of the netbuf to return
719 	 */
720 	nb = (struct netbuf *)malloc(sizeof (struct netbuf));
721 	if (nb == NULL) {
722 		errprintf(NULL, "no memory");
723 		goto done;
724 	}
725 	*nb = tbind->addr;
726 	nb->buf = (char *)malloc(nb->len);
727 	if (nb->buf == NULL) {
728 		errprintf(NULL, "no memory");
729 		free(nb);
730 		nb = NULL;
731 		goto done;
732 	}
733 	(void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
734 
735 done:
736 	if (tbind)
737 		t_free((char *)tbind, T_BIND);
738 	if (fd >= 0)
739 		(void) t_close(fd);
740 	return (nb);
741 }
742 
743 static struct knetconfig *
744 get_knconf(struct netconfig *nconf)
745 {
746 	struct stat stbuf;
747 	struct knetconfig *k;
748 
749 	if (stat(nconf->nc_device, &stbuf) < 0) {
750 		errprintf(NULL, "get_knconf: stat %s: %m", nconf->nc_device);
751 		return (NULL);
752 	}
753 	k = (struct knetconfig *)malloc(sizeof (*k));
754 	if (k == NULL)
755 		goto nomem;
756 	k->knc_semantics = nconf->nc_semantics;
757 	k->knc_protofmly = strdup(nconf->nc_protofmly);
758 	if (k->knc_protofmly == NULL)
759 		goto nomem;
760 	k->knc_proto = strdup(nconf->nc_proto);
761 	if (k->knc_proto == NULL)
762 		goto nomem;
763 	k->knc_rdev = stbuf.st_rdev;
764 
765 	return (k);
766 
767 nomem:
768 	errprintf(NULL, "get_knconf: no memory");
769 	free_knconf(k);
770 	return (NULL);
771 }
772 
773 static void
774 free_knconf(struct knetconfig *k)
775 {
776 	if (k == NULL)
777 		return;
778 	if (k->knc_protofmly)
779 		free(k->knc_protofmly);
780 	if (k->knc_proto)
781 		free(k->knc_proto);
782 	free(k);
783 }
784 
785 static void
786 netbuf_free(struct netbuf *nb)
787 {
788 	if (nb == NULL)
789 		return;
790 	if (nb->buf)
791 		free(nb->buf);
792 	free(nb);
793 }
794 
795 
796 static enum clnt_stat
797 pingnfs(char *hostname, rpcvers_t *versp)
798 {
799 	CLIENT *cl;
800 	enum clnt_stat clnt_stat;
801 	static char goodhost[MAXHOSTNAMELEN+1];
802 	static char deadhost[MAXHOSTNAMELEN+1];
803 	static time_t goodtime, deadtime;
804 	int cache_time = 60;	/* sec */
805 
806 	if (goodtime > time_now && strcmp(hostname, goodhost) == 0)
807 		return (RPC_SUCCESS);
808 	if (deadtime > time_now && strcmp(hostname, deadhost) == 0)
809 		return (RPC_TIMEDOUT);
810 
811 	if (Debug)
812 		printf("ping %s ", hostname);
813 
814 	/* ping the NFS nullproc on the server */
815 
816 	cl = clnt_create_vers(hostname, NFS_PROGRAM, versp, NFS_VERSMIN,
817 	    NFS_VERSMAX, "udp");
818 	if (cl == NULL) {
819 		errprintf(NULL, "pingnfs: %s%s",
820 		    hostname, clnt_spcreateerror(""));
821 		if (Debug)
822 			printf("clnt_create failed\n");
823 		clnt_stat = RPC_TIMEDOUT;
824 	} else {
825 		clnt_stat = RPC_SUCCESS;
826 		clnt_destroy(cl);
827 	}
828 
829 	if (clnt_stat == RPC_SUCCESS) {
830 		(void) strcpy(goodhost, hostname);
831 		goodtime = time_now + cache_time;
832 	} else {
833 		(void) strcpy(deadhost, hostname);
834 		deadtime = time_now + cache_time;
835 	}
836 
837 	if (Debug)
838 		(void) printf("%s\n", clnt_stat == RPC_SUCCESS ?
839 		    "OK" : "NO RESPONSE");
840 
841 	return (clnt_stat);
842 }
843 
844 static int bindudp_resvport(CLIENT *client)
845 {
846 	struct netconfig *udpnconf;
847 	int clfd;
848 	int rv;
849 
850 	/* check for superuser as reserved ports are for superuser only */
851 	if (geteuid()) {
852 		errno = EACCES;
853 		return (-1);
854 	}
855 
856 	if (clnt_control(client, CLGET_FD, (char *)&clfd) == FALSE) {
857 		errprintf(NULL,
858 		    "Could not get file dscriptor for client handle\n");
859 		return (-1);
860 	}
861 
862 	if (Debug)
863 		printf("Clnt_control success, clfd = %d\n", clfd);
864 
865 	if (t_getstate(clfd) != T_UNBND) {
866 		if (t_unbind(clfd) < 0) {
867 			return (-1);
868 		}
869 	}
870 
871 	if ((udpnconf = getnetconfigent("udp")) == (struct netconfig *)NULL) {
872 		errprintf(NULL, "no netconfig information about \"udp\"\n");
873 		return (-1);
874 	}
875 
876 	if (Debug) {
877 		printf("getnetconfigent success\n");
878 	}
879 
880 	if ((rv = netdir_options(udpnconf, ND_SET_RESERVEDPORT, clfd,
881 	    (char *)NULL)) == -1) {
882 		if (Debug) {
883 			printf("netdir_options fails rv=%d\n", rv);
884 		}
885 
886 		errprintf(NULL, netdir_sperror());
887 		return (-1);
888 	}
889 
890 	if (Debug)
891 		printf("netdir_options success rv = %d\n", rv);
892 
893 	freenetconfigent(udpnconf);
894 	return (0);
895 }
896