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