1 /* $NetBSD: nfs.c,v 1.29 2000/03/30 12:19:48 augustss 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 "netif.h" 60 #include "nfs.h" 61 #include "rpc.h" 62 63 /* Define our own NFS attributes without NQNFS stuff. */ 64 struct nfsv2_fattrs { 65 n_long fa_type; 66 n_long fa_mode; 67 n_long fa_nlink; 68 n_long fa_uid; 69 n_long fa_gid; 70 n_long fa_size; 71 n_long fa_blocksize; 72 n_long fa_rdev; 73 n_long fa_blocks; 74 n_long fa_fsid; 75 n_long fa_fileid; 76 struct nfsv2_time fa_atime; 77 struct nfsv2_time fa_mtime; 78 struct nfsv2_time fa_ctime; 79 }; 80 81 82 struct nfs_read_args { 83 u_char fh[NFS_FHSIZE]; 84 n_long off; 85 n_long len; 86 n_long xxx; /* XXX what's this for? */ 87 }; 88 89 /* Data part of nfs rpc reply (also the largest thing we receive) */ 90 #define NFSREAD_SIZE 1024 91 struct nfs_read_repl { 92 n_long errno; 93 struct nfsv2_fattrs fa; 94 n_long count; 95 u_char data[NFSREAD_SIZE]; 96 }; 97 98 #ifndef NFS_NOSYMLINK 99 struct nfs_readlnk_repl { 100 n_long errno; 101 n_long len; 102 char path[NFS_MAXPATHLEN]; 103 }; 104 #endif 105 106 struct nfs_iodesc { 107 struct iodesc *iodesc; 108 off_t off; 109 u_char fh[NFS_FHSIZE]; 110 struct nfsv2_fattrs fa; /* all in network order */ 111 }; 112 113 struct nfs_iodesc nfs_root_node; 114 115 int nfs_getrootfh __P((struct iodesc *, char *, u_char *)); 116 int nfs_lookupfh __P((struct nfs_iodesc *, char *, 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 size_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 (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, newfd) 189 struct nfs_iodesc *d; 190 char *name; 191 struct nfs_iodesc *newfd; 192 { 193 int len, rlen; 194 struct args { 195 u_char fh[NFS_FHSIZE]; 196 n_long len; 197 char name[FNAME_SIZE]; 198 } *args; 199 struct repl { 200 n_long errno; 201 u_char fh[NFS_FHSIZE]; 202 struct nfsv2_fattrs fa; 203 } *repl; 204 struct { 205 n_long h[RPC_HEADER_WORDS]; 206 struct args d; 207 } sdata; 208 struct { 209 n_long h[RPC_HEADER_WORDS]; 210 struct repl d; 211 } rdata; 212 ssize_t cc; 213 214 #ifdef NFS_DEBUG 215 if (debug) 216 printf("lookupfh: called\n"); 217 #endif 218 219 args = &sdata.d; 220 repl = &rdata.d; 221 222 bzero(args, sizeof(*args)); 223 bcopy(d->fh, args->fh, sizeof(args->fh)); 224 len = strlen(name); 225 if (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 size_t cc; 318 long x; 319 int 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 < 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 < x) { 350 printf("nfsread: short packet, %d < %ld\n", 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 char *path; 403 struct open_file *f; 404 { 405 struct nfs_iodesc *newfd, *currfd; 406 char *cp; 407 #ifndef NFS_NOSYMLINK 408 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 *cp = '\0'; 467 } 468 469 /* lookup a file handle */ 470 error = nfs_lookupfh(currfd, ncp, newfd); 471 *cp = c; 472 if (error) 473 goto out; 474 475 /* 476 * Check for symbolic link 477 */ 478 if (newfd->fa.fa_type == htonl(NFLNK)) { 479 int link_len, len; 480 481 error = nfs_readlink(newfd, linkbuf); 482 if (error) 483 goto out; 484 485 link_len = strlen(linkbuf); 486 len = strlen(cp); 487 488 if (link_len + len > MAXPATHLEN 489 || ++nlinks > MAXSYMLINKS) { 490 error = ENOENT; 491 goto out; 492 } 493 494 bcopy(cp, &namebuf[link_len], len + 1); 495 bcopy(linkbuf, namebuf, link_len); 496 497 /* 498 * If absolute pathname, restart at root. 499 * If relative pathname, restart at parent directory. 500 */ 501 cp = namebuf; 502 if (*cp == '/') { 503 if (currfd != &nfs_root_node) 504 free(currfd, sizeof(*currfd)); 505 currfd = &nfs_root_node; 506 } 507 508 free(newfd, sizeof(*newfd)); 509 newfd = 0; 510 511 continue; 512 } 513 514 if (currfd != &nfs_root_node) 515 free(currfd, sizeof(*currfd)); 516 currfd = newfd; 517 newfd = 0; 518 } 519 520 error = 0; 521 522 out: 523 #else 524 /* allocate file system specific data structure */ 525 currfd = alloc(sizeof(*currfd)); 526 currfd->iodesc = nfs_root_node.iodesc; 527 currfd->off = 0; 528 529 cp = path; 530 /* 531 * Remove extra separators 532 */ 533 while (*cp == '/') 534 cp++; 535 536 /* XXX: Check for empty path here? */ 537 538 error = nfs_lookupfh(&nfs_root_node, cp, currfd); 539 #endif 540 if (!error) { 541 f->f_fsdata = (void *)currfd; 542 return (0); 543 } 544 545 #ifdef NFS_DEBUG 546 if (debug) 547 printf("nfs_open: %s lookupfh failed: %s\n", 548 path, strerror(error)); 549 #endif 550 if (currfd != &nfs_root_node) 551 free(currfd, sizeof(*currfd)); 552 if (newfd) 553 free(newfd, sizeof(*newfd)); 554 555 return (error); 556 } 557 558 int 559 nfs_close(f) 560 struct open_file *f; 561 { 562 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 563 564 #ifdef NFS_DEBUG 565 if (debug) 566 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 567 #endif 568 569 if (fp) 570 free(fp, sizeof(struct nfs_iodesc)); 571 f->f_fsdata = (void *)0; 572 573 return (0); 574 } 575 576 /* 577 * read a portion of a file 578 */ 579 int 580 nfs_read(f, buf, size, resid) 581 struct open_file *f; 582 void *buf; 583 size_t size; 584 size_t *resid; /* out */ 585 { 586 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 587 ssize_t cc; 588 char *addr = buf; 589 590 #ifdef NFS_DEBUG 591 if (debug) 592 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 593 (int)fp->off); 594 #endif 595 while ((int)size > 0) { 596 #if !defined(LIBSA_NO_TWIDDLE) 597 twiddle(); 598 #endif 599 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 600 /* XXX maybe should retry on certain errors */ 601 if (cc == -1) { 602 #ifdef NFS_DEBUG 603 if (debug) 604 printf("nfs_read: read: %s", strerror(errno)); 605 #endif 606 return (errno); /* XXX - from nfs_readdata */ 607 } 608 if (cc == 0) { 609 #ifdef NFS_DEBUG 610 if (debug) 611 printf("nfs_read: hit EOF unexpectantly"); 612 #endif 613 goto ret; 614 } 615 fp->off += cc; 616 addr += cc; 617 size -= cc; 618 } 619 ret: 620 if (resid) 621 *resid = size; 622 623 return (0); 624 } 625 626 /* 627 * Not implemented. 628 */ 629 int 630 nfs_write(f, buf, size, resid) 631 struct open_file *f; 632 void *buf; 633 size_t size; 634 size_t *resid; /* out */ 635 { 636 return (EROFS); 637 } 638 639 off_t 640 nfs_seek(f, offset, where) 641 struct open_file *f; 642 off_t offset; 643 int where; 644 { 645 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 646 n_long size = ntohl(d->fa.fa_size); 647 648 switch (where) { 649 case SEEK_SET: 650 d->off = offset; 651 break; 652 case SEEK_CUR: 653 d->off += offset; 654 break; 655 case SEEK_END: 656 d->off = size - offset; 657 break; 658 default: 659 return (-1); 660 } 661 662 return (d->off); 663 } 664 665 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 666 int nfs_stat_types[8] = { 667 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 668 669 int 670 nfs_stat(f, sb) 671 struct open_file *f; 672 struct stat *sb; 673 { 674 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 675 n_long ftype, mode; 676 677 ftype = ntohl(fp->fa.fa_type); 678 mode = ntohl(fp->fa.fa_mode); 679 mode |= nfs_stat_types[ftype & 7]; 680 681 sb->st_mode = mode; 682 sb->st_nlink = ntohl(fp->fa.fa_nlink); 683 sb->st_uid = ntohl(fp->fa.fa_uid); 684 sb->st_gid = ntohl(fp->fa.fa_gid); 685 sb->st_size = ntohl(fp->fa.fa_size); 686 687 return (0); 688 } 689