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