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