xref: /netbsd-src/sys/lib/libsa/nfs.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
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