nfs.c revision 124811
1170076Skmacy/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 2170076Skmacy 3170076Skmacy/*- 4170076Skmacy * Copyright (c) 1993 John Brezak 5170076Skmacy * All rights reserved. 6174686Skmacy * 7174686Skmacy * Redistribution and use in source and binary forms, with or without 8174637Skmacy * modification, are permitted provided that the following conditions 9174637Skmacy * are met: 10170076Skmacy * 1. Redistributions of source code must retain the above copyright 11170076Skmacy * notice, this list of conditions and the following disclaimer. 12170076Skmacy * 2. Redistributions in binary form must reproduce the above copyright 13170076Skmacy * notice, this list of conditions and the following disclaimer in the 14170076Skmacy * documentation and/or other materials provided with the distribution. 15170076Skmacy * 3. The name of the author may not be used to endorse or promote products 16170076Skmacy * derived from this software without specific prior written permission. 17172109Skmacy * 18172109Skmacy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19170076Skmacy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20170076Skmacy * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21174626Skmacy * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22170076Skmacy * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23170076Skmacy * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24170076Skmacy * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25170076Skmacy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26170076Skmacy * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27170076Skmacy * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28170076Skmacy * POSSIBILITY OF SUCH DAMAGE. 29170076Skmacy */ 30170076Skmacy 31170076Skmacy#include <sys/cdefs.h> 32170076Skmacy__FBSDID("$FreeBSD: head/lib/libstand/nfs.c 124811 2004-01-21 20:12:23Z jhb $"); 33170076Skmacy 34174626Skmacy#include <sys/param.h> 35170076Skmacy#include <sys/time.h> 36174626Skmacy#include <sys/socket.h> 37174626Skmacy#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", path, rootpath); 409#endif 410 if (!rootpath[0]) { 411 printf("no rootpath, no nfs\n"); 412 return (ENXIO); 413 } 414 415#ifndef __i386__ 416 if (strcmp(f->f_dev->dv_name, "net") != 0) 417 return(EINVAL); 418#endif 419 420 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 421 return(EINVAL); 422 423 /* Bind to a reserved port. */ 424 desc->myport = htons(--rpc_port); 425 desc->destip = rootip; 426 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 427 return (error); 428 nfs_root_node.iodesc = desc; 429 430 fh = &nfs_root_node.fh[0]; 431 buf[0] = 'X'; 432 cp = &buf[1]; 433 for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 434 sprintf(cp, "%02x", fh[i]); 435 sprintf(cp, "X"); 436 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 437 setenv("boot.nfsroot.path", rootpath, 1); 438 setenv("boot.nfsroot.nfshandle", buf, 1); 439 440#ifndef NFS_NOSYMLINK 441 /* Fake up attributes for the root dir. */ 442 fa = &nfs_root_node.fa; 443 fa->fa_type = htonl(NFDIR); 444 fa->fa_mode = htonl(0755); 445 fa->fa_nlink = htonl(2); 446 447 currfd = &nfs_root_node; 448 newfd = 0; 449 450 cp = path = strdup(upath); 451 if (path == NULL) { 452 error = ENOMEM; 453 goto out; 454 } 455 while (*cp) { 456 /* 457 * Remove extra separators 458 */ 459 while (*cp == '/') 460 cp++; 461 462 if (*cp == '\0') 463 break; 464 /* 465 * Check that current node is a directory. 466 */ 467 if (currfd->fa.fa_type != htonl(NFDIR)) { 468 error = ENOTDIR; 469 goto out; 470 } 471 472 /* allocate file system specific data structure */ 473 newfd = malloc(sizeof(*newfd)); 474 newfd->iodesc = currfd->iodesc; 475 newfd->off = 0; 476 477 /* 478 * Get next component of path name. 479 */ 480 { 481 int len = 0; 482 483 ncp = cp; 484 while ((c = *cp) != '\0' && c != '/') { 485 if (++len > NFS_MAXNAMLEN) { 486 error = ENOENT; 487 goto out; 488 } 489 cp++; 490 } 491 *cp = '\0'; 492 } 493 494 /* lookup a file handle */ 495 error = nfs_lookupfh(currfd, ncp, newfd); 496 *cp = c; 497 if (error) 498 goto out; 499 500 /* 501 * Check for symbolic link 502 */ 503 if (newfd->fa.fa_type == htonl(NFLNK)) { 504 int link_len, len; 505 506 error = nfs_readlink(newfd, linkbuf); 507 if (error) 508 goto out; 509 510 link_len = strlen(linkbuf); 511 len = strlen(cp); 512 513 if (link_len + len > MAXPATHLEN 514 || ++nlinks > MAXSYMLINKS) { 515 error = ENOENT; 516 goto out; 517 } 518 519 bcopy(cp, &namebuf[link_len], len + 1); 520 bcopy(linkbuf, namebuf, link_len); 521 522 /* 523 * If absolute pathname, restart at root. 524 * If relative pathname, restart at parent directory. 525 */ 526 cp = namebuf; 527 if (*cp == '/') { 528 if (currfd != &nfs_root_node) 529 free(currfd); 530 currfd = &nfs_root_node; 531 } 532 533 free(newfd); 534 newfd = 0; 535 536 continue; 537 } 538 539 if (currfd != &nfs_root_node) 540 free(currfd); 541 currfd = newfd; 542 newfd = 0; 543 } 544 545 error = 0; 546 547out: 548 if (newfd) 549 free(newfd); 550 if (path) 551 free(path); 552#else 553 /* allocate file system specific data structure */ 554 currfd = malloc(sizeof(*currfd)); 555 currfd->iodesc = desc; 556 currfd->off = 0; 557 558 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 559#endif 560 if (!error) { 561 f->f_fsdata = (void *)currfd; 562 return (0); 563 } 564 565#ifdef NFS_DEBUG 566 if (debug) 567 printf("nfs_open: %s lookupfh failed: %s\n", 568 path, strerror(error)); 569#endif 570#ifndef NFS_NOSYMLINK 571 if (currfd != &nfs_root_node) 572#endif 573 free(currfd); 574 575 return (error); 576} 577 578int 579nfs_close(f) 580 struct open_file *f; 581{ 582 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 583 584#ifdef NFS_DEBUG 585 if (debug) 586 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 587#endif 588 589 if (fp != &nfs_root_node && fp) 590 free(fp); 591 f->f_fsdata = (void *)0; 592 593 return (0); 594} 595 596/* 597 * read a portion of a file 598 */ 599int 600nfs_read(f, buf, size, resid) 601 struct open_file *f; 602 void *buf; 603 size_t size; 604 size_t *resid; /* out */ 605{ 606 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 607 ssize_t cc; 608 char *addr = buf; 609 610#ifdef NFS_DEBUG 611 if (debug) 612 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 613 (int)fp->off); 614#endif 615 while ((int)size > 0) { 616 twiddle(); 617 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 618 /* XXX maybe should retry on certain errors */ 619 if (cc == -1) { 620#ifdef NFS_DEBUG 621 if (debug) 622 printf("nfs_read: read: %s", strerror(errno)); 623#endif 624 return (errno); /* XXX - from nfs_readdata */ 625 } 626 if (cc == 0) { 627#ifdef NFS_DEBUG 628 if (debug) 629 printf("nfs_read: hit EOF unexpectantly"); 630#endif 631 goto ret; 632 } 633 fp->off += cc; 634 addr += cc; 635 size -= cc; 636 } 637ret: 638 if (resid) 639 *resid = size; 640 641 return (0); 642} 643 644/* 645 * Not implemented. 646 */ 647int 648nfs_write(f, buf, size, resid) 649 struct open_file *f; 650 void *buf; 651 size_t size; 652 size_t *resid; /* out */ 653{ 654 return (EROFS); 655} 656 657off_t 658nfs_seek(f, offset, where) 659 struct open_file *f; 660 off_t offset; 661 int where; 662{ 663 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 664 n_long size = ntohl(d->fa.fa_size); 665 666 switch (where) { 667 case SEEK_SET: 668 d->off = offset; 669 break; 670 case SEEK_CUR: 671 d->off += offset; 672 break; 673 case SEEK_END: 674 d->off = size - offset; 675 break; 676 default: 677 errno = EINVAL; 678 return (-1); 679 } 680 681 return (d->off); 682} 683 684/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 685int nfs_stat_types[8] = { 686 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 687 688int 689nfs_stat(f, sb) 690 struct open_file *f; 691 struct stat *sb; 692{ 693 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 694 n_long ftype, mode; 695 696 ftype = ntohl(fp->fa.fa_type); 697 mode = ntohl(fp->fa.fa_mode); 698 mode |= nfs_stat_types[ftype & 7]; 699 700 sb->st_mode = mode; 701 sb->st_nlink = ntohl(fp->fa.fa_nlink); 702 sb->st_uid = ntohl(fp->fa.fa_uid); 703 sb->st_gid = ntohl(fp->fa.fa_gid); 704 sb->st_size = ntohl(fp->fa.fa_size); 705 706 return (0); 707} 708 709static int 710nfs_readdir(struct open_file *f, struct dirent *d) 711{ 712 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 713 struct nfs_readdir_args *args; 714 struct nfs_readdir_data *rd; 715 struct nfs_readdir_off *roff = NULL; 716 static char *buf; 717 static n_long cookie = 0; 718 size_t cc; 719 n_long eof; 720 721 struct { 722 n_long h[RPC_HEADER_WORDS]; 723 struct nfs_readdir_args d; 724 } sdata; 725 static struct { 726 n_long h[RPC_HEADER_WORDS]; 727 u_char d[NFS_READDIRSIZE]; 728 } rdata; 729 730 if (cookie == 0) { 731 refill: 732 args = &sdata.d; 733 bzero(args, sizeof(*args)); 734 735 bcopy(fp->fh, args->fh, NFS_FHSIZE); 736 args->cookie = htonl(cookie); 737 args->count = htonl(NFS_READDIRSIZE); 738 739 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 740 args, sizeof(*args), 741 rdata.d, sizeof(rdata.d)); 742 buf = rdata.d; 743 roff = (struct nfs_readdir_off *)buf; 744 if (ntohl(roff->cookie) != 0) 745 return EIO; 746 } 747 roff = (struct nfs_readdir_off *)buf; 748 749 if (ntohl(roff->follows) == 0) { 750 eof = ntohl((roff+1)->cookie); 751 if (eof) { 752 cookie = 0; 753 return ENOENT; 754 } 755 goto refill; 756 } 757 758 buf += sizeof(struct nfs_readdir_off); 759 rd = (struct nfs_readdir_data *)buf; 760 d->d_namlen = ntohl(rd->len); 761 bcopy(rd->name, d->d_name, d->d_namlen); 762 d->d_name[d->d_namlen] = '\0'; 763 764 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 765 roff = (struct nfs_readdir_off *)buf; 766 cookie = ntohl(roff->cookie); 767 return 0; 768} 769