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