1 /* $NetBSD: nfs.c,v 1.31 2003/03/18 19:20:09 mycroft 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 *, char *, struct nfs_iodesc *)); 116 int nfs_readlink __P((struct nfs_iodesc *, char *)); 117 ssize_t nfs_readdata __P((struct nfs_iodesc *, off_t, void *, size_t)); 118 119 /* 120 * Fetch the root file handle (call mount daemon) 121 * On error, return non-zero and set errno. 122 */ 123 int 124 nfs_getrootfh(d, path, fhp) 125 struct iodesc *d; 126 char *path; 127 u_char *fhp; 128 { 129 int len; 130 struct args { 131 n_long len; 132 char path[FNAME_SIZE]; 133 } *args; 134 struct repl { 135 n_long errno; 136 u_char fh[NFS_FHSIZE]; 137 } *repl; 138 struct { 139 n_long h[RPC_HEADER_WORDS]; 140 struct args d; 141 } sdata; 142 struct { 143 n_long h[RPC_HEADER_WORDS]; 144 struct repl d; 145 } rdata; 146 size_t cc; 147 148 #ifdef NFS_DEBUG 149 if (debug) 150 printf("nfs_getrootfh: %s\n", path); 151 #endif 152 153 args = &sdata.d; 154 repl = &rdata.d; 155 156 bzero(args, sizeof(*args)); 157 len = strlen(path); 158 if (len > sizeof(args->path)) 159 len = sizeof(args->path); 160 args->len = htonl(len); 161 bcopy(path, args->path, len); 162 len = 4 + roundup(len, 4); 163 164 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 165 args, len, repl, sizeof(*repl)); 166 if (cc == -1) { 167 /* errno was set by rpc_call */ 168 return (-1); 169 } 170 if (cc < 4) { 171 errno = EBADRPC; 172 return (-1); 173 } 174 if (repl->errno) { 175 errno = ntohl(repl->errno); 176 return (-1); 177 } 178 bcopy(repl->fh, fhp, sizeof(repl->fh)); 179 return (0); 180 } 181 182 /* 183 * Lookup a file. Store handle and attributes. 184 * Return zero or error number. 185 */ 186 int 187 nfs_lookupfh(d, name, newfd) 188 struct nfs_iodesc *d; 189 char *name; 190 struct nfs_iodesc *newfd; 191 { 192 int len, rlen; 193 struct args { 194 u_char fh[NFS_FHSIZE]; 195 n_long len; 196 char name[FNAME_SIZE]; 197 } *args; 198 struct repl { 199 n_long errno; 200 u_char fh[NFS_FHSIZE]; 201 struct nfsv2_fattrs fa; 202 } *repl; 203 struct { 204 n_long h[RPC_HEADER_WORDS]; 205 struct args d; 206 } sdata; 207 struct { 208 n_long h[RPC_HEADER_WORDS]; 209 struct repl d; 210 } rdata; 211 ssize_t cc; 212 213 #ifdef NFS_DEBUG 214 if (debug) 215 printf("lookupfh: called\n"); 216 #endif 217 218 args = &sdata.d; 219 repl = &rdata.d; 220 221 bzero(args, sizeof(*args)); 222 bcopy(d->fh, args->fh, sizeof(args->fh)); 223 len = strlen(name); 224 if (len > sizeof(args->name)) 225 len = sizeof(args->name); 226 bcopy(name, args->name, len); 227 args->len = htonl(len); 228 len = 4 + roundup(len, 4); 229 len += NFS_FHSIZE; 230 231 rlen = sizeof(*repl); 232 233 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 234 args, len, repl, rlen); 235 if (cc == -1) 236 return (errno); /* XXX - from rpc_call */ 237 if (cc < 4) 238 return (EIO); 239 if (repl->errno) { 240 /* saerrno.h now matches NFS error numbers. */ 241 return (ntohl(repl->errno)); 242 } 243 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 244 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 245 return (0); 246 } 247 248 #ifndef NFS_NOSYMLINK 249 /* 250 * Get the destination of a symbolic link. 251 */ 252 int 253 nfs_readlink(d, buf) 254 struct nfs_iodesc *d; 255 char *buf; 256 { 257 struct { 258 n_long h[RPC_HEADER_WORDS]; 259 u_char fh[NFS_FHSIZE]; 260 } sdata; 261 struct { 262 n_long h[RPC_HEADER_WORDS]; 263 struct nfs_readlnk_repl d; 264 } rdata; 265 ssize_t cc; 266 267 #ifdef NFS_DEBUG 268 if (debug) 269 printf("readlink: called\n"); 270 #endif 271 272 bcopy(d->fh, sdata.fh, NFS_FHSIZE); 273 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 274 sdata.fh, NFS_FHSIZE, 275 &rdata.d, sizeof(rdata.d)); 276 if (cc == -1) 277 return (errno); 278 279 if (cc < 4) 280 return (EIO); 281 282 if (rdata.d.errno) 283 return (ntohl(rdata.d.errno)); 284 285 rdata.d.len = ntohl(rdata.d.len); 286 if (rdata.d.len > NFS_MAXPATHLEN) 287 return (ENAMETOOLONG); 288 289 bcopy(rdata.d.path, buf, rdata.d.len); 290 buf[rdata.d.len] = 0; 291 return (0); 292 } 293 #endif 294 295 /* 296 * Read data from a file. 297 * Return transfer count or -1 (and set errno) 298 */ 299 ssize_t 300 nfs_readdata(d, off, addr, len) 301 struct nfs_iodesc *d; 302 off_t off; 303 void *addr; 304 size_t len; 305 { 306 struct nfs_read_args *args; 307 struct nfs_read_repl *repl; 308 struct { 309 n_long h[RPC_HEADER_WORDS]; 310 struct nfs_read_args d; 311 } sdata; 312 struct { 313 n_long h[RPC_HEADER_WORDS]; 314 struct nfs_read_repl d; 315 } rdata; 316 size_t cc; 317 long x; 318 int hlen, rlen; 319 320 args = &sdata.d; 321 repl = &rdata.d; 322 323 bcopy(d->fh, args->fh, NFS_FHSIZE); 324 args->off = htonl((n_long)off); 325 if (len > NFSREAD_SIZE) 326 len = NFSREAD_SIZE; 327 args->len = htonl((n_long)len); 328 args->xxx = htonl((n_long)0); 329 hlen = sizeof(*repl) - NFSREAD_SIZE; 330 331 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 332 args, sizeof(*args), 333 repl, sizeof(*repl)); 334 if (cc == -1) { 335 /* errno was already set by rpc_call */ 336 return (-1); 337 } 338 if (cc < hlen) { 339 errno = EBADRPC; 340 return (-1); 341 } 342 if (repl->errno) { 343 errno = ntohl(repl->errno); 344 return (-1); 345 } 346 rlen = cc - hlen; 347 x = ntohl(repl->count); 348 if (rlen < x) { 349 printf("nfsread: short packet, %d < %ld\n", rlen, x); 350 errno = EBADRPC; 351 return(-1); 352 } 353 bcopy(repl->data, addr, x); 354 return (x); 355 } 356 357 /* 358 * nfs_mount - mount this nfs filesystem to a host 359 * On error, return non-zero and set errno. 360 */ 361 int 362 nfs_mount(sock, ip, path) 363 int sock; 364 struct in_addr ip; 365 char *path; 366 { 367 struct iodesc *desc; 368 struct nfsv2_fattrs *fa; 369 370 if (!(desc = socktodesc(sock))) { 371 errno = EINVAL; 372 return(-1); 373 } 374 375 /* Bind to a reserved port. */ 376 desc->myport = htons(--rpc_port); 377 desc->destip = ip; 378 if (nfs_getrootfh(desc, path, nfs_root_node.fh)) 379 return (-1); 380 nfs_root_node.iodesc = desc; 381 /* Fake up attributes for the root dir. */ 382 fa = &nfs_root_node.fa; 383 fa->fa_type = htonl(NFDIR); 384 fa->fa_mode = htonl(0755); 385 fa->fa_nlink = htonl(2); 386 387 #ifdef NFS_DEBUG 388 if (debug) 389 printf("nfs_mount: got fh for %s\n", path); 390 #endif 391 392 return(0); 393 } 394 395 /* 396 * Open a file. 397 * return zero or error number 398 */ 399 int 400 nfs_open(path, f) 401 char *path; 402 struct open_file *f; 403 { 404 struct nfs_iodesc *newfd, *currfd; 405 char *cp; 406 #ifndef NFS_NOSYMLINK 407 char *ncp; 408 int c; 409 char namebuf[NFS_MAXPATHLEN + 1]; 410 char linkbuf[NFS_MAXPATHLEN + 1]; 411 int nlinks = 0; 412 #endif 413 int error = 0; 414 415 #ifdef NFS_DEBUG 416 if (debug) 417 printf("nfs_open: %s\n", path); 418 #endif 419 if (nfs_root_node.iodesc == NULL) { 420 printf("nfs_open: must mount first.\n"); 421 return (ENXIO); 422 } 423 424 currfd = &nfs_root_node; 425 newfd = 0; 426 427 #ifndef NFS_NOSYMLINK 428 cp = path; 429 while (*cp) { 430 /* 431 * Remove extra separators 432 */ 433 while (*cp == '/') 434 cp++; 435 436 if (*cp == '\0') 437 break; 438 /* 439 * Check that current node is a directory. 440 */ 441 if (currfd->fa.fa_type != htonl(NFDIR)) { 442 error = ENOTDIR; 443 goto out; 444 } 445 446 /* allocate file system specific data structure */ 447 newfd = alloc(sizeof(*newfd)); 448 newfd->iodesc = currfd->iodesc; 449 newfd->off = 0; 450 451 /* 452 * Get next component of path name. 453 */ 454 { 455 int len = 0; 456 457 ncp = cp; 458 while ((c = *cp) != '\0' && c != '/') { 459 if (++len > NFS_MAXNAMLEN) { 460 error = ENOENT; 461 goto out; 462 } 463 cp++; 464 } 465 *cp = '\0'; 466 } 467 468 /* lookup a file handle */ 469 error = nfs_lookupfh(currfd, ncp, newfd); 470 *cp = c; 471 if (error) 472 goto out; 473 474 /* 475 * Check for symbolic link 476 */ 477 if (newfd->fa.fa_type == htonl(NFLNK)) { 478 int link_len, len; 479 480 error = nfs_readlink(newfd, linkbuf); 481 if (error) 482 goto out; 483 484 link_len = strlen(linkbuf); 485 len = strlen(cp); 486 487 if (link_len + len > MAXPATHLEN 488 || ++nlinks > MAXSYMLINKS) { 489 error = ENOENT; 490 goto out; 491 } 492 493 bcopy(cp, &namebuf[link_len], len + 1); 494 bcopy(linkbuf, namebuf, link_len); 495 496 /* 497 * If absolute pathname, restart at root. 498 * If relative pathname, restart at parent directory. 499 */ 500 cp = namebuf; 501 if (*cp == '/') { 502 if (currfd != &nfs_root_node) 503 free(currfd, sizeof(*currfd)); 504 currfd = &nfs_root_node; 505 } 506 507 free(newfd, sizeof(*newfd)); 508 newfd = 0; 509 510 continue; 511 } 512 513 if (currfd != &nfs_root_node) 514 free(currfd, sizeof(*currfd)); 515 currfd = newfd; 516 newfd = 0; 517 } 518 519 error = 0; 520 521 out: 522 #else 523 /* allocate file system specific data structure */ 524 currfd = alloc(sizeof(*currfd)); 525 currfd->iodesc = nfs_root_node.iodesc; 526 currfd->off = 0; 527 528 cp = path; 529 /* 530 * Remove extra separators 531 */ 532 while (*cp == '/') 533 cp++; 534 535 /* XXX: Check for empty path here? */ 536 537 error = nfs_lookupfh(&nfs_root_node, cp, 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 if (currfd != &nfs_root_node) 550 free(currfd, sizeof(*currfd)); 551 if (newfd) 552 free(newfd, sizeof(*newfd)); 553 554 return (error); 555 } 556 557 int 558 nfs_close(f) 559 struct open_file *f; 560 { 561 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) 569 free(fp, sizeof(struct nfs_iodesc)); 570 f->f_fsdata = (void *)0; 571 572 return (0); 573 } 574 575 /* 576 * read a portion of a file 577 */ 578 int 579 nfs_read(f, buf, size, resid) 580 struct open_file *f; 581 void *buf; 582 size_t size; 583 size_t *resid; /* out */ 584 { 585 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 586 ssize_t cc; 587 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 #if !defined(LIBSA_NO_TWIDDLE) 596 twiddle(); 597 #endif 598 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 599 /* XXX maybe should retry on certain errors */ 600 if (cc == -1) { 601 #ifdef NFS_DEBUG 602 if (debug) 603 printf("nfs_read: read: %s", strerror(errno)); 604 #endif 605 return (errno); /* XXX - from nfs_readdata */ 606 } 607 if (cc == 0) { 608 #ifdef NFS_DEBUG 609 if (debug) 610 printf("nfs_read: hit EOF unexpectantly"); 611 #endif 612 goto ret; 613 } 614 fp->off += cc; 615 addr += cc; 616 size -= cc; 617 } 618 ret: 619 if (resid) 620 *resid = size; 621 622 return (0); 623 } 624 625 /* 626 * Not implemented. 627 */ 628 int 629 nfs_write(f, buf, size, resid) 630 struct open_file *f; 631 void *buf; 632 size_t size; 633 size_t *resid; /* out */ 634 { 635 return (EROFS); 636 } 637 638 off_t 639 nfs_seek(f, offset, where) 640 struct open_file *f; 641 off_t offset; 642 int where; 643 { 644 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 645 n_long size = ntohl(d->fa.fa_size); 646 647 switch (where) { 648 case SEEK_SET: 649 d->off = offset; 650 break; 651 case SEEK_CUR: 652 d->off += offset; 653 break; 654 case SEEK_END: 655 d->off = size - offset; 656 break; 657 default: 658 return (-1); 659 } 660 661 return (d->off); 662 } 663 664 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 665 const int nfs_stat_types[8] = { 666 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 667 668 int 669 nfs_stat(f, sb) 670 struct open_file *f; 671 struct stat *sb; 672 { 673 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 674 n_long ftype, mode; 675 676 ftype = ntohl(fp->fa.fa_type); 677 mode = ntohl(fp->fa.fa_mode); 678 mode |= nfs_stat_types[ftype & 7]; 679 680 sb->st_mode = mode; 681 sb->st_nlink = ntohl(fp->fa.fa_nlink); 682 sb->st_uid = ntohl(fp->fa.fa_uid); 683 sb->st_gid = ntohl(fp->fa.fa_gid); 684 sb->st_size = ntohl(fp->fa.fa_size); 685 686 return (0); 687 } 688