1 /* $FreeBSD: src/lib/libstand/nfs.c,v 1.2.6.3 2000/09/10 01:33:25 ps Exp $ */ 2 /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 3 4 /*- 5 * Copyright (c) 1993 John Brezak 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/time.h> 34 #include <sys/socket.h> 35 #include <sys/stat.h> 36 #include <string.h> 37 #include <stddef.h> 38 39 #include <netinet/in.h> 40 #include <netinet/in_systm.h> 41 42 #include "rpcv2.h" 43 #include "nfsv2.h" 44 45 #include "stand.h" 46 #include "net.h" 47 #include "netif.h" 48 #include "rpc.h" 49 50 #define NFS_DEBUGxx 51 52 /* Define our own NFS attributes without NQNFS stuff. */ 53 struct nfsv2_fattrs { 54 n_long fa_type; 55 n_long fa_mode; 56 n_long fa_nlink; 57 n_long fa_uid; 58 n_long fa_gid; 59 n_long fa_size; 60 n_long fa_blocksize; 61 n_long fa_rdev; 62 n_long fa_blocks; 63 n_long fa_fsid; 64 n_long fa_fileid; 65 struct nfsv2_time fa_atime; 66 struct nfsv2_time fa_mtime; 67 struct nfsv2_time fa_ctime; 68 }; 69 70 71 struct nfs_read_args { 72 u_char fh[NFS_FHSIZE]; 73 n_long off; 74 n_long len; 75 n_long xxx; /* XXX what's this for? */ 76 }; 77 78 /* 79 * Data part of nfs rpc reply (also the largest thing we receive). 80 * Worry about the size of the structure declared on the stack. 81 */ 82 83 #define NFSREAD_MIN_SIZE 1024 84 #define NFSREAD_MAX_SIZE 4096 85 86 struct nfs_read_repl { 87 n_long errno; 88 struct nfsv2_fattrs fa; 89 n_long count; 90 u_char data[NFSREAD_MAX_SIZE]; 91 }; 92 93 #ifndef NFS_NOSYMLINK 94 struct nfs_readlnk_repl { 95 n_long errno; 96 n_long len; 97 char path[NFS_MAXPATHLEN]; 98 }; 99 #endif 100 101 struct nfs_readdir_args { 102 u_char fh[NFS_FHSIZE]; 103 n_long cookie; 104 n_long count; 105 }; 106 107 struct nfs_readdir_data { 108 n_long fileid; 109 n_long len; 110 char name[0]; 111 }; 112 113 struct nfs_readdir_off { 114 n_long cookie; 115 n_long follows; 116 }; 117 118 struct nfs_iodesc { 119 struct iodesc *iodesc; 120 off_t off; 121 u_char fh[NFS_FHSIZE]; 122 struct nfsv2_fattrs fa; /* all in network order */ 123 }; 124 125 /* 126 * XXX interactions with tftp? See nfswrapper.c for a confusing 127 * issue. 128 */ 129 int nfs_open(const char *path, struct open_file *f); 130 static int nfs_close(struct open_file *f); 131 static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 132 static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 133 static off_t nfs_seek(struct open_file *f, off_t offset, int where); 134 static int nfs_stat(struct open_file *f, struct stat *sb); 135 static int nfs_readdir(struct open_file *f, struct dirent *d); 136 137 struct nfs_iodesc nfs_root_node; 138 139 struct fs_ops nfs_fsops = { 140 "nfs", 141 nfs_open, 142 nfs_close, 143 nfs_read, 144 nfs_write, 145 nfs_seek, 146 nfs_stat, 147 nfs_readdir 148 }; 149 150 static int nfs_read_size = NFSREAD_MIN_SIZE; 151 152 /* 153 * Fetch the root file handle (call mount daemon) 154 * Return zero or error number. 155 */ 156 int 157 nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) 158 { 159 int len; 160 struct args { 161 n_long len; 162 char path[FNAME_SIZE]; 163 } *args; 164 struct repl { 165 n_long errno; 166 u_char fh[NFS_FHSIZE]; 167 } *repl; 168 struct { 169 n_long h[RPC_HEADER_WORDS]; 170 struct args d; 171 } sdata; 172 struct { 173 n_long h[RPC_HEADER_WORDS]; 174 struct repl d; 175 } rdata; 176 size_t cc; 177 178 #ifdef NFS_DEBUG 179 if (debug) 180 printf("nfs_getrootfh: %s\n", path); 181 #endif 182 183 args = &sdata.d; 184 repl = &rdata.d; 185 186 bzero(args, sizeof(*args)); 187 len = strlen(path); 188 if (len > sizeof(args->path)) 189 len = sizeof(args->path); 190 args->len = htonl(len); 191 bcopy(path, args->path, len); 192 len = 4 + roundup(len, 4); 193 194 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 195 args, len, repl, sizeof(*repl)); 196 if (cc == -1) { 197 /* errno was set by rpc_call */ 198 return (errno); 199 } 200 if (cc < 4) 201 return (EBADRPC); 202 if (repl->errno) 203 return (ntohl(repl->errno)); 204 bcopy(repl->fh, fhp, sizeof(repl->fh)); 205 206 /* 207 * Improve boot performance over NFS 208 */ 209 if (getenv("nfs.read_size") != NULL) 210 nfs_read_size = strtol(getenv("nfs.read_size"), NULL, 0); 211 if (nfs_read_size < NFSREAD_MIN_SIZE) 212 nfs_read_size = NFSREAD_MIN_SIZE; 213 if (nfs_read_size > NFSREAD_MAX_SIZE) 214 nfs_read_size = NFSREAD_MAX_SIZE; 215 216 return (0); 217 } 218 219 /* 220 * Lookup a file. Store handle and attributes. 221 * Return zero or error number. 222 */ 223 int 224 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 225 { 226 int len, rlen; 227 struct args { 228 u_char fh[NFS_FHSIZE]; 229 n_long len; 230 char name[FNAME_SIZE]; 231 } *args; 232 struct repl { 233 n_long errno; 234 u_char fh[NFS_FHSIZE]; 235 struct nfsv2_fattrs fa; 236 } *repl; 237 struct { 238 n_long h[RPC_HEADER_WORDS]; 239 struct args d; 240 } sdata; 241 struct { 242 n_long h[RPC_HEADER_WORDS]; 243 struct repl d; 244 } rdata; 245 ssize_t cc; 246 247 #ifdef NFS_DEBUG 248 if (debug) 249 printf("lookupfh: called\n"); 250 #endif 251 252 args = &sdata.d; 253 repl = &rdata.d; 254 255 bzero(args, sizeof(*args)); 256 bcopy(d->fh, args->fh, sizeof(args->fh)); 257 len = strlen(name); 258 if (len > sizeof(args->name)) 259 len = sizeof(args->name); 260 bcopy(name, args->name, len); 261 args->len = htonl(len); 262 len = 4 + roundup(len, 4); 263 len += NFS_FHSIZE; 264 265 rlen = sizeof(*repl); 266 267 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 268 args, len, repl, rlen); 269 if (cc == -1) 270 return (errno); /* XXX - from rpc_call */ 271 if (cc < 4) 272 return (EIO); 273 if (repl->errno) { 274 /* saerrno.h now matches NFS error numbers. */ 275 return (ntohl(repl->errno)); 276 } 277 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 278 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 279 return (0); 280 } 281 282 #ifndef NFS_NOSYMLINK 283 /* 284 * Get the destination of a symbolic link. 285 */ 286 int 287 nfs_readlink(struct nfs_iodesc *d, char *buf) 288 { 289 struct { 290 n_long h[RPC_HEADER_WORDS]; 291 u_char fh[NFS_FHSIZE]; 292 } sdata; 293 struct { 294 n_long h[RPC_HEADER_WORDS]; 295 struct nfs_readlnk_repl d; 296 } rdata; 297 ssize_t cc; 298 299 #ifdef NFS_DEBUG 300 if (debug) 301 printf("readlink: called\n"); 302 #endif 303 304 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 305 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 306 sdata.fh, NFS_FHSIZE, 307 &rdata.d, sizeof(rdata.d)); 308 if (cc == -1) 309 return (errno); 310 311 if (cc < 4) 312 return (EIO); 313 314 if (rdata.d.errno) 315 return (ntohl(rdata.d.errno)); 316 317 rdata.d.len = ntohl(rdata.d.len); 318 if (rdata.d.len > NFS_MAXPATHLEN) 319 return (ENAMETOOLONG); 320 321 bcopy(rdata.d.path, buf, rdata.d.len); 322 buf[rdata.d.len] = 0; 323 return (0); 324 } 325 #endif 326 327 /* 328 * Read data from a file. 329 * Return transfer count or -1 (and set errno) 330 */ 331 ssize_t 332 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 333 { 334 struct nfs_read_args *args; 335 struct nfs_read_repl *repl; 336 struct { 337 n_long h[RPC_HEADER_WORDS]; 338 struct nfs_read_args d; 339 } sdata; 340 struct { 341 n_long h[RPC_HEADER_WORDS]; 342 struct nfs_read_repl d; 343 } rdata; 344 size_t cc; 345 long x; 346 int hlen, rlen; 347 348 args = &sdata.d; 349 repl = &rdata.d; 350 351 bcopy(d->fh, args->fh, NFS_FHSIZE); 352 args->off = htonl((n_long)off); 353 if (len > nfs_read_size) 354 len = nfs_read_size; 355 args->len = htonl((n_long)len); 356 args->xxx = htonl((n_long)0); 357 hlen = offsetof(struct nfs_read_repl, data[0]); 358 359 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 360 args, sizeof(*args), 361 repl, sizeof(*repl)); 362 if (cc == -1) { 363 /* errno was already set by rpc_call */ 364 return (-1); 365 } 366 if (cc < hlen) { 367 errno = EBADRPC; 368 return (-1); 369 } 370 if (repl->errno) { 371 errno = ntohl(repl->errno); 372 return (-1); 373 } 374 rlen = cc - hlen; 375 x = ntohl(repl->count); 376 if (rlen < x) { 377 printf("nfsread: short packet, %d < %ld\n", rlen, x); 378 errno = EBADRPC; 379 return(-1); 380 } 381 bcopy(repl->data, addr, x); 382 return (x); 383 } 384 385 /* 386 * Open a file. 387 * return zero or error number 388 */ 389 int 390 nfs_open(const char *upath, struct open_file *f) 391 { 392 struct iodesc *desc; 393 struct nfs_iodesc *currfd; 394 #ifndef NFS_NOSYMLINK 395 struct nfs_iodesc *newfd; 396 struct nfsv2_fattrs *fa; 397 char *cp, *ncp; 398 int c; 399 char namebuf[NFS_MAXPATHLEN + 1]; 400 char linkbuf[NFS_MAXPATHLEN + 1]; 401 int nlinks = 0; 402 #endif 403 int error; 404 char *path; 405 406 #ifdef NFS_DEBUG 407 if (debug) 408 printf("nfs_open: %s (rootpath=%s)\n", path, rootpath); 409 #endif 410 if (!rootpath[0]) { 411 printf("no rootpath, no nfs\n"); 412 return (ENXIO); 413 } 414 415 /* Avoid trying out nfs_open for disk devices in the EFI loader */ 416 #ifndef __i386__ 417 if (strcmp(f->f_dev->dv_name, "net") != 0) 418 return (EINVAL); 419 #endif 420 421 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 422 return(EINVAL); 423 424 /* Bind to a reserved port. */ 425 desc->myport = htons(rpc_newport()); 426 desc->destip = rootip; 427 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 428 return (error); 429 nfs_root_node.iodesc = desc; 430 431 #ifndef NFS_NOSYMLINK 432 /* Fake up attributes for the root dir. */ 433 fa = &nfs_root_node.fa; 434 fa->fa_type = htonl(NFDIR); 435 fa->fa_mode = htonl(0755); 436 fa->fa_nlink = htonl(2); 437 438 currfd = &nfs_root_node; 439 newfd = NULL; 440 441 cp = path = strdup(upath); 442 if (path == NULL) { 443 error = ENOMEM; 444 goto out; 445 } 446 while (*cp) { 447 /* 448 * Remove extra separators 449 */ 450 while (*cp == '/') 451 cp++; 452 453 if (*cp == '\0') 454 break; 455 /* 456 * Check that current node is a directory. 457 */ 458 if (currfd->fa.fa_type != htonl(NFDIR)) { 459 error = ENOTDIR; 460 goto out; 461 } 462 463 /* allocate file system specific data structure */ 464 newfd = malloc(sizeof(*newfd)); 465 newfd->iodesc = currfd->iodesc; 466 newfd->off = 0; 467 468 /* 469 * Get next component of path name. 470 */ 471 { 472 int len = 0; 473 474 ncp = cp; 475 while ((c = *cp) != '\0' && c != '/') { 476 if (++len > NFS_MAXNAMLEN) { 477 error = ENOENT; 478 goto out; 479 } 480 cp++; 481 } 482 *cp = '\0'; 483 } 484 485 /* lookup a file handle */ 486 error = nfs_lookupfh(currfd, ncp, newfd); 487 *cp = c; 488 if (error) 489 goto out; 490 491 /* 492 * Check for symbolic link 493 */ 494 if (newfd->fa.fa_type == htonl(NFLNK)) { 495 int link_len, len; 496 497 error = nfs_readlink(newfd, linkbuf); 498 if (error) 499 goto out; 500 501 link_len = strlen(linkbuf); 502 len = strlen(cp); 503 504 if (link_len + len > MAXPATHLEN 505 || ++nlinks > MAXSYMLINKS) { 506 error = ENOENT; 507 goto out; 508 } 509 510 bcopy(cp, &namebuf[link_len], len + 1); 511 bcopy(linkbuf, namebuf, link_len); 512 513 /* 514 * If absolute pathname, restart at root. 515 * If relative pathname, restart at parent directory. 516 */ 517 cp = namebuf; 518 if (*cp == '/') { 519 if (currfd != &nfs_root_node) 520 free(currfd); 521 currfd = &nfs_root_node; 522 } 523 524 free(newfd); 525 newfd = NULL; 526 527 continue; 528 } 529 530 if (currfd != &nfs_root_node) 531 free(currfd); 532 currfd = newfd; 533 newfd = NULL; 534 } 535 536 error = 0; 537 538 out: 539 if (newfd) 540 free(newfd); 541 if (path) 542 free(path); 543 #else 544 /* allocate file system specific data structure */ 545 currfd = malloc(sizeof(*currfd)); 546 currfd->iodesc = desc; 547 currfd->off = 0; 548 549 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 550 #endif 551 if (!error) { 552 f->f_fsdata = (void *)currfd; 553 return (0); 554 } 555 556 #ifdef NFS_DEBUG 557 if (debug) 558 printf("nfs_open: %s lookupfh failed: %s\n", 559 path, strerror(error)); 560 #endif 561 #ifndef NFS_NOSYMLINK 562 if (currfd != &nfs_root_node) 563 #endif 564 free(currfd); 565 566 return (error); 567 } 568 569 int 570 nfs_close(struct open_file *f) 571 { 572 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 573 574 #ifdef NFS_DEBUG 575 if (debug) 576 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 577 #endif 578 579 f->f_fsdata = NULL; 580 if (fp && fp != &nfs_root_node) 581 free(fp); 582 583 return (0); 584 } 585 586 /* 587 * read a portion of a file 588 * 589 * Parameters: 590 * resid: out 591 */ 592 int 593 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 594 { 595 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 596 ssize_t cc; 597 static int tc; 598 char *addr = buf; 599 600 #ifdef NFS_DEBUG 601 if (debug) 602 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 603 (int)fp->off); 604 #endif 605 while ((int)size > 0) { 606 if (!(tc++ % 256)) 607 twiddle(); 608 cc = nfs_readdata(fp, fp->off, addr, size); 609 /* XXX maybe should retry on certain errors */ 610 if (cc == -1) { 611 #ifdef NFS_DEBUG 612 if (debug) 613 printf("nfs_read: read: %s", strerror(errno)); 614 #endif 615 return (errno); /* XXX - from nfs_readdata */ 616 } 617 if (cc == 0) { 618 #ifdef NFS_DEBUG 619 if (debug) 620 printf("nfs_read: hit EOF unexpectantly"); 621 #endif 622 goto ret; 623 } 624 fp->off += cc; 625 addr += cc; 626 size -= cc; 627 } 628 ret: 629 if (resid) 630 *resid = size; 631 632 return (0); 633 } 634 635 /* 636 * Not implemented. 637 * 638 * Parameters: 639 * resid: out 640 */ 641 int 642 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 643 { 644 return (EROFS); 645 } 646 647 off_t 648 nfs_seek(struct open_file *f, off_t offset, int where) 649 { 650 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 651 n_long size = ntohl(d->fa.fa_size); 652 653 switch (where) { 654 case SEEK_SET: 655 d->off = offset; 656 break; 657 case SEEK_CUR: 658 d->off += offset; 659 break; 660 case SEEK_END: 661 d->off = size - offset; 662 break; 663 default: 664 return (-1); 665 } 666 667 return (d->off); 668 } 669 670 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 671 int nfs_stat_types[8] = { 672 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 673 674 int 675 nfs_stat(struct open_file *f, struct stat *sb) 676 { 677 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 678 n_long ftype, mode; 679 680 ftype = ntohl(fp->fa.fa_type); 681 mode = ntohl(fp->fa.fa_mode); 682 mode |= nfs_stat_types[ftype & 7]; 683 684 sb->st_mode = mode; 685 sb->st_nlink = ntohl(fp->fa.fa_nlink); 686 sb->st_uid = ntohl(fp->fa.fa_uid); 687 sb->st_gid = ntohl(fp->fa.fa_gid); 688 sb->st_size = ntohl(fp->fa.fa_size); 689 690 return (0); 691 } 692 693 static int 694 nfs_readdir(struct open_file *f, struct dirent *d) 695 { 696 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 697 struct nfs_readdir_args *args; 698 struct nfs_readdir_data *rd; 699 struct nfs_readdir_off *roff = NULL; 700 static char *buf; 701 static n_long cookie = 0; 702 size_t cc; 703 n_long eof; 704 705 struct { 706 n_long h[RPC_HEADER_WORDS]; 707 struct nfs_readdir_args d; 708 } sdata; 709 static struct { 710 n_long h[RPC_HEADER_WORDS]; 711 u_char d[NFS_READDIRSIZE]; 712 } rdata; 713 714 if (cookie == 0) { 715 refill: 716 args = &sdata.d; 717 bzero(args, sizeof(*args)); 718 719 bcopy(fp->fh, args->fh, NFS_FHSIZE); 720 args->cookie = htonl(cookie); 721 args->count = htonl(NFS_READDIRSIZE); 722 723 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 724 args, sizeof(*args), 725 rdata.d, sizeof(rdata.d)); 726 buf = rdata.d; 727 roff = (struct nfs_readdir_off *)buf; 728 if (ntohl(roff->cookie) != 0) 729 return 1; 730 } 731 roff = (struct nfs_readdir_off *)buf; 732 733 if (ntohl(roff->follows) == 0) { 734 eof = ntohl((roff+1)->cookie); 735 if (eof) { 736 cookie = 0; 737 return 1; 738 } 739 goto refill; 740 } 741 742 buf += sizeof(struct nfs_readdir_off); 743 rd = (struct nfs_readdir_data *)buf; 744 d->d_namlen = ntohl(rd->len); 745 bcopy(rd->name, d->d_name, d->d_namlen); 746 d->d_name[d->d_namlen] = '\0'; 747 748 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 749 roff = (struct nfs_readdir_off *)buf; 750 cookie = ntohl(roff->cookie); 751 return 0; 752 } 753