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