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