Home | History | Annotate | Line # | Download | only in libsa
nfs.c revision 1.11
      1 /*	$NetBSD: nfs.c,v 1.11 1995/09/18 21:19:36 pk 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 	ssize_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 ssize_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 	long x;
    232 	int hlen, rlen;
    233 
    234 	args = &sdata.d;
    235 	repl = &rdata.d;
    236 
    237 	bcopy(d->fh, args->fh, NFS_FHSIZE);
    238 	args->off = txdr_unsigned(off);
    239 	if (len > NFSREAD_SIZE)
    240 		len = NFSREAD_SIZE;
    241 	args->len = txdr_unsigned(len);
    242 	args->xxx = txdr_unsigned(0);
    243 	hlen = sizeof(*repl) - NFSREAD_SIZE;
    244 
    245 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
    246 	    args, sizeof(*args),
    247 	    repl, sizeof(*repl));
    248 	if (cc < hlen) {
    249 		if (cc != -1)
    250 			errno = EBADRPC;
    251 		return (-1);
    252 	}
    253 	if (repl->errno) {
    254 		errno = ntohl(repl->errno);
    255 		return (-1);
    256 	}
    257 	rlen = cc - hlen;
    258 	x = ntohl(repl->count);
    259 	if (rlen < x) {
    260 		printf("nfsread: short packet, %d < %d\n", rlen, x);
    261 		errno = EBADRPC;
    262 		return(-1);
    263 	}
    264 	bcopy(repl->data, addr, x);
    265 	return (x);
    266 }
    267 
    268 /*
    269  * nfs_mount - mount this nfs filesystem to a host
    270  */
    271 int
    272 nfs_mount(sock, ip, path)
    273 	int sock;
    274 	struct in_addr ip;
    275 	char *path;
    276 {
    277 	struct iodesc *desc;
    278 	struct nfsv2_fattrs *fa;
    279 
    280 	if (!(desc = socktodesc(sock))) {
    281 		errno = EINVAL;
    282 		return(-1);
    283 	}
    284 
    285 	/* Bind to a reserved port. */
    286 	desc->myport = htons(--rpc_port);
    287 	desc->destip = ip;
    288 	if (nfs_getrootfh(desc, path, nfs_root_node.fh))
    289 		return (-1);
    290 	nfs_root_node.iodesc = desc;
    291 	/* Fake up attributes for the root dir. */
    292 	fa = &nfs_root_node.fa;
    293 	fa->fa_type  = htonl(NFDIR);
    294 	fa->fa_mode  = htonl(0755);
    295 	fa->fa_nlink = htonl(2);
    296 
    297 #ifdef NFS_DEBUG
    298 	if (debug)
    299 		printf("nfs_mount: got fh for %s\n", path);
    300 #endif
    301 
    302 	return(0);
    303 }
    304 
    305 /*
    306  * Open a file.
    307  */
    308 int
    309 nfs_open(path, f)
    310 	char *path;
    311 	struct open_file *f;
    312 {
    313 	struct nfs_iodesc *newfd;
    314 	int rc = 0;
    315 
    316 #ifdef NFS_DEBUG
    317  	if (debug)
    318  	    printf("nfs_open: %s\n", path);
    319 #endif
    320 	if (nfs_root_node.iodesc == NULL) {
    321 		errno = EIO;
    322 		printf("nfs_open: must mount first.\n");
    323 		return(-1);
    324 	}
    325 
    326 	/* allocate file system specific data structure */
    327 	newfd = alloc(sizeof(*newfd));
    328 	newfd->iodesc = nfs_root_node.iodesc;
    329 	newfd->off = 0;
    330 
    331 	/* lookup a file handle */
    332 	rc = nfs_lookupfh(&nfs_root_node, path, newfd);
    333 	if (rc) {
    334 #ifdef NFS_DEBUG
    335 		if (debug)
    336 			printf("nfs_open: %s lookupfh failed: %s\n",
    337 				path, strerror(errno));
    338 #endif
    339 		free(newfd, sizeof(*newfd));
    340 		return(rc);
    341 	}
    342 	f->f_fsdata = (void *)newfd;
    343 
    344 #ifdef NFS_DEBUG
    345 	if (debug)
    346 		printf("nfs_open: \"%s\", type=%d size=%d\n", path,
    347 			   ntohl(newfd->fa.fa_type),
    348 			   ntohl(newfd->fa.fa_size));
    349 #endif
    350 
    351 	return(rc);
    352 }
    353 
    354 int
    355 nfs_close(f)
    356 	struct open_file *f;
    357 {
    358 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    359 
    360 #ifdef NFS_DEBUG
    361 	if (debug)
    362 		printf("nfs_close: fp=0x%x\n", fp);
    363 #endif
    364 
    365 	if (fp)
    366 		free(fp, sizeof(struct nfs_iodesc));
    367 	f->f_fsdata = (void *)0;
    368 
    369 	return (0);
    370 }
    371 
    372 /*
    373  * read a portion of a file
    374  */
    375 int
    376 nfs_read(f, buf, size, resid)
    377 	struct open_file *f;
    378 	void *buf;
    379 	size_t size;
    380 	size_t *resid;	/* out */
    381 {
    382 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    383 	register ssize_t cc;
    384 	register char *addr = buf;
    385 
    386 #ifdef NFS_DEBUG
    387 	if (debug)
    388 		printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
    389 #endif
    390 	while ((int)size > 0) {
    391 		twiddle();
    392 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
    393 		/* XXX maybe should retry on certain errors */
    394 		if (cc == -1) {
    395 #ifdef NFS_DEBUG
    396 			if (debug)
    397 				printf("nfs_read: read: %s", strerror(errno));
    398 #endif
    399 			return errno;
    400 		}
    401 		if (cc == 0) {
    402 			if (debug)
    403 				printf("nfs_read: hit EOF unexpectantly");
    404 			goto ret;
    405 		}
    406 		fp->off += cc;
    407 		addr += cc;
    408 		size -= cc;
    409 	}
    410 ret:
    411 	if (resid)
    412 		*resid = size;
    413 
    414 	return (0);
    415 }
    416 
    417 /*
    418  * Not implemented.
    419  */
    420 int
    421 nfs_write(f, buf, size, resid)
    422 	struct open_file *f;
    423 	void *buf;
    424 	size_t size;
    425 	size_t *resid;	/* out */
    426 {
    427 	return (EROFS);
    428 }
    429 
    430 off_t
    431 nfs_seek(f, offset, where)
    432 	struct open_file *f;
    433 	off_t offset;
    434 	int where;
    435 {
    436 	register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
    437 	n_long size = ntohl(d->fa.fa_size);
    438 
    439 	switch (where) {
    440 	case SEEK_SET:
    441 		d->off = offset;
    442 		break;
    443 	case SEEK_CUR:
    444 		d->off += offset;
    445 		break;
    446 	case SEEK_END:
    447 		d->off = size - offset;
    448 		break;
    449 	default:
    450 		return (-1);
    451 	}
    452 
    453 	return (d->off);
    454 }
    455 
    456 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
    457 int nfs_stat_types[8] = {
    458 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
    459 
    460 int
    461 nfs_stat(f, sb)
    462 	struct open_file *f;
    463 	struct stat *sb;
    464 {
    465 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    466 	register n_long ftype, mode;
    467 
    468 	ftype = ntohl(fp->fa.fa_type);
    469 	mode  = ntohl(fp->fa.fa_mode);
    470 	mode |= nfs_stat_types[ftype & 7];
    471 
    472 	sb->st_mode  = mode;
    473 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
    474 	sb->st_uid   = ntohl(fp->fa.fa_uid);
    475 	sb->st_gid   = ntohl(fp->fa.fa_gid);
    476 	sb->st_size  = ntohl(fp->fa.fa_size);
    477 
    478 	return (0);
    479 }
    480