xref: /netbsd/sys/arch/i386/stand/libsa/nfs.c (revision bf9ec67e)
1 /*	$NetBSD: nfs.c,v 1.3 2001/07/07 22:57:58 perry 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 #ifdef _STANDALONE
36 #include <lib/libkern/libkern.h>
37 #else
38 #include <string.h>
39 #endif
40 
41 #include <netinet/in.h>
42 #include <netinet/in_systm.h>
43 
44 #include "rpcv2.h"
45 #include "nfsv2.h"
46 
47 #include "stand.h"
48 #include "net.h"
49 #include "netif.h"
50 #include "nfs.h"
51 #include "rpc.h"
52 
53 /* Define our own NFS attributes without NQNFS stuff. */
54 struct nfsv2_fattrs {
55 	n_long	fa_type;
56 	n_long	fa_mode;
57 	n_long	fa_nlink;
58 	n_long	fa_uid;
59 	n_long	fa_gid;
60 	n_long	fa_size;
61 	n_long	fa_blocksize;
62 	n_long	fa_rdev;
63 	n_long	fa_blocks;
64 	n_long	fa_fsid;
65 	n_long	fa_fileid;
66 	struct nfsv2_time fa_atime;
67 	struct nfsv2_time fa_mtime;
68 	struct nfsv2_time fa_ctime;
69 };
70 
71 
72 struct nfs_read_args {
73 	u_char	fh[NFS_FHSIZE];
74 	n_long	off;
75 	n_long	len;
76 	n_long	xxx;			/* XXX what's this for? */
77 };
78 
79 /* Data part of nfs rpc reply (also the largest thing we receive) */
80 #define NFSREAD_SIZE 1024
81 struct nfs_read_repl {
82 	n_long	errno;
83 	struct	nfsv2_fattrs fa;
84 	n_long	count;
85 	u_char	data[NFSREAD_SIZE];
86 };
87 
88 #ifndef NFS_NOSYMLINK
89 struct nfs_readlnk_repl {
90 	n_long	errno;
91 	n_long	len;
92 	char	path[NFS_MAXPATHLEN];
93 };
94 #endif
95 
96 struct nfs_iodesc {
97 	struct	iodesc	*iodesc;
98 	off_t	off;
99 	u_char	fh[NFS_FHSIZE];
100 	struct nfsv2_fattrs fa;	/* all in network order */
101 };
102 
103 
104 /*
105  * Fetch the root file handle (call mount daemon)
106  * Return zero or error number.
107  */
108 int
109 nfs_getrootfh(d, path, fhp)
110 	register struct iodesc *d;
111 	char *path;
112 	u_char *fhp;
113 {
114 	register int len;
115 	struct args {
116 		n_long	len;
117 		char	path[FNAME_SIZE];
118 	} *args;
119 	struct repl {
120 		n_long	errno;
121 		u_char	fh[NFS_FHSIZE];
122 	} *repl;
123 	struct {
124 		n_long	h[RPC_HEADER_WORDS];
125 		struct args d;
126 	} sdata;
127 	struct {
128 		n_long	h[RPC_HEADER_WORDS];
129 		struct repl d;
130 	} rdata;
131 	size_t cc;
132 
133 #ifdef NFS_DEBUG
134 	if (debug)
135 		printf("nfs_getrootfh: %s\n", path);
136 #endif
137 
138 	args = &sdata.d;
139 	repl = &rdata.d;
140 
141 	memset(args, 0, sizeof(*args));
142 	len = strlen(path);
143 	if (len > sizeof(args->path))
144 		len = sizeof(args->path);
145 	args->len = htonl(len);
146 	memcpy(args->path, path, len);
147 	len = 4 + roundup(len, 4);
148 
149 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
150 	    args, len, repl, sizeof(*repl));
151 	if (cc == -1) {
152 		/* errno was set by rpc_call */
153 		return (errno);
154 	}
155 	if (cc < 4)
156 		return (EBADRPC);
157 	if (repl->errno)
158 		return (ntohl(repl->errno));
159 	memcpy(fhp, repl->fh, sizeof(repl->fh));
160 	return (0);
161 }
162 
163 /*
164  * Lookup a file.  Store handle and attributes.
165  * Return zero or error number.
166  */
167 int
168 nfs_lookupfh(d, name, newfd)
169 	struct nfs_iodesc *d;
170 	char *name;
171 	struct nfs_iodesc *newfd;
172 {
173 	register int len, rlen;
174 	struct args {
175 		u_char	fh[NFS_FHSIZE];
176 		n_long	len;
177 		char	name[FNAME_SIZE];
178 	} *args;
179 	struct repl {
180 		n_long	errno;
181 		u_char	fh[NFS_FHSIZE];
182 		struct	nfsv2_fattrs fa;
183 	} *repl;
184 	struct {
185 		n_long	h[RPC_HEADER_WORDS];
186 		struct args d;
187 	} sdata;
188 	struct {
189 		n_long	h[RPC_HEADER_WORDS];
190 		struct repl d;
191 	} rdata;
192 	ssize_t cc;
193 
194 #ifdef NFS_DEBUG
195 	if (debug)
196 		printf("lookupfh: called\n");
197 #endif
198 
199 	args = &sdata.d;
200 	repl = &rdata.d;
201 
202 	memset(args, 0, sizeof(*args));
203 	memcpy(args->fh, d->fh, sizeof(args->fh));
204 	len = strlen(name);
205 	if (len > sizeof(args->name))
206 		len = sizeof(args->name);
207 	memcpy(args->name, name, len);
208 	args->len = htonl(len);
209 	len = 4 + roundup(len, 4);
210 	len += NFS_FHSIZE;
211 
212 	rlen = sizeof(*repl);
213 
214 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
215 	    args, len, repl, rlen);
216 	if (cc == -1)
217 		return (errno);		/* XXX - from rpc_call */
218 	if (cc < 4)
219 		return (EIO);
220 	if (repl->errno) {
221 		/* saerrno.h now matches NFS error numbers. */
222 		return (ntohl(repl->errno));
223 	}
224 	memcpy(&newfd->fh, repl->fh, sizeof(newfd->fh));
225 	memcpy(&newfd->fa, &repl->fa, sizeof(newfd->fa));
226 	return (0);
227 }
228 
229 #ifndef NFS_NOSYMLINK
230 /*
231  * Get the destination of a symbolic link.
232  */
233 int
234 nfs_readlink(d, buf)
235 	struct nfs_iodesc *d;
236 	char *buf;
237 {
238 	struct {
239 		n_long	h[RPC_HEADER_WORDS];
240 		u_char fh[NFS_FHSIZE];
241 	} sdata;
242 	struct {
243 		n_long	h[RPC_HEADER_WORDS];
244 		struct nfs_readlnk_repl d;
245 	} rdata;
246 	ssize_t cc;
247 
248 #ifdef NFS_DEBUG
249 	if (debug)
250 		printf("readlink: called\n");
251 #endif
252 
253 	memcpy(sdata.fh, d->fh, NFS_FHSIZE);
254 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
255 		      sdata.fh, NFS_FHSIZE,
256 		      &rdata.d, sizeof(rdata.d));
257 	if (cc == -1)
258 		return (errno);
259 
260 	if (cc < 4)
261 		return (EIO);
262 
263 	if (rdata.d.errno)
264 		return (ntohl(rdata.d.errno));
265 
266 	rdata.d.len = ntohl(rdata.d.len);
267 	if (rdata.d.len > NFS_MAXPATHLEN)
268 		return (ENAMETOOLONG);
269 
270 	memcpy(buf, rdata.d.path, rdata.d.len);
271 	buf[rdata.d.len] = 0;
272 	return (0);
273 }
274 #endif
275 
276 /*
277  * Read data from a file.
278  * Return transfer count or -1 (and set errno)
279  */
280 ssize_t
281 nfs_readdata(d, off, addr, len)
282 	struct nfs_iodesc *d;
283 	off_t off;
284 	void *addr;
285 	size_t len;
286 {
287 	struct nfs_read_args *args;
288 	struct nfs_read_repl *repl;
289 	struct {
290 		n_long	h[RPC_HEADER_WORDS];
291 		struct nfs_read_args d;
292 	} sdata;
293 	struct {
294 		n_long	h[RPC_HEADER_WORDS];
295 		struct nfs_read_repl d;
296 	} rdata;
297 	size_t cc;
298 	long x;
299 	int hlen, rlen;
300 
301 	args = &sdata.d;
302 	repl = &rdata.d;
303 
304 	memcpy(args->fh, d->fh, NFS_FHSIZE);
305 	args->off = htonl((n_long)off);
306 	if (len > NFSREAD_SIZE)
307 		len = NFSREAD_SIZE;
308 	args->len = htonl((n_long)len);
309 	args->xxx = htonl((n_long)0);
310 	hlen = sizeof(*repl) - NFSREAD_SIZE;
311 
312 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
313 	    args, sizeof(*args),
314 	    repl, sizeof(*repl));
315 	if (cc == -1) {
316 		/* errno was already set by rpc_call */
317 		return (-1);
318 	}
319 	if (cc < hlen) {
320 		errno = EBADRPC;
321 		return (-1);
322 	}
323 	if (repl->errno) {
324 		errno = ntohl(repl->errno);
325 		return (-1);
326 	}
327 	rlen = cc - hlen;
328 	x = ntohl(repl->count);
329 	if (rlen < x) {
330 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
331 		errno = EBADRPC;
332 		return(-1);
333 	}
334 	memcpy(addr, repl->data, x);
335 	return (x);
336 }
337 
338 /*
339  * Open a file.
340  * return zero or error number
341  */
342 int
343 nfs_open(path, f)
344 	char *path;
345 	struct open_file *f;
346 {
347 	static struct nfs_iodesc nfs_root_node;
348 	struct iodesc *desc;
349 	struct nfs_iodesc *currfd;
350 #ifndef NFS_NOSYMLINK
351 	struct nfs_iodesc *newfd;
352 	struct nfsv2_fattrs *fa;
353 	register char *cp, *ncp;
354 	register int c;
355 	char namebuf[NFS_MAXPATHLEN + 1];
356 	char linkbuf[NFS_MAXPATHLEN + 1];
357 	int nlinks = 0;
358 #endif
359 	int error;
360 
361 #ifdef NFS_DEBUG
362  	if (debug)
363  	    printf("nfs_open: %s\n", path);
364 #endif
365 	if (!rootpath[0]) {
366 		printf("no rootpath, no nfs\n");
367 		return (ENXIO);
368 	}
369 
370 	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
371 		return(EINVAL);
372 
373 	/* Bind to a reserved port. */
374 	desc->myport = htons(--rpc_port);
375 	desc->destip = rootip;
376 	if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
377 		return (error);
378 	nfs_root_node.iodesc = desc;
379 
380 #ifndef NFS_NOSYMLINK
381 	/* Fake up attributes for the root dir. */
382 	fa = &nfs_root_node.fa;
383 	fa->fa_type  = htonl(NFDIR);
384 	fa->fa_mode  = htonl(0755);
385 	fa->fa_nlink = htonl(2);
386 
387 	currfd = &nfs_root_node;
388 	newfd = 0;
389 
390 	cp = path;
391 	while (*cp) {
392 		/*
393 		 * Remove extra separators
394 		 */
395 		while (*cp == '/')
396 			cp++;
397 
398 		if (*cp == '\0')
399 			break;
400 		/*
401 		 * Check that current node is a directory.
402 		 */
403 		if (currfd->fa.fa_type != htonl(NFDIR)) {
404 			error = ENOTDIR;
405 			goto out;
406 		}
407 
408 		/* allocate file system specific data structure */
409 		newfd = alloc(sizeof(*newfd));
410 		newfd->iodesc = currfd->iodesc;
411 		newfd->off = 0;
412 
413 		/*
414 		 * Get next component of path name.
415 		 */
416 		{
417 			register int len = 0;
418 
419 			ncp = cp;
420 			while ((c = *cp) != '\0' && c != '/') {
421 				if (++len > NFS_MAXNAMLEN) {
422 					error = ENOENT;
423 					goto out;
424 				}
425 				cp++;
426 			}
427 			*cp = '\0';
428 		}
429 
430 		/* lookup a file handle */
431 		error = nfs_lookupfh(currfd, ncp, newfd);
432 		*cp = c;
433 		if (error)
434 			goto out;
435 
436 		/*
437 		 * Check for symbolic link
438 		 */
439 		if (newfd->fa.fa_type == htonl(NFLNK)) {
440 			int link_len, len;
441 
442 			error = nfs_readlink(newfd, linkbuf);
443 			if (error)
444 				goto out;
445 
446 			link_len = strlen(linkbuf);
447 			len = strlen(cp);
448 
449 			if (link_len + len > MAXPATHLEN
450 			    || ++nlinks > MAXSYMLINKS) {
451 				error = ENOENT;
452 				goto out;
453 			}
454 
455 			memcpy(&namebuf[link_len], cp, len + 1);
456 			memcpy(namebuf, linkbuf, link_len);
457 
458 			/*
459 			 * If absolute pathname, restart at root.
460 			 * If relative pathname, restart at parent directory.
461 			 */
462 			cp = namebuf;
463 			if (*cp == '/') {
464 				if (currfd != &nfs_root_node)
465 					free(currfd, sizeof(*currfd));
466 				currfd = &nfs_root_node;
467 			}
468 
469 			free(newfd, sizeof(*newfd));
470 			newfd = 0;
471 
472 			continue;
473 		}
474 
475 		if (currfd != &nfs_root_node)
476 			free(currfd, sizeof(*currfd));
477 		currfd = newfd;
478 		newfd = 0;
479 	}
480 
481 	error = 0;
482 
483 out:
484 	if (newfd)
485 		free(newfd, sizeof(*newfd));
486 #else
487         /* allocate file system specific data structure */
488         currfd = alloc(sizeof(*currfd));
489         currfd->iodesc = desc;
490         currfd->off = 0;
491 
492         error = nfs_lookupfh(&nfs_root_node, path, currfd);
493 #endif
494 	if (!error) {
495 		f->f_fsdata = (void *)currfd;
496 		return (0);
497 	}
498 
499 #ifdef NFS_DEBUG
500 	if (debug)
501 		printf("nfs_open: %s lookupfh failed: %s\n",
502 		    path, strerror(error));
503 #endif
504 #ifndef NFS_NOSYMLINK
505 	if (currfd != &nfs_root_node)
506 #endif
507 		free(currfd, sizeof(*currfd));
508 
509 	return (error);
510 }
511 
512 int
513 nfs_close(f)
514 	struct open_file *f;
515 {
516 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
517 
518 #ifdef NFS_DEBUG
519 	if (debug)
520 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
521 #endif
522 
523 	if (fp)
524 		free(fp, sizeof(struct nfs_iodesc));
525 	f->f_fsdata = (void *)0;
526 
527 	return (0);
528 }
529 
530 /*
531  * read a portion of a file
532  */
533 int
534 nfs_read(f, buf, size, resid)
535 	struct open_file *f;
536 	void *buf;
537 	size_t size;
538 	size_t *resid;	/* out */
539 {
540 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
541 	register ssize_t cc;
542 	register char *addr = buf;
543 
544 #ifdef NFS_DEBUG
545 	if (debug)
546 		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
547 		       (int)fp->off);
548 #endif
549 	while ((int)size > 0) {
550 		twiddle();
551 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
552 		/* XXX maybe should retry on certain errors */
553 		if (cc == -1) {
554 #ifdef NFS_DEBUG
555 			if (debug)
556 				printf("nfs_read: read: %s", strerror(errno));
557 #endif
558 			return (errno);	/* XXX - from nfs_readdata */
559 		}
560 		if (cc == 0) {
561 #ifdef NFS_DEBUG
562 			if (debug)
563 				printf("nfs_read: hit EOF unexpectantly");
564 #endif
565 			goto ret;
566 		}
567 		fp->off += cc;
568 		addr += cc;
569 		size -= cc;
570 	}
571 ret:
572 	if (resid)
573 		*resid = size;
574 
575 	return (0);
576 }
577 
578 /*
579  * Not implemented.
580  */
581 int
582 nfs_write(f, buf, size, resid)
583 	struct open_file *f;
584 	void *buf;
585 	size_t size;
586 	size_t *resid;	/* out */
587 {
588 	return (EROFS);
589 }
590 
591 off_t
592 nfs_seek(f, offset, where)
593 	struct open_file *f;
594 	off_t offset;
595 	int where;
596 {
597 	register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
598 	n_long size = ntohl(d->fa.fa_size);
599 
600 	switch (where) {
601 	case SEEK_SET:
602 		d->off = offset;
603 		break;
604 	case SEEK_CUR:
605 		d->off += offset;
606 		break;
607 	case SEEK_END:
608 		d->off = size - offset;
609 		break;
610 	default:
611 		return (-1);
612 	}
613 
614 	return (d->off);
615 }
616 
617 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
618 int nfs_stat_types[8] = {
619 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
620 
621 int
622 nfs_stat(f, sb)
623 	struct open_file *f;
624 	struct stat *sb;
625 {
626 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
627 	register n_long ftype, mode;
628 
629 	ftype = ntohl(fp->fa.fa_type);
630 	mode  = ntohl(fp->fa.fa_mode);
631 	mode |= nfs_stat_types[ftype & 7];
632 
633 	sb->st_mode  = mode;
634 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
635 	sb->st_uid   = ntohl(fp->fa.fa_uid);
636 	sb->st_gid   = ntohl(fp->fa.fa_gid);
637 	sb->st_size  = ntohl(fp->fa.fa_size);
638 
639 	return (0);
640 }
641