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