nfs.c revision 240881
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/cdefs.h>
32__FBSDID("$FreeBSD: head/lib/libstand/nfs.c 240881 2012-09-24 05:24:10Z kevlo $");
33
34#include <sys/param.h>
35#include <sys/time.h>
36#include <sys/socket.h>
37#include <sys/stat.h>
38#include <string.h>
39
40#include <netinet/in.h>
41#include <netinet/in_systm.h>
42
43#include "rpcv2.h"
44#include "nfsv2.h"
45
46#include "stand.h"
47#include "net.h"
48#include "netif.h"
49#include "rpc.h"
50
51#define NFS_DEBUGxx
52
53#define NFSREAD_SIZE 1024
54
55/* Define our own NFS attributes without NQNFS stuff. */
56#ifdef OLD_NFSV2
57struct nfsv2_fattrs {
58	n_long	fa_type;
59	n_long	fa_mode;
60	n_long	fa_nlink;
61	n_long	fa_uid;
62	n_long	fa_gid;
63	n_long	fa_size;
64	n_long	fa_blocksize;
65	n_long	fa_rdev;
66	n_long	fa_blocks;
67	n_long	fa_fsid;
68	n_long	fa_fileid;
69	struct nfsv2_time fa_atime;
70	struct nfsv2_time fa_mtime;
71	struct nfsv2_time fa_ctime;
72};
73
74struct nfs_read_args {
75	u_char	fh[NFS_FHSIZE];
76	n_long	off;
77	n_long	len;
78	n_long	xxx;			/* XXX what's this for? */
79};
80
81/* Data part of nfs rpc reply (also the largest thing we receive) */
82struct nfs_read_repl {
83	n_long	errno;
84	struct	nfsv2_fattrs fa;
85	n_long	count;
86	u_char	data[NFSREAD_SIZE];
87};
88
89#ifndef NFS_NOSYMLINK
90struct nfs_readlnk_repl {
91	n_long	errno;
92	n_long	len;
93	char	path[NFS_MAXPATHLEN];
94};
95#endif
96
97struct nfs_readdir_args {
98	u_char	fh[NFS_FHSIZE];
99	n_long	cookie;
100	n_long	count;
101};
102
103struct nfs_readdir_data {
104	n_long	fileid;
105	n_long	len;
106	char	name[0];
107};
108
109struct nfs_readdir_off {
110	n_long	cookie;
111	n_long	follows;
112};
113
114struct nfs_iodesc {
115	struct	iodesc	*iodesc;
116	off_t	off;
117	u_char	fh[NFS_FHSIZE];
118	struct nfsv2_fattrs fa;	/* all in network order */
119};
120#else	/* !OLD_NFSV2 */
121
122/* NFSv3 definitions */
123#define	NFS_V3MAXFHSIZE		64
124#define	NFS_VER3		3
125#define	RPCMNT_VER3		3
126#define	NFSPROCV3_LOOKUP	3
127#define	NFSPROCV3_READLINK	5
128#define	NFSPROCV3_READ		6
129#define	NFSPROCV3_READDIR	16
130
131typedef struct {
132	uint32_t val[2];
133} n_quad;
134
135struct nfsv3_time {
136	uint32_t nfs_sec;
137	uint32_t nfs_nsec;
138};
139
140struct nfsv3_fattrs {
141	uint32_t fa_type;
142	uint32_t fa_mode;
143	uint32_t fa_nlink;
144	uint32_t fa_uid;
145	uint32_t fa_gid;
146	n_quad fa_size;
147	n_quad fa_used;
148	n_quad fa_rdev;
149	n_quad fa_fsid;
150	n_quad fa_fileid;
151	struct nfsv3_time fa_atime;
152	struct nfsv3_time fa_mtime;
153	struct nfsv3_time fa_ctime;
154};
155
156/*
157 * For NFSv3, the file handle is variable in size, so most fixed sized
158 * structures for arguments won't work. For most cases, a structure
159 * that starts with any fixed size section is followed by an array
160 * that covers the maximum size required.
161 */
162struct nfsv3_readdir_repl {
163	uint32_t errno;
164	uint32_t ok;
165	struct nfsv3_fattrs fa;
166	uint32_t cookiev0;
167	uint32_t cookiev1;
168};
169
170struct nfsv3_readdir_entry {
171	uint32_t follows;
172	uint32_t fid0;
173	uint32_t fid1;
174	uint32_t len;
175	uint32_t nameplus[0];
176};
177
178struct nfs_iodesc {
179	struct iodesc *iodesc;
180	off_t off;
181	uint32_t fhsize;
182	u_char fh[NFS_V3MAXFHSIZE];
183	struct nfsv3_fattrs fa;	/* all in network order */
184	uint64_t cookie;
185};
186#endif	/* OLD_NFSV2 */
187
188/*
189 * XXX interactions with tftp? See nfswrapper.c for a confusing
190 *     issue.
191 */
192int		nfs_open(const char *path, struct open_file *f);
193static int	nfs_close(struct open_file *f);
194static int	nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
195static int	nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
196static off_t	nfs_seek(struct open_file *f, off_t offset, int where);
197static int	nfs_stat(struct open_file *f, struct stat *sb);
198static int	nfs_readdir(struct open_file *f, struct dirent *d);
199
200struct	nfs_iodesc nfs_root_node;
201
202struct fs_ops nfs_fsops = {
203	"nfs",
204	nfs_open,
205	nfs_close,
206	nfs_read,
207	nfs_write,
208	nfs_seek,
209	nfs_stat,
210	nfs_readdir
211};
212
213#ifdef	OLD_NFSV2
214/*
215 * Fetch the root file handle (call mount daemon)
216 * Return zero or error number.
217 */
218int
219nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
220{
221	int len;
222	struct args {
223		n_long	len;
224		char	path[FNAME_SIZE];
225	} *args;
226	struct repl {
227		n_long	errno;
228		u_char	fh[NFS_FHSIZE];
229	} *repl;
230	struct {
231		n_long	h[RPC_HEADER_WORDS];
232		struct args d;
233	} sdata;
234	struct {
235		n_long	h[RPC_HEADER_WORDS];
236		struct repl d;
237	} rdata;
238	size_t cc;
239
240#ifdef NFS_DEBUG
241	if (debug)
242		printf("nfs_getrootfh: %s\n", path);
243#endif
244
245	args = &sdata.d;
246	repl = &rdata.d;
247
248	bzero(args, sizeof(*args));
249	len = strlen(path);
250	if (len > sizeof(args->path))
251		len = sizeof(args->path);
252	args->len = htonl(len);
253	bcopy(path, args->path, len);
254	len = 4 + roundup(len, 4);
255
256	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
257	    args, len, repl, sizeof(*repl));
258	if (cc == -1) {
259		/* errno was set by rpc_call */
260		return (errno);
261	}
262	if (cc < 4)
263		return (EBADRPC);
264	if (repl->errno)
265		return (ntohl(repl->errno));
266	bcopy(repl->fh, fhp, sizeof(repl->fh));
267	return (0);
268}
269
270/*
271 * Lookup a file.  Store handle and attributes.
272 * Return zero or error number.
273 */
274int
275nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
276{
277	int len, rlen;
278	struct args {
279		u_char	fh[NFS_FHSIZE];
280		n_long	len;
281		char	name[FNAME_SIZE];
282	} *args;
283	struct repl {
284		n_long	errno;
285		u_char	fh[NFS_FHSIZE];
286		struct	nfsv2_fattrs fa;
287	} *repl;
288	struct {
289		n_long	h[RPC_HEADER_WORDS];
290		struct args d;
291	} sdata;
292	struct {
293		n_long	h[RPC_HEADER_WORDS];
294		struct repl d;
295	} rdata;
296	ssize_t cc;
297
298#ifdef NFS_DEBUG
299	if (debug)
300		printf("lookupfh: called\n");
301#endif
302
303	args = &sdata.d;
304	repl = &rdata.d;
305
306	bzero(args, sizeof(*args));
307	bcopy(d->fh, args->fh, sizeof(args->fh));
308	len = strlen(name);
309	if (len > sizeof(args->name))
310		len = sizeof(args->name);
311	bcopy(name, args->name, len);
312	args->len = htonl(len);
313	len = 4 + roundup(len, 4);
314	len += NFS_FHSIZE;
315
316	rlen = sizeof(*repl);
317
318	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
319	    args, len, repl, rlen);
320	if (cc == -1)
321		return (errno);		/* XXX - from rpc_call */
322	if (cc < 4)
323		return (EIO);
324	if (repl->errno) {
325		/* saerrno.h now matches NFS error numbers. */
326		return (ntohl(repl->errno));
327	}
328	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
329	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
330	return (0);
331}
332
333#ifndef NFS_NOSYMLINK
334/*
335 * Get the destination of a symbolic link.
336 */
337int
338nfs_readlink(struct nfs_iodesc *d, char *buf)
339{
340	struct {
341		n_long	h[RPC_HEADER_WORDS];
342		u_char fh[NFS_FHSIZE];
343	} sdata;
344	struct {
345		n_long	h[RPC_HEADER_WORDS];
346		struct nfs_readlnk_repl d;
347	} rdata;
348	ssize_t cc;
349
350#ifdef NFS_DEBUG
351	if (debug)
352		printf("readlink: called\n");
353#endif
354
355	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
356	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
357		      sdata.fh, NFS_FHSIZE,
358		      &rdata.d, sizeof(rdata.d));
359	if (cc == -1)
360		return (errno);
361
362	if (cc < 4)
363		return (EIO);
364
365	if (rdata.d.errno)
366		return (ntohl(rdata.d.errno));
367
368	rdata.d.len = ntohl(rdata.d.len);
369	if (rdata.d.len > NFS_MAXPATHLEN)
370		return (ENAMETOOLONG);
371
372	bcopy(rdata.d.path, buf, rdata.d.len);
373	buf[rdata.d.len] = 0;
374	return (0);
375}
376#endif
377
378/*
379 * Read data from a file.
380 * Return transfer count or -1 (and set errno)
381 */
382ssize_t
383nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
384{
385	struct nfs_read_args *args;
386	struct nfs_read_repl *repl;
387	struct {
388		n_long	h[RPC_HEADER_WORDS];
389		struct nfs_read_args d;
390	} sdata;
391	struct {
392		n_long	h[RPC_HEADER_WORDS];
393		struct nfs_read_repl d;
394	} rdata;
395	size_t cc;
396	long x;
397	int hlen, rlen;
398
399	args = &sdata.d;
400	repl = &rdata.d;
401
402	bcopy(d->fh, args->fh, NFS_FHSIZE);
403	args->off = htonl((n_long)off);
404	if (len > NFSREAD_SIZE)
405		len = NFSREAD_SIZE;
406	args->len = htonl((n_long)len);
407	args->xxx = htonl((n_long)0);
408	hlen = sizeof(*repl) - NFSREAD_SIZE;
409
410	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
411	    args, sizeof(*args),
412	    repl, sizeof(*repl));
413	if (cc == -1) {
414		/* errno was already set by rpc_call */
415		return (-1);
416	}
417	if (cc < hlen) {
418		errno = EBADRPC;
419		return (-1);
420	}
421	if (repl->errno) {
422		errno = ntohl(repl->errno);
423		return (-1);
424	}
425	rlen = cc - hlen;
426	x = ntohl(repl->count);
427	if (rlen < x) {
428		printf("nfsread: short packet, %d < %ld\n", rlen, x);
429		errno = EBADRPC;
430		return(-1);
431	}
432	bcopy(repl->data, addr, x);
433	return (x);
434}
435
436/*
437 * Open a file.
438 * return zero or error number
439 */
440int
441nfs_open(const char *upath, struct open_file *f)
442{
443	struct iodesc *desc;
444	struct nfs_iodesc *currfd;
445	char buf[2 * NFS_FHSIZE + 3];
446	u_char *fh;
447	char *cp;
448	int i;
449#ifndef NFS_NOSYMLINK
450	struct nfs_iodesc *newfd;
451	struct nfsv2_fattrs *fa;
452	char *ncp;
453	int c;
454	char namebuf[NFS_MAXPATHLEN + 1];
455	char linkbuf[NFS_MAXPATHLEN + 1];
456	int nlinks = 0;
457#endif
458	int error;
459	char *path;
460
461#ifdef NFS_DEBUG
462 	if (debug)
463 	    printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
464#endif
465	if (!rootpath[0]) {
466		printf("no rootpath, no nfs\n");
467		return (ENXIO);
468	}
469
470	/*
471	 * This is silly - we should look at dv_type but that value is
472	 * arch dependant and we can't use it here.
473	 */
474#ifndef __i386__
475	if (strcmp(f->f_dev->dv_name, "net") != 0)
476		return(EINVAL);
477#else
478	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
479		return(EINVAL);
480#endif
481
482	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
483		return(EINVAL);
484
485	/* Bind to a reserved port. */
486	desc->myport = htons(--rpc_port);
487	desc->destip = rootip;
488	if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
489		return (error);
490	nfs_root_node.fa.fa_type  = htonl(NFDIR);
491	nfs_root_node.fa.fa_mode  = htonl(0755);
492	nfs_root_node.fa.fa_nlink = htonl(2);
493	nfs_root_node.iodesc = desc;
494
495	fh = &nfs_root_node.fh[0];
496	buf[0] = 'X';
497	cp = &buf[1];
498	for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
499		sprintf(cp, "%02x", fh[i]);
500	sprintf(cp, "X");
501	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
502	setenv("boot.nfsroot.path", rootpath, 1);
503	setenv("boot.nfsroot.nfshandle", buf, 1);
504
505	/* Allocate file system specific data structure */
506	currfd = malloc(sizeof(*newfd));
507	if (currfd == NULL) {
508		error = ENOMEM;
509		goto out;
510	}
511
512#ifndef NFS_NOSYMLINK
513	bcopy(&nfs_root_node, currfd, sizeof(*currfd));
514	newfd = 0;
515
516	cp = path = strdup(upath);
517	if (path == NULL) {
518	    error = ENOMEM;
519	    goto out;
520	}
521	while (*cp) {
522		/*
523		 * Remove extra separators
524		 */
525		while (*cp == '/')
526			cp++;
527
528		if (*cp == '\0')
529			break;
530		/*
531		 * Check that current node is a directory.
532		 */
533		if (currfd->fa.fa_type != htonl(NFDIR)) {
534			error = ENOTDIR;
535			goto out;
536		}
537
538		/* allocate file system specific data structure */
539		newfd = malloc(sizeof(*newfd));
540		newfd->iodesc = currfd->iodesc;
541
542		/*
543		 * Get next component of path name.
544		 */
545		{
546			int len = 0;
547
548			ncp = cp;
549			while ((c = *cp) != '\0' && c != '/') {
550				if (++len > NFS_MAXNAMLEN) {
551					error = ENOENT;
552					goto out;
553				}
554				cp++;
555			}
556			*cp = '\0';
557		}
558
559		/* lookup a file handle */
560		error = nfs_lookupfh(currfd, ncp, newfd);
561		*cp = c;
562		if (error)
563			goto out;
564
565		/*
566		 * Check for symbolic link
567		 */
568		if (newfd->fa.fa_type == htonl(NFLNK)) {
569			int link_len, len;
570
571			error = nfs_readlink(newfd, linkbuf);
572			if (error)
573				goto out;
574
575			link_len = strlen(linkbuf);
576			len = strlen(cp);
577
578			if (link_len + len > MAXPATHLEN
579			    || ++nlinks > MAXSYMLINKS) {
580				error = ENOENT;
581				goto out;
582			}
583
584			bcopy(cp, &namebuf[link_len], len + 1);
585			bcopy(linkbuf, namebuf, link_len);
586
587			/*
588			 * If absolute pathname, restart at root.
589			 * If relative pathname, restart at parent directory.
590			 */
591			cp = namebuf;
592			if (*cp == '/')
593				bcopy(&nfs_root_node, currfd, sizeof(*currfd));
594
595			free(newfd);
596			newfd = 0;
597
598			continue;
599		}
600
601		free(currfd);
602		currfd = newfd;
603		newfd = 0;
604	}
605
606	error = 0;
607
608out:
609	free(newfd);
610	free(path);
611#else
612        currfd->iodesc = desc;
613
614        error = nfs_lookupfh(&nfs_root_node, upath, currfd);
615#endif
616	if (!error) {
617		currfd->off = 0;
618		f->f_fsdata = (void *)currfd;
619		return (0);
620	}
621
622#ifdef NFS_DEBUG
623	if (debug)
624		printf("nfs_open: %s lookupfh failed: %s\n",
625		    path, strerror(error));
626#endif
627	free(currfd);
628
629	return (error);
630}
631
632int
633nfs_close(struct open_file *f)
634{
635	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
636
637#ifdef NFS_DEBUG
638	if (debug)
639		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
640#endif
641
642	if (fp)
643		free(fp);
644	f->f_fsdata = (void *)0;
645
646	return (0);
647}
648
649/*
650 * read a portion of a file
651 */
652int
653nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
654{
655	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
656	ssize_t cc;
657	char *addr = buf;
658
659#ifdef NFS_DEBUG
660	if (debug)
661		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
662		       (int)fp->off);
663#endif
664	while ((int)size > 0) {
665		twiddle();
666		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
667		/* XXX maybe should retry on certain errors */
668		if (cc == -1) {
669#ifdef NFS_DEBUG
670			if (debug)
671				printf("nfs_read: read: %s", strerror(errno));
672#endif
673			return (errno);	/* XXX - from nfs_readdata */
674		}
675		if (cc == 0) {
676#ifdef NFS_DEBUG
677			if (debug)
678				printf("nfs_read: hit EOF unexpectantly");
679#endif
680			goto ret;
681		}
682		fp->off += cc;
683		addr += cc;
684		size -= cc;
685	}
686ret:
687	if (resid)
688		*resid = size;
689
690	return (0);
691}
692
693/*
694 * Not implemented.
695 */
696int
697nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
698{
699	return (EROFS);
700}
701
702off_t
703nfs_seek(struct open_file *f, off_t offset, int where)
704{
705	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
706	n_long size = ntohl(d->fa.fa_size);
707
708	switch (where) {
709	case SEEK_SET:
710		d->off = offset;
711		break;
712	case SEEK_CUR:
713		d->off += offset;
714		break;
715	case SEEK_END:
716		d->off = size - offset;
717		break;
718	default:
719		errno = EINVAL;
720		return (-1);
721	}
722
723	return (d->off);
724}
725
726/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
727int nfs_stat_types[8] = {
728	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
729
730int
731nfs_stat(struct open_file *f, struct stat *sb)
732{
733	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
734	n_long ftype, mode;
735
736	ftype = ntohl(fp->fa.fa_type);
737	mode  = ntohl(fp->fa.fa_mode);
738	mode |= nfs_stat_types[ftype & 7];
739
740	sb->st_mode  = mode;
741	sb->st_nlink = ntohl(fp->fa.fa_nlink);
742	sb->st_uid   = ntohl(fp->fa.fa_uid);
743	sb->st_gid   = ntohl(fp->fa.fa_gid);
744	sb->st_size  = ntohl(fp->fa.fa_size);
745
746	return (0);
747}
748
749static int
750nfs_readdir(struct open_file *f, struct dirent *d)
751{
752	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
753	struct nfs_readdir_args *args;
754	struct nfs_readdir_data *rd;
755	struct nfs_readdir_off  *roff = NULL;
756	static char *buf;
757	static struct nfs_iodesc *pfp = NULL;
758	static n_long cookie = 0;
759	size_t cc;
760	n_long eof;
761
762	struct {
763		n_long h[RPC_HEADER_WORDS];
764		struct nfs_readdir_args d;
765	} sdata;
766	static struct {
767		n_long h[RPC_HEADER_WORDS];
768		u_char d[NFS_READDIRSIZE];
769	} rdata;
770
771	if (fp != pfp || fp->off != cookie) {
772		pfp = NULL;
773	refill:
774		args = &sdata.d;
775		bzero(args, sizeof(*args));
776
777		bcopy(fp->fh, args->fh, NFS_FHSIZE);
778		args->cookie = htonl(fp->off);
779		args->count  = htonl(NFS_READDIRSIZE);
780
781		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
782			      args, sizeof(*args),
783			      rdata.d, sizeof(rdata.d));
784		buf  = rdata.d;
785		roff = (struct nfs_readdir_off *)buf;
786		if (ntohl(roff->cookie) != 0)
787			return EIO;
788		pfp = fp;
789		cookie = fp->off;
790	}
791	roff = (struct nfs_readdir_off *)buf;
792
793	if (ntohl(roff->follows) == 0) {
794		eof = ntohl((roff+1)->cookie);
795		if (eof) {
796			cookie = 0;
797			return ENOENT;
798		}
799		goto refill;
800	}
801
802	buf += sizeof(struct nfs_readdir_off);
803	rd = (struct nfs_readdir_data *)buf;
804	d->d_namlen = ntohl(rd->len);
805	bcopy(rd->name, d->d_name, d->d_namlen);
806	d->d_name[d->d_namlen] = '\0';
807
808	buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
809	roff = (struct nfs_readdir_off *)buf;
810	fp->off = cookie = ntohl(roff->cookie);
811	return 0;
812}
813#else	/* !OLD_NFSV2 */
814/*
815 * Fetch the root file handle (call mount daemon)
816 * Return zero or error number.
817 */
818int
819nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
820{
821	int len;
822	struct args {
823		uint32_t len;
824		char path[FNAME_SIZE];
825	} *args;
826	struct repl {
827		uint32_t errno;
828		uint32_t fhsize;
829		u_char fh[NFS_V3MAXFHSIZE];
830		uint32_t authcnt;
831		uint32_t auth[7];
832	} *repl;
833	struct {
834		uint32_t h[RPC_HEADER_WORDS];
835		struct args d;
836	} sdata;
837	struct {
838		uint32_t h[RPC_HEADER_WORDS];
839		struct repl d;
840	} rdata;
841	size_t cc;
842
843#ifdef NFS_DEBUG
844	if (debug)
845		printf("nfs_getrootfh: %s\n", path);
846#endif
847
848	args = &sdata.d;
849	repl = &rdata.d;
850
851	bzero(args, sizeof(*args));
852	len = strlen(path);
853	if (len > sizeof(args->path))
854		len = sizeof(args->path);
855	args->len = htonl(len);
856	bcopy(path, args->path, len);
857	len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
858
859	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
860	    args, len, repl, sizeof(*repl));
861	if (cc == -1)
862		/* errno was set by rpc_call */
863		return (errno);
864	if (cc < 2 * sizeof (uint32_t))
865		return (EBADRPC);
866	if (repl->errno != 0)
867		return (ntohl(repl->errno));
868	*fhlenp = ntohl(repl->fhsize);
869	bcopy(repl->fh, fhp, *fhlenp);
870	return (0);
871}
872
873/*
874 * Lookup a file.  Store handle and attributes.
875 * Return zero or error number.
876 */
877int
878nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
879{
880	int len, rlen, pos;
881	struct args {
882		uint32_t fhsize;
883		uint32_t fhplusname[1 +
884		    (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
885	} *args;
886	struct repl {
887		uint32_t errno;
888		uint32_t fhsize;
889		uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
890		    2 * (sizeof(uint32_t) +
891		    sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
892	} *repl;
893	struct {
894		uint32_t h[RPC_HEADER_WORDS];
895		struct args d;
896	} sdata;
897	struct {
898		uint32_t h[RPC_HEADER_WORDS];
899		struct repl d;
900	} rdata;
901	ssize_t cc;
902
903#ifdef NFS_DEBUG
904	if (debug)
905		printf("lookupfh: called\n");
906#endif
907
908	args = &sdata.d;
909	repl = &rdata.d;
910
911	bzero(args, sizeof(*args));
912	args->fhsize = htonl(d->fhsize);
913	bcopy(d->fh, args->fhplusname, d->fhsize);
914	len = strlen(name);
915	if (len > FNAME_SIZE)
916		len = FNAME_SIZE;
917	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
918	args->fhplusname[pos++] = htonl(len);
919	bcopy(name, &args->fhplusname[pos], len);
920	len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
921	    roundup(len, sizeof(uint32_t));
922
923	rlen = sizeof(*repl);
924
925	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
926	    args, len, repl, rlen);
927	if (cc == -1)
928		return (errno);		/* XXX - from rpc_call */
929	if (cc < 2 * sizeof(uint32_t))
930		return (EIO);
931	if (repl->errno != 0)
932		/* saerrno.h now matches NFS error numbers. */
933		return (ntohl(repl->errno));
934	newfd->fhsize = ntohl(repl->fhsize);
935	bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
936	pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
937	if (repl->fhplusattr[pos++] == 0)
938		return (EIO);
939	bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
940	return (0);
941}
942
943#ifndef NFS_NOSYMLINK
944/*
945 * Get the destination of a symbolic link.
946 */
947int
948nfs_readlink(struct nfs_iodesc *d, char *buf)
949{
950	struct args {
951		uint32_t fhsize;
952		u_char fh[NFS_V3MAXFHSIZE];
953	} *args;
954	struct repl {
955		uint32_t errno;
956		uint32_t ok;
957		struct nfsv3_fattrs fa;
958		uint32_t len;
959		u_char path[NFS_MAXPATHLEN];
960	} *repl;
961	struct {
962		uint32_t h[RPC_HEADER_WORDS];
963		struct args d;
964	} sdata;
965	struct {
966		uint32_t h[RPC_HEADER_WORDS];
967		struct repl d;
968	} rdata;
969	ssize_t cc;
970
971#ifdef NFS_DEBUG
972	if (debug)
973		printf("readlink: called\n");
974#endif
975
976	args = &sdata.d;
977	repl = &rdata.d;
978
979	bzero(args, sizeof(*args));
980	args->fhsize = htonl(d->fhsize);
981	bcopy(d->fh, args->fh, d->fhsize);
982	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
983	    args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
984	    repl, sizeof(*repl));
985	if (cc == -1)
986		return (errno);
987
988	if (cc < 2 * sizeof(uint32_t))
989		return (EIO);
990
991	if (repl->errno != 0)
992		return (ntohl(repl->errno));
993
994	if (repl->ok == 0)
995		return (EIO);
996
997	repl->len = ntohl(repl->len);
998	if (repl->len > NFS_MAXPATHLEN)
999		return (ENAMETOOLONG);
1000
1001	bcopy(repl->path, buf, repl->len);
1002	buf[repl->len] = 0;
1003	return (0);
1004}
1005#endif
1006
1007/*
1008 * Read data from a file.
1009 * Return transfer count or -1 (and set errno)
1010 */
1011ssize_t
1012nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1013{
1014	struct args {
1015		uint32_t fhsize;
1016		uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1017	} *args;
1018	struct repl {
1019		uint32_t errno;
1020		uint32_t ok;
1021		struct nfsv3_fattrs fa;
1022		uint32_t count;
1023		uint32_t eof;
1024		uint32_t len;
1025		u_char data[NFSREAD_SIZE];
1026	} *repl;
1027	struct {
1028		uint32_t h[RPC_HEADER_WORDS];
1029		struct args d;
1030	} sdata;
1031	struct {
1032		uint32_t h[RPC_HEADER_WORDS];
1033		struct repl d;
1034	} rdata;
1035	size_t cc;
1036	long x;
1037	int hlen, rlen, pos;
1038
1039	args = &sdata.d;
1040	repl = &rdata.d;
1041
1042	bzero(args, sizeof(*args));
1043	args->fhsize = htonl(d->fhsize);
1044	bcopy(d->fh, args->fhoffcnt, d->fhsize);
1045	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1046	args->fhoffcnt[pos++] = 0;
1047	args->fhoffcnt[pos++] = htonl((uint32_t)off);
1048	if (len > NFSREAD_SIZE)
1049		len = NFSREAD_SIZE;
1050	args->fhoffcnt[pos] = htonl((uint32_t)len);
1051	hlen = sizeof(*repl) - NFSREAD_SIZE;
1052
1053	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1054	    args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1055	    repl, sizeof(*repl));
1056	if (cc == -1)
1057		/* errno was already set by rpc_call */
1058		return (-1);
1059	if (cc < hlen) {
1060		errno = EBADRPC;
1061		return (-1);
1062	}
1063	if (repl->errno != 0) {
1064		errno = ntohl(repl->errno);
1065		return (-1);
1066	}
1067	rlen = cc - hlen;
1068	x = ntohl(repl->count);
1069	if (rlen < x) {
1070		printf("nfsread: short packet, %d < %ld\n", rlen, x);
1071		errno = EBADRPC;
1072		return (-1);
1073	}
1074	bcopy(repl->data, addr, x);
1075	return (x);
1076}
1077
1078/*
1079 * Open a file.
1080 * return zero or error number
1081 */
1082int
1083nfs_open(const char *upath, struct open_file *f)
1084{
1085	struct iodesc *desc;
1086	struct nfs_iodesc *currfd;
1087	char buf[2 * NFS_V3MAXFHSIZE + 3];
1088	u_char *fh;
1089	char *cp;
1090	int i;
1091#ifndef NFS_NOSYMLINK
1092	struct nfs_iodesc *newfd;
1093	struct nfsv3_fattrs *fa;
1094	char *ncp;
1095	int c;
1096	char namebuf[NFS_MAXPATHLEN + 1];
1097	char linkbuf[NFS_MAXPATHLEN + 1];
1098	int nlinks = 0;
1099#endif
1100	int error;
1101	char *path;
1102
1103#ifdef NFS_DEBUG
1104 	if (debug)
1105 	    printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1106#endif
1107	if (!rootpath[0]) {
1108		printf("no rootpath, no nfs\n");
1109		return (ENXIO);
1110	}
1111
1112	/*
1113	 * This is silly - we should look at dv_type but that value is
1114	 * arch dependant and we can't use it here.
1115	 */
1116#ifndef __i386__
1117	if (strcmp(f->f_dev->dv_name, "net") != 0)
1118		return (EINVAL);
1119#else
1120	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1121		return (EINVAL);
1122#endif
1123
1124	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1125		return (EINVAL);
1126
1127	/* Bind to a reserved port. */
1128	desc->myport = htons(--rpc_port);
1129	desc->destip = rootip;
1130	if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1131	    nfs_root_node.fh)))
1132		return (error);
1133	nfs_root_node.fa.fa_type  = htonl(NFDIR);
1134	nfs_root_node.fa.fa_mode  = htonl(0755);
1135	nfs_root_node.fa.fa_nlink = htonl(2);
1136	nfs_root_node.iodesc = desc;
1137
1138	fh = &nfs_root_node.fh[0];
1139	buf[0] = 'X';
1140	cp = &buf[1];
1141	for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1142		sprintf(cp, "%02x", fh[i]);
1143	sprintf(cp, "X");
1144	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
1145	setenv("boot.nfsroot.path", rootpath, 1);
1146	setenv("boot.nfsroot.nfshandle", buf, 1);
1147	sprintf(buf, "%d", nfs_root_node.fhsize);
1148	setenv("boot.nfsroot.nfshandlelen", buf, 1);
1149
1150	/* Allocate file system specific data structure */
1151	currfd = malloc(sizeof(*newfd));
1152	if (currfd == NULL) {
1153		error = ENOMEM;
1154		goto out;
1155	}
1156#ifndef NFS_NOSYMLINK
1157	bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1158	newfd = 0;
1159
1160	cp = path = strdup(upath);
1161	if (path == NULL) {
1162		error = ENOMEM;
1163		goto out;
1164	}
1165	while (*cp) {
1166		/*
1167		 * Remove extra separators
1168		 */
1169		while (*cp == '/')
1170			cp++;
1171
1172		if (*cp == '\0')
1173			break;
1174		/*
1175		 * Check that current node is a directory.
1176		 */
1177		if (currfd->fa.fa_type != htonl(NFDIR)) {
1178			error = ENOTDIR;
1179			goto out;
1180		}
1181
1182		/* allocate file system specific data structure */
1183		newfd = malloc(sizeof(*newfd));
1184		if (newfd == NULL) {
1185			error = ENOMEM;
1186			goto out;
1187		}
1188		newfd->iodesc = currfd->iodesc;
1189
1190		/*
1191		 * Get next component of path name.
1192		 */
1193		{
1194			int len = 0;
1195
1196			ncp = cp;
1197			while ((c = *cp) != '\0' && c != '/') {
1198				if (++len > NFS_MAXNAMLEN) {
1199					error = ENOENT;
1200					goto out;
1201				}
1202				cp++;
1203			}
1204			*cp = '\0';
1205		}
1206
1207		/* lookup a file handle */
1208		error = nfs_lookupfh(currfd, ncp, newfd);
1209		*cp = c;
1210		if (error)
1211			goto out;
1212
1213		/*
1214		 * Check for symbolic link
1215		 */
1216		if (newfd->fa.fa_type == htonl(NFLNK)) {
1217			int link_len, len;
1218
1219			error = nfs_readlink(newfd, linkbuf);
1220			if (error)
1221				goto out;
1222
1223			link_len = strlen(linkbuf);
1224			len = strlen(cp);
1225
1226			if (link_len + len > MAXPATHLEN
1227			    || ++nlinks > MAXSYMLINKS) {
1228				error = ENOENT;
1229				goto out;
1230			}
1231
1232			bcopy(cp, &namebuf[link_len], len + 1);
1233			bcopy(linkbuf, namebuf, link_len);
1234
1235			/*
1236			 * If absolute pathname, restart at root.
1237			 * If relative pathname, restart at parent directory.
1238			 */
1239			cp = namebuf;
1240			if (*cp == '/')
1241				bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1242
1243			free(newfd);
1244			newfd = 0;
1245
1246			continue;
1247		}
1248
1249		free(currfd);
1250		currfd = newfd;
1251		newfd = 0;
1252	}
1253
1254	error = 0;
1255
1256out:
1257	free(newfd);
1258	free(path);
1259#else
1260	currfd->iodesc = desc;
1261
1262	error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1263#endif
1264	if (!error) {
1265		currfd->off = 0;
1266		currfd->cookie = 0;
1267		f->f_fsdata = (void *)currfd;
1268		return (0);
1269	}
1270
1271#ifdef NFS_DEBUG
1272	if (debug)
1273		printf("nfs_open: %s lookupfh failed: %s\n",
1274		    path, strerror(error));
1275#endif
1276	free(currfd);
1277
1278	return (error);
1279}
1280
1281int
1282nfs_close(struct open_file *f)
1283{
1284	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1285
1286#ifdef NFS_DEBUG
1287	if (debug)
1288		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1289#endif
1290
1291	if (fp)
1292		free(fp);
1293	f->f_fsdata = (void *)0;
1294
1295	return (0);
1296}
1297
1298/*
1299 * read a portion of a file
1300 */
1301int
1302nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1303{
1304	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1305	ssize_t cc;
1306	char *addr = buf;
1307
1308#ifdef NFS_DEBUG
1309	if (debug)
1310		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1311		       (int)fp->off);
1312#endif
1313	while ((int)size > 0) {
1314		twiddle();
1315		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1316		/* XXX maybe should retry on certain errors */
1317		if (cc == -1) {
1318#ifdef NFS_DEBUG
1319			if (debug)
1320				printf("nfs_read: read: %s", strerror(errno));
1321#endif
1322			return (errno);	/* XXX - from nfs_readdata */
1323		}
1324		if (cc == 0) {
1325#ifdef NFS_DEBUG
1326			if (debug)
1327				printf("nfs_read: hit EOF unexpectantly");
1328#endif
1329			goto ret;
1330		}
1331		fp->off += cc;
1332		addr += cc;
1333		size -= cc;
1334	}
1335ret:
1336	if (resid)
1337		*resid = size;
1338
1339	return (0);
1340}
1341
1342/*
1343 * Not implemented.
1344 */
1345int
1346nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1347{
1348	return (EROFS);
1349}
1350
1351off_t
1352nfs_seek(struct open_file *f, off_t offset, int where)
1353{
1354	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1355	uint32_t size = ntohl(d->fa.fa_size.val[1]);
1356
1357	switch (where) {
1358	case SEEK_SET:
1359		d->off = offset;
1360		break;
1361	case SEEK_CUR:
1362		d->off += offset;
1363		break;
1364	case SEEK_END:
1365		d->off = size - offset;
1366		break;
1367	default:
1368		errno = EINVAL;
1369		return (-1);
1370	}
1371
1372	return (d->off);
1373}
1374
1375/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1376int nfs_stat_types[9] = {
1377	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1378
1379int
1380nfs_stat(struct open_file *f, struct stat *sb)
1381{
1382	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1383	uint32_t ftype, mode;
1384
1385	ftype = ntohl(fp->fa.fa_type);
1386	mode  = ntohl(fp->fa.fa_mode);
1387	mode |= nfs_stat_types[ftype & 7];
1388
1389	sb->st_mode  = mode;
1390	sb->st_nlink = ntohl(fp->fa.fa_nlink);
1391	sb->st_uid   = ntohl(fp->fa.fa_uid);
1392	sb->st_gid   = ntohl(fp->fa.fa_gid);
1393	sb->st_size  = ntohl(fp->fa.fa_size.val[1]);
1394
1395	return (0);
1396}
1397
1398static int
1399nfs_readdir(struct open_file *f, struct dirent *d)
1400{
1401	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1402	struct nfsv3_readdir_repl *repl;
1403	struct nfsv3_readdir_entry *rent;
1404	static char *buf;
1405	static struct nfs_iodesc *pfp = NULL;
1406	static uint64_t cookie = 0;
1407	size_t cc;
1408	int pos;
1409
1410	struct args {
1411		uint32_t fhsize;
1412		uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1413	} *args;
1414	struct {
1415		uint32_t h[RPC_HEADER_WORDS];
1416		struct args d;
1417	} sdata;
1418	static struct {
1419		uint32_t h[RPC_HEADER_WORDS];
1420		u_char d[NFS_READDIRSIZE];
1421	} rdata;
1422
1423	if (fp != pfp || fp->off != cookie) {
1424		pfp = NULL;
1425	refill:
1426		args = &sdata.d;
1427		bzero(args, sizeof(*args));
1428
1429		args->fhsize = htonl(fp->fhsize);
1430		bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1431		pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1432		args->fhpluscookie[pos++] = htonl(fp->off >> 32);
1433		args->fhpluscookie[pos++] = htonl(fp->off);
1434		args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
1435		args->fhpluscookie[pos++] = htonl(fp->cookie);
1436		args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1437
1438		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1439		    args, 6 * sizeof(uint32_t) +
1440		    roundup(fp->fhsize, sizeof(uint32_t)),
1441		    rdata.d, sizeof(rdata.d));
1442		buf  = rdata.d;
1443		repl = (struct nfsv3_readdir_repl *)buf;
1444		if (repl->errno != 0)
1445			return (ntohl(repl->errno));
1446		pfp = fp;
1447		cookie = fp->off;
1448		fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
1449		    ntohl(repl->cookiev1);
1450		buf += sizeof (struct nfsv3_readdir_repl);
1451	}
1452	rent = (struct nfsv3_readdir_entry *)buf;
1453
1454	if (rent->follows == 0) {
1455		/* fid0 is actually eof */
1456		if (rent->fid0 != 0) {
1457			cookie = 0;
1458			return (ENOENT);
1459		}
1460		goto refill;
1461	}
1462
1463	d->d_namlen = ntohl(rent->len);
1464	bcopy(rent->nameplus, d->d_name, d->d_namlen);
1465	d->d_name[d->d_namlen] = '\0';
1466
1467	pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1468	fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos++]) << 32) |
1469	    ntohl(rent->nameplus[pos++]);
1470	buf = (u_char *)&rent->nameplus[pos];
1471	return (0);
1472}
1473#endif	/* OLD_NFSV2 */
1474