xref: /onnv-gate/usr/src/stand/lib/fs/nfs/nfs4ops.c (revision 6747:393cf276a040)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*6747Sga159272  * Common Development and Distribution License (the "License").
6*6747Sga159272  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*6747Sga159272  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * Simple nfs V4 ops
260Sstevel@tonic-gate  */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <rpc/types.h>
310Sstevel@tonic-gate #include <rpc/auth.h>
320Sstevel@tonic-gate #include <sys/t_lock.h>
330Sstevel@tonic-gate #include "clnt.h"
340Sstevel@tonic-gate #include <sys/fcntl.h>
350Sstevel@tonic-gate #include <sys/vfs.h>
360Sstevel@tonic-gate #include <errno.h>
370Sstevel@tonic-gate #include <sys/promif.h>
380Sstevel@tonic-gate #include <rpc/xdr.h>
390Sstevel@tonic-gate #include "nfs_inet.h"
400Sstevel@tonic-gate #include <sys/stat.h>
410Sstevel@tonic-gate #include <sys/bootvfs.h>
420Sstevel@tonic-gate #include <sys/bootdebug.h>
430Sstevel@tonic-gate #include <sys/salib.h>
440Sstevel@tonic-gate #include <sys/sacache.h>
450Sstevel@tonic-gate #include <rpc/rpc.h>
460Sstevel@tonic-gate #include "brpc.h"
470Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #define	dprintf	if (boothowto & RB_DEBUG) printf
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static struct timeval zero_timeout = {0, 0};	/* default */
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * NFS Version 4 specific functions
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate 
570Sstevel@tonic-gate ssize_t
nfs4read(struct nfs_file * filep,char * buf,size_t size)580Sstevel@tonic-gate nfs4read(struct nfs_file *filep, char *buf, size_t size)
590Sstevel@tonic-gate {
600Sstevel@tonic-gate 	enum clnt_stat	status;
610Sstevel@tonic-gate 	read4arg_t	readargs;
620Sstevel@tonic-gate 	read4res_t	readres;
630Sstevel@tonic-gate 	char		*buf_offset;
640Sstevel@tonic-gate 	uint_t		count = 0;
650Sstevel@tonic-gate 	uint_t		readcnt = 0;
660Sstevel@tonic-gate 	bool_t		done = FALSE;
670Sstevel@tonic-gate 	struct timeval	timeout;
680Sstevel@tonic-gate 	int		framing_errs = 0;
690Sstevel@tonic-gate 	static uint_t	pos;
700Sstevel@tonic-gate 	static char	ind[] = "|/-\\";
710Sstevel@tonic-gate 	static int	blks_read;
720Sstevel@tonic-gate 	utf8string	str;
730Sstevel@tonic-gate 	char		tagname[] = "inetboot read";
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	bzero(&readres, sizeof (readres));
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	str.utf8string_len = sizeof (tagname) - 1;
780Sstevel@tonic-gate 	str.utf8string_val = tagname;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	/*
810Sstevel@tonic-gate 	 * read
820Sstevel@tonic-gate 	 */
830Sstevel@tonic-gate 	buf_offset = buf;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	if (nfs_readsize == 0)
860Sstevel@tonic-gate 		nfs_readsize = READ4_SIZE;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	if (size < nfs_readsize)
890Sstevel@tonic-gate 		readargs.r_count = size;
900Sstevel@tonic-gate 	else
910Sstevel@tonic-gate 		readargs.r_count = nfs_readsize;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	if (filep->fh.fh4.len > 0)
940Sstevel@tonic-gate 		compound_init(&readargs.r_arg, &str, 0, 2, &filep->fh.fh4);
950Sstevel@tonic-gate 	else
960Sstevel@tonic-gate 		compound_init(&readargs.r_arg, &str, 0, 2, NULL);
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	readargs.r_opread = OP_READ;
990Sstevel@tonic-gate 	/*
1000Sstevel@tonic-gate 	 * zero out the stateid field
1010Sstevel@tonic-gate 	 */
1020Sstevel@tonic-gate 	bzero(&readargs.r_stateid, sizeof (readargs.r_stateid));
1030Sstevel@tonic-gate 	readargs.r_offset = filep->offset;
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	do {
1060Sstevel@tonic-gate 		readres.r_data_val = buf_offset;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 		if ((count + readargs.r_count) > size)
1090Sstevel@tonic-gate 			readargs.r_count = size - count;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 		timeout.tv_sec = NFS_REXMIT_MIN;
1120Sstevel@tonic-gate 		timeout.tv_usec = 0;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 		do {
1150Sstevel@tonic-gate 			status = CLNT_CALL(root_CLIENT, NFSPROC4_COMPOUND,
116*6747Sga159272 			    xdr_read4_args, (caddr_t)&readargs,
117*6747Sga159272 			    xdr_read4_res, (caddr_t)&readres,
118*6747Sga159272 			    timeout);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 			if (status == RPC_TIMEDOUT) {
1210Sstevel@tonic-gate 	dprintf("NFS read(%d) timed out. Retrying...\n", readargs.r_count);
1220Sstevel@tonic-gate 				if (errno == ETIMEDOUT)
1230Sstevel@tonic-gate 					framing_errs++;
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 				if (framing_errs > NFS_MAX_FERRS &&
1260Sstevel@tonic-gate 				    readargs.r_count > NFS_READ_DECR) {
1270Sstevel@tonic-gate 					readargs.r_count /= 2;
1280Sstevel@tonic-gate 					nfs_readsize /= 2;
1290Sstevel@tonic-gate 					dprintf("NFS read size now %d.\n",
130*6747Sga159272 					    nfs_readsize);
1310Sstevel@tonic-gate 					timeout.tv_sec = NFS_REXMIT_MIN;
1320Sstevel@tonic-gate 					framing_errs = 0;
1330Sstevel@tonic-gate 				} else {
1340Sstevel@tonic-gate 					if (timeout.tv_sec < NFS_REXMIT_MAX)
1350Sstevel@tonic-gate 						timeout.tv_sec++;
1360Sstevel@tonic-gate 					else
1370Sstevel@tonic-gate 						timeout.tv_sec = 0;
1380Sstevel@tonic-gate 				}
1390Sstevel@tonic-gate 			}
1400Sstevel@tonic-gate 		} while (status == RPC_TIMEDOUT);
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 		if (status != RPC_SUCCESS)
1430Sstevel@tonic-gate 			return (-1);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 		if (readres.r_status != NFS4_OK) {
1460Sstevel@tonic-gate 			nfs4_error(readres.r_status);
1470Sstevel@tonic-gate 			return (-1);
1480Sstevel@tonic-gate 		}
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 		readcnt = readres.r_data_len;
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 		if (readres.r_eof == TRUE)
1530Sstevel@tonic-gate 			done = TRUE;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 		if (readcnt < readargs.r_count) {
1560Sstevel@tonic-gate #ifdef NFS_OPS_DEBUG
1570Sstevel@tonic-gate 			if ((boothowto & DBFLAGS) == DBFLAGS)
158*6747Sga159272 				printf("nfs4read: partial read %d instead "
159*6747Sga159272 				"of %d\n", readcnt, readargs.count);
1600Sstevel@tonic-gate #endif
1610Sstevel@tonic-gate 			done = TRUE;
1620Sstevel@tonic-gate 		}
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 		count += readcnt;
1650Sstevel@tonic-gate 		filep->offset += readcnt;
1660Sstevel@tonic-gate 		buf_offset += readcnt;
1670Sstevel@tonic-gate 		readargs.r_offset += readcnt;
1680Sstevel@tonic-gate 		if ((blks_read++ & 0x3) == 0)
1690Sstevel@tonic-gate 			printf("%c\b", ind[pos++ & 3]);
1700Sstevel@tonic-gate 	} while (count < size && !done);
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	return (count);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate static vtype_t nf4_to_vt[] = {
1770Sstevel@tonic-gate 	VBAD, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
1780Sstevel@tonic-gate };
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate int
nfs4getattr(struct nfs_file * nfp,struct vattr * vap)1810Sstevel@tonic-gate nfs4getattr(struct nfs_file *nfp, struct vattr *vap)
1820Sstevel@tonic-gate {
1830Sstevel@tonic-gate 	enum clnt_stat	status;
1840Sstevel@tonic-gate 	attr4_bitmap1_t bitmap1;
1850Sstevel@tonic-gate 	attr4_bitmap2_t bitmap2;
1860Sstevel@tonic-gate 	getattr4arg_t	getattrargs;
1870Sstevel@tonic-gate 	getattr4res_t	getattrres;
1880Sstevel@tonic-gate 	b_fattr4_t	*bfattr4;
1890Sstevel@tonic-gate 	utf8string	str;
1900Sstevel@tonic-gate 	char		tagname[] = "inetboot getattr";
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	bzero(&getattrres, sizeof (getattrres));
1930Sstevel@tonic-gate 	/*
1940Sstevel@tonic-gate 	 * Putfh
1950Sstevel@tonic-gate 	 */
1960Sstevel@tonic-gate 	str.utf8string_len = sizeof (tagname) - 1;
1970Sstevel@tonic-gate 	str.utf8string_val = tagname;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (nfp->fh.fh4.len > 0)
2000Sstevel@tonic-gate 		compound_init(&getattrargs.ga_arg, &str, 0, 2, &nfp->fh.fh4);
2010Sstevel@tonic-gate 	else
2020Sstevel@tonic-gate 		compound_init(&getattrargs.ga_arg, &str, 0, 2, NULL);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/*
2050Sstevel@tonic-gate 	 * getattr
2060Sstevel@tonic-gate 	 */
2070Sstevel@tonic-gate 	getattrargs.ga_opgetattr = OP_GETATTR;
2080Sstevel@tonic-gate 	/*
2090Sstevel@tonic-gate 	 * Set up the attribute bitmap.  We pretty much need everything
2100Sstevel@tonic-gate 	 * except for the filehandle and supported attrs.
2110Sstevel@tonic-gate 	 */
2120Sstevel@tonic-gate 	bitmap1.word = 0;
2130Sstevel@tonic-gate 	bitmap1.bm_fattr4_type = 1;
2140Sstevel@tonic-gate 	bitmap1.bm_fattr4_size = 1;
2150Sstevel@tonic-gate 	bitmap1.bm_fattr4_fileid = 1;
2160Sstevel@tonic-gate 	bitmap2.word = 0;
2170Sstevel@tonic-gate 	bitmap2.bm_fattr4_mode = 1;
2180Sstevel@tonic-gate 	bitmap2.bm_fattr4_time_access = 1;
2190Sstevel@tonic-gate 	bitmap2.bm_fattr4_time_metadata = 1;
2200Sstevel@tonic-gate 	bitmap2.bm_fattr4_time_modify = 1;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	getattrargs.ga_attr_req.b_bitmap_len = NFS4_MAX_BITWORDS;
2230Sstevel@tonic-gate 	getattrargs.ga_attr_req.b_bitmap_val[0] = bitmap1.word;
2240Sstevel@tonic-gate 	getattrargs.ga_attr_req.b_bitmap_val[1] = bitmap2.word;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	status = CLNT_CALL(root_CLIENT, NFSPROC4_COMPOUND, xdr_getattr4_args,
227*6747Sga159272 	    (caddr_t)&getattrargs, xdr_getattr4_res,
228*6747Sga159272 	    (caddr_t)&getattrres, zero_timeout);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	if (status != RPC_SUCCESS) {
2310Sstevel@tonic-gate 		dprintf("nfs4getattr: RPC error %d\n", status);
2320Sstevel@tonic-gate 		return (-1);
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	if (getattrres.gr_attr_status != NFS4_OK) {
2360Sstevel@tonic-gate 		nfs4_error(getattrres.gr_attr_status);
2370Sstevel@tonic-gate 		return (getattrres.gr_attr_status);
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	bfattr4 = &getattrres.gr_attrs;
2410Sstevel@tonic-gate 	if (vap->va_mask & AT_TYPE) {
2420Sstevel@tonic-gate 		if (bfattr4->b_fattr4_type < NF4REG ||
2430Sstevel@tonic-gate 		    bfattr4->b_fattr4_type > NF4FIFO)
2440Sstevel@tonic-gate 			vap->va_type = VBAD;
2450Sstevel@tonic-gate 		else
2460Sstevel@tonic-gate 			vap->va_type = nf4_to_vt[bfattr4->b_fattr4_type];
2470Sstevel@tonic-gate 	}
2480Sstevel@tonic-gate 	if (vap->va_mask & AT_MODE)
2490Sstevel@tonic-gate 		vap->va_mode = (mode_t)bfattr4->b_fattr4_mode;
2500Sstevel@tonic-gate 	if (vap->va_mask & AT_SIZE)
2510Sstevel@tonic-gate 		vap->va_size = (u_offset_t)bfattr4->b_fattr4_size;
2520Sstevel@tonic-gate 	if (vap->va_mask & AT_NODEID)
2530Sstevel@tonic-gate 		vap->va_nodeid = (uint64_t)bfattr4->b_fattr4_fileid;
2540Sstevel@tonic-gate 	/*
2550Sstevel@tonic-gate 	 * XXX - may need to do something more here.
2560Sstevel@tonic-gate 	 */
2570Sstevel@tonic-gate 	if (vap->va_mask & AT_ATIME) {
2580Sstevel@tonic-gate 		vap->va_atime.tv_sec = bfattr4->b_fattr4_time_access.seconds;
2590Sstevel@tonic-gate 		vap->va_atime.tv_nsec = bfattr4->b_fattr4_time_access.nseconds;
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 	if (vap->va_mask & AT_CTIME) {
2620Sstevel@tonic-gate 		vap->va_ctime.tv_sec = bfattr4->b_fattr4_time_metadata.seconds;
2630Sstevel@tonic-gate 		vap->va_ctime.tv_nsec =
264*6747Sga159272 		    bfattr4->b_fattr4_time_metadata.nseconds;
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 	if (vap->va_mask & AT_MTIME) {
2670Sstevel@tonic-gate 		vap->va_mtime.tv_sec = bfattr4->b_fattr4_time_modify.seconds;
2680Sstevel@tonic-gate 		vap->va_mtime.tv_nsec = bfattr4->b_fattr4_time_modify.nseconds;
2690Sstevel@tonic-gate 	}
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	return (NFS4_OK);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate  * Display nfs error messages.
2760Sstevel@tonic-gate  */
2770Sstevel@tonic-gate /*ARGSUSED*/
2780Sstevel@tonic-gate void
nfs4_error(enum nfsstat4 status)2790Sstevel@tonic-gate nfs4_error(enum nfsstat4 status)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate 	if (!(boothowto & RB_DEBUG))
2820Sstevel@tonic-gate 		return;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	switch (status) {
2850Sstevel@tonic-gate 	case NFS4_OK:
2860Sstevel@tonic-gate 		printf("NFS: No error.\n");
2870Sstevel@tonic-gate 		break;
2880Sstevel@tonic-gate 	case NFS4ERR_PERM:
2890Sstevel@tonic-gate 		printf("NFS: Not owner.\n");
2900Sstevel@tonic-gate 		break;
2910Sstevel@tonic-gate 	case NFS4ERR_NOENT:
2920Sstevel@tonic-gate #ifdef	NFS_OPS_DEBUG
2930Sstevel@tonic-gate 		printf("NFS: No such file or directory.\n");
2940Sstevel@tonic-gate #endif	/* NFS_OPS_DEBUG */
2950Sstevel@tonic-gate 		break;
2960Sstevel@tonic-gate 	case NFS4ERR_IO:
2970Sstevel@tonic-gate 		printf("NFS: IO ERROR occurred on NFS server.\n");
2980Sstevel@tonic-gate 		break;
2990Sstevel@tonic-gate 	case NFS4ERR_NXIO:
3000Sstevel@tonic-gate 		printf("NFS: No such device or address.\n");
3010Sstevel@tonic-gate 		break;
3020Sstevel@tonic-gate 	case NFS4ERR_ACCESS:
3030Sstevel@tonic-gate 		printf("NFS: Permission denied.\n");
3040Sstevel@tonic-gate 		break;
3050Sstevel@tonic-gate 	case NFS4ERR_EXIST:
3060Sstevel@tonic-gate 		printf("NFS: File exists.\n");
3070Sstevel@tonic-gate 		break;
3080Sstevel@tonic-gate 	case NFS4ERR_XDEV:
3090Sstevel@tonic-gate 		printf("NFS: Cross device hard link.\n");
3100Sstevel@tonic-gate 		break;
3110Sstevel@tonic-gate 	case NFS4ERR_NOTDIR:
3120Sstevel@tonic-gate 		printf("NFS: Not a directory.\n");
3130Sstevel@tonic-gate 		break;
3140Sstevel@tonic-gate 	case NFS4ERR_ISDIR:
3150Sstevel@tonic-gate 		printf("NFS: Is a directory.\n");
3160Sstevel@tonic-gate 		break;
3170Sstevel@tonic-gate 	case NFS4ERR_INVAL:
3180Sstevel@tonic-gate 		printf("NFS: Invalid argument.\n");
3190Sstevel@tonic-gate 		break;
3200Sstevel@tonic-gate 	case NFS4ERR_FBIG:
3210Sstevel@tonic-gate 		printf("NFS: File too large.\n");
3220Sstevel@tonic-gate 		break;
3230Sstevel@tonic-gate 	case NFS4ERR_NOSPC:
3240Sstevel@tonic-gate 		printf("NFS: No space left on device.\n");
3250Sstevel@tonic-gate 		break;
3260Sstevel@tonic-gate 	case NFS4ERR_ROFS:
3270Sstevel@tonic-gate 		printf("NFS: Read-only filesystem.\n");
3280Sstevel@tonic-gate 		break;
3290Sstevel@tonic-gate 	case NFS4ERR_MLINK:
3300Sstevel@tonic-gate 		printf("NFS: Too many hard links.\n");
3310Sstevel@tonic-gate 		break;
3320Sstevel@tonic-gate 	case NFS4ERR_NAMETOOLONG:
3330Sstevel@tonic-gate 		printf("NFS: File name too long.\n");
3340Sstevel@tonic-gate 		break;
3350Sstevel@tonic-gate 	case NFS4ERR_NOTEMPTY:
3360Sstevel@tonic-gate 		printf("NFS: Directory not empty.\n");
3370Sstevel@tonic-gate 		break;
3380Sstevel@tonic-gate 	case NFS4ERR_DQUOT:
3390Sstevel@tonic-gate 		printf("NFS: Disk quota exceeded.\n");
3400Sstevel@tonic-gate 		break;
3410Sstevel@tonic-gate 	case NFS4ERR_STALE:
3420Sstevel@tonic-gate 		printf("NFS: Stale file handle.\n");
3430Sstevel@tonic-gate 		break;
3440Sstevel@tonic-gate 	case NFS4ERR_BADHANDLE:
3450Sstevel@tonic-gate 		printf("NFS: Illegal NFS file handle.\n");
3460Sstevel@tonic-gate 		break;
3470Sstevel@tonic-gate 	case NFS4ERR_BAD_COOKIE:
3480Sstevel@tonic-gate 		printf("NFS: Stale Cookie.\n");
3490Sstevel@tonic-gate 		break;
3500Sstevel@tonic-gate 	case NFS4ERR_NOTSUPP:
3510Sstevel@tonic-gate 		printf("NFS: Operation is not supported.\n");
3520Sstevel@tonic-gate 		break;
3530Sstevel@tonic-gate 	case NFS4ERR_TOOSMALL:
3540Sstevel@tonic-gate 		printf("NFS: Buffer too small.\n");
3550Sstevel@tonic-gate 		break;
3560Sstevel@tonic-gate 	case NFS4ERR_SERVERFAULT:
3570Sstevel@tonic-gate 		printf("NFS: Server fault.\n");
3580Sstevel@tonic-gate 		break;
3590Sstevel@tonic-gate 	case NFS4ERR_BADTYPE:
3600Sstevel@tonic-gate 		printf("NFS: Unsupported object type.\n");
3610Sstevel@tonic-gate 		break;
3620Sstevel@tonic-gate 	case NFS4ERR_BAD_STATEID:
3630Sstevel@tonic-gate 		printf("NFS: Bad stateid\n");
3640Sstevel@tonic-gate 		break;
3650Sstevel@tonic-gate 	case NFS4ERR_BAD_SEQID:
3660Sstevel@tonic-gate 		printf("NFS: Bad seqid\n");
3670Sstevel@tonic-gate 		break;
3680Sstevel@tonic-gate 	default:
3690Sstevel@tonic-gate 		printf("NFS: unknown error.\n");
3700Sstevel@tonic-gate 		break;
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate  * lookup one component.  for multicomponent lookup use a driver like lookup().
3760Sstevel@tonic-gate  */
3770Sstevel@tonic-gate struct nfs_file *
nfs4lookup(struct nfs_file * dir,char * name,int * nstat)3780Sstevel@tonic-gate nfs4lookup(struct nfs_file *dir, char *name, int *nstat)
3790Sstevel@tonic-gate {
3800Sstevel@tonic-gate 	static struct nfs_file	cd;
3810Sstevel@tonic-gate 	attr4_bitmap1_t		bitmap1;
3820Sstevel@tonic-gate 	lookup4arg_t		lookupargs;
3830Sstevel@tonic-gate 	lookup4res_t		lookupres;
3840Sstevel@tonic-gate 	enum clnt_stat		status;
3850Sstevel@tonic-gate 	utf8string		str;
3860Sstevel@tonic-gate 	char			tagname[] = "inetboot lookup";
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	/*
3890Sstevel@tonic-gate 	 * NFSv4 uses a special LOOKUPP op
3900Sstevel@tonic-gate 	 * for looking up the parent directory.
3910Sstevel@tonic-gate 	 */
3920Sstevel@tonic-gate 	if (strcmp(name, "..") == 0)
3930Sstevel@tonic-gate 		return (nfs4lookupp(dir, nstat, NULL));
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	*nstat = (int)NFS4_OK;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	bzero(&lookupres, sizeof (lookupres));
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/*
4000Sstevel@tonic-gate 	 * Check if we have a filehandle and initialize the compound
4010Sstevel@tonic-gate 	 * with putfh or putrootfh appropriately.
4020Sstevel@tonic-gate 	 */
4030Sstevel@tonic-gate 	str.utf8string_len = sizeof (tagname) - 1;
4040Sstevel@tonic-gate 	str.utf8string_val = tagname;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	if (dir->fh.fh4.len > 0)
4070Sstevel@tonic-gate 		compound_init(&lookupargs.la_arg, &str, 0, 3, &dir->fh.fh4);
4080Sstevel@tonic-gate 	else
4090Sstevel@tonic-gate 		compound_init(&lookupargs.la_arg, &str, 0, 3, NULL);
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	/*
4120Sstevel@tonic-gate 	 * lookup
4130Sstevel@tonic-gate 	 */
4140Sstevel@tonic-gate 	lookupargs.la_oplookup = OP_LOOKUP;
4150Sstevel@tonic-gate 	/*
4160Sstevel@tonic-gate 	 * convert the pathname from char * to utf8string
4170Sstevel@tonic-gate 	 */
4180Sstevel@tonic-gate 	lookupargs.la_pathname.utf8string_len = strlen(name);
4190Sstevel@tonic-gate 	lookupargs.la_pathname.utf8string_val =
420*6747Sga159272 	    bkmem_alloc(lookupargs.la_pathname.utf8string_len);
4210Sstevel@tonic-gate 	if (lookupargs.la_pathname.utf8string_val == NULL) {
4220Sstevel@tonic-gate 		dprintf("nfs4lookup: bkmem_alloc failed\n");
4230Sstevel@tonic-gate 		return (NULL);
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 	bcopy(name, lookupargs.la_pathname.utf8string_val,
426*6747Sga159272 	    lookupargs.la_pathname.utf8string_len);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	/*
4290Sstevel@tonic-gate 	 * Setup the attr bitmap.  All we need is the type and filehandle info
4300Sstevel@tonic-gate 	 */
4310Sstevel@tonic-gate 	lookupargs.la_opgetattr = OP_GETATTR;
4320Sstevel@tonic-gate 	bitmap1.word = 0;
4330Sstevel@tonic-gate 	bitmap1.bm_fattr4_type = 1;
4340Sstevel@tonic-gate 	bitmap1.bm_fattr4_filehandle = 1;
4350Sstevel@tonic-gate 	lookupargs.la_attr_req.b_bitmap_len = 1;
4360Sstevel@tonic-gate 	lookupargs.la_attr_req.b_bitmap_val[0] = bitmap1.word;
4370Sstevel@tonic-gate 	lookupargs.la_attr_req.b_bitmap_val[1] = 0;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	status = CLNT_CALL(root_CLIENT, NFSPROC4_COMPOUND, xdr_lookup4_args,
440*6747Sga159272 	    (caddr_t)&lookupargs, xdr_lookup4_res,
441*6747Sga159272 	    (caddr_t)&lookupres, zero_timeout);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	if (status != RPC_SUCCESS) {
4440Sstevel@tonic-gate 		dprintf("nfs4lookup: RPC error. status %d\n", status);
4450Sstevel@tonic-gate 		return (NULL);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	if (lookupres.lr_lookup_status != NFS4_OK) {
4490Sstevel@tonic-gate #ifdef DEBUG
4500Sstevel@tonic-gate 		dprintf("nfs4lookup: lookup status = %d\n",
451*6747Sga159272 		    lookupres.lr_lookup_status);
4520Sstevel@tonic-gate #endif
4530Sstevel@tonic-gate 		nfs4_error(lookupres.lr_lookup_status);
4540Sstevel@tonic-gate 		*nstat = (int)lookupres.lr_lookup_status;
4550Sstevel@tonic-gate 		if (lookupargs.la_pathname.utf8string_val != NULL)
4560Sstevel@tonic-gate 			bkmem_free(lookupargs.la_pathname.utf8string_val,
457*6747Sga159272 			    lookupargs.la_pathname.utf8string_len);
4580Sstevel@tonic-gate 		return (NULL);
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	if (lookupres.lr_attr_status != NFS4_OK) {
4620Sstevel@tonic-gate #ifdef DEBUG
4630Sstevel@tonic-gate 		dprintf("nfs4lookup: getattr status = %d\n",
464*6747Sga159272 		    lookupres.lr_attr_status);
4650Sstevel@tonic-gate #endif
4660Sstevel@tonic-gate 		nfs4_error(lookupres.lr_attr_status);
4670Sstevel@tonic-gate 		*nstat = (int)lookupres.lr_attr_status;
4680Sstevel@tonic-gate 		if (lookupargs.la_pathname.utf8string_val != NULL)
4690Sstevel@tonic-gate 			bkmem_free(lookupargs.la_pathname.utf8string_val,
470*6747Sga159272 			    lookupargs.la_pathname.utf8string_len);
4710Sstevel@tonic-gate 		return (NULL);
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/*
4750Sstevel@tonic-gate 	 * We have all the information we need to update the file pointer
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	bzero((caddr_t)&cd, sizeof (struct nfs_file));
4780Sstevel@tonic-gate 	cd.version = NFS_V4;
4790Sstevel@tonic-gate 	cd.ftype.type4 = lookupres.lr_attrs.b_fattr4_type;
4800Sstevel@tonic-gate 	cd.fh.fh4.len = lookupres.lr_attrs.b_fattr4_filehandle.len;
4810Sstevel@tonic-gate 	bcopy(lookupres.lr_attrs.b_fattr4_filehandle.data, cd.fh.fh4.data,
482*6747Sga159272 	    cd.fh.fh4.len);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * Free the arg string
4860Sstevel@tonic-gate 	 */
4870Sstevel@tonic-gate 	if (lookupargs.la_pathname.utf8string_val != NULL)
4880Sstevel@tonic-gate 		bkmem_free(lookupargs.la_pathname.utf8string_val,
489*6747Sga159272 		    lookupargs.la_pathname.utf8string_len);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	return (&cd);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate /*
4950Sstevel@tonic-gate  * lookup parent directory.
4960Sstevel@tonic-gate  */
4970Sstevel@tonic-gate struct nfs_file *
nfs4lookupp(struct nfs_file * dir,int * nstat,uint64_t * fileid)4980Sstevel@tonic-gate nfs4lookupp(struct nfs_file *dir, int *nstat, uint64_t *fileid)
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	static struct nfs_file	cd;
5010Sstevel@tonic-gate 	attr4_bitmap1_t		bitmap1;
5020Sstevel@tonic-gate 	lookupp4arg_t		lookuppargs;
5030Sstevel@tonic-gate 	lookup4res_t		lookupres;
5040Sstevel@tonic-gate 	enum clnt_stat		status;
5050Sstevel@tonic-gate 	utf8string		str;
5060Sstevel@tonic-gate 	char			tagname[] = "inetboot lookupp";
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	*nstat = (int)NFS4_OK;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	bzero(&lookupres, sizeof (lookupres));
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	/*
5130Sstevel@tonic-gate 	 * Check if we have a filehandle and initialize the compound
5140Sstevel@tonic-gate 	 * with putfh or putrootfh appropriately.
5150Sstevel@tonic-gate 	 */
5160Sstevel@tonic-gate 	str.utf8string_len = sizeof (tagname) - 1;
5170Sstevel@tonic-gate 	str.utf8string_val = tagname;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	if (dir->fh.fh4.len > 0)
5200Sstevel@tonic-gate 		compound_init(&lookuppargs.la_arg, &str, 0, 3, &dir->fh.fh4);
5210Sstevel@tonic-gate 	else
5220Sstevel@tonic-gate 		compound_init(&lookuppargs.la_arg, &str, 0, 3, NULL);
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	/*
5250Sstevel@tonic-gate 	 * lookupp
5260Sstevel@tonic-gate 	 */
5270Sstevel@tonic-gate 	lookuppargs.la_oplookupp = OP_LOOKUPP;
5280Sstevel@tonic-gate 	/*
5290Sstevel@tonic-gate 	 * Setup the attr bitmap.  Normally, all we need is the type and
5300Sstevel@tonic-gate 	 * filehandle info, but getdents might require the fileid of the
5310Sstevel@tonic-gate 	 * parent.
5320Sstevel@tonic-gate 	 */
5330Sstevel@tonic-gate 	lookuppargs.la_opgetattr = OP_GETATTR;
5340Sstevel@tonic-gate 	bitmap1.word = 0;
5350Sstevel@tonic-gate 	bitmap1.bm_fattr4_type = 1;
5360Sstevel@tonic-gate 	bitmap1.bm_fattr4_filehandle = 1;
5370Sstevel@tonic-gate 	if (fileid != NULL)
5380Sstevel@tonic-gate 		bitmap1.bm_fattr4_fileid = 1;
5390Sstevel@tonic-gate 	lookuppargs.la_attr_req.b_bitmap_len = 1;
5400Sstevel@tonic-gate 	lookuppargs.la_attr_req.b_bitmap_val[0] = bitmap1.word;
5410Sstevel@tonic-gate 	lookuppargs.la_attr_req.b_bitmap_val[1] = 0;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	status = CLNT_CALL(root_CLIENT, NFSPROC4_COMPOUND, xdr_lookupp4_args,
544*6747Sga159272 	    (caddr_t)&lookuppargs, xdr_lookup4_res,
545*6747Sga159272 	    (caddr_t)&lookupres, zero_timeout);
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	if (status != RPC_SUCCESS) {
5480Sstevel@tonic-gate 		dprintf("nfs4lookupp: RPC error. status %d\n", status);
5490Sstevel@tonic-gate 		return (NULL);
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	if (lookupres.lr_lookup_status != NFS4_OK) {
5530Sstevel@tonic-gate #ifdef DEBUG
5540Sstevel@tonic-gate 		dprintf("nfs4lookupp: lookupp status = %d\n",
555*6747Sga159272 		    lookupres.lr_lookup_status);
5560Sstevel@tonic-gate #endif
5570Sstevel@tonic-gate 		nfs4_error(lookupres.lr_lookup_status);
5580Sstevel@tonic-gate 		*nstat = (int)lookupres.lr_lookup_status;
5590Sstevel@tonic-gate 		return (NULL);
5600Sstevel@tonic-gate 	}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	if (lookupres.lr_attr_status != NFS4_OK) {
5630Sstevel@tonic-gate #ifdef DEBUG
5640Sstevel@tonic-gate 		dprintf("nfs4lookupp: getattr status = %d\n",
565*6747Sga159272 		    lookupres.lr_attr_status);
5660Sstevel@tonic-gate #endif
5670Sstevel@tonic-gate 		nfs4_error(lookupres.lr_attr_status);
5680Sstevel@tonic-gate 		*nstat = (int)lookupres.lr_attr_status;
5690Sstevel@tonic-gate 		return (NULL);
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	/*
5730Sstevel@tonic-gate 	 * We have all the information we need to update the file pointer
5740Sstevel@tonic-gate 	 */
5750Sstevel@tonic-gate 	bzero((caddr_t)&cd, sizeof (struct nfs_file));
5760Sstevel@tonic-gate 	cd.version = NFS_V4;
5770Sstevel@tonic-gate 	cd.ftype.type4 = lookupres.lr_attrs.b_fattr4_type;
5780Sstevel@tonic-gate 	cd.fh.fh4.len = lookupres.lr_attrs.b_fattr4_filehandle.len;
5790Sstevel@tonic-gate 	bcopy(lookupres.lr_attrs.b_fattr4_filehandle.data, cd.fh.fh4.data,
580*6747Sga159272 	    cd.fh.fh4.len);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	/*
5830Sstevel@tonic-gate 	 * Fill in the fileid if the user passed in one
5840Sstevel@tonic-gate 	 */
5850Sstevel@tonic-gate 	if (fileid != NULL)
5860Sstevel@tonic-gate 		*fileid = lookupres.lr_attrs.b_fattr4_fileid;
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	return (&cd);
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate  * Gets symbolic link into pathname.
5930Sstevel@tonic-gate  */
5940Sstevel@tonic-gate int
nfs4getsymlink(struct nfs_file * cfile,char ** path)5950Sstevel@tonic-gate nfs4getsymlink(struct nfs_file *cfile, char **path)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 	enum clnt_stat	status;
5980Sstevel@tonic-gate 	readlink4arg_t	readlinkargs;
5990Sstevel@tonic-gate 	readlink4res_t	readlinkres;
6000Sstevel@tonic-gate 	static char	symlink_path[NFS_MAXPATHLEN];
6010Sstevel@tonic-gate 	int		spathlen;
6020Sstevel@tonic-gate 	utf8string	str;
6030Sstevel@tonic-gate 	char		tagname[] = "inetboot getsymlink";
6040Sstevel@tonic-gate 	int		error = NFS4_OK;
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	bzero(&readlinkres, sizeof (readlinkres));
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	/*
6090Sstevel@tonic-gate 	 * readlink
6100Sstevel@tonic-gate 	 */
6110Sstevel@tonic-gate 	str.utf8string_len = sizeof (tagname) - 1;
6120Sstevel@tonic-gate 	str.utf8string_val = tagname;
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	if (cfile->fh.fh4.len > 0)
6150Sstevel@tonic-gate 		compound_init(&readlinkargs.rl_arg, &str, 0, 2,
616*6747Sga159272 		    &cfile->fh.fh4);
6170Sstevel@tonic-gate 	else
6180Sstevel@tonic-gate 		compound_init(&readlinkargs.rl_arg, &str, 0, 2,	NULL);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	readlinkargs.rl_opreadlink = OP_READLINK;
6210Sstevel@tonic-gate 	status = CLNT_CALL(root_CLIENT, NFSPROC4_COMPOUND, xdr_readlink4_args,
622*6747Sga159272 	    (caddr_t)&readlinkargs, xdr_readlink4_res,
623*6747Sga159272 	    (caddr_t)&readlinkres, zero_timeout);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	if (status != RPC_SUCCESS) {
6260Sstevel@tonic-gate 		dprintf("nfs4getsymlink: RPC readlink error %d\n", status);
6270Sstevel@tonic-gate 		error = -1;
6280Sstevel@tonic-gate 		goto out;
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (readlinkres.rl_status != NFS4_OK) {
6320Sstevel@tonic-gate 		nfs4_error(readlinkres.rl_status);
6330Sstevel@tonic-gate 		error = readlinkres.rl_status;
6340Sstevel@tonic-gate 		goto out;
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	/*
6380Sstevel@tonic-gate 	 * Convert the utf8string to a normal character string
6390Sstevel@tonic-gate 	 */
6400Sstevel@tonic-gate 	spathlen = readlinkres.rl_link.utf8string_len;
6410Sstevel@tonic-gate 	if (spathlen <= 0 || readlinkres.rl_link.utf8string_val == NULL) {
6420Sstevel@tonic-gate 		*path = NULL;
6430Sstevel@tonic-gate 		error = readlinkres.rl_status;
6440Sstevel@tonic-gate 		goto out;
6450Sstevel@tonic-gate 	}
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	bcopy(readlinkres.rl_link.utf8string_val, symlink_path, spathlen);
6480Sstevel@tonic-gate 	symlink_path[spathlen] = '\0';
6490Sstevel@tonic-gate 	*path = symlink_path;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate out:
6520Sstevel@tonic-gate 	/*
6530Sstevel@tonic-gate 	 * Free the results
6540Sstevel@tonic-gate 	 */
6550Sstevel@tonic-gate 	if (readlinkres.rl_link.utf8string_val != NULL)
6560Sstevel@tonic-gate 		bkmem_free(readlinkres.rl_link.utf8string_val, spathlen);
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	return (error);
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate /*
6620Sstevel@tonic-gate  * Should just forget about the tag, but will leave in support for the time
6630Sstevel@tonic-gate  * being.
6640Sstevel@tonic-gate  */
6650Sstevel@tonic-gate void
compound_init(b_compound_t * cp,utf8string * str,uint_t mvers,uint_t arglen,struct nfs_bfh4 * pfh)6660Sstevel@tonic-gate compound_init(b_compound_t *cp, utf8string *str, uint_t mvers, uint_t arglen,
6670Sstevel@tonic-gate 		struct nfs_bfh4 *pfh)
6680Sstevel@tonic-gate {
6690Sstevel@tonic-gate 	if (str == NULL || str->utf8string_len == 0) {
6700Sstevel@tonic-gate 		cp->ca_tag.utf8string_len = 0;
6710Sstevel@tonic-gate 		cp->ca_tag.utf8string_val = NULL;
6720Sstevel@tonic-gate 	} else {
6730Sstevel@tonic-gate 		cp->ca_tag.utf8string_len = str->utf8string_len;
6740Sstevel@tonic-gate 		cp->ca_tag.utf8string_val = str->utf8string_val;
6750Sstevel@tonic-gate 	}
6760Sstevel@tonic-gate 	cp->ca_minorversion = mvers;
6770Sstevel@tonic-gate 	cp->ca_argarray_len = arglen;
6780Sstevel@tonic-gate 	if (pfh == NULL) {
6790Sstevel@tonic-gate 		cp->ca_isputrootfh = TRUE;
6800Sstevel@tonic-gate 		cp->ca_opputfh.pf_opnum = OP_PUTROOTFH;
6810Sstevel@tonic-gate 	} else {
6820Sstevel@tonic-gate 		cp->ca_isputrootfh = FALSE;
6830Sstevel@tonic-gate 		cp->ca_opputfh.pf_opnum = OP_PUTFH;
6840Sstevel@tonic-gate 		cp->ca_opputfh.pf_filehandle.len = pfh->len;
6850Sstevel@tonic-gate 		bcopy(pfh->data, cp->ca_opputfh.pf_filehandle.data, pfh->len);
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate }
688