xref: /titanic_51/usr/src/boot/lib/libstand/nfs.c (revision dd8e2f72a62767f0af8754a9ad0513fc69316fea)
14a5d661aSToomas Soome /*	$NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $	*/
24a5d661aSToomas Soome 
34a5d661aSToomas Soome /*-
44a5d661aSToomas Soome  *  Copyright (c) 1993 John Brezak
54a5d661aSToomas Soome  *  All rights reserved.
64a5d661aSToomas Soome  *
74a5d661aSToomas Soome  *  Redistribution and use in source and binary forms, with or without
84a5d661aSToomas Soome  *  modification, are permitted provided that the following conditions
94a5d661aSToomas Soome  *  are met:
104a5d661aSToomas Soome  *  1. Redistributions of source code must retain the above copyright
114a5d661aSToomas Soome  *     notice, this list of conditions and the following disclaimer.
124a5d661aSToomas Soome  *  2. Redistributions in binary form must reproduce the above copyright
134a5d661aSToomas Soome  *     notice, this list of conditions and the following disclaimer in the
144a5d661aSToomas Soome  *     documentation and/or other materials provided with the distribution.
154a5d661aSToomas Soome  *  3. The name of the author may not be used to endorse or promote products
164a5d661aSToomas Soome  *     derived from this software without specific prior written permission.
174a5d661aSToomas Soome  *
184a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
194a5d661aSToomas Soome  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
204a5d661aSToomas Soome  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
214a5d661aSToomas Soome  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
224a5d661aSToomas Soome  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
234a5d661aSToomas Soome  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
244a5d661aSToomas Soome  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
254a5d661aSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
264a5d661aSToomas Soome  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
274a5d661aSToomas Soome  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
284a5d661aSToomas Soome  * POSSIBILITY OF SUCH DAMAGE.
294a5d661aSToomas Soome  */
304a5d661aSToomas Soome 
314a5d661aSToomas Soome #include <sys/cdefs.h>
324a5d661aSToomas Soome 
334a5d661aSToomas Soome #include <sys/param.h>
344a5d661aSToomas Soome #include <sys/time.h>
354a5d661aSToomas Soome #include <sys/socket.h>
364a5d661aSToomas Soome #include <sys/stat.h>
374a5d661aSToomas Soome #include <string.h>
38*dd8e2f72SToomas Soome #include <stddef.h>
394a5d661aSToomas Soome 
404a5d661aSToomas Soome #include <netinet/in.h>
414a5d661aSToomas Soome #include <netinet/in_systm.h>
424a5d661aSToomas Soome 
434a5d661aSToomas Soome #include "rpcv2.h"
444a5d661aSToomas Soome #include "nfsv2.h"
454a5d661aSToomas Soome 
464a5d661aSToomas Soome #include "stand.h"
474a5d661aSToomas Soome #include "net.h"
484a5d661aSToomas Soome #include "netif.h"
494a5d661aSToomas Soome #include "rpc.h"
504a5d661aSToomas Soome 
514a5d661aSToomas Soome #define NFS_DEBUGxx
524a5d661aSToomas Soome 
53*dd8e2f72SToomas Soome #define NFSREAD_MIN_SIZE 1024
54*dd8e2f72SToomas Soome #define NFSREAD_MAX_SIZE 4096
554a5d661aSToomas Soome 
564a5d661aSToomas Soome /* Define our own NFS attributes without NQNFS stuff. */
574a5d661aSToomas Soome #ifdef OLD_NFSV2
584a5d661aSToomas Soome struct nfsv2_fattrs {
594a5d661aSToomas Soome 	n_long	fa_type;
604a5d661aSToomas Soome 	n_long	fa_mode;
614a5d661aSToomas Soome 	n_long	fa_nlink;
624a5d661aSToomas Soome 	n_long	fa_uid;
634a5d661aSToomas Soome 	n_long	fa_gid;
644a5d661aSToomas Soome 	n_long	fa_size;
654a5d661aSToomas Soome 	n_long	fa_blocksize;
664a5d661aSToomas Soome 	n_long	fa_rdev;
674a5d661aSToomas Soome 	n_long	fa_blocks;
684a5d661aSToomas Soome 	n_long	fa_fsid;
694a5d661aSToomas Soome 	n_long	fa_fileid;
704a5d661aSToomas Soome 	struct nfsv2_time fa_atime;
714a5d661aSToomas Soome 	struct nfsv2_time fa_mtime;
724a5d661aSToomas Soome 	struct nfsv2_time fa_ctime;
734a5d661aSToomas Soome };
744a5d661aSToomas Soome 
754a5d661aSToomas Soome struct nfs_read_args {
764a5d661aSToomas Soome 	u_char	fh[NFS_FHSIZE];
774a5d661aSToomas Soome 	n_long	off;
784a5d661aSToomas Soome 	n_long	len;
794a5d661aSToomas Soome 	n_long	xxx;			/* XXX what's this for? */
804a5d661aSToomas Soome };
814a5d661aSToomas Soome 
824a5d661aSToomas Soome /* Data part of nfs rpc reply (also the largest thing we receive) */
834a5d661aSToomas Soome struct nfs_read_repl {
844a5d661aSToomas Soome 	n_long	errno;
854a5d661aSToomas Soome 	struct	nfsv2_fattrs fa;
864a5d661aSToomas Soome 	n_long	count;
87*dd8e2f72SToomas Soome 	u_char	data[NFSREAD_MAX_SIZE];
884a5d661aSToomas Soome };
894a5d661aSToomas Soome 
904a5d661aSToomas Soome #ifndef NFS_NOSYMLINK
914a5d661aSToomas Soome struct nfs_readlnk_repl {
924a5d661aSToomas Soome 	n_long	errno;
934a5d661aSToomas Soome 	n_long	len;
944a5d661aSToomas Soome 	char	path[NFS_MAXPATHLEN];
954a5d661aSToomas Soome };
964a5d661aSToomas Soome #endif
974a5d661aSToomas Soome 
984a5d661aSToomas Soome struct nfs_readdir_args {
994a5d661aSToomas Soome 	u_char	fh[NFS_FHSIZE];
1004a5d661aSToomas Soome 	n_long	cookie;
1014a5d661aSToomas Soome 	n_long	count;
1024a5d661aSToomas Soome };
1034a5d661aSToomas Soome 
1044a5d661aSToomas Soome struct nfs_readdir_data {
1054a5d661aSToomas Soome 	n_long	fileid;
1064a5d661aSToomas Soome 	n_long	len;
1074a5d661aSToomas Soome 	char	name[0];
1084a5d661aSToomas Soome };
1094a5d661aSToomas Soome 
1104a5d661aSToomas Soome struct nfs_readdir_off {
1114a5d661aSToomas Soome 	n_long	cookie;
1124a5d661aSToomas Soome 	n_long	follows;
1134a5d661aSToomas Soome };
1144a5d661aSToomas Soome 
1154a5d661aSToomas Soome struct nfs_iodesc {
1164a5d661aSToomas Soome 	struct	iodesc	*iodesc;
1174a5d661aSToomas Soome 	off_t	off;
1184a5d661aSToomas Soome 	u_char	fh[NFS_FHSIZE];
1194a5d661aSToomas Soome 	struct nfsv2_fattrs fa;	/* all in network order */
1204a5d661aSToomas Soome };
1214a5d661aSToomas Soome #else	/* !OLD_NFSV2 */
1224a5d661aSToomas Soome 
1234a5d661aSToomas Soome /* NFSv3 definitions */
1244a5d661aSToomas Soome #define	NFS_V3MAXFHSIZE		64
1254a5d661aSToomas Soome #define	NFS_VER3		3
1264a5d661aSToomas Soome #define	RPCMNT_VER3		3
1274a5d661aSToomas Soome #define	NFSPROCV3_LOOKUP	3
1284a5d661aSToomas Soome #define	NFSPROCV3_READLINK	5
1294a5d661aSToomas Soome #define	NFSPROCV3_READ		6
1304a5d661aSToomas Soome #define	NFSPROCV3_READDIR	16
1314a5d661aSToomas Soome 
1324a5d661aSToomas Soome typedef struct {
1334a5d661aSToomas Soome 	uint32_t val[2];
1344a5d661aSToomas Soome } n_quad;
1354a5d661aSToomas Soome 
1364a5d661aSToomas Soome struct nfsv3_time {
1374a5d661aSToomas Soome 	uint32_t nfs_sec;
1384a5d661aSToomas Soome 	uint32_t nfs_nsec;
1394a5d661aSToomas Soome };
1404a5d661aSToomas Soome 
1414a5d661aSToomas Soome struct nfsv3_fattrs {
1424a5d661aSToomas Soome 	uint32_t fa_type;
1434a5d661aSToomas Soome 	uint32_t fa_mode;
1444a5d661aSToomas Soome 	uint32_t fa_nlink;
1454a5d661aSToomas Soome 	uint32_t fa_uid;
1464a5d661aSToomas Soome 	uint32_t fa_gid;
1474a5d661aSToomas Soome 	n_quad fa_size;
1484a5d661aSToomas Soome 	n_quad fa_used;
1494a5d661aSToomas Soome 	n_quad fa_rdev;
1504a5d661aSToomas Soome 	n_quad fa_fsid;
1514a5d661aSToomas Soome 	n_quad fa_fileid;
1524a5d661aSToomas Soome 	struct nfsv3_time fa_atime;
1534a5d661aSToomas Soome 	struct nfsv3_time fa_mtime;
1544a5d661aSToomas Soome 	struct nfsv3_time fa_ctime;
1554a5d661aSToomas Soome };
1564a5d661aSToomas Soome 
1574a5d661aSToomas Soome /*
1584a5d661aSToomas Soome  * For NFSv3, the file handle is variable in size, so most fixed sized
1594a5d661aSToomas Soome  * structures for arguments won't work. For most cases, a structure
1604a5d661aSToomas Soome  * that starts with any fixed size section is followed by an array
1614a5d661aSToomas Soome  * that covers the maximum size required.
1624a5d661aSToomas Soome  */
1634a5d661aSToomas Soome struct nfsv3_readdir_repl {
1644a5d661aSToomas Soome 	uint32_t errno;
1654a5d661aSToomas Soome 	uint32_t ok;
1664a5d661aSToomas Soome 	struct nfsv3_fattrs fa;
1674a5d661aSToomas Soome 	uint32_t cookiev0;
1684a5d661aSToomas Soome 	uint32_t cookiev1;
1694a5d661aSToomas Soome };
1704a5d661aSToomas Soome 
1714a5d661aSToomas Soome struct nfsv3_readdir_entry {
1724a5d661aSToomas Soome 	uint32_t follows;
1734a5d661aSToomas Soome 	uint32_t fid0;
1744a5d661aSToomas Soome 	uint32_t fid1;
1754a5d661aSToomas Soome 	uint32_t len;
1764a5d661aSToomas Soome 	uint32_t nameplus[0];
1774a5d661aSToomas Soome };
1784a5d661aSToomas Soome 
1794a5d661aSToomas Soome struct nfs_iodesc {
1804a5d661aSToomas Soome 	struct iodesc *iodesc;
1814a5d661aSToomas Soome 	off_t off;
1824a5d661aSToomas Soome 	uint32_t fhsize;
1834a5d661aSToomas Soome 	u_char fh[NFS_V3MAXFHSIZE];
1844a5d661aSToomas Soome 	struct nfsv3_fattrs fa;	/* all in network order */
1854a5d661aSToomas Soome 	uint64_t cookie;
1864a5d661aSToomas Soome };
1874a5d661aSToomas Soome #endif	/* OLD_NFSV2 */
1884a5d661aSToomas Soome 
1894a5d661aSToomas Soome /*
1904a5d661aSToomas Soome  * XXX interactions with tftp? See nfswrapper.c for a confusing
1914a5d661aSToomas Soome  *     issue.
1924a5d661aSToomas Soome  */
1934a5d661aSToomas Soome int		nfs_open(const char *path, struct open_file *f);
1944a5d661aSToomas Soome static int	nfs_close(struct open_file *f);
1954a5d661aSToomas Soome static int	nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
1964a5d661aSToomas Soome static int	nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
1974a5d661aSToomas Soome static off_t	nfs_seek(struct open_file *f, off_t offset, int where);
1984a5d661aSToomas Soome static int	nfs_stat(struct open_file *f, struct stat *sb);
1994a5d661aSToomas Soome static int	nfs_readdir(struct open_file *f, struct dirent *d);
2004a5d661aSToomas Soome 
2014a5d661aSToomas Soome struct	nfs_iodesc nfs_root_node;
2024a5d661aSToomas Soome 
2034a5d661aSToomas Soome struct fs_ops nfs_fsops = {
2044a5d661aSToomas Soome 	"nfs",
2054a5d661aSToomas Soome 	nfs_open,
2064a5d661aSToomas Soome 	nfs_close,
2074a5d661aSToomas Soome 	nfs_read,
2084a5d661aSToomas Soome 	nfs_write,
2094a5d661aSToomas Soome 	nfs_seek,
2104a5d661aSToomas Soome 	nfs_stat,
2114a5d661aSToomas Soome 	nfs_readdir
2124a5d661aSToomas Soome };
2134a5d661aSToomas Soome 
214*dd8e2f72SToomas Soome static int nfs_read_size = NFSREAD_MIN_SIZE;
215*dd8e2f72SToomas Soome 
216*dd8e2f72SToomas Soome /*
217*dd8e2f72SToomas Soome  * Improve boot performance over NFS
218*dd8e2f72SToomas Soome  */
219*dd8e2f72SToomas Soome static void
220*dd8e2f72SToomas Soome set_nfs_read_size(void)
221*dd8e2f72SToomas Soome {
222*dd8e2f72SToomas Soome 	char *env, *end;
223*dd8e2f72SToomas Soome 	char buf[10];
224*dd8e2f72SToomas Soome 
225*dd8e2f72SToomas Soome 	if ((env = getenv("nfs.read_size")) != NULL) {
226*dd8e2f72SToomas Soome 		errno = 0;
227*dd8e2f72SToomas Soome 		nfs_read_size = strtol(env, &end, 0);
228*dd8e2f72SToomas Soome 		if (errno != 0 || *env == '\0' || *end != '\0') {
229*dd8e2f72SToomas Soome 			printf("%s: bad value: \"%s\", defaulting to %d\n",
230*dd8e2f72SToomas Soome 			    "nfs.read_size", env, NFSREAD_MIN_SIZE);
231*dd8e2f72SToomas Soome 			nfs_read_size = NFSREAD_MIN_SIZE;
232*dd8e2f72SToomas Soome 		}
233*dd8e2f72SToomas Soome 	}
234*dd8e2f72SToomas Soome 	if (nfs_read_size < NFSREAD_MIN_SIZE) {
235*dd8e2f72SToomas Soome 		printf("%s: bad value: \"%d\", defaulting to %d\n",
236*dd8e2f72SToomas Soome 		    "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE);
237*dd8e2f72SToomas Soome 		nfs_read_size = NFSREAD_MIN_SIZE;
238*dd8e2f72SToomas Soome 	}
239*dd8e2f72SToomas Soome 	if (nfs_read_size > NFSREAD_MAX_SIZE) {
240*dd8e2f72SToomas Soome 		printf("%s: bad value: \"%d\", defaulting to %d\n",
241*dd8e2f72SToomas Soome 		    "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE);
242*dd8e2f72SToomas Soome 		nfs_read_size = NFSREAD_MAX_SIZE;
243*dd8e2f72SToomas Soome 	}
244*dd8e2f72SToomas Soome 	snprintf(buf, sizeof (buf), "%d", nfs_read_size);
245*dd8e2f72SToomas Soome 	setenv("nfs.read_size", buf, 1);
246*dd8e2f72SToomas Soome }
247*dd8e2f72SToomas Soome 
2484a5d661aSToomas Soome #ifdef	OLD_NFSV2
2494a5d661aSToomas Soome /*
2504a5d661aSToomas Soome  * Fetch the root file handle (call mount daemon)
2514a5d661aSToomas Soome  * Return zero or error number.
2524a5d661aSToomas Soome  */
2534a5d661aSToomas Soome int
2544a5d661aSToomas Soome nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
2554a5d661aSToomas Soome {
2564a5d661aSToomas Soome 	int len;
2574a5d661aSToomas Soome 	struct args {
2584a5d661aSToomas Soome 		n_long	len;
2594a5d661aSToomas Soome 		char	path[FNAME_SIZE];
2604a5d661aSToomas Soome 	} *args;
2614a5d661aSToomas Soome 	struct repl {
2624a5d661aSToomas Soome 		n_long	errno;
2634a5d661aSToomas Soome 		u_char	fh[NFS_FHSIZE];
2644a5d661aSToomas Soome 	} *repl;
2654a5d661aSToomas Soome 	struct {
2664a5d661aSToomas Soome 		n_long	h[RPC_HEADER_WORDS];
2674a5d661aSToomas Soome 		struct args d;
2684a5d661aSToomas Soome 	} sdata;
2694a5d661aSToomas Soome 	struct {
2704a5d661aSToomas Soome 		n_long	h[RPC_HEADER_WORDS];
2714a5d661aSToomas Soome 		struct repl d;
2724a5d661aSToomas Soome 	} rdata;
2734a5d661aSToomas Soome 	size_t cc;
2744a5d661aSToomas Soome 
2754a5d661aSToomas Soome #ifdef NFS_DEBUG
2764a5d661aSToomas Soome 	if (debug)
2774a5d661aSToomas Soome 		printf("nfs_getrootfh: %s\n", path);
2784a5d661aSToomas Soome #endif
2794a5d661aSToomas Soome 
2804a5d661aSToomas Soome 	args = &sdata.d;
2814a5d661aSToomas Soome 	repl = &rdata.d;
2824a5d661aSToomas Soome 
2834a5d661aSToomas Soome 	bzero(args, sizeof(*args));
2844a5d661aSToomas Soome 	len = strlen(path);
2854a5d661aSToomas Soome 	if (len > sizeof(args->path))
2864a5d661aSToomas Soome 		len = sizeof(args->path);
2874a5d661aSToomas Soome 	args->len = htonl(len);
2884a5d661aSToomas Soome 	bcopy(path, args->path, len);
2894a5d661aSToomas Soome 	len = 4 + roundup(len, 4);
2904a5d661aSToomas Soome 
2914a5d661aSToomas Soome 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
2924a5d661aSToomas Soome 	    args, len, repl, sizeof(*repl));
2934a5d661aSToomas Soome 	if (cc == -1) {
2944a5d661aSToomas Soome 		/* errno was set by rpc_call */
2954a5d661aSToomas Soome 		return (errno);
2964a5d661aSToomas Soome 	}
2974a5d661aSToomas Soome 	if (cc < 4)
2984a5d661aSToomas Soome 		return (EBADRPC);
2994a5d661aSToomas Soome 	if (repl->errno)
3004a5d661aSToomas Soome 		return (ntohl(repl->errno));
3014a5d661aSToomas Soome 	bcopy(repl->fh, fhp, sizeof(repl->fh));
302*dd8e2f72SToomas Soome 
303*dd8e2f72SToomas Soome 	set_nfs_read_size();
3044a5d661aSToomas Soome 	return (0);
3054a5d661aSToomas Soome }
3064a5d661aSToomas Soome 
3074a5d661aSToomas Soome /*
3084a5d661aSToomas Soome  * Lookup a file.  Store handle and attributes.
3094a5d661aSToomas Soome  * Return zero or error number.
3104a5d661aSToomas Soome  */
3114a5d661aSToomas Soome int
3124a5d661aSToomas Soome nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
3134a5d661aSToomas Soome {
3144a5d661aSToomas Soome 	int len, rlen;
3154a5d661aSToomas Soome 	struct args {
3164a5d661aSToomas Soome 		u_char	fh[NFS_FHSIZE];
3174a5d661aSToomas Soome 		n_long	len;
3184a5d661aSToomas Soome 		char	name[FNAME_SIZE];
3194a5d661aSToomas Soome 	} *args;
3204a5d661aSToomas Soome 	struct repl {
3214a5d661aSToomas Soome 		n_long	errno;
3224a5d661aSToomas Soome 		u_char	fh[NFS_FHSIZE];
3234a5d661aSToomas Soome 		struct	nfsv2_fattrs fa;
3244a5d661aSToomas Soome 	} *repl;
3254a5d661aSToomas Soome 	struct {
3264a5d661aSToomas Soome 		n_long	h[RPC_HEADER_WORDS];
3274a5d661aSToomas Soome 		struct args d;
3284a5d661aSToomas Soome 	} sdata;
3294a5d661aSToomas Soome 	struct {
3304a5d661aSToomas Soome 		n_long	h[RPC_HEADER_WORDS];
3314a5d661aSToomas Soome 		struct repl d;
3324a5d661aSToomas Soome 	} rdata;
3334a5d661aSToomas Soome 	ssize_t cc;
3344a5d661aSToomas Soome 
3354a5d661aSToomas Soome #ifdef NFS_DEBUG
3364a5d661aSToomas Soome 	if (debug)
3374a5d661aSToomas Soome 		printf("lookupfh: called\n");
3384a5d661aSToomas Soome #endif
3394a5d661aSToomas Soome 
3404a5d661aSToomas Soome 	args = &sdata.d;
3414a5d661aSToomas Soome 	repl = &rdata.d;
3424a5d661aSToomas Soome 
3434a5d661aSToomas Soome 	bzero(args, sizeof(*args));
3444a5d661aSToomas Soome 	bcopy(d->fh, args->fh, sizeof(args->fh));
3454a5d661aSToomas Soome 	len = strlen(name);
3464a5d661aSToomas Soome 	if (len > sizeof(args->name))
3474a5d661aSToomas Soome 		len = sizeof(args->name);
3484a5d661aSToomas Soome 	bcopy(name, args->name, len);
3494a5d661aSToomas Soome 	args->len = htonl(len);
3504a5d661aSToomas Soome 	len = 4 + roundup(len, 4);
3514a5d661aSToomas Soome 	len += NFS_FHSIZE;
3524a5d661aSToomas Soome 
3534a5d661aSToomas Soome 	rlen = sizeof(*repl);
3544a5d661aSToomas Soome 
3554a5d661aSToomas Soome 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
3564a5d661aSToomas Soome 	    args, len, repl, rlen);
3574a5d661aSToomas Soome 	if (cc == -1)
3584a5d661aSToomas Soome 		return (errno);		/* XXX - from rpc_call */
3594a5d661aSToomas Soome 	if (cc < 4)
3604a5d661aSToomas Soome 		return (EIO);
3614a5d661aSToomas Soome 	if (repl->errno) {
3624a5d661aSToomas Soome 		/* saerrno.h now matches NFS error numbers. */
3634a5d661aSToomas Soome 		return (ntohl(repl->errno));
3644a5d661aSToomas Soome 	}
3654a5d661aSToomas Soome 	bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
3664a5d661aSToomas Soome 	bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
3674a5d661aSToomas Soome 	return (0);
3684a5d661aSToomas Soome }
3694a5d661aSToomas Soome 
3704a5d661aSToomas Soome #ifndef NFS_NOSYMLINK
3714a5d661aSToomas Soome /*
3724a5d661aSToomas Soome  * Get the destination of a symbolic link.
3734a5d661aSToomas Soome  */
3744a5d661aSToomas Soome int
3754a5d661aSToomas Soome nfs_readlink(struct nfs_iodesc *d, char *buf)
3764a5d661aSToomas Soome {
3774a5d661aSToomas Soome 	struct {
3784a5d661aSToomas Soome 		n_long	h[RPC_HEADER_WORDS];
3794a5d661aSToomas Soome 		u_char fh[NFS_FHSIZE];
3804a5d661aSToomas Soome 	} sdata;
3814a5d661aSToomas Soome 	struct {
3824a5d661aSToomas Soome 		n_long	h[RPC_HEADER_WORDS];
3834a5d661aSToomas Soome 		struct nfs_readlnk_repl d;
3844a5d661aSToomas Soome 	} rdata;
3854a5d661aSToomas Soome 	ssize_t cc;
3864a5d661aSToomas Soome 
3874a5d661aSToomas Soome #ifdef NFS_DEBUG
3884a5d661aSToomas Soome 	if (debug)
3894a5d661aSToomas Soome 		printf("readlink: called\n");
3904a5d661aSToomas Soome #endif
3914a5d661aSToomas Soome 
3924a5d661aSToomas Soome 	bcopy(d->fh, sdata.fh, NFS_FHSIZE);
3934a5d661aSToomas Soome 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
3944a5d661aSToomas Soome 		      sdata.fh, NFS_FHSIZE,
3954a5d661aSToomas Soome 		      &rdata.d, sizeof(rdata.d));
3964a5d661aSToomas Soome 	if (cc == -1)
3974a5d661aSToomas Soome 		return (errno);
3984a5d661aSToomas Soome 
3994a5d661aSToomas Soome 	if (cc < 4)
4004a5d661aSToomas Soome 		return (EIO);
4014a5d661aSToomas Soome 
4024a5d661aSToomas Soome 	if (rdata.d.errno)
4034a5d661aSToomas Soome 		return (ntohl(rdata.d.errno));
4044a5d661aSToomas Soome 
4054a5d661aSToomas Soome 	rdata.d.len = ntohl(rdata.d.len);
4064a5d661aSToomas Soome 	if (rdata.d.len > NFS_MAXPATHLEN)
4074a5d661aSToomas Soome 		return (ENAMETOOLONG);
4084a5d661aSToomas Soome 
4094a5d661aSToomas Soome 	bcopy(rdata.d.path, buf, rdata.d.len);
4104a5d661aSToomas Soome 	buf[rdata.d.len] = 0;
4114a5d661aSToomas Soome 	return (0);
4124a5d661aSToomas Soome }
4134a5d661aSToomas Soome #endif
4144a5d661aSToomas Soome 
4154a5d661aSToomas Soome /*
4164a5d661aSToomas Soome  * Read data from a file.
4174a5d661aSToomas Soome  * Return transfer count or -1 (and set errno)
4184a5d661aSToomas Soome  */
4194a5d661aSToomas Soome ssize_t
4204a5d661aSToomas Soome nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
4214a5d661aSToomas Soome {
4224a5d661aSToomas Soome 	struct nfs_read_args *args;
4234a5d661aSToomas Soome 	struct nfs_read_repl *repl;
4244a5d661aSToomas Soome 	struct {
4254a5d661aSToomas Soome 		n_long	h[RPC_HEADER_WORDS];
4264a5d661aSToomas Soome 		struct nfs_read_args d;
4274a5d661aSToomas Soome 	} sdata;
4284a5d661aSToomas Soome 	struct {
4294a5d661aSToomas Soome 		n_long	h[RPC_HEADER_WORDS];
4304a5d661aSToomas Soome 		struct nfs_read_repl d;
4314a5d661aSToomas Soome 	} rdata;
4324a5d661aSToomas Soome 	size_t cc;
4334a5d661aSToomas Soome 	long x;
4344a5d661aSToomas Soome 	int hlen, rlen;
4354a5d661aSToomas Soome 
4364a5d661aSToomas Soome 	args = &sdata.d;
4374a5d661aSToomas Soome 	repl = &rdata.d;
4384a5d661aSToomas Soome 
4394a5d661aSToomas Soome 	bcopy(d->fh, args->fh, NFS_FHSIZE);
4404a5d661aSToomas Soome 	args->off = htonl((n_long)off);
441*dd8e2f72SToomas Soome 	if (len > nfs_read_size)
442*dd8e2f72SToomas Soome 		len = nfs_read_size;
4434a5d661aSToomas Soome 	args->len = htonl((n_long)len);
4444a5d661aSToomas Soome 	args->xxx = htonl((n_long)0);
445*dd8e2f72SToomas Soome 	hlen = offsetof(struct nfs_read_rpl, data[0]);
4464a5d661aSToomas Soome 
4474a5d661aSToomas Soome 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
4484a5d661aSToomas Soome 	    args, sizeof(*args),
4494a5d661aSToomas Soome 	    repl, sizeof(*repl));
4504a5d661aSToomas Soome 	if (cc == -1) {
4514a5d661aSToomas Soome 		/* errno was already set by rpc_call */
4524a5d661aSToomas Soome 		return (-1);
4534a5d661aSToomas Soome 	}
4544a5d661aSToomas Soome 	if (cc < hlen) {
4554a5d661aSToomas Soome 		errno = EBADRPC;
4564a5d661aSToomas Soome 		return (-1);
4574a5d661aSToomas Soome 	}
4584a5d661aSToomas Soome 	if (repl->errno) {
4594a5d661aSToomas Soome 		errno = ntohl(repl->errno);
4604a5d661aSToomas Soome 		return (-1);
4614a5d661aSToomas Soome 	}
4624a5d661aSToomas Soome 	rlen = cc - hlen;
4634a5d661aSToomas Soome 	x = ntohl(repl->count);
4644a5d661aSToomas Soome 	if (rlen < x) {
4654a5d661aSToomas Soome 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
4664a5d661aSToomas Soome 		errno = EBADRPC;
4674a5d661aSToomas Soome 		return(-1);
4684a5d661aSToomas Soome 	}
4694a5d661aSToomas Soome 	bcopy(repl->data, addr, x);
4704a5d661aSToomas Soome 	return (x);
4714a5d661aSToomas Soome }
4724a5d661aSToomas Soome 
4734a5d661aSToomas Soome /*
4744a5d661aSToomas Soome  * Open a file.
4754a5d661aSToomas Soome  * return zero or error number
4764a5d661aSToomas Soome  */
4774a5d661aSToomas Soome int
4784a5d661aSToomas Soome nfs_open(const char *upath, struct open_file *f)
4794a5d661aSToomas Soome {
4804a5d661aSToomas Soome 	struct iodesc *desc;
4814a5d661aSToomas Soome 	struct nfs_iodesc *currfd;
4824a5d661aSToomas Soome 	char buf[2 * NFS_FHSIZE + 3];
4834a5d661aSToomas Soome 	u_char *fh;
4844a5d661aSToomas Soome 	char *cp;
4854a5d661aSToomas Soome 	int i;
4864a5d661aSToomas Soome #ifndef NFS_NOSYMLINK
4874a5d661aSToomas Soome 	struct nfs_iodesc *newfd;
4884a5d661aSToomas Soome 	struct nfsv2_fattrs *fa;
4894a5d661aSToomas Soome 	char *ncp;
4904a5d661aSToomas Soome 	int c;
4914a5d661aSToomas Soome 	char namebuf[NFS_MAXPATHLEN + 1];
4924a5d661aSToomas Soome 	char linkbuf[NFS_MAXPATHLEN + 1];
4934a5d661aSToomas Soome 	int nlinks = 0;
4944a5d661aSToomas Soome #endif
4954a5d661aSToomas Soome 	int error;
4964a5d661aSToomas Soome 	char *path;
4974a5d661aSToomas Soome 
49818609d04SToomas Soome 	if (netproto != NET_NFS)
49918609d04SToomas Soome 		return (EINVAL);
50018609d04SToomas Soome 
5014a5d661aSToomas Soome #ifdef NFS_DEBUG
5024a5d661aSToomas Soome  	if (debug)
5034a5d661aSToomas Soome  	    printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
5044a5d661aSToomas Soome #endif
5054a5d661aSToomas Soome 	if (!rootpath[0]) {
5064a5d661aSToomas Soome 		printf("no rootpath, no nfs\n");
5074a5d661aSToomas Soome 		return (ENXIO);
5084a5d661aSToomas Soome 	}
5094a5d661aSToomas Soome 
5104a5d661aSToomas Soome 	/*
5114a5d661aSToomas Soome 	 * This is silly - we should look at dv_type but that value is
5124a5d661aSToomas Soome 	 * arch dependant and we can't use it here.
5134a5d661aSToomas Soome 	 */
5144a5d661aSToomas Soome #ifndef __i386__
5154a5d661aSToomas Soome 	if (strcmp(f->f_dev->dv_name, "net") != 0)
5164a5d661aSToomas Soome 		return(EINVAL);
5174a5d661aSToomas Soome #else
5184a5d661aSToomas Soome 	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
5194a5d661aSToomas Soome 		return(EINVAL);
5204a5d661aSToomas Soome #endif
5214a5d661aSToomas Soome 
5224a5d661aSToomas Soome 	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
5234a5d661aSToomas Soome 		return(EINVAL);
5244a5d661aSToomas Soome 
5254a5d661aSToomas Soome 	/* Bind to a reserved port. */
5264a5d661aSToomas Soome 	desc->myport = htons(--rpc_port);
5274a5d661aSToomas Soome 	desc->destip = rootip;
5284a5d661aSToomas Soome 	if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
5294a5d661aSToomas Soome 		return (error);
5304a5d661aSToomas Soome 	nfs_root_node.fa.fa_type  = htonl(NFDIR);
5314a5d661aSToomas Soome 	nfs_root_node.fa.fa_mode  = htonl(0755);
5324a5d661aSToomas Soome 	nfs_root_node.fa.fa_nlink = htonl(2);
5334a5d661aSToomas Soome 	nfs_root_node.iodesc = desc;
5344a5d661aSToomas Soome 
5354a5d661aSToomas Soome 	fh = &nfs_root_node.fh[0];
5364a5d661aSToomas Soome 	buf[0] = 'X';
5374a5d661aSToomas Soome 	cp = &buf[1];
5384a5d661aSToomas Soome 	for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
5394a5d661aSToomas Soome 		sprintf(cp, "%02x", fh[i]);
5404a5d661aSToomas Soome 	sprintf(cp, "X");
5414a5d661aSToomas Soome 	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
5424a5d661aSToomas Soome 	setenv("boot.nfsroot.path", rootpath, 1);
5434a5d661aSToomas Soome 	setenv("boot.nfsroot.nfshandle", buf, 1);
5444a5d661aSToomas Soome 
5454a5d661aSToomas Soome 	/* Allocate file system specific data structure */
5464a5d661aSToomas Soome 	currfd = malloc(sizeof(*newfd));
5474a5d661aSToomas Soome 	if (currfd == NULL) {
5484a5d661aSToomas Soome 		error = ENOMEM;
5494a5d661aSToomas Soome 		goto out;
5504a5d661aSToomas Soome 	}
5514a5d661aSToomas Soome 
5524a5d661aSToomas Soome #ifndef NFS_NOSYMLINK
5534a5d661aSToomas Soome 	bcopy(&nfs_root_node, currfd, sizeof(*currfd));
554830d404aSToomas Soome 	newfd = NULL;
5554a5d661aSToomas Soome 
5564a5d661aSToomas Soome 	cp = path = strdup(upath);
5574a5d661aSToomas Soome 	if (path == NULL) {
5584a5d661aSToomas Soome 	    error = ENOMEM;
5594a5d661aSToomas Soome 	    goto out;
5604a5d661aSToomas Soome 	}
5614a5d661aSToomas Soome 	while (*cp) {
5624a5d661aSToomas Soome 		/*
5634a5d661aSToomas Soome 		 * Remove extra separators
5644a5d661aSToomas Soome 		 */
5654a5d661aSToomas Soome 		while (*cp == '/')
5664a5d661aSToomas Soome 			cp++;
5674a5d661aSToomas Soome 
5684a5d661aSToomas Soome 		if (*cp == '\0')
5694a5d661aSToomas Soome 			break;
5704a5d661aSToomas Soome 		/*
5714a5d661aSToomas Soome 		 * Check that current node is a directory.
5724a5d661aSToomas Soome 		 */
5734a5d661aSToomas Soome 		if (currfd->fa.fa_type != htonl(NFDIR)) {
5744a5d661aSToomas Soome 			error = ENOTDIR;
5754a5d661aSToomas Soome 			goto out;
5764a5d661aSToomas Soome 		}
5774a5d661aSToomas Soome 
5784a5d661aSToomas Soome 		/* allocate file system specific data structure */
5794a5d661aSToomas Soome 		newfd = malloc(sizeof(*newfd));
5804a5d661aSToomas Soome 		newfd->iodesc = currfd->iodesc;
5814a5d661aSToomas Soome 
5824a5d661aSToomas Soome 		/*
5834a5d661aSToomas Soome 		 * Get next component of path name.
5844a5d661aSToomas Soome 		 */
5854a5d661aSToomas Soome 		{
5864a5d661aSToomas Soome 			int len = 0;
5874a5d661aSToomas Soome 
5884a5d661aSToomas Soome 			ncp = cp;
5894a5d661aSToomas Soome 			while ((c = *cp) != '\0' && c != '/') {
5904a5d661aSToomas Soome 				if (++len > NFS_MAXNAMLEN) {
5914a5d661aSToomas Soome 					error = ENOENT;
5924a5d661aSToomas Soome 					goto out;
5934a5d661aSToomas Soome 				}
5944a5d661aSToomas Soome 				cp++;
5954a5d661aSToomas Soome 			}
5964a5d661aSToomas Soome 			*cp = '\0';
5974a5d661aSToomas Soome 		}
5984a5d661aSToomas Soome 
5994a5d661aSToomas Soome 		/* lookup a file handle */
6004a5d661aSToomas Soome 		error = nfs_lookupfh(currfd, ncp, newfd);
6014a5d661aSToomas Soome 		*cp = c;
6024a5d661aSToomas Soome 		if (error)
6034a5d661aSToomas Soome 			goto out;
6044a5d661aSToomas Soome 
6054a5d661aSToomas Soome 		/*
6064a5d661aSToomas Soome 		 * Check for symbolic link
6074a5d661aSToomas Soome 		 */
6084a5d661aSToomas Soome 		if (newfd->fa.fa_type == htonl(NFLNK)) {
6094a5d661aSToomas Soome 			int link_len, len;
6104a5d661aSToomas Soome 
6114a5d661aSToomas Soome 			error = nfs_readlink(newfd, linkbuf);
6124a5d661aSToomas Soome 			if (error)
6134a5d661aSToomas Soome 				goto out;
6144a5d661aSToomas Soome 
6154a5d661aSToomas Soome 			link_len = strlen(linkbuf);
6164a5d661aSToomas Soome 			len = strlen(cp);
6174a5d661aSToomas Soome 
6184a5d661aSToomas Soome 			if (link_len + len > MAXPATHLEN
6194a5d661aSToomas Soome 			    || ++nlinks > MAXSYMLINKS) {
6204a5d661aSToomas Soome 				error = ENOENT;
6214a5d661aSToomas Soome 				goto out;
6224a5d661aSToomas Soome 			}
6234a5d661aSToomas Soome 
6244a5d661aSToomas Soome 			bcopy(cp, &namebuf[link_len], len + 1);
6254a5d661aSToomas Soome 			bcopy(linkbuf, namebuf, link_len);
6264a5d661aSToomas Soome 
6274a5d661aSToomas Soome 			/*
6284a5d661aSToomas Soome 			 * If absolute pathname, restart at root.
6294a5d661aSToomas Soome 			 * If relative pathname, restart at parent directory.
6304a5d661aSToomas Soome 			 */
6314a5d661aSToomas Soome 			cp = namebuf;
6324a5d661aSToomas Soome 			if (*cp == '/')
6334a5d661aSToomas Soome 				bcopy(&nfs_root_node, currfd, sizeof(*currfd));
6344a5d661aSToomas Soome 
6354a5d661aSToomas Soome 			free(newfd);
636830d404aSToomas Soome 			newfd = NULL;
6374a5d661aSToomas Soome 
6384a5d661aSToomas Soome 			continue;
6394a5d661aSToomas Soome 		}
6404a5d661aSToomas Soome 
6414a5d661aSToomas Soome 		free(currfd);
6424a5d661aSToomas Soome 		currfd = newfd;
643830d404aSToomas Soome 		newfd = NULL;
6444a5d661aSToomas Soome 	}
6454a5d661aSToomas Soome 
6464a5d661aSToomas Soome 	error = 0;
6474a5d661aSToomas Soome 
6484a5d661aSToomas Soome out:
6494a5d661aSToomas Soome 	free(newfd);
6504a5d661aSToomas Soome 	free(path);
6514a5d661aSToomas Soome #else
6524a5d661aSToomas Soome         currfd->iodesc = desc;
6534a5d661aSToomas Soome 
6544a5d661aSToomas Soome         error = nfs_lookupfh(&nfs_root_node, upath, currfd);
6554a5d661aSToomas Soome #endif
6564a5d661aSToomas Soome 	if (!error) {
6574a5d661aSToomas Soome 		currfd->off = 0;
6584a5d661aSToomas Soome 		f->f_fsdata = (void *)currfd;
6594a5d661aSToomas Soome 		return (0);
6604a5d661aSToomas Soome 	}
6614a5d661aSToomas Soome 
6624a5d661aSToomas Soome #ifdef NFS_DEBUG
6634a5d661aSToomas Soome 	if (debug)
6644a5d661aSToomas Soome 		printf("nfs_open: %s lookupfh failed: %s\n",
6654a5d661aSToomas Soome 		    path, strerror(error));
6664a5d661aSToomas Soome #endif
6674a5d661aSToomas Soome 	free(currfd);
6684a5d661aSToomas Soome 
6694a5d661aSToomas Soome 	return (error);
6704a5d661aSToomas Soome }
6714a5d661aSToomas Soome 
6724a5d661aSToomas Soome int
6734a5d661aSToomas Soome nfs_close(struct open_file *f)
6744a5d661aSToomas Soome {
6754a5d661aSToomas Soome 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
6764a5d661aSToomas Soome 
6774a5d661aSToomas Soome #ifdef NFS_DEBUG
6784a5d661aSToomas Soome 	if (debug)
6794a5d661aSToomas Soome 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
6804a5d661aSToomas Soome #endif
6814a5d661aSToomas Soome 
6824a5d661aSToomas Soome 	if (fp)
6834a5d661aSToomas Soome 		free(fp);
6844a5d661aSToomas Soome 	f->f_fsdata = (void *)0;
6854a5d661aSToomas Soome 
6864a5d661aSToomas Soome 	return (0);
6874a5d661aSToomas Soome }
6884a5d661aSToomas Soome 
6894a5d661aSToomas Soome /*
6904a5d661aSToomas Soome  * read a portion of a file
6914a5d661aSToomas Soome  */
6924a5d661aSToomas Soome int
6934a5d661aSToomas Soome nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
6944a5d661aSToomas Soome {
6954a5d661aSToomas Soome 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
6964a5d661aSToomas Soome 	ssize_t cc;
6974a5d661aSToomas Soome 	char *addr = buf;
6984a5d661aSToomas Soome 
6994a5d661aSToomas Soome #ifdef NFS_DEBUG
7004a5d661aSToomas Soome 	if (debug)
7014a5d661aSToomas Soome 		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
7024a5d661aSToomas Soome 		       (int)fp->off);
7034a5d661aSToomas Soome #endif
7044a5d661aSToomas Soome 	while ((int)size > 0) {
7054a5d661aSToomas Soome 		twiddle(16);
7064a5d661aSToomas Soome 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
7074a5d661aSToomas Soome 		/* XXX maybe should retry on certain errors */
7084a5d661aSToomas Soome 		if (cc == -1) {
7094a5d661aSToomas Soome #ifdef NFS_DEBUG
7104a5d661aSToomas Soome 			if (debug)
7114a5d661aSToomas Soome 				printf("nfs_read: read: %s", strerror(errno));
7124a5d661aSToomas Soome #endif
7134a5d661aSToomas Soome 			return (errno);	/* XXX - from nfs_readdata */
7144a5d661aSToomas Soome 		}
7154a5d661aSToomas Soome 		if (cc == 0) {
7164a5d661aSToomas Soome #ifdef NFS_DEBUG
7174a5d661aSToomas Soome 			if (debug)
7184a5d661aSToomas Soome 				printf("nfs_read: hit EOF unexpectantly");
7194a5d661aSToomas Soome #endif
7204a5d661aSToomas Soome 			goto ret;
7214a5d661aSToomas Soome 		}
7224a5d661aSToomas Soome 		fp->off += cc;
7234a5d661aSToomas Soome 		addr += cc;
7244a5d661aSToomas Soome 		size -= cc;
7254a5d661aSToomas Soome 	}
7264a5d661aSToomas Soome ret:
7274a5d661aSToomas Soome 	if (resid)
7284a5d661aSToomas Soome 		*resid = size;
7294a5d661aSToomas Soome 
7304a5d661aSToomas Soome 	return (0);
7314a5d661aSToomas Soome }
7324a5d661aSToomas Soome 
7334a5d661aSToomas Soome /*
7344a5d661aSToomas Soome  * Not implemented.
7354a5d661aSToomas Soome  */
7364a5d661aSToomas Soome int
7374a5d661aSToomas Soome nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
7384a5d661aSToomas Soome {
7394a5d661aSToomas Soome 	return (EROFS);
7404a5d661aSToomas Soome }
7414a5d661aSToomas Soome 
7424a5d661aSToomas Soome off_t
7434a5d661aSToomas Soome nfs_seek(struct open_file *f, off_t offset, int where)
7444a5d661aSToomas Soome {
7454a5d661aSToomas Soome 	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
7464a5d661aSToomas Soome 	n_long size = ntohl(d->fa.fa_size);
7474a5d661aSToomas Soome 
7484a5d661aSToomas Soome 	switch (where) {
7494a5d661aSToomas Soome 	case SEEK_SET:
7504a5d661aSToomas Soome 		d->off = offset;
7514a5d661aSToomas Soome 		break;
7524a5d661aSToomas Soome 	case SEEK_CUR:
7534a5d661aSToomas Soome 		d->off += offset;
7544a5d661aSToomas Soome 		break;
7554a5d661aSToomas Soome 	case SEEK_END:
7564a5d661aSToomas Soome 		d->off = size - offset;
7574a5d661aSToomas Soome 		break;
7584a5d661aSToomas Soome 	default:
7594a5d661aSToomas Soome 		errno = EINVAL;
7604a5d661aSToomas Soome 		return (-1);
7614a5d661aSToomas Soome 	}
7624a5d661aSToomas Soome 
7634a5d661aSToomas Soome 	return (d->off);
7644a5d661aSToomas Soome }
7654a5d661aSToomas Soome 
7664a5d661aSToomas Soome /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
7674a5d661aSToomas Soome int nfs_stat_types[8] = {
7684a5d661aSToomas Soome 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
7694a5d661aSToomas Soome 
7704a5d661aSToomas Soome int
7714a5d661aSToomas Soome nfs_stat(struct open_file *f, struct stat *sb)
7724a5d661aSToomas Soome {
7734a5d661aSToomas Soome 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
7744a5d661aSToomas Soome 	n_long ftype, mode;
7754a5d661aSToomas Soome 
7764a5d661aSToomas Soome 	ftype = ntohl(fp->fa.fa_type);
7774a5d661aSToomas Soome 	mode  = ntohl(fp->fa.fa_mode);
7784a5d661aSToomas Soome 	mode |= nfs_stat_types[ftype & 7];
7794a5d661aSToomas Soome 
7804a5d661aSToomas Soome 	sb->st_mode  = mode;
7814a5d661aSToomas Soome 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
7824a5d661aSToomas Soome 	sb->st_uid   = ntohl(fp->fa.fa_uid);
7834a5d661aSToomas Soome 	sb->st_gid   = ntohl(fp->fa.fa_gid);
7844a5d661aSToomas Soome 	sb->st_size  = ntohl(fp->fa.fa_size);
7854a5d661aSToomas Soome 
7864a5d661aSToomas Soome 	return (0);
7874a5d661aSToomas Soome }
7884a5d661aSToomas Soome 
7894a5d661aSToomas Soome static int
7904a5d661aSToomas Soome nfs_readdir(struct open_file *f, struct dirent *d)
7914a5d661aSToomas Soome {
7924a5d661aSToomas Soome 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
7934a5d661aSToomas Soome 	struct nfs_readdir_args *args;
7944a5d661aSToomas Soome 	struct nfs_readdir_data *rd;
7954a5d661aSToomas Soome 	struct nfs_readdir_off  *roff = NULL;
7964a5d661aSToomas Soome 	static char *buf;
7974a5d661aSToomas Soome 	static struct nfs_iodesc *pfp = NULL;
7984a5d661aSToomas Soome 	static n_long cookie = 0;
7994a5d661aSToomas Soome 	size_t cc;
8004a5d661aSToomas Soome 	n_long eof;
8014a5d661aSToomas Soome 
8024a5d661aSToomas Soome 	struct {
8034a5d661aSToomas Soome 		n_long h[RPC_HEADER_WORDS];
8044a5d661aSToomas Soome 		struct nfs_readdir_args d;
8054a5d661aSToomas Soome 	} sdata;
8064a5d661aSToomas Soome 	static struct {
8074a5d661aSToomas Soome 		n_long h[RPC_HEADER_WORDS];
8084a5d661aSToomas Soome 		u_char d[NFS_READDIRSIZE];
8094a5d661aSToomas Soome 	} rdata;
8104a5d661aSToomas Soome 
8114a5d661aSToomas Soome 	if (fp != pfp || fp->off != cookie) {
8124a5d661aSToomas Soome 		pfp = NULL;
8134a5d661aSToomas Soome 	refill:
8144a5d661aSToomas Soome 		args = &sdata.d;
8154a5d661aSToomas Soome 		bzero(args, sizeof(*args));
8164a5d661aSToomas Soome 
8174a5d661aSToomas Soome 		bcopy(fp->fh, args->fh, NFS_FHSIZE);
8184a5d661aSToomas Soome 		args->cookie = htonl(fp->off);
8194a5d661aSToomas Soome 		args->count  = htonl(NFS_READDIRSIZE);
8204a5d661aSToomas Soome 
8214a5d661aSToomas Soome 		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
8224a5d661aSToomas Soome 			      args, sizeof(*args),
8234a5d661aSToomas Soome 			      rdata.d, sizeof(rdata.d));
8244a5d661aSToomas Soome 		buf  = rdata.d;
8254a5d661aSToomas Soome 		roff = (struct nfs_readdir_off *)buf;
8264a5d661aSToomas Soome 		if (ntohl(roff->cookie) != 0)
8274a5d661aSToomas Soome 			return EIO;
8284a5d661aSToomas Soome 		pfp = fp;
8294a5d661aSToomas Soome 		cookie = fp->off;
8304a5d661aSToomas Soome 	}
8314a5d661aSToomas Soome 	roff = (struct nfs_readdir_off *)buf;
8324a5d661aSToomas Soome 
8334a5d661aSToomas Soome 	if (ntohl(roff->follows) == 0) {
8344a5d661aSToomas Soome 		eof = ntohl((roff+1)->cookie);
8354a5d661aSToomas Soome 		if (eof) {
8364a5d661aSToomas Soome 			cookie = 0;
8374a5d661aSToomas Soome 			return ENOENT;
8384a5d661aSToomas Soome 		}
8394a5d661aSToomas Soome 		goto refill;
8404a5d661aSToomas Soome 	}
8414a5d661aSToomas Soome 
8424a5d661aSToomas Soome 	buf += sizeof(struct nfs_readdir_off);
8434a5d661aSToomas Soome 	rd = (struct nfs_readdir_data *)buf;
8444a5d661aSToomas Soome 	d->d_namlen = ntohl(rd->len);
8454a5d661aSToomas Soome 	bcopy(rd->name, d->d_name, d->d_namlen);
8464a5d661aSToomas Soome 	d->d_name[d->d_namlen] = '\0';
8474a5d661aSToomas Soome 
8484a5d661aSToomas Soome 	buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
8494a5d661aSToomas Soome 	roff = (struct nfs_readdir_off *)buf;
8504a5d661aSToomas Soome 	fp->off = cookie = ntohl(roff->cookie);
8514a5d661aSToomas Soome 	return 0;
8524a5d661aSToomas Soome }
8534a5d661aSToomas Soome #else	/* !OLD_NFSV2 */
8544a5d661aSToomas Soome /*
8554a5d661aSToomas Soome  * Fetch the root file handle (call mount daemon)
8564a5d661aSToomas Soome  * Return zero or error number.
8574a5d661aSToomas Soome  */
8584a5d661aSToomas Soome int
8594a5d661aSToomas Soome nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
8604a5d661aSToomas Soome {
8614a5d661aSToomas Soome 	int len;
8624a5d661aSToomas Soome 	struct args {
8634a5d661aSToomas Soome 		uint32_t len;
8644a5d661aSToomas Soome 		char path[FNAME_SIZE];
8654a5d661aSToomas Soome 	} *args;
8664a5d661aSToomas Soome 	struct repl {
8674a5d661aSToomas Soome 		uint32_t errno;
8684a5d661aSToomas Soome 		uint32_t fhsize;
8694a5d661aSToomas Soome 		u_char fh[NFS_V3MAXFHSIZE];
8704a5d661aSToomas Soome 		uint32_t authcnt;
8714a5d661aSToomas Soome 		uint32_t auth[7];
8724a5d661aSToomas Soome 	} *repl;
8734a5d661aSToomas Soome 	struct {
8744a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
8754a5d661aSToomas Soome 		struct args d;
8764a5d661aSToomas Soome 	} sdata;
8774a5d661aSToomas Soome 	struct {
8784a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
8794a5d661aSToomas Soome 		struct repl d;
8804a5d661aSToomas Soome 	} rdata;
8814a5d661aSToomas Soome 	size_t cc;
8824a5d661aSToomas Soome 
8834a5d661aSToomas Soome #ifdef NFS_DEBUG
8844a5d661aSToomas Soome 	if (debug)
8854a5d661aSToomas Soome 		printf("nfs_getrootfh: %s\n", path);
8864a5d661aSToomas Soome #endif
8874a5d661aSToomas Soome 
8884a5d661aSToomas Soome 	args = &sdata.d;
8894a5d661aSToomas Soome 	repl = &rdata.d;
8904a5d661aSToomas Soome 
8914a5d661aSToomas Soome 	bzero(args, sizeof(*args));
8924a5d661aSToomas Soome 	len = strlen(path);
8934a5d661aSToomas Soome 	if (len > sizeof(args->path))
8944a5d661aSToomas Soome 		len = sizeof(args->path);
8954a5d661aSToomas Soome 	args->len = htonl(len);
8964a5d661aSToomas Soome 	bcopy(path, args->path, len);
8974a5d661aSToomas Soome 	len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
8984a5d661aSToomas Soome 
8994a5d661aSToomas Soome 	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
9004a5d661aSToomas Soome 	    args, len, repl, sizeof(*repl));
9014a5d661aSToomas Soome 	if (cc == -1)
9024a5d661aSToomas Soome 		/* errno was set by rpc_call */
9034a5d661aSToomas Soome 		return (errno);
9044a5d661aSToomas Soome 	if (cc < 2 * sizeof (uint32_t))
9054a5d661aSToomas Soome 		return (EBADRPC);
9064a5d661aSToomas Soome 	if (repl->errno != 0)
9074a5d661aSToomas Soome 		return (ntohl(repl->errno));
9084a5d661aSToomas Soome 	*fhlenp = ntohl(repl->fhsize);
9094a5d661aSToomas Soome 	bcopy(repl->fh, fhp, *fhlenp);
910*dd8e2f72SToomas Soome 
911*dd8e2f72SToomas Soome 	set_nfs_read_size();
9124a5d661aSToomas Soome 	return (0);
9134a5d661aSToomas Soome }
9144a5d661aSToomas Soome 
9154a5d661aSToomas Soome /*
9164a5d661aSToomas Soome  * Lookup a file.  Store handle and attributes.
9174a5d661aSToomas Soome  * Return zero or error number.
9184a5d661aSToomas Soome  */
9194a5d661aSToomas Soome int
9204a5d661aSToomas Soome nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
9214a5d661aSToomas Soome {
9224a5d661aSToomas Soome 	int len, rlen, pos;
9234a5d661aSToomas Soome 	struct args {
9244a5d661aSToomas Soome 		uint32_t fhsize;
9254a5d661aSToomas Soome 		uint32_t fhplusname[1 +
9264a5d661aSToomas Soome 		    (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
9274a5d661aSToomas Soome 	} *args;
9284a5d661aSToomas Soome 	struct repl {
9294a5d661aSToomas Soome 		uint32_t errno;
9304a5d661aSToomas Soome 		uint32_t fhsize;
9314a5d661aSToomas Soome 		uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
9324a5d661aSToomas Soome 		    2 * (sizeof(uint32_t) +
9334a5d661aSToomas Soome 		    sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
9344a5d661aSToomas Soome 	} *repl;
9354a5d661aSToomas Soome 	struct {
9364a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
9374a5d661aSToomas Soome 		struct args d;
9384a5d661aSToomas Soome 	} sdata;
9394a5d661aSToomas Soome 	struct {
9404a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
9414a5d661aSToomas Soome 		struct repl d;
9424a5d661aSToomas Soome 	} rdata;
9434a5d661aSToomas Soome 	ssize_t cc;
9444a5d661aSToomas Soome 
9454a5d661aSToomas Soome #ifdef NFS_DEBUG
9464a5d661aSToomas Soome 	if (debug)
9474a5d661aSToomas Soome 		printf("lookupfh: called\n");
9484a5d661aSToomas Soome #endif
9494a5d661aSToomas Soome 
9504a5d661aSToomas Soome 	args = &sdata.d;
9514a5d661aSToomas Soome 	repl = &rdata.d;
9524a5d661aSToomas Soome 
9534a5d661aSToomas Soome 	bzero(args, sizeof(*args));
9544a5d661aSToomas Soome 	args->fhsize = htonl(d->fhsize);
9554a5d661aSToomas Soome 	bcopy(d->fh, args->fhplusname, d->fhsize);
9564a5d661aSToomas Soome 	len = strlen(name);
9574a5d661aSToomas Soome 	if (len > FNAME_SIZE)
9584a5d661aSToomas Soome 		len = FNAME_SIZE;
9594a5d661aSToomas Soome 	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
9604a5d661aSToomas Soome 	args->fhplusname[pos++] = htonl(len);
9614a5d661aSToomas Soome 	bcopy(name, &args->fhplusname[pos], len);
9624a5d661aSToomas Soome 	len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
9634a5d661aSToomas Soome 	    roundup(len, sizeof(uint32_t));
9644a5d661aSToomas Soome 
9654a5d661aSToomas Soome 	rlen = sizeof(*repl);
9664a5d661aSToomas Soome 
9674a5d661aSToomas Soome 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
9684a5d661aSToomas Soome 	    args, len, repl, rlen);
9694a5d661aSToomas Soome 	if (cc == -1)
9704a5d661aSToomas Soome 		return (errno);		/* XXX - from rpc_call */
9714a5d661aSToomas Soome 	if (cc < 2 * sizeof(uint32_t))
9724a5d661aSToomas Soome 		return (EIO);
9734a5d661aSToomas Soome 	if (repl->errno != 0)
9744a5d661aSToomas Soome 		/* saerrno.h now matches NFS error numbers. */
9754a5d661aSToomas Soome 		return (ntohl(repl->errno));
9764a5d661aSToomas Soome 	newfd->fhsize = ntohl(repl->fhsize);
9774a5d661aSToomas Soome 	bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
9784a5d661aSToomas Soome 	pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
9794a5d661aSToomas Soome 	if (repl->fhplusattr[pos++] == 0)
9804a5d661aSToomas Soome 		return (EIO);
9814a5d661aSToomas Soome 	bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
9824a5d661aSToomas Soome 	return (0);
9834a5d661aSToomas Soome }
9844a5d661aSToomas Soome 
9854a5d661aSToomas Soome #ifndef NFS_NOSYMLINK
9864a5d661aSToomas Soome /*
9874a5d661aSToomas Soome  * Get the destination of a symbolic link.
9884a5d661aSToomas Soome  */
9894a5d661aSToomas Soome int
9904a5d661aSToomas Soome nfs_readlink(struct nfs_iodesc *d, char *buf)
9914a5d661aSToomas Soome {
9924a5d661aSToomas Soome 	struct args {
9934a5d661aSToomas Soome 		uint32_t fhsize;
9944a5d661aSToomas Soome 		u_char fh[NFS_V3MAXFHSIZE];
9954a5d661aSToomas Soome 	} *args;
9964a5d661aSToomas Soome 	struct repl {
9974a5d661aSToomas Soome 		uint32_t errno;
9984a5d661aSToomas Soome 		uint32_t ok;
9994a5d661aSToomas Soome 		struct nfsv3_fattrs fa;
10004a5d661aSToomas Soome 		uint32_t len;
10014a5d661aSToomas Soome 		u_char path[NFS_MAXPATHLEN];
10024a5d661aSToomas Soome 	} *repl;
10034a5d661aSToomas Soome 	struct {
10044a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
10054a5d661aSToomas Soome 		struct args d;
10064a5d661aSToomas Soome 	} sdata;
10074a5d661aSToomas Soome 	struct {
10084a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
10094a5d661aSToomas Soome 		struct repl d;
10104a5d661aSToomas Soome 	} rdata;
10114a5d661aSToomas Soome 	ssize_t cc;
10124a5d661aSToomas Soome 
10134a5d661aSToomas Soome #ifdef NFS_DEBUG
10144a5d661aSToomas Soome 	if (debug)
10154a5d661aSToomas Soome 		printf("readlink: called\n");
10164a5d661aSToomas Soome #endif
10174a5d661aSToomas Soome 
10184a5d661aSToomas Soome 	args = &sdata.d;
10194a5d661aSToomas Soome 	repl = &rdata.d;
10204a5d661aSToomas Soome 
10214a5d661aSToomas Soome 	bzero(args, sizeof(*args));
10224a5d661aSToomas Soome 	args->fhsize = htonl(d->fhsize);
10234a5d661aSToomas Soome 	bcopy(d->fh, args->fh, d->fhsize);
10244a5d661aSToomas Soome 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
10254a5d661aSToomas Soome 	    args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
10264a5d661aSToomas Soome 	    repl, sizeof(*repl));
10274a5d661aSToomas Soome 	if (cc == -1)
10284a5d661aSToomas Soome 		return (errno);
10294a5d661aSToomas Soome 
10304a5d661aSToomas Soome 	if (cc < 2 * sizeof(uint32_t))
10314a5d661aSToomas Soome 		return (EIO);
10324a5d661aSToomas Soome 
10334a5d661aSToomas Soome 	if (repl->errno != 0)
10344a5d661aSToomas Soome 		return (ntohl(repl->errno));
10354a5d661aSToomas Soome 
10364a5d661aSToomas Soome 	if (repl->ok == 0)
10374a5d661aSToomas Soome 		return (EIO);
10384a5d661aSToomas Soome 
10394a5d661aSToomas Soome 	repl->len = ntohl(repl->len);
10404a5d661aSToomas Soome 	if (repl->len > NFS_MAXPATHLEN)
10414a5d661aSToomas Soome 		return (ENAMETOOLONG);
10424a5d661aSToomas Soome 
10434a5d661aSToomas Soome 	bcopy(repl->path, buf, repl->len);
10444a5d661aSToomas Soome 	buf[repl->len] = 0;
10454a5d661aSToomas Soome 	return (0);
10464a5d661aSToomas Soome }
10474a5d661aSToomas Soome #endif
10484a5d661aSToomas Soome 
10494a5d661aSToomas Soome /*
10504a5d661aSToomas Soome  * Read data from a file.
10514a5d661aSToomas Soome  * Return transfer count or -1 (and set errno)
10524a5d661aSToomas Soome  */
10534a5d661aSToomas Soome ssize_t
10544a5d661aSToomas Soome nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
10554a5d661aSToomas Soome {
10564a5d661aSToomas Soome 	struct args {
10574a5d661aSToomas Soome 		uint32_t fhsize;
10584a5d661aSToomas Soome 		uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
10594a5d661aSToomas Soome 	} *args;
10604a5d661aSToomas Soome 	struct repl {
10614a5d661aSToomas Soome 		uint32_t errno;
10624a5d661aSToomas Soome 		uint32_t ok;
10634a5d661aSToomas Soome 		struct nfsv3_fattrs fa;
10644a5d661aSToomas Soome 		uint32_t count;
10654a5d661aSToomas Soome 		uint32_t eof;
10664a5d661aSToomas Soome 		uint32_t len;
1067*dd8e2f72SToomas Soome 		u_char data[NFSREAD_MAX_SIZE];
10684a5d661aSToomas Soome 	} *repl;
10694a5d661aSToomas Soome 	struct {
10704a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
10714a5d661aSToomas Soome 		struct args d;
10724a5d661aSToomas Soome 	} sdata;
10734a5d661aSToomas Soome 	struct {
10744a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
10754a5d661aSToomas Soome 		struct repl d;
10764a5d661aSToomas Soome 	} rdata;
10774a5d661aSToomas Soome 	size_t cc;
10784a5d661aSToomas Soome 	long x;
10794a5d661aSToomas Soome 	int hlen, rlen, pos;
10804a5d661aSToomas Soome 
10814a5d661aSToomas Soome 	args = &sdata.d;
10824a5d661aSToomas Soome 	repl = &rdata.d;
10834a5d661aSToomas Soome 
10844a5d661aSToomas Soome 	bzero(args, sizeof(*args));
10854a5d661aSToomas Soome 	args->fhsize = htonl(d->fhsize);
10864a5d661aSToomas Soome 	bcopy(d->fh, args->fhoffcnt, d->fhsize);
10874a5d661aSToomas Soome 	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
10884a5d661aSToomas Soome 	args->fhoffcnt[pos++] = 0;
10894a5d661aSToomas Soome 	args->fhoffcnt[pos++] = htonl((uint32_t)off);
1090*dd8e2f72SToomas Soome 	if (len > nfs_read_size)
1091*dd8e2f72SToomas Soome 		len = nfs_read_size;
10924a5d661aSToomas Soome 	args->fhoffcnt[pos] = htonl((uint32_t)len);
1093*dd8e2f72SToomas Soome 	hlen = offsetof(struct repl, data[0]);
10944a5d661aSToomas Soome 
10954a5d661aSToomas Soome 	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
10964a5d661aSToomas Soome 	    args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
10974a5d661aSToomas Soome 	    repl, sizeof(*repl));
10984a5d661aSToomas Soome 	if (cc == -1)
10994a5d661aSToomas Soome 		/* errno was already set by rpc_call */
11004a5d661aSToomas Soome 		return (-1);
11014a5d661aSToomas Soome 	if (cc < hlen) {
11024a5d661aSToomas Soome 		errno = EBADRPC;
11034a5d661aSToomas Soome 		return (-1);
11044a5d661aSToomas Soome 	}
11054a5d661aSToomas Soome 	if (repl->errno != 0) {
11064a5d661aSToomas Soome 		errno = ntohl(repl->errno);
11074a5d661aSToomas Soome 		return (-1);
11084a5d661aSToomas Soome 	}
11094a5d661aSToomas Soome 	rlen = cc - hlen;
11104a5d661aSToomas Soome 	x = ntohl(repl->count);
11114a5d661aSToomas Soome 	if (rlen < x) {
11124a5d661aSToomas Soome 		printf("nfsread: short packet, %d < %ld\n", rlen, x);
11134a5d661aSToomas Soome 		errno = EBADRPC;
11144a5d661aSToomas Soome 		return (-1);
11154a5d661aSToomas Soome 	}
11164a5d661aSToomas Soome 	bcopy(repl->data, addr, x);
11174a5d661aSToomas Soome 	return (x);
11184a5d661aSToomas Soome }
11194a5d661aSToomas Soome 
11204a5d661aSToomas Soome /*
11214a5d661aSToomas Soome  * Open a file.
11224a5d661aSToomas Soome  * return zero or error number
11234a5d661aSToomas Soome  */
11244a5d661aSToomas Soome int
11254a5d661aSToomas Soome nfs_open(const char *upath, struct open_file *f)
11264a5d661aSToomas Soome {
11274a5d661aSToomas Soome 	struct iodesc *desc;
11284a5d661aSToomas Soome 	struct nfs_iodesc *currfd;
11294a5d661aSToomas Soome 	char buf[2 * NFS_V3MAXFHSIZE + 3];
11304a5d661aSToomas Soome 	u_char *fh;
11314a5d661aSToomas Soome 	char *cp;
11324a5d661aSToomas Soome 	int i;
11334a5d661aSToomas Soome #ifndef NFS_NOSYMLINK
11344a5d661aSToomas Soome 	struct nfs_iodesc *newfd;
11354a5d661aSToomas Soome 	struct nfsv3_fattrs *fa;
11364a5d661aSToomas Soome 	char *ncp;
11374a5d661aSToomas Soome 	int c;
11384a5d661aSToomas Soome 	char namebuf[NFS_MAXPATHLEN + 1];
11394a5d661aSToomas Soome 	char linkbuf[NFS_MAXPATHLEN + 1];
11404a5d661aSToomas Soome 	int nlinks = 0;
11414a5d661aSToomas Soome #endif
11424a5d661aSToomas Soome 	int error;
11434a5d661aSToomas Soome 	char *path;
11444a5d661aSToomas Soome 
114518609d04SToomas Soome 	if (netproto != NET_NFS)
114618609d04SToomas Soome 		return (EINVAL);
114718609d04SToomas Soome 
11484a5d661aSToomas Soome #ifdef NFS_DEBUG
11494a5d661aSToomas Soome  	if (debug)
11504a5d661aSToomas Soome  	    printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
11514a5d661aSToomas Soome #endif
11524a5d661aSToomas Soome 	if (!rootpath[0]) {
11534a5d661aSToomas Soome 		printf("no rootpath, no nfs\n");
11544a5d661aSToomas Soome 		return (ENXIO);
11554a5d661aSToomas Soome 	}
11564a5d661aSToomas Soome 
11574a5d661aSToomas Soome 	/*
11584a5d661aSToomas Soome 	 * This is silly - we should look at dv_type but that value is
11594a5d661aSToomas Soome 	 * arch dependant and we can't use it here.
11604a5d661aSToomas Soome 	 */
11614a5d661aSToomas Soome #ifndef __i386__
11624a5d661aSToomas Soome 	if (strcmp(f->f_dev->dv_name, "net") != 0)
11634a5d661aSToomas Soome 		return (EINVAL);
11644a5d661aSToomas Soome #else
11654a5d661aSToomas Soome 	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
11664a5d661aSToomas Soome 		return (EINVAL);
11674a5d661aSToomas Soome #endif
11684a5d661aSToomas Soome 
11694a5d661aSToomas Soome 	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
11704a5d661aSToomas Soome 		return (EINVAL);
11714a5d661aSToomas Soome 
11724a5d661aSToomas Soome 	/* Bind to a reserved port. */
11734a5d661aSToomas Soome 	desc->myport = htons(--rpc_port);
11744a5d661aSToomas Soome 	desc->destip = rootip;
11754a5d661aSToomas Soome 	if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
11764a5d661aSToomas Soome 	    nfs_root_node.fh)))
11774a5d661aSToomas Soome 		return (error);
11784a5d661aSToomas Soome 	nfs_root_node.fa.fa_type  = htonl(NFDIR);
11794a5d661aSToomas Soome 	nfs_root_node.fa.fa_mode  = htonl(0755);
11804a5d661aSToomas Soome 	nfs_root_node.fa.fa_nlink = htonl(2);
11814a5d661aSToomas Soome 	nfs_root_node.iodesc = desc;
11824a5d661aSToomas Soome 
11834a5d661aSToomas Soome 	fh = &nfs_root_node.fh[0];
11844a5d661aSToomas Soome 	buf[0] = 'X';
11854a5d661aSToomas Soome 	cp = &buf[1];
11864a5d661aSToomas Soome 	for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
11874a5d661aSToomas Soome 		sprintf(cp, "%02x", fh[i]);
11884a5d661aSToomas Soome 	sprintf(cp, "X");
11894a5d661aSToomas Soome 	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
11904a5d661aSToomas Soome 	setenv("boot.nfsroot.path", rootpath, 1);
11914a5d661aSToomas Soome 	setenv("boot.nfsroot.nfshandle", buf, 1);
11924a5d661aSToomas Soome 	sprintf(buf, "%d", nfs_root_node.fhsize);
11934a5d661aSToomas Soome 	setenv("boot.nfsroot.nfshandlelen", buf, 1);
11944a5d661aSToomas Soome 
11954a5d661aSToomas Soome 	/* Allocate file system specific data structure */
11964a5d661aSToomas Soome 	currfd = malloc(sizeof(*newfd));
11974a5d661aSToomas Soome 	if (currfd == NULL) {
11984a5d661aSToomas Soome 		error = ENOMEM;
11994a5d661aSToomas Soome 		goto out;
12004a5d661aSToomas Soome 	}
12014a5d661aSToomas Soome #ifndef NFS_NOSYMLINK
12024a5d661aSToomas Soome 	bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1203830d404aSToomas Soome 	newfd = NULL;
12044a5d661aSToomas Soome 
12054a5d661aSToomas Soome 	cp = path = strdup(upath);
12064a5d661aSToomas Soome 	if (path == NULL) {
12074a5d661aSToomas Soome 		error = ENOMEM;
12084a5d661aSToomas Soome 		goto out;
12094a5d661aSToomas Soome 	}
12104a5d661aSToomas Soome 	while (*cp) {
12114a5d661aSToomas Soome 		/*
12124a5d661aSToomas Soome 		 * Remove extra separators
12134a5d661aSToomas Soome 		 */
12144a5d661aSToomas Soome 		while (*cp == '/')
12154a5d661aSToomas Soome 			cp++;
12164a5d661aSToomas Soome 
12174a5d661aSToomas Soome 		if (*cp == '\0')
12184a5d661aSToomas Soome 			break;
12194a5d661aSToomas Soome 		/*
12204a5d661aSToomas Soome 		 * Check that current node is a directory.
12214a5d661aSToomas Soome 		 */
12224a5d661aSToomas Soome 		if (currfd->fa.fa_type != htonl(NFDIR)) {
12234a5d661aSToomas Soome 			error = ENOTDIR;
12244a5d661aSToomas Soome 			goto out;
12254a5d661aSToomas Soome 		}
12264a5d661aSToomas Soome 
12274a5d661aSToomas Soome 		/* allocate file system specific data structure */
12284a5d661aSToomas Soome 		newfd = malloc(sizeof(*newfd));
12294a5d661aSToomas Soome 		if (newfd == NULL) {
12304a5d661aSToomas Soome 			error = ENOMEM;
12314a5d661aSToomas Soome 			goto out;
12324a5d661aSToomas Soome 		}
12334a5d661aSToomas Soome 		newfd->iodesc = currfd->iodesc;
12344a5d661aSToomas Soome 
12354a5d661aSToomas Soome 		/*
12364a5d661aSToomas Soome 		 * Get next component of path name.
12374a5d661aSToomas Soome 		 */
12384a5d661aSToomas Soome 		{
12394a5d661aSToomas Soome 			int len = 0;
12404a5d661aSToomas Soome 
12414a5d661aSToomas Soome 			ncp = cp;
12424a5d661aSToomas Soome 			while ((c = *cp) != '\0' && c != '/') {
12434a5d661aSToomas Soome 				if (++len > NFS_MAXNAMLEN) {
12444a5d661aSToomas Soome 					error = ENOENT;
12454a5d661aSToomas Soome 					goto out;
12464a5d661aSToomas Soome 				}
12474a5d661aSToomas Soome 				cp++;
12484a5d661aSToomas Soome 			}
12494a5d661aSToomas Soome 			*cp = '\0';
12504a5d661aSToomas Soome 		}
12514a5d661aSToomas Soome 
12524a5d661aSToomas Soome 		/* lookup a file handle */
12534a5d661aSToomas Soome 		error = nfs_lookupfh(currfd, ncp, newfd);
12544a5d661aSToomas Soome 		*cp = c;
12554a5d661aSToomas Soome 		if (error)
12564a5d661aSToomas Soome 			goto out;
12574a5d661aSToomas Soome 
12584a5d661aSToomas Soome 		/*
12594a5d661aSToomas Soome 		 * Check for symbolic link
12604a5d661aSToomas Soome 		 */
12614a5d661aSToomas Soome 		if (newfd->fa.fa_type == htonl(NFLNK)) {
12624a5d661aSToomas Soome 			int link_len, len;
12634a5d661aSToomas Soome 
12644a5d661aSToomas Soome 			error = nfs_readlink(newfd, linkbuf);
12654a5d661aSToomas Soome 			if (error)
12664a5d661aSToomas Soome 				goto out;
12674a5d661aSToomas Soome 
12684a5d661aSToomas Soome 			link_len = strlen(linkbuf);
12694a5d661aSToomas Soome 			len = strlen(cp);
12704a5d661aSToomas Soome 
12714a5d661aSToomas Soome 			if (link_len + len > MAXPATHLEN
12724a5d661aSToomas Soome 			    || ++nlinks > MAXSYMLINKS) {
12734a5d661aSToomas Soome 				error = ENOENT;
12744a5d661aSToomas Soome 				goto out;
12754a5d661aSToomas Soome 			}
12764a5d661aSToomas Soome 
12774a5d661aSToomas Soome 			bcopy(cp, &namebuf[link_len], len + 1);
12784a5d661aSToomas Soome 			bcopy(linkbuf, namebuf, link_len);
12794a5d661aSToomas Soome 
12804a5d661aSToomas Soome 			/*
12814a5d661aSToomas Soome 			 * If absolute pathname, restart at root.
12824a5d661aSToomas Soome 			 * If relative pathname, restart at parent directory.
12834a5d661aSToomas Soome 			 */
12844a5d661aSToomas Soome 			cp = namebuf;
12854a5d661aSToomas Soome 			if (*cp == '/')
12864a5d661aSToomas Soome 				bcopy(&nfs_root_node, currfd, sizeof(*currfd));
12874a5d661aSToomas Soome 
12884a5d661aSToomas Soome 			free(newfd);
1289830d404aSToomas Soome 			newfd = NULL;
12904a5d661aSToomas Soome 
12914a5d661aSToomas Soome 			continue;
12924a5d661aSToomas Soome 		}
12934a5d661aSToomas Soome 
12944a5d661aSToomas Soome 		free(currfd);
12954a5d661aSToomas Soome 		currfd = newfd;
1296830d404aSToomas Soome 		newfd = NULL;
12974a5d661aSToomas Soome 	}
12984a5d661aSToomas Soome 
12994a5d661aSToomas Soome 	error = 0;
13004a5d661aSToomas Soome 
13014a5d661aSToomas Soome out:
13024a5d661aSToomas Soome 	free(newfd);
13034a5d661aSToomas Soome 	free(path);
13044a5d661aSToomas Soome #else
13054a5d661aSToomas Soome 	currfd->iodesc = desc;
13064a5d661aSToomas Soome 
13074a5d661aSToomas Soome 	error = nfs_lookupfh(&nfs_root_node, upath, currfd);
13084a5d661aSToomas Soome #endif
13094a5d661aSToomas Soome 	if (!error) {
13104a5d661aSToomas Soome 		currfd->off = 0;
13114a5d661aSToomas Soome 		currfd->cookie = 0;
13124a5d661aSToomas Soome 		f->f_fsdata = (void *)currfd;
13134a5d661aSToomas Soome 		return (0);
13144a5d661aSToomas Soome 	}
13154a5d661aSToomas Soome 
13164a5d661aSToomas Soome #ifdef NFS_DEBUG
13174a5d661aSToomas Soome 	if (debug)
13184a5d661aSToomas Soome 		printf("nfs_open: %s lookupfh failed: %s\n",
13194a5d661aSToomas Soome 		    path, strerror(error));
13204a5d661aSToomas Soome #endif
13214a5d661aSToomas Soome 	free(currfd);
13224a5d661aSToomas Soome 
13234a5d661aSToomas Soome 	return (error);
13244a5d661aSToomas Soome }
13254a5d661aSToomas Soome 
13264a5d661aSToomas Soome int
13274a5d661aSToomas Soome nfs_close(struct open_file *f)
13284a5d661aSToomas Soome {
13294a5d661aSToomas Soome 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
13304a5d661aSToomas Soome 
13314a5d661aSToomas Soome #ifdef NFS_DEBUG
13324a5d661aSToomas Soome 	if (debug)
13334a5d661aSToomas Soome 		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
13344a5d661aSToomas Soome #endif
13354a5d661aSToomas Soome 
13364a5d661aSToomas Soome 	if (fp)
13374a5d661aSToomas Soome 		free(fp);
13384a5d661aSToomas Soome 	f->f_fsdata = (void *)0;
13394a5d661aSToomas Soome 
13404a5d661aSToomas Soome 	return (0);
13414a5d661aSToomas Soome }
13424a5d661aSToomas Soome 
13434a5d661aSToomas Soome /*
13444a5d661aSToomas Soome  * read a portion of a file
13454a5d661aSToomas Soome  */
13464a5d661aSToomas Soome int
13474a5d661aSToomas Soome nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
13484a5d661aSToomas Soome {
13494a5d661aSToomas Soome 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
13504a5d661aSToomas Soome 	ssize_t cc;
13514a5d661aSToomas Soome 	char *addr = buf;
13524a5d661aSToomas Soome 
13534a5d661aSToomas Soome #ifdef NFS_DEBUG
13544a5d661aSToomas Soome 	if (debug)
13554a5d661aSToomas Soome 		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
13564a5d661aSToomas Soome 		       (int)fp->off);
13574a5d661aSToomas Soome #endif
13584a5d661aSToomas Soome 	while ((int)size > 0) {
13594a5d661aSToomas Soome 		twiddle(16);
13604a5d661aSToomas Soome 		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
13614a5d661aSToomas Soome 		/* XXX maybe should retry on certain errors */
13624a5d661aSToomas Soome 		if (cc == -1) {
13634a5d661aSToomas Soome #ifdef NFS_DEBUG
13644a5d661aSToomas Soome 			if (debug)
13654a5d661aSToomas Soome 				printf("nfs_read: read: %s", strerror(errno));
13664a5d661aSToomas Soome #endif
13674a5d661aSToomas Soome 			return (errno);	/* XXX - from nfs_readdata */
13684a5d661aSToomas Soome 		}
13694a5d661aSToomas Soome 		if (cc == 0) {
13704a5d661aSToomas Soome #ifdef NFS_DEBUG
13714a5d661aSToomas Soome 			if (debug)
13724a5d661aSToomas Soome 				printf("nfs_read: hit EOF unexpectantly");
13734a5d661aSToomas Soome #endif
13744a5d661aSToomas Soome 			goto ret;
13754a5d661aSToomas Soome 		}
13764a5d661aSToomas Soome 		fp->off += cc;
13774a5d661aSToomas Soome 		addr += cc;
13784a5d661aSToomas Soome 		size -= cc;
13794a5d661aSToomas Soome 	}
13804a5d661aSToomas Soome ret:
13814a5d661aSToomas Soome 	if (resid)
13824a5d661aSToomas Soome 		*resid = size;
13834a5d661aSToomas Soome 
13844a5d661aSToomas Soome 	return (0);
13854a5d661aSToomas Soome }
13864a5d661aSToomas Soome 
13874a5d661aSToomas Soome /*
13884a5d661aSToomas Soome  * Not implemented.
13894a5d661aSToomas Soome  */
13904a5d661aSToomas Soome int
13914a5d661aSToomas Soome nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
13924a5d661aSToomas Soome {
13934a5d661aSToomas Soome 	return (EROFS);
13944a5d661aSToomas Soome }
13954a5d661aSToomas Soome 
13964a5d661aSToomas Soome off_t
13974a5d661aSToomas Soome nfs_seek(struct open_file *f, off_t offset, int where)
13984a5d661aSToomas Soome {
13994a5d661aSToomas Soome 	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
14004a5d661aSToomas Soome 	uint32_t size = ntohl(d->fa.fa_size.val[1]);
14014a5d661aSToomas Soome 
14024a5d661aSToomas Soome 	switch (where) {
14034a5d661aSToomas Soome 	case SEEK_SET:
14044a5d661aSToomas Soome 		d->off = offset;
14054a5d661aSToomas Soome 		break;
14064a5d661aSToomas Soome 	case SEEK_CUR:
14074a5d661aSToomas Soome 		d->off += offset;
14084a5d661aSToomas Soome 		break;
14094a5d661aSToomas Soome 	case SEEK_END:
14104a5d661aSToomas Soome 		d->off = size - offset;
14114a5d661aSToomas Soome 		break;
14124a5d661aSToomas Soome 	default:
14134a5d661aSToomas Soome 		errno = EINVAL;
14144a5d661aSToomas Soome 		return (-1);
14154a5d661aSToomas Soome 	}
14164a5d661aSToomas Soome 
14174a5d661aSToomas Soome 	return (d->off);
14184a5d661aSToomas Soome }
14194a5d661aSToomas Soome 
14204a5d661aSToomas Soome /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
14214a5d661aSToomas Soome int nfs_stat_types[9] = {
14224a5d661aSToomas Soome 	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
14234a5d661aSToomas Soome 
14244a5d661aSToomas Soome int
14254a5d661aSToomas Soome nfs_stat(struct open_file *f, struct stat *sb)
14264a5d661aSToomas Soome {
14274a5d661aSToomas Soome 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
14284a5d661aSToomas Soome 	uint32_t ftype, mode;
14294a5d661aSToomas Soome 
14304a5d661aSToomas Soome 	ftype = ntohl(fp->fa.fa_type);
14314a5d661aSToomas Soome 	mode  = ntohl(fp->fa.fa_mode);
14324a5d661aSToomas Soome 	mode |= nfs_stat_types[ftype & 7];
14334a5d661aSToomas Soome 
14344a5d661aSToomas Soome 	sb->st_mode  = mode;
14354a5d661aSToomas Soome 	sb->st_nlink = ntohl(fp->fa.fa_nlink);
14364a5d661aSToomas Soome 	sb->st_uid   = ntohl(fp->fa.fa_uid);
14374a5d661aSToomas Soome 	sb->st_gid   = ntohl(fp->fa.fa_gid);
14384a5d661aSToomas Soome 	sb->st_size  = ntohl(fp->fa.fa_size.val[1]);
14394a5d661aSToomas Soome 
14404a5d661aSToomas Soome 	return (0);
14414a5d661aSToomas Soome }
14424a5d661aSToomas Soome 
14434a5d661aSToomas Soome static int
14444a5d661aSToomas Soome nfs_readdir(struct open_file *f, struct dirent *d)
14454a5d661aSToomas Soome {
14464a5d661aSToomas Soome 	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
14474a5d661aSToomas Soome 	struct nfsv3_readdir_repl *repl;
14484a5d661aSToomas Soome 	struct nfsv3_readdir_entry *rent;
14494a5d661aSToomas Soome 	static char *buf;
14504a5d661aSToomas Soome 	static struct nfs_iodesc *pfp = NULL;
14514a5d661aSToomas Soome 	static uint64_t cookie = 0;
14524a5d661aSToomas Soome 	size_t cc;
14534a5d661aSToomas Soome 	int pos;
14544a5d661aSToomas Soome 
14554a5d661aSToomas Soome 	struct args {
14564a5d661aSToomas Soome 		uint32_t fhsize;
14574a5d661aSToomas Soome 		uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
14584a5d661aSToomas Soome 	} *args;
14594a5d661aSToomas Soome 	struct {
14604a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
14614a5d661aSToomas Soome 		struct args d;
14624a5d661aSToomas Soome 	} sdata;
14634a5d661aSToomas Soome 	static struct {
14644a5d661aSToomas Soome 		uint32_t h[RPC_HEADER_WORDS];
14654a5d661aSToomas Soome 		u_char d[NFS_READDIRSIZE];
14664a5d661aSToomas Soome 	} rdata;
14674a5d661aSToomas Soome 
14684a5d661aSToomas Soome 	if (fp != pfp || fp->off != cookie) {
14694a5d661aSToomas Soome 		pfp = NULL;
14704a5d661aSToomas Soome 	refill:
14714a5d661aSToomas Soome 		args = &sdata.d;
14724a5d661aSToomas Soome 		bzero(args, sizeof(*args));
14734a5d661aSToomas Soome 
14744a5d661aSToomas Soome 		args->fhsize = htonl(fp->fhsize);
14754a5d661aSToomas Soome 		bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
14764a5d661aSToomas Soome 		pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
14774a5d661aSToomas Soome 		args->fhpluscookie[pos++] = htonl(fp->off >> 32);
14784a5d661aSToomas Soome 		args->fhpluscookie[pos++] = htonl(fp->off);
14794a5d661aSToomas Soome 		args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
14804a5d661aSToomas Soome 		args->fhpluscookie[pos++] = htonl(fp->cookie);
14814a5d661aSToomas Soome 		args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
14824a5d661aSToomas Soome 
14834a5d661aSToomas Soome 		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
14844a5d661aSToomas Soome 		    args, 6 * sizeof(uint32_t) +
14854a5d661aSToomas Soome 		    roundup(fp->fhsize, sizeof(uint32_t)),
14864a5d661aSToomas Soome 		    rdata.d, sizeof(rdata.d));
14874a5d661aSToomas Soome 		buf  = rdata.d;
14884a5d661aSToomas Soome 		repl = (struct nfsv3_readdir_repl *)buf;
14894a5d661aSToomas Soome 		if (repl->errno != 0)
14904a5d661aSToomas Soome 			return (ntohl(repl->errno));
14914a5d661aSToomas Soome 		pfp = fp;
14924a5d661aSToomas Soome 		cookie = fp->off;
14934a5d661aSToomas Soome 		fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
14944a5d661aSToomas Soome 		    ntohl(repl->cookiev1);
14954a5d661aSToomas Soome 		buf += sizeof (struct nfsv3_readdir_repl);
14964a5d661aSToomas Soome 	}
14974a5d661aSToomas Soome 	rent = (struct nfsv3_readdir_entry *)buf;
14984a5d661aSToomas Soome 
14994a5d661aSToomas Soome 	if (rent->follows == 0) {
15004a5d661aSToomas Soome 		/* fid0 is actually eof */
15014a5d661aSToomas Soome 		if (rent->fid0 != 0) {
15024a5d661aSToomas Soome 			cookie = 0;
15034a5d661aSToomas Soome 			return (ENOENT);
15044a5d661aSToomas Soome 		}
15054a5d661aSToomas Soome 		goto refill;
15064a5d661aSToomas Soome 	}
15074a5d661aSToomas Soome 
15084a5d661aSToomas Soome 	d->d_namlen = ntohl(rent->len);
15094a5d661aSToomas Soome 	bcopy(rent->nameplus, d->d_name, d->d_namlen);
15104a5d661aSToomas Soome 	d->d_name[d->d_namlen] = '\0';
15114a5d661aSToomas Soome 
15124a5d661aSToomas Soome 	pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
15134a5d661aSToomas Soome 	fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
15144a5d661aSToomas Soome 	    ntohl(rent->nameplus[pos + 1]);
15154a5d661aSToomas Soome 	pos += 2;
15164a5d661aSToomas Soome 	buf = (u_char *)&rent->nameplus[pos];
15174a5d661aSToomas Soome 	return (0);
15184a5d661aSToomas Soome }
15194a5d661aSToomas Soome #endif	/* OLD_NFSV2 */
1520