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