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