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