138451Smsmith/*	$NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $	*/
238451Smsmith
338451Smsmith/*-
438451Smsmith *  Copyright (c) 1993 John Brezak
538451Smsmith *  All rights reserved.
6197178Semaste *
738451Smsmith *  Redistribution and use in source and binary forms, with or without
838451Smsmith *  modification, are permitted provided that the following conditions
938451Smsmith *  are met:
1038451Smsmith *  1. Redistributions of source code must retain the above copyright
1138451Smsmith *     notice, this list of conditions and the following disclaimer.
1238451Smsmith *  2. Redistributions in binary form must reproduce the above copyright
1338451Smsmith *     notice, this list of conditions and the following disclaimer in the
1438451Smsmith *     documentation and/or other materials provided with the distribution.
1538451Smsmith *  3. The name of the author may not be used to endorse or promote products
1638451Smsmith *     derived from this software without specific prior written permission.
17197178Semaste *
1838451Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
1938451Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2038451Smsmith * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2138451Smsmith * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2238451Smsmith * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2338451Smsmith * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2438451Smsmith * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2538451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2638451Smsmith * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2738451Smsmith * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2838451Smsmith * POSSIBILITY OF SUCH DAMAGE.
2938451Smsmith */
3038451Smsmith
3184221Sdillon#include <sys/cdefs.h>
3284221Sdillon__FBSDID("$FreeBSD: stable/10/lib/libstand/nfs.c 307203 2016-10-13 08:09:40Z sephe $");
3384221Sdillon
3438451Smsmith#include <sys/param.h>
3538451Smsmith#include <sys/time.h>
3638451Smsmith#include <sys/socket.h>
3738451Smsmith#include <sys/stat.h>
3838451Smsmith#include <string.h>
39307203Ssephe#include <stddef.h>
4038451Smsmith
4138451Smsmith#include <netinet/in.h>
4238451Smsmith#include <netinet/in_systm.h>
4338451Smsmith
4438451Smsmith#include "rpcv2.h"
4538451Smsmith#include "nfsv2.h"
4638451Smsmith
4738451Smsmith#include "stand.h"
4838451Smsmith#include "net.h"
4938451Smsmith#include "netif.h"
5038451Smsmith#include "rpc.h"
5138451Smsmith
5238451Smsmith#define NFS_DEBUGxx
5338451Smsmith
54307203Ssephe#define NFSREAD_MIN_SIZE 1024
55307203Ssephe#define NFSREAD_MAX_SIZE 4096
56212125Srmacklem
5738451Smsmith/* Define our own NFS attributes without NQNFS stuff. */
58212125Srmacklem#ifdef OLD_NFSV2
5938451Smsmithstruct nfsv2_fattrs {
6038451Smsmith	n_long	fa_type;
6138451Smsmith	n_long	fa_mode;
6238451Smsmith	n_long	fa_nlink;
6338451Smsmith	n_long	fa_uid;
6438451Smsmith	n_long	fa_gid;
6538451Smsmith	n_long	fa_size;
6638451Smsmith	n_long	fa_blocksize;
6738451Smsmith	n_long	fa_rdev;
6838451Smsmith	n_long	fa_blocks;
6938451Smsmith	n_long	fa_fsid;
7038451Smsmith	n_long	fa_fileid;
7138451Smsmith	struct nfsv2_time fa_atime;
7238451Smsmith	struct nfsv2_time fa_mtime;
7338451Smsmith	struct nfsv2_time fa_ctime;
7438451Smsmith};
7538451Smsmith
7638451Smsmithstruct nfs_read_args {
7738451Smsmith	u_char	fh[NFS_FHSIZE];
7838451Smsmith	n_long	off;
7938451Smsmith	n_long	len;
8038451Smsmith	n_long	xxx;			/* XXX what's this for? */
8138451Smsmith};
8238451Smsmith
8338451Smsmith/* Data part of nfs rpc reply (also the largest thing we receive) */
8438451Smsmithstruct nfs_read_repl {
8538451Smsmith	n_long	errno;
8638451Smsmith	struct	nfsv2_fattrs fa;
8738451Smsmith	n_long	count;
88307203Ssephe	u_char	data[NFSREAD_MAX_SIZE];
8938451Smsmith};
9038451Smsmith
9138451Smsmith#ifndef NFS_NOSYMLINK
9238451Smsmithstruct nfs_readlnk_repl {
9338451Smsmith	n_long	errno;
9438451Smsmith	n_long	len;
9538451Smsmith	char	path[NFS_MAXPATHLEN];
9638451Smsmith};
9738451Smsmith#endif
9838451Smsmith
9959853Spsstruct nfs_readdir_args {
10059853Sps	u_char	fh[NFS_FHSIZE];
10159853Sps	n_long	cookie;
10259853Sps	n_long	count;
10359853Sps};
10459853Sps
10559853Spsstruct nfs_readdir_data {
10659853Sps	n_long	fileid;
10759853Sps	n_long	len;
10859853Sps	char	name[0];
10959853Sps};
11059853Sps
11159853Spsstruct nfs_readdir_off {
11259853Sps	n_long	cookie;
11359853Sps	n_long	follows;
11459853Sps};
11559853Sps
11638451Smsmithstruct nfs_iodesc {
11738451Smsmith	struct	iodesc	*iodesc;
11838451Smsmith	off_t	off;
11938451Smsmith	u_char	fh[NFS_FHSIZE];
12038451Smsmith	struct nfsv2_fattrs fa;	/* all in network order */
12138451Smsmith};
122212125Srmacklem#else	/* !OLD_NFSV2 */
12338451Smsmith
124212125Srmacklem/* NFSv3 definitions */
125212125Srmacklem#define	NFS_V3MAXFHSIZE		64
126212125Srmacklem#define	NFS_VER3		3
127212125Srmacklem#define	RPCMNT_VER3		3
128212125Srmacklem#define	NFSPROCV3_LOOKUP	3
129212125Srmacklem#define	NFSPROCV3_READLINK	5
130212125Srmacklem#define	NFSPROCV3_READ		6
131212125Srmacklem#define	NFSPROCV3_READDIR	16
132212125Srmacklem
133212125Srmacklemtypedef struct {
134212125Srmacklem	uint32_t val[2];
135212125Srmacklem} n_quad;
136212125Srmacklem
137212125Srmacklemstruct nfsv3_time {
138212125Srmacklem	uint32_t nfs_sec;
139212125Srmacklem	uint32_t nfs_nsec;
140212125Srmacklem};
141212125Srmacklem
142212125Srmacklemstruct nfsv3_fattrs {
143212125Srmacklem	uint32_t fa_type;
144212125Srmacklem	uint32_t fa_mode;
145212125Srmacklem	uint32_t fa_nlink;
146212125Srmacklem	uint32_t fa_uid;
147212125Srmacklem	uint32_t fa_gid;
148212125Srmacklem	n_quad fa_size;
149212125Srmacklem	n_quad fa_used;
150212125Srmacklem	n_quad fa_rdev;
151212125Srmacklem	n_quad fa_fsid;
152212125Srmacklem	n_quad fa_fileid;
153212125Srmacklem	struct nfsv3_time fa_atime;
154212125Srmacklem	struct nfsv3_time fa_mtime;
155212125Srmacklem	struct nfsv3_time fa_ctime;
156212125Srmacklem};
157212125Srmacklem
15838451Smsmith/*
159212125Srmacklem * For NFSv3, the file handle is variable in size, so most fixed sized
160212125Srmacklem * structures for arguments won't work. For most cases, a structure
161212125Srmacklem * that starts with any fixed size section is followed by an array
162212125Srmacklem * that covers the maximum size required.
163212125Srmacklem */
164212125Srmacklemstruct nfsv3_readdir_repl {
165212125Srmacklem	uint32_t errno;
166212125Srmacklem	uint32_t ok;
167212125Srmacklem	struct nfsv3_fattrs fa;
168212125Srmacklem	uint32_t cookiev0;
169212125Srmacklem	uint32_t cookiev1;
170212125Srmacklem};
171212125Srmacklem
172212125Srmacklemstruct nfsv3_readdir_entry {
173212125Srmacklem	uint32_t follows;
174212125Srmacklem	uint32_t fid0;
175212125Srmacklem	uint32_t fid1;
176212125Srmacklem	uint32_t len;
177212125Srmacklem	uint32_t nameplus[0];
178212125Srmacklem};
179212125Srmacklem
180212125Srmacklemstruct nfs_iodesc {
181212125Srmacklem	struct iodesc *iodesc;
182212125Srmacklem	off_t off;
183212125Srmacklem	uint32_t fhsize;
184212125Srmacklem	u_char fh[NFS_V3MAXFHSIZE];
185212125Srmacklem	struct nfsv3_fattrs fa;	/* all in network order */
186240780Smav	uint64_t cookie;
187212125Srmacklem};
188212125Srmacklem#endif	/* OLD_NFSV2 */
189212125Srmacklem
190212125Srmacklem/*
19138451Smsmith * XXX interactions with tftp? See nfswrapper.c for a confusing
19238451Smsmith *     issue.
19338451Smsmith */
19439468Smsmithint		nfs_open(const char *path, struct open_file *f);
19538451Smsmithstatic int	nfs_close(struct open_file *f);
19638451Smsmithstatic int	nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
19738451Smsmithstatic int	nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
19838451Smsmithstatic off_t	nfs_seek(struct open_file *f, off_t offset, int where);
19938451Smsmithstatic int	nfs_stat(struct open_file *f, struct stat *sb);
20059853Spsstatic int	nfs_readdir(struct open_file *f, struct dirent *d);
20138451Smsmith
20265496Smsmithstruct	nfs_iodesc nfs_root_node;
20359824Sps
20438451Smsmithstruct fs_ops nfs_fsops = {
20559766Sjlemon	"nfs",
20659766Sjlemon	nfs_open,
20759766Sjlemon	nfs_close,
20859766Sjlemon	nfs_read,
20959766Sjlemon	nfs_write,
21059766Sjlemon	nfs_seek,
21159766Sjlemon	nfs_stat,
21259853Sps	nfs_readdir
21338451Smsmith};
21438451Smsmith
215307203Ssephestatic int nfs_read_size = NFSREAD_MIN_SIZE;
216307203Ssephe
217212125Srmacklem#ifdef	OLD_NFSV2
21838451Smsmith/*
21938451Smsmith * Fetch the root file handle (call mount daemon)
22038451Smsmith * Return zero or error number.
22138451Smsmith */
22238451Smsmithint
223197178Semastenfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
22438451Smsmith{
22592913Sobrien	int len;
22638451Smsmith	struct args {
22738451Smsmith		n_long	len;
22838451Smsmith		char	path[FNAME_SIZE];
22938451Smsmith	} *args;
23038451Smsmith	struct repl {
23138451Smsmith		n_long	errno;
23238451Smsmith		u_char	fh[NFS_FHSIZE];
23338451Smsmith	} *repl;
23438451Smsmith	struct {
23538451Smsmith		n_long	h[RPC_HEADER_WORDS];
23638451Smsmith		struct args d;
23738451Smsmith	} sdata;
23838451Smsmith	struct {
23938451Smsmith		n_long	h[RPC_HEADER_WORDS];
24038451Smsmith		struct repl d;
24138451Smsmith	} rdata;
24238451Smsmith	size_t cc;
243197178Semaste
24438451Smsmith#ifdef NFS_DEBUG
24538451Smsmith	if (debug)
24638451Smsmith		printf("nfs_getrootfh: %s\n", path);
24738451Smsmith#endif
24838451Smsmith
24938451Smsmith	args = &sdata.d;
25038451Smsmith	repl = &rdata.d;
25138451Smsmith
25238451Smsmith	bzero(args, sizeof(*args));
25338451Smsmith	len = strlen(path);
25438451Smsmith	if (len > sizeof(args->path))
25538451Smsmith		len = sizeof(args->path);
25638451Smsmith	args->len = htonl(len);
25738451Smsmith	bcopy(path, args->path, len);
25838451Smsmith	len = 4 + roundup(len, 4);
25938451Smsmith
26038451Smsmith	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
26138451Smsmith	    args, len, repl, sizeof(*repl));
26238451Smsmith	if (cc == -1) {
26338451Smsmith		/* errno was set by rpc_call */
26438451Smsmith		return (errno);
26538451Smsmith	}
26638451Smsmith	if (cc < 4)
26738451Smsmith		return (EBADRPC);
26838451Smsmith	if (repl->errno)
26938451Smsmith		return (ntohl(repl->errno));
27038451Smsmith	bcopy(repl->fh, fhp, sizeof(repl->fh));
271307203Ssephe
272307203Ssephe	/*
273307203Ssephe	 * Improve boot performance over NFS
274307203Ssephe	 */
275307203Ssephe	if (getenv("nfs.read_size") != NULL)
276307203Ssephe		nfs_read_size = strtol(getenv("nfs.read_size"), NULL, 0);
277307203Ssephe	if (nfs_read_size < NFSREAD_MIN_SIZE)
278307203Ssephe		nfs_read_size = NFSREAD_MIN_SIZE;
279307203Ssephe	if (nfs_read_size > NFSREAD_MAX_SIZE)
280307203Ssephe		nfs_read_size = NFSREAD_MAX_SIZE;
281307203Ssephe
28238451Smsmith	return (0);
28338451Smsmith}
28438451Smsmith
28538451Smsmith/*
28638451Smsmith * Lookup a file.  Store handle and attributes.
28738451Smsmith * Return zero or error number.
28838451Smsmith */
28938451Smsmithint
290197178Semastenfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
29138451Smsmith{
29292913Sobrien	int len, rlen;
29338451Smsmith	struct args {
29438451Smsmith		u_char	fh[NFS_FHSIZE];
29538451Smsmith		n_long	len;
29638451Smsmith		char	name[FNAME_SIZE];
29738451Smsmith	} *args;
29838451Smsmith	struct repl {
29938451Smsmith		n_long	errno;
30038451Smsmith		u_char	fh[NFS_FHSIZE];
30138451Smsmith		struct	nfsv2_fattrs fa;
30238451Smsmith	} *repl;
30338451Smsmith	struct {
30438451Smsmith		n_long	h[RPC_HEADER_WORDS];
30538451Smsmith		struct args d;
30638451Smsmith	} sdata;
30738451Smsmith	struct {
30838451Smsmith		n_long	h[RPC_HEADER_WORDS];
30938451Smsmith		struct repl d;
31038451Smsmith	} rdata;
31138451Smsmith	ssize_t cc;
312197178Semaste
31338451Smsmith#ifdef NFS_DEBUG
31438451Smsmith	if (debug)
31538451Smsmith		printf("lookupfh: called\n");
31638451Smsmith#endif
31738451Smsmith
31838451Smsmith	args = &sdata.d;
31938451Smsmith	repl = &rdata.d;
32038451Smsmith
32138451Smsmith	bzero(args, sizeof(*args));
32238451Smsmith	bcopy(d->fh, args->fh, sizeof(args->fh));
32338451Smsmith	len = strlen(name);
32438451Smsmith	if (len > sizeof(args->name))
32538451Smsmith		len = sizeof(args->name);
32638451Smsmith	bcopy(name, args->name, len);
32738451Smsmith	args->len = htonl(len);
32838451Smsmith	len = 4 + roundup(len, 4);
32938451Smsmith	len += NFS_FHSIZE;
33038451Smsmith
33138451Smsmith	rlen = sizeof(*repl);
33238451Smsmith
33338451Smsmith	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
33438451Smsmith	    args, len, repl, rlen);
33538451Smsmith	if (cc == -1)
33638451Smsmith		return (errno);		/* XXX - from rpc_call */
33738451Smsmith	if (cc < 4)
33838451Smsmith		return (EIO);
33938451Smsmith	if (repl->errno) {
34038451Smsmith		/* saerrno.h now matches NFS error numbers. */
34138451Smsmith		return (ntohl(repl->errno));
34238451Smsmith	}
34338451Smsmith	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
34438451Smsmith	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
34538451Smsmith	return (0);
34638451Smsmith}
34738451Smsmith
34838451Smsmith#ifndef NFS_NOSYMLINK
34938451Smsmith/*
35038451Smsmith * Get the destination of a symbolic link.
35138451Smsmith */
35238451Smsmithint
353197178Semastenfs_readlink(struct nfs_iodesc *d, char *buf)
35438451Smsmith{
35538451Smsmith	struct {
35638451Smsmith		n_long	h[RPC_HEADER_WORDS];
35738451Smsmith		u_char fh[NFS_FHSIZE];
35838451Smsmith	} sdata;
35938451Smsmith	struct {
36038451Smsmith		n_long	h[RPC_HEADER_WORDS];
36138451Smsmith		struct nfs_readlnk_repl d;
36238451Smsmith	} rdata;
36338451Smsmith	ssize_t cc;
36438451Smsmith
36538451Smsmith#ifdef NFS_DEBUG
36638451Smsmith	if (debug)
36738451Smsmith		printf("readlink: called\n");
36838451Smsmith#endif
36938451Smsmith
37038451Smsmith	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
37138451Smsmith	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
37238451Smsmith		      sdata.fh, NFS_FHSIZE,
37338451Smsmith		      &rdata.d, sizeof(rdata.d));
37438451Smsmith	if (cc == -1)
37538451Smsmith		return (errno);
37638451Smsmith
37738451Smsmith	if (cc < 4)
37838451Smsmith		return (EIO);
379197178Semaste
38038451Smsmith	if (rdata.d.errno)
38138451Smsmith		return (ntohl(rdata.d.errno));
38238451Smsmith
38338451Smsmith	rdata.d.len = ntohl(rdata.d.len);
38438451Smsmith	if (rdata.d.len > NFS_MAXPATHLEN)
38538451Smsmith		return (ENAMETOOLONG);
38638451Smsmith
38738451Smsmith	bcopy(rdata.d.path, buf, rdata.d.len);
38838451Smsmith	buf[rdata.d.len] = 0;
38938451Smsmith	return (0);
39038451Smsmith}
39138451Smsmith#endif
39238451Smsmith
39338451Smsmith/*
39438451Smsmith * Read data from a file.
39538451Smsmith * Return transfer count or -1 (and set errno)
39638451Smsmith */
39738451Smsmithssize_t
398197178Semastenfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
39938451Smsmith{
40038451Smsmith	struct nfs_read_args *args;
40138451Smsmith	struct nfs_read_repl *repl;
40238451Smsmith	struct {
40338451Smsmith		n_long	h[RPC_HEADER_WORDS];
40438451Smsmith		struct nfs_read_args d;
40538451Smsmith	} sdata;
40638451Smsmith	struct {
40738451Smsmith		n_long	h[RPC_HEADER_WORDS];
40838451Smsmith		struct nfs_read_repl d;
40938451Smsmith	} rdata;
41038451Smsmith	size_t cc;
41138451Smsmith	long x;
41238451Smsmith	int hlen, rlen;
41338451Smsmith
41438451Smsmith	args = &sdata.d;
41538451Smsmith	repl = &rdata.d;
41638451Smsmith
41738451Smsmith	bcopy(d->fh, args->fh, NFS_FHSIZE);
41838451Smsmith	args->off = htonl((n_long)off);
419307203Ssephe	if (len > nfs_read_size)
420307203Ssephe		len = nfs_read_size;
42138451Smsmith	args->len = htonl((n_long)len);
42238451Smsmith	args->xxx = htonl((n_long)0);
423307203Ssephe	hlen = offsetof(struct nfs_read_rpl, data[0]);
42438451Smsmith
42538451Smsmith	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
42638451Smsmith	    args, sizeof(*args),
42738451Smsmith	    repl, sizeof(*repl));
42838451Smsmith	if (cc == -1) {
42938451Smsmith		/* errno was already set by rpc_call */
43038451Smsmith		return (-1);
43138451Smsmith	}
43238451Smsmith	if (cc < hlen) {
43338451Smsmith		errno = EBADRPC;
43438451Smsmith		return (-1);
43538451Smsmith	}
43638451Smsmith	if (repl->errno) {
43738451Smsmith		errno = ntohl(repl->errno);
43838451Smsmith		return (-1);
43938451Smsmith	}
44038451Smsmith	rlen = cc - hlen;
44138451Smsmith	x = ntohl(repl->count);
44238451Smsmith	if (rlen < x) {
44338451Smsmith		printf("nfsread: short packet, %d < %ld\n", rlen, x);
44438451Smsmith		errno = EBADRPC;
44538451Smsmith		return(-1);
44638451Smsmith	}
44738451Smsmith	bcopy(repl->data, addr, x);
44838451Smsmith	return (x);
44938451Smsmith}
45038451Smsmith
45138451Smsmith/*
45238451Smsmith * Open a file.
45338451Smsmith * return zero or error number
45438451Smsmith */
45538451Smsmithint
456197178Semastenfs_open(const char *upath, struct open_file *f)
45738451Smsmith{
45838451Smsmith	struct iodesc *desc;
45938451Smsmith	struct nfs_iodesc *currfd;
460101112Sjake	char buf[2 * NFS_FHSIZE + 3];
461101112Sjake	u_char *fh;
462101112Sjake	char *cp;
463101112Sjake	int i;
46438451Smsmith#ifndef NFS_NOSYMLINK
46538451Smsmith	struct nfs_iodesc *newfd;
46638451Smsmith	struct nfsv2_fattrs *fa;
467101112Sjake	char *ncp;
46892913Sobrien	int c;
46938451Smsmith	char namebuf[NFS_MAXPATHLEN + 1];
47038451Smsmith	char linkbuf[NFS_MAXPATHLEN + 1];
47138451Smsmith	int nlinks = 0;
47238451Smsmith#endif
47338451Smsmith	int error;
47439468Smsmith	char *path;
47538451Smsmith
47638451Smsmith#ifdef NFS_DEBUG
47738451Smsmith 	if (debug)
478185155Sluigi 	    printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
47938451Smsmith#endif
48038451Smsmith	if (!rootpath[0]) {
48138451Smsmith		printf("no rootpath, no nfs\n");
48238451Smsmith		return (ENXIO);
48338451Smsmith	}
48438451Smsmith
485177935Sdfr	/*
486177935Sdfr	 * This is silly - we should look at dv_type but that value is
487177935Sdfr	 * arch dependant and we can't use it here.
488177935Sdfr	 */
489111776Smarcel#ifndef __i386__
49099558Sjake	if (strcmp(f->f_dev->dv_name, "net") != 0)
49199558Sjake		return(EINVAL);
492177935Sdfr#else
493177935Sdfr	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
494177935Sdfr		return(EINVAL);
49599558Sjake#endif
496111776Smarcel
49738451Smsmith	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
49838451Smsmith		return(EINVAL);
49938451Smsmith
50038451Smsmith	/* Bind to a reserved port. */
50138451Smsmith	desc->myport = htons(--rpc_port);
50238451Smsmith	desc->destip = rootip;
50338451Smsmith	if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
50438451Smsmith		return (error);
505240774Smav	nfs_root_node.fa.fa_type  = htonl(NFDIR);
506240774Smav	nfs_root_node.fa.fa_mode  = htonl(0755);
507240774Smav	nfs_root_node.fa.fa_nlink = htonl(2);
50838451Smsmith	nfs_root_node.iodesc = desc;
50938451Smsmith
510101112Sjake	fh = &nfs_root_node.fh[0];
511101112Sjake	buf[0] = 'X';
512101112Sjake	cp = &buf[1];
513101112Sjake	for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
514101112Sjake		sprintf(cp, "%02x", fh[i]);
515101112Sjake	sprintf(cp, "X");
516101112Sjake	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
517101112Sjake	setenv("boot.nfsroot.path", rootpath, 1);
518101112Sjake	setenv("boot.nfsroot.nfshandle", buf, 1);
519101112Sjake
520240774Smav	/* Allocate file system specific data structure */
521240774Smav	currfd = malloc(sizeof(*newfd));
522240774Smav	if (currfd == NULL) {
523240774Smav		error = ENOMEM;
524240774Smav		goto out;
525240774Smav	}
526240774Smav
52738451Smsmith#ifndef NFS_NOSYMLINK
528240774Smav	bcopy(&nfs_root_node, currfd, sizeof(*currfd));
52938451Smsmith	newfd = 0;
53038451Smsmith
53139468Smsmith	cp = path = strdup(upath);
53239468Smsmith	if (path == NULL) {
53339468Smsmith	    error = ENOMEM;
53439468Smsmith	    goto out;
53539468Smsmith	}
53638451Smsmith	while (*cp) {
53738451Smsmith		/*
53838451Smsmith		 * Remove extra separators
53938451Smsmith		 */
54038451Smsmith		while (*cp == '/')
54138451Smsmith			cp++;
54238451Smsmith
54338451Smsmith		if (*cp == '\0')
54438451Smsmith			break;
54538451Smsmith		/*
54638451Smsmith		 * Check that current node is a directory.
54738451Smsmith		 */
54838451Smsmith		if (currfd->fa.fa_type != htonl(NFDIR)) {
54938451Smsmith			error = ENOTDIR;
55038451Smsmith			goto out;
55138451Smsmith		}
552197178Semaste
55338451Smsmith		/* allocate file system specific data structure */
55438451Smsmith		newfd = malloc(sizeof(*newfd));
55538451Smsmith		newfd->iodesc = currfd->iodesc;
556197178Semaste
55738451Smsmith		/*
55838451Smsmith		 * Get next component of path name.
55938451Smsmith		 */
56038451Smsmith		{
56192913Sobrien			int len = 0;
562197178Semaste
56338451Smsmith			ncp = cp;
56438451Smsmith			while ((c = *cp) != '\0' && c != '/') {
56538451Smsmith				if (++len > NFS_MAXNAMLEN) {
56638451Smsmith					error = ENOENT;
56738451Smsmith					goto out;
56838451Smsmith				}
56938451Smsmith				cp++;
57038451Smsmith			}
57138451Smsmith			*cp = '\0';
57238451Smsmith		}
573197178Semaste
57438451Smsmith		/* lookup a file handle */
57538451Smsmith		error = nfs_lookupfh(currfd, ncp, newfd);
57638451Smsmith		*cp = c;
57738451Smsmith		if (error)
57838451Smsmith			goto out;
579197178Semaste
58038451Smsmith		/*
58138451Smsmith		 * Check for symbolic link
58238451Smsmith		 */
58338451Smsmith		if (newfd->fa.fa_type == htonl(NFLNK)) {
58438451Smsmith			int link_len, len;
585197178Semaste
58638451Smsmith			error = nfs_readlink(newfd, linkbuf);
58738451Smsmith			if (error)
58838451Smsmith				goto out;
58938451Smsmith
59038451Smsmith			link_len = strlen(linkbuf);
59138451Smsmith			len = strlen(cp);
59238451Smsmith
59338451Smsmith			if (link_len + len > MAXPATHLEN
59438451Smsmith			    || ++nlinks > MAXSYMLINKS) {
59538451Smsmith				error = ENOENT;
59638451Smsmith				goto out;
59738451Smsmith			}
59838451Smsmith
59938451Smsmith			bcopy(cp, &namebuf[link_len], len + 1);
60038451Smsmith			bcopy(linkbuf, namebuf, link_len);
601197178Semaste
60238451Smsmith			/*
60338451Smsmith			 * If absolute pathname, restart at root.
60438451Smsmith			 * If relative pathname, restart at parent directory.
60538451Smsmith			 */
60638451Smsmith			cp = namebuf;
607240774Smav			if (*cp == '/')
608240774Smav				bcopy(&nfs_root_node, currfd, sizeof(*currfd));
60938451Smsmith
61038451Smsmith			free(newfd);
61138451Smsmith			newfd = 0;
612197178Semaste
61338451Smsmith			continue;
61438451Smsmith		}
615197178Semaste
616240774Smav		free(currfd);
61738451Smsmith		currfd = newfd;
61838451Smsmith		newfd = 0;
61938451Smsmith	}
62038451Smsmith
62138451Smsmith	error = 0;
62238451Smsmith
62338451Smsmithout:
624240881Skevlo	free(newfd);
625240881Skevlo	free(path);
62638451Smsmith#else
62738451Smsmith        currfd->iodesc = desc;
62838451Smsmith
62939468Smsmith        error = nfs_lookupfh(&nfs_root_node, upath, currfd);
63038451Smsmith#endif
63138451Smsmith	if (!error) {
632240774Smav		currfd->off = 0;
63338451Smsmith		f->f_fsdata = (void *)currfd;
63438451Smsmith		return (0);
63538451Smsmith	}
636197178Semaste
63738451Smsmith#ifdef NFS_DEBUG
63838451Smsmith	if (debug)
63938451Smsmith		printf("nfs_open: %s lookupfh failed: %s\n",
64038451Smsmith		    path, strerror(error));
64138451Smsmith#endif
642240774Smav	free(currfd);
64338451Smsmith
64438451Smsmith	return (error);
64538451Smsmith}
64638451Smsmith
64738451Smsmithint
648197178Semastenfs_close(struct open_file *f)
64938451Smsmith{
65092913Sobrien	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
65138451Smsmith
65238451Smsmith#ifdef NFS_DEBUG
65338451Smsmith	if (debug)
65438451Smsmith		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
65538451Smsmith#endif
65638451Smsmith
657240774Smav	if (fp)
65838451Smsmith		free(fp);
65938451Smsmith	f->f_fsdata = (void *)0;
660197178Semaste
66138451Smsmith	return (0);
66238451Smsmith}
66338451Smsmith
66438451Smsmith/*
66538451Smsmith * read a portion of a file
66638451Smsmith */
66738451Smsmithint
668197178Semastenfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
66938451Smsmith{
67092913Sobrien	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
67192913Sobrien	ssize_t cc;
67292913Sobrien	char *addr = buf;
673197178Semaste
67438451Smsmith#ifdef NFS_DEBUG
67538451Smsmith	if (debug)
67638451Smsmith		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
67738451Smsmith		       (int)fp->off);
67838451Smsmith#endif
67938451Smsmith	while ((int)size > 0) {
680278602Sian		twiddle(16);
68138451Smsmith		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
68238451Smsmith		/* XXX maybe should retry on certain errors */
68338451Smsmith		if (cc == -1) {
68438451Smsmith#ifdef NFS_DEBUG
68538451Smsmith			if (debug)
68638451Smsmith				printf("nfs_read: read: %s", strerror(errno));
68738451Smsmith#endif
68838451Smsmith			return (errno);	/* XXX - from nfs_readdata */
68938451Smsmith		}
69038451Smsmith		if (cc == 0) {
69138451Smsmith#ifdef NFS_DEBUG
69238451Smsmith			if (debug)
69338451Smsmith				printf("nfs_read: hit EOF unexpectantly");
69438451Smsmith#endif
69538451Smsmith			goto ret;
69638451Smsmith		}
69738451Smsmith		fp->off += cc;
69838451Smsmith		addr += cc;
69938451Smsmith		size -= cc;
70038451Smsmith	}
70138451Smsmithret:
70238451Smsmith	if (resid)
70338451Smsmith		*resid = size;
70438451Smsmith
70538451Smsmith	return (0);
70638451Smsmith}
70738451Smsmith
70838451Smsmith/*
70938451Smsmith * Not implemented.
71038451Smsmith */
71138451Smsmithint
712197178Semastenfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
71338451Smsmith{
71438451Smsmith	return (EROFS);
71538451Smsmith}
71638451Smsmith
71738451Smsmithoff_t
718197178Semastenfs_seek(struct open_file *f, off_t offset, int where)
71938451Smsmith{
72092913Sobrien	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
72138451Smsmith	n_long size = ntohl(d->fa.fa_size);
72238451Smsmith
72338451Smsmith	switch (where) {
72438451Smsmith	case SEEK_SET:
72538451Smsmith		d->off = offset;
72638451Smsmith		break;
72738451Smsmith	case SEEK_CUR:
72838451Smsmith		d->off += offset;
72938451Smsmith		break;
73038451Smsmith	case SEEK_END:
73138451Smsmith		d->off = size - offset;
73238451Smsmith		break;
73338451Smsmith	default:
734124811Sjhb		errno = EINVAL;
73538451Smsmith		return (-1);
73638451Smsmith	}
73738451Smsmith
73838451Smsmith	return (d->off);
73938451Smsmith}
74038451Smsmith
74138451Smsmith/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
74238451Smsmithint nfs_stat_types[8] = {
74338451Smsmith	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
74438451Smsmith
74538451Smsmithint
746197178Semastenfs_stat(struct open_file *f, struct stat *sb)
74738451Smsmith{
74838451Smsmith	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
74992913Sobrien	n_long ftype, mode;
75038451Smsmith
75138451Smsmith	ftype = ntohl(fp->fa.fa_type);
75238451Smsmith	mode  = ntohl(fp->fa.fa_mode);
75338451Smsmith	mode |= nfs_stat_types[ftype & 7];
75438451Smsmith
75538451Smsmith	sb->st_mode  = mode;
75638451Smsmith	sb->st_nlink = ntohl(fp->fa.fa_nlink);
75738451Smsmith	sb->st_uid   = ntohl(fp->fa.fa_uid);
75838451Smsmith	sb->st_gid   = ntohl(fp->fa.fa_gid);
75938451Smsmith	sb->st_size  = ntohl(fp->fa.fa_size);
76038451Smsmith
76138451Smsmith	return (0);
76238451Smsmith}
76359853Sps
76459853Spsstatic int
76559853Spsnfs_readdir(struct open_file *f, struct dirent *d)
76659853Sps{
76792913Sobrien	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
76859853Sps	struct nfs_readdir_args *args;
76959853Sps	struct nfs_readdir_data *rd;
77059853Sps	struct nfs_readdir_off  *roff = NULL;
77159853Sps	static char *buf;
772240780Smav	static struct nfs_iodesc *pfp = NULL;
77359853Sps	static n_long cookie = 0;
77459853Sps	size_t cc;
77559853Sps	n_long eof;
776197178Semaste
77759853Sps	struct {
77859853Sps		n_long h[RPC_HEADER_WORDS];
77959853Sps		struct nfs_readdir_args d;
78059853Sps	} sdata;
78159853Sps	static struct {
78259853Sps		n_long h[RPC_HEADER_WORDS];
78359853Sps		u_char d[NFS_READDIRSIZE];
78459853Sps	} rdata;
78559853Sps
786240780Smav	if (fp != pfp || fp->off != cookie) {
787240780Smav		pfp = NULL;
78859853Sps	refill:
78959853Sps		args = &sdata.d;
79059853Sps		bzero(args, sizeof(*args));
79159853Sps
79259853Sps		bcopy(fp->fh, args->fh, NFS_FHSIZE);
793240780Smav		args->cookie = htonl(fp->off);
79459853Sps		args->count  = htonl(NFS_READDIRSIZE);
795197178Semaste
79659853Sps		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
79759853Sps			      args, sizeof(*args),
79859853Sps			      rdata.d, sizeof(rdata.d));
79959853Sps		buf  = rdata.d;
80059853Sps		roff = (struct nfs_readdir_off *)buf;
80159853Sps		if (ntohl(roff->cookie) != 0)
802124811Sjhb			return EIO;
803240780Smav		pfp = fp;
804240780Smav		cookie = fp->off;
80559853Sps	}
80659853Sps	roff = (struct nfs_readdir_off *)buf;
80759853Sps
80859853Sps	if (ntohl(roff->follows) == 0) {
80959853Sps		eof = ntohl((roff+1)->cookie);
81059853Sps		if (eof) {
81159853Sps			cookie = 0;
812124811Sjhb			return ENOENT;
81359853Sps		}
81459853Sps		goto refill;
81559853Sps	}
81659853Sps
81759853Sps	buf += sizeof(struct nfs_readdir_off);
81859853Sps	rd = (struct nfs_readdir_data *)buf;
81959853Sps	d->d_namlen = ntohl(rd->len);
82059853Sps	bcopy(rd->name, d->d_name, d->d_namlen);
82159853Sps	d->d_name[d->d_namlen] = '\0';
82259853Sps
82359853Sps	buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
82459853Sps	roff = (struct nfs_readdir_off *)buf;
825240780Smav	fp->off = cookie = ntohl(roff->cookie);
82659853Sps	return 0;
82759853Sps}
828212125Srmacklem#else	/* !OLD_NFSV2 */
829212125Srmacklem/*
830212125Srmacklem * Fetch the root file handle (call mount daemon)
831212125Srmacklem * Return zero or error number.
832212125Srmacklem */
833212125Srmacklemint
834212125Srmacklemnfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
835212125Srmacklem{
836212125Srmacklem	int len;
837212125Srmacklem	struct args {
838212125Srmacklem		uint32_t len;
839212125Srmacklem		char path[FNAME_SIZE];
840212125Srmacklem	} *args;
841212125Srmacklem	struct repl {
842212125Srmacklem		uint32_t errno;
843212125Srmacklem		uint32_t fhsize;
844212125Srmacklem		u_char fh[NFS_V3MAXFHSIZE];
845212125Srmacklem		uint32_t authcnt;
846212125Srmacklem		uint32_t auth[7];
847212125Srmacklem	} *repl;
848212125Srmacklem	struct {
849212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
850212125Srmacklem		struct args d;
851212125Srmacklem	} sdata;
852212125Srmacklem	struct {
853212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
854212125Srmacklem		struct repl d;
855212125Srmacklem	} rdata;
856212125Srmacklem	size_t cc;
857212125Srmacklem
858212125Srmacklem#ifdef NFS_DEBUG
859212125Srmacklem	if (debug)
860212125Srmacklem		printf("nfs_getrootfh: %s\n", path);
861212125Srmacklem#endif
862212125Srmacklem
863212125Srmacklem	args = &sdata.d;
864212125Srmacklem	repl = &rdata.d;
865212125Srmacklem
866212125Srmacklem	bzero(args, sizeof(*args));
867212125Srmacklem	len = strlen(path);
868212125Srmacklem	if (len > sizeof(args->path))
869212125Srmacklem		len = sizeof(args->path);
870212125Srmacklem	args->len = htonl(len);
871212125Srmacklem	bcopy(path, args->path, len);
872212125Srmacklem	len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
873212125Srmacklem
874212125Srmacklem	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
875212125Srmacklem	    args, len, repl, sizeof(*repl));
876212125Srmacklem	if (cc == -1)
877212125Srmacklem		/* errno was set by rpc_call */
878212125Srmacklem		return (errno);
879212125Srmacklem	if (cc < 2 * sizeof (uint32_t))
880212125Srmacklem		return (EBADRPC);
881212125Srmacklem	if (repl->errno != 0)
882212125Srmacklem		return (ntohl(repl->errno));
883212125Srmacklem	*fhlenp = ntohl(repl->fhsize);
884212125Srmacklem	bcopy(repl->fh, fhp, *fhlenp);
885212125Srmacklem	return (0);
886212125Srmacklem}
887212125Srmacklem
888212125Srmacklem/*
889212125Srmacklem * Lookup a file.  Store handle and attributes.
890212125Srmacklem * Return zero or error number.
891212125Srmacklem */
892212125Srmacklemint
893212125Srmacklemnfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
894212125Srmacklem{
895212125Srmacklem	int len, rlen, pos;
896212125Srmacklem	struct args {
897212125Srmacklem		uint32_t fhsize;
898212125Srmacklem		uint32_t fhplusname[1 +
899212125Srmacklem		    (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
900212125Srmacklem	} *args;
901212125Srmacklem	struct repl {
902212125Srmacklem		uint32_t errno;
903212125Srmacklem		uint32_t fhsize;
904212125Srmacklem		uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
905212125Srmacklem		    2 * (sizeof(uint32_t) +
906212125Srmacklem		    sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
907212125Srmacklem	} *repl;
908212125Srmacklem	struct {
909212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
910212125Srmacklem		struct args d;
911212125Srmacklem	} sdata;
912212125Srmacklem	struct {
913212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
914212125Srmacklem		struct repl d;
915212125Srmacklem	} rdata;
916212125Srmacklem	ssize_t cc;
917212125Srmacklem
918212125Srmacklem#ifdef NFS_DEBUG
919212125Srmacklem	if (debug)
920212125Srmacklem		printf("lookupfh: called\n");
921212125Srmacklem#endif
922212125Srmacklem
923212125Srmacklem	args = &sdata.d;
924212125Srmacklem	repl = &rdata.d;
925212125Srmacklem
926212125Srmacklem	bzero(args, sizeof(*args));
927212125Srmacklem	args->fhsize = htonl(d->fhsize);
928212125Srmacklem	bcopy(d->fh, args->fhplusname, d->fhsize);
929212125Srmacklem	len = strlen(name);
930212125Srmacklem	if (len > FNAME_SIZE)
931212125Srmacklem		len = FNAME_SIZE;
932212125Srmacklem	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
933212125Srmacklem	args->fhplusname[pos++] = htonl(len);
934212125Srmacklem	bcopy(name, &args->fhplusname[pos], len);
935212125Srmacklem	len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
936212125Srmacklem	    roundup(len, sizeof(uint32_t));
937212125Srmacklem
938212125Srmacklem	rlen = sizeof(*repl);
939212125Srmacklem
940212125Srmacklem	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
941212125Srmacklem	    args, len, repl, rlen);
942212125Srmacklem	if (cc == -1)
943212125Srmacklem		return (errno);		/* XXX - from rpc_call */
944212125Srmacklem	if (cc < 2 * sizeof(uint32_t))
945212125Srmacklem		return (EIO);
946212125Srmacklem	if (repl->errno != 0)
947212125Srmacklem		/* saerrno.h now matches NFS error numbers. */
948212125Srmacklem		return (ntohl(repl->errno));
949212125Srmacklem	newfd->fhsize = ntohl(repl->fhsize);
950212125Srmacklem	bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
951212125Srmacklem	pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
952212125Srmacklem	if (repl->fhplusattr[pos++] == 0)
953212125Srmacklem		return (EIO);
954212125Srmacklem	bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
955212125Srmacklem	return (0);
956212125Srmacklem}
957212125Srmacklem
958212125Srmacklem#ifndef NFS_NOSYMLINK
959212125Srmacklem/*
960212125Srmacklem * Get the destination of a symbolic link.
961212125Srmacklem */
962212125Srmacklemint
963212125Srmacklemnfs_readlink(struct nfs_iodesc *d, char *buf)
964212125Srmacklem{
965212125Srmacklem	struct args {
966212125Srmacklem		uint32_t fhsize;
967212125Srmacklem		u_char fh[NFS_V3MAXFHSIZE];
968212125Srmacklem	} *args;
969212125Srmacklem	struct repl {
970212125Srmacklem		uint32_t errno;
971212125Srmacklem		uint32_t ok;
972212125Srmacklem		struct nfsv3_fattrs fa;
973212125Srmacklem		uint32_t len;
974212125Srmacklem		u_char path[NFS_MAXPATHLEN];
975212125Srmacklem	} *repl;
976212125Srmacklem	struct {
977212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
978212125Srmacklem		struct args d;
979212125Srmacklem	} sdata;
980212125Srmacklem	struct {
981212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
982212125Srmacklem		struct repl d;
983212125Srmacklem	} rdata;
984212125Srmacklem	ssize_t cc;
985212125Srmacklem
986212125Srmacklem#ifdef NFS_DEBUG
987212125Srmacklem	if (debug)
988212125Srmacklem		printf("readlink: called\n");
989212125Srmacklem#endif
990212125Srmacklem
991212125Srmacklem	args = &sdata.d;
992212125Srmacklem	repl = &rdata.d;
993212125Srmacklem
994212125Srmacklem	bzero(args, sizeof(*args));
995212125Srmacklem	args->fhsize = htonl(d->fhsize);
996212125Srmacklem	bcopy(d->fh, args->fh, d->fhsize);
997212125Srmacklem	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
998212125Srmacklem	    args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
999212125Srmacklem	    repl, sizeof(*repl));
1000212125Srmacklem	if (cc == -1)
1001212125Srmacklem		return (errno);
1002212125Srmacklem
1003212125Srmacklem	if (cc < 2 * sizeof(uint32_t))
1004212125Srmacklem		return (EIO);
1005212125Srmacklem
1006212125Srmacklem	if (repl->errno != 0)
1007212125Srmacklem		return (ntohl(repl->errno));
1008212125Srmacklem
1009212125Srmacklem	if (repl->ok == 0)
1010212125Srmacklem		return (EIO);
1011212125Srmacklem
1012212125Srmacklem	repl->len = ntohl(repl->len);
1013212125Srmacklem	if (repl->len > NFS_MAXPATHLEN)
1014212125Srmacklem		return (ENAMETOOLONG);
1015212125Srmacklem
1016212125Srmacklem	bcopy(repl->path, buf, repl->len);
1017212125Srmacklem	buf[repl->len] = 0;
1018212125Srmacklem	return (0);
1019212125Srmacklem}
1020212125Srmacklem#endif
1021212125Srmacklem
1022212125Srmacklem/*
1023212125Srmacklem * Read data from a file.
1024212125Srmacklem * Return transfer count or -1 (and set errno)
1025212125Srmacklem */
1026212125Srmacklemssize_t
1027212125Srmacklemnfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1028212125Srmacklem{
1029212125Srmacklem	struct args {
1030212125Srmacklem		uint32_t fhsize;
1031212125Srmacklem		uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1032212125Srmacklem	} *args;
1033212125Srmacklem	struct repl {
1034212125Srmacklem		uint32_t errno;
1035212125Srmacklem		uint32_t ok;
1036212125Srmacklem		struct nfsv3_fattrs fa;
1037212125Srmacklem		uint32_t count;
1038212125Srmacklem		uint32_t eof;
1039212125Srmacklem		uint32_t len;
1040307203Ssephe		u_char data[NFSREAD_MAX_SIZE];
1041212125Srmacklem	} *repl;
1042212125Srmacklem	struct {
1043212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
1044212125Srmacklem		struct args d;
1045212125Srmacklem	} sdata;
1046212125Srmacklem	struct {
1047212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
1048212125Srmacklem		struct repl d;
1049212125Srmacklem	} rdata;
1050212125Srmacklem	size_t cc;
1051212125Srmacklem	long x;
1052212125Srmacklem	int hlen, rlen, pos;
1053212125Srmacklem
1054212125Srmacklem	args = &sdata.d;
1055212125Srmacklem	repl = &rdata.d;
1056212125Srmacklem
1057212125Srmacklem	bzero(args, sizeof(*args));
1058212125Srmacklem	args->fhsize = htonl(d->fhsize);
1059212125Srmacklem	bcopy(d->fh, args->fhoffcnt, d->fhsize);
1060212125Srmacklem	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1061212125Srmacklem	args->fhoffcnt[pos++] = 0;
1062212125Srmacklem	args->fhoffcnt[pos++] = htonl((uint32_t)off);
1063307203Ssephe	if (len > nfs_read_size)
1064307203Ssephe		len = nfs_read_size;
1065212125Srmacklem	args->fhoffcnt[pos] = htonl((uint32_t)len);
1066307203Ssephe	hlen = offsetof(struct repl, data[0]);
1067212125Srmacklem
1068212125Srmacklem	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1069212125Srmacklem	    args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1070212125Srmacklem	    repl, sizeof(*repl));
1071212125Srmacklem	if (cc == -1)
1072212125Srmacklem		/* errno was already set by rpc_call */
1073212125Srmacklem		return (-1);
1074212125Srmacklem	if (cc < hlen) {
1075212125Srmacklem		errno = EBADRPC;
1076212125Srmacklem		return (-1);
1077212125Srmacklem	}
1078212125Srmacklem	if (repl->errno != 0) {
1079212125Srmacklem		errno = ntohl(repl->errno);
1080212125Srmacklem		return (-1);
1081212125Srmacklem	}
1082212125Srmacklem	rlen = cc - hlen;
1083212125Srmacklem	x = ntohl(repl->count);
1084212125Srmacklem	if (rlen < x) {
1085212125Srmacklem		printf("nfsread: short packet, %d < %ld\n", rlen, x);
1086212125Srmacklem		errno = EBADRPC;
1087212125Srmacklem		return (-1);
1088212125Srmacklem	}
1089212125Srmacklem	bcopy(repl->data, addr, x);
1090212125Srmacklem	return (x);
1091212125Srmacklem}
1092212125Srmacklem
1093212125Srmacklem/*
1094212125Srmacklem * Open a file.
1095212125Srmacklem * return zero or error number
1096212125Srmacklem */
1097212125Srmacklemint
1098212125Srmacklemnfs_open(const char *upath, struct open_file *f)
1099212125Srmacklem{
1100212125Srmacklem	struct iodesc *desc;
1101212125Srmacklem	struct nfs_iodesc *currfd;
1102212125Srmacklem	char buf[2 * NFS_V3MAXFHSIZE + 3];
1103212125Srmacklem	u_char *fh;
1104212125Srmacklem	char *cp;
1105212125Srmacklem	int i;
1106212125Srmacklem#ifndef NFS_NOSYMLINK
1107212125Srmacklem	struct nfs_iodesc *newfd;
1108212125Srmacklem	struct nfsv3_fattrs *fa;
1109212125Srmacklem	char *ncp;
1110212125Srmacklem	int c;
1111212125Srmacklem	char namebuf[NFS_MAXPATHLEN + 1];
1112212125Srmacklem	char linkbuf[NFS_MAXPATHLEN + 1];
1113212125Srmacklem	int nlinks = 0;
1114212125Srmacklem#endif
1115212125Srmacklem	int error;
1116212125Srmacklem	char *path;
1117212125Srmacklem
1118212125Srmacklem#ifdef NFS_DEBUG
1119212125Srmacklem 	if (debug)
1120212125Srmacklem 	    printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1121212125Srmacklem#endif
1122212125Srmacklem	if (!rootpath[0]) {
1123212125Srmacklem		printf("no rootpath, no nfs\n");
1124212125Srmacklem		return (ENXIO);
1125212125Srmacklem	}
1126212125Srmacklem
1127212125Srmacklem	/*
1128212125Srmacklem	 * This is silly - we should look at dv_type but that value is
1129212125Srmacklem	 * arch dependant and we can't use it here.
1130212125Srmacklem	 */
1131212125Srmacklem#ifndef __i386__
1132212125Srmacklem	if (strcmp(f->f_dev->dv_name, "net") != 0)
1133212125Srmacklem		return (EINVAL);
1134212125Srmacklem#else
1135212125Srmacklem	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1136212125Srmacklem		return (EINVAL);
1137212125Srmacklem#endif
1138212125Srmacklem
1139212125Srmacklem	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1140212125Srmacklem		return (EINVAL);
1141212125Srmacklem
1142212125Srmacklem	/* Bind to a reserved port. */
1143212125Srmacklem	desc->myport = htons(--rpc_port);
1144212125Srmacklem	desc->destip = rootip;
1145212125Srmacklem	if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1146212125Srmacklem	    nfs_root_node.fh)))
1147212125Srmacklem		return (error);
1148240774Smav	nfs_root_node.fa.fa_type  = htonl(NFDIR);
1149240774Smav	nfs_root_node.fa.fa_mode  = htonl(0755);
1150240774Smav	nfs_root_node.fa.fa_nlink = htonl(2);
1151212125Srmacklem	nfs_root_node.iodesc = desc;
1152212125Srmacklem
1153212125Srmacklem	fh = &nfs_root_node.fh[0];
1154212125Srmacklem	buf[0] = 'X';
1155212125Srmacklem	cp = &buf[1];
1156212125Srmacklem	for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1157212125Srmacklem		sprintf(cp, "%02x", fh[i]);
1158212125Srmacklem	sprintf(cp, "X");
1159212125Srmacklem	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
1160212125Srmacklem	setenv("boot.nfsroot.path", rootpath, 1);
1161212125Srmacklem	setenv("boot.nfsroot.nfshandle", buf, 1);
1162212125Srmacklem	sprintf(buf, "%d", nfs_root_node.fhsize);
1163212125Srmacklem	setenv("boot.nfsroot.nfshandlelen", buf, 1);
1164212125Srmacklem
1165240774Smav	/* Allocate file system specific data structure */
1166240774Smav	currfd = malloc(sizeof(*newfd));
1167240774Smav	if (currfd == NULL) {
1168240774Smav		error = ENOMEM;
1169240774Smav		goto out;
1170240774Smav	}
1171212125Srmacklem#ifndef NFS_NOSYMLINK
1172240774Smav	bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1173212125Srmacklem	newfd = 0;
1174212125Srmacklem
1175212125Srmacklem	cp = path = strdup(upath);
1176212125Srmacklem	if (path == NULL) {
1177212125Srmacklem		error = ENOMEM;
1178212125Srmacklem		goto out;
1179212125Srmacklem	}
1180212125Srmacklem	while (*cp) {
1181212125Srmacklem		/*
1182212125Srmacklem		 * Remove extra separators
1183212125Srmacklem		 */
1184212125Srmacklem		while (*cp == '/')
1185212125Srmacklem			cp++;
1186212125Srmacklem
1187212125Srmacklem		if (*cp == '\0')
1188212125Srmacklem			break;
1189212125Srmacklem		/*
1190212125Srmacklem		 * Check that current node is a directory.
1191212125Srmacklem		 */
1192212125Srmacklem		if (currfd->fa.fa_type != htonl(NFDIR)) {
1193212125Srmacklem			error = ENOTDIR;
1194212125Srmacklem			goto out;
1195212125Srmacklem		}
1196212125Srmacklem
1197212125Srmacklem		/* allocate file system specific data structure */
1198212125Srmacklem		newfd = malloc(sizeof(*newfd));
1199212125Srmacklem		if (newfd == NULL) {
1200212125Srmacklem			error = ENOMEM;
1201212125Srmacklem			goto out;
1202212125Srmacklem		}
1203212125Srmacklem		newfd->iodesc = currfd->iodesc;
1204212125Srmacklem
1205212125Srmacklem		/*
1206212125Srmacklem		 * Get next component of path name.
1207212125Srmacklem		 */
1208212125Srmacklem		{
1209212125Srmacklem			int len = 0;
1210212125Srmacklem
1211212125Srmacklem			ncp = cp;
1212212125Srmacklem			while ((c = *cp) != '\0' && c != '/') {
1213212125Srmacklem				if (++len > NFS_MAXNAMLEN) {
1214212125Srmacklem					error = ENOENT;
1215212125Srmacklem					goto out;
1216212125Srmacklem				}
1217212125Srmacklem				cp++;
1218212125Srmacklem			}
1219212125Srmacklem			*cp = '\0';
1220212125Srmacklem		}
1221212125Srmacklem
1222212125Srmacklem		/* lookup a file handle */
1223212125Srmacklem		error = nfs_lookupfh(currfd, ncp, newfd);
1224212125Srmacklem		*cp = c;
1225212125Srmacklem		if (error)
1226212125Srmacklem			goto out;
1227212125Srmacklem
1228212125Srmacklem		/*
1229212125Srmacklem		 * Check for symbolic link
1230212125Srmacklem		 */
1231212125Srmacklem		if (newfd->fa.fa_type == htonl(NFLNK)) {
1232212125Srmacklem			int link_len, len;
1233212125Srmacklem
1234212125Srmacklem			error = nfs_readlink(newfd, linkbuf);
1235212125Srmacklem			if (error)
1236212125Srmacklem				goto out;
1237212125Srmacklem
1238212125Srmacklem			link_len = strlen(linkbuf);
1239212125Srmacklem			len = strlen(cp);
1240212125Srmacklem
1241212125Srmacklem			if (link_len + len > MAXPATHLEN
1242212125Srmacklem			    || ++nlinks > MAXSYMLINKS) {
1243212125Srmacklem				error = ENOENT;
1244212125Srmacklem				goto out;
1245212125Srmacklem			}
1246212125Srmacklem
1247212125Srmacklem			bcopy(cp, &namebuf[link_len], len + 1);
1248212125Srmacklem			bcopy(linkbuf, namebuf, link_len);
1249212125Srmacklem
1250212125Srmacklem			/*
1251212125Srmacklem			 * If absolute pathname, restart at root.
1252212125Srmacklem			 * If relative pathname, restart at parent directory.
1253212125Srmacklem			 */
1254212125Srmacklem			cp = namebuf;
1255240774Smav			if (*cp == '/')
1256240774Smav				bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1257212125Srmacklem
1258212125Srmacklem			free(newfd);
1259212125Srmacklem			newfd = 0;
1260212125Srmacklem
1261212125Srmacklem			continue;
1262212125Srmacklem		}
1263212125Srmacklem
1264240774Smav		free(currfd);
1265212125Srmacklem		currfd = newfd;
1266212125Srmacklem		newfd = 0;
1267212125Srmacklem	}
1268212125Srmacklem
1269212125Srmacklem	error = 0;
1270212125Srmacklem
1271212125Srmacklemout:
1272240881Skevlo	free(newfd);
1273240881Skevlo	free(path);
1274212125Srmacklem#else
1275240774Smav	currfd->iodesc = desc;
1276212125Srmacklem
1277240774Smav	error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1278212125Srmacklem#endif
1279212125Srmacklem	if (!error) {
1280240774Smav		currfd->off = 0;
1281240780Smav		currfd->cookie = 0;
1282212125Srmacklem		f->f_fsdata = (void *)currfd;
1283212125Srmacklem		return (0);
1284212125Srmacklem	}
1285212125Srmacklem
1286212125Srmacklem#ifdef NFS_DEBUG
1287212125Srmacklem	if (debug)
1288212125Srmacklem		printf("nfs_open: %s lookupfh failed: %s\n",
1289212125Srmacklem		    path, strerror(error));
1290212125Srmacklem#endif
1291240774Smav	free(currfd);
1292212125Srmacklem
1293212125Srmacklem	return (error);
1294212125Srmacklem}
1295212125Srmacklem
1296212125Srmacklemint
1297212125Srmacklemnfs_close(struct open_file *f)
1298212125Srmacklem{
1299212125Srmacklem	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1300212125Srmacklem
1301212125Srmacklem#ifdef NFS_DEBUG
1302212125Srmacklem	if (debug)
1303212125Srmacklem		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1304212125Srmacklem#endif
1305212125Srmacklem
1306240774Smav	if (fp)
1307212125Srmacklem		free(fp);
1308212125Srmacklem	f->f_fsdata = (void *)0;
1309212125Srmacklem
1310212125Srmacklem	return (0);
1311212125Srmacklem}
1312212125Srmacklem
1313212125Srmacklem/*
1314212125Srmacklem * read a portion of a file
1315212125Srmacklem */
1316212125Srmacklemint
1317212125Srmacklemnfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1318212125Srmacklem{
1319212125Srmacklem	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1320212125Srmacklem	ssize_t cc;
1321212125Srmacklem	char *addr = buf;
1322212125Srmacklem
1323212125Srmacklem#ifdef NFS_DEBUG
1324212125Srmacklem	if (debug)
1325212125Srmacklem		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1326212125Srmacklem		       (int)fp->off);
1327212125Srmacklem#endif
1328212125Srmacklem	while ((int)size > 0) {
1329278602Sian		twiddle(16);
1330212125Srmacklem		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1331212125Srmacklem		/* XXX maybe should retry on certain errors */
1332212125Srmacklem		if (cc == -1) {
1333212125Srmacklem#ifdef NFS_DEBUG
1334212125Srmacklem			if (debug)
1335212125Srmacklem				printf("nfs_read: read: %s", strerror(errno));
1336212125Srmacklem#endif
1337212125Srmacklem			return (errno);	/* XXX - from nfs_readdata */
1338212125Srmacklem		}
1339212125Srmacklem		if (cc == 0) {
1340212125Srmacklem#ifdef NFS_DEBUG
1341212125Srmacklem			if (debug)
1342212125Srmacklem				printf("nfs_read: hit EOF unexpectantly");
1343212125Srmacklem#endif
1344212125Srmacklem			goto ret;
1345212125Srmacklem		}
1346212125Srmacklem		fp->off += cc;
1347212125Srmacklem		addr += cc;
1348212125Srmacklem		size -= cc;
1349212125Srmacklem	}
1350212125Srmacklemret:
1351212125Srmacklem	if (resid)
1352212125Srmacklem		*resid = size;
1353212125Srmacklem
1354212125Srmacklem	return (0);
1355212125Srmacklem}
1356212125Srmacklem
1357212125Srmacklem/*
1358212125Srmacklem * Not implemented.
1359212125Srmacklem */
1360212125Srmacklemint
1361212125Srmacklemnfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1362212125Srmacklem{
1363212125Srmacklem	return (EROFS);
1364212125Srmacklem}
1365212125Srmacklem
1366212125Srmacklemoff_t
1367212125Srmacklemnfs_seek(struct open_file *f, off_t offset, int where)
1368212125Srmacklem{
1369212125Srmacklem	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1370212125Srmacklem	uint32_t size = ntohl(d->fa.fa_size.val[1]);
1371212125Srmacklem
1372212125Srmacklem	switch (where) {
1373212125Srmacklem	case SEEK_SET:
1374212125Srmacklem		d->off = offset;
1375212125Srmacklem		break;
1376212125Srmacklem	case SEEK_CUR:
1377212125Srmacklem		d->off += offset;
1378212125Srmacklem		break;
1379212125Srmacklem	case SEEK_END:
1380212125Srmacklem		d->off = size - offset;
1381212125Srmacklem		break;
1382212125Srmacklem	default:
1383212125Srmacklem		errno = EINVAL;
1384212125Srmacklem		return (-1);
1385212125Srmacklem	}
1386212125Srmacklem
1387212125Srmacklem	return (d->off);
1388212125Srmacklem}
1389212125Srmacklem
1390212125Srmacklem/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1391212125Srmacklemint nfs_stat_types[9] = {
1392212125Srmacklem	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1393212125Srmacklem
1394212125Srmacklemint
1395212125Srmacklemnfs_stat(struct open_file *f, struct stat *sb)
1396212125Srmacklem{
1397212125Srmacklem	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1398212125Srmacklem	uint32_t ftype, mode;
1399212125Srmacklem
1400212125Srmacklem	ftype = ntohl(fp->fa.fa_type);
1401212125Srmacklem	mode  = ntohl(fp->fa.fa_mode);
1402212125Srmacklem	mode |= nfs_stat_types[ftype & 7];
1403212125Srmacklem
1404212125Srmacklem	sb->st_mode  = mode;
1405212125Srmacklem	sb->st_nlink = ntohl(fp->fa.fa_nlink);
1406212125Srmacklem	sb->st_uid   = ntohl(fp->fa.fa_uid);
1407212125Srmacklem	sb->st_gid   = ntohl(fp->fa.fa_gid);
1408212125Srmacklem	sb->st_size  = ntohl(fp->fa.fa_size.val[1]);
1409212125Srmacklem
1410212125Srmacklem	return (0);
1411212125Srmacklem}
1412212125Srmacklem
1413212125Srmacklemstatic int
1414212125Srmacklemnfs_readdir(struct open_file *f, struct dirent *d)
1415212125Srmacklem{
1416212125Srmacklem	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1417212125Srmacklem	struct nfsv3_readdir_repl *repl;
1418212125Srmacklem	struct nfsv3_readdir_entry *rent;
1419212125Srmacklem	static char *buf;
1420240780Smav	static struct nfs_iodesc *pfp = NULL;
1421240780Smav	static uint64_t cookie = 0;
1422212125Srmacklem	size_t cc;
1423212125Srmacklem	int pos;
1424212125Srmacklem
1425212125Srmacklem	struct args {
1426212125Srmacklem		uint32_t fhsize;
1427212125Srmacklem		uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1428212125Srmacklem	} *args;
1429212125Srmacklem	struct {
1430212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
1431212125Srmacklem		struct args d;
1432212125Srmacklem	} sdata;
1433212125Srmacklem	static struct {
1434212125Srmacklem		uint32_t h[RPC_HEADER_WORDS];
1435212125Srmacklem		u_char d[NFS_READDIRSIZE];
1436212125Srmacklem	} rdata;
1437212125Srmacklem
1438240780Smav	if (fp != pfp || fp->off != cookie) {
1439240780Smav		pfp = NULL;
1440212125Srmacklem	refill:
1441212125Srmacklem		args = &sdata.d;
1442212125Srmacklem		bzero(args, sizeof(*args));
1443212125Srmacklem
1444212125Srmacklem		args->fhsize = htonl(fp->fhsize);
1445212125Srmacklem		bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1446212125Srmacklem		pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1447240780Smav		args->fhpluscookie[pos++] = htonl(fp->off >> 32);
1448240780Smav		args->fhpluscookie[pos++] = htonl(fp->off);
1449240780Smav		args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
1450240780Smav		args->fhpluscookie[pos++] = htonl(fp->cookie);
1451212125Srmacklem		args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1452212125Srmacklem
1453212125Srmacklem		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1454212125Srmacklem		    args, 6 * sizeof(uint32_t) +
1455212125Srmacklem		    roundup(fp->fhsize, sizeof(uint32_t)),
1456212125Srmacklem		    rdata.d, sizeof(rdata.d));
1457212125Srmacklem		buf  = rdata.d;
1458212125Srmacklem		repl = (struct nfsv3_readdir_repl *)buf;
1459212125Srmacklem		if (repl->errno != 0)
1460212125Srmacklem			return (ntohl(repl->errno));
1461240780Smav		pfp = fp;
1462240780Smav		cookie = fp->off;
1463240780Smav		fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
1464240780Smav		    ntohl(repl->cookiev1);
1465212125Srmacklem		buf += sizeof (struct nfsv3_readdir_repl);
1466212125Srmacklem	}
1467212125Srmacklem	rent = (struct nfsv3_readdir_entry *)buf;
1468212125Srmacklem
1469212125Srmacklem	if (rent->follows == 0) {
1470212125Srmacklem		/* fid0 is actually eof */
1471212125Srmacklem		if (rent->fid0 != 0) {
1472240780Smav			cookie = 0;
1473212125Srmacklem			return (ENOENT);
1474212125Srmacklem		}
1475212125Srmacklem		goto refill;
1476212125Srmacklem	}
1477212125Srmacklem
1478212125Srmacklem	d->d_namlen = ntohl(rent->len);
1479212125Srmacklem	bcopy(rent->nameplus, d->d_name, d->d_namlen);
1480212125Srmacklem	d->d_name[d->d_namlen] = '\0';
1481212125Srmacklem
1482212125Srmacklem	pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1483252468Smav	fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
1484252468Smav	    ntohl(rent->nameplus[pos + 1]);
1485252468Smav	pos += 2;
1486212125Srmacklem	buf = (u_char *)&rent->nameplus[pos];
1487212125Srmacklem	return (0);
1488212125Srmacklem}
1489212125Srmacklem#endif	/* OLD_NFSV2 */
1490