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