nfs.c revision 240850
1241823Smarcel/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 2241823Smarcel 3241823Smarcel/*- 4241823Smarcel * Copyright (c) 1993 John Brezak 5241823Smarcel * All rights reserved. 6241823Smarcel * 7241823Smarcel * Redistribution and use in source and binary forms, with or without 8241823Smarcel * modification, are permitted provided that the following conditions 9241823Smarcel * are met: 10241823Smarcel * 1. Redistributions of source code must retain the above copyright 11241823Smarcel * notice, this list of conditions and the following disclaimer. 12241823Smarcel * 2. Redistributions in binary form must reproduce the above copyright 13241823Smarcel * notice, this list of conditions and the following disclaimer in the 14241823Smarcel * documentation and/or other materials provided with the distribution. 15241823Smarcel * 3. The name of the author may not be used to endorse or promote products 16241823Smarcel * derived from this software without specific prior written permission. 17241823Smarcel * 18241823Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19241823Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20241823Smarcel * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21241823Smarcel * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22241823Smarcel * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23241823Smarcel * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24241823Smarcel * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25241823Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26241823Smarcel * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27241823Smarcel * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28241823Smarcel * POSSIBILITY OF SUCH DAMAGE. 29241823Smarcel */ 30257853Sjmmv 31241823Smarcel#include <sys/cdefs.h> 32241823Smarcel__FBSDID("$FreeBSD: head/lib/libstand/nfs.c 240850 2012-09-23 08:38:06Z kevlo $"); 33241823Smarcel 34241823Smarcel#include <sys/param.h> 35275988Sngie#include <sys/time.h> 36275988Sngie#include <sys/socket.h> 37241823Smarcel#include <sys/stat.h> 38241823Smarcel#include <string.h> 39275988Sngie 40275988Sngie#include <netinet/in.h> 41275988Sngie#include <netinet/in_systm.h> 42241823Smarcel 43241823Smarcel#include "rpcv2.h" 44241823Smarcel#include "nfsv2.h" 45241823Smarcel 46266650Sjmmv#include "stand.h" 47241823Smarcel#include "net.h" 48241823Smarcel#include "netif.h" 49241823Smarcel#include "rpc.h" 50241823Smarcel 51241823Smarcel#define NFS_DEBUGxx 52241823Smarcel 53257853Sjmmv#define NFSREAD_SIZE 1024 54257853Sjmmv 55257853Sjmmv/* Define our own NFS attributes without NQNFS stuff. */ 56257853Sjmmv#ifdef OLD_NFSV2 57260576Sjmmvstruct nfsv2_fattrs { 58241823Smarcel 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 if (newfd) 1260 free(newfd); 1261 if (path) 1262 free(path); 1263#else 1264 currfd->iodesc = desc; 1265 1266 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1267#endif 1268 if (!error) { 1269 currfd->off = 0; 1270 currfd->cookie = 0; 1271 f->f_fsdata = (void *)currfd; 1272 return (0); 1273 } 1274 1275#ifdef NFS_DEBUG 1276 if (debug) 1277 printf("nfs_open: %s lookupfh failed: %s\n", 1278 path, strerror(error)); 1279#endif 1280 free(currfd); 1281 1282 return (error); 1283} 1284 1285int 1286nfs_close(struct open_file *f) 1287{ 1288 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1289 1290#ifdef NFS_DEBUG 1291 if (debug) 1292 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1293#endif 1294 1295 if (fp) 1296 free(fp); 1297 f->f_fsdata = (void *)0; 1298 1299 return (0); 1300} 1301 1302/* 1303 * read a portion of a file 1304 */ 1305int 1306nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1307{ 1308 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1309 ssize_t cc; 1310 char *addr = buf; 1311 1312#ifdef NFS_DEBUG 1313 if (debug) 1314 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1315 (int)fp->off); 1316#endif 1317 while ((int)size > 0) { 1318 twiddle(); 1319 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1320 /* XXX maybe should retry on certain errors */ 1321 if (cc == -1) { 1322#ifdef NFS_DEBUG 1323 if (debug) 1324 printf("nfs_read: read: %s", strerror(errno)); 1325#endif 1326 return (errno); /* XXX - from nfs_readdata */ 1327 } 1328 if (cc == 0) { 1329#ifdef NFS_DEBUG 1330 if (debug) 1331 printf("nfs_read: hit EOF unexpectantly"); 1332#endif 1333 goto ret; 1334 } 1335 fp->off += cc; 1336 addr += cc; 1337 size -= cc; 1338 } 1339ret: 1340 if (resid) 1341 *resid = size; 1342 1343 return (0); 1344} 1345 1346/* 1347 * Not implemented. 1348 */ 1349int 1350nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1351{ 1352 return (EROFS); 1353} 1354 1355off_t 1356nfs_seek(struct open_file *f, off_t offset, int where) 1357{ 1358 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1359 uint32_t size = ntohl(d->fa.fa_size.val[1]); 1360 1361 switch (where) { 1362 case SEEK_SET: 1363 d->off = offset; 1364 break; 1365 case SEEK_CUR: 1366 d->off += offset; 1367 break; 1368 case SEEK_END: 1369 d->off = size - offset; 1370 break; 1371 default: 1372 errno = EINVAL; 1373 return (-1); 1374 } 1375 1376 return (d->off); 1377} 1378 1379/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1380int nfs_stat_types[9] = { 1381 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1382 1383int 1384nfs_stat(struct open_file *f, struct stat *sb) 1385{ 1386 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1387 uint32_t ftype, mode; 1388 1389 ftype = ntohl(fp->fa.fa_type); 1390 mode = ntohl(fp->fa.fa_mode); 1391 mode |= nfs_stat_types[ftype & 7]; 1392 1393 sb->st_mode = mode; 1394 sb->st_nlink = ntohl(fp->fa.fa_nlink); 1395 sb->st_uid = ntohl(fp->fa.fa_uid); 1396 sb->st_gid = ntohl(fp->fa.fa_gid); 1397 sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1398 1399 return (0); 1400} 1401 1402static int 1403nfs_readdir(struct open_file *f, struct dirent *d) 1404{ 1405 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1406 struct nfsv3_readdir_repl *repl; 1407 struct nfsv3_readdir_entry *rent; 1408 static char *buf; 1409 static struct nfs_iodesc *pfp = NULL; 1410 static uint64_t cookie = 0; 1411 size_t cc; 1412 int pos; 1413 1414 struct args { 1415 uint32_t fhsize; 1416 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1417 } *args; 1418 struct { 1419 uint32_t h[RPC_HEADER_WORDS]; 1420 struct args d; 1421 } sdata; 1422 static struct { 1423 uint32_t h[RPC_HEADER_WORDS]; 1424 u_char d[NFS_READDIRSIZE]; 1425 } rdata; 1426 1427 if (fp != pfp || fp->off != cookie) { 1428 pfp = NULL; 1429 refill: 1430 args = &sdata.d; 1431 bzero(args, sizeof(*args)); 1432 1433 args->fhsize = htonl(fp->fhsize); 1434 bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1435 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1436 args->fhpluscookie[pos++] = htonl(fp->off >> 32); 1437 args->fhpluscookie[pos++] = htonl(fp->off); 1438 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 1439 args->fhpluscookie[pos++] = htonl(fp->cookie); 1440 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1441 1442 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1443 args, 6 * sizeof(uint32_t) + 1444 roundup(fp->fhsize, sizeof(uint32_t)), 1445 rdata.d, sizeof(rdata.d)); 1446 buf = rdata.d; 1447 repl = (struct nfsv3_readdir_repl *)buf; 1448 if (repl->errno != 0) 1449 return (ntohl(repl->errno)); 1450 pfp = fp; 1451 cookie = fp->off; 1452 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 1453 ntohl(repl->cookiev1); 1454 buf += sizeof (struct nfsv3_readdir_repl); 1455 } 1456 rent = (struct nfsv3_readdir_entry *)buf; 1457 1458 if (rent->follows == 0) { 1459 /* fid0 is actually eof */ 1460 if (rent->fid0 != 0) { 1461 cookie = 0; 1462 return (ENOENT); 1463 } 1464 goto refill; 1465 } 1466 1467 d->d_namlen = ntohl(rent->len); 1468 bcopy(rent->nameplus, d->d_name, d->d_namlen); 1469 d->d_name[d->d_namlen] = '\0'; 1470 1471 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 1472 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos++]) << 32) | 1473 ntohl(rent->nameplus[pos++]); 1474 buf = (u_char *)&rent->nameplus[pos]; 1475 return (0); 1476} 1477#endif /* OLD_NFSV2 */ 1478