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 57struct 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 74struct 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) */ 82struct 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 90struct nfs_readlnk_repl { 91 n_long errno; 92 n_long len; 93 char path[NFS_MAXPATHLEN]; 94}; 95#endif 96 97struct nfs_readdir_args { 98 u_char fh[NFS_FHSIZE]; 99 n_long cookie; 100 n_long count; 101}; 102 103struct nfs_readdir_data { 104 n_long fileid; 105 n_long len; 106 char name[0]; 107}; 108 109struct nfs_readdir_off { 110 n_long cookie; 111 n_long follows; 112}; 113 114struct 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 131typedef struct { 132 uint32_t val[2]; 133} n_quad; 134 135struct nfsv3_time { 136 uint32_t nfs_sec; 137 uint32_t nfs_nsec; 138}; 139 140struct 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 */ 162struct 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 170struct 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 178struct 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 */ 192int nfs_open(const char *path, struct open_file *f); 193static int nfs_close(struct open_file *f); 194static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 195static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 196static off_t nfs_seek(struct open_file *f, off_t offset, int where); 197static int nfs_stat(struct open_file *f, struct stat *sb); 198static int nfs_readdir(struct open_file *f, struct dirent *d); 199 200struct nfs_iodesc nfs_root_node; 201 202struct 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 */ 218int 219nfs_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 */ 274int 275nfs_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 */ 337int 338nfs_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 */ 382ssize_t 383nfs_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 */ 440int 441nfs_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 608out: 609 if (newfd) 610 free(newfd); 611 if (path) 612 free(path); 613#else 614 currfd->iodesc = desc; 615 616 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 617#endif 618 if (!error) { 619 currfd->off = 0; 620 f->f_fsdata = (void *)currfd; 621 return (0); 622 } 623 624#ifdef NFS_DEBUG 625 if (debug) 626 printf("nfs_open: %s lookupfh failed: %s\n", 627 path, strerror(error)); 628#endif 629 free(currfd); 630 631 return (error); 632} 633 634int 635nfs_close(struct open_file *f) 636{ 637 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 638 639#ifdef NFS_DEBUG 640 if (debug) 641 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 642#endif 643 644 if (fp) 645 free(fp); 646 f->f_fsdata = (void *)0; 647 648 return (0); 649} 650 651/* 652 * read a portion of a file 653 */ 654int 655nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 656{ 657 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 658 ssize_t cc; 659 char *addr = buf; 660 661#ifdef NFS_DEBUG 662 if (debug) 663 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 664 (int)fp->off); 665#endif 666 while ((int)size > 0) { 667 twiddle(); 668 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 669 /* XXX maybe should retry on certain errors */ 670 if (cc == -1) { 671#ifdef NFS_DEBUG 672 if (debug) 673 printf("nfs_read: read: %s", strerror(errno)); 674#endif 675 return (errno); /* XXX - from nfs_readdata */ 676 } 677 if (cc == 0) { 678#ifdef NFS_DEBUG 679 if (debug) 680 printf("nfs_read: hit EOF unexpectantly"); 681#endif 682 goto ret; 683 } 684 fp->off += cc; 685 addr += cc; 686 size -= cc; 687 } 688ret: 689 if (resid) 690 *resid = size; 691 692 return (0); 693} 694 695/* 696 * Not implemented. 697 */ 698int 699nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 700{ 701 return (EROFS); 702} 703 704off_t 705nfs_seek(struct open_file *f, off_t offset, int where) 706{ 707 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 708 n_long size = ntohl(d->fa.fa_size); 709 710 switch (where) { 711 case SEEK_SET: 712 d->off = offset; 713 break; 714 case SEEK_CUR: 715 d->off += offset; 716 break; 717 case SEEK_END: 718 d->off = size - offset; 719 break; 720 default: 721 errno = EINVAL; 722 return (-1); 723 } 724 725 return (d->off); 726} 727 728/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 729int nfs_stat_types[8] = { 730 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 731 732int 733nfs_stat(struct open_file *f, struct stat *sb) 734{ 735 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 736 n_long ftype, mode; 737 738 ftype = ntohl(fp->fa.fa_type); 739 mode = ntohl(fp->fa.fa_mode); 740 mode |= nfs_stat_types[ftype & 7]; 741 742 sb->st_mode = mode; 743 sb->st_nlink = ntohl(fp->fa.fa_nlink); 744 sb->st_uid = ntohl(fp->fa.fa_uid); 745 sb->st_gid = ntohl(fp->fa.fa_gid); 746 sb->st_size = ntohl(fp->fa.fa_size); 747 748 return (0); 749} 750 751static int 752nfs_readdir(struct open_file *f, struct dirent *d) 753{ 754 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 755 struct nfs_readdir_args *args; 756 struct nfs_readdir_data *rd; 757 struct nfs_readdir_off *roff = NULL; 758 static char *buf; 759 static struct nfs_iodesc *pfp = NULL; 760 static n_long cookie = 0; 761 size_t cc; 762 n_long eof; 763 764 struct { 765 n_long h[RPC_HEADER_WORDS]; 766 struct nfs_readdir_args d; 767 } sdata; 768 static struct { 769 n_long h[RPC_HEADER_WORDS]; 770 u_char d[NFS_READDIRSIZE]; 771 } rdata; 772 773 if (fp != pfp || fp->off != cookie) { 774 pfp = NULL; 775 refill: 776 args = &sdata.d; 777 bzero(args, sizeof(*args)); 778 779 bcopy(fp->fh, args->fh, NFS_FHSIZE); 780 args->cookie = htonl(fp->off); 781 args->count = htonl(NFS_READDIRSIZE); 782 783 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 784 args, sizeof(*args), 785 rdata.d, sizeof(rdata.d)); 786 buf = rdata.d; 787 roff = (struct nfs_readdir_off *)buf; 788 if (ntohl(roff->cookie) != 0) 789 return EIO; 790 pfp = fp; 791 cookie = fp->off; 792 } 793 roff = (struct nfs_readdir_off *)buf; 794 795 if (ntohl(roff->follows) == 0) { 796 eof = ntohl((roff+1)->cookie); 797 if (eof) { 798 cookie = 0; 799 return ENOENT; 800 } 801 goto refill; 802 } 803 804 buf += sizeof(struct nfs_readdir_off); 805 rd = (struct nfs_readdir_data *)buf; 806 d->d_namlen = ntohl(rd->len); 807 bcopy(rd->name, d->d_name, d->d_namlen); 808 d->d_name[d->d_namlen] = '\0'; 809 810 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 811 roff = (struct nfs_readdir_off *)buf; 812 fp->off = cookie = ntohl(roff->cookie); 813 return 0; 814} 815#else /* !OLD_NFSV2 */ 816/* 817 * Fetch the root file handle (call mount daemon) 818 * Return zero or error number. 819 */ 820int 821nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 822{ 823 int len; 824 struct args { 825 uint32_t len; 826 char path[FNAME_SIZE]; 827 } *args; 828 struct repl { 829 uint32_t errno; 830 uint32_t fhsize; 831 u_char fh[NFS_V3MAXFHSIZE]; 832 uint32_t authcnt; 833 uint32_t auth[7]; 834 } *repl; 835 struct { 836 uint32_t h[RPC_HEADER_WORDS]; 837 struct args d; 838 } sdata; 839 struct { 840 uint32_t h[RPC_HEADER_WORDS]; 841 struct repl d; 842 } rdata; 843 size_t cc; 844 845#ifdef NFS_DEBUG 846 if (debug) 847 printf("nfs_getrootfh: %s\n", path); 848#endif 849 850 args = &sdata.d; 851 repl = &rdata.d; 852 853 bzero(args, sizeof(*args)); 854 len = strlen(path); 855 if (len > sizeof(args->path)) 856 len = sizeof(args->path); 857 args->len = htonl(len); 858 bcopy(path, args->path, len); 859 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 860 861 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 862 args, len, repl, sizeof(*repl)); 863 if (cc == -1) 864 /* errno was set by rpc_call */ 865 return (errno); 866 if (cc < 2 * sizeof (uint32_t)) 867 return (EBADRPC); 868 if (repl->errno != 0) 869 return (ntohl(repl->errno)); 870 *fhlenp = ntohl(repl->fhsize); 871 bcopy(repl->fh, fhp, *fhlenp); 872 return (0); 873} 874 875/* 876 * Lookup a file. Store handle and attributes. 877 * Return zero or error number. 878 */ 879int 880nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 881{ 882 int len, rlen, pos; 883 struct args { 884 uint32_t fhsize; 885 uint32_t fhplusname[1 + 886 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 887 } *args; 888 struct repl { 889 uint32_t errno; 890 uint32_t fhsize; 891 uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 892 2 * (sizeof(uint32_t) + 893 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 894 } *repl; 895 struct { 896 uint32_t h[RPC_HEADER_WORDS]; 897 struct args d; 898 } sdata; 899 struct { 900 uint32_t h[RPC_HEADER_WORDS]; 901 struct repl d; 902 } rdata; 903 ssize_t cc; 904 905#ifdef NFS_DEBUG 906 if (debug) 907 printf("lookupfh: called\n"); 908#endif 909 910 args = &sdata.d; 911 repl = &rdata.d; 912 913 bzero(args, sizeof(*args)); 914 args->fhsize = htonl(d->fhsize); 915 bcopy(d->fh, args->fhplusname, d->fhsize); 916 len = strlen(name); 917 if (len > FNAME_SIZE) 918 len = FNAME_SIZE; 919 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 920 args->fhplusname[pos++] = htonl(len); 921 bcopy(name, &args->fhplusname[pos], len); 922 len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 923 roundup(len, sizeof(uint32_t)); 924 925 rlen = sizeof(*repl); 926 927 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 928 args, len, repl, rlen); 929 if (cc == -1) 930 return (errno); /* XXX - from rpc_call */ 931 if (cc < 2 * sizeof(uint32_t)) 932 return (EIO); 933 if (repl->errno != 0) 934 /* saerrno.h now matches NFS error numbers. */ 935 return (ntohl(repl->errno)); 936 newfd->fhsize = ntohl(repl->fhsize); 937 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 938 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 939 if (repl->fhplusattr[pos++] == 0) 940 return (EIO); 941 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 942 return (0); 943} 944 945#ifndef NFS_NOSYMLINK 946/* 947 * Get the destination of a symbolic link. 948 */ 949int 950nfs_readlink(struct nfs_iodesc *d, char *buf) 951{ 952 struct args { 953 uint32_t fhsize; 954 u_char fh[NFS_V3MAXFHSIZE]; 955 } *args; 956 struct repl { 957 uint32_t errno; 958 uint32_t ok; 959 struct nfsv3_fattrs fa; 960 uint32_t len; 961 u_char path[NFS_MAXPATHLEN]; 962 } *repl; 963 struct { 964 uint32_t h[RPC_HEADER_WORDS]; 965 struct args d; 966 } sdata; 967 struct { 968 uint32_t h[RPC_HEADER_WORDS]; 969 struct repl d; 970 } rdata; 971 ssize_t cc; 972 973#ifdef NFS_DEBUG 974 if (debug) 975 printf("readlink: called\n"); 976#endif 977 978 args = &sdata.d; 979 repl = &rdata.d; 980 981 bzero(args, sizeof(*args)); 982 args->fhsize = htonl(d->fhsize); 983 bcopy(d->fh, args->fh, d->fhsize); 984 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 985 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 986 repl, sizeof(*repl)); 987 if (cc == -1) 988 return (errno); 989 990 if (cc < 2 * sizeof(uint32_t)) 991 return (EIO); 992 993 if (repl->errno != 0) 994 return (ntohl(repl->errno)); 995 996 if (repl->ok == 0) 997 return (EIO); 998 999 repl->len = ntohl(repl->len); 1000 if (repl->len > NFS_MAXPATHLEN) 1001 return (ENAMETOOLONG); 1002 1003 bcopy(repl->path, buf, repl->len); 1004 buf[repl->len] = 0; 1005 return (0); 1006} 1007#endif 1008 1009/* 1010 * Read data from a file. 1011 * Return transfer count or -1 (and set errno) 1012 */ 1013ssize_t 1014nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 1015{ 1016 struct args { 1017 uint32_t fhsize; 1018 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 1019 } *args; 1020 struct repl { 1021 uint32_t errno; 1022 uint32_t ok; 1023 struct nfsv3_fattrs fa; 1024 uint32_t count; 1025 uint32_t eof; 1026 uint32_t len; 1027 u_char data[NFSREAD_SIZE]; 1028 } *repl; 1029 struct { 1030 uint32_t h[RPC_HEADER_WORDS]; 1031 struct args d; 1032 } sdata; 1033 struct { 1034 uint32_t h[RPC_HEADER_WORDS]; 1035 struct repl d; 1036 } rdata; 1037 size_t cc; 1038 long x; 1039 int hlen, rlen, pos; 1040 1041 args = &sdata.d; 1042 repl = &rdata.d; 1043 1044 bzero(args, sizeof(*args)); 1045 args->fhsize = htonl(d->fhsize); 1046 bcopy(d->fh, args->fhoffcnt, d->fhsize); 1047 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1048 args->fhoffcnt[pos++] = 0; 1049 args->fhoffcnt[pos++] = htonl((uint32_t)off); 1050 if (len > NFSREAD_SIZE) 1051 len = NFSREAD_SIZE; 1052 args->fhoffcnt[pos] = htonl((uint32_t)len); 1053 hlen = sizeof(*repl) - NFSREAD_SIZE; 1054 1055 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 1056 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1057 repl, sizeof(*repl)); 1058 if (cc == -1) 1059 /* errno was already set by rpc_call */ 1060 return (-1); 1061 if (cc < hlen) { 1062 errno = EBADRPC; 1063 return (-1); 1064 } 1065 if (repl->errno != 0) { 1066 errno = ntohl(repl->errno); 1067 return (-1); 1068 } 1069 rlen = cc - hlen; 1070 x = ntohl(repl->count); 1071 if (rlen < x) { 1072 printf("nfsread: short packet, %d < %ld\n", rlen, x); 1073 errno = EBADRPC; 1074 return (-1); 1075 } 1076 bcopy(repl->data, addr, x); 1077 return (x); 1078} 1079 1080/* 1081 * Open a file. 1082 * return zero or error number 1083 */ 1084int 1085nfs_open(const char *upath, struct open_file *f) 1086{ 1087 struct iodesc *desc; 1088 struct nfs_iodesc *currfd; 1089 char buf[2 * NFS_V3MAXFHSIZE + 3]; 1090 u_char *fh; 1091 char *cp; 1092 int i; 1093#ifndef NFS_NOSYMLINK 1094 struct nfs_iodesc *newfd; 1095 struct nfsv3_fattrs *fa; 1096 char *ncp; 1097 int c; 1098 char namebuf[NFS_MAXPATHLEN + 1]; 1099 char linkbuf[NFS_MAXPATHLEN + 1]; 1100 int nlinks = 0; 1101#endif 1102 int error; 1103 char *path; 1104 1105#ifdef NFS_DEBUG 1106 if (debug) 1107 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 1108#endif 1109 if (!rootpath[0]) { 1110 printf("no rootpath, no nfs\n"); 1111 return (ENXIO); 1112 } 1113 1114 /* 1115 * This is silly - we should look at dv_type but that value is 1116 * arch dependant and we can't use it here. 1117 */ 1118#ifndef __i386__ 1119 if (strcmp(f->f_dev->dv_name, "net") != 0) 1120 return (EINVAL); 1121#else 1122 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 1123 return (EINVAL); 1124#endif 1125 1126 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 1127 return (EINVAL); 1128 1129 /* Bind to a reserved port. */ 1130 desc->myport = htons(--rpc_port); 1131 desc->destip = rootip; 1132 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 1133 nfs_root_node.fh))) 1134 return (error); 1135 nfs_root_node.fa.fa_type = htonl(NFDIR); 1136 nfs_root_node.fa.fa_mode = htonl(0755); 1137 nfs_root_node.fa.fa_nlink = htonl(2); 1138 nfs_root_node.iodesc = desc; 1139 1140 fh = &nfs_root_node.fh[0]; 1141 buf[0] = 'X'; 1142 cp = &buf[1]; 1143 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 1144 sprintf(cp, "%02x", fh[i]); 1145 sprintf(cp, "X"); 1146 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 1147 setenv("boot.nfsroot.path", rootpath, 1); 1148 setenv("boot.nfsroot.nfshandle", buf, 1); 1149 sprintf(buf, "%d", nfs_root_node.fhsize); 1150 setenv("boot.nfsroot.nfshandlelen", buf, 1); 1151 1152 /* Allocate file system specific data structure */ 1153 currfd = malloc(sizeof(*newfd)); 1154 if (currfd == NULL) { 1155 error = ENOMEM; 1156 goto out; 1157 } 1158#ifndef NFS_NOSYMLINK 1159 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1160 newfd = 0; 1161 1162 cp = path = strdup(upath); 1163 if (path == NULL) { 1164 error = ENOMEM; 1165 goto out; 1166 } 1167 while (*cp) { 1168 /* 1169 * Remove extra separators 1170 */ 1171 while (*cp == '/') 1172 cp++; 1173 1174 if (*cp == '\0') 1175 break; 1176 /* 1177 * Check that current node is a directory. 1178 */ 1179 if (currfd->fa.fa_type != htonl(NFDIR)) { 1180 error = ENOTDIR; 1181 goto out; 1182 } 1183 1184 /* allocate file system specific data structure */ 1185 newfd = malloc(sizeof(*newfd)); 1186 if (newfd == NULL) { 1187 error = ENOMEM; 1188 goto out; 1189 } 1190 newfd->iodesc = currfd->iodesc; 1191 1192 /* 1193 * Get next component of path name. 1194 */ 1195 { 1196 int len = 0; 1197 1198 ncp = cp; 1199 while ((c = *cp) != '\0' && c != '/') { 1200 if (++len > NFS_MAXNAMLEN) { 1201 error = ENOENT; 1202 goto out; 1203 } 1204 cp++; 1205 } 1206 *cp = '\0'; 1207 } 1208 1209 /* lookup a file handle */ 1210 error = nfs_lookupfh(currfd, ncp, newfd); 1211 *cp = c; 1212 if (error) 1213 goto out; 1214 1215 /* 1216 * Check for symbolic link 1217 */ 1218 if (newfd->fa.fa_type == htonl(NFLNK)) { 1219 int link_len, len; 1220 1221 error = nfs_readlink(newfd, linkbuf); 1222 if (error) 1223 goto out; 1224 1225 link_len = strlen(linkbuf); 1226 len = strlen(cp); 1227 1228 if (link_len + len > MAXPATHLEN 1229 || ++nlinks > MAXSYMLINKS) { 1230 error = ENOENT; 1231 goto out; 1232 } 1233 1234 bcopy(cp, &namebuf[link_len], len + 1); 1235 bcopy(linkbuf, namebuf, link_len); 1236 1237 /* 1238 * If absolute pathname, restart at root. 1239 * If relative pathname, restart at parent directory. 1240 */ 1241 cp = namebuf; 1242 if (*cp == '/') 1243 bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1244 1245 free(newfd); 1246 newfd = 0; 1247 1248 continue; 1249 } 1250 1251 free(currfd); 1252 currfd = newfd; 1253 newfd = 0; 1254 } 1255 1256 error = 0; 1257 1258out: 1259 free(newfd); 1260 free(path); 1261#else 1262 currfd->iodesc = desc; 1263 1264 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1265#endif 1266 if (!error) { 1267 currfd->off = 0; 1268 currfd->cookie = 0; 1269 f->f_fsdata = (void *)currfd; 1270 return (0); 1271 } 1272 1273#ifdef NFS_DEBUG 1274 if (debug) 1275 printf("nfs_open: %s lookupfh failed: %s\n", 1276 path, strerror(error)); 1277#endif 1278 free(currfd); 1279 1280 return (error); 1281} 1282 1283int 1284nfs_close(struct open_file *f) 1285{ 1286 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1287 1288#ifdef NFS_DEBUG 1289 if (debug) 1290 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1291#endif 1292 1293 if (fp) 1294 free(fp); 1295 f->f_fsdata = (void *)0; 1296 1297 return (0); 1298} 1299 1300/* 1301 * read a portion of a file 1302 */ 1303int 1304nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1305{ 1306 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1307 ssize_t cc; 1308 char *addr = buf; 1309 1310#ifdef NFS_DEBUG 1311 if (debug) 1312 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1313 (int)fp->off); 1314#endif 1315 while ((int)size > 0) { 1316 twiddle(); 1317 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1318 /* XXX maybe should retry on certain errors */ 1319 if (cc == -1) { 1320#ifdef NFS_DEBUG 1321 if (debug) 1322 printf("nfs_read: read: %s", strerror(errno)); 1323#endif 1324 return (errno); /* XXX - from nfs_readdata */ 1325 } 1326 if (cc == 0) { 1327#ifdef NFS_DEBUG 1328 if (debug) 1329 printf("nfs_read: hit EOF unexpectantly"); 1330#endif 1331 goto ret; 1332 } 1333 fp->off += cc; 1334 addr += cc; 1335 size -= cc; 1336 } 1337ret: 1338 if (resid) 1339 *resid = size; 1340 1341 return (0); 1342} 1343 1344/* 1345 * Not implemented. 1346 */ 1347int 1348nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1349{ 1350 return (EROFS); 1351} 1352 1353off_t 1354nfs_seek(struct open_file *f, off_t offset, int where) 1355{ 1356 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1357 uint32_t size = ntohl(d->fa.fa_size.val[1]); 1358 1359 switch (where) { 1360 case SEEK_SET: 1361 d->off = offset; 1362 break; 1363 case SEEK_CUR: 1364 d->off += offset; 1365 break; 1366 case SEEK_END: 1367 d->off = size - offset; 1368 break; 1369 default: 1370 errno = EINVAL; 1371 return (-1); 1372 } 1373 1374 return (d->off); 1375} 1376 1377/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1378int nfs_stat_types[9] = { 1379 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1380 1381int 1382nfs_stat(struct open_file *f, struct stat *sb) 1383{ 1384 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1385 uint32_t ftype, mode; 1386 1387 ftype = ntohl(fp->fa.fa_type); 1388 mode = ntohl(fp->fa.fa_mode); 1389 mode |= nfs_stat_types[ftype & 7]; 1390 1391 sb->st_mode = mode; 1392 sb->st_nlink = ntohl(fp->fa.fa_nlink); 1393 sb->st_uid = ntohl(fp->fa.fa_uid); 1394 sb->st_gid = ntohl(fp->fa.fa_gid); 1395 sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1396 1397 return (0); 1398} 1399 1400static int 1401nfs_readdir(struct open_file *f, struct dirent *d) 1402{ 1403 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1404 struct nfsv3_readdir_repl *repl; 1405 struct nfsv3_readdir_entry *rent; 1406 static char *buf; 1407 static struct nfs_iodesc *pfp = NULL; 1408 static uint64_t cookie = 0; 1409 size_t cc; 1410 int pos; 1411 1412 struct args { 1413 uint32_t fhsize; 1414 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1415 } *args; 1416 struct { 1417 uint32_t h[RPC_HEADER_WORDS]; 1418 struct args d; 1419 } sdata; 1420 static struct { 1421 uint32_t h[RPC_HEADER_WORDS]; 1422 u_char d[NFS_READDIRSIZE]; 1423 } rdata; 1424 1425 if (fp != pfp || fp->off != cookie) { 1426 pfp = NULL; 1427 refill: 1428 args = &sdata.d; 1429 bzero(args, sizeof(*args)); 1430 1431 args->fhsize = htonl(fp->fhsize); 1432 bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1433 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1434 args->fhpluscookie[pos++] = htonl(fp->off >> 32); 1435 args->fhpluscookie[pos++] = htonl(fp->off); 1436 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 1437 args->fhpluscookie[pos++] = htonl(fp->cookie); 1438 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1439 1440 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1441 args, 6 * sizeof(uint32_t) + 1442 roundup(fp->fhsize, sizeof(uint32_t)), 1443 rdata.d, sizeof(rdata.d)); 1444 buf = rdata.d; 1445 repl = (struct nfsv3_readdir_repl *)buf; 1446 if (repl->errno != 0) 1447 return (ntohl(repl->errno)); 1448 pfp = fp; 1449 cookie = fp->off; 1450 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 1451 ntohl(repl->cookiev1); 1452 buf += sizeof (struct nfsv3_readdir_repl); 1453 } 1454 rent = (struct nfsv3_readdir_entry *)buf; 1455 1456 if (rent->follows == 0) { 1457 /* fid0 is actually eof */ 1458 if (rent->fid0 != 0) { 1459 cookie = 0; 1460 return (ENOENT); 1461 } 1462 goto refill; 1463 } 1464 1465 d->d_namlen = ntohl(rent->len); 1466 bcopy(rent->nameplus, d->d_name, d->d_namlen); 1467 d->d_name[d->d_namlen] = '\0'; 1468 1469 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 1470 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 1471 ntohl(rent->nameplus[pos + 1]); 1472 pos += 2; 1473 buf = (u_char *)&rent->nameplus[pos]; 1474 return (0); 1475} 1476#endif /* OLD_NFSV2 */ 1477