1 /*- 2 * Copyright (c) 1993 John Brezak 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $Id: nfs.c,v 1.1 1994/05/08 16:11:31 brezak Exp $ 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 <nfs/rpcv2.h> 41 #include <nfs/nfsv2.h> 42 #undef NFSX_FATTR 43 44 #include "stand.h" 45 #include "net.h" 46 #include "netif.h" 47 #include "nfs.h" 48 #include "rpc.h" 49 50 struct nfs_call_data { 51 u_char fh[NFS_FHSIZE]; 52 u_long off; 53 u_long len; 54 u_long xxx; /* XXX what's this for? */ 55 }; 56 57 /* Data part of nfs rpc reply (also the largest thing we receive) */ 58 struct nfs_reply_data { 59 u_long errno; 60 #ifndef NFSX_FATTR 61 struct nfsv2_fattr fa; 62 #else 63 u_char fa[NFSX_FATTR(0)]; 64 #endif 65 u_long count; 66 u_char data[1200]; 67 }; 68 #define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data) 69 70 /* max number of nfs reads pending */ 71 #define NFS_COUNT 10 72 73 static struct nfsstate { 74 u_long off; 75 u_long len; 76 int done; 77 void *addr; 78 u_long xid; 79 } nfsstate[NFS_COUNT]; 80 81 static u_long nfscc; 82 83 struct nfs_iodesc { 84 off_t off; 85 size_t size; 86 u_char *fh; 87 struct iodesc *iodesc; 88 }; 89 90 /* Fetch (mount) file handle */ 91 static int 92 getmountfh(d, path, fhp) 93 register struct iodesc *d; 94 char *path; 95 u_char *fhp; 96 { 97 register int len; 98 struct { 99 u_long len; 100 char path[FNAME_SIZE]; 101 } sdata; 102 struct { 103 u_long errno; 104 u_char fh[NFS_FHSIZE]; 105 } rdata; 106 int cc; 107 108 #ifdef NFS_DEBUG 109 if (debug) 110 printf("getmountfh: called\n"); 111 #endif 112 bzero(&sdata, sizeof(sdata)); 113 len = strlen(path); 114 if (len > sizeof(sdata.path)) 115 len = sizeof(sdata.path); 116 bcopy(path, sdata.path, len); 117 sdata.len = htonl(len); 118 len = sizeof(sdata) - sizeof(sdata.path) + roundup(len, sizeof(long)); 119 120 if ((cc = callrpc(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 121 &sdata, len, &rdata, sizeof(rdata))) < 0) 122 return(-1); 123 if (cc < sizeof(rdata.errno)) 124 panic("getmountfh: callrpc small read"); 125 if (rdata.errno) { 126 errno = ntohl(rdata.errno); 127 return(-1); 128 } 129 bcopy(rdata.fh, fhp, sizeof(rdata.fh)); 130 return(0); 131 } 132 133 /* Fetch file timestamp and size */ 134 static int 135 getnfsinfo(d, tp, sp, fp, mp, up, gp) 136 register struct nfs_iodesc *d; 137 register time_t *tp; 138 u_long *sp, *fp; 139 mode_t *mp; 140 uid_t *up; 141 gid_t *gp; 142 { 143 register int rlen; 144 register u_long t; 145 struct { 146 u_long errno; 147 struct nfsv2_fattr fa; 148 } rdata; 149 int cc; 150 151 #ifdef NFS_DEBUG 152 if (debug) 153 printf("getnfsinfo: called\n"); 154 #endif 155 rlen = sizeof(rdata); 156 #if 0 157 #ifdef NFSX_FATTR 158 #if NFSX_FATTR(1) > NFSX_FATTR(0) 159 /* nqnfs makes this more painful than it needs to be */ 160 rlen -= NFSX_FATTR(1) - NFSX_FATTR(0); 161 #endif 162 #endif 163 #endif 164 if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_GETATTR, 165 d->fh, NFS_FHSIZE, &rdata, rlen)) < 0) 166 return(-1); 167 if (cc < sizeof(rdata.errno)) 168 panic("getnfsinfo: callrpc small read"); 169 if (rdata.errno) { 170 errno = ntohl(rdata.errno); 171 return(-1); 172 } 173 if (tp) { 174 *tp = ntohl(rdata.fa.fa_mtime.tv_sec); 175 t = ntohl(rdata.fa.fa_atime.tv_sec); 176 if (*tp < t) 177 *tp = t; 178 } 179 if (sp) 180 *sp = ntohl(rdata.fa.fa_size); 181 if (fp) 182 *fp = ntohl(rdata.fa.fa_type); 183 if (mp) 184 *mp = ntohl(rdata.fa.fa_mode); 185 if (up) 186 *up = ntohl(rdata.fa.fa_uid); 187 if (gp) 188 *gp = ntohl(rdata.fa.fa_gid); 189 return(0); 190 } 191 192 /* Lookup a file. Optionally return timestamp and size */ 193 static int 194 lookupfh(d, name, fhp, tp, sp, fp) 195 struct nfs_iodesc *d; 196 char *name; 197 u_char *fhp; 198 time_t *tp; 199 u_long *sp, *fp; 200 { 201 register int len, rlen; 202 struct { 203 u_char fh[NFS_FHSIZE]; 204 u_long len; 205 char name[FNAME_SIZE]; 206 } sdata; 207 struct { 208 u_long errno; 209 u_char fh[NFS_FHSIZE]; 210 struct nfsv2_fattr fa; 211 } rdata; 212 int cc; 213 214 #ifdef NFS_DEBUG 215 if (debug) 216 printf("lookupfh: called\n"); 217 #endif 218 219 bzero(&sdata, sizeof(sdata)); 220 bcopy(d->fh, sdata.fh, sizeof(sdata.fh)); 221 len = strlen(name); 222 if (len > sizeof(sdata.name)) 223 len = sizeof(sdata.name); 224 bcopy(name, sdata.name, len); 225 sdata.len = htonl(len); 226 len = sizeof(sdata) - sizeof(sdata.name) + roundup(len, sizeof(long)); 227 228 rlen = sizeof(rdata); 229 #if 0 230 #ifdef NFSX_FATTR 231 #if NFSX_FATTR(1) > NFSX_FATTR(0) 232 /* nqnfs makes this more painful than it needs to be */ 233 rlen -= NFSX_FATTR(1) - NFSX_FATTR(0); 234 #endif 235 #endif 236 #endif 237 if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 238 &sdata, len, &rdata, rlen)) < 0) 239 return (-1); 240 if (cc < sizeof(rdata.errno)) 241 panic("lookupfh: callrpc small read"); 242 if (rdata.errno) { 243 errno = ntohl(rdata.errno); 244 return(-1); 245 } 246 bcopy(rdata.fh, fhp, sizeof(rdata.fh)); 247 if (tp) 248 *tp = ntohl(rdata.fa.fa_ctime.tv_sec); 249 if (sp) 250 *sp = ntohl(rdata.fa.fa_size); 251 if (fp) 252 *fp = ntohl(rdata.fa.fa_type); 253 return (0); 254 } 255 256 static int 257 sendreaddata(d, pkt, len) 258 register struct nfs_iodesc *d; 259 register void *pkt; 260 register int len; 261 { 262 register int i; 263 register u_long cc; 264 register struct rpc_call *rpc; 265 register struct nfs_call_data *nfs; 266 register struct nfsstate *ns; 267 268 #ifdef NFS_DEBUG 269 if (debug) 270 printf("sendreaddata: called\n"); 271 #endif 272 273 if (len != sizeof(*rpc) + sizeof(*nfs)) 274 panic("sendreaddata: bad buffer (%d != %d)", 275 len, sizeof(*rpc) + sizeof(*nfs)); 276 rpc = pkt; 277 nfs = (struct nfs_call_data *)(rpc + 1); 278 for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) { 279 if (ns->done) 280 continue; 281 282 rpc->rp_xid = ns->xid; 283 nfs->off = htonl(ns->off); 284 nfs->len = htonl(ns->len); 285 cc = sendudp(d->iodesc, rpc, len); 286 287 if (cc != len) 288 panic("sendreaddata: short write (%d != %d)", cc, len); 289 } 290 /* XXX we may have actually sent a lot more bytes... */ 291 292 return (len); 293 } 294 295 /* Returns char count if done else -1 (and errno == 0) */ 296 static int 297 recvreaddata(d, pkt, len) 298 register struct nfs_iodesc *d; 299 register void *pkt; 300 int len; 301 { 302 register int i; 303 register struct rpc_reply *rpc; 304 register struct nfs_reply_data *nfs; 305 register struct nfsstate *ns; 306 307 #ifdef NFS_DEBUG 308 if (debug) 309 printf("recvreaddata: called\n"); 310 #endif 311 rpc = (struct rpc_reply *)checkudp(d->iodesc, pkt, &len); 312 if (rpc == NULL || len < sizeof(*rpc)) { 313 errno = 0; 314 return (-1); 315 } 316 len -= sizeof(*rpc); 317 318 NTOHL(rpc->rp_direction); 319 NTOHL(rpc->rp_stat); 320 321 if (rpc->rp_direction != REPLY || rpc->rp_stat != MSG_ACCEPTED) { 322 errno = 0; 323 return (-1); 324 } 325 326 for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) 327 if (rpc->rp_xid == ns->xid) 328 break; 329 if (i >= NFS_COUNT) { 330 errno = 0; 331 return (-1); 332 } 333 334 if (ns->done) { 335 errno = 0; 336 return (-1); 337 } 338 #ifdef NFS_DEBUG 339 if (debug) 340 printf("recvreaddata: ns=%x\n", (u_int)ns); 341 #endif 342 nfs = (struct nfs_reply_data *)(rpc + 1); 343 if (len < sizeof(nfs->errno)) 344 panic("recvreaddata: bad read %d", len); 345 if (nfs->errno) { 346 errno = ntohl(nfs->errno); 347 return (-1); 348 } 349 if (len < sizeof(*nfs) - sizeof(nfs->data)) 350 panic("recvreaddata: less than nfs sized %d", len); 351 len -= sizeof(*nfs) - sizeof(nfs->data); 352 353 if (len < nfs->count) 354 panic("recvreaddata: short read (%d < %d)", len, nfs->count); 355 len = nfs->count; 356 if (len > ns->len) 357 panic("recvreaddata: huge read (%d > %d)", len, ns->len); 358 359 360 #ifdef NFS_DEBUG 361 if (debug) 362 printf("recvreaddata: read %d bytes.\n", len); 363 #endif 364 bcopy(nfs->data, ns->addr, len); 365 ns->done = 1; 366 nfscc += len; 367 368 if (len < ns->len) { 369 /* If first packet assume no more data to read */ 370 if (i == 0) 371 return (0); 372 373 /* Short read, assume we are at EOF */ 374 ++i; 375 ++ns; 376 while (i < NFS_COUNT) { 377 ns->done = 1; 378 ++i; 379 ++ns; 380 } 381 } 382 383 for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) 384 if (!ns->done) { 385 errno = 0; 386 return (-1); 387 } 388 389 /* Return data count (thus indicating success) */ 390 return (nfscc); 391 } 392 393 /* Read data from a file */ 394 static int 395 readdata(d, off, addr, len) 396 register struct nfs_iodesc *d; 397 register u_long off; 398 register void *addr; 399 register u_long len; 400 { 401 register int i, cc; 402 register struct rpc_call *rpc; 403 register struct nfsstate *ns; 404 struct { 405 u_char header[HEADER_SIZE]; 406 struct rpc_call rpc; 407 struct nfs_call_data nfs; 408 } sdata; 409 struct { 410 u_char header[HEADER_SIZE]; 411 struct rpc_call rpc; 412 struct nfs_reply_data nfs; 413 } rdata; 414 415 #ifdef NFS_DEBUG 416 if (debug) 417 printf("readdata: addr=%x, off=%d len=%d\n", (u_int)addr, off, len); 418 #endif 419 if (len == 0) 420 return (0); 421 d->iodesc->destport = getport(d->iodesc, NFS_PROG, NFS_VER2); 422 423 bzero(&sdata, sizeof(sdata)); 424 425 for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) { 426 if (len <= 0) { 427 ns->done = 1; 428 continue; 429 } 430 ns->done = 0; 431 432 ns->xid = d->iodesc->xid; 433 ++d->iodesc->xid; 434 435 ns->off = off; 436 ns->len = len; 437 if (ns->len > NFSREAD_SIZE) 438 ns->len = NFSREAD_SIZE; 439 #ifdef notdef 440 /* XXX to align or not align? It doesn't seem to speed things up... */ 441 if ((ns->off % NFSREAD_SIZE) != 0) 442 ns->len -= off % NFSREAD_SIZE; 443 #endif 444 445 off += ns->len; 446 len -= ns->len; 447 448 ns->addr = addr; 449 addr += NFSREAD_SIZE; 450 } 451 452 rpc = &sdata.rpc; 453 rpc->rp_rpcvers = htonl(RPC_MSG_VERSION); 454 rpc->rp_prog = htonl(NFS_PROG); 455 rpc->rp_vers = htonl(NFS_VER2); 456 rpc->rp_proc = htonl(NFSPROC_READ); 457 bcopy(d->fh, sdata.nfs.fh, sizeof(sdata.nfs.fh)); 458 459 nfscc = 0; 460 cc = sendrecv(d->iodesc, 461 sendreaddata, &sdata.rpc, 462 sizeof(struct rpc_call) + sizeof(struct nfs_call_data), 463 recvreaddata, 464 ((u_char *)&rdata.rpc) - HEADER_SIZE, HEADER_SIZE + 465 sizeof(struct rpc_call) + sizeof(struct nfs_reply_data)); 466 return (cc); 467 } 468 469 static struct iodesc *mountfs; 470 static u_char mountfh[NFS_FHSIZE]; 471 static time_t mounttime; 472 473 /* 474 * nfs_mount - mount this nfs filesystem to a host 475 */ 476 int 477 nfs_mount(sock, ip, path) 478 int sock; 479 n_long ip; 480 char *path; 481 { 482 struct iodesc *desc; 483 struct nfs_iodesc *fp; 484 u_long ftype; 485 486 if (!(desc = socktodesc(sock))) { 487 errno = EINVAL; 488 return(-1); 489 } 490 bcopy(&desc->myea[4], &desc->myport, 2); 491 desc->destip = ip; 492 getmountfh(desc, path, mountfh); 493 494 fp = alloc(sizeof(struct nfs_iodesc)); 495 fp->iodesc = desc; 496 fp->fh = mountfh; 497 fp->off = 0; 498 if (getnfsinfo(fp, &mounttime, NULL, &ftype, NULL, NULL, NULL) < 0) { 499 free(fp, sizeof(struct nfs_iodesc)); 500 return(-1); 501 } 502 503 if (ftype != NFDIR) { 504 free(fp, sizeof(struct nfs_iodesc)); 505 errno = EINVAL; 506 printf("nfs_mount: bad mount ftype %d", ftype); 507 return(-1); 508 } 509 #ifdef NFS_DEBUG 510 if (debug) 511 printf("nfs_mount: got fh for %s, mtime=%d, ftype=%d\n", 512 path, mounttime, ftype); 513 #endif 514 mountfs = desc; 515 free(fp, sizeof(struct nfs_iodesc)); 516 517 return(0); 518 } 519 520 /* 521 * Open a file. 522 */ 523 int 524 nfs_open(path, f) 525 char *path; 526 struct open_file *f; 527 { 528 register struct nfs_iodesc *fp; 529 u_char *imagefh; 530 u_long size, ftype; 531 int rc = 0; 532 533 #ifdef NFS_DEBUG 534 if (debug) 535 printf("nfs_open: %s\n", path); 536 #endif 537 if (!mountfs) { 538 errno = EIO; 539 printf("nfs_open: must mount first.\n"); 540 return(-1); 541 } 542 543 /* allocate file system specific data structure */ 544 fp = alloc(sizeof(struct nfs_iodesc)); 545 fp->iodesc = mountfs; 546 fp->fh = mountfh; 547 fp->off = 0; 548 549 f->f_fsdata = (void *)fp; 550 imagefh = alloc(NFS_FHSIZE); 551 bzero(imagefh, NFS_FHSIZE); 552 553 /* lookup a file handle */ 554 rc = lookupfh(fp, path, imagefh, NULL, &size, &ftype); 555 if (rc < 0) { 556 #ifdef NFS_DEBUG 557 if (debug) 558 printf("nfs_open: %s lookupfh failed: %s\n", path, strerror(errno)); 559 #endif 560 f->f_fsdata = (void *)0; 561 free(fp, sizeof(struct nfs_iodesc)); 562 free(imagefh, NFS_FHSIZE); 563 return(rc); 564 } 565 fp->fh = imagefh; 566 567 #ifdef NFS_DEBUG 568 if (debug) 569 printf("nfs_open: %s success, size=%d ftype=%d\n", 570 path, size, ftype); 571 #endif 572 fp->size = size; 573 574 return(rc); 575 } 576 577 int 578 nfs_close(f) 579 struct open_file *f; 580 { 581 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 582 583 #ifdef NFS_DEBUG 584 if (debug) 585 printf("nfs_close: called\n"); 586 #endif 587 f->f_fsdata = (void *)0; 588 if (fp == (struct nfs_iodesc *)0) 589 return (0); 590 591 free(fp->fh, NFS_FHSIZE); 592 free(fp, sizeof(struct nfs_iodesc)); 593 594 return (0); 595 } 596 597 /* 598 * read a portion of a file 599 */ 600 int 601 nfs_read(f, addr, size, resid) 602 struct open_file *f; 603 char *addr; 604 u_int size; 605 u_int *resid; /* out */ 606 { 607 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 608 register int cc; 609 610 #ifdef NFS_DEBUG 611 if (debug) 612 printf("nfs_read: size=%d off=%d\n", size, fp->off); 613 #endif 614 while (size > 0) { 615 cc = readdata(fp->iodesc, fp->off, (void *)addr, size); 616 if (cc <= 0) { 617 /* XXX maybe should retry on certain errors */ 618 if (cc < 0) { 619 #ifdef NFS_DEBUG 620 if (debug) 621 printf("nfs_read: read: %s", 622 strerror(errno)); 623 #endif 624 return (-1); 625 } 626 if (debug) 627 printf("nfs_read: hit EOF unexpectantly"); 628 goto ret; 629 } 630 fp->off += cc; 631 addr += cc; 632 size -= cc; 633 } 634 ret: 635 if (resid) 636 *resid = size; 637 638 return (0); 639 } 640 641 /* 642 * Not implemented. 643 */ 644 int 645 nfs_write(f, start, size, resid) 646 struct open_file *f; 647 char *start; 648 u_int size; 649 u_int *resid; /* out */ 650 { 651 errno = EROFS; 652 653 return (-1); 654 } 655 656 off_t 657 nfs_seek(f, offset, where) 658 struct open_file *f; 659 off_t offset; 660 int where; 661 { 662 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 663 664 switch (where) { 665 case SEEK_SET: 666 fp->off = offset; 667 break; 668 case SEEK_CUR: 669 fp->off += offset; 670 break; 671 case SEEK_END: 672 fp->off = fp->size - offset; 673 break; 674 default: 675 return (-1); 676 } 677 return (fp->off); 678 } 679 680 int 681 nfs_stat(f, sb) 682 struct open_file *f; 683 struct stat *sb; 684 { 685 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 686 mode_t mode = 0; 687 u_long ftype = 0; 688 689 #ifdef NFS_DEBUG 690 if (debug) 691 printf("nfs_stat: called\n"); 692 #endif 693 if (getnfsinfo(fp, &mounttime, &sb->st_size, &ftype, &mode, &sb->st_uid, &sb->st_gid) < 0) 694 return(-1); 695 696 /* create a mode */ 697 switch (ftype) { 698 case NFNON: 699 sb->st_mode = 0; 700 break; 701 case NFREG: 702 sb->st_mode = S_IFREG; 703 break; 704 case NFDIR: 705 sb->st_mode = S_IFDIR; 706 break; 707 case NFBLK: 708 sb->st_mode = S_IFBLK; 709 break; 710 case NFCHR: 711 sb->st_mode = S_IFCHR; 712 break; 713 case NFLNK: 714 sb->st_mode = S_IFLNK; 715 break; 716 } 717 sb->st_mode |= mode; 718 719 return (0); 720 } 721