1 /* $NetBSD: nfs.c,v 1.3 2001/07/07 22:57:58 perry 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 104 /* 105 * Fetch the root file handle (call mount daemon) 106 * Return zero or error number. 107 */ 108 int 109 nfs_getrootfh(d, path, fhp) 110 register struct iodesc *d; 111 char *path; 112 u_char *fhp; 113 { 114 register int len; 115 struct args { 116 n_long len; 117 char path[FNAME_SIZE]; 118 } *args; 119 struct repl { 120 n_long errno; 121 u_char fh[NFS_FHSIZE]; 122 } *repl; 123 struct { 124 n_long h[RPC_HEADER_WORDS]; 125 struct args d; 126 } sdata; 127 struct { 128 n_long h[RPC_HEADER_WORDS]; 129 struct repl d; 130 } rdata; 131 size_t cc; 132 133 #ifdef NFS_DEBUG 134 if (debug) 135 printf("nfs_getrootfh: %s\n", path); 136 #endif 137 138 args = &sdata.d; 139 repl = &rdata.d; 140 141 memset(args, 0, sizeof(*args)); 142 len = strlen(path); 143 if (len > sizeof(args->path)) 144 len = sizeof(args->path); 145 args->len = htonl(len); 146 memcpy(args->path, path, len); 147 len = 4 + roundup(len, 4); 148 149 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 150 args, len, repl, sizeof(*repl)); 151 if (cc == -1) { 152 /* errno was set by rpc_call */ 153 return (errno); 154 } 155 if (cc < 4) 156 return (EBADRPC); 157 if (repl->errno) 158 return (ntohl(repl->errno)); 159 memcpy(fhp, repl->fh, 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 memset(args, 0, sizeof(*args)); 203 memcpy(args->fh, d->fh, sizeof(args->fh)); 204 len = strlen(name); 205 if (len > sizeof(args->name)) 206 len = sizeof(args->name); 207 memcpy(args->name, 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 memcpy(&newfd->fh, repl->fh, sizeof(newfd->fh)); 225 memcpy(&newfd->fa, &repl->fa, sizeof(newfd->fa)); 226 return (0); 227 } 228 229 #ifndef NFS_NOSYMLINK 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 memcpy(sdata.fh, d->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 memcpy(buf, rdata.d.path, rdata.d.len); 271 buf[rdata.d.len] = 0; 272 return (0); 273 } 274 #endif 275 276 /* 277 * Read data from a file. 278 * Return transfer count or -1 (and set errno) 279 */ 280 ssize_t 281 nfs_readdata(d, off, addr, len) 282 struct nfs_iodesc *d; 283 off_t off; 284 void *addr; 285 size_t len; 286 { 287 struct nfs_read_args *args; 288 struct nfs_read_repl *repl; 289 struct { 290 n_long h[RPC_HEADER_WORDS]; 291 struct nfs_read_args d; 292 } sdata; 293 struct { 294 n_long h[RPC_HEADER_WORDS]; 295 struct nfs_read_repl d; 296 } rdata; 297 size_t cc; 298 long x; 299 int hlen, rlen; 300 301 args = &sdata.d; 302 repl = &rdata.d; 303 304 memcpy(args->fh, d->fh, NFS_FHSIZE); 305 args->off = htonl((n_long)off); 306 if (len > NFSREAD_SIZE) 307 len = NFSREAD_SIZE; 308 args->len = htonl((n_long)len); 309 args->xxx = htonl((n_long)0); 310 hlen = sizeof(*repl) - NFSREAD_SIZE; 311 312 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 313 args, sizeof(*args), 314 repl, sizeof(*repl)); 315 if (cc == -1) { 316 /* errno was already set by rpc_call */ 317 return (-1); 318 } 319 if (cc < hlen) { 320 errno = EBADRPC; 321 return (-1); 322 } 323 if (repl->errno) { 324 errno = ntohl(repl->errno); 325 return (-1); 326 } 327 rlen = cc - hlen; 328 x = ntohl(repl->count); 329 if (rlen < x) { 330 printf("nfsread: short packet, %d < %ld\n", rlen, x); 331 errno = EBADRPC; 332 return(-1); 333 } 334 memcpy(addr, repl->data, x); 335 return (x); 336 } 337 338 /* 339 * Open a file. 340 * return zero or error number 341 */ 342 int 343 nfs_open(path, f) 344 char *path; 345 struct open_file *f; 346 { 347 static struct nfs_iodesc nfs_root_node; 348 struct iodesc *desc; 349 struct nfs_iodesc *currfd; 350 #ifndef NFS_NOSYMLINK 351 struct nfs_iodesc *newfd; 352 struct nfsv2_fattrs *fa; 353 register char *cp, *ncp; 354 register int c; 355 char namebuf[NFS_MAXPATHLEN + 1]; 356 char linkbuf[NFS_MAXPATHLEN + 1]; 357 int nlinks = 0; 358 #endif 359 int error; 360 361 #ifdef NFS_DEBUG 362 if (debug) 363 printf("nfs_open: %s\n", path); 364 #endif 365 if (!rootpath[0]) { 366 printf("no rootpath, no nfs\n"); 367 return (ENXIO); 368 } 369 370 if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 371 return(EINVAL); 372 373 /* Bind to a reserved port. */ 374 desc->myport = htons(--rpc_port); 375 desc->destip = rootip; 376 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 377 return (error); 378 nfs_root_node.iodesc = desc; 379 380 #ifndef NFS_NOSYMLINK 381 /* Fake up attributes for the root dir. */ 382 fa = &nfs_root_node.fa; 383 fa->fa_type = htonl(NFDIR); 384 fa->fa_mode = htonl(0755); 385 fa->fa_nlink = htonl(2); 386 387 currfd = &nfs_root_node; 388 newfd = 0; 389 390 cp = path; 391 while (*cp) { 392 /* 393 * Remove extra separators 394 */ 395 while (*cp == '/') 396 cp++; 397 398 if (*cp == '\0') 399 break; 400 /* 401 * Check that current node is a directory. 402 */ 403 if (currfd->fa.fa_type != htonl(NFDIR)) { 404 error = ENOTDIR; 405 goto out; 406 } 407 408 /* allocate file system specific data structure */ 409 newfd = alloc(sizeof(*newfd)); 410 newfd->iodesc = currfd->iodesc; 411 newfd->off = 0; 412 413 /* 414 * Get next component of path name. 415 */ 416 { 417 register int len = 0; 418 419 ncp = cp; 420 while ((c = *cp) != '\0' && c != '/') { 421 if (++len > NFS_MAXNAMLEN) { 422 error = ENOENT; 423 goto out; 424 } 425 cp++; 426 } 427 *cp = '\0'; 428 } 429 430 /* lookup a file handle */ 431 error = nfs_lookupfh(currfd, ncp, newfd); 432 *cp = c; 433 if (error) 434 goto out; 435 436 /* 437 * Check for symbolic link 438 */ 439 if (newfd->fa.fa_type == htonl(NFLNK)) { 440 int link_len, len; 441 442 error = nfs_readlink(newfd, linkbuf); 443 if (error) 444 goto out; 445 446 link_len = strlen(linkbuf); 447 len = strlen(cp); 448 449 if (link_len + len > MAXPATHLEN 450 || ++nlinks > MAXSYMLINKS) { 451 error = ENOENT; 452 goto out; 453 } 454 455 memcpy(&namebuf[link_len], cp, len + 1); 456 memcpy(namebuf, linkbuf, link_len); 457 458 /* 459 * If absolute pathname, restart at root. 460 * If relative pathname, restart at parent directory. 461 */ 462 cp = namebuf; 463 if (*cp == '/') { 464 if (currfd != &nfs_root_node) 465 free(currfd, sizeof(*currfd)); 466 currfd = &nfs_root_node; 467 } 468 469 free(newfd, sizeof(*newfd)); 470 newfd = 0; 471 472 continue; 473 } 474 475 if (currfd != &nfs_root_node) 476 free(currfd, sizeof(*currfd)); 477 currfd = newfd; 478 newfd = 0; 479 } 480 481 error = 0; 482 483 out: 484 if (newfd) 485 free(newfd, sizeof(*newfd)); 486 #else 487 /* allocate file system specific data structure */ 488 currfd = alloc(sizeof(*currfd)); 489 currfd->iodesc = desc; 490 currfd->off = 0; 491 492 error = nfs_lookupfh(&nfs_root_node, path, currfd); 493 #endif 494 if (!error) { 495 f->f_fsdata = (void *)currfd; 496 return (0); 497 } 498 499 #ifdef NFS_DEBUG 500 if (debug) 501 printf("nfs_open: %s lookupfh failed: %s\n", 502 path, strerror(error)); 503 #endif 504 #ifndef NFS_NOSYMLINK 505 if (currfd != &nfs_root_node) 506 #endif 507 free(currfd, sizeof(*currfd)); 508 509 return (error); 510 } 511 512 int 513 nfs_close(f) 514 struct open_file *f; 515 { 516 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 517 518 #ifdef NFS_DEBUG 519 if (debug) 520 printf("nfs_close: fp=0x%lx\n", (u_long)fp); 521 #endif 522 523 if (fp) 524 free(fp, sizeof(struct nfs_iodesc)); 525 f->f_fsdata = (void *)0; 526 527 return (0); 528 } 529 530 /* 531 * read a portion of a file 532 */ 533 int 534 nfs_read(f, buf, size, resid) 535 struct open_file *f; 536 void *buf; 537 size_t size; 538 size_t *resid; /* out */ 539 { 540 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 541 register ssize_t cc; 542 register char *addr = buf; 543 544 #ifdef NFS_DEBUG 545 if (debug) 546 printf("nfs_read: size=%lu off=%d\n", (u_long)size, 547 (int)fp->off); 548 #endif 549 while ((int)size > 0) { 550 twiddle(); 551 cc = nfs_readdata(fp, fp->off, (void *)addr, size); 552 /* XXX maybe should retry on certain errors */ 553 if (cc == -1) { 554 #ifdef NFS_DEBUG 555 if (debug) 556 printf("nfs_read: read: %s", strerror(errno)); 557 #endif 558 return (errno); /* XXX - from nfs_readdata */ 559 } 560 if (cc == 0) { 561 #ifdef NFS_DEBUG 562 if (debug) 563 printf("nfs_read: hit EOF unexpectantly"); 564 #endif 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