nfs.c revision 307203
1/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 2 3/*- 4 * Copyright (c) 1993 John Brezak 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: stable/10/lib/libstand/nfs.c 307203 2016-10-13 08:09:40Z sephe $"); 33 34#include <sys/param.h> 35#include <sys/time.h> 36#include <sys/socket.h> 37#include <sys/stat.h> 38#include <string.h> 39#include <stddef.h> 40 41#include <netinet/in.h> 42#include <netinet/in_systm.h> 43 44#include "rpcv2.h" 45#include "nfsv2.h" 46 47#include "stand.h" 48#include "net.h" 49#include "netif.h" 50#include "rpc.h" 51 52#define NFS_DEBUGxx 53 54#define NFSREAD_MIN_SIZE 1024 55#define NFSREAD_MAX_SIZE 4096 56 57/* Define our own NFS attributes without NQNFS stuff. */ 58#ifdef OLD_NFSV2 59struct nfsv2_fattrs { 60 n_long fa_type; 61 n_long fa_mode; 62 n_long fa_nlink; 63 n_long fa_uid; 64 n_long fa_gid; 65 n_long fa_size; 66 n_long fa_blocksize; 67 n_long fa_rdev; 68 n_long fa_blocks; 69 n_long fa_fsid; 70 n_long fa_fileid; 71 struct nfsv2_time fa_atime; 72 struct nfsv2_time fa_mtime; 73 struct nfsv2_time fa_ctime; 74}; 75 76struct nfs_read_args { 77 u_char fh[NFS_FHSIZE]; 78 n_long off; 79 n_long len; 80 n_long xxx; /* XXX what's this for? */ 81}; 82 83/* Data part of nfs rpc reply (also the largest thing we receive) */ 84struct nfs_read_repl { 85 n_long errno; 86 struct nfsv2_fattrs fa; 87 n_long count; 88 u_char data[NFSREAD_MAX_SIZE]; 89}; 90 91#ifndef NFS_NOSYMLINK 92struct nfs_readlnk_repl { 93 n_long errno; 94 n_long len; 95 char path[NFS_MAXPATHLEN]; 96}; 97#endif 98 99struct nfs_readdir_args { 100 u_char fh[NFS_FHSIZE]; 101 n_long cookie; 102 n_long count; 103}; 104 105struct nfs_readdir_data { 106 n_long fileid; 107 n_long len; 108 char name[0]; 109}; 110 111struct nfs_readdir_off { 112 n_long cookie; 113 n_long follows; 114}; 115 116struct nfs_iodesc { 117 struct iodesc *iodesc; 118 off_t off; 119 u_char fh[NFS_FHSIZE]; 120 struct nfsv2_fattrs fa; /* all in network order */ 121}; 122#else /* !OLD_NFSV2 */ 123 124/* NFSv3 definitions */ 125#define NFS_V3MAXFHSIZE 64 126#define NFS_VER3 3 127#define RPCMNT_VER3 3 128#define NFSPROCV3_LOOKUP 3 129#define NFSPROCV3_READLINK 5 130#define NFSPROCV3_READ 6 131#define NFSPROCV3_READDIR 16 132 133typedef struct { 134 uint32_t val[2]; 135} n_quad; 136 137struct nfsv3_time { 138 uint32_t nfs_sec; 139 uint32_t nfs_nsec; 140}; 141 142struct nfsv3_fattrs { 143 uint32_t fa_type; 144 uint32_t fa_mode; 145 uint32_t fa_nlink; 146 uint32_t fa_uid; 147 uint32_t fa_gid; 148 n_quad fa_size; 149 n_quad fa_used; 150 n_quad fa_rdev; 151 n_quad fa_fsid; 152 n_quad fa_fileid; 153 struct nfsv3_time fa_atime; 154 struct nfsv3_time fa_mtime; 155 struct nfsv3_time fa_ctime; 156}; 157 158/* 159 * For NFSv3, the file handle is variable in size, so most fixed sized 160 * structures for arguments won't work. For most cases, a structure 161 * that starts with any fixed size section is followed by an array 162 * that covers the maximum size required. 163 */ 164struct nfsv3_readdir_repl { 165 uint32_t errno; 166 uint32_t ok; 167 struct nfsv3_fattrs fa; 168 uint32_t cookiev0; 169 uint32_t cookiev1; 170}; 171 172struct nfsv3_readdir_entry { 173 uint32_t follows; 174 uint32_t fid0; 175 uint32_t fid1; 176 uint32_t len; 177 uint32_t nameplus[0]; 178}; 179 180struct nfs_iodesc { 181 struct iodesc *iodesc; 182 off_t off; 183 uint32_t fhsize; 184 u_char fh[NFS_V3MAXFHSIZE]; 185 struct nfsv3_fattrs fa; /* all in network order */ 186 uint64_t cookie; 187}; 188#endif /* OLD_NFSV2 */ 189 190/* 191 * XXX interactions with tftp? See nfswrapper.c for a confusing 192 * issue. 193 */ 194int nfs_open(const char *path, struct open_file *f); 195static int nfs_close(struct open_file *f); 196static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 197static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 198static off_t nfs_seek(struct open_file *f, off_t offset, int where); 199static int nfs_stat(struct open_file *f, struct stat *sb); 200static int nfs_readdir(struct open_file *f, struct dirent *d); 201 202struct nfs_iodesc nfs_root_node; 203 204struct fs_ops nfs_fsops = { 205 "nfs", 206 nfs_open, 207 nfs_close, 208 nfs_read, 209 nfs_write, 210 nfs_seek, 211 nfs_stat, 212 nfs_readdir 213}; 214 215static int nfs_read_size = NFSREAD_MIN_SIZE; 216 217#ifdef OLD_NFSV2 218/* 219 * Fetch the root file handle (call mount daemon) 220 * Return zero or error number. 221 */ 222int 223nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) 224{ 225 int len; 226 struct args { 227 n_long len; 228 char path[FNAME_SIZE]; 229 } *args; 230 struct repl { 231 n_long errno; 232 u_char fh[NFS_FHSIZE]; 233 } *repl; 234 struct { 235 n_long h[RPC_HEADER_WORDS]; 236 struct args d; 237 } sdata; 238 struct { 239 n_long h[RPC_HEADER_WORDS]; 240 struct repl d; 241 } rdata; 242 size_t cc; 243 244#ifdef NFS_DEBUG 245 if (debug) 246 printf("nfs_getrootfh: %s\n", path); 247#endif 248 249 args = &sdata.d; 250 repl = &rdata.d; 251 252 bzero(args, sizeof(*args)); 253 len = strlen(path); 254 if (len > sizeof(args->path)) 255 len = sizeof(args->path); 256 args->len = htonl(len); 257 bcopy(path, args->path, len); 258 len = 4 + roundup(len, 4); 259 260 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 261 args, len, repl, sizeof(*repl)); 262 if (cc == -1) { 263 /* errno was set by rpc_call */ 264 return (errno); 265 } 266 if (cc < 4) 267 return (EBADRPC); 268 if (repl->errno) 269 return (ntohl(repl->errno)); 270 bcopy(repl->fh, fhp, sizeof(repl->fh)); 271 272 /* 273 * Improve boot performance over NFS 274 */ 275 if (getenv("nfs.read_size") != NULL) 276 nfs_read_size = strtol(getenv("nfs.read_size"), NULL, 0); 277 if (nfs_read_size < NFSREAD_MIN_SIZE) 278 nfs_read_size = NFSREAD_MIN_SIZE; 279 if (nfs_read_size > NFSREAD_MAX_SIZE) 280 nfs_read_size = NFSREAD_MAX_SIZE; 281 282 return (0); 283} 284 285/* 286 * Lookup a file. Store handle and attributes. 287 * Return zero or error number. 288 */ 289int 290nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 291{ 292 int len, rlen; 293 struct args { 294 u_char fh[NFS_FHSIZE]; 295 n_long len; 296 char name[FNAME_SIZE]; 297 } *args; 298 struct repl { 299 n_long errno; 300 u_char fh[NFS_FHSIZE]; 301 struct nfsv2_fattrs fa; 302 } *repl; 303 struct { 304 n_long h[RPC_HEADER_WORDS]; 305 struct args d; 306 } sdata; 307 struct { 308 n_long h[RPC_HEADER_WORDS]; 309 struct repl d; 310 } rdata; 311 ssize_t cc; 312 313#ifdef NFS_DEBUG 314 if (debug) 315 printf("lookupfh: called\n"); 316#endif 317 318 args = &sdata.d; 319 repl = &rdata.d; 320 321 bzero(args, sizeof(*args)); 322 bcopy(d->fh, args->fh, sizeof(args->fh)); 323 len = strlen(name); 324 if (len > sizeof(args->name)) 325 len = sizeof(args->name); 326 bcopy(name, args->name, len); 327 args->len = htonl(len); 328 len = 4 + roundup(len, 4); 329 len += NFS_FHSIZE; 330 331 rlen = sizeof(*repl); 332 333 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 334 args, len, repl, rlen); 335 if (cc == -1) 336 return (errno); /* XXX - from rpc_call */ 337 if (cc < 4) 338 return (EIO); 339 if (repl->errno) { 340 /* saerrno.h now matches NFS error numbers. */ 341 return (ntohl(repl->errno)); 342 } 343 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 344 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 345 return (0); 346} 347 348#ifndef NFS_NOSYMLINK 349/* 350 * Get the destination of a symbolic link. 351 */ 352int 353nfs_readlink(struct nfs_iodesc *d, char *buf) 354{ 355 struct { 356 n_long h[RPC_HEADER_WORDS]; 357 u_char fh[NFS_FHSIZE]; 358 } sdata; 359 struct { 360 n_long h[RPC_HEADER_WORDS]; 361 struct nfs_readlnk_repl d; 362 } rdata; 363 ssize_t cc; 364 365#ifdef NFS_DEBUG 366 if (debug) 367 printf("readlink: called\n"); 368#endif 369 370 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 371 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 372 sdata.fh, NFS_FHSIZE, 373 &rdata.d, sizeof(rdata.d)); 374 if (cc == -1) 375 return (errno); 376 377 if (cc < 4) 378 return (EIO); 379 380 if (rdata.d.errno) 381 return (ntohl(rdata.d.errno)); 382 383 rdata.d.len = ntohl(rdata.d.len); 384 if (rdata.d.len > NFS_MAXPATHLEN) 385 return (ENAMETOOLONG); 386 387 bcopy(rdata.d.path, buf, rdata.d.len); 388 buf[rdata.d.len] = 0; 389 return (0); 390} 391#endif 392 393/* 394 * Read data from a file. 395 * Return transfer count or -1 (and set errno) 396 */ 397ssize_t 398nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 399{ 400 struct nfs_read_args *args; 401 struct nfs_read_repl *repl; 402 struct { 403 n_long h[RPC_HEADER_WORDS]; 404 struct nfs_read_args d; 405 } sdata; 406 struct { 407 n_long h[RPC_HEADER_WORDS]; 408 struct nfs_read_repl d; 409 } rdata; 410 size_t cc; 411 long x; 412 int hlen, rlen; 413 414 args = &sdata.d; 415 repl = &rdata.d; 416 417 bcopy(d->fh, args->fh, NFS_FHSIZE); 418 args->off = htonl((n_long)off); 419 if (len > nfs_read_size) 420 len = nfs_read_size; 421 args->len = htonl((n_long)len); 422 args->xxx = htonl((n_long)0); 423 hlen = offsetof(struct nfs_read_rpl, data[0]); 424 425 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 426 args, sizeof(*args), 427 repl, sizeof(*repl)); 428 if (cc == -1) { 429 /* errno was already set by rpc_call */ 430 return (-1); 431 } 432 if (cc < hlen) { 433 errno = EBADRPC; 434 return (-1); 435 } 436 if (repl->errno) { 437 errno = ntohl(repl->errno); 438 return (-1); 439 } 440 rlen = cc - hlen; 441 x = ntohl(repl->count); 442 if (rlen < x) { 443 printf("nfsread: short packet, %d < %ld\n", rlen, x); 444 errno = EBADRPC; 445 return(-1); 446 } 447 bcopy(repl->data, addr, x); 448 return (x); 449} 450 451/* 452 * Open a file. 453 * return zero or error number 454 */ 455int 456nfs_open(const char *upath, struct open_file *f) 457{ 458 struct iodesc *desc; 459 struct nfs_iodesc *currfd; 460 char buf[2 * NFS_FHSIZE + 3]; 461 u_char *fh; 462 char *cp; 463 int i; 464#ifndef NFS_NOSYMLINK 465 struct nfs_iodesc *newfd; 466 struct nfsv2_fattrs *fa; 467 char *ncp; 468 int c; 469 char namebuf[NFS_MAXPATHLEN + 1]; 470 char linkbuf[NFS_MAXPATHLEN + 1]; 471 int nlinks = 0; 472#endif 473 int error; 474 char *path; 475 476#ifdef NFS_DEBUG 477 if (debug) 478 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 479#endif 480 if (!rootpath[0]) { 481 printf("no rootpath, no nfs\n"); 482 return (ENXIO); 483 } 484 485 /* 486 * This is silly - we should look at dv_type but that value is 487 * arch dependant and we can't use it here. 488 */ 489#ifndef __i386__ 490 if (strcmp(f->f_dev->dv_name, "net") != 0) 491 return(EINVAL); 492#else 493 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 494 return(EINVAL); 495#endif 496 497 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 498 return(EINVAL); 499 500 /* Bind to a reserved port. */ 501 desc->myport = htons(--rpc_port); 502 desc->destip = rootip; 503 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 504 return (error); 505 nfs_root_node.fa.fa_type = htonl(NFDIR); 506 nfs_root_node.fa.fa_mode = htonl(0755); 507 nfs_root_node.fa.fa_nlink = htonl(2); 508 nfs_root_node.iodesc = desc; 509 510 fh = &nfs_root_node.fh[0]; 511 buf[0] = 'X'; 512 cp = &buf[1]; 513 for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 514 sprintf(cp, "%02x", fh[i]); 515 sprintf(cp, "X"); 516 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 517 setenv("boot.nfsroot.path", rootpath, 1); 518 setenv("boot.nfsroot.nfshandle", buf, 1); 519 520 /* Allocate file system specific data structure */ 521 currfd = malloc(sizeof(*newfd)); 522 if (currfd == NULL) { 523 error = ENOMEM; 524 goto out; 525 } 526 527#ifndef NFS_NOSYMLINK 528 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 529 newfd = 0; 530 531 cp = path = strdup(upath); 532 if (path == NULL) { 533 error = ENOMEM; 534 goto out; 535 } 536 while (*cp) { 537 /* 538 * Remove extra separators 539 */ 540 while (*cp == '/') 541 cp++; 542 543 if (*cp == '\0') 544 break; 545 /* 546 * Check that current node is a directory. 547 */ 548 if (currfd->fa.fa_type != htonl(NFDIR)) { 549 error = ENOTDIR; 550 goto out; 551 } 552 553 /* allocate file system specific data structure */ 554 newfd = malloc(sizeof(*newfd)); 555 newfd->iodesc = currfd->iodesc; 556 557 /* 558 * Get next component of path name. 559 */ 560 { 561 int len = 0; 562 563 ncp = cp; 564 while ((c = *cp) != '\0' && c != '/') { 565 if (++len > NFS_MAXNAMLEN) { 566 error = ENOENT; 567 goto out; 568 } 569 cp++; 570 } 571 *cp = '\0'; 572 } 573 574 /* lookup a file handle */ 575 error = nfs_lookupfh(currfd, ncp, newfd); 576 *cp = c; 577 if (error) 578 goto out; 579 580 /* 581 * Check for symbolic link 582 */ 583 if (newfd->fa.fa_type == htonl(NFLNK)) { 584 int link_len, len; 585 586 error = nfs_readlink(newfd, linkbuf); 587 if (error) 588 goto out; 589 590 link_len = strlen(linkbuf); 591 len = strlen(cp); 592 593 if (link_len + len > MAXPATHLEN 594 || ++nlinks > MAXSYMLINKS) { 595 error = ENOENT; 596 goto out; 597 } 598 599 bcopy(cp, &namebuf[link_len], len + 1); 600 bcopy(linkbuf, namebuf, link_len); 601 602 /* 603 * If absolute pathname, restart at root. 604 * If relative pathname, restart at parent directory. 605 */ 606 cp = namebuf; 607 if (*cp == '/') 608 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 609 610 free(newfd); 611 newfd = 0; 612 613 continue; 614 } 615 616 free(currfd); 617 currfd = newfd; 618 newfd = 0; 619 } 620 621 error = 0; 622 623out: 624 free(newfd); 625 free(path); 626#else 627 currfd->iodesc = desc; 628 629 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 630#endif 631 if (!error) { 632 currfd->off = 0; 633 f->f_fsdata = (void *)currfd; 634 return (0); 635 } 636 637#ifdef NFS_DEBUG 638 if (debug) 639 printf("nfs_open: %s lookupfh failed: %s\n", 640 path, strerror(error)); 641#endif 642 free(currfd); 643 644 return (error); 645} 646 647int 648nfs_close(struct open_file *f) 649{ 650 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 651 652#ifdef NFS_DEBUG 653 if (debug) 654 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 655#endif 656 657 if (fp) 658 free(fp); 659 f->f_fsdata = (void *)0; 660 661 return (0); 662} 663 664/* 665 * read a portion of a file 666 */ 667int 668nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 669{ 670 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 671 ssize_t cc; 672 char *addr = buf; 673 674#ifdef NFS_DEBUG 675 if (debug) 676 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 677 (int)fp->off); 678#endif 679 while ((int)size > 0) { 680 twiddle(16); 681 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 682 /* XXX maybe should retry on certain errors */ 683 if (cc == -1) { 684#ifdef NFS_DEBUG 685 if (debug) 686 printf("nfs_read: read: %s", strerror(errno)); 687#endif 688 return (errno); /* XXX - from nfs_readdata */ 689 } 690 if (cc == 0) { 691#ifdef NFS_DEBUG 692 if (debug) 693 printf("nfs_read: hit EOF unexpectantly"); 694#endif 695 goto ret; 696 } 697 fp->off += cc; 698 addr += cc; 699 size -= cc; 700 } 701ret: 702 if (resid) 703 *resid = size; 704 705 return (0); 706} 707 708/* 709 * Not implemented. 710 */ 711int 712nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 713{ 714 return (EROFS); 715} 716 717off_t 718nfs_seek(struct open_file *f, off_t offset, int where) 719{ 720 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 721 n_long size = ntohl(d->fa.fa_size); 722 723 switch (where) { 724 case SEEK_SET: 725 d->off = offset; 726 break; 727 case SEEK_CUR: 728 d->off += offset; 729 break; 730 case SEEK_END: 731 d->off = size - offset; 732 break; 733 default: 734 errno = EINVAL; 735 return (-1); 736 } 737 738 return (d->off); 739} 740 741/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 742int nfs_stat_types[8] = { 743 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 744 745int 746nfs_stat(struct open_file *f, struct stat *sb) 747{ 748 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 749 n_long ftype, mode; 750 751 ftype = ntohl(fp->fa.fa_type); 752 mode = ntohl(fp->fa.fa_mode); 753 mode |= nfs_stat_types[ftype & 7]; 754 755 sb->st_mode = mode; 756 sb->st_nlink = ntohl(fp->fa.fa_nlink); 757 sb->st_uid = ntohl(fp->fa.fa_uid); 758 sb->st_gid = ntohl(fp->fa.fa_gid); 759 sb->st_size = ntohl(fp->fa.fa_size); 760 761 return (0); 762} 763 764static int 765nfs_readdir(struct open_file *f, struct dirent *d) 766{ 767 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 768 struct nfs_readdir_args *args; 769 struct nfs_readdir_data *rd; 770 struct nfs_readdir_off *roff = NULL; 771 static char *buf; 772 static struct nfs_iodesc *pfp = NULL; 773 static n_long cookie = 0; 774 size_t cc; 775 n_long eof; 776 777 struct { 778 n_long h[RPC_HEADER_WORDS]; 779 struct nfs_readdir_args d; 780 } sdata; 781 static struct { 782 n_long h[RPC_HEADER_WORDS]; 783 u_char d[NFS_READDIRSIZE]; 784 } rdata; 785 786 if (fp != pfp || fp->off != cookie) { 787 pfp = NULL; 788 refill: 789 args = &sdata.d; 790 bzero(args, sizeof(*args)); 791 792 bcopy(fp->fh, args->fh, NFS_FHSIZE); 793 args->cookie = htonl(fp->off); 794 args->count = htonl(NFS_READDIRSIZE); 795 796 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 797 args, sizeof(*args), 798 rdata.d, sizeof(rdata.d)); 799 buf = rdata.d; 800 roff = (struct nfs_readdir_off *)buf; 801 if (ntohl(roff->cookie) != 0) 802 return EIO; 803 pfp = fp; 804 cookie = fp->off; 805 } 806 roff = (struct nfs_readdir_off *)buf; 807 808 if (ntohl(roff->follows) == 0) { 809 eof = ntohl((roff+1)->cookie); 810 if (eof) { 811 cookie = 0; 812 return ENOENT; 813 } 814 goto refill; 815 } 816 817 buf += sizeof(struct nfs_readdir_off); 818 rd = (struct nfs_readdir_data *)buf; 819 d->d_namlen = ntohl(rd->len); 820 bcopy(rd->name, d->d_name, d->d_namlen); 821 d->d_name[d->d_namlen] = '\0'; 822 823 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 824 roff = (struct nfs_readdir_off *)buf; 825 fp->off = cookie = ntohl(roff->cookie); 826 return 0; 827} 828#else /* !OLD_NFSV2 */ 829/* 830 * Fetch the root file handle (call mount daemon) 831 * Return zero or error number. 832 */ 833int 834nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 835{ 836 int len; 837 struct args { 838 uint32_t len; 839 char path[FNAME_SIZE]; 840 } *args; 841 struct repl { 842 uint32_t errno; 843 uint32_t fhsize; 844 u_char fh[NFS_V3MAXFHSIZE]; 845 uint32_t authcnt; 846 uint32_t auth[7]; 847 } *repl; 848 struct { 849 uint32_t h[RPC_HEADER_WORDS]; 850 struct args d; 851 } sdata; 852 struct { 853 uint32_t h[RPC_HEADER_WORDS]; 854 struct repl d; 855 } rdata; 856 size_t cc; 857 858#ifdef NFS_DEBUG 859 if (debug) 860 printf("nfs_getrootfh: %s\n", path); 861#endif 862 863 args = &sdata.d; 864 repl = &rdata.d; 865 866 bzero(args, sizeof(*args)); 867 len = strlen(path); 868 if (len > sizeof(args->path)) 869 len = sizeof(args->path); 870 args->len = htonl(len); 871 bcopy(path, args->path, len); 872 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 873 874 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 875 args, len, repl, sizeof(*repl)); 876 if (cc == -1) 877 /* errno was set by rpc_call */ 878 return (errno); 879 if (cc < 2 * sizeof (uint32_t)) 880 return (EBADRPC); 881 if (repl->errno != 0) 882 return (ntohl(repl->errno)); 883 *fhlenp = ntohl(repl->fhsize); 884 bcopy(repl->fh, fhp, *fhlenp); 885 return (0); 886} 887 888/* 889 * Lookup a file. Store handle and attributes. 890 * Return zero or error number. 891 */ 892int 893nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 894{ 895 int len, rlen, pos; 896 struct args { 897 uint32_t fhsize; 898 uint32_t fhplusname[1 + 899 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 900 } *args; 901 struct repl { 902 uint32_t errno; 903 uint32_t fhsize; 904 uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 905 2 * (sizeof(uint32_t) + 906 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 907 } *repl; 908 struct { 909 uint32_t h[RPC_HEADER_WORDS]; 910 struct args d; 911 } sdata; 912 struct { 913 uint32_t h[RPC_HEADER_WORDS]; 914 struct repl d; 915 } rdata; 916 ssize_t cc; 917 918#ifdef NFS_DEBUG 919 if (debug) 920 printf("lookupfh: called\n"); 921#endif 922 923 args = &sdata.d; 924 repl = &rdata.d; 925 926 bzero(args, sizeof(*args)); 927 args->fhsize = htonl(d->fhsize); 928 bcopy(d->fh, args->fhplusname, d->fhsize); 929 len = strlen(name); 930 if (len > FNAME_SIZE) 931 len = FNAME_SIZE; 932 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 933 args->fhplusname[pos++] = htonl(len); 934 bcopy(name, &args->fhplusname[pos], len); 935 len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 936 roundup(len, sizeof(uint32_t)); 937 938 rlen = sizeof(*repl); 939 940 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 941 args, len, repl, rlen); 942 if (cc == -1) 943 return (errno); /* XXX - from rpc_call */ 944 if (cc < 2 * sizeof(uint32_t)) 945 return (EIO); 946 if (repl->errno != 0) 947 /* saerrno.h now matches NFS error numbers. */ 948 return (ntohl(repl->errno)); 949 newfd->fhsize = ntohl(repl->fhsize); 950 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 951 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 952 if (repl->fhplusattr[pos++] == 0) 953 return (EIO); 954 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 955 return (0); 956} 957 958#ifndef NFS_NOSYMLINK 959/* 960 * Get the destination of a symbolic link. 961 */ 962int 963nfs_readlink(struct nfs_iodesc *d, char *buf) 964{ 965 struct args { 966 uint32_t fhsize; 967 u_char fh[NFS_V3MAXFHSIZE]; 968 } *args; 969 struct repl { 970 uint32_t errno; 971 uint32_t ok; 972 struct nfsv3_fattrs fa; 973 uint32_t len; 974 u_char path[NFS_MAXPATHLEN]; 975 } *repl; 976 struct { 977 uint32_t h[RPC_HEADER_WORDS]; 978 struct args d; 979 } sdata; 980 struct { 981 uint32_t h[RPC_HEADER_WORDS]; 982 struct repl d; 983 } rdata; 984 ssize_t cc; 985 986#ifdef NFS_DEBUG 987 if (debug) 988 printf("readlink: called\n"); 989#endif 990 991 args = &sdata.d; 992 repl = &rdata.d; 993 994 bzero(args, sizeof(*args)); 995 args->fhsize = htonl(d->fhsize); 996 bcopy(d->fh, args->fh, d->fhsize); 997 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 998 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 999 repl, sizeof(*repl)); 1000 if (cc == -1) 1001 return (errno); 1002 1003 if (cc < 2 * sizeof(uint32_t)) 1004 return (EIO); 1005 1006 if (repl->errno != 0) 1007 return (ntohl(repl->errno)); 1008 1009 if (repl->ok == 0) 1010 return (EIO); 1011 1012 repl->len = ntohl(repl->len); 1013 if (repl->len > NFS_MAXPATHLEN) 1014 return (ENAMETOOLONG); 1015 1016 bcopy(repl->path, buf, repl->len); 1017 buf[repl->len] = 0; 1018 return (0); 1019} 1020#endif 1021 1022/* 1023 * Read data from a file. 1024 * Return transfer count or -1 (and set errno) 1025 */ 1026ssize_t 1027nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 1028{ 1029 struct args { 1030 uint32_t fhsize; 1031 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 1032 } *args; 1033 struct repl { 1034 uint32_t errno; 1035 uint32_t ok; 1036 struct nfsv3_fattrs fa; 1037 uint32_t count; 1038 uint32_t eof; 1039 uint32_t len; 1040 u_char data[NFSREAD_MAX_SIZE]; 1041 } *repl; 1042 struct { 1043 uint32_t h[RPC_HEADER_WORDS]; 1044 struct args d; 1045 } sdata; 1046 struct { 1047 uint32_t h[RPC_HEADER_WORDS]; 1048 struct repl d; 1049 } rdata; 1050 size_t cc; 1051 long x; 1052 int hlen, rlen, pos; 1053 1054 args = &sdata.d; 1055 repl = &rdata.d; 1056 1057 bzero(args, sizeof(*args)); 1058 args->fhsize = htonl(d->fhsize); 1059 bcopy(d->fh, args->fhoffcnt, d->fhsize); 1060 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1061 args->fhoffcnt[pos++] = 0; 1062 args->fhoffcnt[pos++] = htonl((uint32_t)off); 1063 if (len > nfs_read_size) 1064 len = nfs_read_size; 1065 args->fhoffcnt[pos] = htonl((uint32_t)len); 1066 hlen = offsetof(struct repl, data[0]); 1067 1068 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 1069 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1070 repl, sizeof(*repl)); 1071 if (cc == -1) 1072 /* errno was already set by rpc_call */ 1073 return (-1); 1074 if (cc < hlen) { 1075 errno = EBADRPC; 1076 return (-1); 1077 } 1078 if (repl->errno != 0) { 1079 errno = ntohl(repl->errno); 1080 return (-1); 1081 } 1082 rlen = cc - hlen; 1083 x = ntohl(repl->count); 1084 if (rlen < x) { 1085 printf("nfsread: short packet, %d < %ld\n", rlen, x); 1086 errno = EBADRPC; 1087 return (-1); 1088 } 1089 bcopy(repl->data, addr, x); 1090 return (x); 1091} 1092 1093/* 1094 * Open a file. 1095 * return zero or error number 1096 */ 1097int 1098nfs_open(const char *upath, struct open_file *f) 1099{ 1100 struct iodesc *desc; 1101 struct nfs_iodesc *currfd; 1102 char buf[2 * NFS_V3MAXFHSIZE + 3]; 1103 u_char *fh; 1104 char *cp; 1105 int i; 1106#ifndef NFS_NOSYMLINK 1107 struct nfs_iodesc *newfd; 1108 struct nfsv3_fattrs *fa; 1109 char *ncp; 1110 int c; 1111 char namebuf[NFS_MAXPATHLEN + 1]; 1112 char linkbuf[NFS_MAXPATHLEN + 1]; 1113 int nlinks = 0; 1114#endif 1115 int error; 1116 char *path; 1117 1118#ifdef NFS_DEBUG 1119 if (debug) 1120 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 1121#endif 1122 if (!rootpath[0]) { 1123 printf("no rootpath, no nfs\n"); 1124 return (ENXIO); 1125 } 1126 1127 /* 1128 * This is silly - we should look at dv_type but that value is 1129 * arch dependant and we can't use it here. 1130 */ 1131#ifndef __i386__ 1132 if (strcmp(f->f_dev->dv_name, "net") != 0) 1133 return (EINVAL); 1134#else 1135 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 1136 return (EINVAL); 1137#endif 1138 1139 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 1140 return (EINVAL); 1141 1142 /* Bind to a reserved port. */ 1143 desc->myport = htons(--rpc_port); 1144 desc->destip = rootip; 1145 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 1146 nfs_root_node.fh))) 1147 return (error); 1148 nfs_root_node.fa.fa_type = htonl(NFDIR); 1149 nfs_root_node.fa.fa_mode = htonl(0755); 1150 nfs_root_node.fa.fa_nlink = htonl(2); 1151 nfs_root_node.iodesc = desc; 1152 1153 fh = &nfs_root_node.fh[0]; 1154 buf[0] = 'X'; 1155 cp = &buf[1]; 1156 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 1157 sprintf(cp, "%02x", fh[i]); 1158 sprintf(cp, "X"); 1159 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 1160 setenv("boot.nfsroot.path", rootpath, 1); 1161 setenv("boot.nfsroot.nfshandle", buf, 1); 1162 sprintf(buf, "%d", nfs_root_node.fhsize); 1163 setenv("boot.nfsroot.nfshandlelen", buf, 1); 1164 1165 /* Allocate file system specific data structure */ 1166 currfd = malloc(sizeof(*newfd)); 1167 if (currfd == NULL) { 1168 error = ENOMEM; 1169 goto out; 1170 } 1171#ifndef NFS_NOSYMLINK 1172 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1173 newfd = 0; 1174 1175 cp = path = strdup(upath); 1176 if (path == NULL) { 1177 error = ENOMEM; 1178 goto out; 1179 } 1180 while (*cp) { 1181 /* 1182 * Remove extra separators 1183 */ 1184 while (*cp == '/') 1185 cp++; 1186 1187 if (*cp == '\0') 1188 break; 1189 /* 1190 * Check that current node is a directory. 1191 */ 1192 if (currfd->fa.fa_type != htonl(NFDIR)) { 1193 error = ENOTDIR; 1194 goto out; 1195 } 1196 1197 /* allocate file system specific data structure */ 1198 newfd = malloc(sizeof(*newfd)); 1199 if (newfd == NULL) { 1200 error = ENOMEM; 1201 goto out; 1202 } 1203 newfd->iodesc = currfd->iodesc; 1204 1205 /* 1206 * Get next component of path name. 1207 */ 1208 { 1209 int len = 0; 1210 1211 ncp = cp; 1212 while ((c = *cp) != '\0' && c != '/') { 1213 if (++len > NFS_MAXNAMLEN) { 1214 error = ENOENT; 1215 goto out; 1216 } 1217 cp++; 1218 } 1219 *cp = '\0'; 1220 } 1221 1222 /* lookup a file handle */ 1223 error = nfs_lookupfh(currfd, ncp, newfd); 1224 *cp = c; 1225 if (error) 1226 goto out; 1227 1228 /* 1229 * Check for symbolic link 1230 */ 1231 if (newfd->fa.fa_type == htonl(NFLNK)) { 1232 int link_len, len; 1233 1234 error = nfs_readlink(newfd, linkbuf); 1235 if (error) 1236 goto out; 1237 1238 link_len = strlen(linkbuf); 1239 len = strlen(cp); 1240 1241 if (link_len + len > MAXPATHLEN 1242 || ++nlinks > MAXSYMLINKS) { 1243 error = ENOENT; 1244 goto out; 1245 } 1246 1247 bcopy(cp, &namebuf[link_len], len + 1); 1248 bcopy(linkbuf, namebuf, link_len); 1249 1250 /* 1251 * If absolute pathname, restart at root. 1252 * If relative pathname, restart at parent directory. 1253 */ 1254 cp = namebuf; 1255 if (*cp == '/') 1256 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1257 1258 free(newfd); 1259 newfd = 0; 1260 1261 continue; 1262 } 1263 1264 free(currfd); 1265 currfd = newfd; 1266 newfd = 0; 1267 } 1268 1269 error = 0; 1270 1271out: 1272 free(newfd); 1273 free(path); 1274#else 1275 currfd->iodesc = desc; 1276 1277 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1278#endif 1279 if (!error) { 1280 currfd->off = 0; 1281 currfd->cookie = 0; 1282 f->f_fsdata = (void *)currfd; 1283 return (0); 1284 } 1285 1286#ifdef NFS_DEBUG 1287 if (debug) 1288 printf("nfs_open: %s lookupfh failed: %s\n", 1289 path, strerror(error)); 1290#endif 1291 free(currfd); 1292 1293 return (error); 1294} 1295 1296int 1297nfs_close(struct open_file *f) 1298{ 1299 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1300 1301#ifdef NFS_DEBUG 1302 if (debug) 1303 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1304#endif 1305 1306 if (fp) 1307 free(fp); 1308 f->f_fsdata = (void *)0; 1309 1310 return (0); 1311} 1312 1313/* 1314 * read a portion of a file 1315 */ 1316int 1317nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1318{ 1319 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1320 ssize_t cc; 1321 char *addr = buf; 1322 1323#ifdef NFS_DEBUG 1324 if (debug) 1325 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1326 (int)fp->off); 1327#endif 1328 while ((int)size > 0) { 1329 twiddle(16); 1330 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1331 /* XXX maybe should retry on certain errors */ 1332 if (cc == -1) { 1333#ifdef NFS_DEBUG 1334 if (debug) 1335 printf("nfs_read: read: %s", strerror(errno)); 1336#endif 1337 return (errno); /* XXX - from nfs_readdata */ 1338 } 1339 if (cc == 0) { 1340#ifdef NFS_DEBUG 1341 if (debug) 1342 printf("nfs_read: hit EOF unexpectantly"); 1343#endif 1344 goto ret; 1345 } 1346 fp->off += cc; 1347 addr += cc; 1348 size -= cc; 1349 } 1350ret: 1351 if (resid) 1352 *resid = size; 1353 1354 return (0); 1355} 1356 1357/* 1358 * Not implemented. 1359 */ 1360int 1361nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1362{ 1363 return (EROFS); 1364} 1365 1366off_t 1367nfs_seek(struct open_file *f, off_t offset, int where) 1368{ 1369 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1370 uint32_t size = ntohl(d->fa.fa_size.val[1]); 1371 1372 switch (where) { 1373 case SEEK_SET: 1374 d->off = offset; 1375 break; 1376 case SEEK_CUR: 1377 d->off += offset; 1378 break; 1379 case SEEK_END: 1380 d->off = size - offset; 1381 break; 1382 default: 1383 errno = EINVAL; 1384 return (-1); 1385 } 1386 1387 return (d->off); 1388} 1389 1390/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1391int nfs_stat_types[9] = { 1392 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1393 1394int 1395nfs_stat(struct open_file *f, struct stat *sb) 1396{ 1397 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1398 uint32_t ftype, mode; 1399 1400 ftype = ntohl(fp->fa.fa_type); 1401 mode = ntohl(fp->fa.fa_mode); 1402 mode |= nfs_stat_types[ftype & 7]; 1403 1404 sb->st_mode = mode; 1405 sb->st_nlink = ntohl(fp->fa.fa_nlink); 1406 sb->st_uid = ntohl(fp->fa.fa_uid); 1407 sb->st_gid = ntohl(fp->fa.fa_gid); 1408 sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1409 1410 return (0); 1411} 1412 1413static int 1414nfs_readdir(struct open_file *f, struct dirent *d) 1415{ 1416 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1417 struct nfsv3_readdir_repl *repl; 1418 struct nfsv3_readdir_entry *rent; 1419 static char *buf; 1420 static struct nfs_iodesc *pfp = NULL; 1421 static uint64_t cookie = 0; 1422 size_t cc; 1423 int pos; 1424 1425 struct args { 1426 uint32_t fhsize; 1427 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1428 } *args; 1429 struct { 1430 uint32_t h[RPC_HEADER_WORDS]; 1431 struct args d; 1432 } sdata; 1433 static struct { 1434 uint32_t h[RPC_HEADER_WORDS]; 1435 u_char d[NFS_READDIRSIZE]; 1436 } rdata; 1437 1438 if (fp != pfp || fp->off != cookie) { 1439 pfp = NULL; 1440 refill: 1441 args = &sdata.d; 1442 bzero(args, sizeof(*args)); 1443 1444 args->fhsize = htonl(fp->fhsize); 1445 bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1446 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1447 args->fhpluscookie[pos++] = htonl(fp->off >> 32); 1448 args->fhpluscookie[pos++] = htonl(fp->off); 1449 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 1450 args->fhpluscookie[pos++] = htonl(fp->cookie); 1451 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1452 1453 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1454 args, 6 * sizeof(uint32_t) + 1455 roundup(fp->fhsize, sizeof(uint32_t)), 1456 rdata.d, sizeof(rdata.d)); 1457 buf = rdata.d; 1458 repl = (struct nfsv3_readdir_repl *)buf; 1459 if (repl->errno != 0) 1460 return (ntohl(repl->errno)); 1461 pfp = fp; 1462 cookie = fp->off; 1463 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 1464 ntohl(repl->cookiev1); 1465 buf += sizeof (struct nfsv3_readdir_repl); 1466 } 1467 rent = (struct nfsv3_readdir_entry *)buf; 1468 1469 if (rent->follows == 0) { 1470 /* fid0 is actually eof */ 1471 if (rent->fid0 != 0) { 1472 cookie = 0; 1473 return (ENOENT); 1474 } 1475 goto refill; 1476 } 1477 1478 d->d_namlen = ntohl(rent->len); 1479 bcopy(rent->nameplus, d->d_name, d->d_namlen); 1480 d->d_name[d->d_namlen] = '\0'; 1481 1482 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 1483 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 1484 ntohl(rent->nameplus[pos + 1]); 1485 pos += 2; 1486 buf = (u_char *)&rent->nameplus[pos]; 1487 return (0); 1488} 1489#endif /* OLD_NFSV2 */ 1490