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