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