Home | History | Annotate | Line # | Download | only in libsa
nfs.c revision 1.6
      1 /*	$NetBSD: nfs.c,v 1.6 1995/02/20 11:04:12 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 #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 struct nfs_call_data {
     51 	u_char	fh[NFS_FHSIZE];
     52 	u_long	off;
     53 	u_long	len;
     54 	u_long	xxx;			/* XXX what's this for? */
     55 };
     56 
     57 /* Data part of nfs rpc reply (also the largest thing we receive) */
     58 struct nfs_reply_data {
     59 	u_long	errno;
     60 	struct	nfsv2_fattr fa;
     61 	u_long	count;
     62 	u_char	data[1200];
     63 };
     64 #define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data)
     65 
     66 struct nfs_iodesc {
     67 	off_t	off;
     68 	size_t	size;
     69 	u_char	*fh;
     70 	struct	iodesc	*iodesc;
     71 };
     72 
     73 /* Fetch (mount) file handle */
     74 static int
     75 getmountfh(d, path, fhp)
     76 	register struct iodesc *d;
     77 	char *path;
     78 	u_char *fhp;
     79 {
     80 	register int len;
     81 	struct {
     82 		u_long	len;
     83 		char	path[FNAME_SIZE];
     84 	} wbuf;
     85 	struct {
     86 		u_long	errno;
     87 		u_char	fh[NFS_FHSIZE];
     88 	} rbuf;
     89 	size_t cc;
     90 
     91 #ifdef NFS_DEBUG
     92 	if (debug)
     93 		printf("getmountfh: called\n");
     94 #endif
     95 
     96 	bzero(&wbuf, sizeof(wbuf));
     97 	len = strlen(path);
     98 	if (len > sizeof(wbuf.path))
     99 		len = sizeof(wbuf.path);
    100 	bcopy(path, wbuf.path, len);
    101 	wbuf.len = htonl(len);
    102 	len = sizeof(wbuf) - sizeof(wbuf.path) + roundup(len, sizeof(long));
    103 
    104 	if ((cc = callrpc(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
    105 	    &wbuf, len, &rbuf, sizeof(rbuf))) == -1)
    106 		    return (-1);
    107 	if (cc < sizeof(rbuf.errno))
    108 		panic("getmountfh: callrpc small read");
    109 	if (rbuf.errno) {
    110 		errno = ntohl(rbuf.errno);
    111 		return (-1);
    112 	}
    113 	bcopy(rbuf.fh, fhp, sizeof(rbuf.fh));
    114 	return (0);
    115 }
    116 
    117 /* Fetch file timestamp and size */
    118 static int
    119 getnfsinfo(d, tp, sp, fp, mp, up, gp)
    120 	register struct nfs_iodesc *d;
    121 	register time_t *tp;
    122 	u_long *sp, *fp;
    123 	mode_t *mp;
    124 	uid_t *up;
    125 	gid_t *gp;
    126 {
    127 	register int rlen;
    128 	register u_long t;
    129 	struct {
    130 		u_long	errno;
    131 		struct	nfsv2_fattr fa;
    132 	} rbuf;
    133 	size_t cc;
    134 
    135 #ifdef NFS_DEBUG
    136  	if (debug)
    137  	    printf("getnfsinfo: called\n");
    138 #endif
    139 	rlen = sizeof(rbuf);
    140 #if NFSX_FATTR(1) > NFSX_FATTR(0)
    141 	/* nqnfs makes this more painful than it needs to be */
    142 	rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
    143 #endif
    144 	if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_GETATTR,
    145 	    d->fh, NFS_FHSIZE, &rbuf, rlen)) == -1)
    146 		return (-1);
    147 	if (cc < sizeof(rbuf.errno))
    148 		panic("getnfsinfo: callrpc small read");
    149 	if (rbuf.errno) {
    150 		errno = ntohl(rbuf.errno);
    151 		return (-1);
    152 	}
    153 	if (tp) {
    154 		*tp = ntohl(rbuf.fa.fa_nfsmtime.nfs_sec);
    155 		t = ntohl(rbuf.fa.fa_nfsatime.nfs_sec);
    156 		if (*tp < t)
    157 			*tp = t;
    158 	}
    159 	if (sp)
    160 		*sp = ntohl(rbuf.fa.fa_nfssize);
    161 	if (fp)
    162 		*fp = ntohl(rbuf.fa.fa_type);
    163 	if (mp)
    164 		*mp = ntohl(rbuf.fa.fa_mode);
    165 	if (up)
    166 		*up = ntohl(rbuf.fa.fa_uid);
    167 	if (gp)
    168 		*gp = ntohl(rbuf.fa.fa_gid);
    169 	return(0);
    170 }
    171 
    172 /* Lookup a file. Optionally return timestamp and size */
    173 static int
    174 lookupfh(d, name, fhp, tp, sp, fp)
    175 	struct nfs_iodesc *d;
    176 	char *name;
    177 	u_char *fhp;
    178 	time_t *tp;
    179 	u_long *sp, *fp;
    180 {
    181 	register int len, rlen;
    182 	struct {
    183 		u_char	fh[NFS_FHSIZE];
    184 		u_long	len;
    185 		char	name[FNAME_SIZE];
    186 	} wbuf;
    187 	struct {
    188 		u_long	errno;
    189 		u_char	fh[NFS_FHSIZE];
    190 		struct	nfsv2_fattr fa;
    191 	} rbuf;
    192 	size_t cc;
    193 
    194 #ifdef NFS_DEBUG
    195 	if (debug)
    196 		printf("lookupfh: called\n");
    197 #endif
    198 
    199 	bzero(&wbuf, sizeof(wbuf));
    200 	bcopy(d->fh, wbuf.fh, sizeof(wbuf.fh));
    201 	len = strlen(name);
    202 	if (len > sizeof(wbuf.name))
    203 		len = sizeof(wbuf.name);
    204 	bcopy(name, wbuf.name, len);
    205 	wbuf.len = htonl(len);
    206 	len = sizeof(wbuf) - sizeof(wbuf.name) + roundup(len, sizeof(long));
    207 
    208 	rlen = sizeof(rbuf);
    209 #ifdef NFSX_FATTR
    210 #if NFSX_FATTR(1) > NFSX_FATTR(0)
    211 	/* nqnfs makes this more painful than it needs to be */
    212 	rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
    213 #endif
    214 #endif
    215 
    216 	if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
    217 	    &wbuf, len, &rbuf, rlen)) == -1)
    218 		return (-1);
    219 	if (cc < sizeof(rbuf.errno))
    220 		panic("lookupfh: callrpc small read");
    221 	if (rbuf.errno) {
    222 		errno = ntohl(rbuf.errno);
    223 		return (-1);
    224 	}
    225 	bcopy(rbuf.fh, fhp, sizeof(rbuf.fh));
    226 	if (tp)
    227 		*tp = ntohl(rbuf.fa.fa_nfsctime.nfs_sec);
    228 	if (sp)
    229 		*sp = ntohl(rbuf.fa.fa_nfssize);
    230 	if (fp)
    231 		*fp = ntohl(rbuf.fa.fa_type);
    232 	return (0);
    233 }
    234 
    235 /* Read data from a file */
    236 static size_t
    237 readdata(d, off, addr, len)
    238 	register struct nfs_iodesc *d;
    239 	register off_t off;
    240 	register void *addr;
    241 	register size_t len;
    242 {
    243 	size_t cc;
    244 	struct nfs_call_data wbuf;
    245 	struct nfs_reply_data rbuf;
    246 
    247 	bcopy(d->fh, wbuf.fh, NFS_FHSIZE);
    248 	wbuf.off = txdr_unsigned(off);
    249 	if (len > NFSREAD_SIZE)
    250 		len = NFSREAD_SIZE;
    251 	wbuf.len = txdr_unsigned(len);
    252 	wbuf.xxx = txdr_unsigned(0);
    253 
    254 	cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
    255 	    &wbuf, sizeof(wbuf),
    256 	    &rbuf, sizeof(rbuf) - NFSREAD_SIZE + len);
    257 	if (cc == -1 || cc < sizeof(rbuf) - NFSREAD_SIZE)
    258 		return (-1);
    259 
    260 	cc -= sizeof(rbuf) - NFSREAD_SIZE;
    261 	bcopy(rbuf.data, addr, cc);
    262 	return (cc);
    263 }
    264 
    265 static struct iodesc *mountfs;
    266 static u_char mountfh[NFS_FHSIZE];
    267 static time_t mounttime;
    268 
    269 /*
    270  * nfs_mount - mount this nfs filesystem to a host
    271  */
    272 int
    273 nfs_mount(sock, ip, path)
    274 	int sock;
    275 	n_long ip;
    276 	char *path;
    277 {
    278 	struct iodesc *desc;
    279 	struct nfs_iodesc *fp;
    280 	u_long ftype;
    281 
    282 	if (!(desc = socktodesc(sock))) {
    283 		errno = EINVAL;
    284 		return(-1);
    285 	}
    286 	bcopy(&desc->myea[4], &desc->myport, 2);
    287 	desc->destip = ip;
    288 	getmountfh(desc, path, mountfh);
    289 
    290 	fp = alloc(sizeof(struct nfs_iodesc));
    291 	fp->iodesc = desc;
    292 	fp->fh = mountfh;
    293 	fp->off = 0;
    294 	if (getnfsinfo(fp, &mounttime, NULL, &ftype, NULL, NULL, NULL) < 0) {
    295 		free(fp, sizeof(struct nfs_iodesc));
    296 		return(-1);
    297 	}
    298 
    299 	if (ftype != NFDIR) {
    300 		free(fp, sizeof(struct nfs_iodesc));
    301 	    	errno = EINVAL;
    302 		printf("nfs_mount: bad mount ftype %d", ftype);
    303 		return(-1);
    304 	}
    305 #ifdef NFS_DEBUG
    306 	if (debug)
    307 		printf("nfs_mount: got fh for %s, mtime=%d, ftype=%d\n",
    308 			path, mounttime, ftype);
    309 #endif
    310 	mountfs = desc;
    311 	free(fp, sizeof(struct nfs_iodesc));
    312 
    313 	return(0);
    314 }
    315 
    316 /*
    317  * Open a file.
    318  */
    319 int
    320 nfs_open(path, f)
    321 	char *path;
    322 	struct open_file *f;
    323 {
    324 	register struct nfs_iodesc *fp;
    325 	u_char *imagefh;
    326 	u_long size, ftype;
    327 	int rc = 0;
    328 
    329 #ifdef NFS_DEBUG
    330  	if (debug)
    331  	    printf("nfs_open: %s\n", path);
    332 #endif
    333 	if (!mountfs) {
    334 		errno = EIO;
    335 		printf("nfs_open: must mount first.\n");
    336 		return(-1);
    337 	}
    338 
    339 	/* allocate file system specific data structure */
    340 	fp = alloc(sizeof(struct nfs_iodesc));
    341 	fp->iodesc = mountfs;
    342 	fp->fh = mountfh;
    343 	fp->off = 0;
    344 
    345 	f->f_fsdata = (void *)fp;
    346 	imagefh = alloc(NFS_FHSIZE);
    347 	bzero(imagefh, NFS_FHSIZE);
    348 
    349 	/* lookup a file handle */
    350 	rc = lookupfh(fp, path, imagefh, NULL, &size, &ftype);
    351 	if (rc < 0) {
    352 #ifdef NFS_DEBUG
    353 		if (debug)
    354 			printf("nfs_open: %s lookupfh failed: %s\n", path, strerror(errno));
    355 #endif
    356 		f->f_fsdata = (void *)0;
    357 		free(fp, sizeof(struct nfs_iodesc));
    358 		free(imagefh, NFS_FHSIZE);
    359 		return(rc);
    360 	}
    361 	fp->fh = imagefh;
    362 
    363 #ifdef NFS_DEBUG
    364 	if (debug)
    365 		printf("nfs_open: %s success, size=%d ftype=%d\n",
    366 			path, size, ftype);
    367 #endif
    368 	fp->size = size;
    369 
    370 	return(rc);
    371 }
    372 
    373 int
    374 nfs_close(f)
    375 	struct open_file *f;
    376 {
    377 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    378 
    379 #ifdef NFS_DEBUG
    380 	if (debug)
    381 		printf("nfs_close: called\n");
    382 #endif
    383 	f->f_fsdata = (void *)0;
    384 	if (fp == (struct nfs_iodesc *)0)
    385 		return (0);
    386 
    387 	free(fp->fh, NFS_FHSIZE);
    388 	free(fp, sizeof(struct nfs_iodesc));
    389 
    390 	return (0);
    391 }
    392 
    393 /*
    394  * read a portion of a file
    395  */
    396 int
    397 nfs_read(f, addr, size, resid)
    398 	struct open_file *f;
    399 	char *addr;
    400 	u_int size;
    401 	u_int *resid;	/* out */
    402 {
    403 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    404 	register size_t cc;
    405 
    406 #ifdef NFS_DEBUG
    407 	if (debug)
    408 		printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
    409 #endif
    410 	while (size > 0) {
    411 		cc = readdata(fp->iodesc, fp->off, (void *)addr, size);
    412 		/* XXX maybe should retry on certain errors */
    413 		if (cc == -1) {
    414 #ifdef NFS_DEBUG
    415 			if (debug)
    416 				printf("nfs_read: read: %s", strerror(errno));
    417 #endif
    418 			return (-1);
    419 		}
    420 		if (cc == 0) {
    421 			if (debug)
    422 				printf("nfs_read: hit EOF unexpectantly");
    423 			goto ret;
    424 		}
    425 		fp->off += cc;
    426 		addr += cc;
    427 		size -= cc;
    428 	}
    429 ret:
    430 	if (resid)
    431 		*resid = size;
    432 
    433 	return (0);
    434 }
    435 
    436 /*
    437  * Not implemented.
    438  */
    439 int
    440 nfs_write(f, start, size, resid)
    441 	struct open_file *f;
    442 	char *start;
    443 	u_int size;
    444 	u_int *resid;	/* out */
    445 {
    446 	errno = EROFS;
    447 
    448 	return (-1);
    449 }
    450 
    451 off_t
    452 nfs_seek(f, offset, where)
    453 	struct open_file *f;
    454 	off_t offset;
    455 	int where;
    456 {
    457 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    458 
    459 	switch (where) {
    460 	case SEEK_SET:
    461 		fp->off = offset;
    462 		break;
    463 	case SEEK_CUR:
    464 		fp->off += offset;
    465 		break;
    466 	case SEEK_END:
    467 		fp->off = fp->size - offset;
    468 		break;
    469 	default:
    470 		return (-1);
    471 	}
    472 	return (fp->off);
    473 }
    474 
    475 int
    476 nfs_stat(f, sb)
    477 	struct open_file *f;
    478 	struct stat *sb;
    479 {
    480 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    481 	mode_t mode = 0;
    482 	u_long ftype = 0;
    483 
    484 #ifdef NFS_DEBUG
    485  	if (debug)
    486 		printf("nfs_stat: called\n");
    487 #endif
    488 
    489 	if (getnfsinfo(fp, &mounttime, &sb->st_size, &ftype, &mode, &sb->st_uid, &sb->st_gid) < 0)
    490 		return(-1);
    491 
    492 	/* create a mode */
    493 	switch (ftype) {
    494 	case NFNON:
    495 		sb->st_mode = 0;
    496 		break;
    497 	case NFREG:
    498 		sb->st_mode = S_IFREG;
    499 		break;
    500 	case NFDIR:
    501 		sb->st_mode = S_IFDIR;
    502 		break;
    503 	case NFBLK:
    504 		sb->st_mode = S_IFBLK;
    505 		break;
    506 	case NFCHR:
    507 		sb->st_mode = S_IFCHR;
    508 		break;
    509 	case NFLNK:
    510 		sb->st_mode = S_IFLNK;
    511 		break;
    512 	}
    513 	sb->st_mode |= mode;
    514 
    515 	return (0);
    516 }
    517