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