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