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