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