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
mount_nfs(char * fsname,char * dir,char * error)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
umount_nfs(char * fsname,char * dir)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 *
dupmnttab(struct mnttab * mnt)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
freemnttab(struct mnttab * mnt)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
freemntlist(struct mntlist * mntl)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 *
parsefs(char * fullname,char * error)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 *
get_addr(char * hostname,int prog,int vers,struct netconfig ** nconfp)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 *
get_knconf(struct netconfig * nconf)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
free_knconf(struct knetconfig * k)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
netbuf_free(struct netbuf * nb)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
pingnfs(char * hostname,rpcvers_t * versp)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
bindudp_resvport(CLIENT * client)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