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