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