xref: /netbsd-src/sys/lib/libsa/nfs.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*	$NetBSD: nfs.c,v 1.19 1996/10/13 02:29:04 christos 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_readlnk_repl {
85 	n_long	errno;
86 	n_long	len;
87 	char	path[NFS_MAXPATHLEN];
88 };
89 
90 struct nfs_iodesc {
91 	struct	iodesc	*iodesc;
92 	off_t	off;
93 	u_char	fh[NFS_FHSIZE];
94 	struct nfsv2_fattrs fa;	/* all in network order */
95 };
96 
97 struct nfs_iodesc nfs_root_node;
98 
99 
100 /*
101  * Fetch the root file handle (call mount daemon)
102  * On error, return non-zero and set errno.
103  */
104 int
105 nfs_getrootfh(d, path, fhp)
106 	register struct iodesc *d;
107 	char *path;
108 	u_char *fhp;
109 {
110 	register int len;
111 	struct args {
112 		n_long	len;
113 		char	path[FNAME_SIZE];
114 	} *args;
115 	struct repl {
116 		n_long	errno;
117 		u_char	fh[NFS_FHSIZE];
118 	} *repl;
119 	struct {
120 		n_long	h[RPC_HEADER_WORDS];
121 		struct args d;
122 	} sdata;
123 	struct {
124 		n_long	h[RPC_HEADER_WORDS];
125 		struct repl d;
126 	} rdata;
127 	size_t cc;
128 
129 #ifdef NFS_DEBUG
130 	if (debug)
131 		printf("nfs_getrootfh: %s\n", path);
132 #endif
133 
134 	args = &sdata.d;
135 	repl = &rdata.d;
136 
137 	bzero(args, sizeof(*args));
138 	len = strlen(path);
139 	if (len > sizeof(args->path))
140 		len = sizeof(args->path);
141 	args->len = htonl(len);
142 	bcopy(path, args->path, len);
143 	len = 4 + roundup(len, 4);
144 
145 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
146 	    args, len, repl, sizeof(*repl));
147 	if (cc == -1) {
148 		/* errno was set by rpc_call */
149 		return (-1);
150 	}
151 	if (cc < 4) {
152 		errno = EBADRPC;
153 		return (-1);
154 	}
155 	if (repl->errno) {
156 		errno = ntohl(repl->errno);
157 		return (-1);
158 	}
159 	bcopy(repl->fh, fhp, 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 	bzero(args, sizeof(*args));
203 	bcopy(d->fh, args->fh, sizeof(args->fh));
204 	len = strlen(name);
205 	if (len > sizeof(args->name))
206 		len = sizeof(args->name);
207 	bcopy(name, args->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 	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
225 	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
226 	return (0);
227 }
228 
229 /*
230  * Get the destination of a symbolic link.
231  */
232 int
233 nfs_readlink(d, buf)
234 	struct nfs_iodesc *d;
235 	char *buf;
236 {
237 	struct {
238 		n_long	h[RPC_HEADER_WORDS];
239 		u_char fh[NFS_FHSIZE];
240 	} sdata;
241 	struct {
242 		n_long	h[RPC_HEADER_WORDS];
243 		struct nfs_readlnk_repl d;
244 	} rdata;
245 	ssize_t cc;
246 
247 #ifdef NFS_DEBUG
248 	if (debug)
249 		printf("readlink: called\n");
250 #endif
251 
252 	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
253 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
254 		      sdata.fh, NFS_FHSIZE,
255 		      &rdata.d, sizeof(rdata.d));
256 	if (cc == -1)
257 		return (errno);
258 
259 	if (cc < 4)
260 		return (EIO);
261 
262 	if (rdata.d.errno)
263 		return (ntohl(rdata.d.errno));
264 
265 	rdata.d.len = ntohl(rdata.d.len);
266 	if (rdata.d.len > NFS_MAXPATHLEN)
267 		return (ENAMETOOLONG);
268 
269 	bcopy(rdata.d.path, buf, rdata.d.len);
270 	buf[rdata.d.len] = 0;
271 	return (0);
272 }
273 
274 /*
275  * Read data from a file.
276  * Return transfer count or -1 (and set errno)
277  */
278 ssize_t
279 nfs_readdata(d, off, addr, len)
280 	struct nfs_iodesc *d;
281 	off_t off;
282 	void *addr;
283 	size_t len;
284 {
285 	struct nfs_read_args *args;
286 	struct nfs_read_repl *repl;
287 	struct {
288 		n_long	h[RPC_HEADER_WORDS];
289 		struct nfs_read_args d;
290 	} sdata;
291 	struct {
292 		n_long	h[RPC_HEADER_WORDS];
293 		struct nfs_read_repl d;
294 	} rdata;
295 	size_t cc;
296 	long x;
297 	int hlen, rlen;
298 
299 	args = &sdata.d;
300 	repl = &rdata.d;
301 
302 	bcopy(d->fh, args->fh, NFS_FHSIZE);
303 	args->off = htonl((n_long)off);
304 	if (len > NFSREAD_SIZE)
305 		len = NFSREAD_SIZE;
306 	args->len = htonl((n_long)len);
307 	args->xxx = htonl((n_long)0);
308 	hlen = sizeof(*repl) - NFSREAD_SIZE;
309 
310 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
311 	    args, sizeof(*args),
312 	    repl, sizeof(*repl));
313 	if (cc == -1) {
314 		/* errno was already set by rpc_call */
315 		return (-1);
316 	}
317 	if (cc < hlen) {
318 		errno = EBADRPC;
319 		return (-1);
320 	}
321 	if (repl->errno) {
322 		errno = ntohl(repl->errno);
323 		return (-1);
324 	}
325 	rlen = cc - hlen;
326 	x = ntohl(repl->count);
327 	if (rlen < x) {
328 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
329 		errno = EBADRPC;
330 		return(-1);
331 	}
332 	bcopy(repl->data, addr, x);
333 	return (x);
334 }
335 
336 /*
337  * nfs_mount - mount this nfs filesystem to a host
338  * On error, return non-zero and set errno.
339  */
340 int
341 nfs_mount(sock, ip, path)
342 	int sock;
343 	struct in_addr ip;
344 	char *path;
345 {
346 	struct iodesc *desc;
347 	struct nfsv2_fattrs *fa;
348 
349 	if (!(desc = socktodesc(sock))) {
350 		errno = EINVAL;
351 		return(-1);
352 	}
353 
354 	/* Bind to a reserved port. */
355 	desc->myport = htons(--rpc_port);
356 	desc->destip = ip;
357 	if (nfs_getrootfh(desc, path, nfs_root_node.fh))
358 		return (-1);
359 	nfs_root_node.iodesc = desc;
360 	/* Fake up attributes for the root dir. */
361 	fa = &nfs_root_node.fa;
362 	fa->fa_type  = htonl(NFDIR);
363 	fa->fa_mode  = htonl(0755);
364 	fa->fa_nlink = htonl(2);
365 
366 #ifdef NFS_DEBUG
367 	if (debug)
368 		printf("nfs_mount: got fh for %s\n", path);
369 #endif
370 
371 	return(0);
372 }
373 
374 /*
375  * Open a file.
376  * return zero or error number
377  */
378 int
379 nfs_open(path, f)
380 	char *path;
381 	struct open_file *f;
382 {
383 	struct nfs_iodesc *newfd, *currfd;
384 	register char *cp, *ncp;
385 	register int c;
386 	char namebuf[NFS_MAXPATHLEN + 1];
387 	char linkbuf[NFS_MAXPATHLEN + 1];
388 	int nlinks = 0;
389 	int error = 0;
390 
391 #ifdef NFS_DEBUG
392  	if (debug)
393  	    printf("nfs_open: %s\n", path);
394 #endif
395 	if (nfs_root_node.iodesc == NULL) {
396 		printf("nfs_open: must mount first.\n");
397 		return (ENXIO);
398 	}
399 
400 	currfd = &nfs_root_node;
401 	newfd = 0;
402 
403 	cp = path;
404 	while (*cp) {
405 		/*
406 		 * Remove extra separators
407 		 */
408 		while (*cp == '/')
409 			cp++;
410 
411 		if (*cp == '\0')
412 			break;
413 		/*
414 		 * Check that current node is a directory.
415 		 */
416 		if (currfd->fa.fa_type != htonl(NFDIR)) {
417 			error = ENOTDIR;
418 			goto out;
419 		}
420 
421 		/* allocate file system specific data structure */
422 		newfd = alloc(sizeof(*newfd));
423 		newfd->iodesc = currfd->iodesc;
424 		newfd->off = 0;
425 
426 		/*
427 		 * Get next component of path name.
428 		 */
429 		{
430 			register int len = 0;
431 
432 			ncp = cp;
433 			while ((c = *cp) != '\0' && c != '/') {
434 				if (++len > NFS_MAXNAMLEN) {
435 					error = ENOENT;
436 					goto out;
437 				}
438 				cp++;
439 			}
440 			*cp = '\0';
441 		}
442 
443 		/* lookup a file handle */
444 		error = nfs_lookupfh(currfd, ncp, newfd);
445 		*cp = c;
446 		if (error)
447 			goto out;
448 
449 		/*
450 		 * Check for symbolic link
451 		 */
452 		if (newfd->fa.fa_type == htonl(NFLNK)) {
453 			int link_len, len;
454 
455 			error = nfs_readlink(newfd, linkbuf);
456 			if (error)
457 				goto out;
458 
459 			link_len = strlen(linkbuf);
460 			len = strlen(cp);
461 
462 			if (link_len + len > MAXPATHLEN
463 			    || ++nlinks > MAXSYMLINKS) {
464 				error = ENOENT;
465 				goto out;
466 			}
467 
468 			bcopy(cp, &namebuf[link_len], len + 1);
469 			bcopy(linkbuf, namebuf, link_len);
470 
471 			/*
472 			 * If absolute pathname, restart at root.
473 			 * If relative pathname, restart at parent directory.
474 			 */
475 			cp = namebuf;
476 			if (*cp == '/') {
477 				if (currfd != &nfs_root_node)
478 					free(currfd, sizeof(*currfd));
479 				currfd = &nfs_root_node;
480 			}
481 
482 			free(newfd, sizeof(*newfd));
483 			newfd = 0;
484 
485 			continue;
486 		}
487 
488 		if (currfd != &nfs_root_node)
489 			free(currfd, sizeof(*currfd));
490 		currfd = newfd;
491 		newfd = 0;
492 	}
493 
494 	error = 0;
495 
496 out:
497 	if (!error) {
498 		f->f_fsdata = (void *)currfd;
499 		return (0);
500 	}
501 
502 #ifdef NFS_DEBUG
503 	if (debug)
504 		printf("nfs_open: %s lookupfh failed: %s\n",
505 		    path, strerror(error));
506 #endif
507 	if (currfd != &nfs_root_node)
508 		free(currfd, sizeof(*currfd));
509 	if (newfd)
510 		free(newfd, sizeof(*newfd));
511 
512 	return (error);
513 }
514 
515 int
516 nfs_close(f)
517 	struct open_file *f;
518 {
519 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
520 
521 #ifdef NFS_DEBUG
522 	if (debug)
523 		printf("nfs_close: fp=0x%x\n", fp);
524 #endif
525 
526 	if (fp)
527 		free(fp, sizeof(struct nfs_iodesc));
528 	f->f_fsdata = (void *)0;
529 
530 	return (0);
531 }
532 
533 /*
534  * read a portion of a file
535  */
536 int
537 nfs_read(f, buf, size, resid)
538 	struct open_file *f;
539 	void *buf;
540 	size_t size;
541 	size_t *resid;	/* out */
542 {
543 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
544 	register ssize_t cc;
545 	register char *addr = buf;
546 
547 #ifdef NFS_DEBUG
548 	if (debug)
549 		printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
550 #endif
551 	while ((int)size > 0) {
552 		twiddle();
553 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
554 		/* XXX maybe should retry on certain errors */
555 		if (cc == -1) {
556 #ifdef NFS_DEBUG
557 			if (debug)
558 				printf("nfs_read: read: %s", strerror(errno));
559 #endif
560 			return (errno);	/* XXX - from nfs_readdata */
561 		}
562 		if (cc == 0) {
563 			if (debug)
564 				printf("nfs_read: hit EOF unexpectantly");
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