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