xref: /openbsd-src/sys/lib/libsa/nfs.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: nfs.c,v 1.8 1997/03/25 20:30:43 niklas Exp $	*/
2 /*	$NetBSD: nfs.c,v 1.19 1996/10/13 02:29:04 christos Exp $	*/
3 
4 /*-
5  *  Copyright (c) 1993 John Brezak
6  *  All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *  1. Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  *  2. Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution.
16  *  3. The name of the author may not be used to endorse or promote products
17  *     derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/socket.h>
35 #include <sys/stat.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 "saerrno.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_readlnk_repl {
86 	n_long	errno;
87 	n_long	len;
88 	char	path[NFS_MAXPATHLEN];
89 };
90 
91 struct nfs_iodesc {
92 	struct	iodesc	*iodesc;
93 	off_t	off;
94 	u_char	fh[NFS_FHSIZE];
95 	struct nfsv2_fattrs fa;	/* all in network order */
96 };
97 
98 struct nfs_iodesc nfs_root_node;
99 
100 
101 /*
102  * Fetch the root file handle (call mount daemon)
103  * On error, return non-zero and set errno.
104  */
105 int
106 nfs_getrootfh(d, path, fhp)
107 	register struct iodesc *d;
108 	char *path;
109 	u_char *fhp;
110 {
111 	register int len;
112 	struct args {
113 		n_long	len;
114 		char	path[FNAME_SIZE];
115 	} *args;
116 	struct repl {
117 		n_long	errno;
118 		u_char	fh[NFS_FHSIZE];
119 	} *repl;
120 	struct {
121 		n_long	h[RPC_HEADER_WORDS];
122 		struct args d;
123 	} sdata;
124 	struct {
125 		n_long	h[RPC_HEADER_WORDS];
126 		struct repl d;
127 	} rdata;
128 	size_t cc;
129 
130 #ifdef NFS_DEBUG
131 	if (debug)
132 		printf("nfs_getrootfh: %s\n", path);
133 #endif
134 
135 	args = &sdata.d;
136 	repl = &rdata.d;
137 
138 	bzero(args, sizeof(*args));
139 	len = strlen(path);
140 	if (len > sizeof(args->path))
141 		len = sizeof(args->path);
142 	args->len = htonl(len);
143 	bcopy(path, args->path, len);
144 	len = 4 + roundup(len, 4);
145 
146 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
147 	    args, len, repl, sizeof(*repl));
148 	if (cc == -1) {
149 		/* errno was set by rpc_call */
150 		return (-1);
151 	}
152 	if (cc < 4) {
153 		errno = EBADRPC;
154 		return (-1);
155 	}
156 	if (repl->errno) {
157 		errno = ntohl(repl->errno);
158 		return (-1);
159 	}
160 	bcopy(repl->fh, fhp, sizeof(repl->fh));
161 	return (0);
162 }
163 
164 /*
165  * Lookup a file.  Store handle and attributes.
166  * Return zero or error number.
167  */
168 int
169 nfs_lookupfh(d, name, newfd)
170 	struct nfs_iodesc *d;
171 	char *name;
172 	struct nfs_iodesc *newfd;
173 {
174 	register int len, rlen;
175 	struct args {
176 		u_char	fh[NFS_FHSIZE];
177 		n_long	len;
178 		char	name[FNAME_SIZE];
179 	} *args;
180 	struct repl {
181 		n_long	errno;
182 		u_char	fh[NFS_FHSIZE];
183 		struct	nfsv2_fattrs fa;
184 	} *repl;
185 	struct {
186 		n_long	h[RPC_HEADER_WORDS];
187 		struct args d;
188 	} sdata;
189 	struct {
190 		n_long	h[RPC_HEADER_WORDS];
191 		struct repl d;
192 	} rdata;
193 	ssize_t cc;
194 
195 #ifdef NFS_DEBUG
196 	if (debug)
197 		printf("lookupfh: called\n");
198 #endif
199 
200 	args = &sdata.d;
201 	repl = &rdata.d;
202 
203 	bzero(args, sizeof(*args));
204 	bcopy(d->fh, args->fh, sizeof(args->fh));
205 	len = strlen(name);
206 	if (len > sizeof(args->name))
207 		len = sizeof(args->name);
208 	bcopy(name, args->name, len);
209 	args->len = htonl(len);
210 	len = 4 + roundup(len, 4);
211 	len += NFS_FHSIZE;
212 
213 	rlen = sizeof(*repl);
214 
215 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
216 	    args, len, repl, rlen);
217 	if (cc == -1)
218 		return (errno);		/* XXX - from rpc_call */
219 	if (cc < 4)
220 		return (EIO);
221 	if (repl->errno) {
222 		/* saerrno.h now matches NFS error numbers. */
223 		return (ntohl(repl->errno));
224 	}
225 	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
226 	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
227 	return (0);
228 }
229 
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 	bcopy(d->fh, sdata.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 	bcopy(rdata.d.path, buf, rdata.d.len);
271 	buf[rdata.d.len] = 0;
272 	return (0);
273 }
274 
275 /*
276  * Read data from a file.
277  * Return transfer count or -1 (and set errno)
278  */
279 ssize_t
280 nfs_readdata(d, off, addr, len)
281 	struct nfs_iodesc *d;
282 	off_t off;
283 	void *addr;
284 	size_t len;
285 {
286 	struct nfs_read_args *args;
287 	struct nfs_read_repl *repl;
288 	struct {
289 		n_long	h[RPC_HEADER_WORDS];
290 		struct nfs_read_args d;
291 	} sdata;
292 	struct {
293 		n_long	h[RPC_HEADER_WORDS];
294 		struct nfs_read_repl d;
295 	} rdata;
296 	size_t cc;
297 	long x;
298 	int hlen, rlen;
299 
300 	args = &sdata.d;
301 	repl = &rdata.d;
302 
303 	bcopy(d->fh, args->fh, NFS_FHSIZE);
304 	args->off = htonl((n_long)off);
305 	if (len > NFSREAD_SIZE)
306 		len = NFSREAD_SIZE;
307 	args->len = htonl((n_long)len);
308 	args->xxx = htonl((n_long)0);
309 	hlen = sizeof(*repl) - NFSREAD_SIZE;
310 
311 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
312 	    args, sizeof(*args),
313 	    repl, sizeof(*repl));
314 	if (cc == -1) {
315 		/* errno was already set by rpc_call */
316 		return (-1);
317 	}
318 	if (cc < hlen) {
319 		errno = EBADRPC;
320 		return (-1);
321 	}
322 	if (repl->errno) {
323 		errno = ntohl(repl->errno);
324 		return (-1);
325 	}
326 	rlen = cc - hlen;
327 	x = ntohl(repl->count);
328 	if (rlen < x) {
329 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
330 		errno = EBADRPC;
331 		return(-1);
332 	}
333 	bcopy(repl->data, addr, x);
334 	return (x);
335 }
336 
337 /*
338  * nfs_mount - mount this nfs filesystem to a host
339  * On error, return non-zero and set errno.
340  */
341 int
342 nfs_mount(sock, ip, path)
343 	int sock;
344 	struct in_addr ip;
345 	char *path;
346 {
347 	struct iodesc *desc;
348 	struct nfsv2_fattrs *fa;
349 
350 	if (!(desc = socktodesc(sock))) {
351 		errno = EINVAL;
352 		return(-1);
353 	}
354 
355 	/* Bind to a reserved port. */
356 	desc->myport = htons(--rpc_port);
357 	desc->destip = ip;
358 	if (nfs_getrootfh(desc, path, nfs_root_node.fh))
359 		return (-1);
360 	nfs_root_node.iodesc = desc;
361 	/* Fake up attributes for the root dir. */
362 	fa = &nfs_root_node.fa;
363 	fa->fa_type  = htonl(NFDIR);
364 	fa->fa_mode  = htonl(0755);
365 	fa->fa_nlink = htonl(2);
366 
367 #ifdef NFS_DEBUG
368 	if (debug)
369 		printf("nfs_mount: got fh for %s\n", path);
370 #endif
371 
372 	return(0);
373 }
374 
375 /*
376  * Open a file.
377  * return zero or error number
378  */
379 int
380 nfs_open(path, f)
381 	char *path;
382 	struct open_file *f;
383 {
384 	struct nfs_iodesc *newfd, *currfd;
385 	register char *cp, *ncp;
386 	register int c;
387 	char namebuf[NFS_MAXPATHLEN + 1];
388 	char linkbuf[NFS_MAXPATHLEN + 1];
389 	int nlinks = 0;
390 	int error = 0;
391 
392 #ifdef NFS_DEBUG
393  	if (debug)
394  	    printf("nfs_open: %s\n", path);
395 #endif
396 	if (nfs_root_node.iodesc == NULL) {
397 		printf("nfs_open: must mount first.\n");
398 		return (ENXIO);
399 	}
400 
401 	currfd = &nfs_root_node;
402 	newfd = 0;
403 
404 	cp = path;
405 	while (*cp) {
406 		/*
407 		 * Remove extra separators
408 		 */
409 		while (*cp == '/')
410 			cp++;
411 
412 		if (*cp == '\0')
413 			break;
414 		/*
415 		 * Check that current node is a directory.
416 		 */
417 		if (currfd->fa.fa_type != htonl(NFDIR)) {
418 			error = ENOTDIR;
419 			goto out;
420 		}
421 
422 		/* allocate file system specific data structure */
423 		newfd = alloc(sizeof(*newfd));
424 		newfd->iodesc = currfd->iodesc;
425 		newfd->off = 0;
426 
427 		/*
428 		 * Get next component of path name.
429 		 */
430 		{
431 			register int len = 0;
432 
433 			ncp = cp;
434 			while ((c = *cp) != '\0' && c != '/') {
435 				if (++len > NFS_MAXNAMLEN) {
436 					error = ENOENT;
437 					goto out;
438 				}
439 				cp++;
440 			}
441 			*cp = '\0';
442 		}
443 
444 		/* lookup a file handle */
445 		error = nfs_lookupfh(currfd, ncp, newfd);
446 		*cp = c;
447 		if (error)
448 			goto out;
449 
450 		/*
451 		 * Check for symbolic link
452 		 */
453 		if (newfd->fa.fa_type == htonl(NFLNK)) {
454 			int link_len, len;
455 
456 			error = nfs_readlink(newfd, linkbuf);
457 			if (error)
458 				goto out;
459 
460 			link_len = strlen(linkbuf);
461 			len = strlen(cp);
462 
463 			if (link_len + len > MAXPATHLEN
464 			    || ++nlinks > MAXSYMLINKS) {
465 				error = ENOENT;
466 				goto out;
467 			}
468 
469 			bcopy(cp, &namebuf[link_len], len + 1);
470 			bcopy(linkbuf, namebuf, link_len);
471 
472 			/*
473 			 * If absolute pathname, restart at root.
474 			 * If relative pathname, restart at parent directory.
475 			 */
476 			cp = namebuf;
477 			if (*cp == '/') {
478 				if (currfd != &nfs_root_node)
479 					free(currfd, sizeof(*currfd));
480 				currfd = &nfs_root_node;
481 			}
482 
483 			free(newfd, sizeof(*newfd));
484 			newfd = 0;
485 
486 			continue;
487 		}
488 
489 		if (currfd != &nfs_root_node)
490 			free(currfd, sizeof(*currfd));
491 		currfd = newfd;
492 		newfd = 0;
493 	}
494 
495 	error = 0;
496 
497 out:
498 	if (!error) {
499 		f->f_fsdata = (void *)currfd;
500 		return (0);
501 	}
502 
503 #ifdef NFS_DEBUG
504 	if (debug)
505 		printf("nfs_open: %s lookupfh failed: %s\n",
506 		    path, strerror(error));
507 #endif
508 	if (currfd != &nfs_root_node)
509 		free(currfd, sizeof(*currfd));
510 	if (newfd)
511 		free(newfd, sizeof(*newfd));
512 
513 	return (error);
514 }
515 
516 int
517 nfs_close(f)
518 	struct open_file *f;
519 {
520 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
521 
522 #ifdef NFS_DEBUG
523 	if (debug)
524 		printf("nfs_close: fp=%p\n", fp);
525 #endif
526 
527 	if (fp)
528 		free(fp, sizeof(struct nfs_iodesc));
529 	f->f_fsdata = (void *)0;
530 
531 	return (0);
532 }
533 
534 /*
535  * read a portion of a file
536  */
537 int
538 nfs_read(f, buf, size, resid)
539 	struct open_file *f;
540 	void *buf;
541 	size_t size;
542 	size_t *resid;	/* out */
543 {
544 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
545 	register ssize_t cc;
546 	register char *addr = buf;
547 
548 #ifdef NFS_DEBUG
549 	if (debug)
550 		printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
551 #endif
552 	while ((int)size > 0) {
553 		twiddle();
554 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
555 		/* XXX maybe should retry on certain errors */
556 		if (cc == -1) {
557 #ifdef NFS_DEBUG
558 			if (debug)
559 				printf("nfs_read: read: %s", strerror(errno));
560 #endif
561 			return (errno);	/* XXX - from nfs_readdata */
562 		}
563 		if (cc == 0) {
564 			if (debug)
565 				printf("nfs_read: hit EOF unexpectantly");
566 			goto ret;
567 		}
568 		fp->off += cc;
569 		addr += cc;
570 		size -= cc;
571 	}
572 ret:
573 	if (resid)
574 		*resid = size;
575 
576 	return (0);
577 }
578 
579 /*
580  * Not implemented.
581  */
582 int
583 nfs_write(f, buf, size, resid)
584 	struct open_file *f;
585 	void *buf;
586 	size_t size;
587 	size_t *resid;	/* out */
588 {
589 	return (EROFS);
590 }
591 
592 off_t
593 nfs_seek(f, offset, where)
594 	struct open_file *f;
595 	off_t offset;
596 	int where;
597 {
598 	register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
599 	n_long size = ntohl(d->fa.fa_size);
600 
601 	switch (where) {
602 	case SEEK_SET:
603 		d->off = offset;
604 		break;
605 	case SEEK_CUR:
606 		d->off += offset;
607 		break;
608 	case SEEK_END:
609 		d->off = size - offset;
610 		break;
611 	default:
612 		return (-1);
613 	}
614 
615 	return (d->off);
616 }
617 
618 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
619 int nfs_stat_types[8] = {
620 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
621 
622 int
623 nfs_stat(f, sb)
624 	struct open_file *f;
625 	struct stat *sb;
626 {
627 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
628 	register n_long ftype, mode;
629 
630 	ftype = ntohl(fp->fa.fa_type);
631 	mode  = ntohl(fp->fa.fa_mode);
632 	mode |= nfs_stat_types[ftype & 7];
633 
634 	sb->st_mode  = mode;
635 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
636 	sb->st_uid   = ntohl(fp->fa.fa_uid);
637 	sb->st_gid   = ntohl(fp->fa.fa_gid);
638 	sb->st_size  = ntohl(fp->fa.fa_size);
639 
640 	return (0);
641 }
642 
643 /*
644  * Not implemented.
645  */
646 #ifndef NO_READDIR
647 int
648 nfs_readdir(f, name)
649 	struct open_file *f;
650 	char *name;
651 {
652 	return (EROFS);
653 }
654 #endif
655