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