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