1 /* 2 * Copyright (c) 1980, 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980, 1989 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)mount.c 5.43 (Berkeley) 12/04/90"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/file.h> 20 #include <sys/time.h> 21 #include <sys/wait.h> 22 #include <sys/errno.h> 23 #include <sys/signal.h> 24 #include <sys/mount.h> 25 #ifdef NFS 26 #include <sys/socket.h> 27 #include <sys/socketvar.h> 28 #include <netdb.h> 29 #include <rpc/rpc.h> 30 #include <rpc/pmap_clnt.h> 31 #include <rpc/pmap_prot.h> 32 #include <nfs/rpcv2.h> 33 #include <nfs/nfsv2.h> 34 #include <nfs/nfs.h> 35 #endif 36 #include <fstab.h> 37 #include <string.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include "pathnames.h" 41 42 #define DEFAULT_ROOTUID -2 43 44 #define BADTYPE(type) \ 45 (strcmp(type, FSTAB_RO) && strcmp(type, FSTAB_RW) && \ 46 strcmp(type, FSTAB_RQ)) 47 #define SETTYPE(type) \ 48 (!strcmp(type, FSTAB_RW) || !strcmp(type, FSTAB_RQ)) 49 50 int fake, verbose, updateflg, mnttype; 51 char *mntname, **envp; 52 char **vfslist, **makevfslist(); 53 54 #ifdef NFS 55 int xdr_dir(), xdr_fh(); 56 char *getnfsargs(); 57 struct nfs_args nfsdefargs = { 58 (struct sockaddr *)0, 59 SOCK_DGRAM, 60 0, 61 (nfsv2fh_t *)0, 62 0, 63 NFS_WSIZE, 64 NFS_RSIZE, 65 NFS_TIMEO, 66 NFS_RETRANS, 67 (char *)0, 68 }; 69 70 struct nfhret { 71 u_long stat; 72 nfsv2fh_t nfh; 73 }; 74 #define DEF_RETRY 10000 75 int retrycnt; 76 #define BGRND 1 77 #define ISBGRND 2 78 int opflags = 0; 79 #endif 80 81 main(argc, argv, arge) 82 int argc; 83 char **argv; 84 char **arge; 85 { 86 extern char *optarg; 87 extern int optind; 88 register struct fstab *fs; 89 int all, ch, rval, flags, ret, pid, i; 90 long mntsize; 91 struct statfs *mntbuf, *getmntpt(); 92 char *type, *options = NULL; 93 FILE *pidfile; 94 95 envp = arge; 96 all = 0; 97 type = NULL; 98 mnttype = MOUNT_UFS; 99 mntname = "ufs"; 100 while ((ch = getopt(argc, argv, "afrwuvt:o:")) != EOF) 101 switch((char)ch) { 102 case 'a': 103 all = 1; 104 break; 105 case 'f': 106 fake = 1; 107 break; 108 case 'r': 109 type = FSTAB_RO; 110 break; 111 case 'u': 112 updateflg = MNT_UPDATE; 113 break; 114 case 'v': 115 verbose = 1; 116 break; 117 case 'w': 118 type = FSTAB_RW; 119 break; 120 case 'o': 121 options = optarg; 122 break; 123 case 't': 124 vfslist = makevfslist(optarg); 125 mnttype = getmnttype(optarg); 126 break; 127 case '?': 128 default: 129 usage(); 130 /* NOTREACHED */ 131 } 132 argc -= optind; 133 argv += optind; 134 135 /* NOSTRICT */ 136 137 if (all) { 138 rval = 0; 139 while (fs = getfsent()) { 140 if (BADTYPE(fs->fs_type)) 141 continue; 142 if (badvfsname(fs->fs_vfstype, vfslist)) 143 continue; 144 /* `/' is special, it's always mounted */ 145 if (!strcmp(fs->fs_file, "/")) 146 flags = MNT_UPDATE; 147 else 148 flags = updateflg; 149 mnttype = getmnttype(fs->fs_vfstype); 150 rval |= mountfs(fs->fs_spec, fs->fs_file, flags, 151 type, options, fs->fs_mntops); 152 } 153 exit(rval); 154 } 155 156 if (argc == 0) { 157 if (verbose || fake || type) 158 usage(); 159 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { 160 (void) fprintf(stderr, 161 "mount: cannot get mount information\n"); 162 exit(1); 163 } 164 for (i = 0; i < mntsize; i++) { 165 if (badvfstype(mntbuf[i].f_type, vfslist)) 166 continue; 167 prmount(mntbuf[i].f_mntfromname, mntbuf[i].f_mntonname, 168 mntbuf[i].f_flags); 169 } 170 exit(0); 171 } 172 173 if (argc == 1 && updateflg) { 174 if ((mntbuf = getmntpt(*argv)) == NULL) { 175 (void) fprintf(stderr, 176 "mount: unknown special file or file system %s.\n", 177 *argv); 178 exit(1); 179 } 180 mnttype = mntbuf->f_type; 181 if (!strcmp(mntbuf->f_mntfromname, "root_device")) { 182 fs = getfsfile("/"); 183 strcpy(mntbuf->f_mntfromname, fs->fs_spec); 184 } 185 ret = mountfs(mntbuf->f_mntfromname, mntbuf->f_mntonname, 186 updateflg, type, options, (char *)NULL); 187 } else if (argc == 1) { 188 if (!(fs = getfsfile(*argv)) && !(fs = getfsspec(*argv))) { 189 (void) fprintf(stderr, 190 "mount: unknown special file or file system %s.\n", 191 *argv); 192 exit(1); 193 } 194 if (BADTYPE(fs->fs_type)) { 195 (void) fprintf(stderr, 196 "mount: %s has unknown file system type.\n", *argv); 197 exit(1); 198 } 199 mnttype = getmnttype(fs->fs_vfstype); 200 ret = mountfs(fs->fs_spec, fs->fs_file, updateflg, 201 type, options, fs->fs_mntops); 202 } else if (argc != 2) { 203 usage(); 204 ret = 1; 205 } else { 206 /* 207 * If -t flag has not been specified, and spec 208 * contains either a ':' or a '@' then assume that 209 * an NFS filesystem is being specified ala Sun. 210 */ 211 if (vfslist == (char **)0 && 212 (index(argv[0], ':') || index(argv[0], '@'))) 213 mnttype = MOUNT_NFS; 214 ret = mountfs(argv[0], argv[1], updateflg, type, options, 215 (char *)NULL); 216 } 217 if ((pidfile = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 218 pid = 0; 219 fscanf(pidfile, "%d", &pid); 220 fclose(pidfile); 221 if (pid > 0) 222 kill(pid, SIGHUP); 223 } 224 exit (ret); 225 } 226 227 mountfs(spec, name, flags, type, options, mntopts) 228 char *spec, *name, *type, *options, *mntopts; 229 int flags; 230 { 231 union wait status; 232 pid_t pid; 233 int argc, i; 234 struct ufs_args args; 235 struct nfs_args nfsargs; 236 char *argp, *argv[50]; 237 char execname[MAXPATHLEN + 1], flagval[12]; 238 239 nfsargs = nfsdefargs; 240 if (mntopts) 241 getstdopts(mntopts, &flags); 242 if (options) 243 getstdopts(options, &flags); 244 if (type) 245 getstdopts(type, &flags); 246 switch (mnttype) { 247 case MOUNT_UFS: 248 if (mntopts) 249 getufsopts(mntopts, &flags); 250 if (options) 251 getufsopts(options, &flags); 252 args.fspec = spec; 253 args.exroot = DEFAULT_ROOTUID; 254 if (flags & MNT_RDONLY) 255 args.exflags = MNT_EXRDONLY; 256 else 257 args.exflags = 0; 258 argp = (caddr_t)&args; 259 break; 260 261 #ifdef NFS 262 case MOUNT_NFS: 263 retrycnt = DEF_RETRY; 264 if (mntopts) 265 getnfsopts(mntopts, &nfsargs, &opflags, &retrycnt); 266 if (options) 267 getnfsopts(options, &nfsargs, &opflags, &retrycnt); 268 if (argp = getnfsargs(spec, &nfsargs)) 269 break; 270 return (1); 271 #endif /* NFS */ 272 273 case MOUNT_MFS: 274 default: 275 argv[0] = mntname; 276 argc = 1; 277 if (flags) { 278 argv[argc++] = "-F"; 279 sprintf(flagval, "%d", flags); 280 argv[argc++] = flagval; 281 } 282 if (mntopts) 283 argc += getexecopts(mntopts, &argv[argc]); 284 if (options) 285 argc += getexecopts(options, &argv[argc]); 286 argv[argc++] = spec; 287 argv[argc++] = name; 288 argv[argc++] = NULL; 289 sprintf(execname, "%s/mount_%s", _PATH_EXECDIR, mntname); 290 if (verbose) { 291 (void)printf("exec: %s", execname); 292 for (i = 1; i < argc - 1; i++) 293 (void)printf(" %s", argv[i]); 294 (void)printf("\n"); 295 } 296 if (fake) 297 break; 298 if (pid = vfork()) { 299 if (pid == -1) { 300 perror("mount: vfork starting file system"); 301 return (1); 302 } 303 if (waitpid(pid, &status, 0) != -1 && 304 WIFEXITED(status) && 305 WEXITSTATUS(status) != 0) 306 return (WEXITSTATUS(status)); 307 spec = mntname; 308 goto out; 309 } 310 execve(execname, argv, envp); 311 (void) fprintf(stderr, "mount: cannot exec %s for %s: ", 312 execname, name); 313 perror((char *)NULL); 314 exit (1); 315 /* NOTREACHED */ 316 317 } 318 if (!fake && mount(mnttype, name, flags, argp)) { 319 if (opflags & ISBGRND) 320 exit(1); 321 (void) fprintf(stderr, "%s on %s: ", spec, name); 322 switch (errno) { 323 case EMFILE: 324 (void) fprintf(stderr, "Mount table full\n"); 325 break; 326 case EINVAL: 327 if (flags & MNT_UPDATE) 328 (void) fprintf(stderr, "Specified device %s\n", 329 "does not match mounted device"); 330 else if (mnttype == MOUNT_UFS) 331 (void) fprintf(stderr, "Bogus super block\n"); 332 else 333 perror((char *)NULL); 334 break; 335 default: 336 perror((char *)NULL); 337 break; 338 } 339 return(1); 340 } 341 342 out: 343 if (verbose) 344 prmount(spec, name, flags); 345 346 if (opflags & ISBGRND) 347 exit(1); 348 return(0); 349 } 350 351 static 352 prmount(spec, name, flags) 353 char *spec, *name; 354 register short flags; 355 { 356 register int first; 357 358 if (opflags & ISBGRND) 359 return; 360 (void)printf("%s on %s", spec, name); 361 if (!(flags & MNT_VISFLAGMASK)) { 362 (void)printf("\n"); 363 return; 364 } 365 first = 0; 366 #define PR(msg) (void)printf("%s%s", !first++ ? " (" : ", ", msg) 367 if (flags & MNT_RDONLY) 368 PR("read-only"); 369 if (flags & MNT_NOEXEC) 370 PR("noexec"); 371 if (flags & MNT_NOSUID) 372 PR("nosuid"); 373 if (flags & MNT_NODEV) 374 PR("nodev"); 375 if (flags & MNT_SYNCHRONOUS) 376 PR("synchronous"); 377 if (flags & MNT_QUOTA) 378 PR("with quotas"); 379 if (flags & MNT_LOCAL) 380 PR("local"); 381 if (flags & MNT_EXPORTED) 382 if (flags & MNT_EXRDONLY) 383 PR("NFS exported read-only"); 384 else 385 PR("NFS exported"); 386 (void)printf(")\n"); 387 } 388 389 getmnttype(fstype) 390 char *fstype; 391 { 392 393 mntname = fstype; 394 if (!strcmp(fstype, "ufs")) 395 return (MOUNT_UFS); 396 if (!strcmp(fstype, "nfs")) 397 return (MOUNT_NFS); 398 if (!strcmp(fstype, "mfs")) 399 return (MOUNT_MFS); 400 return (0); 401 } 402 403 usage() 404 { 405 406 (void) fprintf(stderr, 407 "usage:\n mount %s %s\n mount %s\n mount %s\n", 408 "[ -frwu ] [ -t nfs | ufs | external_type ]", 409 "[ -o options ] special node", 410 "[ -afrwu ] [ -t nfs | ufs | external_type ]", 411 "[ -frwu ] special | node"); 412 exit(1); 413 } 414 415 getstdopts(options, flagp) 416 char *options; 417 int *flagp; 418 { 419 register char *opt; 420 int negative; 421 char optbuf[BUFSIZ]; 422 423 (void)strcpy(optbuf, options); 424 for (opt = strtok(optbuf, ","); opt; opt = strtok((char *)NULL, ",")) { 425 if (opt[0] == 'n' && opt[1] == 'o') { 426 negative++; 427 opt += 2; 428 } else { 429 negative = 0; 430 } 431 if (!negative && !strcasecmp(opt, FSTAB_RO)) { 432 *flagp |= MNT_RDONLY; 433 continue; 434 } 435 if (!negative && !strcasecmp(opt, FSTAB_RW)) { 436 *flagp &= ~MNT_RDONLY; 437 continue; 438 } 439 if (!strcasecmp(opt, "exec")) { 440 if (negative) 441 *flagp |= MNT_NOEXEC; 442 else 443 *flagp &= ~MNT_NOEXEC; 444 continue; 445 } 446 if (!strcasecmp(opt, "suid")) { 447 if (negative) 448 *flagp |= MNT_NOSUID; 449 else 450 *flagp &= ~MNT_NOSUID; 451 continue; 452 } 453 if (!strcasecmp(opt, "dev")) { 454 if (negative) 455 *flagp |= MNT_NODEV; 456 else 457 *flagp &= ~MNT_NODEV; 458 continue; 459 } 460 if (!strcasecmp(opt, "synchronous")) { 461 if (!negative) 462 *flagp |= MNT_SYNCHRONOUS; 463 else 464 *flagp &= ~MNT_SYNCHRONOUS; 465 continue; 466 } 467 } 468 } 469 470 /* ARGSUSED */ 471 getufsopts(options, flagp) 472 char *options; 473 int *flagp; 474 { 475 return; 476 } 477 478 getexecopts(options, argv) 479 char *options; 480 char **argv; 481 { 482 register int argc = 0; 483 register char *opt; 484 485 for (opt = strtok(options, ","); opt; opt = strtok((char *)NULL, ",")) { 486 if (opt[0] != '-') 487 continue; 488 argv[argc++] = opt; 489 if (opt[2] == '\0' || opt[2] != '=') 490 continue; 491 opt[2] = '\0'; 492 argv[argc++] = &opt[3]; 493 } 494 return (argc); 495 } 496 497 struct statfs * 498 getmntpt(name) 499 char *name; 500 { 501 long mntsize; 502 register long i; 503 struct statfs *mntbuf; 504 505 mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 506 for (i = 0; i < mntsize; i++) { 507 if (!strcmp(mntbuf[i].f_mntfromname, name) || 508 !strcmp(mntbuf[i].f_mntonname, name)) 509 return (&mntbuf[i]); 510 } 511 return ((struct statfs *)0); 512 } 513 514 static int skipvfs; 515 516 badvfstype(vfstype, vfslist) 517 short vfstype; 518 char **vfslist; 519 { 520 521 if (vfslist == 0) 522 return(0); 523 while (*vfslist) { 524 if (vfstype == getmnttype(*vfslist)) 525 return(skipvfs); 526 vfslist++; 527 } 528 return (!skipvfs); 529 } 530 531 badvfsname(vfsname, vfslist) 532 char *vfsname; 533 char **vfslist; 534 { 535 536 if (vfslist == 0) 537 return(0); 538 while (*vfslist) { 539 if (strcmp(vfsname, *vfslist) == 0) 540 return(skipvfs); 541 vfslist++; 542 } 543 return (!skipvfs); 544 } 545 546 char ** 547 makevfslist(fslist) 548 char *fslist; 549 { 550 register char **av, *nextcp; 551 register int i; 552 553 if (fslist == NULL) 554 return (NULL); 555 if (fslist[0] == 'n' && fslist[1] == 'o') { 556 fslist += 2; 557 skipvfs = 1; 558 } 559 for (i = 0, nextcp = fslist; *nextcp; nextcp++) 560 if (*nextcp == ',') 561 i++; 562 av = (char **)malloc((size_t)(i+2) * sizeof(char *)); 563 if (av == NULL) 564 return (NULL); 565 nextcp = fslist; 566 i = 0; 567 av[i++] = nextcp; 568 while (nextcp = index(nextcp, ',')) { 569 *nextcp++ = '\0'; 570 av[i++] = nextcp; 571 } 572 av[i++] = 0; 573 return (av); 574 } 575 576 #ifdef NFS 577 exclusive(a, b) 578 char *a, *b; 579 { 580 581 (void) fprintf(stderr, "mount: Options %s, %s mutually exclusive\n", 582 a, b); 583 exit(1); 584 } 585 586 /* 587 * Handle the getoption arg. 588 * Essentially update "opflags", "retrycnt" and "nfsargs" 589 */ 590 getnfsopts(optarg, nfsargsp, opflagsp, retrycntp) 591 char *optarg; 592 register struct nfs_args *nfsargsp; 593 int *opflagsp; 594 int *retrycntp; 595 { 596 register char *cp, *nextcp; 597 int num; 598 char *nump; 599 600 for (cp = optarg; cp != NULL && *cp != '\0'; cp = nextcp) { 601 if ((nextcp = index(cp, ',')) != NULL) 602 *nextcp++ = '\0'; 603 if ((nump = index(cp, '=')) != NULL) { 604 *nump++ = '\0'; 605 num = atoi(nump); 606 } else 607 num = -1; 608 /* 609 * Just test for a string match and do it 610 */ 611 if (!strcmp(cp, "bg")) { 612 *opflagsp |= BGRND; 613 } else if (!strcmp(cp, "soft")) { 614 if (nfsargsp->flags & NFSMNT_SPONGY) 615 exclusive("soft, spongy"); 616 nfsargsp->flags |= NFSMNT_SOFT; 617 } else if (!strcmp(cp, "spongy")) { 618 if (nfsargsp->flags & NFSMNT_SOFT) 619 exclusive("soft, spongy"); 620 nfsargsp->flags |= NFSMNT_SPONGY; 621 } else if (!strcmp(cp, "compress")) { 622 nfsargsp->flags |= NFSMNT_COMPRESS; 623 } else if (!strcmp(cp, "intr")) { 624 nfsargsp->flags |= NFSMNT_INT; 625 } else if (!strcmp(cp, "tcp")) { 626 nfsargsp->sotype = SOCK_STREAM; 627 } else if (!strcmp(cp, "noconn")) { 628 nfsargsp->flags |= NFSMNT_NOCONN; 629 } else if (!strcmp(cp, "retry") && num > 0) { 630 *retrycntp = num; 631 } else if (!strcmp(cp, "rsize") && num > 0) { 632 nfsargsp->rsize = num; 633 nfsargsp->flags |= NFSMNT_RSIZE; 634 } else if (!strcmp(cp, "wsize") && num > 0) { 635 nfsargsp->wsize = num; 636 nfsargsp->flags |= NFSMNT_WSIZE; 637 } else if (!strcmp(cp, "timeo") && num > 0) { 638 nfsargsp->timeo = num; 639 nfsargsp->flags |= NFSMNT_TIMEO; 640 } else if (!strcmp(cp, "retrans") && num > 0) { 641 nfsargsp->retrans = num; 642 nfsargsp->flags |= NFSMNT_RETRANS; 643 } 644 } 645 if (nfsargsp->sotype == SOCK_DGRAM) { 646 if (nfsargsp->rsize > NFS_MAXDGRAMDATA) 647 nfsargsp->rsize = NFS_MAXDGRAMDATA; 648 if (nfsargsp->wsize > NFS_MAXDGRAMDATA) 649 nfsargsp->wsize = NFS_MAXDGRAMDATA; 650 } 651 } 652 653 char * 654 getnfsargs(spec, nfsargsp) 655 char *spec; 656 struct nfs_args *nfsargsp; 657 { 658 register CLIENT *clp; 659 struct hostent *hp; 660 static struct sockaddr_in saddr; 661 struct timeval pertry, try; 662 enum clnt_stat clnt_stat; 663 int so = RPC_ANYSOCK; 664 char *fsp, *hostp, *delimp; 665 u_short tport; 666 static struct nfhret nfhret; 667 static char nam[MNAMELEN + 1]; 668 char buf[MAXPATHLEN + 1]; 669 670 strncpy(buf, spec, MAXPATHLEN); 671 buf[MAXPATHLEN] = '\0'; 672 strncpy(nam, spec, MNAMELEN); 673 nam[MNAMELEN] = '\0'; 674 if ((delimp = index(buf, '@')) != NULL) { 675 hostp = delimp + 1; 676 fsp = buf; 677 } else if ((delimp = index(buf, ':')) != NULL) { 678 hostp = buf; 679 fsp = delimp + 1; 680 } else { 681 (void) fprintf(stderr, 682 "mount: No <host>:<dirpath> or <dirpath>@<host> spec\n"); 683 return (0); 684 } 685 *delimp = '\0'; 686 if ((hp = gethostbyname(hostp)) == NULL) { 687 (void) fprintf(stderr, "mount: Can't get net id for host\n"); 688 return (0); 689 } 690 bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length); 691 nfhret.stat = ETIMEDOUT; /* Mark not yet successful */ 692 while (retrycnt > 0) { 693 saddr.sin_family = AF_INET; 694 saddr.sin_port = htons(PMAPPORT); 695 if ((tport = pmap_getport(&saddr, RPCPROG_NFS, 696 NFS_VER2, IPPROTO_UDP)) == 0) { 697 if ((opflags & ISBGRND) == 0) 698 clnt_pcreateerror("NFS Portmap"); 699 } else { 700 saddr.sin_port = 0; 701 pertry.tv_sec = 10; 702 pertry.tv_usec = 0; 703 if ((clp = clntudp_create(&saddr, RPCPROG_MNT, 704 RPCMNT_VER1, pertry, &so)) == NULL) { 705 if ((opflags & ISBGRND) == 0) 706 clnt_pcreateerror("Cannot MNT PRC"); 707 } else { 708 clp->cl_auth = authunix_create_default(); 709 try.tv_sec = 10; 710 try.tv_usec = 0; 711 clnt_stat = clnt_call(clp, RPCMNT_MOUNT, 712 xdr_dir, fsp, xdr_fh, &nfhret, try); 713 if (clnt_stat != RPC_SUCCESS) { 714 if ((opflags & ISBGRND) == 0) 715 clnt_perror(clp, "Bad MNT RPC"); 716 } else { 717 auth_destroy(clp->cl_auth); 718 clnt_destroy(clp); 719 retrycnt = 0; 720 } 721 } 722 } 723 if (--retrycnt > 0) { 724 if (opflags & BGRND) { 725 opflags &= ~BGRND; 726 if (fork()) 727 return (0); 728 else 729 opflags |= ISBGRND; 730 } 731 sleep(10); 732 } 733 } 734 if (nfhret.stat) { 735 if (opflags & ISBGRND) 736 exit(1); 737 (void) fprintf(stderr, "Mount RPC error on %s: ", spec); 738 errno = nfhret.stat; 739 perror((char *)NULL); 740 return (0); 741 } 742 saddr.sin_port = htons(tport); 743 nfsargsp->addr = (struct sockaddr *) &saddr; 744 nfsargsp->fh = &nfhret.nfh; 745 nfsargsp->hostname = nam; 746 return ((caddr_t)nfsargsp); 747 } 748 749 /* 750 * xdr routines for mount rpc's 751 */ 752 xdr_dir(xdrsp, dirp) 753 XDR *xdrsp; 754 char *dirp; 755 { 756 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 757 } 758 759 xdr_fh(xdrsp, np) 760 XDR *xdrsp; 761 struct nfhret *np; 762 { 763 if (!xdr_u_long(xdrsp, &(np->stat))) 764 return (0); 765 if (np->stat) 766 return (1); 767 return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH)); 768 } 769 #endif /* NFS */ 770