17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4a634bb8Sga159272 * Common Development and Distribution License (the "License"). 6*4a634bb8Sga159272 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*4a634bb8Sga159272 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate * 257c478bd9Sstevel@tonic-gate * Simple nfs ops - open, close, read, and lseek. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <rpc/types.h> 317c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 327c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 337c478bd9Sstevel@tonic-gate #include "clnt.h" 347c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 357c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 367c478bd9Sstevel@tonic-gate #include <errno.h> 377c478bd9Sstevel@tonic-gate #include <sys/promif.h> 387c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 397c478bd9Sstevel@tonic-gate #include "nfs_inet.h" 407c478bd9Sstevel@tonic-gate #include <sys/stat.h> 417c478bd9Sstevel@tonic-gate #include <sys/bootvfs.h> 427c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h> 437c478bd9Sstevel@tonic-gate #include <sys/salib.h> 447c478bd9Sstevel@tonic-gate #include <sys/sacache.h> 457c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 467c478bd9Sstevel@tonic-gate #include "brpc.h" 477c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define dprintf if (boothowto & RB_DEBUG) printf 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate static struct timeval zero_timeout = {0, 0}; /* default */ 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* 547c478bd9Sstevel@tonic-gate * NFS Version 2 specific functions 557c478bd9Sstevel@tonic-gate */ 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate ssize_t 587c478bd9Sstevel@tonic-gate nfsread(struct nfs_file *filep, char *buf, size_t size) 597c478bd9Sstevel@tonic-gate { 607c478bd9Sstevel@tonic-gate readargs read_args; 617c478bd9Sstevel@tonic-gate readres read_res; 627c478bd9Sstevel@tonic-gate enum clnt_stat read_stat; 637c478bd9Sstevel@tonic-gate uint_t readcnt = 0; /* # bytes read by nfs */ 647c478bd9Sstevel@tonic-gate uint_t count = 0; /* # bytes transferred to buf */ 657c478bd9Sstevel@tonic-gate int done = FALSE; /* last block has come in */ 667c478bd9Sstevel@tonic-gate int framing_errs = 0; /* stack errors */ 677c478bd9Sstevel@tonic-gate char *buf_offset; /* current buffer offset */ 687c478bd9Sstevel@tonic-gate struct timeval timeout; 697c478bd9Sstevel@tonic-gate static uint_t pos; /* progress indicator counter */ 707c478bd9Sstevel@tonic-gate static char ind[] = "|/-\\"; /* progress indicator */ 717c478bd9Sstevel@tonic-gate static int blks_read; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate read_args.file = filep->fh.fh2; /* structure copy */ 747c478bd9Sstevel@tonic-gate read_args.offset = filep->offset; 757c478bd9Sstevel@tonic-gate buf_offset = buf; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate /* Optimize for reads of less than one block size */ 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate if (nfs_readsize == 0) 807c478bd9Sstevel@tonic-gate nfs_readsize = READ_SIZE; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate if (size < nfs_readsize) 837c478bd9Sstevel@tonic-gate read_args.count = size; 847c478bd9Sstevel@tonic-gate else 857c478bd9Sstevel@tonic-gate read_args.count = nfs_readsize; 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate do { 887c478bd9Sstevel@tonic-gate /* use the user's buffer to stuff the data into. */ 897c478bd9Sstevel@tonic-gate read_res.readres_u.reply.data.data_val = buf_offset; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * Handle the case where the file does not end 937c478bd9Sstevel@tonic-gate * on a block boundary. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate if ((count + read_args.count) > size) 967c478bd9Sstevel@tonic-gate read_args.count = size - count; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate timeout.tv_sec = NFS_REXMIT_MIN; /* Total wait for call */ 997c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 1007c478bd9Sstevel@tonic-gate do { 1017c478bd9Sstevel@tonic-gate read_stat = CLNT_CALL(root_CLIENT, NFSPROC_READ, 1027c478bd9Sstevel@tonic-gate xdr_readargs, (caddr_t)&read_args, 1037c478bd9Sstevel@tonic-gate xdr_readres, (caddr_t)&read_res, timeout); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate if (read_stat == RPC_TIMEDOUT) { 1067c478bd9Sstevel@tonic-gate dprintf("NFS read(%d) timed out. Retrying...\n", 1077c478bd9Sstevel@tonic-gate read_args.count); 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * If the remote is there and trying to respond, 1107c478bd9Sstevel@tonic-gate * but our stack is having trouble reassembling 1117c478bd9Sstevel@tonic-gate * the reply, reduce the read size in an 1127c478bd9Sstevel@tonic-gate * attempt to compensate. Reset the 1137c478bd9Sstevel@tonic-gate * transmission and reply wait timers. 1147c478bd9Sstevel@tonic-gate */ 1157c478bd9Sstevel@tonic-gate if (errno == ETIMEDOUT) 1167c478bd9Sstevel@tonic-gate framing_errs++; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if (framing_errs > NFS_MAX_FERRS && 1197c478bd9Sstevel@tonic-gate read_args.count > NFS_READ_DECR) { 1207c478bd9Sstevel@tonic-gate read_args.count -= NFS_READ_DECR; 1217c478bd9Sstevel@tonic-gate nfs_readsize -= NFS_READ_DECR; 1227c478bd9Sstevel@tonic-gate dprintf("NFS Read size now %d.\n", 1237c478bd9Sstevel@tonic-gate nfs_readsize); 1247c478bd9Sstevel@tonic-gate timeout.tv_sec = NFS_REXMIT_MIN; 1257c478bd9Sstevel@tonic-gate framing_errs = 0; 1267c478bd9Sstevel@tonic-gate } else { 1277c478bd9Sstevel@tonic-gate if (timeout.tv_sec < NFS_REXMIT_MAX) 1287c478bd9Sstevel@tonic-gate timeout.tv_sec++; 1297c478bd9Sstevel@tonic-gate else 1307c478bd9Sstevel@tonic-gate timeout.tv_sec = 0; 1317c478bd9Sstevel@tonic-gate /* default RPC */ 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate } while (read_stat == RPC_TIMEDOUT); 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate if (read_stat != RPC_SUCCESS) 1377c478bd9Sstevel@tonic-gate return (-1); 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate readcnt = read_res.readres_u.reply.data.data_len; 1407c478bd9Sstevel@tonic-gate /* 1417c478bd9Sstevel@tonic-gate * Handle the case where the file is simply empty, and 1427c478bd9Sstevel@tonic-gate * nothing could be read. 1437c478bd9Sstevel@tonic-gate */ 1447c478bd9Sstevel@tonic-gate if (readcnt == 0) 1457c478bd9Sstevel@tonic-gate break; /* eof */ 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* 1487c478bd9Sstevel@tonic-gate * Handle the case where the file is smaller than 1497c478bd9Sstevel@tonic-gate * the size of the read request, thus the request 1507c478bd9Sstevel@tonic-gate * couldn't be completely filled. 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate if (readcnt < read_args.count) { 1537c478bd9Sstevel@tonic-gate #ifdef NFS_OPS_DEBUG 1547c478bd9Sstevel@tonic-gate if ((boothowto & DBFLAGS) == DBFLAGS) 1557c478bd9Sstevel@tonic-gate printf("nfsread(): partial read %d" 1567c478bd9Sstevel@tonic-gate " instead of %d\n", 1577c478bd9Sstevel@tonic-gate readcnt, read_args.count); 1587c478bd9Sstevel@tonic-gate #endif 1597c478bd9Sstevel@tonic-gate done = TRUE; /* update the counts and exit */ 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* update various offsets */ 1637c478bd9Sstevel@tonic-gate count += readcnt; 1647c478bd9Sstevel@tonic-gate filep->offset += readcnt; 1657c478bd9Sstevel@tonic-gate buf_offset += readcnt; 1667c478bd9Sstevel@tonic-gate read_args.offset += readcnt; 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * round and round she goes (though not on every block.. 1697c478bd9Sstevel@tonic-gate * - OBP's take a fair bit of time to actually print stuff) 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate if ((blks_read++ & 0x3) == 0) 1727c478bd9Sstevel@tonic-gate printf("%c\b", ind[pos++ & 3]); 1737c478bd9Sstevel@tonic-gate } while (count < size && !done); 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate return (count); 1767c478bd9Sstevel@tonic-gate } 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate static vtype_t nf_to_vt[] = { 1797c478bd9Sstevel@tonic-gate VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK 1807c478bd9Sstevel@tonic-gate }; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate int 1837c478bd9Sstevel@tonic-gate nfsgetattr(struct nfs_file *nfp, struct vattr *vap) 1847c478bd9Sstevel@tonic-gate { 1857c478bd9Sstevel@tonic-gate enum clnt_stat getattr_stat; 1867c478bd9Sstevel@tonic-gate attrstat getattr_res; 1877c478bd9Sstevel@tonic-gate fattr *na; 1887c478bd9Sstevel@tonic-gate struct timeval timeout = {0, 0}; /* default */ 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate getattr_stat = CLNT_CALL(root_CLIENT, NFSPROC_GETATTR, 1917c478bd9Sstevel@tonic-gate xdr_nfs_fh, (caddr_t)&(nfp->fh.fh2), 1927c478bd9Sstevel@tonic-gate xdr_attrstat, (caddr_t)&getattr_res, timeout); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (getattr_stat != RPC_SUCCESS) { 1957c478bd9Sstevel@tonic-gate dprintf("nfs_getattr: RPC error %d\n", getattr_stat); 1967c478bd9Sstevel@tonic-gate return (-1); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate if (getattr_res.status != NFS_OK) { 1997c478bd9Sstevel@tonic-gate nfs_error(getattr_res.status); 2007c478bd9Sstevel@tonic-gate return (getattr_res.status); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* adapted from nattr_to_vattr() in nfs_client.c */ 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate na = &getattr_res.attrstat_u.attributes; 2067c478bd9Sstevel@tonic-gate if (vap->va_mask & AT_TYPE) { 2077c478bd9Sstevel@tonic-gate if (na->type < NFNON || na->type > NFSOCK) 2087c478bd9Sstevel@tonic-gate vap->va_type = VBAD; 2097c478bd9Sstevel@tonic-gate else 2107c478bd9Sstevel@tonic-gate vap->va_type = nf_to_vt[na->type]; 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate if (vap->va_mask & AT_MODE) 2137c478bd9Sstevel@tonic-gate vap->va_mode = na->mode; 2147c478bd9Sstevel@tonic-gate if (vap->va_mask & AT_SIZE) 2157c478bd9Sstevel@tonic-gate vap->va_size = na->size; 2167c478bd9Sstevel@tonic-gate if (vap->va_mask & AT_NODEID) 2177c478bd9Sstevel@tonic-gate vap->va_nodeid = na->fileid; 2187c478bd9Sstevel@tonic-gate if (vap->va_mask & AT_ATIME) { 2197c478bd9Sstevel@tonic-gate vap->va_atime.tv_sec = na->atime.seconds; 2207c478bd9Sstevel@tonic-gate vap->va_atime.tv_nsec = na->atime.useconds * 1000; 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate if (vap->va_mask & AT_CTIME) { 2237c478bd9Sstevel@tonic-gate vap->va_ctime.tv_sec = na->ctime.seconds; 2247c478bd9Sstevel@tonic-gate vap->va_ctime.tv_nsec = na->ctime.useconds * 1000; 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate if (vap->va_mask & AT_MTIME) { 2277c478bd9Sstevel@tonic-gate vap->va_mtime.tv_sec = na->mtime.seconds; 2287c478bd9Sstevel@tonic-gate vap->va_mtime.tv_nsec = na->mtime.useconds * 1000; 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate #ifdef NFS_OPS_DEBUG 2327c478bd9Sstevel@tonic-gate if ((boothowto & DBFLAGS) == DBFLAGS) 2337c478bd9Sstevel@tonic-gate printf("nfs_getattr(): done.\n"); 2347c478bd9Sstevel@tonic-gate #endif 2357c478bd9Sstevel@tonic-gate return (getattr_res.status); 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * Display nfs error messages. 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2427c478bd9Sstevel@tonic-gate void 2437c478bd9Sstevel@tonic-gate nfs_error(enum nfsstat status) 2447c478bd9Sstevel@tonic-gate { 2457c478bd9Sstevel@tonic-gate if (!(boothowto & RB_DEBUG)) 2467c478bd9Sstevel@tonic-gate return; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate switch (status) { 2497c478bd9Sstevel@tonic-gate case NFSERR_PERM: 2507c478bd9Sstevel@tonic-gate printf("NFS: Not owner.\n"); 2517c478bd9Sstevel@tonic-gate break; 2527c478bd9Sstevel@tonic-gate case NFSERR_NOENT: 2537c478bd9Sstevel@tonic-gate #ifdef NFS_OPS_DEBUG 2547c478bd9Sstevel@tonic-gate printf("NFS: No such file or directory.\n"); 2557c478bd9Sstevel@tonic-gate #endif /* NFS_OPS_DEBUG */ 2567c478bd9Sstevel@tonic-gate break; 2577c478bd9Sstevel@tonic-gate case NFSERR_IO: 2587c478bd9Sstevel@tonic-gate printf("NFS: IO ERROR occurred on NFS server.\n"); 2597c478bd9Sstevel@tonic-gate break; 2607c478bd9Sstevel@tonic-gate case NFSERR_NXIO: 2617c478bd9Sstevel@tonic-gate printf("NFS: No such device or address.\n"); 2627c478bd9Sstevel@tonic-gate break; 2637c478bd9Sstevel@tonic-gate case NFSERR_ACCES: 2647c478bd9Sstevel@tonic-gate printf("NFS: Permission denied.\n"); 2657c478bd9Sstevel@tonic-gate break; 2667c478bd9Sstevel@tonic-gate case NFSERR_EXIST: 2677c478bd9Sstevel@tonic-gate printf("NFS: File exists.\n"); 2687c478bd9Sstevel@tonic-gate break; 2697c478bd9Sstevel@tonic-gate case NFSERR_NODEV: 2707c478bd9Sstevel@tonic-gate printf("NFS: No such device.\n"); 2717c478bd9Sstevel@tonic-gate break; 2727c478bd9Sstevel@tonic-gate case NFSERR_NOTDIR: 2737c478bd9Sstevel@tonic-gate printf("NFS: Not a directory.\n"); 2747c478bd9Sstevel@tonic-gate break; 2757c478bd9Sstevel@tonic-gate case NFSERR_ISDIR: 2767c478bd9Sstevel@tonic-gate printf("NFS: Is a directory.\n"); 2777c478bd9Sstevel@tonic-gate break; 2787c478bd9Sstevel@tonic-gate case NFSERR_FBIG: 2797c478bd9Sstevel@tonic-gate printf("NFS: File too large.\n"); 2807c478bd9Sstevel@tonic-gate break; 2817c478bd9Sstevel@tonic-gate case NFSERR_NOSPC: 2827c478bd9Sstevel@tonic-gate printf("NFS: No space left on device.\n"); 2837c478bd9Sstevel@tonic-gate break; 2847c478bd9Sstevel@tonic-gate case NFSERR_ROFS: 2857c478bd9Sstevel@tonic-gate printf("NFS: Read-only filesystem.\n"); 2867c478bd9Sstevel@tonic-gate break; 2877c478bd9Sstevel@tonic-gate case NFSERR_NAMETOOLONG: 2887c478bd9Sstevel@tonic-gate printf("NFS: File name too long.\n"); 2897c478bd9Sstevel@tonic-gate break; 2907c478bd9Sstevel@tonic-gate case NFSERR_NOTEMPTY: 2917c478bd9Sstevel@tonic-gate printf("NFS: Directory not empty.\n"); 2927c478bd9Sstevel@tonic-gate break; 2937c478bd9Sstevel@tonic-gate case NFSERR_DQUOT: 2947c478bd9Sstevel@tonic-gate printf("NFS: Disk quota exceeded.\n"); 2957c478bd9Sstevel@tonic-gate break; 2967c478bd9Sstevel@tonic-gate case NFSERR_STALE: 2977c478bd9Sstevel@tonic-gate printf("NFS: Stale file handle.\n"); 2987c478bd9Sstevel@tonic-gate break; 2997c478bd9Sstevel@tonic-gate case NFSERR_WFLUSH: 3007c478bd9Sstevel@tonic-gate printf("NFS: server's write cache has been flushed.\n"); 3017c478bd9Sstevel@tonic-gate break; 3027c478bd9Sstevel@tonic-gate default: 3037c478bd9Sstevel@tonic-gate printf("NFS: unknown error.\n"); 3047c478bd9Sstevel@tonic-gate break; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate struct nfs_file * 3097c478bd9Sstevel@tonic-gate nfslookup(struct nfs_file *dir, char *name, int *nstat) 3107c478bd9Sstevel@tonic-gate { 3117c478bd9Sstevel@tonic-gate static struct nfs_file cd; 3127c478bd9Sstevel@tonic-gate diropargs dirop; 3137c478bd9Sstevel@tonic-gate diropres res_lookup; 3147c478bd9Sstevel@tonic-gate enum clnt_stat status; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate *nstat = (int)NFS_OK; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate bcopy(&dir->fh.fh2, &dirop.dir, NFS_FHSIZE); 3197c478bd9Sstevel@tonic-gate dirop.name = name; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate status = CLNT_CALL(root_CLIENT, NFSPROC_LOOKUP, xdr_diropargs, 3227c478bd9Sstevel@tonic-gate (caddr_t)&dirop, xdr_diropres, (caddr_t)&res_lookup, 3237c478bd9Sstevel@tonic-gate zero_timeout); 3247c478bd9Sstevel@tonic-gate if (status != RPC_SUCCESS) { 3257c478bd9Sstevel@tonic-gate dprintf("lookup: RPC error.\n"); 3267c478bd9Sstevel@tonic-gate return (NULL); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate if (res_lookup.status != NFS_OK) { 3297c478bd9Sstevel@tonic-gate nfs_error(res_lookup.status); 3307c478bd9Sstevel@tonic-gate *nstat = (int)res_lookup.status; 3317c478bd9Sstevel@tonic-gate return (NULL); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate bzero((caddr_t)&cd, sizeof (struct nfs_file)); 3357c478bd9Sstevel@tonic-gate cd.version = NFS_VERSION; 3367c478bd9Sstevel@tonic-gate cd.ftype.type2 = res_lookup.diropres_u.diropres.attributes.type; 3377c478bd9Sstevel@tonic-gate bcopy(&res_lookup.diropres_u.diropres.file, &cd.fh.fh2, NFS_FHSIZE); 3387c478bd9Sstevel@tonic-gate return (&cd); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * Gets symbolic link into pathname. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate int 3457c478bd9Sstevel@tonic-gate nfsgetsymlink(struct nfs_file *cfile, char **path) 3467c478bd9Sstevel@tonic-gate { 3477c478bd9Sstevel@tonic-gate enum clnt_stat status; 3487c478bd9Sstevel@tonic-gate struct readlinkres linkres; 3497c478bd9Sstevel@tonic-gate static char symlink_path[NFS_MAXPATHLEN]; 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * linkres needs a zeroed buffer to place path data into: 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate bzero(symlink_path, NFS_MAXPATHLEN); 3557c478bd9Sstevel@tonic-gate linkres.readlinkres_u.data = &symlink_path[0]; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate status = CLNT_CALL(root_CLIENT, NFSPROC_READLINK, 3587c478bd9Sstevel@tonic-gate xdr_nfs_fh, (caddr_t)&cfile->fh.fh2, 3597c478bd9Sstevel@tonic-gate xdr_readlinkres, (caddr_t)&linkres, zero_timeout); 3607c478bd9Sstevel@tonic-gate if (status != RPC_SUCCESS) { 3617c478bd9Sstevel@tonic-gate dprintf("nfsgetsymlink: RPC call failed.\n"); 3627c478bd9Sstevel@tonic-gate return (-1); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate if (linkres.status != NFS_OK) { 3657c478bd9Sstevel@tonic-gate nfs_error(linkres.status); 3667c478bd9Sstevel@tonic-gate return (linkres.status); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate *path = linkres.readlinkres_u.data; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate return (NFS_OK); 3727c478bd9Sstevel@tonic-gate } 373