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