Home | History | Annotate | Line # | Download | only in libsa
nfs.c revision 1.31
      1 /*	$NetBSD: nfs.c,v 1.31 2003/03/18 19:20:09 mycroft 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 without NQNFS stuff. */
     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 __P((struct iodesc *, char *, u_char *));
    115 int	nfs_lookupfh __P((struct nfs_iodesc *, char *, struct nfs_iodesc *));
    116 int	nfs_readlink __P((struct nfs_iodesc *, char *));
    117 ssize_t	nfs_readdata __P((struct nfs_iodesc *, off_t, void *, size_t));
    118 
    119 /*
    120  * Fetch the root file handle (call mount daemon)
    121  * On error, return non-zero and set errno.
    122  */
    123 int
    124 nfs_getrootfh(d, path, fhp)
    125 	struct iodesc *d;
    126 	char *path;
    127 	u_char *fhp;
    128 {
    129 	int len;
    130 	struct args {
    131 		n_long	len;
    132 		char	path[FNAME_SIZE];
    133 	} *args;
    134 	struct repl {
    135 		n_long	errno;
    136 		u_char	fh[NFS_FHSIZE];
    137 	} *repl;
    138 	struct {
    139 		n_long	h[RPC_HEADER_WORDS];
    140 		struct args d;
    141 	} sdata;
    142 	struct {
    143 		n_long	h[RPC_HEADER_WORDS];
    144 		struct repl d;
    145 	} rdata;
    146 	size_t cc;
    147 
    148 #ifdef NFS_DEBUG
    149 	if (debug)
    150 		printf("nfs_getrootfh: %s\n", path);
    151 #endif
    152 
    153 	args = &sdata.d;
    154 	repl = &rdata.d;
    155 
    156 	bzero(args, sizeof(*args));
    157 	len = strlen(path);
    158 	if (len > sizeof(args->path))
    159 		len = sizeof(args->path);
    160 	args->len = htonl(len);
    161 	bcopy(path, args->path, len);
    162 	len = 4 + roundup(len, 4);
    163 
    164 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
    165 	    args, len, repl, sizeof(*repl));
    166 	if (cc == -1) {
    167 		/* errno was set by rpc_call */
    168 		return (-1);
    169 	}
    170 	if (cc < 4) {
    171 		errno = EBADRPC;
    172 		return (-1);
    173 	}
    174 	if (repl->errno) {
    175 		errno = ntohl(repl->errno);
    176 		return (-1);
    177 	}
    178 	bcopy(repl->fh, fhp, sizeof(repl->fh));
    179 	return (0);
    180 }
    181 
    182 /*
    183  * Lookup a file.  Store handle and attributes.
    184  * Return zero or error number.
    185  */
    186 int
    187 nfs_lookupfh(d, name, newfd)
    188 	struct nfs_iodesc *d;
    189 	char *name;
    190 	struct nfs_iodesc *newfd;
    191 {
    192 	int len, rlen;
    193 	struct args {
    194 		u_char	fh[NFS_FHSIZE];
    195 		n_long	len;
    196 		char	name[FNAME_SIZE];
    197 	} *args;
    198 	struct repl {
    199 		n_long	errno;
    200 		u_char	fh[NFS_FHSIZE];
    201 		struct	nfsv2_fattrs fa;
    202 	} *repl;
    203 	struct {
    204 		n_long	h[RPC_HEADER_WORDS];
    205 		struct args d;
    206 	} sdata;
    207 	struct {
    208 		n_long	h[RPC_HEADER_WORDS];
    209 		struct repl d;
    210 	} rdata;
    211 	ssize_t cc;
    212 
    213 #ifdef NFS_DEBUG
    214 	if (debug)
    215 		printf("lookupfh: called\n");
    216 #endif
    217 
    218 	args = &sdata.d;
    219 	repl = &rdata.d;
    220 
    221 	bzero(args, sizeof(*args));
    222 	bcopy(d->fh, args->fh, sizeof(args->fh));
    223 	len = strlen(name);
    224 	if (len > sizeof(args->name))
    225 		len = sizeof(args->name);
    226 	bcopy(name, args->name, len);
    227 	args->len = htonl(len);
    228 	len = 4 + roundup(len, 4);
    229 	len += NFS_FHSIZE;
    230 
    231 	rlen = sizeof(*repl);
    232 
    233 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
    234 	    args, len, repl, rlen);
    235 	if (cc == -1)
    236 		return (errno);		/* XXX - from rpc_call */
    237 	if (cc < 4)
    238 		return (EIO);
    239 	if (repl->errno) {
    240 		/* saerrno.h now matches NFS error numbers. */
    241 		return (ntohl(repl->errno));
    242 	}
    243 	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
    244 	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
    245 	return (0);
    246 }
    247 
    248 #ifndef NFS_NOSYMLINK
    249 /*
    250  * Get the destination of a symbolic link.
    251  */
    252 int
    253 nfs_readlink(d, buf)
    254 	struct nfs_iodesc *d;
    255 	char *buf;
    256 {
    257 	struct {
    258 		n_long	h[RPC_HEADER_WORDS];
    259 		u_char fh[NFS_FHSIZE];
    260 	} sdata;
    261 	struct {
    262 		n_long	h[RPC_HEADER_WORDS];
    263 		struct nfs_readlnk_repl d;
    264 	} rdata;
    265 	ssize_t cc;
    266 
    267 #ifdef NFS_DEBUG
    268 	if (debug)
    269 		printf("readlink: called\n");
    270 #endif
    271 
    272 	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
    273 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
    274 		      sdata.fh, NFS_FHSIZE,
    275 		      &rdata.d, sizeof(rdata.d));
    276 	if (cc == -1)
    277 		return (errno);
    278 
    279 	if (cc < 4)
    280 		return (EIO);
    281 
    282 	if (rdata.d.errno)
    283 		return (ntohl(rdata.d.errno));
    284 
    285 	rdata.d.len = ntohl(rdata.d.len);
    286 	if (rdata.d.len > NFS_MAXPATHLEN)
    287 		return (ENAMETOOLONG);
    288 
    289 	bcopy(rdata.d.path, buf, rdata.d.len);
    290 	buf[rdata.d.len] = 0;
    291 	return (0);
    292 }
    293 #endif
    294 
    295 /*
    296  * Read data from a file.
    297  * Return transfer count or -1 (and set errno)
    298  */
    299 ssize_t
    300 nfs_readdata(d, off, addr, len)
    301 	struct nfs_iodesc *d;
    302 	off_t off;
    303 	void *addr;
    304 	size_t len;
    305 {
    306 	struct nfs_read_args *args;
    307 	struct nfs_read_repl *repl;
    308 	struct {
    309 		n_long	h[RPC_HEADER_WORDS];
    310 		struct nfs_read_args d;
    311 	} sdata;
    312 	struct {
    313 		n_long	h[RPC_HEADER_WORDS];
    314 		struct nfs_read_repl d;
    315 	} rdata;
    316 	size_t cc;
    317 	long x;
    318 	int hlen, rlen;
    319 
    320 	args = &sdata.d;
    321 	repl = &rdata.d;
    322 
    323 	bcopy(d->fh, args->fh, NFS_FHSIZE);
    324 	args->off = htonl((n_long)off);
    325 	if (len > NFSREAD_SIZE)
    326 		len = NFSREAD_SIZE;
    327 	args->len = htonl((n_long)len);
    328 	args->xxx = htonl((n_long)0);
    329 	hlen = sizeof(*repl) - NFSREAD_SIZE;
    330 
    331 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
    332 	    args, sizeof(*args),
    333 	    repl, sizeof(*repl));
    334 	if (cc == -1) {
    335 		/* errno was already set by rpc_call */
    336 		return (-1);
    337 	}
    338 	if (cc < hlen) {
    339 		errno = EBADRPC;
    340 		return (-1);
    341 	}
    342 	if (repl->errno) {
    343 		errno = ntohl(repl->errno);
    344 		return (-1);
    345 	}
    346 	rlen = cc - hlen;
    347 	x = ntohl(repl->count);
    348 	if (rlen < x) {
    349 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
    350 		errno = EBADRPC;
    351 		return(-1);
    352 	}
    353 	bcopy(repl->data, addr, x);
    354 	return (x);
    355 }
    356 
    357 /*
    358  * nfs_mount - mount this nfs filesystem to a host
    359  * On error, return non-zero and set errno.
    360  */
    361 int
    362 nfs_mount(sock, ip, path)
    363 	int sock;
    364 	struct in_addr ip;
    365 	char *path;
    366 {
    367 	struct iodesc *desc;
    368 	struct nfsv2_fattrs *fa;
    369 
    370 	if (!(desc = socktodesc(sock))) {
    371 		errno = EINVAL;
    372 		return(-1);
    373 	}
    374 
    375 	/* Bind to a reserved port. */
    376 	desc->myport = htons(--rpc_port);
    377 	desc->destip = ip;
    378 	if (nfs_getrootfh(desc, path, nfs_root_node.fh))
    379 		return (-1);
    380 	nfs_root_node.iodesc = desc;
    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 #ifdef NFS_DEBUG
    388 	if (debug)
    389 		printf("nfs_mount: got fh for %s\n", path);
    390 #endif
    391 
    392 	return(0);
    393 }
    394 
    395 /*
    396  * Open a file.
    397  * return zero or error number
    398  */
    399 int
    400 nfs_open(path, f)
    401 	char *path;
    402 	struct open_file *f;
    403 {
    404 	struct nfs_iodesc *newfd, *currfd;
    405 	char *cp;
    406 #ifndef NFS_NOSYMLINK
    407 	char *ncp;
    408 	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 			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 	cp = path;
    529 	/*
    530 	 * Remove extra separators
    531 	 */
    532 	while (*cp == '/')
    533 		cp++;
    534 
    535 	/* XXX: Check for empty path here? */
    536 
    537 	error = nfs_lookupfh(&nfs_root_node, cp, currfd);
    538 #endif
    539 	if (!error) {
    540 		f->f_fsdata = (void *)currfd;
    541 		return (0);
    542 	}
    543 
    544 #ifdef NFS_DEBUG
    545 	if (debug)
    546 		printf("nfs_open: %s lookupfh failed: %s\n",
    547 		    path, strerror(error));
    548 #endif
    549 	if (currfd != &nfs_root_node)
    550 		free(currfd, sizeof(*currfd));
    551 	if (newfd)
    552 		free(newfd, sizeof(*newfd));
    553 
    554 	return (error);
    555 }
    556 
    557 int
    558 nfs_close(f)
    559 	struct open_file *f;
    560 {
    561 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    562 
    563 #ifdef NFS_DEBUG
    564 	if (debug)
    565 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
    566 #endif
    567 
    568 	if (fp)
    569 		free(fp, sizeof(struct nfs_iodesc));
    570 	f->f_fsdata = (void *)0;
    571 
    572 	return (0);
    573 }
    574 
    575 /*
    576  * read a portion of a file
    577  */
    578 int
    579 nfs_read(f, buf, size, resid)
    580 	struct open_file *f;
    581 	void *buf;
    582 	size_t size;
    583 	size_t *resid;	/* out */
    584 {
    585 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    586 	ssize_t cc;
    587 	char *addr = buf;
    588 
    589 #ifdef NFS_DEBUG
    590 	if (debug)
    591 		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
    592 		    (int)fp->off);
    593 #endif
    594 	while ((int)size > 0) {
    595 #if !defined(LIBSA_NO_TWIDDLE)
    596 		twiddle();
    597 #endif
    598 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
    599 		/* XXX maybe should retry on certain errors */
    600 		if (cc == -1) {
    601 #ifdef NFS_DEBUG
    602 			if (debug)
    603 				printf("nfs_read: read: %s", strerror(errno));
    604 #endif
    605 			return (errno);	/* XXX - from nfs_readdata */
    606 		}
    607 		if (cc == 0) {
    608 #ifdef NFS_DEBUG
    609 			if (debug)
    610 				printf("nfs_read: hit EOF unexpectantly");
    611 #endif
    612 			goto ret;
    613 		}
    614 		fp->off += cc;
    615 		addr += cc;
    616 		size -= cc;
    617 	}
    618 ret:
    619 	if (resid)
    620 		*resid = size;
    621 
    622 	return (0);
    623 }
    624 
    625 /*
    626  * Not implemented.
    627  */
    628 int
    629 nfs_write(f, buf, size, resid)
    630 	struct open_file *f;
    631 	void *buf;
    632 	size_t size;
    633 	size_t *resid;	/* out */
    634 {
    635 	return (EROFS);
    636 }
    637 
    638 off_t
    639 nfs_seek(f, offset, where)
    640 	struct open_file *f;
    641 	off_t offset;
    642 	int where;
    643 {
    644 	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
    645 	n_long size = ntohl(d->fa.fa_size);
    646 
    647 	switch (where) {
    648 	case SEEK_SET:
    649 		d->off = offset;
    650 		break;
    651 	case SEEK_CUR:
    652 		d->off += offset;
    653 		break;
    654 	case SEEK_END:
    655 		d->off = size - offset;
    656 		break;
    657 	default:
    658 		return (-1);
    659 	}
    660 
    661 	return (d->off);
    662 }
    663 
    664 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
    665 const int nfs_stat_types[8] = {
    666 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
    667 
    668 int
    669 nfs_stat(f, sb)
    670 	struct open_file *f;
    671 	struct stat *sb;
    672 {
    673 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    674 	n_long ftype, mode;
    675 
    676 	ftype = ntohl(fp->fa.fa_type);
    677 	mode  = ntohl(fp->fa.fa_mode);
    678 	mode |= nfs_stat_types[ftype & 7];
    679 
    680 	sb->st_mode  = mode;
    681 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
    682 	sb->st_uid   = ntohl(fp->fa.fa_uid);
    683 	sb->st_gid   = ntohl(fp->fa.fa_gid);
    684 	sb->st_size  = ntohl(fp->fa.fa_size);
    685 
    686 	return (0);
    687 }
    688