Home | History | Annotate | Line # | Download | only in libsa
nfs.c revision 1.8
      1 /*	$NetBSD: nfs.c,v 1.8 1995/07/03 04:56:33 gwr 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 #include <sys/param.h>
     32 #include <sys/time.h>
     33 #include <sys/socket.h>
     34 #include <sys/stat.h>
     35 #include <string.h>
     36 
     37 #include <netinet/in.h>
     38 #include <netinet/in_systm.h>
     39 
     40 #include <nfs/rpcv2.h>
     41 #include <nfs/nfsv2.h>
     42 #include <nfs/xdr_subs.h>
     43 
     44 #include "stand.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_iodesc {
     86 	struct	iodesc	*iodesc;
     87 	off_t	off;
     88 	u_char	fh[NFS_FHSIZE];
     89 	struct nfsv2_fattrs fa;	/* all in network order */
     90 };
     91 
     92 struct nfs_iodesc nfs_root_node;
     93 
     94 
     95 /* Fetch the root file handle (call mount daemon) */
     96 int
     97 nfs_getrootfh(d, path, fhp)
     98 	register struct iodesc *d;
     99 	char *path;
    100 	u_char *fhp;
    101 {
    102 	register int len;
    103 	struct args {
    104 		n_long	len;
    105 		char	path[FNAME_SIZE];
    106 	} *args;
    107 	struct repl {
    108 		n_long	errno;
    109 		u_char	fh[NFS_FHSIZE];
    110 	} *repl;
    111 	struct {
    112 		n_long	h[RPC_HEADER_WORDS];
    113 		struct args d;
    114 	} sdata;
    115 	struct {
    116 		n_long	h[RPC_HEADER_WORDS];
    117 		struct repl d;
    118 	} rdata;
    119 	size_t cc;
    120 
    121 #ifdef NFS_DEBUG
    122 	if (debug)
    123 		printf("nfs_getrootfh: %s\n", path);
    124 #endif
    125 
    126 	args = &sdata.d;
    127 	repl = &rdata.d;
    128 
    129 	bzero(args, sizeof(*args));
    130 	len = strlen(path);
    131 	if (len > sizeof(args->path))
    132 		len = sizeof(args->path);
    133 	args->len = htonl(len);
    134 	bcopy(path, args->path, len);
    135 	len = 4 + roundup(len, 4);
    136 
    137 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
    138 	    args, len, repl, sizeof(*repl));
    139 	if (cc < 4)
    140 		return (-1);
    141 	if (repl->errno) {
    142 		errno = ntohl(repl->errno);
    143 		return (-1);
    144 	}
    145 	bcopy(repl->fh, fhp, sizeof(repl->fh));
    146 	return (0);
    147 }
    148 
    149 /* Lookup a file.  Return handle and attributes. */
    150 int
    151 nfs_lookupfh(d, name, newfd)
    152 	struct nfs_iodesc *d;
    153 	char *name;
    154 	struct nfs_iodesc *newfd;
    155 {
    156 	register int len, rlen;
    157 	struct args {
    158 		u_char	fh[NFS_FHSIZE];
    159 		n_long	len;
    160 		char	name[FNAME_SIZE];
    161 	} *args;
    162 	struct repl {
    163 		n_long	errno;
    164 		u_char	fh[NFS_FHSIZE];
    165 		struct	nfsv2_fattrs fa;
    166 	} *repl;
    167 	struct {
    168 		n_long	h[RPC_HEADER_WORDS];
    169 		struct args d;
    170 	} sdata;
    171 	struct {
    172 		n_long	h[RPC_HEADER_WORDS];
    173 		struct repl d;
    174 	} rdata;
    175 	size_t cc;
    176 
    177 #ifdef NFS_DEBUG
    178 	if (debug)
    179 		printf("lookupfh: called\n");
    180 #endif
    181 
    182 	args = &sdata.d;
    183 	repl = &rdata.d;
    184 
    185 	bzero(args, sizeof(*args));
    186 	bcopy(d->fh, args->fh, sizeof(args->fh));
    187 	len = strlen(name);
    188 	if (len > sizeof(args->name))
    189 		len = sizeof(args->name);
    190 	bcopy(name, args->name, len);
    191 	args->len = htonl(len);
    192 	len = 4 + roundup(len, 4);
    193 	len += NFS_FHSIZE;
    194 
    195 	rlen = sizeof(*repl);
    196 
    197 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
    198 	    args, len, repl, rlen);
    199 	if (cc < 4)
    200 		return (EIO);
    201 	if (repl->errno) {
    202 		/* XXX - saerrno.h should match errno.h and RPC! */
    203 		printf("nfs_lookup: \"%s\" error=%d\n",
    204 			   name, ntohl(repl->errno));
    205 		return (ENOENT);
    206 	}
    207 	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
    208 	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
    209 	return (0);
    210 }
    211 
    212 /* Read data from a file */
    213 size_t
    214 nfs_readdata(d, off, addr, len)
    215 	struct nfs_iodesc *d;
    216 	off_t off;
    217 	void *addr;
    218 	size_t len;
    219 {
    220 	struct nfs_read_args *args;
    221 	struct nfs_read_repl *repl;
    222 	struct {
    223 		n_long	h[RPC_HEADER_WORDS];
    224 		struct nfs_read_args d;
    225 	} sdata;
    226 	struct {
    227 		n_long	h[RPC_HEADER_WORDS];
    228 		struct nfs_read_repl d;
    229 	} rdata;
    230 	size_t cc;
    231 	int hlen, rlen, x;
    232 
    233 	args = &sdata.d;
    234 	repl = &rdata.d;
    235 
    236 	bcopy(d->fh, args->fh, NFS_FHSIZE);
    237 	args->off = txdr_unsigned(off);
    238 	if (len > NFSREAD_SIZE)
    239 		len = NFSREAD_SIZE;
    240 	args->len = txdr_unsigned(len);
    241 	args->xxx = txdr_unsigned(0);
    242 	hlen = sizeof(*repl) - NFSREAD_SIZE;
    243 
    244 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
    245 	    args, sizeof(*args),
    246 	    repl, sizeof(*repl));
    247 	if (cc < hlen)
    248 		return (-1);
    249 	if (repl->errno) {
    250 		errno = ntohl(repl->errno);
    251 		return (-1);
    252 	}
    253 	rlen = cc - hlen;
    254 	x = ntohl(repl->count);
    255 	if (rlen < x) {
    256 		printf("nfsread: short packet, %d < %d\n", rlen, x);
    257 		return(-1);
    258 	}
    259 	bcopy(repl->data, addr, x);
    260 	return (x);
    261 }
    262 
    263 /*
    264  * nfs_mount - mount this nfs filesystem to a host
    265  */
    266 int
    267 nfs_mount(sock, ip, path)
    268 	int sock;
    269 	n_long ip;
    270 	char *path;
    271 {
    272 	struct iodesc *desc;
    273 	struct nfsv2_fattrs *fa;
    274 
    275 	if (!(desc = socktodesc(sock))) {
    276 		errno = EINVAL;
    277 		return(-1);
    278 	}
    279 
    280 	/* Bind to a reserved port. */
    281 	desc->myport = htons(--rpc_port);
    282 	desc->destip = ip;
    283 	if (nfs_getrootfh(desc, path, nfs_root_node.fh))
    284 		return (-1);
    285 	nfs_root_node.iodesc = desc;
    286 	/* Fake up attributes for the root dir. */
    287 	fa = &nfs_root_node.fa;
    288 	fa->fa_type  = htonl(NFDIR);
    289 	fa->fa_mode  = htonl(0755);
    290 	fa->fa_nlink = htonl(2);
    291 
    292 #ifdef NFS_DEBUG
    293 	if (debug)
    294 		printf("nfs_mount: got fh for %s\n", path);
    295 #endif
    296 
    297 	return(0);
    298 }
    299 
    300 /*
    301  * Open a file.
    302  */
    303 int
    304 nfs_open(path, f)
    305 	char *path;
    306 	struct open_file *f;
    307 {
    308 	struct nfs_iodesc *newfd;
    309 	int rc = 0;
    310 
    311 #ifdef NFS_DEBUG
    312  	if (debug)
    313  	    printf("nfs_open: %s\n", path);
    314 #endif
    315 	if (nfs_root_node.iodesc == NULL) {
    316 		errno = EIO;
    317 		printf("nfs_open: must mount first.\n");
    318 		return(-1);
    319 	}
    320 
    321 	/* allocate file system specific data structure */
    322 	newfd = alloc(sizeof(*newfd));
    323 	newfd->iodesc = nfs_root_node.iodesc;
    324 	newfd->off = 0;
    325 
    326 	/* lookup a file handle */
    327 	rc = nfs_lookupfh(&nfs_root_node, path, newfd);
    328 	if (rc) {
    329 #ifdef NFS_DEBUG
    330 		if (debug)
    331 			printf("nfs_open: %s lookupfh failed: %s\n",
    332 				path, strerror(errno));
    333 #endif
    334 		free(newfd, sizeof(*newfd));
    335 		return(rc);
    336 	}
    337 	f->f_fsdata = (void *)newfd;
    338 
    339 #ifdef NFS_DEBUG
    340 	if (debug)
    341 		printf("nfs_open: \"%s\", type=%d size=%d\n", path,
    342 			   ntohl(newfd->fa.fa_type),
    343 			   ntohl(newfd->fa.fa_size));
    344 #endif
    345 
    346 	return(rc);
    347 }
    348 
    349 int
    350 nfs_close(f)
    351 	struct open_file *f;
    352 {
    353 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    354 
    355 #ifdef NFS_DEBUG
    356 	if (debug)
    357 		printf("nfs_close: fp=0x%x\n", fp);
    358 #endif
    359 
    360 	if (fp)
    361 		free(fp, sizeof(struct nfs_iodesc));
    362 	f->f_fsdata = (void *)0;
    363 
    364 	return (0);
    365 }
    366 
    367 /*
    368  * read a portion of a file
    369  */
    370 int
    371 nfs_read(f, addr, size, resid)
    372 	struct open_file *f;
    373 	char *addr;
    374 	u_int size;
    375 	u_int *resid;	/* out */
    376 {
    377 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    378 	register size_t cc;
    379 
    380 #ifdef NFS_DEBUG
    381 	if (debug)
    382 		printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
    383 #endif
    384 	while (size > 0) {
    385 		twiddle();
    386 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
    387 		/* XXX maybe should retry on certain errors */
    388 		if (cc == -1) {
    389 #ifdef NFS_DEBUG
    390 			if (debug)
    391 				printf("nfs_read: read: %s", strerror(errno));
    392 #endif
    393 			return (-1);
    394 		}
    395 		if (cc == 0) {
    396 			if (debug)
    397 				printf("nfs_read: hit EOF unexpectantly");
    398 			goto ret;
    399 		}
    400 		fp->off += cc;
    401 		addr += cc;
    402 		size -= cc;
    403 	}
    404 ret:
    405 	if (resid)
    406 		*resid = size;
    407 
    408 	return (0);
    409 }
    410 
    411 /*
    412  * Not implemented.
    413  */
    414 int
    415 nfs_write(f, start, size, resid)
    416 	struct open_file *f;
    417 	char *start;
    418 	u_int size;
    419 	u_int *resid;	/* out */
    420 {
    421 	errno = EROFS;
    422 
    423 	return (-1);
    424 }
    425 
    426 off_t
    427 nfs_seek(f, offset, where)
    428 	struct open_file *f;
    429 	off_t offset;
    430 	int where;
    431 {
    432 	register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
    433 	n_long size = ntohl(d->fa.fa_size);
    434 
    435 	switch (where) {
    436 	case SEEK_SET:
    437 		d->off = offset;
    438 		break;
    439 	case SEEK_CUR:
    440 		d->off += offset;
    441 		break;
    442 	case SEEK_END:
    443 		d->off = size - offset;
    444 		break;
    445 	default:
    446 		return (-1);
    447 	}
    448 
    449 	return (d->off);
    450 }
    451 
    452 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
    453 int nfs_stat_types[8] = {
    454 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
    455 
    456 int
    457 nfs_stat(f, sb)
    458 	struct open_file *f;
    459 	struct stat *sb;
    460 {
    461 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    462 	register n_long ftype, mode;
    463 
    464 	ftype = ntohl(fp->fa.fa_type);
    465 	mode  = ntohl(fp->fa.fa_mode);
    466 	mode |= nfs_stat_types[ftype & 7];
    467 
    468 	sb->st_mode  = mode;
    469 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
    470 	sb->st_uid   = ntohl(fp->fa.fa_uid);
    471 	sb->st_gid   = ntohl(fp->fa.fa_gid);
    472 	sb->st_size  = ntohl(fp->fa.fa_size);
    473 
    474 	return (0);
    475 }
    476