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