1*4a5d661aSToomas Soome /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 2*4a5d661aSToomas Soome 3*4a5d661aSToomas Soome /*- 4*4a5d661aSToomas Soome * Copyright (c) 1993 John Brezak 5*4a5d661aSToomas Soome * All rights reserved. 6*4a5d661aSToomas Soome * 7*4a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without 8*4a5d661aSToomas Soome * modification, are permitted provided that the following conditions 9*4a5d661aSToomas Soome * are met: 10*4a5d661aSToomas Soome * 1. Redistributions of source code must retain the above copyright 11*4a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer. 12*4a5d661aSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 13*4a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer in the 14*4a5d661aSToomas Soome * documentation and/or other materials provided with the distribution. 15*4a5d661aSToomas Soome * 3. The name of the author may not be used to endorse or promote products 16*4a5d661aSToomas Soome * derived from this software without specific prior written permission. 17*4a5d661aSToomas Soome * 18*4a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19*4a5d661aSToomas Soome * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20*4a5d661aSToomas Soome * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21*4a5d661aSToomas Soome * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22*4a5d661aSToomas Soome * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23*4a5d661aSToomas Soome * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24*4a5d661aSToomas Soome * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*4a5d661aSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26*4a5d661aSToomas Soome * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27*4a5d661aSToomas Soome * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*4a5d661aSToomas Soome * POSSIBILITY OF SUCH DAMAGE. 29*4a5d661aSToomas Soome */ 30*4a5d661aSToomas Soome 31*4a5d661aSToomas Soome #include <sys/cdefs.h> 32*4a5d661aSToomas Soome __FBSDID("$FreeBSD$"); 33*4a5d661aSToomas Soome 34*4a5d661aSToomas Soome #include <sys/param.h> 35*4a5d661aSToomas Soome #include <sys/time.h> 36*4a5d661aSToomas Soome #include <sys/socket.h> 37*4a5d661aSToomas Soome #include <sys/stat.h> 38*4a5d661aSToomas Soome #include <string.h> 39*4a5d661aSToomas Soome 40*4a5d661aSToomas Soome #include <netinet/in.h> 41*4a5d661aSToomas Soome #include <netinet/in_systm.h> 42*4a5d661aSToomas Soome 43*4a5d661aSToomas Soome #include "rpcv2.h" 44*4a5d661aSToomas Soome #include "nfsv2.h" 45*4a5d661aSToomas Soome 46*4a5d661aSToomas Soome #include "stand.h" 47*4a5d661aSToomas Soome #include "net.h" 48*4a5d661aSToomas Soome #include "netif.h" 49*4a5d661aSToomas Soome #include "rpc.h" 50*4a5d661aSToomas Soome 51*4a5d661aSToomas Soome #define NFS_DEBUGxx 52*4a5d661aSToomas Soome 53*4a5d661aSToomas Soome #define NFSREAD_SIZE 1024 54*4a5d661aSToomas Soome 55*4a5d661aSToomas Soome /* Define our own NFS attributes without NQNFS stuff. */ 56*4a5d661aSToomas Soome #ifdef OLD_NFSV2 57*4a5d661aSToomas Soome struct nfsv2_fattrs { 58*4a5d661aSToomas Soome n_long fa_type; 59*4a5d661aSToomas Soome n_long fa_mode; 60*4a5d661aSToomas Soome n_long fa_nlink; 61*4a5d661aSToomas Soome n_long fa_uid; 62*4a5d661aSToomas Soome n_long fa_gid; 63*4a5d661aSToomas Soome n_long fa_size; 64*4a5d661aSToomas Soome n_long fa_blocksize; 65*4a5d661aSToomas Soome n_long fa_rdev; 66*4a5d661aSToomas Soome n_long fa_blocks; 67*4a5d661aSToomas Soome n_long fa_fsid; 68*4a5d661aSToomas Soome n_long fa_fileid; 69*4a5d661aSToomas Soome struct nfsv2_time fa_atime; 70*4a5d661aSToomas Soome struct nfsv2_time fa_mtime; 71*4a5d661aSToomas Soome struct nfsv2_time fa_ctime; 72*4a5d661aSToomas Soome }; 73*4a5d661aSToomas Soome 74*4a5d661aSToomas Soome struct nfs_read_args { 75*4a5d661aSToomas Soome u_char fh[NFS_FHSIZE]; 76*4a5d661aSToomas Soome n_long off; 77*4a5d661aSToomas Soome n_long len; 78*4a5d661aSToomas Soome n_long xxx; /* XXX what's this for? */ 79*4a5d661aSToomas Soome }; 80*4a5d661aSToomas Soome 81*4a5d661aSToomas Soome /* Data part of nfs rpc reply (also the largest thing we receive) */ 82*4a5d661aSToomas Soome struct nfs_read_repl { 83*4a5d661aSToomas Soome n_long errno; 84*4a5d661aSToomas Soome struct nfsv2_fattrs fa; 85*4a5d661aSToomas Soome n_long count; 86*4a5d661aSToomas Soome u_char data[NFSREAD_SIZE]; 87*4a5d661aSToomas Soome }; 88*4a5d661aSToomas Soome 89*4a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 90*4a5d661aSToomas Soome struct nfs_readlnk_repl { 91*4a5d661aSToomas Soome n_long errno; 92*4a5d661aSToomas Soome n_long len; 93*4a5d661aSToomas Soome char path[NFS_MAXPATHLEN]; 94*4a5d661aSToomas Soome }; 95*4a5d661aSToomas Soome #endif 96*4a5d661aSToomas Soome 97*4a5d661aSToomas Soome struct nfs_readdir_args { 98*4a5d661aSToomas Soome u_char fh[NFS_FHSIZE]; 99*4a5d661aSToomas Soome n_long cookie; 100*4a5d661aSToomas Soome n_long count; 101*4a5d661aSToomas Soome }; 102*4a5d661aSToomas Soome 103*4a5d661aSToomas Soome struct nfs_readdir_data { 104*4a5d661aSToomas Soome n_long fileid; 105*4a5d661aSToomas Soome n_long len; 106*4a5d661aSToomas Soome char name[0]; 107*4a5d661aSToomas Soome }; 108*4a5d661aSToomas Soome 109*4a5d661aSToomas Soome struct nfs_readdir_off { 110*4a5d661aSToomas Soome n_long cookie; 111*4a5d661aSToomas Soome n_long follows; 112*4a5d661aSToomas Soome }; 113*4a5d661aSToomas Soome 114*4a5d661aSToomas Soome struct nfs_iodesc { 115*4a5d661aSToomas Soome struct iodesc *iodesc; 116*4a5d661aSToomas Soome off_t off; 117*4a5d661aSToomas Soome u_char fh[NFS_FHSIZE]; 118*4a5d661aSToomas Soome struct nfsv2_fattrs fa; /* all in network order */ 119*4a5d661aSToomas Soome }; 120*4a5d661aSToomas Soome #else /* !OLD_NFSV2 */ 121*4a5d661aSToomas Soome 122*4a5d661aSToomas Soome /* NFSv3 definitions */ 123*4a5d661aSToomas Soome #define NFS_V3MAXFHSIZE 64 124*4a5d661aSToomas Soome #define NFS_VER3 3 125*4a5d661aSToomas Soome #define RPCMNT_VER3 3 126*4a5d661aSToomas Soome #define NFSPROCV3_LOOKUP 3 127*4a5d661aSToomas Soome #define NFSPROCV3_READLINK 5 128*4a5d661aSToomas Soome #define NFSPROCV3_READ 6 129*4a5d661aSToomas Soome #define NFSPROCV3_READDIR 16 130*4a5d661aSToomas Soome 131*4a5d661aSToomas Soome typedef struct { 132*4a5d661aSToomas Soome uint32_t val[2]; 133*4a5d661aSToomas Soome } n_quad; 134*4a5d661aSToomas Soome 135*4a5d661aSToomas Soome struct nfsv3_time { 136*4a5d661aSToomas Soome uint32_t nfs_sec; 137*4a5d661aSToomas Soome uint32_t nfs_nsec; 138*4a5d661aSToomas Soome }; 139*4a5d661aSToomas Soome 140*4a5d661aSToomas Soome struct nfsv3_fattrs { 141*4a5d661aSToomas Soome uint32_t fa_type; 142*4a5d661aSToomas Soome uint32_t fa_mode; 143*4a5d661aSToomas Soome uint32_t fa_nlink; 144*4a5d661aSToomas Soome uint32_t fa_uid; 145*4a5d661aSToomas Soome uint32_t fa_gid; 146*4a5d661aSToomas Soome n_quad fa_size; 147*4a5d661aSToomas Soome n_quad fa_used; 148*4a5d661aSToomas Soome n_quad fa_rdev; 149*4a5d661aSToomas Soome n_quad fa_fsid; 150*4a5d661aSToomas Soome n_quad fa_fileid; 151*4a5d661aSToomas Soome struct nfsv3_time fa_atime; 152*4a5d661aSToomas Soome struct nfsv3_time fa_mtime; 153*4a5d661aSToomas Soome struct nfsv3_time fa_ctime; 154*4a5d661aSToomas Soome }; 155*4a5d661aSToomas Soome 156*4a5d661aSToomas Soome /* 157*4a5d661aSToomas Soome * For NFSv3, the file handle is variable in size, so most fixed sized 158*4a5d661aSToomas Soome * structures for arguments won't work. For most cases, a structure 159*4a5d661aSToomas Soome * that starts with any fixed size section is followed by an array 160*4a5d661aSToomas Soome * that covers the maximum size required. 161*4a5d661aSToomas Soome */ 162*4a5d661aSToomas Soome struct nfsv3_readdir_repl { 163*4a5d661aSToomas Soome uint32_t errno; 164*4a5d661aSToomas Soome uint32_t ok; 165*4a5d661aSToomas Soome struct nfsv3_fattrs fa; 166*4a5d661aSToomas Soome uint32_t cookiev0; 167*4a5d661aSToomas Soome uint32_t cookiev1; 168*4a5d661aSToomas Soome }; 169*4a5d661aSToomas Soome 170*4a5d661aSToomas Soome struct nfsv3_readdir_entry { 171*4a5d661aSToomas Soome uint32_t follows; 172*4a5d661aSToomas Soome uint32_t fid0; 173*4a5d661aSToomas Soome uint32_t fid1; 174*4a5d661aSToomas Soome uint32_t len; 175*4a5d661aSToomas Soome uint32_t nameplus[0]; 176*4a5d661aSToomas Soome }; 177*4a5d661aSToomas Soome 178*4a5d661aSToomas Soome struct nfs_iodesc { 179*4a5d661aSToomas Soome struct iodesc *iodesc; 180*4a5d661aSToomas Soome off_t off; 181*4a5d661aSToomas Soome uint32_t fhsize; 182*4a5d661aSToomas Soome u_char fh[NFS_V3MAXFHSIZE]; 183*4a5d661aSToomas Soome struct nfsv3_fattrs fa; /* all in network order */ 184*4a5d661aSToomas Soome uint64_t cookie; 185*4a5d661aSToomas Soome }; 186*4a5d661aSToomas Soome #endif /* OLD_NFSV2 */ 187*4a5d661aSToomas Soome 188*4a5d661aSToomas Soome /* 189*4a5d661aSToomas Soome * XXX interactions with tftp? See nfswrapper.c for a confusing 190*4a5d661aSToomas Soome * issue. 191*4a5d661aSToomas Soome */ 192*4a5d661aSToomas Soome int nfs_open(const char *path, struct open_file *f); 193*4a5d661aSToomas Soome static int nfs_close(struct open_file *f); 194*4a5d661aSToomas Soome static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 195*4a5d661aSToomas Soome static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 196*4a5d661aSToomas Soome static off_t nfs_seek(struct open_file *f, off_t offset, int where); 197*4a5d661aSToomas Soome static int nfs_stat(struct open_file *f, struct stat *sb); 198*4a5d661aSToomas Soome static int nfs_readdir(struct open_file *f, struct dirent *d); 199*4a5d661aSToomas Soome 200*4a5d661aSToomas Soome struct nfs_iodesc nfs_root_node; 201*4a5d661aSToomas Soome 202*4a5d661aSToomas Soome struct fs_ops nfs_fsops = { 203*4a5d661aSToomas Soome "nfs", 204*4a5d661aSToomas Soome nfs_open, 205*4a5d661aSToomas Soome nfs_close, 206*4a5d661aSToomas Soome nfs_read, 207*4a5d661aSToomas Soome nfs_write, 208*4a5d661aSToomas Soome nfs_seek, 209*4a5d661aSToomas Soome nfs_stat, 210*4a5d661aSToomas Soome nfs_readdir 211*4a5d661aSToomas Soome }; 212*4a5d661aSToomas Soome 213*4a5d661aSToomas Soome #ifdef OLD_NFSV2 214*4a5d661aSToomas Soome /* 215*4a5d661aSToomas Soome * Fetch the root file handle (call mount daemon) 216*4a5d661aSToomas Soome * Return zero or error number. 217*4a5d661aSToomas Soome */ 218*4a5d661aSToomas Soome int 219*4a5d661aSToomas Soome nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) 220*4a5d661aSToomas Soome { 221*4a5d661aSToomas Soome int len; 222*4a5d661aSToomas Soome struct args { 223*4a5d661aSToomas Soome n_long len; 224*4a5d661aSToomas Soome char path[FNAME_SIZE]; 225*4a5d661aSToomas Soome } *args; 226*4a5d661aSToomas Soome struct repl { 227*4a5d661aSToomas Soome n_long errno; 228*4a5d661aSToomas Soome u_char fh[NFS_FHSIZE]; 229*4a5d661aSToomas Soome } *repl; 230*4a5d661aSToomas Soome struct { 231*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 232*4a5d661aSToomas Soome struct args d; 233*4a5d661aSToomas Soome } sdata; 234*4a5d661aSToomas Soome struct { 235*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 236*4a5d661aSToomas Soome struct repl d; 237*4a5d661aSToomas Soome } rdata; 238*4a5d661aSToomas Soome size_t cc; 239*4a5d661aSToomas Soome 240*4a5d661aSToomas Soome #ifdef NFS_DEBUG 241*4a5d661aSToomas Soome if (debug) 242*4a5d661aSToomas Soome printf("nfs_getrootfh: %s\n", path); 243*4a5d661aSToomas Soome #endif 244*4a5d661aSToomas Soome 245*4a5d661aSToomas Soome args = &sdata.d; 246*4a5d661aSToomas Soome repl = &rdata.d; 247*4a5d661aSToomas Soome 248*4a5d661aSToomas Soome bzero(args, sizeof(*args)); 249*4a5d661aSToomas Soome len = strlen(path); 250*4a5d661aSToomas Soome if (len > sizeof(args->path)) 251*4a5d661aSToomas Soome len = sizeof(args->path); 252*4a5d661aSToomas Soome args->len = htonl(len); 253*4a5d661aSToomas Soome bcopy(path, args->path, len); 254*4a5d661aSToomas Soome len = 4 + roundup(len, 4); 255*4a5d661aSToomas Soome 256*4a5d661aSToomas Soome cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 257*4a5d661aSToomas Soome args, len, repl, sizeof(*repl)); 258*4a5d661aSToomas Soome if (cc == -1) { 259*4a5d661aSToomas Soome /* errno was set by rpc_call */ 260*4a5d661aSToomas Soome return (errno); 261*4a5d661aSToomas Soome } 262*4a5d661aSToomas Soome if (cc < 4) 263*4a5d661aSToomas Soome return (EBADRPC); 264*4a5d661aSToomas Soome if (repl->errno) 265*4a5d661aSToomas Soome return (ntohl(repl->errno)); 266*4a5d661aSToomas Soome bcopy(repl->fh, fhp, sizeof(repl->fh)); 267*4a5d661aSToomas Soome return (0); 268*4a5d661aSToomas Soome } 269*4a5d661aSToomas Soome 270*4a5d661aSToomas Soome /* 271*4a5d661aSToomas Soome * Lookup a file. Store handle and attributes. 272*4a5d661aSToomas Soome * Return zero or error number. 273*4a5d661aSToomas Soome */ 274*4a5d661aSToomas Soome int 275*4a5d661aSToomas Soome nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 276*4a5d661aSToomas Soome { 277*4a5d661aSToomas Soome int len, rlen; 278*4a5d661aSToomas Soome struct args { 279*4a5d661aSToomas Soome u_char fh[NFS_FHSIZE]; 280*4a5d661aSToomas Soome n_long len; 281*4a5d661aSToomas Soome char name[FNAME_SIZE]; 282*4a5d661aSToomas Soome } *args; 283*4a5d661aSToomas Soome struct repl { 284*4a5d661aSToomas Soome n_long errno; 285*4a5d661aSToomas Soome u_char fh[NFS_FHSIZE]; 286*4a5d661aSToomas Soome struct nfsv2_fattrs fa; 287*4a5d661aSToomas Soome } *repl; 288*4a5d661aSToomas Soome struct { 289*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 290*4a5d661aSToomas Soome struct args d; 291*4a5d661aSToomas Soome } sdata; 292*4a5d661aSToomas Soome struct { 293*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 294*4a5d661aSToomas Soome struct repl d; 295*4a5d661aSToomas Soome } rdata; 296*4a5d661aSToomas Soome ssize_t cc; 297*4a5d661aSToomas Soome 298*4a5d661aSToomas Soome #ifdef NFS_DEBUG 299*4a5d661aSToomas Soome if (debug) 300*4a5d661aSToomas Soome printf("lookupfh: called\n"); 301*4a5d661aSToomas Soome #endif 302*4a5d661aSToomas Soome 303*4a5d661aSToomas Soome args = &sdata.d; 304*4a5d661aSToomas Soome repl = &rdata.d; 305*4a5d661aSToomas Soome 306*4a5d661aSToomas Soome bzero(args, sizeof(*args)); 307*4a5d661aSToomas Soome bcopy(d->fh, args->fh, sizeof(args->fh)); 308*4a5d661aSToomas Soome len = strlen(name); 309*4a5d661aSToomas Soome if (len > sizeof(args->name)) 310*4a5d661aSToomas Soome len = sizeof(args->name); 311*4a5d661aSToomas Soome bcopy(name, args->name, len); 312*4a5d661aSToomas Soome args->len = htonl(len); 313*4a5d661aSToomas Soome len = 4 + roundup(len, 4); 314*4a5d661aSToomas Soome len += NFS_FHSIZE; 315*4a5d661aSToomas Soome 316*4a5d661aSToomas Soome rlen = sizeof(*repl); 317*4a5d661aSToomas Soome 318*4a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 319*4a5d661aSToomas Soome args, len, repl, rlen); 320*4a5d661aSToomas Soome if (cc == -1) 321*4a5d661aSToomas Soome return (errno); /* XXX - from rpc_call */ 322*4a5d661aSToomas Soome if (cc < 4) 323*4a5d661aSToomas Soome return (EIO); 324*4a5d661aSToomas Soome if (repl->errno) { 325*4a5d661aSToomas Soome /* saerrno.h now matches NFS error numbers. */ 326*4a5d661aSToomas Soome return (ntohl(repl->errno)); 327*4a5d661aSToomas Soome } 328*4a5d661aSToomas Soome bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 329*4a5d661aSToomas Soome bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 330*4a5d661aSToomas Soome return (0); 331*4a5d661aSToomas Soome } 332*4a5d661aSToomas Soome 333*4a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 334*4a5d661aSToomas Soome /* 335*4a5d661aSToomas Soome * Get the destination of a symbolic link. 336*4a5d661aSToomas Soome */ 337*4a5d661aSToomas Soome int 338*4a5d661aSToomas Soome nfs_readlink(struct nfs_iodesc *d, char *buf) 339*4a5d661aSToomas Soome { 340*4a5d661aSToomas Soome struct { 341*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 342*4a5d661aSToomas Soome u_char fh[NFS_FHSIZE]; 343*4a5d661aSToomas Soome } sdata; 344*4a5d661aSToomas Soome struct { 345*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 346*4a5d661aSToomas Soome struct nfs_readlnk_repl d; 347*4a5d661aSToomas Soome } rdata; 348*4a5d661aSToomas Soome ssize_t cc; 349*4a5d661aSToomas Soome 350*4a5d661aSToomas Soome #ifdef NFS_DEBUG 351*4a5d661aSToomas Soome if (debug) 352*4a5d661aSToomas Soome printf("readlink: called\n"); 353*4a5d661aSToomas Soome #endif 354*4a5d661aSToomas Soome 355*4a5d661aSToomas Soome bcopy(d->fh, sdata.fh, NFS_FHSIZE); 356*4a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 357*4a5d661aSToomas Soome sdata.fh, NFS_FHSIZE, 358*4a5d661aSToomas Soome &rdata.d, sizeof(rdata.d)); 359*4a5d661aSToomas Soome if (cc == -1) 360*4a5d661aSToomas Soome return (errno); 361*4a5d661aSToomas Soome 362*4a5d661aSToomas Soome if (cc < 4) 363*4a5d661aSToomas Soome return (EIO); 364*4a5d661aSToomas Soome 365*4a5d661aSToomas Soome if (rdata.d.errno) 366*4a5d661aSToomas Soome return (ntohl(rdata.d.errno)); 367*4a5d661aSToomas Soome 368*4a5d661aSToomas Soome rdata.d.len = ntohl(rdata.d.len); 369*4a5d661aSToomas Soome if (rdata.d.len > NFS_MAXPATHLEN) 370*4a5d661aSToomas Soome return (ENAMETOOLONG); 371*4a5d661aSToomas Soome 372*4a5d661aSToomas Soome bcopy(rdata.d.path, buf, rdata.d.len); 373*4a5d661aSToomas Soome buf[rdata.d.len] = 0; 374*4a5d661aSToomas Soome return (0); 375*4a5d661aSToomas Soome } 376*4a5d661aSToomas Soome #endif 377*4a5d661aSToomas Soome 378*4a5d661aSToomas Soome /* 379*4a5d661aSToomas Soome * Read data from a file. 380*4a5d661aSToomas Soome * Return transfer count or -1 (and set errno) 381*4a5d661aSToomas Soome */ 382*4a5d661aSToomas Soome ssize_t 383*4a5d661aSToomas Soome nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 384*4a5d661aSToomas Soome { 385*4a5d661aSToomas Soome struct nfs_read_args *args; 386*4a5d661aSToomas Soome struct nfs_read_repl *repl; 387*4a5d661aSToomas Soome struct { 388*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 389*4a5d661aSToomas Soome struct nfs_read_args d; 390*4a5d661aSToomas Soome } sdata; 391*4a5d661aSToomas Soome struct { 392*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 393*4a5d661aSToomas Soome struct nfs_read_repl d; 394*4a5d661aSToomas Soome } rdata; 395*4a5d661aSToomas Soome size_t cc; 396*4a5d661aSToomas Soome long x; 397*4a5d661aSToomas Soome int hlen, rlen; 398*4a5d661aSToomas Soome 399*4a5d661aSToomas Soome args = &sdata.d; 400*4a5d661aSToomas Soome repl = &rdata.d; 401*4a5d661aSToomas Soome 402*4a5d661aSToomas Soome bcopy(d->fh, args->fh, NFS_FHSIZE); 403*4a5d661aSToomas Soome args->off = htonl((n_long)off); 404*4a5d661aSToomas Soome if (len > NFSREAD_SIZE) 405*4a5d661aSToomas Soome len = NFSREAD_SIZE; 406*4a5d661aSToomas Soome args->len = htonl((n_long)len); 407*4a5d661aSToomas Soome args->xxx = htonl((n_long)0); 408*4a5d661aSToomas Soome hlen = sizeof(*repl) - NFSREAD_SIZE; 409*4a5d661aSToomas Soome 410*4a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 411*4a5d661aSToomas Soome args, sizeof(*args), 412*4a5d661aSToomas Soome repl, sizeof(*repl)); 413*4a5d661aSToomas Soome if (cc == -1) { 414*4a5d661aSToomas Soome /* errno was already set by rpc_call */ 415*4a5d661aSToomas Soome return (-1); 416*4a5d661aSToomas Soome } 417*4a5d661aSToomas Soome if (cc < hlen) { 418*4a5d661aSToomas Soome errno = EBADRPC; 419*4a5d661aSToomas Soome return (-1); 420*4a5d661aSToomas Soome } 421*4a5d661aSToomas Soome if (repl->errno) { 422*4a5d661aSToomas Soome errno = ntohl(repl->errno); 423*4a5d661aSToomas Soome return (-1); 424*4a5d661aSToomas Soome } 425*4a5d661aSToomas Soome rlen = cc - hlen; 426*4a5d661aSToomas Soome x = ntohl(repl->count); 427*4a5d661aSToomas Soome if (rlen < x) { 428*4a5d661aSToomas Soome printf("nfsread: short packet, %d < %ld\n", rlen, x); 429*4a5d661aSToomas Soome errno = EBADRPC; 430*4a5d661aSToomas Soome return(-1); 431*4a5d661aSToomas Soome } 432*4a5d661aSToomas Soome bcopy(repl->data, addr, x); 433*4a5d661aSToomas Soome return (x); 434*4a5d661aSToomas Soome } 435*4a5d661aSToomas Soome 436*4a5d661aSToomas Soome /* 437*4a5d661aSToomas Soome * Open a file. 438*4a5d661aSToomas Soome * return zero or error number 439*4a5d661aSToomas Soome */ 440*4a5d661aSToomas Soome int 441*4a5d661aSToomas Soome nfs_open(const char *upath, struct open_file *f) 442*4a5d661aSToomas Soome { 443*4a5d661aSToomas Soome struct iodesc *desc; 444*4a5d661aSToomas Soome struct nfs_iodesc *currfd; 445*4a5d661aSToomas Soome char buf[2 * NFS_FHSIZE + 3]; 446*4a5d661aSToomas Soome u_char *fh; 447*4a5d661aSToomas Soome char *cp; 448*4a5d661aSToomas Soome int i; 449*4a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 450*4a5d661aSToomas Soome struct nfs_iodesc *newfd; 451*4a5d661aSToomas Soome struct nfsv2_fattrs *fa; 452*4a5d661aSToomas Soome char *ncp; 453*4a5d661aSToomas Soome int c; 454*4a5d661aSToomas Soome char namebuf[NFS_MAXPATHLEN + 1]; 455*4a5d661aSToomas Soome char linkbuf[NFS_MAXPATHLEN + 1]; 456*4a5d661aSToomas Soome int nlinks = 0; 457*4a5d661aSToomas Soome #endif 458*4a5d661aSToomas Soome int error; 459*4a5d661aSToomas Soome char *path; 460*4a5d661aSToomas Soome 461*4a5d661aSToomas Soome #ifdef NFS_DEBUG 462*4a5d661aSToomas Soome if (debug) 463*4a5d661aSToomas Soome printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 464*4a5d661aSToomas Soome #endif 465*4a5d661aSToomas Soome if (!rootpath[0]) { 466*4a5d661aSToomas Soome printf("no rootpath, no nfs\n"); 467*4a5d661aSToomas Soome return (ENXIO); 468*4a5d661aSToomas Soome } 469*4a5d661aSToomas Soome 470*4a5d661aSToomas Soome /* 471*4a5d661aSToomas Soome * This is silly - we should look at dv_type but that value is 472*4a5d661aSToomas Soome * arch dependant and we can't use it here. 473*4a5d661aSToomas Soome */ 474*4a5d661aSToomas Soome #ifndef __i386__ 475*4a5d661aSToomas Soome if (strcmp(f->f_dev->dv_name, "net") != 0) 476*4a5d661aSToomas Soome return(EINVAL); 477*4a5d661aSToomas Soome #else 478*4a5d661aSToomas Soome if (strcmp(f->f_dev->dv_name, "pxe") != 0) 479*4a5d661aSToomas Soome return(EINVAL); 480*4a5d661aSToomas Soome #endif 481*4a5d661aSToomas Soome 482*4a5d661aSToomas Soome if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 483*4a5d661aSToomas Soome return(EINVAL); 484*4a5d661aSToomas Soome 485*4a5d661aSToomas Soome /* Bind to a reserved port. */ 486*4a5d661aSToomas Soome desc->myport = htons(--rpc_port); 487*4a5d661aSToomas Soome desc->destip = rootip; 488*4a5d661aSToomas Soome if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 489*4a5d661aSToomas Soome return (error); 490*4a5d661aSToomas Soome nfs_root_node.fa.fa_type = htonl(NFDIR); 491*4a5d661aSToomas Soome nfs_root_node.fa.fa_mode = htonl(0755); 492*4a5d661aSToomas Soome nfs_root_node.fa.fa_nlink = htonl(2); 493*4a5d661aSToomas Soome nfs_root_node.iodesc = desc; 494*4a5d661aSToomas Soome 495*4a5d661aSToomas Soome fh = &nfs_root_node.fh[0]; 496*4a5d661aSToomas Soome buf[0] = 'X'; 497*4a5d661aSToomas Soome cp = &buf[1]; 498*4a5d661aSToomas Soome for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 499*4a5d661aSToomas Soome sprintf(cp, "%02x", fh[i]); 500*4a5d661aSToomas Soome sprintf(cp, "X"); 501*4a5d661aSToomas Soome setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 502*4a5d661aSToomas Soome setenv("boot.nfsroot.path", rootpath, 1); 503*4a5d661aSToomas Soome setenv("boot.nfsroot.nfshandle", buf, 1); 504*4a5d661aSToomas Soome 505*4a5d661aSToomas Soome /* Allocate file system specific data structure */ 506*4a5d661aSToomas Soome currfd = malloc(sizeof(*newfd)); 507*4a5d661aSToomas Soome if (currfd == NULL) { 508*4a5d661aSToomas Soome error = ENOMEM; 509*4a5d661aSToomas Soome goto out; 510*4a5d661aSToomas Soome } 511*4a5d661aSToomas Soome 512*4a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 513*4a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 514*4a5d661aSToomas Soome newfd = 0; 515*4a5d661aSToomas Soome 516*4a5d661aSToomas Soome cp = path = strdup(upath); 517*4a5d661aSToomas Soome if (path == NULL) { 518*4a5d661aSToomas Soome error = ENOMEM; 519*4a5d661aSToomas Soome goto out; 520*4a5d661aSToomas Soome } 521*4a5d661aSToomas Soome while (*cp) { 522*4a5d661aSToomas Soome /* 523*4a5d661aSToomas Soome * Remove extra separators 524*4a5d661aSToomas Soome */ 525*4a5d661aSToomas Soome while (*cp == '/') 526*4a5d661aSToomas Soome cp++; 527*4a5d661aSToomas Soome 528*4a5d661aSToomas Soome if (*cp == '\0') 529*4a5d661aSToomas Soome break; 530*4a5d661aSToomas Soome /* 531*4a5d661aSToomas Soome * Check that current node is a directory. 532*4a5d661aSToomas Soome */ 533*4a5d661aSToomas Soome if (currfd->fa.fa_type != htonl(NFDIR)) { 534*4a5d661aSToomas Soome error = ENOTDIR; 535*4a5d661aSToomas Soome goto out; 536*4a5d661aSToomas Soome } 537*4a5d661aSToomas Soome 538*4a5d661aSToomas Soome /* allocate file system specific data structure */ 539*4a5d661aSToomas Soome newfd = malloc(sizeof(*newfd)); 540*4a5d661aSToomas Soome newfd->iodesc = currfd->iodesc; 541*4a5d661aSToomas Soome 542*4a5d661aSToomas Soome /* 543*4a5d661aSToomas Soome * Get next component of path name. 544*4a5d661aSToomas Soome */ 545*4a5d661aSToomas Soome { 546*4a5d661aSToomas Soome int len = 0; 547*4a5d661aSToomas Soome 548*4a5d661aSToomas Soome ncp = cp; 549*4a5d661aSToomas Soome while ((c = *cp) != '\0' && c != '/') { 550*4a5d661aSToomas Soome if (++len > NFS_MAXNAMLEN) { 551*4a5d661aSToomas Soome error = ENOENT; 552*4a5d661aSToomas Soome goto out; 553*4a5d661aSToomas Soome } 554*4a5d661aSToomas Soome cp++; 555*4a5d661aSToomas Soome } 556*4a5d661aSToomas Soome *cp = '\0'; 557*4a5d661aSToomas Soome } 558*4a5d661aSToomas Soome 559*4a5d661aSToomas Soome /* lookup a file handle */ 560*4a5d661aSToomas Soome error = nfs_lookupfh(currfd, ncp, newfd); 561*4a5d661aSToomas Soome *cp = c; 562*4a5d661aSToomas Soome if (error) 563*4a5d661aSToomas Soome goto out; 564*4a5d661aSToomas Soome 565*4a5d661aSToomas Soome /* 566*4a5d661aSToomas Soome * Check for symbolic link 567*4a5d661aSToomas Soome */ 568*4a5d661aSToomas Soome if (newfd->fa.fa_type == htonl(NFLNK)) { 569*4a5d661aSToomas Soome int link_len, len; 570*4a5d661aSToomas Soome 571*4a5d661aSToomas Soome error = nfs_readlink(newfd, linkbuf); 572*4a5d661aSToomas Soome if (error) 573*4a5d661aSToomas Soome goto out; 574*4a5d661aSToomas Soome 575*4a5d661aSToomas Soome link_len = strlen(linkbuf); 576*4a5d661aSToomas Soome len = strlen(cp); 577*4a5d661aSToomas Soome 578*4a5d661aSToomas Soome if (link_len + len > MAXPATHLEN 579*4a5d661aSToomas Soome || ++nlinks > MAXSYMLINKS) { 580*4a5d661aSToomas Soome error = ENOENT; 581*4a5d661aSToomas Soome goto out; 582*4a5d661aSToomas Soome } 583*4a5d661aSToomas Soome 584*4a5d661aSToomas Soome bcopy(cp, &namebuf[link_len], len + 1); 585*4a5d661aSToomas Soome bcopy(linkbuf, namebuf, link_len); 586*4a5d661aSToomas Soome 587*4a5d661aSToomas Soome /* 588*4a5d661aSToomas Soome * If absolute pathname, restart at root. 589*4a5d661aSToomas Soome * If relative pathname, restart at parent directory. 590*4a5d661aSToomas Soome */ 591*4a5d661aSToomas Soome cp = namebuf; 592*4a5d661aSToomas Soome if (*cp == '/') 593*4a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 594*4a5d661aSToomas Soome 595*4a5d661aSToomas Soome free(newfd); 596*4a5d661aSToomas Soome newfd = 0; 597*4a5d661aSToomas Soome 598*4a5d661aSToomas Soome continue; 599*4a5d661aSToomas Soome } 600*4a5d661aSToomas Soome 601*4a5d661aSToomas Soome free(currfd); 602*4a5d661aSToomas Soome currfd = newfd; 603*4a5d661aSToomas Soome newfd = 0; 604*4a5d661aSToomas Soome } 605*4a5d661aSToomas Soome 606*4a5d661aSToomas Soome error = 0; 607*4a5d661aSToomas Soome 608*4a5d661aSToomas Soome out: 609*4a5d661aSToomas Soome free(newfd); 610*4a5d661aSToomas Soome free(path); 611*4a5d661aSToomas Soome #else 612*4a5d661aSToomas Soome currfd->iodesc = desc; 613*4a5d661aSToomas Soome 614*4a5d661aSToomas Soome error = nfs_lookupfh(&nfs_root_node, upath, currfd); 615*4a5d661aSToomas Soome #endif 616*4a5d661aSToomas Soome if (!error) { 617*4a5d661aSToomas Soome currfd->off = 0; 618*4a5d661aSToomas Soome f->f_fsdata = (void *)currfd; 619*4a5d661aSToomas Soome return (0); 620*4a5d661aSToomas Soome } 621*4a5d661aSToomas Soome 622*4a5d661aSToomas Soome #ifdef NFS_DEBUG 623*4a5d661aSToomas Soome if (debug) 624*4a5d661aSToomas Soome printf("nfs_open: %s lookupfh failed: %s\n", 625*4a5d661aSToomas Soome path, strerror(error)); 626*4a5d661aSToomas Soome #endif 627*4a5d661aSToomas Soome free(currfd); 628*4a5d661aSToomas Soome 629*4a5d661aSToomas Soome return (error); 630*4a5d661aSToomas Soome } 631*4a5d661aSToomas Soome 632*4a5d661aSToomas Soome int 633*4a5d661aSToomas Soome nfs_close(struct open_file *f) 634*4a5d661aSToomas Soome { 635*4a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 636*4a5d661aSToomas Soome 637*4a5d661aSToomas Soome #ifdef NFS_DEBUG 638*4a5d661aSToomas Soome if (debug) 639*4a5d661aSToomas Soome printf("nfs_close: fp=0x%lx\n", (u_long)fp); 640*4a5d661aSToomas Soome #endif 641*4a5d661aSToomas Soome 642*4a5d661aSToomas Soome if (fp) 643*4a5d661aSToomas Soome free(fp); 644*4a5d661aSToomas Soome f->f_fsdata = (void *)0; 645*4a5d661aSToomas Soome 646*4a5d661aSToomas Soome return (0); 647*4a5d661aSToomas Soome } 648*4a5d661aSToomas Soome 649*4a5d661aSToomas Soome /* 650*4a5d661aSToomas Soome * read a portion of a file 651*4a5d661aSToomas Soome */ 652*4a5d661aSToomas Soome int 653*4a5d661aSToomas Soome nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 654*4a5d661aSToomas Soome { 655*4a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 656*4a5d661aSToomas Soome ssize_t cc; 657*4a5d661aSToomas Soome char *addr = buf; 658*4a5d661aSToomas Soome 659*4a5d661aSToomas Soome #ifdef NFS_DEBUG 660*4a5d661aSToomas Soome if (debug) 661*4a5d661aSToomas Soome printf("nfs_read: size=%lu off=%d\n", (u_long)size, 662*4a5d661aSToomas Soome (int)fp->off); 663*4a5d661aSToomas Soome #endif 664*4a5d661aSToomas Soome while ((int)size > 0) { 665*4a5d661aSToomas Soome twiddle(16); 666*4a5d661aSToomas Soome cc = nfs_readdata(fp, fp->off, (void *)addr, size); 667*4a5d661aSToomas Soome /* XXX maybe should retry on certain errors */ 668*4a5d661aSToomas Soome if (cc == -1) { 669*4a5d661aSToomas Soome #ifdef NFS_DEBUG 670*4a5d661aSToomas Soome if (debug) 671*4a5d661aSToomas Soome printf("nfs_read: read: %s", strerror(errno)); 672*4a5d661aSToomas Soome #endif 673*4a5d661aSToomas Soome return (errno); /* XXX - from nfs_readdata */ 674*4a5d661aSToomas Soome } 675*4a5d661aSToomas Soome if (cc == 0) { 676*4a5d661aSToomas Soome #ifdef NFS_DEBUG 677*4a5d661aSToomas Soome if (debug) 678*4a5d661aSToomas Soome printf("nfs_read: hit EOF unexpectantly"); 679*4a5d661aSToomas Soome #endif 680*4a5d661aSToomas Soome goto ret; 681*4a5d661aSToomas Soome } 682*4a5d661aSToomas Soome fp->off += cc; 683*4a5d661aSToomas Soome addr += cc; 684*4a5d661aSToomas Soome size -= cc; 685*4a5d661aSToomas Soome } 686*4a5d661aSToomas Soome ret: 687*4a5d661aSToomas Soome if (resid) 688*4a5d661aSToomas Soome *resid = size; 689*4a5d661aSToomas Soome 690*4a5d661aSToomas Soome return (0); 691*4a5d661aSToomas Soome } 692*4a5d661aSToomas Soome 693*4a5d661aSToomas Soome /* 694*4a5d661aSToomas Soome * Not implemented. 695*4a5d661aSToomas Soome */ 696*4a5d661aSToomas Soome int 697*4a5d661aSToomas Soome nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 698*4a5d661aSToomas Soome { 699*4a5d661aSToomas Soome return (EROFS); 700*4a5d661aSToomas Soome } 701*4a5d661aSToomas Soome 702*4a5d661aSToomas Soome off_t 703*4a5d661aSToomas Soome nfs_seek(struct open_file *f, off_t offset, int where) 704*4a5d661aSToomas Soome { 705*4a5d661aSToomas Soome struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 706*4a5d661aSToomas Soome n_long size = ntohl(d->fa.fa_size); 707*4a5d661aSToomas Soome 708*4a5d661aSToomas Soome switch (where) { 709*4a5d661aSToomas Soome case SEEK_SET: 710*4a5d661aSToomas Soome d->off = offset; 711*4a5d661aSToomas Soome break; 712*4a5d661aSToomas Soome case SEEK_CUR: 713*4a5d661aSToomas Soome d->off += offset; 714*4a5d661aSToomas Soome break; 715*4a5d661aSToomas Soome case SEEK_END: 716*4a5d661aSToomas Soome d->off = size - offset; 717*4a5d661aSToomas Soome break; 718*4a5d661aSToomas Soome default: 719*4a5d661aSToomas Soome errno = EINVAL; 720*4a5d661aSToomas Soome return (-1); 721*4a5d661aSToomas Soome } 722*4a5d661aSToomas Soome 723*4a5d661aSToomas Soome return (d->off); 724*4a5d661aSToomas Soome } 725*4a5d661aSToomas Soome 726*4a5d661aSToomas Soome /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 727*4a5d661aSToomas Soome int nfs_stat_types[8] = { 728*4a5d661aSToomas Soome 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 729*4a5d661aSToomas Soome 730*4a5d661aSToomas Soome int 731*4a5d661aSToomas Soome nfs_stat(struct open_file *f, struct stat *sb) 732*4a5d661aSToomas Soome { 733*4a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 734*4a5d661aSToomas Soome n_long ftype, mode; 735*4a5d661aSToomas Soome 736*4a5d661aSToomas Soome ftype = ntohl(fp->fa.fa_type); 737*4a5d661aSToomas Soome mode = ntohl(fp->fa.fa_mode); 738*4a5d661aSToomas Soome mode |= nfs_stat_types[ftype & 7]; 739*4a5d661aSToomas Soome 740*4a5d661aSToomas Soome sb->st_mode = mode; 741*4a5d661aSToomas Soome sb->st_nlink = ntohl(fp->fa.fa_nlink); 742*4a5d661aSToomas Soome sb->st_uid = ntohl(fp->fa.fa_uid); 743*4a5d661aSToomas Soome sb->st_gid = ntohl(fp->fa.fa_gid); 744*4a5d661aSToomas Soome sb->st_size = ntohl(fp->fa.fa_size); 745*4a5d661aSToomas Soome 746*4a5d661aSToomas Soome return (0); 747*4a5d661aSToomas Soome } 748*4a5d661aSToomas Soome 749*4a5d661aSToomas Soome static int 750*4a5d661aSToomas Soome nfs_readdir(struct open_file *f, struct dirent *d) 751*4a5d661aSToomas Soome { 752*4a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 753*4a5d661aSToomas Soome struct nfs_readdir_args *args; 754*4a5d661aSToomas Soome struct nfs_readdir_data *rd; 755*4a5d661aSToomas Soome struct nfs_readdir_off *roff = NULL; 756*4a5d661aSToomas Soome static char *buf; 757*4a5d661aSToomas Soome static struct nfs_iodesc *pfp = NULL; 758*4a5d661aSToomas Soome static n_long cookie = 0; 759*4a5d661aSToomas Soome size_t cc; 760*4a5d661aSToomas Soome n_long eof; 761*4a5d661aSToomas Soome 762*4a5d661aSToomas Soome struct { 763*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 764*4a5d661aSToomas Soome struct nfs_readdir_args d; 765*4a5d661aSToomas Soome } sdata; 766*4a5d661aSToomas Soome static struct { 767*4a5d661aSToomas Soome n_long h[RPC_HEADER_WORDS]; 768*4a5d661aSToomas Soome u_char d[NFS_READDIRSIZE]; 769*4a5d661aSToomas Soome } rdata; 770*4a5d661aSToomas Soome 771*4a5d661aSToomas Soome if (fp != pfp || fp->off != cookie) { 772*4a5d661aSToomas Soome pfp = NULL; 773*4a5d661aSToomas Soome refill: 774*4a5d661aSToomas Soome args = &sdata.d; 775*4a5d661aSToomas Soome bzero(args, sizeof(*args)); 776*4a5d661aSToomas Soome 777*4a5d661aSToomas Soome bcopy(fp->fh, args->fh, NFS_FHSIZE); 778*4a5d661aSToomas Soome args->cookie = htonl(fp->off); 779*4a5d661aSToomas Soome args->count = htonl(NFS_READDIRSIZE); 780*4a5d661aSToomas Soome 781*4a5d661aSToomas Soome cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 782*4a5d661aSToomas Soome args, sizeof(*args), 783*4a5d661aSToomas Soome rdata.d, sizeof(rdata.d)); 784*4a5d661aSToomas Soome buf = rdata.d; 785*4a5d661aSToomas Soome roff = (struct nfs_readdir_off *)buf; 786*4a5d661aSToomas Soome if (ntohl(roff->cookie) != 0) 787*4a5d661aSToomas Soome return EIO; 788*4a5d661aSToomas Soome pfp = fp; 789*4a5d661aSToomas Soome cookie = fp->off; 790*4a5d661aSToomas Soome } 791*4a5d661aSToomas Soome roff = (struct nfs_readdir_off *)buf; 792*4a5d661aSToomas Soome 793*4a5d661aSToomas Soome if (ntohl(roff->follows) == 0) { 794*4a5d661aSToomas Soome eof = ntohl((roff+1)->cookie); 795*4a5d661aSToomas Soome if (eof) { 796*4a5d661aSToomas Soome cookie = 0; 797*4a5d661aSToomas Soome return ENOENT; 798*4a5d661aSToomas Soome } 799*4a5d661aSToomas Soome goto refill; 800*4a5d661aSToomas Soome } 801*4a5d661aSToomas Soome 802*4a5d661aSToomas Soome buf += sizeof(struct nfs_readdir_off); 803*4a5d661aSToomas Soome rd = (struct nfs_readdir_data *)buf; 804*4a5d661aSToomas Soome d->d_namlen = ntohl(rd->len); 805*4a5d661aSToomas Soome bcopy(rd->name, d->d_name, d->d_namlen); 806*4a5d661aSToomas Soome d->d_name[d->d_namlen] = '\0'; 807*4a5d661aSToomas Soome 808*4a5d661aSToomas Soome buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 809*4a5d661aSToomas Soome roff = (struct nfs_readdir_off *)buf; 810*4a5d661aSToomas Soome fp->off = cookie = ntohl(roff->cookie); 811*4a5d661aSToomas Soome return 0; 812*4a5d661aSToomas Soome } 813*4a5d661aSToomas Soome #else /* !OLD_NFSV2 */ 814*4a5d661aSToomas Soome /* 815*4a5d661aSToomas Soome * Fetch the root file handle (call mount daemon) 816*4a5d661aSToomas Soome * Return zero or error number. 817*4a5d661aSToomas Soome */ 818*4a5d661aSToomas Soome int 819*4a5d661aSToomas Soome nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 820*4a5d661aSToomas Soome { 821*4a5d661aSToomas Soome int len; 822*4a5d661aSToomas Soome struct args { 823*4a5d661aSToomas Soome uint32_t len; 824*4a5d661aSToomas Soome char path[FNAME_SIZE]; 825*4a5d661aSToomas Soome } *args; 826*4a5d661aSToomas Soome struct repl { 827*4a5d661aSToomas Soome uint32_t errno; 828*4a5d661aSToomas Soome uint32_t fhsize; 829*4a5d661aSToomas Soome u_char fh[NFS_V3MAXFHSIZE]; 830*4a5d661aSToomas Soome uint32_t authcnt; 831*4a5d661aSToomas Soome uint32_t auth[7]; 832*4a5d661aSToomas Soome } *repl; 833*4a5d661aSToomas Soome struct { 834*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 835*4a5d661aSToomas Soome struct args d; 836*4a5d661aSToomas Soome } sdata; 837*4a5d661aSToomas Soome struct { 838*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 839*4a5d661aSToomas Soome struct repl d; 840*4a5d661aSToomas Soome } rdata; 841*4a5d661aSToomas Soome size_t cc; 842*4a5d661aSToomas Soome 843*4a5d661aSToomas Soome #ifdef NFS_DEBUG 844*4a5d661aSToomas Soome if (debug) 845*4a5d661aSToomas Soome printf("nfs_getrootfh: %s\n", path); 846*4a5d661aSToomas Soome #endif 847*4a5d661aSToomas Soome 848*4a5d661aSToomas Soome args = &sdata.d; 849*4a5d661aSToomas Soome repl = &rdata.d; 850*4a5d661aSToomas Soome 851*4a5d661aSToomas Soome bzero(args, sizeof(*args)); 852*4a5d661aSToomas Soome len = strlen(path); 853*4a5d661aSToomas Soome if (len > sizeof(args->path)) 854*4a5d661aSToomas Soome len = sizeof(args->path); 855*4a5d661aSToomas Soome args->len = htonl(len); 856*4a5d661aSToomas Soome bcopy(path, args->path, len); 857*4a5d661aSToomas Soome len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 858*4a5d661aSToomas Soome 859*4a5d661aSToomas Soome cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 860*4a5d661aSToomas Soome args, len, repl, sizeof(*repl)); 861*4a5d661aSToomas Soome if (cc == -1) 862*4a5d661aSToomas Soome /* errno was set by rpc_call */ 863*4a5d661aSToomas Soome return (errno); 864*4a5d661aSToomas Soome if (cc < 2 * sizeof (uint32_t)) 865*4a5d661aSToomas Soome return (EBADRPC); 866*4a5d661aSToomas Soome if (repl->errno != 0) 867*4a5d661aSToomas Soome return (ntohl(repl->errno)); 868*4a5d661aSToomas Soome *fhlenp = ntohl(repl->fhsize); 869*4a5d661aSToomas Soome bcopy(repl->fh, fhp, *fhlenp); 870*4a5d661aSToomas Soome return (0); 871*4a5d661aSToomas Soome } 872*4a5d661aSToomas Soome 873*4a5d661aSToomas Soome /* 874*4a5d661aSToomas Soome * Lookup a file. Store handle and attributes. 875*4a5d661aSToomas Soome * Return zero or error number. 876*4a5d661aSToomas Soome */ 877*4a5d661aSToomas Soome int 878*4a5d661aSToomas Soome nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 879*4a5d661aSToomas Soome { 880*4a5d661aSToomas Soome int len, rlen, pos; 881*4a5d661aSToomas Soome struct args { 882*4a5d661aSToomas Soome uint32_t fhsize; 883*4a5d661aSToomas Soome uint32_t fhplusname[1 + 884*4a5d661aSToomas Soome (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 885*4a5d661aSToomas Soome } *args; 886*4a5d661aSToomas Soome struct repl { 887*4a5d661aSToomas Soome uint32_t errno; 888*4a5d661aSToomas Soome uint32_t fhsize; 889*4a5d661aSToomas Soome uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 890*4a5d661aSToomas Soome 2 * (sizeof(uint32_t) + 891*4a5d661aSToomas Soome sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 892*4a5d661aSToomas Soome } *repl; 893*4a5d661aSToomas Soome struct { 894*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 895*4a5d661aSToomas Soome struct args d; 896*4a5d661aSToomas Soome } sdata; 897*4a5d661aSToomas Soome struct { 898*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 899*4a5d661aSToomas Soome struct repl d; 900*4a5d661aSToomas Soome } rdata; 901*4a5d661aSToomas Soome ssize_t cc; 902*4a5d661aSToomas Soome 903*4a5d661aSToomas Soome #ifdef NFS_DEBUG 904*4a5d661aSToomas Soome if (debug) 905*4a5d661aSToomas Soome printf("lookupfh: called\n"); 906*4a5d661aSToomas Soome #endif 907*4a5d661aSToomas Soome 908*4a5d661aSToomas Soome args = &sdata.d; 909*4a5d661aSToomas Soome repl = &rdata.d; 910*4a5d661aSToomas Soome 911*4a5d661aSToomas Soome bzero(args, sizeof(*args)); 912*4a5d661aSToomas Soome args->fhsize = htonl(d->fhsize); 913*4a5d661aSToomas Soome bcopy(d->fh, args->fhplusname, d->fhsize); 914*4a5d661aSToomas Soome len = strlen(name); 915*4a5d661aSToomas Soome if (len > FNAME_SIZE) 916*4a5d661aSToomas Soome len = FNAME_SIZE; 917*4a5d661aSToomas Soome pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 918*4a5d661aSToomas Soome args->fhplusname[pos++] = htonl(len); 919*4a5d661aSToomas Soome bcopy(name, &args->fhplusname[pos], len); 920*4a5d661aSToomas Soome len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 921*4a5d661aSToomas Soome roundup(len, sizeof(uint32_t)); 922*4a5d661aSToomas Soome 923*4a5d661aSToomas Soome rlen = sizeof(*repl); 924*4a5d661aSToomas Soome 925*4a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 926*4a5d661aSToomas Soome args, len, repl, rlen); 927*4a5d661aSToomas Soome if (cc == -1) 928*4a5d661aSToomas Soome return (errno); /* XXX - from rpc_call */ 929*4a5d661aSToomas Soome if (cc < 2 * sizeof(uint32_t)) 930*4a5d661aSToomas Soome return (EIO); 931*4a5d661aSToomas Soome if (repl->errno != 0) 932*4a5d661aSToomas Soome /* saerrno.h now matches NFS error numbers. */ 933*4a5d661aSToomas Soome return (ntohl(repl->errno)); 934*4a5d661aSToomas Soome newfd->fhsize = ntohl(repl->fhsize); 935*4a5d661aSToomas Soome bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 936*4a5d661aSToomas Soome pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 937*4a5d661aSToomas Soome if (repl->fhplusattr[pos++] == 0) 938*4a5d661aSToomas Soome return (EIO); 939*4a5d661aSToomas Soome bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 940*4a5d661aSToomas Soome return (0); 941*4a5d661aSToomas Soome } 942*4a5d661aSToomas Soome 943*4a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 944*4a5d661aSToomas Soome /* 945*4a5d661aSToomas Soome * Get the destination of a symbolic link. 946*4a5d661aSToomas Soome */ 947*4a5d661aSToomas Soome int 948*4a5d661aSToomas Soome nfs_readlink(struct nfs_iodesc *d, char *buf) 949*4a5d661aSToomas Soome { 950*4a5d661aSToomas Soome struct args { 951*4a5d661aSToomas Soome uint32_t fhsize; 952*4a5d661aSToomas Soome u_char fh[NFS_V3MAXFHSIZE]; 953*4a5d661aSToomas Soome } *args; 954*4a5d661aSToomas Soome struct repl { 955*4a5d661aSToomas Soome uint32_t errno; 956*4a5d661aSToomas Soome uint32_t ok; 957*4a5d661aSToomas Soome struct nfsv3_fattrs fa; 958*4a5d661aSToomas Soome uint32_t len; 959*4a5d661aSToomas Soome u_char path[NFS_MAXPATHLEN]; 960*4a5d661aSToomas Soome } *repl; 961*4a5d661aSToomas Soome struct { 962*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 963*4a5d661aSToomas Soome struct args d; 964*4a5d661aSToomas Soome } sdata; 965*4a5d661aSToomas Soome struct { 966*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 967*4a5d661aSToomas Soome struct repl d; 968*4a5d661aSToomas Soome } rdata; 969*4a5d661aSToomas Soome ssize_t cc; 970*4a5d661aSToomas Soome 971*4a5d661aSToomas Soome #ifdef NFS_DEBUG 972*4a5d661aSToomas Soome if (debug) 973*4a5d661aSToomas Soome printf("readlink: called\n"); 974*4a5d661aSToomas Soome #endif 975*4a5d661aSToomas Soome 976*4a5d661aSToomas Soome args = &sdata.d; 977*4a5d661aSToomas Soome repl = &rdata.d; 978*4a5d661aSToomas Soome 979*4a5d661aSToomas Soome bzero(args, sizeof(*args)); 980*4a5d661aSToomas Soome args->fhsize = htonl(d->fhsize); 981*4a5d661aSToomas Soome bcopy(d->fh, args->fh, d->fhsize); 982*4a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 983*4a5d661aSToomas Soome args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 984*4a5d661aSToomas Soome repl, sizeof(*repl)); 985*4a5d661aSToomas Soome if (cc == -1) 986*4a5d661aSToomas Soome return (errno); 987*4a5d661aSToomas Soome 988*4a5d661aSToomas Soome if (cc < 2 * sizeof(uint32_t)) 989*4a5d661aSToomas Soome return (EIO); 990*4a5d661aSToomas Soome 991*4a5d661aSToomas Soome if (repl->errno != 0) 992*4a5d661aSToomas Soome return (ntohl(repl->errno)); 993*4a5d661aSToomas Soome 994*4a5d661aSToomas Soome if (repl->ok == 0) 995*4a5d661aSToomas Soome return (EIO); 996*4a5d661aSToomas Soome 997*4a5d661aSToomas Soome repl->len = ntohl(repl->len); 998*4a5d661aSToomas Soome if (repl->len > NFS_MAXPATHLEN) 999*4a5d661aSToomas Soome return (ENAMETOOLONG); 1000*4a5d661aSToomas Soome 1001*4a5d661aSToomas Soome bcopy(repl->path, buf, repl->len); 1002*4a5d661aSToomas Soome buf[repl->len] = 0; 1003*4a5d661aSToomas Soome return (0); 1004*4a5d661aSToomas Soome } 1005*4a5d661aSToomas Soome #endif 1006*4a5d661aSToomas Soome 1007*4a5d661aSToomas Soome /* 1008*4a5d661aSToomas Soome * Read data from a file. 1009*4a5d661aSToomas Soome * Return transfer count or -1 (and set errno) 1010*4a5d661aSToomas Soome */ 1011*4a5d661aSToomas Soome ssize_t 1012*4a5d661aSToomas Soome nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 1013*4a5d661aSToomas Soome { 1014*4a5d661aSToomas Soome struct args { 1015*4a5d661aSToomas Soome uint32_t fhsize; 1016*4a5d661aSToomas Soome uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 1017*4a5d661aSToomas Soome } *args; 1018*4a5d661aSToomas Soome struct repl { 1019*4a5d661aSToomas Soome uint32_t errno; 1020*4a5d661aSToomas Soome uint32_t ok; 1021*4a5d661aSToomas Soome struct nfsv3_fattrs fa; 1022*4a5d661aSToomas Soome uint32_t count; 1023*4a5d661aSToomas Soome uint32_t eof; 1024*4a5d661aSToomas Soome uint32_t len; 1025*4a5d661aSToomas Soome u_char data[NFSREAD_SIZE]; 1026*4a5d661aSToomas Soome } *repl; 1027*4a5d661aSToomas Soome struct { 1028*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 1029*4a5d661aSToomas Soome struct args d; 1030*4a5d661aSToomas Soome } sdata; 1031*4a5d661aSToomas Soome struct { 1032*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 1033*4a5d661aSToomas Soome struct repl d; 1034*4a5d661aSToomas Soome } rdata; 1035*4a5d661aSToomas Soome size_t cc; 1036*4a5d661aSToomas Soome long x; 1037*4a5d661aSToomas Soome int hlen, rlen, pos; 1038*4a5d661aSToomas Soome 1039*4a5d661aSToomas Soome args = &sdata.d; 1040*4a5d661aSToomas Soome repl = &rdata.d; 1041*4a5d661aSToomas Soome 1042*4a5d661aSToomas Soome bzero(args, sizeof(*args)); 1043*4a5d661aSToomas Soome args->fhsize = htonl(d->fhsize); 1044*4a5d661aSToomas Soome bcopy(d->fh, args->fhoffcnt, d->fhsize); 1045*4a5d661aSToomas Soome pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1046*4a5d661aSToomas Soome args->fhoffcnt[pos++] = 0; 1047*4a5d661aSToomas Soome args->fhoffcnt[pos++] = htonl((uint32_t)off); 1048*4a5d661aSToomas Soome if (len > NFSREAD_SIZE) 1049*4a5d661aSToomas Soome len = NFSREAD_SIZE; 1050*4a5d661aSToomas Soome args->fhoffcnt[pos] = htonl((uint32_t)len); 1051*4a5d661aSToomas Soome hlen = sizeof(*repl) - NFSREAD_SIZE; 1052*4a5d661aSToomas Soome 1053*4a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 1054*4a5d661aSToomas Soome args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1055*4a5d661aSToomas Soome repl, sizeof(*repl)); 1056*4a5d661aSToomas Soome if (cc == -1) 1057*4a5d661aSToomas Soome /* errno was already set by rpc_call */ 1058*4a5d661aSToomas Soome return (-1); 1059*4a5d661aSToomas Soome if (cc < hlen) { 1060*4a5d661aSToomas Soome errno = EBADRPC; 1061*4a5d661aSToomas Soome return (-1); 1062*4a5d661aSToomas Soome } 1063*4a5d661aSToomas Soome if (repl->errno != 0) { 1064*4a5d661aSToomas Soome errno = ntohl(repl->errno); 1065*4a5d661aSToomas Soome return (-1); 1066*4a5d661aSToomas Soome } 1067*4a5d661aSToomas Soome rlen = cc - hlen; 1068*4a5d661aSToomas Soome x = ntohl(repl->count); 1069*4a5d661aSToomas Soome if (rlen < x) { 1070*4a5d661aSToomas Soome printf("nfsread: short packet, %d < %ld\n", rlen, x); 1071*4a5d661aSToomas Soome errno = EBADRPC; 1072*4a5d661aSToomas Soome return (-1); 1073*4a5d661aSToomas Soome } 1074*4a5d661aSToomas Soome bcopy(repl->data, addr, x); 1075*4a5d661aSToomas Soome return (x); 1076*4a5d661aSToomas Soome } 1077*4a5d661aSToomas Soome 1078*4a5d661aSToomas Soome /* 1079*4a5d661aSToomas Soome * Open a file. 1080*4a5d661aSToomas Soome * return zero or error number 1081*4a5d661aSToomas Soome */ 1082*4a5d661aSToomas Soome int 1083*4a5d661aSToomas Soome nfs_open(const char *upath, struct open_file *f) 1084*4a5d661aSToomas Soome { 1085*4a5d661aSToomas Soome struct iodesc *desc; 1086*4a5d661aSToomas Soome struct nfs_iodesc *currfd; 1087*4a5d661aSToomas Soome char buf[2 * NFS_V3MAXFHSIZE + 3]; 1088*4a5d661aSToomas Soome u_char *fh; 1089*4a5d661aSToomas Soome char *cp; 1090*4a5d661aSToomas Soome int i; 1091*4a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 1092*4a5d661aSToomas Soome struct nfs_iodesc *newfd; 1093*4a5d661aSToomas Soome struct nfsv3_fattrs *fa; 1094*4a5d661aSToomas Soome char *ncp; 1095*4a5d661aSToomas Soome int c; 1096*4a5d661aSToomas Soome char namebuf[NFS_MAXPATHLEN + 1]; 1097*4a5d661aSToomas Soome char linkbuf[NFS_MAXPATHLEN + 1]; 1098*4a5d661aSToomas Soome int nlinks = 0; 1099*4a5d661aSToomas Soome #endif 1100*4a5d661aSToomas Soome int error; 1101*4a5d661aSToomas Soome char *path; 1102*4a5d661aSToomas Soome 1103*4a5d661aSToomas Soome #ifdef NFS_DEBUG 1104*4a5d661aSToomas Soome if (debug) 1105*4a5d661aSToomas Soome printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 1106*4a5d661aSToomas Soome #endif 1107*4a5d661aSToomas Soome if (!rootpath[0]) { 1108*4a5d661aSToomas Soome printf("no rootpath, no nfs\n"); 1109*4a5d661aSToomas Soome return (ENXIO); 1110*4a5d661aSToomas Soome } 1111*4a5d661aSToomas Soome 1112*4a5d661aSToomas Soome /* 1113*4a5d661aSToomas Soome * This is silly - we should look at dv_type but that value is 1114*4a5d661aSToomas Soome * arch dependant and we can't use it here. 1115*4a5d661aSToomas Soome */ 1116*4a5d661aSToomas Soome #ifndef __i386__ 1117*4a5d661aSToomas Soome if (strcmp(f->f_dev->dv_name, "net") != 0) 1118*4a5d661aSToomas Soome return (EINVAL); 1119*4a5d661aSToomas Soome #else 1120*4a5d661aSToomas Soome if (strcmp(f->f_dev->dv_name, "pxe") != 0) 1121*4a5d661aSToomas Soome return (EINVAL); 1122*4a5d661aSToomas Soome #endif 1123*4a5d661aSToomas Soome 1124*4a5d661aSToomas Soome if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 1125*4a5d661aSToomas Soome return (EINVAL); 1126*4a5d661aSToomas Soome 1127*4a5d661aSToomas Soome /* Bind to a reserved port. */ 1128*4a5d661aSToomas Soome desc->myport = htons(--rpc_port); 1129*4a5d661aSToomas Soome desc->destip = rootip; 1130*4a5d661aSToomas Soome if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 1131*4a5d661aSToomas Soome nfs_root_node.fh))) 1132*4a5d661aSToomas Soome return (error); 1133*4a5d661aSToomas Soome nfs_root_node.fa.fa_type = htonl(NFDIR); 1134*4a5d661aSToomas Soome nfs_root_node.fa.fa_mode = htonl(0755); 1135*4a5d661aSToomas Soome nfs_root_node.fa.fa_nlink = htonl(2); 1136*4a5d661aSToomas Soome nfs_root_node.iodesc = desc; 1137*4a5d661aSToomas Soome 1138*4a5d661aSToomas Soome fh = &nfs_root_node.fh[0]; 1139*4a5d661aSToomas Soome buf[0] = 'X'; 1140*4a5d661aSToomas Soome cp = &buf[1]; 1141*4a5d661aSToomas Soome for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 1142*4a5d661aSToomas Soome sprintf(cp, "%02x", fh[i]); 1143*4a5d661aSToomas Soome sprintf(cp, "X"); 1144*4a5d661aSToomas Soome setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 1145*4a5d661aSToomas Soome setenv("boot.nfsroot.path", rootpath, 1); 1146*4a5d661aSToomas Soome setenv("boot.nfsroot.nfshandle", buf, 1); 1147*4a5d661aSToomas Soome sprintf(buf, "%d", nfs_root_node.fhsize); 1148*4a5d661aSToomas Soome setenv("boot.nfsroot.nfshandlelen", buf, 1); 1149*4a5d661aSToomas Soome 1150*4a5d661aSToomas Soome /* Allocate file system specific data structure */ 1151*4a5d661aSToomas Soome currfd = malloc(sizeof(*newfd)); 1152*4a5d661aSToomas Soome if (currfd == NULL) { 1153*4a5d661aSToomas Soome error = ENOMEM; 1154*4a5d661aSToomas Soome goto out; 1155*4a5d661aSToomas Soome } 1156*4a5d661aSToomas Soome #ifndef NFS_NOSYMLINK 1157*4a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1158*4a5d661aSToomas Soome newfd = 0; 1159*4a5d661aSToomas Soome 1160*4a5d661aSToomas Soome cp = path = strdup(upath); 1161*4a5d661aSToomas Soome if (path == NULL) { 1162*4a5d661aSToomas Soome error = ENOMEM; 1163*4a5d661aSToomas Soome goto out; 1164*4a5d661aSToomas Soome } 1165*4a5d661aSToomas Soome while (*cp) { 1166*4a5d661aSToomas Soome /* 1167*4a5d661aSToomas Soome * Remove extra separators 1168*4a5d661aSToomas Soome */ 1169*4a5d661aSToomas Soome while (*cp == '/') 1170*4a5d661aSToomas Soome cp++; 1171*4a5d661aSToomas Soome 1172*4a5d661aSToomas Soome if (*cp == '\0') 1173*4a5d661aSToomas Soome break; 1174*4a5d661aSToomas Soome /* 1175*4a5d661aSToomas Soome * Check that current node is a directory. 1176*4a5d661aSToomas Soome */ 1177*4a5d661aSToomas Soome if (currfd->fa.fa_type != htonl(NFDIR)) { 1178*4a5d661aSToomas Soome error = ENOTDIR; 1179*4a5d661aSToomas Soome goto out; 1180*4a5d661aSToomas Soome } 1181*4a5d661aSToomas Soome 1182*4a5d661aSToomas Soome /* allocate file system specific data structure */ 1183*4a5d661aSToomas Soome newfd = malloc(sizeof(*newfd)); 1184*4a5d661aSToomas Soome if (newfd == NULL) { 1185*4a5d661aSToomas Soome error = ENOMEM; 1186*4a5d661aSToomas Soome goto out; 1187*4a5d661aSToomas Soome } 1188*4a5d661aSToomas Soome newfd->iodesc = currfd->iodesc; 1189*4a5d661aSToomas Soome 1190*4a5d661aSToomas Soome /* 1191*4a5d661aSToomas Soome * Get next component of path name. 1192*4a5d661aSToomas Soome */ 1193*4a5d661aSToomas Soome { 1194*4a5d661aSToomas Soome int len = 0; 1195*4a5d661aSToomas Soome 1196*4a5d661aSToomas Soome ncp = cp; 1197*4a5d661aSToomas Soome while ((c = *cp) != '\0' && c != '/') { 1198*4a5d661aSToomas Soome if (++len > NFS_MAXNAMLEN) { 1199*4a5d661aSToomas Soome error = ENOENT; 1200*4a5d661aSToomas Soome goto out; 1201*4a5d661aSToomas Soome } 1202*4a5d661aSToomas Soome cp++; 1203*4a5d661aSToomas Soome } 1204*4a5d661aSToomas Soome *cp = '\0'; 1205*4a5d661aSToomas Soome } 1206*4a5d661aSToomas Soome 1207*4a5d661aSToomas Soome /* lookup a file handle */ 1208*4a5d661aSToomas Soome error = nfs_lookupfh(currfd, ncp, newfd); 1209*4a5d661aSToomas Soome *cp = c; 1210*4a5d661aSToomas Soome if (error) 1211*4a5d661aSToomas Soome goto out; 1212*4a5d661aSToomas Soome 1213*4a5d661aSToomas Soome /* 1214*4a5d661aSToomas Soome * Check for symbolic link 1215*4a5d661aSToomas Soome */ 1216*4a5d661aSToomas Soome if (newfd->fa.fa_type == htonl(NFLNK)) { 1217*4a5d661aSToomas Soome int link_len, len; 1218*4a5d661aSToomas Soome 1219*4a5d661aSToomas Soome error = nfs_readlink(newfd, linkbuf); 1220*4a5d661aSToomas Soome if (error) 1221*4a5d661aSToomas Soome goto out; 1222*4a5d661aSToomas Soome 1223*4a5d661aSToomas Soome link_len = strlen(linkbuf); 1224*4a5d661aSToomas Soome len = strlen(cp); 1225*4a5d661aSToomas Soome 1226*4a5d661aSToomas Soome if (link_len + len > MAXPATHLEN 1227*4a5d661aSToomas Soome || ++nlinks > MAXSYMLINKS) { 1228*4a5d661aSToomas Soome error = ENOENT; 1229*4a5d661aSToomas Soome goto out; 1230*4a5d661aSToomas Soome } 1231*4a5d661aSToomas Soome 1232*4a5d661aSToomas Soome bcopy(cp, &namebuf[link_len], len + 1); 1233*4a5d661aSToomas Soome bcopy(linkbuf, namebuf, link_len); 1234*4a5d661aSToomas Soome 1235*4a5d661aSToomas Soome /* 1236*4a5d661aSToomas Soome * If absolute pathname, restart at root. 1237*4a5d661aSToomas Soome * If relative pathname, restart at parent directory. 1238*4a5d661aSToomas Soome */ 1239*4a5d661aSToomas Soome cp = namebuf; 1240*4a5d661aSToomas Soome if (*cp == '/') 1241*4a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1242*4a5d661aSToomas Soome 1243*4a5d661aSToomas Soome free(newfd); 1244*4a5d661aSToomas Soome newfd = 0; 1245*4a5d661aSToomas Soome 1246*4a5d661aSToomas Soome continue; 1247*4a5d661aSToomas Soome } 1248*4a5d661aSToomas Soome 1249*4a5d661aSToomas Soome free(currfd); 1250*4a5d661aSToomas Soome currfd = newfd; 1251*4a5d661aSToomas Soome newfd = 0; 1252*4a5d661aSToomas Soome } 1253*4a5d661aSToomas Soome 1254*4a5d661aSToomas Soome error = 0; 1255*4a5d661aSToomas Soome 1256*4a5d661aSToomas Soome out: 1257*4a5d661aSToomas Soome free(newfd); 1258*4a5d661aSToomas Soome free(path); 1259*4a5d661aSToomas Soome #else 1260*4a5d661aSToomas Soome currfd->iodesc = desc; 1261*4a5d661aSToomas Soome 1262*4a5d661aSToomas Soome error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1263*4a5d661aSToomas Soome #endif 1264*4a5d661aSToomas Soome if (!error) { 1265*4a5d661aSToomas Soome currfd->off = 0; 1266*4a5d661aSToomas Soome currfd->cookie = 0; 1267*4a5d661aSToomas Soome f->f_fsdata = (void *)currfd; 1268*4a5d661aSToomas Soome return (0); 1269*4a5d661aSToomas Soome } 1270*4a5d661aSToomas Soome 1271*4a5d661aSToomas Soome #ifdef NFS_DEBUG 1272*4a5d661aSToomas Soome if (debug) 1273*4a5d661aSToomas Soome printf("nfs_open: %s lookupfh failed: %s\n", 1274*4a5d661aSToomas Soome path, strerror(error)); 1275*4a5d661aSToomas Soome #endif 1276*4a5d661aSToomas Soome free(currfd); 1277*4a5d661aSToomas Soome 1278*4a5d661aSToomas Soome return (error); 1279*4a5d661aSToomas Soome } 1280*4a5d661aSToomas Soome 1281*4a5d661aSToomas Soome int 1282*4a5d661aSToomas Soome nfs_close(struct open_file *f) 1283*4a5d661aSToomas Soome { 1284*4a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1285*4a5d661aSToomas Soome 1286*4a5d661aSToomas Soome #ifdef NFS_DEBUG 1287*4a5d661aSToomas Soome if (debug) 1288*4a5d661aSToomas Soome printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1289*4a5d661aSToomas Soome #endif 1290*4a5d661aSToomas Soome 1291*4a5d661aSToomas Soome if (fp) 1292*4a5d661aSToomas Soome free(fp); 1293*4a5d661aSToomas Soome f->f_fsdata = (void *)0; 1294*4a5d661aSToomas Soome 1295*4a5d661aSToomas Soome return (0); 1296*4a5d661aSToomas Soome } 1297*4a5d661aSToomas Soome 1298*4a5d661aSToomas Soome /* 1299*4a5d661aSToomas Soome * read a portion of a file 1300*4a5d661aSToomas Soome */ 1301*4a5d661aSToomas Soome int 1302*4a5d661aSToomas Soome nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1303*4a5d661aSToomas Soome { 1304*4a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1305*4a5d661aSToomas Soome ssize_t cc; 1306*4a5d661aSToomas Soome char *addr = buf; 1307*4a5d661aSToomas Soome 1308*4a5d661aSToomas Soome #ifdef NFS_DEBUG 1309*4a5d661aSToomas Soome if (debug) 1310*4a5d661aSToomas Soome printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1311*4a5d661aSToomas Soome (int)fp->off); 1312*4a5d661aSToomas Soome #endif 1313*4a5d661aSToomas Soome while ((int)size > 0) { 1314*4a5d661aSToomas Soome twiddle(16); 1315*4a5d661aSToomas Soome cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1316*4a5d661aSToomas Soome /* XXX maybe should retry on certain errors */ 1317*4a5d661aSToomas Soome if (cc == -1) { 1318*4a5d661aSToomas Soome #ifdef NFS_DEBUG 1319*4a5d661aSToomas Soome if (debug) 1320*4a5d661aSToomas Soome printf("nfs_read: read: %s", strerror(errno)); 1321*4a5d661aSToomas Soome #endif 1322*4a5d661aSToomas Soome return (errno); /* XXX - from nfs_readdata */ 1323*4a5d661aSToomas Soome } 1324*4a5d661aSToomas Soome if (cc == 0) { 1325*4a5d661aSToomas Soome #ifdef NFS_DEBUG 1326*4a5d661aSToomas Soome if (debug) 1327*4a5d661aSToomas Soome printf("nfs_read: hit EOF unexpectantly"); 1328*4a5d661aSToomas Soome #endif 1329*4a5d661aSToomas Soome goto ret; 1330*4a5d661aSToomas Soome } 1331*4a5d661aSToomas Soome fp->off += cc; 1332*4a5d661aSToomas Soome addr += cc; 1333*4a5d661aSToomas Soome size -= cc; 1334*4a5d661aSToomas Soome } 1335*4a5d661aSToomas Soome ret: 1336*4a5d661aSToomas Soome if (resid) 1337*4a5d661aSToomas Soome *resid = size; 1338*4a5d661aSToomas Soome 1339*4a5d661aSToomas Soome return (0); 1340*4a5d661aSToomas Soome } 1341*4a5d661aSToomas Soome 1342*4a5d661aSToomas Soome /* 1343*4a5d661aSToomas Soome * Not implemented. 1344*4a5d661aSToomas Soome */ 1345*4a5d661aSToomas Soome int 1346*4a5d661aSToomas Soome nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1347*4a5d661aSToomas Soome { 1348*4a5d661aSToomas Soome return (EROFS); 1349*4a5d661aSToomas Soome } 1350*4a5d661aSToomas Soome 1351*4a5d661aSToomas Soome off_t 1352*4a5d661aSToomas Soome nfs_seek(struct open_file *f, off_t offset, int where) 1353*4a5d661aSToomas Soome { 1354*4a5d661aSToomas Soome struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1355*4a5d661aSToomas Soome uint32_t size = ntohl(d->fa.fa_size.val[1]); 1356*4a5d661aSToomas Soome 1357*4a5d661aSToomas Soome switch (where) { 1358*4a5d661aSToomas Soome case SEEK_SET: 1359*4a5d661aSToomas Soome d->off = offset; 1360*4a5d661aSToomas Soome break; 1361*4a5d661aSToomas Soome case SEEK_CUR: 1362*4a5d661aSToomas Soome d->off += offset; 1363*4a5d661aSToomas Soome break; 1364*4a5d661aSToomas Soome case SEEK_END: 1365*4a5d661aSToomas Soome d->off = size - offset; 1366*4a5d661aSToomas Soome break; 1367*4a5d661aSToomas Soome default: 1368*4a5d661aSToomas Soome errno = EINVAL; 1369*4a5d661aSToomas Soome return (-1); 1370*4a5d661aSToomas Soome } 1371*4a5d661aSToomas Soome 1372*4a5d661aSToomas Soome return (d->off); 1373*4a5d661aSToomas Soome } 1374*4a5d661aSToomas Soome 1375*4a5d661aSToomas Soome /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1376*4a5d661aSToomas Soome int nfs_stat_types[9] = { 1377*4a5d661aSToomas Soome 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1378*4a5d661aSToomas Soome 1379*4a5d661aSToomas Soome int 1380*4a5d661aSToomas Soome nfs_stat(struct open_file *f, struct stat *sb) 1381*4a5d661aSToomas Soome { 1382*4a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1383*4a5d661aSToomas Soome uint32_t ftype, mode; 1384*4a5d661aSToomas Soome 1385*4a5d661aSToomas Soome ftype = ntohl(fp->fa.fa_type); 1386*4a5d661aSToomas Soome mode = ntohl(fp->fa.fa_mode); 1387*4a5d661aSToomas Soome mode |= nfs_stat_types[ftype & 7]; 1388*4a5d661aSToomas Soome 1389*4a5d661aSToomas Soome sb->st_mode = mode; 1390*4a5d661aSToomas Soome sb->st_nlink = ntohl(fp->fa.fa_nlink); 1391*4a5d661aSToomas Soome sb->st_uid = ntohl(fp->fa.fa_uid); 1392*4a5d661aSToomas Soome sb->st_gid = ntohl(fp->fa.fa_gid); 1393*4a5d661aSToomas Soome sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1394*4a5d661aSToomas Soome 1395*4a5d661aSToomas Soome return (0); 1396*4a5d661aSToomas Soome } 1397*4a5d661aSToomas Soome 1398*4a5d661aSToomas Soome static int 1399*4a5d661aSToomas Soome nfs_readdir(struct open_file *f, struct dirent *d) 1400*4a5d661aSToomas Soome { 1401*4a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1402*4a5d661aSToomas Soome struct nfsv3_readdir_repl *repl; 1403*4a5d661aSToomas Soome struct nfsv3_readdir_entry *rent; 1404*4a5d661aSToomas Soome static char *buf; 1405*4a5d661aSToomas Soome static struct nfs_iodesc *pfp = NULL; 1406*4a5d661aSToomas Soome static uint64_t cookie = 0; 1407*4a5d661aSToomas Soome size_t cc; 1408*4a5d661aSToomas Soome int pos; 1409*4a5d661aSToomas Soome 1410*4a5d661aSToomas Soome struct args { 1411*4a5d661aSToomas Soome uint32_t fhsize; 1412*4a5d661aSToomas Soome uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1413*4a5d661aSToomas Soome } *args; 1414*4a5d661aSToomas Soome struct { 1415*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 1416*4a5d661aSToomas Soome struct args d; 1417*4a5d661aSToomas Soome } sdata; 1418*4a5d661aSToomas Soome static struct { 1419*4a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 1420*4a5d661aSToomas Soome u_char d[NFS_READDIRSIZE]; 1421*4a5d661aSToomas Soome } rdata; 1422*4a5d661aSToomas Soome 1423*4a5d661aSToomas Soome if (fp != pfp || fp->off != cookie) { 1424*4a5d661aSToomas Soome pfp = NULL; 1425*4a5d661aSToomas Soome refill: 1426*4a5d661aSToomas Soome args = &sdata.d; 1427*4a5d661aSToomas Soome bzero(args, sizeof(*args)); 1428*4a5d661aSToomas Soome 1429*4a5d661aSToomas Soome args->fhsize = htonl(fp->fhsize); 1430*4a5d661aSToomas Soome bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1431*4a5d661aSToomas Soome pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1432*4a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->off >> 32); 1433*4a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->off); 1434*4a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 1435*4a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->cookie); 1436*4a5d661aSToomas Soome args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1437*4a5d661aSToomas Soome 1438*4a5d661aSToomas Soome cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1439*4a5d661aSToomas Soome args, 6 * sizeof(uint32_t) + 1440*4a5d661aSToomas Soome roundup(fp->fhsize, sizeof(uint32_t)), 1441*4a5d661aSToomas Soome rdata.d, sizeof(rdata.d)); 1442*4a5d661aSToomas Soome buf = rdata.d; 1443*4a5d661aSToomas Soome repl = (struct nfsv3_readdir_repl *)buf; 1444*4a5d661aSToomas Soome if (repl->errno != 0) 1445*4a5d661aSToomas Soome return (ntohl(repl->errno)); 1446*4a5d661aSToomas Soome pfp = fp; 1447*4a5d661aSToomas Soome cookie = fp->off; 1448*4a5d661aSToomas Soome fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 1449*4a5d661aSToomas Soome ntohl(repl->cookiev1); 1450*4a5d661aSToomas Soome buf += sizeof (struct nfsv3_readdir_repl); 1451*4a5d661aSToomas Soome } 1452*4a5d661aSToomas Soome rent = (struct nfsv3_readdir_entry *)buf; 1453*4a5d661aSToomas Soome 1454*4a5d661aSToomas Soome if (rent->follows == 0) { 1455*4a5d661aSToomas Soome /* fid0 is actually eof */ 1456*4a5d661aSToomas Soome if (rent->fid0 != 0) { 1457*4a5d661aSToomas Soome cookie = 0; 1458*4a5d661aSToomas Soome return (ENOENT); 1459*4a5d661aSToomas Soome } 1460*4a5d661aSToomas Soome goto refill; 1461*4a5d661aSToomas Soome } 1462*4a5d661aSToomas Soome 1463*4a5d661aSToomas Soome d->d_namlen = ntohl(rent->len); 1464*4a5d661aSToomas Soome bcopy(rent->nameplus, d->d_name, d->d_namlen); 1465*4a5d661aSToomas Soome d->d_name[d->d_namlen] = '\0'; 1466*4a5d661aSToomas Soome 1467*4a5d661aSToomas Soome pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 1468*4a5d661aSToomas Soome fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 1469*4a5d661aSToomas Soome ntohl(rent->nameplus[pos + 1]); 1470*4a5d661aSToomas Soome pos += 2; 1471*4a5d661aSToomas Soome buf = (u_char *)&rent->nameplus[pos]; 1472*4a5d661aSToomas Soome return (0); 1473*4a5d661aSToomas Soome } 1474*4a5d661aSToomas Soome #endif /* OLD_NFSV2 */ 1475