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