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