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