nfs.c revision 59824
1104478Ssam/* $FreeBSD: head/lib/libstand/nfs.c 59824 2000-05-01 10:53:21Z ps $ */ 2104630Ssam/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 3104478Ssam 4139749Simp/*- 5104478Ssam * Copyright (c) 1993 John Brezak 6104478Ssam * All rights reserved. 7104478Ssam * 8104478Ssam * Redistribution and use in source and binary forms, with or without 9104478Ssam * modification, are permitted provided that the following conditions 10104478Ssam * are met: 11104478Ssam * 1. Redistributions of source code must retain the above copyright 12104478Ssam * notice, this list of conditions and the following disclaimer. 13104478Ssam * 2. Redistributions in binary form must reproduce the above copyright 14104478Ssam * notice, this list of conditions and the following disclaimer in the 15104478Ssam * documentation and/or other materials provided with the distribution. 16104478Ssam * 3. The name of the author may not be used to endorse or promote products 17104478Ssam * derived from this software without specific prior written permission. 18104478Ssam * 19104478Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 20104478Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21104478Ssam * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22104478Ssam * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 23104478Ssam * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24104478Ssam * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25104478Ssam * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26104478Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 27104478Ssam * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28104478Ssam * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29104478Ssam * POSSIBILITY OF SUCH DAMAGE. 30104478Ssam */ 31104478Ssam 32104478Ssam#include <sys/param.h> 33104478Ssam#include <sys/time.h> 34104478Ssam#include <sys/socket.h> 35104478Ssam#include <sys/stat.h> 36104478Ssam#include <string.h> 37104478Ssam 38104478Ssam#include <netinet/in.h> 39104478Ssam#include <netinet/in_systm.h> 40104478Ssam 41104478Ssam#include "rpcv2.h" 42104478Ssam#include "nfsv2.h" 43104478Ssam 44104478Ssam#include "stand.h" 45104478Ssam#include "net.h" 46104478Ssam#include "netif.h" 47104478Ssam#include "rpc.h" 48104478Ssam 49104478Ssam#define NFS_DEBUGxx 50104478Ssam 51104478Ssam/* Define our own NFS attributes without NQNFS stuff. */ 52104478Ssamstruct nfsv2_fattrs { 53104478Ssam n_long fa_type; 54104478Ssam n_long fa_mode; 55104478Ssam n_long fa_nlink; 56110519Ssam n_long fa_uid; 57110519Ssam n_long fa_gid; 58104478Ssam n_long fa_size; 59104478Ssam n_long fa_blocksize; 60104478Ssam n_long fa_rdev; 61108823Ssam n_long fa_blocks; 62104478Ssam n_long fa_fsid; 63104478Ssam n_long fa_fileid; 64104478Ssam struct nfsv2_time fa_atime; 65104478Ssam struct nfsv2_time fa_mtime; 66104478Ssam struct nfsv2_time fa_ctime; 67104478Ssam}; 68104478Ssam 69104478Ssam 70104478Ssamstruct nfs_read_args { 71104478Ssam u_char fh[NFS_FHSIZE]; 72104478Ssam n_long off; 73104478Ssam n_long len; 74104478Ssam n_long xxx; /* XXX what's this for? */ 75104478Ssam}; 76104478Ssam 77104478Ssam/* Data part of nfs rpc reply (also the largest thing we receive) */ 78104478Ssam#define NFSREAD_SIZE 1024 79104478Ssamstruct nfs_read_repl { 80104478Ssam n_long errno; 81104478Ssam struct nfsv2_fattrs fa; 82104478Ssam n_long count; 83104478Ssam u_char data[NFSREAD_SIZE]; 84104478Ssam}; 85104478Ssam 86104478Ssam#ifndef NFS_NOSYMLINK 87104478Ssamstruct nfs_readlnk_repl { 88104478Ssam n_long errno; 89104478Ssam n_long len; 90104478Ssam char path[NFS_MAXPATHLEN]; 91104478Ssam}; 92104478Ssam#endif 93104478Ssam 94104478Ssamstruct nfs_iodesc { 95104630Ssam struct iodesc *iodesc; 96104478Ssam off_t off; 97104478Ssam u_char fh[NFS_FHSIZE]; 98104478Ssam struct nfsv2_fattrs fa; /* all in network order */ 99104478Ssam}; 100104478Ssam 101104478Ssam/* 102104478Ssam * XXX interactions with tftp? See nfswrapper.c for a confusing 103104478Ssam * issue. 104104478Ssam */ 105104478Ssamint nfs_open(const char *path, struct open_file *f); 106104478Ssamstatic int nfs_close(struct open_file *f); 107104478Ssamstatic int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 108104478Ssamstatic int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 109104478Ssamstatic off_t nfs_seek(struct open_file *f, off_t offset, int where); 110104478Ssamstatic int nfs_stat(struct open_file *f, struct stat *sb); 111104478Ssam 112104478Ssamstatic struct nfs_iodesc nfs_root_node; 113104478Ssam 114104478Ssamstruct fs_ops nfs_fsops = { 115104478Ssam "nfs", 116104478Ssam nfs_open, 117104478Ssam nfs_close, 118104478Ssam nfs_read, 119104478Ssam nfs_write, 120104478Ssam nfs_seek, 121104478Ssam nfs_stat, 122104478Ssam null_readdir 123104478Ssam}; 124104478Ssam 125104478Ssam/* 126104478Ssam * Fetch the root file handle (call mount daemon) 127104478Ssam * Return zero or error number. 128104478Ssam */ 129104478Ssamint 130104478Ssamnfs_getrootfh(d, path, fhp) 131104478Ssam register struct iodesc *d; 132104478Ssam char *path; 133104478Ssam u_char *fhp; 134104478Ssam{ 135104478Ssam register int len; 136104478Ssam struct args { 137104478Ssam n_long len; 138104478Ssam char path[FNAME_SIZE]; 139104478Ssam } *args; 140104478Ssam struct repl { 141104478Ssam n_long errno; 142104478Ssam u_char fh[NFS_FHSIZE]; 143104478Ssam } *repl; 144104478Ssam struct { 145104478Ssam n_long h[RPC_HEADER_WORDS]; 146104478Ssam struct args d; 147104478Ssam } sdata; 148104478Ssam struct { 149104478Ssam n_long h[RPC_HEADER_WORDS]; 150104478Ssam struct repl d; 151104478Ssam } rdata; 152104478Ssam size_t cc; 153104478Ssam 154104478Ssam#ifdef NFS_DEBUG 155104478Ssam if (debug) 156104478Ssam printf("nfs_getrootfh: %s\n", path); 157104478Ssam#endif 158104478Ssam 159104478Ssam args = &sdata.d; 160104478Ssam repl = &rdata.d; 161104478Ssam 162104478Ssam bzero(args, sizeof(*args)); 163104478Ssam len = strlen(path); 164104478Ssam if (len > sizeof(args->path)) 165104478Ssam len = sizeof(args->path); 166104478Ssam args->len = htonl(len); 167104478Ssam bcopy(path, args->path, len); 168104478Ssam len = 4 + roundup(len, 4); 169104478Ssam 170104478Ssam cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 171104478Ssam args, len, repl, sizeof(*repl)); 172104478Ssam if (cc == -1) { 173104478Ssam /* errno was set by rpc_call */ 174104478Ssam return (errno); 175104478Ssam } 176104478Ssam if (cc < 4) 177112124Ssam return (EBADRPC); 178112124Ssam if (repl->errno) 179104478Ssam return (ntohl(repl->errno)); 180104478Ssam bcopy(repl->fh, fhp, sizeof(repl->fh)); 181104478Ssam return (0); 182104478Ssam} 183104478Ssam 184104478Ssam/* 185104478Ssam * Lookup a file. Store handle and attributes. 186104478Ssam * Return zero or error number. 187104478Ssam */ 188104478Ssamint 189104478Ssamnfs_lookupfh(d, name, newfd) 190104478Ssam struct nfs_iodesc *d; 191104478Ssam const char *name; 192115747Ssam struct nfs_iodesc *newfd; 193104478Ssam{ 194104478Ssam register int len, rlen; 195104478Ssam struct args { 196108471Ssam u_char fh[NFS_FHSIZE]; 197115747Ssam n_long len; 198104478Ssam char name[FNAME_SIZE]; 199115747Ssam } *args; 200104478Ssam struct repl { 201104478Ssam n_long errno; 202104478Ssam u_char fh[NFS_FHSIZE]; 203104478Ssam struct nfsv2_fattrs fa; 204104478Ssam } *repl; 205104478Ssam struct { 206104478Ssam n_long h[RPC_HEADER_WORDS]; 207104478Ssam struct args d; 208112124Ssam } sdata; 209112124Ssam struct { 210112124Ssam n_long h[RPC_HEADER_WORDS]; 211104478Ssam struct repl d; 212104478Ssam } rdata; 213104478Ssam ssize_t cc; 214104478Ssam 215104478Ssam#ifdef NFS_DEBUG 216104478Ssam if (debug) 217104478Ssam printf("lookupfh: called\n"); 218104478Ssam#endif 219104478Ssam 220104478Ssam args = &sdata.d; 221158705Spjd repl = &rdata.d; 222104478Ssam 223104478Ssam bzero(args, sizeof(*args)); 224104478Ssam bcopy(d->fh, args->fh, sizeof(args->fh)); 225104478Ssam len = strlen(name); 226110519Ssam if (len > sizeof(args->name)) 227104478Ssam len = sizeof(args->name); 228104478Ssam bcopy(name, args->name, len); 229104478Ssam args->len = htonl(len); 230104478Ssam len = 4 + roundup(len, 4); 231104478Ssam len += NFS_FHSIZE; 232104478Ssam 233108471Ssam rlen = sizeof(*repl); 234108471Ssam 235108471Ssam cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 236108471Ssam args, len, repl, rlen); 237108471Ssam if (cc == -1) 238104478Ssam return (errno); /* XXX - from rpc_call */ 239104478Ssam if (cc < 4) 240104478Ssam return (EIO); 241104478Ssam if (repl->errno) { 242104478Ssam /* saerrno.h now matches NFS error numbers. */ 243104478Ssam return (ntohl(repl->errno)); 244104478Ssam } 245104478Ssam bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 246104478Ssam bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 247104478Ssam return (0); 248104478Ssam} 249104478Ssam 250104478Ssam#ifndef NFS_NOSYMLINK 251104478Ssam/* 252104478Ssam * Get the destination of a symbolic link. 253104478Ssam */ 254108471Ssamint 255108471Ssamnfs_readlink(d, buf) 256108471Ssam struct nfs_iodesc *d; 257104478Ssam char *buf; 258104478Ssam{ 259104478Ssam struct { 260104478Ssam n_long h[RPC_HEADER_WORDS]; 261 u_char fh[NFS_FHSIZE]; 262 } sdata; 263 struct { 264 n_long h[RPC_HEADER_WORDS]; 265 struct nfs_readlnk_repl d; 266 } rdata; 267 ssize_t cc; 268 269#ifdef NFS_DEBUG 270 if (debug) 271 printf("readlink: called\n"); 272#endif 273 274 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 275 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 276 sdata.fh, NFS_FHSIZE, 277 &rdata.d, sizeof(rdata.d)); 278 if (cc == -1) 279 return (errno); 280 281 if (cc < 4) 282 return (EIO); 283 284 if (rdata.d.errno) 285 return (ntohl(rdata.d.errno)); 286 287 rdata.d.len = ntohl(rdata.d.len); 288 if (rdata.d.len > NFS_MAXPATHLEN) 289 return (ENAMETOOLONG); 290 291 bcopy(rdata.d.path, buf, rdata.d.len); 292 buf[rdata.d.len] = 0; 293 return (0); 294} 295#endif 296 297/* 298 * Read data from a file. 299 * Return transfer count or -1 (and set errno) 300 */ 301ssize_t 302nfs_readdata(d, off, addr, len) 303 struct nfs_iodesc *d; 304 off_t off; 305 void *addr; 306 size_t len; 307{ 308 struct nfs_read_args *args; 309 struct nfs_read_repl *repl; 310 struct { 311 n_long h[RPC_HEADER_WORDS]; 312 struct nfs_read_args d; 313 } sdata; 314 struct { 315 n_long h[RPC_HEADER_WORDS]; 316 struct nfs_read_repl d; 317 } rdata; 318 size_t cc; 319 long x; 320 int hlen, rlen; 321 322 args = &sdata.d; 323 repl = &rdata.d; 324 325 bcopy(d->fh, args->fh, NFS_FHSIZE); 326 args->off = htonl((n_long)off); 327 if (len > NFSREAD_SIZE) 328 len = NFSREAD_SIZE; 329 args->len = htonl((n_long)len); 330 args->xxx = htonl((n_long)0); 331 hlen = sizeof(*repl) - NFSREAD_SIZE; 332 333 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 334 args, sizeof(*args), 335 repl, sizeof(*repl)); 336 if (cc == -1) { 337 /* errno was already set by rpc_call */ 338 return (-1); 339 } 340 if (cc < hlen) { 341 errno = EBADRPC; 342 return (-1); 343 } 344 if (repl->errno) { 345 errno = ntohl(repl->errno); 346 return (-1); 347 } 348 rlen = cc - hlen; 349 x = ntohl(repl->count); 350 if (rlen < x) { 351 printf("nfsread: short packet, %d < %ld\n", rlen, x); 352 errno = EBADRPC; 353 return(-1); 354 } 355 bcopy(repl->data, addr, x); 356 return (x); 357} 358 359/* 360 * Open a file. 361 * return zero or error number 362 */ 363int 364nfs_open(upath, f) 365 const char *upath; 366 struct open_file *f; 367{ 368 struct iodesc *desc; 369 struct nfs_iodesc *currfd; 370#ifndef NFS_NOSYMLINK 371 struct nfs_iodesc *newfd; 372 struct nfsv2_fattrs *fa; 373 register char *cp, *ncp; 374 register int c; 375 char namebuf[NFS_MAXPATHLEN + 1]; 376 char linkbuf[NFS_MAXPATHLEN + 1]; 377 int nlinks = 0; 378#endif 379 int error; 380 char *path; 381 382#ifdef NFS_DEBUG 383 if (debug) 384 printf("nfs_open: %s (rootpath=%s)\n", path, rootpath); 385#endif 386 if (!rootpath[0]) { 387 printf("no rootpath, no nfs\n"); 388 return (ENXIO); 389 } 390 391 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 392 return(EINVAL); 393 394 /* Bind to a reserved port. */ 395 desc->myport = htons(--rpc_port); 396 desc->destip = rootip; 397 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 398 return (error); 399 nfs_root_node.iodesc = desc; 400 401#ifndef NFS_NOSYMLINK 402 /* Fake up attributes for the root dir. */ 403 fa = &nfs_root_node.fa; 404 fa->fa_type = htonl(NFDIR); 405 fa->fa_mode = htonl(0755); 406 fa->fa_nlink = htonl(2); 407 408 currfd = &nfs_root_node; 409 newfd = 0; 410 411 cp = path = strdup(upath); 412 if (path == NULL) { 413 error = ENOMEM; 414 goto out; 415 } 416 while (*cp) { 417 /* 418 * Remove extra separators 419 */ 420 while (*cp == '/') 421 cp++; 422 423 if (*cp == '\0') 424 break; 425 /* 426 * Check that current node is a directory. 427 */ 428 if (currfd->fa.fa_type != htonl(NFDIR)) { 429 error = ENOTDIR; 430 goto out; 431 } 432 433 /* allocate file system specific data structure */ 434 newfd = malloc(sizeof(*newfd)); 435 newfd->iodesc = currfd->iodesc; 436 newfd->off = 0; 437 438 /* 439 * Get next component of path name. 440 */ 441 { 442 register int len = 0; 443 444 ncp = cp; 445 while ((c = *cp) != '\0' && c != '/') { 446 if (++len > NFS_MAXNAMLEN) { 447 error = ENOENT; 448 goto out; 449 } 450 cp++; 451 } 452 *cp = '\0'; 453 } 454 455 /* lookup a file handle */ 456 error = nfs_lookupfh(currfd, ncp, newfd); 457 *cp = c; 458 if (error) 459 goto out; 460 461 /* 462 * Check for symbolic link 463 */ 464 if (newfd->fa.fa_type == htonl(NFLNK)) { 465 int link_len, len; 466 467 error = nfs_readlink(newfd, linkbuf); 468 if (error) 469 goto out; 470 471 link_len = strlen(linkbuf); 472 len = strlen(cp); 473 474 if (link_len + len > MAXPATHLEN 475 || ++nlinks > MAXSYMLINKS) { 476 error = ENOENT; 477 goto out; 478 } 479 480 bcopy(cp, &namebuf[link_len], len + 1); 481 bcopy(linkbuf, namebuf, link_len); 482 483 /* 484 * If absolute pathname, restart at root. 485 * If relative pathname, restart at parent directory. 486 */ 487 cp = namebuf; 488 if (*cp == '/') { 489 if (currfd != &nfs_root_node) 490 free(currfd); 491 currfd = &nfs_root_node; 492 } 493 494 free(newfd); 495 newfd = 0; 496 497 continue; 498 } 499 500 if (currfd != &nfs_root_node) 501 free(currfd); 502 currfd = newfd; 503 newfd = 0; 504 } 505 506 error = 0; 507 508out: 509 if (newfd) 510 free(newfd); 511 if (path) 512 free(path); 513#else 514 /* allocate file system specific data structure */ 515 currfd = malloc(sizeof(*currfd)); 516 currfd->iodesc = desc; 517 currfd->off = 0; 518 519 error = nfs_lookupfh(&nfs_root_node, upath, currfd); 520#endif 521 if (!error) { 522 f->f_fsdata = (void *)currfd; 523 return (0); 524 } 525 526#ifdef NFS_DEBUG 527 if (debug) 528 printf("nfs_open: %s lookupfh failed: %s\n", 529 path, strerror(error)); 530#endif 531#ifndef NFS_NOSYMLINK 532 if (currfd != &nfs_root_node) 533#endif 534 free(currfd); 535 536 return (error); 537} 538 539int 540nfs_close(f) 541 struct open_file *f; 542{ 543 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 544 545#ifdef NFS_DEBUG 546 if (debug) 547 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 548#endif 549 550 if (fp != &nfs_root_node && fp) 551 free(fp); 552 f->f_fsdata = (void *)0; 553 554 return (0); 555} 556 557/* 558 * read a portion of a file 559 */ 560int 561nfs_read(f, buf, size, resid) 562 struct open_file *f; 563 void *buf; 564 size_t size; 565 size_t *resid; /* out */ 566{ 567 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 568 register ssize_t cc; 569 register char *addr = buf; 570 571#ifdef NFS_DEBUG 572 if (debug) 573 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 574 (int)fp->off); 575#endif 576 while ((int)size > 0) { 577 twiddle(); 578 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 579 /* XXX maybe should retry on certain errors */ 580 if (cc == -1) { 581#ifdef NFS_DEBUG 582 if (debug) 583 printf("nfs_read: read: %s", strerror(errno)); 584#endif 585 return (errno); /* XXX - from nfs_readdata */ 586 } 587 if (cc == 0) { 588#ifdef NFS_DEBUG 589 if (debug) 590 printf("nfs_read: hit EOF unexpectantly"); 591#endif 592 goto ret; 593 } 594 fp->off += cc; 595 addr += cc; 596 size -= cc; 597 } 598ret: 599 if (resid) 600 *resid = size; 601 602 return (0); 603} 604 605/* 606 * Not implemented. 607 */ 608int 609nfs_write(f, buf, size, resid) 610 struct open_file *f; 611 void *buf; 612 size_t size; 613 size_t *resid; /* out */ 614{ 615 return (EROFS); 616} 617 618off_t 619nfs_seek(f, offset, where) 620 struct open_file *f; 621 off_t offset; 622 int where; 623{ 624 register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 625 n_long size = ntohl(d->fa.fa_size); 626 627 switch (where) { 628 case SEEK_SET: 629 d->off = offset; 630 break; 631 case SEEK_CUR: 632 d->off += offset; 633 break; 634 case SEEK_END: 635 d->off = size - offset; 636 break; 637 default: 638 return (-1); 639 } 640 641 return (d->off); 642} 643 644/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 645int nfs_stat_types[8] = { 646 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 647 648int 649nfs_stat(f, sb) 650 struct open_file *f; 651 struct stat *sb; 652{ 653 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 654 register n_long ftype, mode; 655 656 ftype = ntohl(fp->fa.fa_type); 657 mode = ntohl(fp->fa.fa_mode); 658 mode |= nfs_stat_types[ftype & 7]; 659 660 sb->st_mode = mode; 661 sb->st_nlink = ntohl(fp->fa.fa_nlink); 662 sb->st_uid = ntohl(fp->fa.fa_uid); 663 sb->st_gid = ntohl(fp->fa.fa_gid); 664 sb->st_size = ntohl(fp->fa.fa_size); 665 666 return (0); 667} 668