nfs.c revision 59824
1104478Ssam/* $FreeBSD: head/lib/libstand/nfs.c 59824 2000-05-01 10:53:21Z ps $ */
2104630Ssam/*	$NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $	*/
3104478Ssam
4139749Simp/*-
5104478Ssam *  Copyright (c) 1993 John Brezak
6104478Ssam *  All rights reserved.
7104478Ssam *
8104478Ssam *  Redistribution and use in source and binary forms, with or without
9104478Ssam *  modification, are permitted provided that the following conditions
10104478Ssam *  are met:
11104478Ssam *  1. Redistributions of source code must retain the above copyright
12104478Ssam *     notice, this list of conditions and the following disclaimer.
13104478Ssam *  2. Redistributions in binary form must reproduce the above copyright
14104478Ssam *     notice, this list of conditions and the following disclaimer in the
15104478Ssam *     documentation and/or other materials provided with the distribution.
16104478Ssam *  3. The name of the author may not be used to endorse or promote products
17104478Ssam *     derived from this software without specific prior written permission.
18104478Ssam *
19104478Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
20104478Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21104478Ssam * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22104478Ssam * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23104478Ssam * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24104478Ssam * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25104478Ssam * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26104478Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27104478Ssam * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28104478Ssam * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29104478Ssam * POSSIBILITY OF SUCH DAMAGE.
30104478Ssam */
31104478Ssam
32104478Ssam#include <sys/param.h>
33104478Ssam#include <sys/time.h>
34104478Ssam#include <sys/socket.h>
35104478Ssam#include <sys/stat.h>
36104478Ssam#include <string.h>
37104478Ssam
38104478Ssam#include <netinet/in.h>
39104478Ssam#include <netinet/in_systm.h>
40104478Ssam
41104478Ssam#include "rpcv2.h"
42104478Ssam#include "nfsv2.h"
43104478Ssam
44104478Ssam#include "stand.h"
45104478Ssam#include "net.h"
46104478Ssam#include "netif.h"
47104478Ssam#include "rpc.h"
48104478Ssam
49104478Ssam#define NFS_DEBUGxx
50104478Ssam
51104478Ssam/* Define our own NFS attributes without NQNFS stuff. */
52104478Ssamstruct nfsv2_fattrs {
53104478Ssam	n_long	fa_type;
54104478Ssam	n_long	fa_mode;
55104478Ssam	n_long	fa_nlink;
56110519Ssam	n_long	fa_uid;
57110519Ssam	n_long	fa_gid;
58104478Ssam	n_long	fa_size;
59104478Ssam	n_long	fa_blocksize;
60104478Ssam	n_long	fa_rdev;
61108823Ssam	n_long	fa_blocks;
62104478Ssam	n_long	fa_fsid;
63104478Ssam	n_long	fa_fileid;
64104478Ssam	struct nfsv2_time fa_atime;
65104478Ssam	struct nfsv2_time fa_mtime;
66104478Ssam	struct nfsv2_time fa_ctime;
67104478Ssam};
68104478Ssam
69104478Ssam
70104478Ssamstruct nfs_read_args {
71104478Ssam	u_char	fh[NFS_FHSIZE];
72104478Ssam	n_long	off;
73104478Ssam	n_long	len;
74104478Ssam	n_long	xxx;			/* XXX what's this for? */
75104478Ssam};
76104478Ssam
77104478Ssam/* Data part of nfs rpc reply (also the largest thing we receive) */
78104478Ssam#define NFSREAD_SIZE 1024
79104478Ssamstruct nfs_read_repl {
80104478Ssam	n_long	errno;
81104478Ssam	struct	nfsv2_fattrs fa;
82104478Ssam	n_long	count;
83104478Ssam	u_char	data[NFSREAD_SIZE];
84104478Ssam};
85104478Ssam
86104478Ssam#ifndef NFS_NOSYMLINK
87104478Ssamstruct nfs_readlnk_repl {
88104478Ssam	n_long	errno;
89104478Ssam	n_long	len;
90104478Ssam	char	path[NFS_MAXPATHLEN];
91104478Ssam};
92104478Ssam#endif
93104478Ssam
94104478Ssamstruct nfs_iodesc {
95104630Ssam	struct	iodesc	*iodesc;
96104478Ssam	off_t	off;
97104478Ssam	u_char	fh[NFS_FHSIZE];
98104478Ssam	struct nfsv2_fattrs fa;	/* all in network order */
99104478Ssam};
100104478Ssam
101104478Ssam/*
102104478Ssam * XXX interactions with tftp? See nfswrapper.c for a confusing
103104478Ssam *     issue.
104104478Ssam */
105104478Ssamint		nfs_open(const char *path, struct open_file *f);
106104478Ssamstatic int	nfs_close(struct open_file *f);
107104478Ssamstatic int	nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
108104478Ssamstatic int	nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
109104478Ssamstatic off_t	nfs_seek(struct open_file *f, off_t offset, int where);
110104478Ssamstatic int	nfs_stat(struct open_file *f, struct stat *sb);
111104478Ssam
112104478Ssamstatic struct	nfs_iodesc nfs_root_node;
113104478Ssam
114104478Ssamstruct fs_ops nfs_fsops = {
115104478Ssam	"nfs",
116104478Ssam	nfs_open,
117104478Ssam	nfs_close,
118104478Ssam	nfs_read,
119104478Ssam	nfs_write,
120104478Ssam	nfs_seek,
121104478Ssam	nfs_stat,
122104478Ssam	null_readdir
123104478Ssam};
124104478Ssam
125104478Ssam/*
126104478Ssam * Fetch the root file handle (call mount daemon)
127104478Ssam * Return zero or error number.
128104478Ssam */
129104478Ssamint
130104478Ssamnfs_getrootfh(d, path, fhp)
131104478Ssam	register struct iodesc *d;
132104478Ssam	char *path;
133104478Ssam	u_char *fhp;
134104478Ssam{
135104478Ssam	register int len;
136104478Ssam	struct args {
137104478Ssam		n_long	len;
138104478Ssam		char	path[FNAME_SIZE];
139104478Ssam	} *args;
140104478Ssam	struct repl {
141104478Ssam		n_long	errno;
142104478Ssam		u_char	fh[NFS_FHSIZE];
143104478Ssam	} *repl;
144104478Ssam	struct {
145104478Ssam		n_long	h[RPC_HEADER_WORDS];
146104478Ssam		struct args d;
147104478Ssam	} sdata;
148104478Ssam	struct {
149104478Ssam		n_long	h[RPC_HEADER_WORDS];
150104478Ssam		struct repl d;
151104478Ssam	} rdata;
152104478Ssam	size_t cc;
153104478Ssam
154104478Ssam#ifdef NFS_DEBUG
155104478Ssam	if (debug)
156104478Ssam		printf("nfs_getrootfh: %s\n", path);
157104478Ssam#endif
158104478Ssam
159104478Ssam	args = &sdata.d;
160104478Ssam	repl = &rdata.d;
161104478Ssam
162104478Ssam	bzero(args, sizeof(*args));
163104478Ssam	len = strlen(path);
164104478Ssam	if (len > sizeof(args->path))
165104478Ssam		len = sizeof(args->path);
166104478Ssam	args->len = htonl(len);
167104478Ssam	bcopy(path, args->path, len);
168104478Ssam	len = 4 + roundup(len, 4);
169104478Ssam
170104478Ssam	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
171104478Ssam	    args, len, repl, sizeof(*repl));
172104478Ssam	if (cc == -1) {
173104478Ssam		/* errno was set by rpc_call */
174104478Ssam		return (errno);
175104478Ssam	}
176104478Ssam	if (cc < 4)
177112124Ssam		return (EBADRPC);
178112124Ssam	if (repl->errno)
179104478Ssam		return (ntohl(repl->errno));
180104478Ssam	bcopy(repl->fh, fhp, sizeof(repl->fh));
181104478Ssam	return (0);
182104478Ssam}
183104478Ssam
184104478Ssam/*
185104478Ssam * Lookup a file.  Store handle and attributes.
186104478Ssam * Return zero or error number.
187104478Ssam */
188104478Ssamint
189104478Ssamnfs_lookupfh(d, name, newfd)
190104478Ssam	struct nfs_iodesc *d;
191104478Ssam	const char *name;
192115747Ssam	struct nfs_iodesc *newfd;
193104478Ssam{
194104478Ssam	register int len, rlen;
195104478Ssam	struct args {
196108471Ssam		u_char	fh[NFS_FHSIZE];
197115747Ssam		n_long	len;
198104478Ssam		char	name[FNAME_SIZE];
199115747Ssam	} *args;
200104478Ssam	struct repl {
201104478Ssam		n_long	errno;
202104478Ssam		u_char	fh[NFS_FHSIZE];
203104478Ssam		struct	nfsv2_fattrs fa;
204104478Ssam	} *repl;
205104478Ssam	struct {
206104478Ssam		n_long	h[RPC_HEADER_WORDS];
207104478Ssam		struct args d;
208112124Ssam	} sdata;
209112124Ssam	struct {
210112124Ssam		n_long	h[RPC_HEADER_WORDS];
211104478Ssam		struct repl d;
212104478Ssam	} rdata;
213104478Ssam	ssize_t cc;
214104478Ssam
215104478Ssam#ifdef NFS_DEBUG
216104478Ssam	if (debug)
217104478Ssam		printf("lookupfh: called\n");
218104478Ssam#endif
219104478Ssam
220104478Ssam	args = &sdata.d;
221158705Spjd	repl = &rdata.d;
222104478Ssam
223104478Ssam	bzero(args, sizeof(*args));
224104478Ssam	bcopy(d->fh, args->fh, sizeof(args->fh));
225104478Ssam	len = strlen(name);
226110519Ssam	if (len > sizeof(args->name))
227104478Ssam		len = sizeof(args->name);
228104478Ssam	bcopy(name, args->name, len);
229104478Ssam	args->len = htonl(len);
230104478Ssam	len = 4 + roundup(len, 4);
231104478Ssam	len += NFS_FHSIZE;
232104478Ssam
233108471Ssam	rlen = sizeof(*repl);
234108471Ssam
235108471Ssam	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
236108471Ssam	    args, len, repl, rlen);
237108471Ssam	if (cc == -1)
238104478Ssam		return (errno);		/* XXX - from rpc_call */
239104478Ssam	if (cc < 4)
240104478Ssam		return (EIO);
241104478Ssam	if (repl->errno) {
242104478Ssam		/* saerrno.h now matches NFS error numbers. */
243104478Ssam		return (ntohl(repl->errno));
244104478Ssam	}
245104478Ssam	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
246104478Ssam	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
247104478Ssam	return (0);
248104478Ssam}
249104478Ssam
250104478Ssam#ifndef NFS_NOSYMLINK
251104478Ssam/*
252104478Ssam * Get the destination of a symbolic link.
253104478Ssam */
254108471Ssamint
255108471Ssamnfs_readlink(d, buf)
256108471Ssam	struct nfs_iodesc *d;
257104478Ssam	char *buf;
258104478Ssam{
259104478Ssam	struct {
260104478Ssam		n_long	h[RPC_HEADER_WORDS];
261		u_char fh[NFS_FHSIZE];
262	} sdata;
263	struct {
264		n_long	h[RPC_HEADER_WORDS];
265		struct nfs_readlnk_repl d;
266	} rdata;
267	ssize_t cc;
268
269#ifdef NFS_DEBUG
270	if (debug)
271		printf("readlink: called\n");
272#endif
273
274	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
275	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
276		      sdata.fh, NFS_FHSIZE,
277		      &rdata.d, sizeof(rdata.d));
278	if (cc == -1)
279		return (errno);
280
281	if (cc < 4)
282		return (EIO);
283
284	if (rdata.d.errno)
285		return (ntohl(rdata.d.errno));
286
287	rdata.d.len = ntohl(rdata.d.len);
288	if (rdata.d.len > NFS_MAXPATHLEN)
289		return (ENAMETOOLONG);
290
291	bcopy(rdata.d.path, buf, rdata.d.len);
292	buf[rdata.d.len] = 0;
293	return (0);
294}
295#endif
296
297/*
298 * Read data from a file.
299 * Return transfer count or -1 (and set errno)
300 */
301ssize_t
302nfs_readdata(d, off, addr, len)
303	struct nfs_iodesc *d;
304	off_t off;
305	void *addr;
306	size_t len;
307{
308	struct nfs_read_args *args;
309	struct nfs_read_repl *repl;
310	struct {
311		n_long	h[RPC_HEADER_WORDS];
312		struct nfs_read_args d;
313	} sdata;
314	struct {
315		n_long	h[RPC_HEADER_WORDS];
316		struct nfs_read_repl d;
317	} rdata;
318	size_t cc;
319	long x;
320	int hlen, rlen;
321
322	args = &sdata.d;
323	repl = &rdata.d;
324
325	bcopy(d->fh, args->fh, NFS_FHSIZE);
326	args->off = htonl((n_long)off);
327	if (len > NFSREAD_SIZE)
328		len = NFSREAD_SIZE;
329	args->len = htonl((n_long)len);
330	args->xxx = htonl((n_long)0);
331	hlen = sizeof(*repl) - NFSREAD_SIZE;
332
333	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
334	    args, sizeof(*args),
335	    repl, sizeof(*repl));
336	if (cc == -1) {
337		/* errno was already set by rpc_call */
338		return (-1);
339	}
340	if (cc < hlen) {
341		errno = EBADRPC;
342		return (-1);
343	}
344	if (repl->errno) {
345		errno = ntohl(repl->errno);
346		return (-1);
347	}
348	rlen = cc - hlen;
349	x = ntohl(repl->count);
350	if (rlen < x) {
351		printf("nfsread: short packet, %d < %ld\n", rlen, x);
352		errno = EBADRPC;
353		return(-1);
354	}
355	bcopy(repl->data, addr, x);
356	return (x);
357}
358
359/*
360 * Open a file.
361 * return zero or error number
362 */
363int
364nfs_open(upath, f)
365	const char *upath;
366	struct open_file *f;
367{
368	struct iodesc *desc;
369	struct nfs_iodesc *currfd;
370#ifndef NFS_NOSYMLINK
371	struct nfs_iodesc *newfd;
372	struct nfsv2_fattrs *fa;
373	register char *cp, *ncp;
374	register int c;
375	char namebuf[NFS_MAXPATHLEN + 1];
376	char linkbuf[NFS_MAXPATHLEN + 1];
377	int nlinks = 0;
378#endif
379	int error;
380	char *path;
381
382#ifdef NFS_DEBUG
383 	if (debug)
384 	    printf("nfs_open: %s (rootpath=%s)\n", path, rootpath);
385#endif
386	if (!rootpath[0]) {
387		printf("no rootpath, no nfs\n");
388		return (ENXIO);
389	}
390
391	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
392		return(EINVAL);
393
394	/* Bind to a reserved port. */
395	desc->myport = htons(--rpc_port);
396	desc->destip = rootip;
397	if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
398		return (error);
399	nfs_root_node.iodesc = desc;
400
401#ifndef NFS_NOSYMLINK
402	/* Fake up attributes for the root dir. */
403	fa = &nfs_root_node.fa;
404	fa->fa_type  = htonl(NFDIR);
405	fa->fa_mode  = htonl(0755);
406	fa->fa_nlink = htonl(2);
407
408	currfd = &nfs_root_node;
409	newfd = 0;
410
411	cp = path = strdup(upath);
412	if (path == NULL) {
413	    error = ENOMEM;
414	    goto out;
415	}
416	while (*cp) {
417		/*
418		 * Remove extra separators
419		 */
420		while (*cp == '/')
421			cp++;
422
423		if (*cp == '\0')
424			break;
425		/*
426		 * Check that current node is a directory.
427		 */
428		if (currfd->fa.fa_type != htonl(NFDIR)) {
429			error = ENOTDIR;
430			goto out;
431		}
432
433		/* allocate file system specific data structure */
434		newfd = malloc(sizeof(*newfd));
435		newfd->iodesc = currfd->iodesc;
436		newfd->off = 0;
437
438		/*
439		 * Get next component of path name.
440		 */
441		{
442			register int len = 0;
443
444			ncp = cp;
445			while ((c = *cp) != '\0' && c != '/') {
446				if (++len > NFS_MAXNAMLEN) {
447					error = ENOENT;
448					goto out;
449				}
450				cp++;
451			}
452			*cp = '\0';
453		}
454
455		/* lookup a file handle */
456		error = nfs_lookupfh(currfd, ncp, newfd);
457		*cp = c;
458		if (error)
459			goto out;
460
461		/*
462		 * Check for symbolic link
463		 */
464		if (newfd->fa.fa_type == htonl(NFLNK)) {
465			int link_len, len;
466
467			error = nfs_readlink(newfd, linkbuf);
468			if (error)
469				goto out;
470
471			link_len = strlen(linkbuf);
472			len = strlen(cp);
473
474			if (link_len + len > MAXPATHLEN
475			    || ++nlinks > MAXSYMLINKS) {
476				error = ENOENT;
477				goto out;
478			}
479
480			bcopy(cp, &namebuf[link_len], len + 1);
481			bcopy(linkbuf, namebuf, link_len);
482
483			/*
484			 * If absolute pathname, restart at root.
485			 * If relative pathname, restart at parent directory.
486			 */
487			cp = namebuf;
488			if (*cp == '/') {
489				if (currfd != &nfs_root_node)
490					free(currfd);
491				currfd = &nfs_root_node;
492			}
493
494			free(newfd);
495			newfd = 0;
496
497			continue;
498		}
499
500		if (currfd != &nfs_root_node)
501			free(currfd);
502		currfd = newfd;
503		newfd = 0;
504	}
505
506	error = 0;
507
508out:
509	if (newfd)
510		free(newfd);
511	if (path)
512		free(path);
513#else
514        /* allocate file system specific data structure */
515        currfd = malloc(sizeof(*currfd));
516        currfd->iodesc = desc;
517        currfd->off = 0;
518
519        error = nfs_lookupfh(&nfs_root_node, upath, currfd);
520#endif
521	if (!error) {
522		f->f_fsdata = (void *)currfd;
523		return (0);
524	}
525
526#ifdef NFS_DEBUG
527	if (debug)
528		printf("nfs_open: %s lookupfh failed: %s\n",
529		    path, strerror(error));
530#endif
531#ifndef NFS_NOSYMLINK
532	if (currfd != &nfs_root_node)
533#endif
534		free(currfd);
535
536	return (error);
537}
538
539int
540nfs_close(f)
541	struct open_file *f;
542{
543	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
544
545#ifdef NFS_DEBUG
546	if (debug)
547		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
548#endif
549
550	if (fp != &nfs_root_node && fp)
551		free(fp);
552	f->f_fsdata = (void *)0;
553
554	return (0);
555}
556
557/*
558 * read a portion of a file
559 */
560int
561nfs_read(f, buf, size, resid)
562	struct open_file *f;
563	void *buf;
564	size_t size;
565	size_t *resid;	/* out */
566{
567	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
568	register ssize_t cc;
569	register char *addr = buf;
570
571#ifdef NFS_DEBUG
572	if (debug)
573		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
574		       (int)fp->off);
575#endif
576	while ((int)size > 0) {
577		twiddle();
578		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
579		/* XXX maybe should retry on certain errors */
580		if (cc == -1) {
581#ifdef NFS_DEBUG
582			if (debug)
583				printf("nfs_read: read: %s", strerror(errno));
584#endif
585			return (errno);	/* XXX - from nfs_readdata */
586		}
587		if (cc == 0) {
588#ifdef NFS_DEBUG
589			if (debug)
590				printf("nfs_read: hit EOF unexpectantly");
591#endif
592			goto ret;
593		}
594		fp->off += cc;
595		addr += cc;
596		size -= cc;
597	}
598ret:
599	if (resid)
600		*resid = size;
601
602	return (0);
603}
604
605/*
606 * Not implemented.
607 */
608int
609nfs_write(f, buf, size, resid)
610	struct open_file *f;
611	void *buf;
612	size_t size;
613	size_t *resid;	/* out */
614{
615	return (EROFS);
616}
617
618off_t
619nfs_seek(f, offset, where)
620	struct open_file *f;
621	off_t offset;
622	int where;
623{
624	register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
625	n_long size = ntohl(d->fa.fa_size);
626
627	switch (where) {
628	case SEEK_SET:
629		d->off = offset;
630		break;
631	case SEEK_CUR:
632		d->off += offset;
633		break;
634	case SEEK_END:
635		d->off = size - offset;
636		break;
637	default:
638		return (-1);
639	}
640
641	return (d->off);
642}
643
644/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
645int nfs_stat_types[8] = {
646	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
647
648int
649nfs_stat(f, sb)
650	struct open_file *f;
651	struct stat *sb;
652{
653	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
654	register n_long ftype, mode;
655
656	ftype = ntohl(fp->fa.fa_type);
657	mode  = ntohl(fp->fa.fa_mode);
658	mode |= nfs_stat_types[ftype & 7];
659
660	sb->st_mode  = mode;
661	sb->st_nlink = ntohl(fp->fa.fa_nlink);
662	sb->st_uid   = ntohl(fp->fa.fa_uid);
663	sb->st_gid   = ntohl(fp->fa.fa_gid);
664	sb->st_size  = ntohl(fp->fa.fa_size);
665
666	return (0);
667}
668