Home | History | Annotate | Line # | Download | only in libsa
nfs.c revision 1.41
      1 /*	$NetBSD: nfs.c,v 1.41 2007/02/25 04:46:32 uwe 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 */
     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 *, const char *, int,
    116 	    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 	struct iodesc *d;
    127 	char *path;
    128 	u_char *fhp;
    129 {
    130 	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 	ssize_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 ((size_t)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, len, newfd)
    189 	struct nfs_iodesc *d;
    190 	const char *name;
    191 	int len;
    192 	struct nfs_iodesc *newfd;
    193 {
    194 	int rlen;
    195 	struct args {
    196 		u_char	fh[NFS_FHSIZE];
    197 		n_long	len;
    198 		char	name[FNAME_SIZE];
    199 	} *args;
    200 	struct repl {
    201 		n_long	errno;
    202 		u_char	fh[NFS_FHSIZE];
    203 		struct	nfsv2_fattrs fa;
    204 	} *repl;
    205 	struct {
    206 		n_long	h[RPC_HEADER_WORDS];
    207 		struct args d;
    208 	} sdata;
    209 	struct {
    210 		n_long	h[RPC_HEADER_WORDS];
    211 		struct repl d;
    212 	} rdata;
    213 	ssize_t cc;
    214 
    215 #ifdef NFS_DEBUG
    216 	if (debug)
    217 		printf("lookupfh: called\n");
    218 #endif
    219 
    220 	args = &sdata.d;
    221 	repl = &rdata.d;
    222 
    223 	bzero(args, sizeof(*args));
    224 	bcopy(d->fh, args->fh, sizeof(args->fh));
    225 	if ((size_t)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 	ssize_t cc;
    318 	long x;
    319 	size_t 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 < (ssize_t)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 < (size_t)x) {
    350 		printf("nfsread: short packet, %lu < %ld\n", (u_long) 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 	const char *path;
    403 	struct open_file *f;
    404 {
    405 	struct nfs_iodesc *newfd, *currfd;
    406 	const char *cp;
    407 #ifndef NFS_NOSYMLINK
    408 	const char *ncp;
    409 	int c;
    410 	char namebuf[NFS_MAXPATHLEN + 1];
    411 	char linkbuf[NFS_MAXPATHLEN + 1];
    412 	int nlinks = 0;
    413 #endif
    414 	int error = 0;
    415 
    416 #ifdef NFS_DEBUG
    417  	if (debug)
    418  	    printf("nfs_open: %s\n", path);
    419 #endif
    420 	if (nfs_root_node.iodesc == NULL) {
    421 		printf("nfs_open: must mount first.\n");
    422 		return (ENXIO);
    423 	}
    424 
    425 	currfd = &nfs_root_node;
    426 	newfd = 0;
    427 
    428 #ifndef NFS_NOSYMLINK
    429 	cp = path;
    430 	while (*cp) {
    431 		/*
    432 		 * Remove extra separators
    433 		 */
    434 		while (*cp == '/')
    435 			cp++;
    436 
    437 		if (*cp == '\0')
    438 			break;
    439 		/*
    440 		 * Check that current node is a directory.
    441 		 */
    442 		if (currfd->fa.fa_type != htonl(NFDIR)) {
    443 			error = ENOTDIR;
    444 			goto out;
    445 		}
    446 
    447 		/* allocate file system specific data structure */
    448 		newfd = alloc(sizeof(*newfd));
    449 		newfd->iodesc = currfd->iodesc;
    450 		newfd->off = 0;
    451 
    452 		/*
    453 		 * Get next component of path name.
    454 		 */
    455 		{
    456 			int len = 0;
    457 
    458 			ncp = cp;
    459 			while ((c = *cp) != '\0' && c != '/') {
    460 				if (++len > NFS_MAXNAMLEN) {
    461 					error = ENOENT;
    462 					goto out;
    463 				}
    464 				cp++;
    465 			}
    466 		}
    467 
    468 		/* lookup a file handle */
    469 		error = nfs_lookupfh(currfd, ncp, cp - ncp, newfd);
    470 		if (error)
    471 			goto out;
    472 
    473 		/*
    474 		 * Check for symbolic link
    475 		 */
    476 		if (newfd->fa.fa_type == htonl(NFLNK)) {
    477 			int link_len, len;
    478 
    479 			error = nfs_readlink(newfd, linkbuf);
    480 			if (error)
    481 				goto out;
    482 
    483 			link_len = strlen(linkbuf);
    484 			len = strlen(cp);
    485 
    486 			if (link_len + len > MAXPATHLEN
    487 			    || ++nlinks > MAXSYMLINKS) {
    488 				error = ENOENT;
    489 				goto out;
    490 			}
    491 
    492 			bcopy(cp, &namebuf[link_len], len + 1);
    493 			bcopy(linkbuf, namebuf, link_len);
    494 
    495 			/*
    496 			 * If absolute pathname, restart at root.
    497 			 * If relative pathname, restart at parent directory.
    498 			 */
    499 			cp = namebuf;
    500 			if (*cp == '/') {
    501 				if (currfd != &nfs_root_node)
    502 					dealloc(currfd, sizeof(*currfd));
    503 				currfd = &nfs_root_node;
    504 			}
    505 
    506 			dealloc(newfd, sizeof(*newfd));
    507 			newfd = 0;
    508 
    509 			continue;
    510 		}
    511 
    512 		if (currfd != &nfs_root_node)
    513 			dealloc(currfd, sizeof(*currfd));
    514 		currfd = newfd;
    515 		newfd = 0;
    516 	}
    517 
    518 	error = 0;
    519 
    520 out:
    521 #else
    522 	/* allocate file system specific data structure */
    523 	currfd = alloc(sizeof(*currfd));
    524 	currfd->iodesc = nfs_root_node.iodesc;
    525 	currfd->off = 0;
    526 
    527 	cp = path;
    528 	/*
    529 	 * Remove extra separators
    530 	 */
    531 	while (*cp == '/')
    532 		cp++;
    533 
    534 	/* XXX: Check for empty path here? */
    535 
    536 	error = nfs_lookupfh(&nfs_root_node, cp, strlen(cp), currfd);
    537 #endif
    538 	if (!error) {
    539 		f->f_fsdata = (void *)currfd;
    540 		return (0);
    541 	}
    542 
    543 #ifdef NFS_DEBUG
    544 	if (debug)
    545 		printf("nfs_open: %s lookupfh failed: %s\n",
    546 		    path, strerror(error));
    547 #endif
    548 	if (currfd != &nfs_root_node)
    549 		dealloc(currfd, sizeof(*currfd));
    550 	if (newfd)
    551 		dealloc(newfd, sizeof(*newfd));
    552 
    553 	return (error);
    554 }
    555 
    556 int
    557 nfs_close(f)
    558 	struct open_file *f;
    559 {
    560 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    561 
    562 #ifdef NFS_DEBUG
    563 	if (debug)
    564 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
    565 #endif
    566 
    567 	if (fp)
    568 		dealloc(fp, sizeof(struct nfs_iodesc));
    569 	f->f_fsdata = (void *)0;
    570 
    571 	return (0);
    572 }
    573 
    574 /*
    575  * read a portion of a file
    576  */
    577 int
    578 nfs_read(f, buf, size, resid)
    579 	struct open_file *f;
    580 	void *buf;
    581 	size_t size;
    582 	size_t *resid;	/* out */
    583 {
    584 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    585 	ssize_t cc;
    586 	char *addr = buf;
    587 
    588 #ifdef NFS_DEBUG
    589 	if (debug)
    590 		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
    591 		    (int)fp->off);
    592 #endif
    593 	while ((int)size > 0) {
    594 #if !defined(LIBSA_NO_TWIDDLE)
    595 		twiddle();
    596 #endif
    597 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
    598 		/* XXX maybe should retry on certain errors */
    599 		if (cc == -1) {
    600 #ifdef NFS_DEBUG
    601 			if (debug)
    602 				printf("nfs_read: read: %s\n",
    603 				       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\n");
    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