nfs.c revision 185155
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: head/lib/libstand/nfs.c 185155 2008-11-21 09:14:29Z luigi $"); 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 our own NFS attributes without NQNFS stuff. */ 54struct nfsv2_fattrs { 55 n_long fa_type; 56 n_long fa_mode; 57 n_long fa_nlink; 58 n_long fa_uid; 59 n_long fa_gid; 60 n_long fa_size; 61 n_long fa_blocksize; 62 n_long fa_rdev; 63 n_long fa_blocks; 64 n_long fa_fsid; 65 n_long fa_fileid; 66 struct nfsv2_time fa_atime; 67 struct nfsv2_time fa_mtime; 68 struct nfsv2_time fa_ctime; 69}; 70 71 72struct nfs_read_args { 73 u_char fh[NFS_FHSIZE]; 74 n_long off; 75 n_long len; 76 n_long xxx; /* XXX what's this for? */ 77}; 78 79/* Data part of nfs rpc reply (also the largest thing we receive) */ 80#define NFSREAD_SIZE 1024 81struct nfs_read_repl { 82 n_long errno; 83 struct nfsv2_fattrs fa; 84 n_long count; 85 u_char data[NFSREAD_SIZE]; 86}; 87 88#ifndef NFS_NOSYMLINK 89struct nfs_readlnk_repl { 90 n_long errno; 91 n_long len; 92 char path[NFS_MAXPATHLEN]; 93}; 94#endif 95 96struct nfs_readdir_args { 97 u_char fh[NFS_FHSIZE]; 98 n_long cookie; 99 n_long count; 100}; 101 102struct nfs_readdir_data { 103 n_long fileid; 104 n_long len; 105 char name[0]; 106}; 107 108struct nfs_readdir_off { 109 n_long cookie; 110 n_long follows; 111}; 112 113struct nfs_iodesc { 114 struct iodesc *iodesc; 115 off_t off; 116 u_char fh[NFS_FHSIZE]; 117 struct nfsv2_fattrs fa; /* all in network order */ 118}; 119 120/* 121 * XXX interactions with tftp? See nfswrapper.c for a confusing 122 * issue. 123 */ 124int nfs_open(const char *path, struct open_file *f); 125static int nfs_close(struct open_file *f); 126static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 127static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 128static off_t nfs_seek(struct open_file *f, off_t offset, int where); 129static int nfs_stat(struct open_file *f, struct stat *sb); 130static int nfs_readdir(struct open_file *f, struct dirent *d); 131 132struct nfs_iodesc nfs_root_node; 133 134struct fs_ops nfs_fsops = { 135 "nfs", 136 nfs_open, 137 nfs_close, 138 nfs_read, 139 nfs_write, 140 nfs_seek, 141 nfs_stat, 142 nfs_readdir 143}; 144 145/* 146 * Fetch the root file handle (call mount daemon) 147 * Return zero or error number. 148 */ 149int 150nfs_getrootfh(d, path, fhp) 151 struct iodesc *d; 152 char *path; 153 u_char *fhp; 154{ 155 int len; 156 struct args { 157 n_long len; 158 char path[FNAME_SIZE]; 159 } *args; 160 struct repl { 161 n_long errno; 162 u_char fh[NFS_FHSIZE]; 163 } *repl; 164 struct { 165 n_long h[RPC_HEADER_WORDS]; 166 struct args d; 167 } sdata; 168 struct { 169 n_long h[RPC_HEADER_WORDS]; 170 struct repl d; 171 } rdata; 172 size_t cc; 173 174#ifdef NFS_DEBUG 175 if (debug) 176 printf("nfs_getrootfh: %s\n", path); 177#endif 178 179 args = &sdata.d; 180 repl = &rdata.d; 181 182 bzero(args, sizeof(*args)); 183 len = strlen(path); 184 if (len > sizeof(args->path)) 185 len = sizeof(args->path); 186 args->len = htonl(len); 187 bcopy(path, args->path, len); 188 len = 4 + roundup(len, 4); 189 190 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 191 args, len, repl, sizeof(*repl)); 192 if (cc == -1) { 193 /* errno was set by rpc_call */ 194 return (errno); 195 } 196 if (cc < 4) 197 return (EBADRPC); 198 if (repl->errno) 199 return (ntohl(repl->errno)); 200 bcopy(repl->fh, fhp, sizeof(repl->fh)); 201 return (0); 202} 203 204/* 205 * Lookup a file. Store handle and attributes. 206 * Return zero or error number. 207 */ 208int 209nfs_lookupfh(d, name, newfd) 210 struct nfs_iodesc *d; 211 const char *name; 212 struct nfs_iodesc *newfd; 213{ 214 int len, rlen; 215 struct args { 216 u_char fh[NFS_FHSIZE]; 217 n_long len; 218 char name[FNAME_SIZE]; 219 } *args; 220 struct repl { 221 n_long errno; 222 u_char fh[NFS_FHSIZE]; 223 struct nfsv2_fattrs fa; 224 } *repl; 225 struct { 226 n_long h[RPC_HEADER_WORDS]; 227 struct args d; 228 } sdata; 229 struct { 230 n_long h[RPC_HEADER_WORDS]; 231 struct repl d; 232 } rdata; 233 ssize_t cc; 234 235#ifdef NFS_DEBUG 236 if (debug) 237 printf("lookupfh: called\n"); 238#endif 239 240 args = &sdata.d; 241 repl = &rdata.d; 242 243 bzero(args, sizeof(*args)); 244 bcopy(d->fh, args->fh, sizeof(args->fh)); 245 len = strlen(name); 246 if (len > sizeof(args->name)) 247 len = sizeof(args->name); 248 bcopy(name, args->name, len); 249 args->len = htonl(len); 250 len = 4 + roundup(len, 4); 251 len += NFS_FHSIZE; 252 253 rlen = sizeof(*repl); 254 255 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 256 args, len, repl, rlen); 257 if (cc == -1) 258 return (errno); /* XXX - from rpc_call */ 259 if (cc < 4) 260 return (EIO); 261 if (repl->errno) { 262 /* saerrno.h now matches NFS error numbers. */ 263 return (ntohl(repl->errno)); 264 } 265 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 266 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 267 return (0); 268} 269 270#ifndef NFS_NOSYMLINK 271/* 272 * Get the destination of a symbolic link. 273 */ 274int 275nfs_readlink(d, buf) 276 struct nfs_iodesc *d; 277 char *buf; 278{ 279 struct { 280 n_long h[RPC_HEADER_WORDS]; 281 u_char fh[NFS_FHSIZE]; 282 } sdata; 283 struct { 284 n_long h[RPC_HEADER_WORDS]; 285 struct nfs_readlnk_repl d; 286 } rdata; 287 ssize_t cc; 288 289#ifdef NFS_DEBUG 290 if (debug) 291 printf("readlink: called\n"); 292#endif 293 294 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 295 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 296 sdata.fh, NFS_FHSIZE, 297 &rdata.d, sizeof(rdata.d)); 298 if (cc == -1) 299 return (errno); 300 301 if (cc < 4) 302 return (EIO); 303 304 if (rdata.d.errno) 305 return (ntohl(rdata.d.errno)); 306 307 rdata.d.len = ntohl(rdata.d.len); 308 if (rdata.d.len > NFS_MAXPATHLEN) 309 return (ENAMETOOLONG); 310 311 bcopy(rdata.d.path, buf, rdata.d.len); 312 buf[rdata.d.len] = 0; 313 return (0); 314} 315#endif 316 317/* 318 * Read data from a file. 319 * Return transfer count or -1 (and set errno) 320 */ 321ssize_t 322nfs_readdata(d, off, addr, len) 323 struct nfs_iodesc *d; 324 off_t off; 325 void *addr; 326 size_t len; 327{ 328 struct nfs_read_args *args; 329 struct nfs_read_repl *repl; 330 struct { 331 n_long h[RPC_HEADER_WORDS]; 332 struct nfs_read_args d; 333 } sdata; 334 struct { 335 n_long h[RPC_HEADER_WORDS]; 336 struct nfs_read_repl d; 337 } rdata; 338 size_t cc; 339 long x; 340 int hlen, rlen; 341 342 args = &sdata.d; 343 repl = &rdata.d; 344 345 bcopy(d->fh, args->fh, NFS_FHSIZE); 346 args->off = htonl((n_long)off); 347 if (len > NFSREAD_SIZE) 348 len = NFSREAD_SIZE; 349 args->len = htonl((n_long)len); 350 args->xxx = htonl((n_long)0); 351 hlen = sizeof(*repl) - NFSREAD_SIZE; 352 353 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 354 args, sizeof(*args), 355 repl, sizeof(*repl)); 356 if (cc == -1) { 357 /* errno was already set by rpc_call */ 358 return (-1); 359 } 360 if (cc < hlen) { 361 errno = EBADRPC; 362 return (-1); 363 } 364 if (repl->errno) { 365 errno = ntohl(repl->errno); 366 return (-1); 367 } 368 rlen = cc - hlen; 369 x = ntohl(repl->count); 370 if (rlen < x) { 371 printf("nfsread: short packet, %d < %ld\n", rlen, x); 372 errno = EBADRPC; 373 return(-1); 374 } 375 bcopy(repl->data, addr, x); 376 return (x); 377} 378 379/* 380 * Open a file. 381 * return zero or error number 382 */ 383int 384nfs_open(upath, f) 385 const char *upath; 386 struct open_file *f; 387{ 388 struct iodesc *desc; 389 struct nfs_iodesc *currfd; 390 char buf[2 * NFS_FHSIZE + 3]; 391 u_char *fh; 392 char *cp; 393 int i; 394#ifndef NFS_NOSYMLINK 395 struct nfs_iodesc *newfd; 396 struct nfsv2_fattrs *fa; 397 char *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", upath, rootpath); 409#endif 410 if (!rootpath[0]) { 411 printf("no rootpath, no nfs\n"); 412 return (ENXIO); 413 } 414 415 /* 416 * This is silly - we should look at dv_type but that value is 417 * arch dependant and we can't use it here. 418 */ 419#ifndef __i386__ 420 if (strcmp(f->f_dev->dv_name, "net") != 0) 421 return(EINVAL); 422#else 423 if (strcmp(f->f_dev->dv_name, "pxe") != 0) 424 return(EINVAL); 425#endif 426 427 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 428 return(EINVAL); 429 430 /* Bind to a reserved port. */ 431 desc->myport = htons(--rpc_port); 432 desc->destip = rootip; 433 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 434 return (error); 435 nfs_root_node.iodesc = desc; 436 437 fh = &nfs_root_node.fh[0]; 438 buf[0] = 'X'; 439 cp = &buf[1]; 440 for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 441 sprintf(cp, "%02x", fh[i]); 442 sprintf(cp, "X"); 443 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 444 setenv("boot.nfsroot.path", rootpath, 1); 445 setenv("boot.nfsroot.nfshandle", buf, 1); 446 447#ifndef NFS_NOSYMLINK 448 /* Fake up attributes for the root dir. */ 449 fa = &nfs_root_node.fa; 450 fa->fa_type = htonl(NFDIR); 451 fa->fa_mode = htonl(0755); 452 fa->fa_nlink = htonl(2); 453 454 currfd = &nfs_root_node; 455 newfd = 0; 456 457 cp = path = strdup(upath); 458 if (path == NULL) { 459 error = ENOMEM; 460 goto out; 461 } 462 while (*cp) { 463 /* 464 * Remove extra separators 465 */ 466 while (*cp == '/') 467 cp++; 468 469 if (*cp == '\0') 470 break; 471 /* 472 * Check that current node is a directory. 473 */ 474 if (currfd->fa.fa_type != htonl(NFDIR)) { 475 error = ENOTDIR; 476 goto out; 477 } 478 479 /* allocate file system specific data structure */ 480 newfd = malloc(sizeof(*newfd)); 481 newfd->iodesc = currfd->iodesc; 482 newfd->off = 0; 483 484 /* 485 * Get next component of path name. 486 */ 487 { 488 int len = 0; 489 490 ncp = cp; 491 while ((c = *cp) != '\0' && c != '/') { 492 if (++len > NFS_MAXNAMLEN) { 493 error = ENOENT; 494 goto out; 495 } 496 cp++; 497 } 498 *cp = '\0'; 499 } 500 501 /* lookup a file handle */ 502 error = nfs_lookupfh(currfd, ncp, newfd); 503 *cp = c; 504 if (error) 505 goto out; 506 507 /* 508 * Check for symbolic link 509 */ 510 if (newfd->fa.fa_type == htonl(NFLNK)) { 511 int link_len, len; 512 513 error = nfs_readlink(newfd, linkbuf); 514 if (error) 515 goto out; 516 517 link_len = strlen(linkbuf); 518 len = strlen(cp); 519 520 if (link_len + len > MAXPATHLEN 521 || ++nlinks > MAXSYMLINKS) { 522 error = ENOENT; 523 goto out; 524 } 525 526 bcopy(cp, &namebuf[link_len], len + 1); 527 bcopy(linkbuf, namebuf, link_len); 528 529 /* 530 * If absolute pathname, restart at root. 531 * If relative pathname, restart at parent directory. 532 */ 533 cp = namebuf; 534 if (*cp == '/') { 535 if (currfd != &nfs_root_node) 536 free(currfd); 537 currfd = &nfs_root_node; 538 } 539 540 free(newfd); 541 newfd = 0; 542 543 continue; 544 } 545 546 if (currfd != &nfs_root_node) 547 free(currfd); 548 currfd = newfd; 549 newfd = 0; 550 } 551 552 error = 0; 553 554out: 555 if (newfd) 556 free(newfd); 557 if (path) 558 free(path); 559#else 560 /* allocate file system specific data structure */ 561 currfd = malloc(sizeof(*currfd)); 562 currfd->iodesc = desc; 563 currfd->off = 0; 564 565 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 566#endif 567 if (!error) { 568 f->f_fsdata = (void *)currfd; 569 return (0); 570 } 571 572#ifdef NFS_DEBUG 573 if (debug) 574 printf("nfs_open: %s lookupfh failed: %s\n", 575 path, strerror(error)); 576#endif 577#ifndef NFS_NOSYMLINK 578 if (currfd != &nfs_root_node) 579#endif 580 free(currfd); 581 582 return (error); 583} 584 585int 586nfs_close(f) 587 struct open_file *f; 588{ 589 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 590 591#ifdef NFS_DEBUG 592 if (debug) 593 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 594#endif 595 596 if (fp != &nfs_root_node && fp) 597 free(fp); 598 f->f_fsdata = (void *)0; 599 600 return (0); 601} 602 603/* 604 * read a portion of a file 605 */ 606int 607nfs_read(f, buf, size, resid) 608 struct open_file *f; 609 void *buf; 610 size_t size; 611 size_t *resid; /* out */ 612{ 613 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 614 ssize_t cc; 615 char *addr = buf; 616 617#ifdef NFS_DEBUG 618 if (debug) 619 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 620 (int)fp->off); 621#endif 622 while ((int)size > 0) { 623 twiddle(); 624 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 625 /* XXX maybe should retry on certain errors */ 626 if (cc == -1) { 627#ifdef NFS_DEBUG 628 if (debug) 629 printf("nfs_read: read: %s", strerror(errno)); 630#endif 631 return (errno); /* XXX - from nfs_readdata */ 632 } 633 if (cc == 0) { 634#ifdef NFS_DEBUG 635 if (debug) 636 printf("nfs_read: hit EOF unexpectantly"); 637#endif 638 goto ret; 639 } 640 fp->off += cc; 641 addr += cc; 642 size -= cc; 643 } 644ret: 645 if (resid) 646 *resid = size; 647 648 return (0); 649} 650 651/* 652 * Not implemented. 653 */ 654int 655nfs_write(f, buf, size, resid) 656 struct open_file *f; 657 void *buf; 658 size_t size; 659 size_t *resid; /* out */ 660{ 661 return (EROFS); 662} 663 664off_t 665nfs_seek(f, offset, where) 666 struct open_file *f; 667 off_t offset; 668 int where; 669{ 670 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 671 n_long size = ntohl(d->fa.fa_size); 672 673 switch (where) { 674 case SEEK_SET: 675 d->off = offset; 676 break; 677 case SEEK_CUR: 678 d->off += offset; 679 break; 680 case SEEK_END: 681 d->off = size - offset; 682 break; 683 default: 684 errno = EINVAL; 685 return (-1); 686 } 687 688 return (d->off); 689} 690 691/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 692int nfs_stat_types[8] = { 693 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 694 695int 696nfs_stat(f, sb) 697 struct open_file *f; 698 struct stat *sb; 699{ 700 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 701 n_long ftype, mode; 702 703 ftype = ntohl(fp->fa.fa_type); 704 mode = ntohl(fp->fa.fa_mode); 705 mode |= nfs_stat_types[ftype & 7]; 706 707 sb->st_mode = mode; 708 sb->st_nlink = ntohl(fp->fa.fa_nlink); 709 sb->st_uid = ntohl(fp->fa.fa_uid); 710 sb->st_gid = ntohl(fp->fa.fa_gid); 711 sb->st_size = ntohl(fp->fa.fa_size); 712 713 return (0); 714} 715 716static int 717nfs_readdir(struct open_file *f, struct dirent *d) 718{ 719 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 720 struct nfs_readdir_args *args; 721 struct nfs_readdir_data *rd; 722 struct nfs_readdir_off *roff = NULL; 723 static char *buf; 724 static n_long cookie = 0; 725 size_t cc; 726 n_long eof; 727 728 struct { 729 n_long h[RPC_HEADER_WORDS]; 730 struct nfs_readdir_args d; 731 } sdata; 732 static struct { 733 n_long h[RPC_HEADER_WORDS]; 734 u_char d[NFS_READDIRSIZE]; 735 } rdata; 736 737 if (cookie == 0) { 738 refill: 739 args = &sdata.d; 740 bzero(args, sizeof(*args)); 741 742 bcopy(fp->fh, args->fh, NFS_FHSIZE); 743 args->cookie = htonl(cookie); 744 args->count = htonl(NFS_READDIRSIZE); 745 746 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 747 args, sizeof(*args), 748 rdata.d, sizeof(rdata.d)); 749 buf = rdata.d; 750 roff = (struct nfs_readdir_off *)buf; 751 if (ntohl(roff->cookie) != 0) 752 return EIO; 753 } 754 roff = (struct nfs_readdir_off *)buf; 755 756 if (ntohl(roff->follows) == 0) { 757 eof = ntohl((roff+1)->cookie); 758 if (eof) { 759 cookie = 0; 760 return ENOENT; 761 } 762 goto refill; 763 } 764 765 buf += sizeof(struct nfs_readdir_off); 766 rd = (struct nfs_readdir_data *)buf; 767 d->d_namlen = ntohl(rd->len); 768 bcopy(rd->name, d->d_name, d->d_namlen); 769 d->d_name[d->d_namlen] = '\0'; 770 771 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 772 roff = (struct nfs_readdir_off *)buf; 773 cookie = ntohl(roff->cookie); 774 return 0; 775} 776