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