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 461*18609d04SToomas Soome if (netproto != NET_NFS) 462*18609d04SToomas Soome return (EINVAL); 463*18609d04SToomas Soome 4644a5d661aSToomas Soome #ifdef NFS_DEBUG 4654a5d661aSToomas Soome if (debug) 4664a5d661aSToomas Soome printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 4674a5d661aSToomas Soome #endif 4684a5d661aSToomas Soome if (!rootpath[0]) { 4694a5d661aSToomas Soome printf("no rootpath, no nfs\n"); 4704a5d661aSToomas Soome return (ENXIO); 4714a5d661aSToomas Soome } 4724a5d661aSToomas Soome 4734a5d661aSToomas Soome /* 4744a5d661aSToomas Soome * This is silly - we should look at dv_type but that value is 4754a5d661aSToomas Soome * arch dependant and we can't use it here. 4764a5d661aSToomas Soome */ 4774a5d661aSToomas Soome #ifndef __i386__ 4784a5d661aSToomas Soome if (strcmp(f->f_dev->dv_name, "net") != 0) 4794a5d661aSToomas Soome return(EINVAL); 4804a5d661aSToomas Soome #else 4814a5d661aSToomas Soome if (strcmp(f->f_dev->dv_name, "pxe") != 0) 4824a5d661aSToomas Soome return(EINVAL); 4834a5d661aSToomas Soome #endif 4844a5d661aSToomas Soome 4854a5d661aSToomas Soome if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 4864a5d661aSToomas Soome return(EINVAL); 4874a5d661aSToomas Soome 4884a5d661aSToomas Soome /* Bind to a reserved port. */ 4894a5d661aSToomas Soome desc->myport = htons(--rpc_port); 4904a5d661aSToomas Soome desc->destip = rootip; 4914a5d661aSToomas Soome if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 4924a5d661aSToomas Soome return (error); 4934a5d661aSToomas Soome nfs_root_node.fa.fa_type = htonl(NFDIR); 4944a5d661aSToomas Soome nfs_root_node.fa.fa_mode = htonl(0755); 4954a5d661aSToomas Soome nfs_root_node.fa.fa_nlink = htonl(2); 4964a5d661aSToomas Soome nfs_root_node.iodesc = desc; 4974a5d661aSToomas Soome 4984a5d661aSToomas Soome fh = &nfs_root_node.fh[0]; 4994a5d661aSToomas Soome buf[0] = 'X'; 5004a5d661aSToomas Soome cp = &buf[1]; 5014a5d661aSToomas Soome for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 5024a5d661aSToomas Soome sprintf(cp, "%02x", fh[i]); 5034a5d661aSToomas Soome sprintf(cp, "X"); 5044a5d661aSToomas Soome setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 5054a5d661aSToomas Soome setenv("boot.nfsroot.path", rootpath, 1); 5064a5d661aSToomas Soome setenv("boot.nfsroot.nfshandle", buf, 1); 5074a5d661aSToomas Soome 5084a5d661aSToomas Soome /* Allocate file system specific data structure */ 5094a5d661aSToomas Soome currfd = malloc(sizeof(*newfd)); 5104a5d661aSToomas Soome if (currfd == NULL) { 5114a5d661aSToomas Soome error = ENOMEM; 5124a5d661aSToomas Soome goto out; 5134a5d661aSToomas Soome } 5144a5d661aSToomas Soome 5154a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 5164a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 517830d404aSToomas Soome newfd = NULL; 5184a5d661aSToomas Soome 5194a5d661aSToomas Soome cp = path = strdup(upath); 5204a5d661aSToomas Soome if (path == NULL) { 5214a5d661aSToomas Soome error = ENOMEM; 5224a5d661aSToomas Soome goto out; 5234a5d661aSToomas Soome } 5244a5d661aSToomas Soome while (*cp) { 5254a5d661aSToomas Soome /* 5264a5d661aSToomas Soome * Remove extra separators 5274a5d661aSToomas Soome */ 5284a5d661aSToomas Soome while (*cp == '/') 5294a5d661aSToomas Soome cp++; 5304a5d661aSToomas Soome 5314a5d661aSToomas Soome if (*cp == '\0') 5324a5d661aSToomas Soome break; 5334a5d661aSToomas Soome /* 5344a5d661aSToomas Soome * Check that current node is a directory. 5354a5d661aSToomas Soome */ 5364a5d661aSToomas Soome if (currfd->fa.fa_type != htonl(NFDIR)) { 5374a5d661aSToomas Soome error = ENOTDIR; 5384a5d661aSToomas Soome goto out; 5394a5d661aSToomas Soome } 5404a5d661aSToomas Soome 5414a5d661aSToomas Soome /* allocate file system specific data structure */ 5424a5d661aSToomas Soome newfd = malloc(sizeof(*newfd)); 5434a5d661aSToomas Soome newfd->iodesc = currfd->iodesc; 5444a5d661aSToomas Soome 5454a5d661aSToomas Soome /* 5464a5d661aSToomas Soome * Get next component of path name. 5474a5d661aSToomas Soome */ 5484a5d661aSToomas Soome { 5494a5d661aSToomas Soome int len = 0; 5504a5d661aSToomas Soome 5514a5d661aSToomas Soome ncp = cp; 5524a5d661aSToomas Soome while ((c = *cp) != '\0' && c != '/') { 5534a5d661aSToomas Soome if (++len > NFS_MAXNAMLEN) { 5544a5d661aSToomas Soome error = ENOENT; 5554a5d661aSToomas Soome goto out; 5564a5d661aSToomas Soome } 5574a5d661aSToomas Soome cp++; 5584a5d661aSToomas Soome } 5594a5d661aSToomas Soome *cp = '\0'; 5604a5d661aSToomas Soome } 5614a5d661aSToomas Soome 5624a5d661aSToomas Soome /* lookup a file handle */ 5634a5d661aSToomas Soome error = nfs_lookupfh(currfd, ncp, newfd); 5644a5d661aSToomas Soome *cp = c; 5654a5d661aSToomas Soome if (error) 5664a5d661aSToomas Soome goto out; 5674a5d661aSToomas Soome 5684a5d661aSToomas Soome /* 5694a5d661aSToomas Soome * Check for symbolic link 5704a5d661aSToomas Soome */ 5714a5d661aSToomas Soome if (newfd->fa.fa_type == htonl(NFLNK)) { 5724a5d661aSToomas Soome int link_len, len; 5734a5d661aSToomas Soome 5744a5d661aSToomas Soome error = nfs_readlink(newfd, linkbuf); 5754a5d661aSToomas Soome if (error) 5764a5d661aSToomas Soome goto out; 5774a5d661aSToomas Soome 5784a5d661aSToomas Soome link_len = strlen(linkbuf); 5794a5d661aSToomas Soome len = strlen(cp); 5804a5d661aSToomas Soome 5814a5d661aSToomas Soome if (link_len + len > MAXPATHLEN 5824a5d661aSToomas Soome || ++nlinks > MAXSYMLINKS) { 5834a5d661aSToomas Soome error = ENOENT; 5844a5d661aSToomas Soome goto out; 5854a5d661aSToomas Soome } 5864a5d661aSToomas Soome 5874a5d661aSToomas Soome bcopy(cp, &namebuf[link_len], len + 1); 5884a5d661aSToomas Soome bcopy(linkbuf, namebuf, link_len); 5894a5d661aSToomas Soome 5904a5d661aSToomas Soome /* 5914a5d661aSToomas Soome * If absolute pathname, restart at root. 5924a5d661aSToomas Soome * If relative pathname, restart at parent directory. 5934a5d661aSToomas Soome */ 5944a5d661aSToomas Soome cp = namebuf; 5954a5d661aSToomas Soome if (*cp == '/') 5964a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 5974a5d661aSToomas Soome 5984a5d661aSToomas Soome free(newfd); 599830d404aSToomas Soome newfd = NULL; 6004a5d661aSToomas Soome 6014a5d661aSToomas Soome continue; 6024a5d661aSToomas Soome } 6034a5d661aSToomas Soome 6044a5d661aSToomas Soome free(currfd); 6054a5d661aSToomas Soome currfd = newfd; 606830d404aSToomas Soome newfd = NULL; 6074a5d661aSToomas Soome } 6084a5d661aSToomas Soome 6094a5d661aSToomas Soome error = 0; 6104a5d661aSToomas Soome 6114a5d661aSToomas Soome out: 6124a5d661aSToomas Soome free(newfd); 6134a5d661aSToomas Soome free(path); 6144a5d661aSToomas Soome #else 6154a5d661aSToomas Soome currfd->iodesc = desc; 6164a5d661aSToomas Soome 6174a5d661aSToomas Soome error = nfs_lookupfh(&nfs_root_node, upath, currfd); 6184a5d661aSToomas Soome #endif 6194a5d661aSToomas Soome if (!error) { 6204a5d661aSToomas Soome currfd->off = 0; 6214a5d661aSToomas Soome f->f_fsdata = (void *)currfd; 6224a5d661aSToomas Soome return (0); 6234a5d661aSToomas Soome } 6244a5d661aSToomas Soome 6254a5d661aSToomas Soome #ifdef NFS_DEBUG 6264a5d661aSToomas Soome if (debug) 6274a5d661aSToomas Soome printf("nfs_open: %s lookupfh failed: %s\n", 6284a5d661aSToomas Soome path, strerror(error)); 6294a5d661aSToomas Soome #endif 6304a5d661aSToomas Soome free(currfd); 6314a5d661aSToomas Soome 6324a5d661aSToomas Soome return (error); 6334a5d661aSToomas Soome } 6344a5d661aSToomas Soome 6354a5d661aSToomas Soome int 6364a5d661aSToomas Soome nfs_close(struct open_file *f) 6374a5d661aSToomas Soome { 6384a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 6394a5d661aSToomas Soome 6404a5d661aSToomas Soome #ifdef NFS_DEBUG 6414a5d661aSToomas Soome if (debug) 6424a5d661aSToomas Soome printf("nfs_close: fp=0x%lx\n", (u_long)fp); 6434a5d661aSToomas Soome #endif 6444a5d661aSToomas Soome 6454a5d661aSToomas Soome if (fp) 6464a5d661aSToomas Soome free(fp); 6474a5d661aSToomas Soome f->f_fsdata = (void *)0; 6484a5d661aSToomas Soome 6494a5d661aSToomas Soome return (0); 6504a5d661aSToomas Soome } 6514a5d661aSToomas Soome 6524a5d661aSToomas Soome /* 6534a5d661aSToomas Soome * read a portion of a file 6544a5d661aSToomas Soome */ 6554a5d661aSToomas Soome int 6564a5d661aSToomas Soome nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 6574a5d661aSToomas Soome { 6584a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 6594a5d661aSToomas Soome ssize_t cc; 6604a5d661aSToomas Soome char *addr = buf; 6614a5d661aSToomas Soome 6624a5d661aSToomas Soome #ifdef NFS_DEBUG 6634a5d661aSToomas Soome if (debug) 6644a5d661aSToomas Soome printf("nfs_read: size=%lu off=%d\n", (u_long)size, 6654a5d661aSToomas Soome (int)fp->off); 6664a5d661aSToomas Soome #endif 6674a5d661aSToomas Soome while ((int)size > 0) { 6684a5d661aSToomas Soome twiddle(16); 6694a5d661aSToomas Soome cc = nfs_readdata(fp, fp->off, (void *)addr, size); 6704a5d661aSToomas Soome /* XXX maybe should retry on certain errors */ 6714a5d661aSToomas Soome if (cc == -1) { 6724a5d661aSToomas Soome #ifdef NFS_DEBUG 6734a5d661aSToomas Soome if (debug) 6744a5d661aSToomas Soome printf("nfs_read: read: %s", strerror(errno)); 6754a5d661aSToomas Soome #endif 6764a5d661aSToomas Soome return (errno); /* XXX - from nfs_readdata */ 6774a5d661aSToomas Soome } 6784a5d661aSToomas Soome if (cc == 0) { 6794a5d661aSToomas Soome #ifdef NFS_DEBUG 6804a5d661aSToomas Soome if (debug) 6814a5d661aSToomas Soome printf("nfs_read: hit EOF unexpectantly"); 6824a5d661aSToomas Soome #endif 6834a5d661aSToomas Soome goto ret; 6844a5d661aSToomas Soome } 6854a5d661aSToomas Soome fp->off += cc; 6864a5d661aSToomas Soome addr += cc; 6874a5d661aSToomas Soome size -= cc; 6884a5d661aSToomas Soome } 6894a5d661aSToomas Soome ret: 6904a5d661aSToomas Soome if (resid) 6914a5d661aSToomas Soome *resid = size; 6924a5d661aSToomas Soome 6934a5d661aSToomas Soome return (0); 6944a5d661aSToomas Soome } 6954a5d661aSToomas Soome 6964a5d661aSToomas Soome /* 6974a5d661aSToomas Soome * Not implemented. 6984a5d661aSToomas Soome */ 6994a5d661aSToomas Soome int 7004a5d661aSToomas Soome nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 7014a5d661aSToomas Soome { 7024a5d661aSToomas Soome return (EROFS); 7034a5d661aSToomas Soome } 7044a5d661aSToomas Soome 7054a5d661aSToomas Soome off_t 7064a5d661aSToomas Soome nfs_seek(struct open_file *f, off_t offset, int where) 7074a5d661aSToomas Soome { 7084a5d661aSToomas Soome struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 7094a5d661aSToomas Soome n_long size = ntohl(d->fa.fa_size); 7104a5d661aSToomas Soome 7114a5d661aSToomas Soome switch (where) { 7124a5d661aSToomas Soome case SEEK_SET: 7134a5d661aSToomas Soome d->off = offset; 7144a5d661aSToomas Soome break; 7154a5d661aSToomas Soome case SEEK_CUR: 7164a5d661aSToomas Soome d->off += offset; 7174a5d661aSToomas Soome break; 7184a5d661aSToomas Soome case SEEK_END: 7194a5d661aSToomas Soome d->off = size - offset; 7204a5d661aSToomas Soome break; 7214a5d661aSToomas Soome default: 7224a5d661aSToomas Soome errno = EINVAL; 7234a5d661aSToomas Soome return (-1); 7244a5d661aSToomas Soome } 7254a5d661aSToomas Soome 7264a5d661aSToomas Soome return (d->off); 7274a5d661aSToomas Soome } 7284a5d661aSToomas Soome 7294a5d661aSToomas Soome /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 7304a5d661aSToomas Soome int nfs_stat_types[8] = { 7314a5d661aSToomas Soome 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 7324a5d661aSToomas Soome 7334a5d661aSToomas Soome int 7344a5d661aSToomas Soome nfs_stat(struct open_file *f, struct stat *sb) 7354a5d661aSToomas Soome { 7364a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 7374a5d661aSToomas Soome n_long ftype, mode; 7384a5d661aSToomas Soome 7394a5d661aSToomas Soome ftype = ntohl(fp->fa.fa_type); 7404a5d661aSToomas Soome mode = ntohl(fp->fa.fa_mode); 7414a5d661aSToomas Soome mode |= nfs_stat_types[ftype & 7]; 7424a5d661aSToomas Soome 7434a5d661aSToomas Soome sb->st_mode = mode; 7444a5d661aSToomas Soome sb->st_nlink = ntohl(fp->fa.fa_nlink); 7454a5d661aSToomas Soome sb->st_uid = ntohl(fp->fa.fa_uid); 7464a5d661aSToomas Soome sb->st_gid = ntohl(fp->fa.fa_gid); 7474a5d661aSToomas Soome sb->st_size = ntohl(fp->fa.fa_size); 7484a5d661aSToomas Soome 7494a5d661aSToomas Soome return (0); 7504a5d661aSToomas Soome } 7514a5d661aSToomas Soome 7524a5d661aSToomas Soome static int 7534a5d661aSToomas Soome nfs_readdir(struct open_file *f, struct dirent *d) 7544a5d661aSToomas Soome { 7554a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 7564a5d661aSToomas Soome struct nfs_readdir_args *args; 7574a5d661aSToomas Soome struct nfs_readdir_data *rd; 7584a5d661aSToomas Soome struct nfs_readdir_off *roff = NULL; 7594a5d661aSToomas Soome static char *buf; 7604a5d661aSToomas Soome static struct nfs_iodesc *pfp = NULL; 7614a5d661aSToomas Soome static n_long cookie = 0; 7624a5d661aSToomas Soome size_t cc; 7634a5d661aSToomas Soome n_long eof; 7644a5d661aSToomas Soome 7654a5d661aSToomas Soome struct { 7664a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 7674a5d661aSToomas Soome struct nfs_readdir_args d; 7684a5d661aSToomas Soome } sdata; 7694a5d661aSToomas Soome static struct { 7704a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 7714a5d661aSToomas Soome u_char d[NFS_READDIRSIZE]; 7724a5d661aSToomas Soome } rdata; 7734a5d661aSToomas Soome 7744a5d661aSToomas Soome if (fp != pfp || fp->off != cookie) { 7754a5d661aSToomas Soome pfp = NULL; 7764a5d661aSToomas Soome refill: 7774a5d661aSToomas Soome args = &sdata.d; 7784a5d661aSToomas Soome bzero(args, sizeof(*args)); 7794a5d661aSToomas Soome 7804a5d661aSToomas Soome bcopy(fp->fh, args->fh, NFS_FHSIZE); 7814a5d661aSToomas Soome args->cookie = htonl(fp->off); 7824a5d661aSToomas Soome args->count = htonl(NFS_READDIRSIZE); 7834a5d661aSToomas Soome 7844a5d661aSToomas Soome cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 7854a5d661aSToomas Soome args, sizeof(*args), 7864a5d661aSToomas Soome rdata.d, sizeof(rdata.d)); 7874a5d661aSToomas Soome buf = rdata.d; 7884a5d661aSToomas Soome roff = (struct nfs_readdir_off *)buf; 7894a5d661aSToomas Soome if (ntohl(roff->cookie) != 0) 7904a5d661aSToomas Soome return EIO; 7914a5d661aSToomas Soome pfp = fp; 7924a5d661aSToomas Soome cookie = fp->off; 7934a5d661aSToomas Soome } 7944a5d661aSToomas Soome roff = (struct nfs_readdir_off *)buf; 7954a5d661aSToomas Soome 7964a5d661aSToomas Soome if (ntohl(roff->follows) == 0) { 7974a5d661aSToomas Soome eof = ntohl((roff+1)->cookie); 7984a5d661aSToomas Soome if (eof) { 7994a5d661aSToomas Soome cookie = 0; 8004a5d661aSToomas Soome return ENOENT; 8014a5d661aSToomas Soome } 8024a5d661aSToomas Soome goto refill; 8034a5d661aSToomas Soome } 8044a5d661aSToomas Soome 8054a5d661aSToomas Soome buf += sizeof(struct nfs_readdir_off); 8064a5d661aSToomas Soome rd = (struct nfs_readdir_data *)buf; 8074a5d661aSToomas Soome d->d_namlen = ntohl(rd->len); 8084a5d661aSToomas Soome bcopy(rd->name, d->d_name, d->d_namlen); 8094a5d661aSToomas Soome d->d_name[d->d_namlen] = '\0'; 8104a5d661aSToomas Soome 8114a5d661aSToomas Soome buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 8124a5d661aSToomas Soome roff = (struct nfs_readdir_off *)buf; 8134a5d661aSToomas Soome fp->off = cookie = ntohl(roff->cookie); 8144a5d661aSToomas Soome return 0; 8154a5d661aSToomas Soome } 8164a5d661aSToomas Soome #else /* !OLD_NFSV2 */ 8174a5d661aSToomas Soome /* 8184a5d661aSToomas Soome * Fetch the root file handle (call mount daemon) 8194a5d661aSToomas Soome * Return zero or error number. 8204a5d661aSToomas Soome */ 8214a5d661aSToomas Soome int 8224a5d661aSToomas Soome nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 8234a5d661aSToomas Soome { 8244a5d661aSToomas Soome int len; 8254a5d661aSToomas Soome struct args { 8264a5d661aSToomas Soome uint32_t len; 8274a5d661aSToomas Soome char path[FNAME_SIZE]; 8284a5d661aSToomas Soome } *args; 8294a5d661aSToomas Soome struct repl { 8304a5d661aSToomas Soome uint32_t errno; 8314a5d661aSToomas Soome uint32_t fhsize; 8324a5d661aSToomas Soome u_char fh[NFS_V3MAXFHSIZE]; 8334a5d661aSToomas Soome uint32_t authcnt; 8344a5d661aSToomas Soome uint32_t auth[7]; 8354a5d661aSToomas Soome } *repl; 8364a5d661aSToomas Soome struct { 8374a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 8384a5d661aSToomas Soome struct args d; 8394a5d661aSToomas Soome } sdata; 8404a5d661aSToomas Soome struct { 8414a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 8424a5d661aSToomas Soome struct repl d; 8434a5d661aSToomas Soome } rdata; 8444a5d661aSToomas Soome size_t cc; 8454a5d661aSToomas Soome 8464a5d661aSToomas Soome #ifdef NFS_DEBUG 8474a5d661aSToomas Soome if (debug) 8484a5d661aSToomas Soome printf("nfs_getrootfh: %s\n", path); 8494a5d661aSToomas Soome #endif 8504a5d661aSToomas Soome 8514a5d661aSToomas Soome args = &sdata.d; 8524a5d661aSToomas Soome repl = &rdata.d; 8534a5d661aSToomas Soome 8544a5d661aSToomas Soome bzero(args, sizeof(*args)); 8554a5d661aSToomas Soome len = strlen(path); 8564a5d661aSToomas Soome if (len > sizeof(args->path)) 8574a5d661aSToomas Soome len = sizeof(args->path); 8584a5d661aSToomas Soome args->len = htonl(len); 8594a5d661aSToomas Soome bcopy(path, args->path, len); 8604a5d661aSToomas Soome len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 8614a5d661aSToomas Soome 8624a5d661aSToomas Soome cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 8634a5d661aSToomas Soome args, len, repl, sizeof(*repl)); 8644a5d661aSToomas Soome if (cc == -1) 8654a5d661aSToomas Soome /* errno was set by rpc_call */ 8664a5d661aSToomas Soome return (errno); 8674a5d661aSToomas Soome if (cc < 2 * sizeof (uint32_t)) 8684a5d661aSToomas Soome return (EBADRPC); 8694a5d661aSToomas Soome if (repl->errno != 0) 8704a5d661aSToomas Soome return (ntohl(repl->errno)); 8714a5d661aSToomas Soome *fhlenp = ntohl(repl->fhsize); 8724a5d661aSToomas Soome bcopy(repl->fh, fhp, *fhlenp); 8734a5d661aSToomas Soome return (0); 8744a5d661aSToomas Soome } 8754a5d661aSToomas Soome 8764a5d661aSToomas Soome /* 8774a5d661aSToomas Soome * Lookup a file. Store handle and attributes. 8784a5d661aSToomas Soome * Return zero or error number. 8794a5d661aSToomas Soome */ 8804a5d661aSToomas Soome int 8814a5d661aSToomas Soome nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 8824a5d661aSToomas Soome { 8834a5d661aSToomas Soome int len, rlen, pos; 8844a5d661aSToomas Soome struct args { 8854a5d661aSToomas Soome uint32_t fhsize; 8864a5d661aSToomas Soome uint32_t fhplusname[1 + 8874a5d661aSToomas Soome (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 8884a5d661aSToomas Soome } *args; 8894a5d661aSToomas Soome struct repl { 8904a5d661aSToomas Soome uint32_t errno; 8914a5d661aSToomas Soome uint32_t fhsize; 8924a5d661aSToomas Soome uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 8934a5d661aSToomas Soome 2 * (sizeof(uint32_t) + 8944a5d661aSToomas Soome sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 8954a5d661aSToomas Soome } *repl; 8964a5d661aSToomas Soome struct { 8974a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 8984a5d661aSToomas Soome struct args d; 8994a5d661aSToomas Soome } sdata; 9004a5d661aSToomas Soome struct { 9014a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 9024a5d661aSToomas Soome struct repl d; 9034a5d661aSToomas Soome } rdata; 9044a5d661aSToomas Soome ssize_t cc; 9054a5d661aSToomas Soome 9064a5d661aSToomas Soome #ifdef NFS_DEBUG 9074a5d661aSToomas Soome if (debug) 9084a5d661aSToomas Soome printf("lookupfh: called\n"); 9094a5d661aSToomas Soome #endif 9104a5d661aSToomas Soome 9114a5d661aSToomas Soome args = &sdata.d; 9124a5d661aSToomas Soome repl = &rdata.d; 9134a5d661aSToomas Soome 9144a5d661aSToomas Soome bzero(args, sizeof(*args)); 9154a5d661aSToomas Soome args->fhsize = htonl(d->fhsize); 9164a5d661aSToomas Soome bcopy(d->fh, args->fhplusname, d->fhsize); 9174a5d661aSToomas Soome len = strlen(name); 9184a5d661aSToomas Soome if (len > FNAME_SIZE) 9194a5d661aSToomas Soome len = FNAME_SIZE; 9204a5d661aSToomas Soome pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 9214a5d661aSToomas Soome args->fhplusname[pos++] = htonl(len); 9224a5d661aSToomas Soome bcopy(name, &args->fhplusname[pos], len); 9234a5d661aSToomas Soome len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 9244a5d661aSToomas Soome roundup(len, sizeof(uint32_t)); 9254a5d661aSToomas Soome 9264a5d661aSToomas Soome rlen = sizeof(*repl); 9274a5d661aSToomas Soome 9284a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 9294a5d661aSToomas Soome args, len, repl, rlen); 9304a5d661aSToomas Soome if (cc == -1) 9314a5d661aSToomas Soome return (errno); /* XXX - from rpc_call */ 9324a5d661aSToomas Soome if (cc < 2 * sizeof(uint32_t)) 9334a5d661aSToomas Soome return (EIO); 9344a5d661aSToomas Soome if (repl->errno != 0) 9354a5d661aSToomas Soome /* saerrno.h now matches NFS error numbers. */ 9364a5d661aSToomas Soome return (ntohl(repl->errno)); 9374a5d661aSToomas Soome newfd->fhsize = ntohl(repl->fhsize); 9384a5d661aSToomas Soome bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 9394a5d661aSToomas Soome pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 9404a5d661aSToomas Soome if (repl->fhplusattr[pos++] == 0) 9414a5d661aSToomas Soome return (EIO); 9424a5d661aSToomas Soome bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 9434a5d661aSToomas Soome return (0); 9444a5d661aSToomas Soome } 9454a5d661aSToomas Soome 9464a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 9474a5d661aSToomas Soome /* 9484a5d661aSToomas Soome * Get the destination of a symbolic link. 9494a5d661aSToomas Soome */ 9504a5d661aSToomas Soome int 9514a5d661aSToomas Soome nfs_readlink(struct nfs_iodesc *d, char *buf) 9524a5d661aSToomas Soome { 9534a5d661aSToomas Soome struct args { 9544a5d661aSToomas Soome uint32_t fhsize; 9554a5d661aSToomas Soome u_char fh[NFS_V3MAXFHSIZE]; 9564a5d661aSToomas Soome } *args; 9574a5d661aSToomas Soome struct repl { 9584a5d661aSToomas Soome uint32_t errno; 9594a5d661aSToomas Soome uint32_t ok; 9604a5d661aSToomas Soome struct nfsv3_fattrs fa; 9614a5d661aSToomas Soome uint32_t len; 9624a5d661aSToomas Soome u_char path[NFS_MAXPATHLEN]; 9634a5d661aSToomas Soome } *repl; 9644a5d661aSToomas Soome struct { 9654a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 9664a5d661aSToomas Soome struct args d; 9674a5d661aSToomas Soome } sdata; 9684a5d661aSToomas Soome struct { 9694a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 9704a5d661aSToomas Soome struct repl d; 9714a5d661aSToomas Soome } rdata; 9724a5d661aSToomas Soome ssize_t cc; 9734a5d661aSToomas Soome 9744a5d661aSToomas Soome #ifdef NFS_DEBUG 9754a5d661aSToomas Soome if (debug) 9764a5d661aSToomas Soome printf("readlink: called\n"); 9774a5d661aSToomas Soome #endif 9784a5d661aSToomas Soome 9794a5d661aSToomas Soome args = &sdata.d; 9804a5d661aSToomas Soome repl = &rdata.d; 9814a5d661aSToomas Soome 9824a5d661aSToomas Soome bzero(args, sizeof(*args)); 9834a5d661aSToomas Soome args->fhsize = htonl(d->fhsize); 9844a5d661aSToomas Soome bcopy(d->fh, args->fh, d->fhsize); 9854a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 9864a5d661aSToomas Soome args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 9874a5d661aSToomas Soome repl, sizeof(*repl)); 9884a5d661aSToomas Soome if (cc == -1) 9894a5d661aSToomas Soome return (errno); 9904a5d661aSToomas Soome 9914a5d661aSToomas Soome if (cc < 2 * sizeof(uint32_t)) 9924a5d661aSToomas Soome return (EIO); 9934a5d661aSToomas Soome 9944a5d661aSToomas Soome if (repl->errno != 0) 9954a5d661aSToomas Soome return (ntohl(repl->errno)); 9964a5d661aSToomas Soome 9974a5d661aSToomas Soome if (repl->ok == 0) 9984a5d661aSToomas Soome return (EIO); 9994a5d661aSToomas Soome 10004a5d661aSToomas Soome repl->len = ntohl(repl->len); 10014a5d661aSToomas Soome if (repl->len > NFS_MAXPATHLEN) 10024a5d661aSToomas Soome return (ENAMETOOLONG); 10034a5d661aSToomas Soome 10044a5d661aSToomas Soome bcopy(repl->path, buf, repl->len); 10054a5d661aSToomas Soome buf[repl->len] = 0; 10064a5d661aSToomas Soome return (0); 10074a5d661aSToomas Soome } 10084a5d661aSToomas Soome #endif 10094a5d661aSToomas Soome 10104a5d661aSToomas Soome /* 10114a5d661aSToomas Soome * Read data from a file. 10124a5d661aSToomas Soome * Return transfer count or -1 (and set errno) 10134a5d661aSToomas Soome */ 10144a5d661aSToomas Soome ssize_t 10154a5d661aSToomas Soome nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 10164a5d661aSToomas Soome { 10174a5d661aSToomas Soome struct args { 10184a5d661aSToomas Soome uint32_t fhsize; 10194a5d661aSToomas Soome uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 10204a5d661aSToomas Soome } *args; 10214a5d661aSToomas Soome struct repl { 10224a5d661aSToomas Soome uint32_t errno; 10234a5d661aSToomas Soome uint32_t ok; 10244a5d661aSToomas Soome struct nfsv3_fattrs fa; 10254a5d661aSToomas Soome uint32_t count; 10264a5d661aSToomas Soome uint32_t eof; 10274a5d661aSToomas Soome uint32_t len; 10284a5d661aSToomas Soome u_char data[NFSREAD_SIZE]; 10294a5d661aSToomas Soome } *repl; 10304a5d661aSToomas Soome struct { 10314a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 10324a5d661aSToomas Soome struct args d; 10334a5d661aSToomas Soome } sdata; 10344a5d661aSToomas Soome struct { 10354a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 10364a5d661aSToomas Soome struct repl d; 10374a5d661aSToomas Soome } rdata; 10384a5d661aSToomas Soome size_t cc; 10394a5d661aSToomas Soome long x; 10404a5d661aSToomas Soome int hlen, rlen, pos; 10414a5d661aSToomas Soome 10424a5d661aSToomas Soome args = &sdata.d; 10434a5d661aSToomas Soome repl = &rdata.d; 10444a5d661aSToomas Soome 10454a5d661aSToomas Soome bzero(args, sizeof(*args)); 10464a5d661aSToomas Soome args->fhsize = htonl(d->fhsize); 10474a5d661aSToomas Soome bcopy(d->fh, args->fhoffcnt, d->fhsize); 10484a5d661aSToomas Soome pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 10494a5d661aSToomas Soome args->fhoffcnt[pos++] = 0; 10504a5d661aSToomas Soome args->fhoffcnt[pos++] = htonl((uint32_t)off); 10514a5d661aSToomas Soome if (len > NFSREAD_SIZE) 10524a5d661aSToomas Soome len = NFSREAD_SIZE; 10534a5d661aSToomas Soome args->fhoffcnt[pos] = htonl((uint32_t)len); 10544a5d661aSToomas Soome hlen = sizeof(*repl) - NFSREAD_SIZE; 10554a5d661aSToomas Soome 10564a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 10574a5d661aSToomas Soome args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 10584a5d661aSToomas Soome repl, sizeof(*repl)); 10594a5d661aSToomas Soome if (cc == -1) 10604a5d661aSToomas Soome /* errno was already set by rpc_call */ 10614a5d661aSToomas Soome return (-1); 10624a5d661aSToomas Soome if (cc < hlen) { 10634a5d661aSToomas Soome errno = EBADRPC; 10644a5d661aSToomas Soome return (-1); 10654a5d661aSToomas Soome } 10664a5d661aSToomas Soome if (repl->errno != 0) { 10674a5d661aSToomas Soome errno = ntohl(repl->errno); 10684a5d661aSToomas Soome return (-1); 10694a5d661aSToomas Soome } 10704a5d661aSToomas Soome rlen = cc - hlen; 10714a5d661aSToomas Soome x = ntohl(repl->count); 10724a5d661aSToomas Soome if (rlen < x) { 10734a5d661aSToomas Soome printf("nfsread: short packet, %d < %ld\n", rlen, x); 10744a5d661aSToomas Soome errno = EBADRPC; 10754a5d661aSToomas Soome return (-1); 10764a5d661aSToomas Soome } 10774a5d661aSToomas Soome bcopy(repl->data, addr, x); 10784a5d661aSToomas Soome return (x); 10794a5d661aSToomas Soome } 10804a5d661aSToomas Soome 10814a5d661aSToomas Soome /* 10824a5d661aSToomas Soome * Open a file. 10834a5d661aSToomas Soome * return zero or error number 10844a5d661aSToomas Soome */ 10854a5d661aSToomas Soome int 10864a5d661aSToomas Soome nfs_open(const char *upath, struct open_file *f) 10874a5d661aSToomas Soome { 10884a5d661aSToomas Soome struct iodesc *desc; 10894a5d661aSToomas Soome struct nfs_iodesc *currfd; 10904a5d661aSToomas Soome char buf[2 * NFS_V3MAXFHSIZE + 3]; 10914a5d661aSToomas Soome u_char *fh; 10924a5d661aSToomas Soome char *cp; 10934a5d661aSToomas Soome int i; 10944a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 10954a5d661aSToomas Soome struct nfs_iodesc *newfd; 10964a5d661aSToomas Soome struct nfsv3_fattrs *fa; 10974a5d661aSToomas Soome char *ncp; 10984a5d661aSToomas Soome int c; 10994a5d661aSToomas Soome char namebuf[NFS_MAXPATHLEN + 1]; 11004a5d661aSToomas Soome char linkbuf[NFS_MAXPATHLEN + 1]; 11014a5d661aSToomas Soome int nlinks = 0; 11024a5d661aSToomas Soome #endif 11034a5d661aSToomas Soome int error; 11044a5d661aSToomas Soome char *path; 11054a5d661aSToomas Soome 1106*18609d04SToomas Soome if (netproto != NET_NFS) 1107*18609d04SToomas Soome return (EINVAL); 1108*18609d04SToomas Soome 11094a5d661aSToomas Soome #ifdef NFS_DEBUG 11104a5d661aSToomas Soome if (debug) 11114a5d661aSToomas Soome printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 11124a5d661aSToomas Soome #endif 11134a5d661aSToomas Soome if (!rootpath[0]) { 11144a5d661aSToomas Soome printf("no rootpath, no nfs\n"); 11154a5d661aSToomas Soome return (ENXIO); 11164a5d661aSToomas Soome } 11174a5d661aSToomas Soome 11184a5d661aSToomas Soome /* 11194a5d661aSToomas Soome * This is silly - we should look at dv_type but that value is 11204a5d661aSToomas Soome * arch dependant and we can't use it here. 11214a5d661aSToomas Soome */ 11224a5d661aSToomas Soome #ifndef __i386__ 11234a5d661aSToomas Soome if (strcmp(f->f_dev->dv_name, "net") != 0) 11244a5d661aSToomas Soome return (EINVAL); 11254a5d661aSToomas Soome #else 11264a5d661aSToomas Soome if (strcmp(f->f_dev->dv_name, "pxe") != 0) 11274a5d661aSToomas Soome return (EINVAL); 11284a5d661aSToomas Soome #endif 11294a5d661aSToomas Soome 11304a5d661aSToomas Soome if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 11314a5d661aSToomas Soome return (EINVAL); 11324a5d661aSToomas Soome 11334a5d661aSToomas Soome /* Bind to a reserved port. */ 11344a5d661aSToomas Soome desc->myport = htons(--rpc_port); 11354a5d661aSToomas Soome desc->destip = rootip; 11364a5d661aSToomas Soome if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 11374a5d661aSToomas Soome nfs_root_node.fh))) 11384a5d661aSToomas Soome return (error); 11394a5d661aSToomas Soome nfs_root_node.fa.fa_type = htonl(NFDIR); 11404a5d661aSToomas Soome nfs_root_node.fa.fa_mode = htonl(0755); 11414a5d661aSToomas Soome nfs_root_node.fa.fa_nlink = htonl(2); 11424a5d661aSToomas Soome nfs_root_node.iodesc = desc; 11434a5d661aSToomas Soome 11444a5d661aSToomas Soome fh = &nfs_root_node.fh[0]; 11454a5d661aSToomas Soome buf[0] = 'X'; 11464a5d661aSToomas Soome cp = &buf[1]; 11474a5d661aSToomas Soome for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 11484a5d661aSToomas Soome sprintf(cp, "%02x", fh[i]); 11494a5d661aSToomas Soome sprintf(cp, "X"); 11504a5d661aSToomas Soome setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 11514a5d661aSToomas Soome setenv("boot.nfsroot.path", rootpath, 1); 11524a5d661aSToomas Soome setenv("boot.nfsroot.nfshandle", buf, 1); 11534a5d661aSToomas Soome sprintf(buf, "%d", nfs_root_node.fhsize); 11544a5d661aSToomas Soome setenv("boot.nfsroot.nfshandlelen", buf, 1); 11554a5d661aSToomas Soome 11564a5d661aSToomas Soome /* Allocate file system specific data structure */ 11574a5d661aSToomas Soome currfd = malloc(sizeof(*newfd)); 11584a5d661aSToomas Soome if (currfd == NULL) { 11594a5d661aSToomas Soome error = ENOMEM; 11604a5d661aSToomas Soome goto out; 11614a5d661aSToomas Soome } 11624a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 11634a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1164830d404aSToomas Soome newfd = NULL; 11654a5d661aSToomas Soome 11664a5d661aSToomas Soome cp = path = strdup(upath); 11674a5d661aSToomas Soome if (path == NULL) { 11684a5d661aSToomas Soome error = ENOMEM; 11694a5d661aSToomas Soome goto out; 11704a5d661aSToomas Soome } 11714a5d661aSToomas Soome while (*cp) { 11724a5d661aSToomas Soome /* 11734a5d661aSToomas Soome * Remove extra separators 11744a5d661aSToomas Soome */ 11754a5d661aSToomas Soome while (*cp == '/') 11764a5d661aSToomas Soome cp++; 11774a5d661aSToomas Soome 11784a5d661aSToomas Soome if (*cp == '\0') 11794a5d661aSToomas Soome break; 11804a5d661aSToomas Soome /* 11814a5d661aSToomas Soome * Check that current node is a directory. 11824a5d661aSToomas Soome */ 11834a5d661aSToomas Soome if (currfd->fa.fa_type != htonl(NFDIR)) { 11844a5d661aSToomas Soome error = ENOTDIR; 11854a5d661aSToomas Soome goto out; 11864a5d661aSToomas Soome } 11874a5d661aSToomas Soome 11884a5d661aSToomas Soome /* allocate file system specific data structure */ 11894a5d661aSToomas Soome newfd = malloc(sizeof(*newfd)); 11904a5d661aSToomas Soome if (newfd == NULL) { 11914a5d661aSToomas Soome error = ENOMEM; 11924a5d661aSToomas Soome goto out; 11934a5d661aSToomas Soome } 11944a5d661aSToomas Soome newfd->iodesc = currfd->iodesc; 11954a5d661aSToomas Soome 11964a5d661aSToomas Soome /* 11974a5d661aSToomas Soome * Get next component of path name. 11984a5d661aSToomas Soome */ 11994a5d661aSToomas Soome { 12004a5d661aSToomas Soome int len = 0; 12014a5d661aSToomas Soome 12024a5d661aSToomas Soome ncp = cp; 12034a5d661aSToomas Soome while ((c = *cp) != '\0' && c != '/') { 12044a5d661aSToomas Soome if (++len > NFS_MAXNAMLEN) { 12054a5d661aSToomas Soome error = ENOENT; 12064a5d661aSToomas Soome goto out; 12074a5d661aSToomas Soome } 12084a5d661aSToomas Soome cp++; 12094a5d661aSToomas Soome } 12104a5d661aSToomas Soome *cp = '\0'; 12114a5d661aSToomas Soome } 12124a5d661aSToomas Soome 12134a5d661aSToomas Soome /* lookup a file handle */ 12144a5d661aSToomas Soome error = nfs_lookupfh(currfd, ncp, newfd); 12154a5d661aSToomas Soome *cp = c; 12164a5d661aSToomas Soome if (error) 12174a5d661aSToomas Soome goto out; 12184a5d661aSToomas Soome 12194a5d661aSToomas Soome /* 12204a5d661aSToomas Soome * Check for symbolic link 12214a5d661aSToomas Soome */ 12224a5d661aSToomas Soome if (newfd->fa.fa_type == htonl(NFLNK)) { 12234a5d661aSToomas Soome int link_len, len; 12244a5d661aSToomas Soome 12254a5d661aSToomas Soome error = nfs_readlink(newfd, linkbuf); 12264a5d661aSToomas Soome if (error) 12274a5d661aSToomas Soome goto out; 12284a5d661aSToomas Soome 12294a5d661aSToomas Soome link_len = strlen(linkbuf); 12304a5d661aSToomas Soome len = strlen(cp); 12314a5d661aSToomas Soome 12324a5d661aSToomas Soome if (link_len + len > MAXPATHLEN 12334a5d661aSToomas Soome || ++nlinks > MAXSYMLINKS) { 12344a5d661aSToomas Soome error = ENOENT; 12354a5d661aSToomas Soome goto out; 12364a5d661aSToomas Soome } 12374a5d661aSToomas Soome 12384a5d661aSToomas Soome bcopy(cp, &namebuf[link_len], len + 1); 12394a5d661aSToomas Soome bcopy(linkbuf, namebuf, link_len); 12404a5d661aSToomas Soome 12414a5d661aSToomas Soome /* 12424a5d661aSToomas Soome * If absolute pathname, restart at root. 12434a5d661aSToomas Soome * If relative pathname, restart at parent directory. 12444a5d661aSToomas Soome */ 12454a5d661aSToomas Soome cp = namebuf; 12464a5d661aSToomas Soome if (*cp == '/') 12474a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 12484a5d661aSToomas Soome 12494a5d661aSToomas Soome free(newfd); 1250830d404aSToomas Soome newfd = NULL; 12514a5d661aSToomas Soome 12524a5d661aSToomas Soome continue; 12534a5d661aSToomas Soome } 12544a5d661aSToomas Soome 12554a5d661aSToomas Soome free(currfd); 12564a5d661aSToomas Soome currfd = newfd; 1257830d404aSToomas Soome newfd = NULL; 12584a5d661aSToomas Soome } 12594a5d661aSToomas Soome 12604a5d661aSToomas Soome error = 0; 12614a5d661aSToomas Soome 12624a5d661aSToomas Soome out: 12634a5d661aSToomas Soome free(newfd); 12644a5d661aSToomas Soome free(path); 12654a5d661aSToomas Soome #else 12664a5d661aSToomas Soome currfd->iodesc = desc; 12674a5d661aSToomas Soome 12684a5d661aSToomas Soome error = nfs_lookupfh(&nfs_root_node, upath, currfd); 12694a5d661aSToomas Soome #endif 12704a5d661aSToomas Soome if (!error) { 12714a5d661aSToomas Soome currfd->off = 0; 12724a5d661aSToomas Soome currfd->cookie = 0; 12734a5d661aSToomas Soome f->f_fsdata = (void *)currfd; 12744a5d661aSToomas Soome return (0); 12754a5d661aSToomas Soome } 12764a5d661aSToomas Soome 12774a5d661aSToomas Soome #ifdef NFS_DEBUG 12784a5d661aSToomas Soome if (debug) 12794a5d661aSToomas Soome printf("nfs_open: %s lookupfh failed: %s\n", 12804a5d661aSToomas Soome path, strerror(error)); 12814a5d661aSToomas Soome #endif 12824a5d661aSToomas Soome free(currfd); 12834a5d661aSToomas Soome 12844a5d661aSToomas Soome return (error); 12854a5d661aSToomas Soome } 12864a5d661aSToomas Soome 12874a5d661aSToomas Soome int 12884a5d661aSToomas Soome nfs_close(struct open_file *f) 12894a5d661aSToomas Soome { 12904a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 12914a5d661aSToomas Soome 12924a5d661aSToomas Soome #ifdef NFS_DEBUG 12934a5d661aSToomas Soome if (debug) 12944a5d661aSToomas Soome printf("nfs_close: fp=0x%lx\n", (u_long)fp); 12954a5d661aSToomas Soome #endif 12964a5d661aSToomas Soome 12974a5d661aSToomas Soome if (fp) 12984a5d661aSToomas Soome free(fp); 12994a5d661aSToomas Soome f->f_fsdata = (void *)0; 13004a5d661aSToomas Soome 13014a5d661aSToomas Soome return (0); 13024a5d661aSToomas Soome } 13034a5d661aSToomas Soome 13044a5d661aSToomas Soome /* 13054a5d661aSToomas Soome * read a portion of a file 13064a5d661aSToomas Soome */ 13074a5d661aSToomas Soome int 13084a5d661aSToomas Soome nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 13094a5d661aSToomas Soome { 13104a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 13114a5d661aSToomas Soome ssize_t cc; 13124a5d661aSToomas Soome char *addr = buf; 13134a5d661aSToomas Soome 13144a5d661aSToomas Soome #ifdef NFS_DEBUG 13154a5d661aSToomas Soome if (debug) 13164a5d661aSToomas Soome printf("nfs_read: size=%lu off=%d\n", (u_long)size, 13174a5d661aSToomas Soome (int)fp->off); 13184a5d661aSToomas Soome #endif 13194a5d661aSToomas Soome while ((int)size > 0) { 13204a5d661aSToomas Soome twiddle(16); 13214a5d661aSToomas Soome cc = nfs_readdata(fp, fp->off, (void *)addr, size); 13224a5d661aSToomas Soome /* XXX maybe should retry on certain errors */ 13234a5d661aSToomas Soome if (cc == -1) { 13244a5d661aSToomas Soome #ifdef NFS_DEBUG 13254a5d661aSToomas Soome if (debug) 13264a5d661aSToomas Soome printf("nfs_read: read: %s", strerror(errno)); 13274a5d661aSToomas Soome #endif 13284a5d661aSToomas Soome return (errno); /* XXX - from nfs_readdata */ 13294a5d661aSToomas Soome } 13304a5d661aSToomas Soome if (cc == 0) { 13314a5d661aSToomas Soome #ifdef NFS_DEBUG 13324a5d661aSToomas Soome if (debug) 13334a5d661aSToomas Soome printf("nfs_read: hit EOF unexpectantly"); 13344a5d661aSToomas Soome #endif 13354a5d661aSToomas Soome goto ret; 13364a5d661aSToomas Soome } 13374a5d661aSToomas Soome fp->off += cc; 13384a5d661aSToomas Soome addr += cc; 13394a5d661aSToomas Soome size -= cc; 13404a5d661aSToomas Soome } 13414a5d661aSToomas Soome ret: 13424a5d661aSToomas Soome if (resid) 13434a5d661aSToomas Soome *resid = size; 13444a5d661aSToomas Soome 13454a5d661aSToomas Soome return (0); 13464a5d661aSToomas Soome } 13474a5d661aSToomas Soome 13484a5d661aSToomas Soome /* 13494a5d661aSToomas Soome * Not implemented. 13504a5d661aSToomas Soome */ 13514a5d661aSToomas Soome int 13524a5d661aSToomas Soome nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 13534a5d661aSToomas Soome { 13544a5d661aSToomas Soome return (EROFS); 13554a5d661aSToomas Soome } 13564a5d661aSToomas Soome 13574a5d661aSToomas Soome off_t 13584a5d661aSToomas Soome nfs_seek(struct open_file *f, off_t offset, int where) 13594a5d661aSToomas Soome { 13604a5d661aSToomas Soome struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 13614a5d661aSToomas Soome uint32_t size = ntohl(d->fa.fa_size.val[1]); 13624a5d661aSToomas Soome 13634a5d661aSToomas Soome switch (where) { 13644a5d661aSToomas Soome case SEEK_SET: 13654a5d661aSToomas Soome d->off = offset; 13664a5d661aSToomas Soome break; 13674a5d661aSToomas Soome case SEEK_CUR: 13684a5d661aSToomas Soome d->off += offset; 13694a5d661aSToomas Soome break; 13704a5d661aSToomas Soome case SEEK_END: 13714a5d661aSToomas Soome d->off = size - offset; 13724a5d661aSToomas Soome break; 13734a5d661aSToomas Soome default: 13744a5d661aSToomas Soome errno = EINVAL; 13754a5d661aSToomas Soome return (-1); 13764a5d661aSToomas Soome } 13774a5d661aSToomas Soome 13784a5d661aSToomas Soome return (d->off); 13794a5d661aSToomas Soome } 13804a5d661aSToomas Soome 13814a5d661aSToomas Soome /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 13824a5d661aSToomas Soome int nfs_stat_types[9] = { 13834a5d661aSToomas Soome 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 13844a5d661aSToomas Soome 13854a5d661aSToomas Soome int 13864a5d661aSToomas Soome nfs_stat(struct open_file *f, struct stat *sb) 13874a5d661aSToomas Soome { 13884a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 13894a5d661aSToomas Soome uint32_t ftype, mode; 13904a5d661aSToomas Soome 13914a5d661aSToomas Soome ftype = ntohl(fp->fa.fa_type); 13924a5d661aSToomas Soome mode = ntohl(fp->fa.fa_mode); 13934a5d661aSToomas Soome mode |= nfs_stat_types[ftype & 7]; 13944a5d661aSToomas Soome 13954a5d661aSToomas Soome sb->st_mode = mode; 13964a5d661aSToomas Soome sb->st_nlink = ntohl(fp->fa.fa_nlink); 13974a5d661aSToomas Soome sb->st_uid = ntohl(fp->fa.fa_uid); 13984a5d661aSToomas Soome sb->st_gid = ntohl(fp->fa.fa_gid); 13994a5d661aSToomas Soome sb->st_size = ntohl(fp->fa.fa_size.val[1]); 14004a5d661aSToomas Soome 14014a5d661aSToomas Soome return (0); 14024a5d661aSToomas Soome } 14034a5d661aSToomas Soome 14044a5d661aSToomas Soome static int 14054a5d661aSToomas Soome nfs_readdir(struct open_file *f, struct dirent *d) 14064a5d661aSToomas Soome { 14074a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 14084a5d661aSToomas Soome struct nfsv3_readdir_repl *repl; 14094a5d661aSToomas Soome struct nfsv3_readdir_entry *rent; 14104a5d661aSToomas Soome static char *buf; 14114a5d661aSToomas Soome static struct nfs_iodesc *pfp = NULL; 14124a5d661aSToomas Soome static uint64_t cookie = 0; 14134a5d661aSToomas Soome size_t cc; 14144a5d661aSToomas Soome int pos; 14154a5d661aSToomas Soome 14164a5d661aSToomas Soome struct args { 14174a5d661aSToomas Soome uint32_t fhsize; 14184a5d661aSToomas Soome uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 14194a5d661aSToomas Soome } *args; 14204a5d661aSToomas Soome struct { 14214a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 14224a5d661aSToomas Soome struct args d; 14234a5d661aSToomas Soome } sdata; 14244a5d661aSToomas Soome static struct { 14254a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 14264a5d661aSToomas Soome u_char d[NFS_READDIRSIZE]; 14274a5d661aSToomas Soome } rdata; 14284a5d661aSToomas Soome 14294a5d661aSToomas Soome if (fp != pfp || fp->off != cookie) { 14304a5d661aSToomas Soome pfp = NULL; 14314a5d661aSToomas Soome refill: 14324a5d661aSToomas Soome args = &sdata.d; 14334a5d661aSToomas Soome bzero(args, sizeof(*args)); 14344a5d661aSToomas Soome 14354a5d661aSToomas Soome args->fhsize = htonl(fp->fhsize); 14364a5d661aSToomas Soome bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 14374a5d661aSToomas Soome pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 14384a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->off >> 32); 14394a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->off); 14404a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 14414a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->cookie); 14424a5d661aSToomas Soome args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 14434a5d661aSToomas Soome 14444a5d661aSToomas Soome cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 14454a5d661aSToomas Soome args, 6 * sizeof(uint32_t) + 14464a5d661aSToomas Soome roundup(fp->fhsize, sizeof(uint32_t)), 14474a5d661aSToomas Soome rdata.d, sizeof(rdata.d)); 14484a5d661aSToomas Soome buf = rdata.d; 14494a5d661aSToomas Soome repl = (struct nfsv3_readdir_repl *)buf; 14504a5d661aSToomas Soome if (repl->errno != 0) 14514a5d661aSToomas Soome return (ntohl(repl->errno)); 14524a5d661aSToomas Soome pfp = fp; 14534a5d661aSToomas Soome cookie = fp->off; 14544a5d661aSToomas Soome fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 14554a5d661aSToomas Soome ntohl(repl->cookiev1); 14564a5d661aSToomas Soome buf += sizeof (struct nfsv3_readdir_repl); 14574a5d661aSToomas Soome } 14584a5d661aSToomas Soome rent = (struct nfsv3_readdir_entry *)buf; 14594a5d661aSToomas Soome 14604a5d661aSToomas Soome if (rent->follows == 0) { 14614a5d661aSToomas Soome /* fid0 is actually eof */ 14624a5d661aSToomas Soome if (rent->fid0 != 0) { 14634a5d661aSToomas Soome cookie = 0; 14644a5d661aSToomas Soome return (ENOENT); 14654a5d661aSToomas Soome } 14664a5d661aSToomas Soome goto refill; 14674a5d661aSToomas Soome } 14684a5d661aSToomas Soome 14694a5d661aSToomas Soome d->d_namlen = ntohl(rent->len); 14704a5d661aSToomas Soome bcopy(rent->nameplus, d->d_name, d->d_namlen); 14714a5d661aSToomas Soome d->d_name[d->d_namlen] = '\0'; 14724a5d661aSToomas Soome 14734a5d661aSToomas Soome pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 14744a5d661aSToomas Soome fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 14754a5d661aSToomas Soome ntohl(rent->nameplus[pos + 1]); 14764a5d661aSToomas Soome pos += 2; 14774a5d661aSToomas Soome buf = (u_char *)&rent->nameplus[pos]; 14784a5d661aSToomas Soome return (0); 14794a5d661aSToomas Soome } 14804a5d661aSToomas Soome #endif /* OLD_NFSV2 */ 1481