138451Smsmith/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 238451Smsmith 338451Smsmith/*- 438451Smsmith * Copyright (c) 1993 John Brezak 538451Smsmith * All rights reserved. 6197178Semaste * 738451Smsmith * Redistribution and use in source and binary forms, with or without 838451Smsmith * modification, are permitted provided that the following conditions 938451Smsmith * are met: 1038451Smsmith * 1. Redistributions of source code must retain the above copyright 1138451Smsmith * notice, this list of conditions and the following disclaimer. 1238451Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1338451Smsmith * notice, this list of conditions and the following disclaimer in the 1438451Smsmith * documentation and/or other materials provided with the distribution. 1538451Smsmith * 3. The name of the author may not be used to endorse or promote products 1638451Smsmith * derived from this software without specific prior written permission. 17197178Semaste * 1838451Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 1938451Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2038451Smsmith * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2138451Smsmith * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2238451Smsmith * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2338451Smsmith * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2438451Smsmith * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2538451Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2638451Smsmith * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 2738451Smsmith * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2838451Smsmith * POSSIBILITY OF SUCH DAMAGE. 2938451Smsmith */ 3038451Smsmith 3184221Sdillon#include <sys/cdefs.h> 3284221Sdillon__FBSDID("$FreeBSD$"); 3384221Sdillon 3438451Smsmith#include <sys/param.h> 3538451Smsmith#include <sys/time.h> 3638451Smsmith#include <sys/socket.h> 3738451Smsmith#include <sys/stat.h> 3838451Smsmith#include <string.h> 3938451Smsmith 4038451Smsmith#include <netinet/in.h> 4138451Smsmith#include <netinet/in_systm.h> 4238451Smsmith 4338451Smsmith#include "rpcv2.h" 4438451Smsmith#include "nfsv2.h" 4538451Smsmith 4638451Smsmith#include "stand.h" 4738451Smsmith#include "net.h" 4838451Smsmith#include "netif.h" 4938451Smsmith#include "rpc.h" 5038451Smsmith 5138451Smsmith#define NFS_DEBUGxx 5238451Smsmith 53212125Srmacklem#define NFSREAD_SIZE 1024 54212125Srmacklem 5538451Smsmith/* Define our own NFS attributes without NQNFS stuff. */ 56212125Srmacklem#ifdef OLD_NFSV2 5738451Smsmithstruct nfsv2_fattrs { 5838451Smsmith n_long fa_type; 5938451Smsmith n_long fa_mode; 6038451Smsmith n_long fa_nlink; 6138451Smsmith n_long fa_uid; 6238451Smsmith n_long fa_gid; 6338451Smsmith n_long fa_size; 6438451Smsmith n_long fa_blocksize; 6538451Smsmith n_long fa_rdev; 6638451Smsmith n_long fa_blocks; 6738451Smsmith n_long fa_fsid; 6838451Smsmith n_long fa_fileid; 6938451Smsmith struct nfsv2_time fa_atime; 7038451Smsmith struct nfsv2_time fa_mtime; 7138451Smsmith struct nfsv2_time fa_ctime; 7238451Smsmith}; 7338451Smsmith 7438451Smsmithstruct nfs_read_args { 7538451Smsmith u_char fh[NFS_FHSIZE]; 7638451Smsmith n_long off; 7738451Smsmith n_long len; 7838451Smsmith n_long xxx; /* XXX what's this for? */ 7938451Smsmith}; 8038451Smsmith 8138451Smsmith/* Data part of nfs rpc reply (also the largest thing we receive) */ 8238451Smsmithstruct nfs_read_repl { 8338451Smsmith n_long errno; 8438451Smsmith struct nfsv2_fattrs fa; 8538451Smsmith n_long count; 8638451Smsmith u_char data[NFSREAD_SIZE]; 8738451Smsmith}; 8838451Smsmith 8938451Smsmith#ifndef NFS_NOSYMLINK 9038451Smsmithstruct nfs_readlnk_repl { 9138451Smsmith n_long errno; 9238451Smsmith n_long len; 9338451Smsmith char path[NFS_MAXPATHLEN]; 9438451Smsmith}; 9538451Smsmith#endif 9638451Smsmith 9759853Spsstruct nfs_readdir_args { 9859853Sps u_char fh[NFS_FHSIZE]; 9959853Sps n_long cookie; 10059853Sps n_long count; 10159853Sps}; 10259853Sps 10359853Spsstruct nfs_readdir_data { 10459853Sps n_long fileid; 10559853Sps n_long len; 10659853Sps char name[0]; 10759853Sps}; 10859853Sps 10959853Spsstruct nfs_readdir_off { 11059853Sps n_long cookie; 11159853Sps n_long follows; 11259853Sps}; 11359853Sps 11438451Smsmithstruct nfs_iodesc { 11538451Smsmith struct iodesc *iodesc; 11638451Smsmith off_t off; 11738451Smsmith u_char fh[NFS_FHSIZE]; 11838451Smsmith struct nfsv2_fattrs fa; /* all in network order */ 11938451Smsmith}; 120212125Srmacklem#else /* !OLD_NFSV2 */ 12138451Smsmith 122212125Srmacklem/* NFSv3 definitions */ 123212125Srmacklem#define NFS_V3MAXFHSIZE 64 124212125Srmacklem#define NFS_VER3 3 125212125Srmacklem#define RPCMNT_VER3 3 126212125Srmacklem#define NFSPROCV3_LOOKUP 3 127212125Srmacklem#define NFSPROCV3_READLINK 5 128212125Srmacklem#define NFSPROCV3_READ 6 129212125Srmacklem#define NFSPROCV3_READDIR 16 130212125Srmacklem 131212125Srmacklemtypedef struct { 132212125Srmacklem uint32_t val[2]; 133212125Srmacklem} n_quad; 134212125Srmacklem 135212125Srmacklemstruct nfsv3_time { 136212125Srmacklem uint32_t nfs_sec; 137212125Srmacklem uint32_t nfs_nsec; 138212125Srmacklem}; 139212125Srmacklem 140212125Srmacklemstruct nfsv3_fattrs { 141212125Srmacklem uint32_t fa_type; 142212125Srmacklem uint32_t fa_mode; 143212125Srmacklem uint32_t fa_nlink; 144212125Srmacklem uint32_t fa_uid; 145212125Srmacklem uint32_t fa_gid; 146212125Srmacklem n_quad fa_size; 147212125Srmacklem n_quad fa_used; 148212125Srmacklem n_quad fa_rdev; 149212125Srmacklem n_quad fa_fsid; 150212125Srmacklem n_quad fa_fileid; 151212125Srmacklem struct nfsv3_time fa_atime; 152212125Srmacklem struct nfsv3_time fa_mtime; 153212125Srmacklem struct nfsv3_time fa_ctime; 154212125Srmacklem}; 155212125Srmacklem 15638451Smsmith/* 157212125Srmacklem * For NFSv3, the file handle is variable in size, so most fixed sized 158212125Srmacklem * structures for arguments won't work. For most cases, a structure 159212125Srmacklem * that starts with any fixed size section is followed by an array 160212125Srmacklem * that covers the maximum size required. 161212125Srmacklem */ 162212125Srmacklemstruct nfsv3_readdir_repl { 163212125Srmacklem uint32_t errno; 164212125Srmacklem uint32_t ok; 165212125Srmacklem struct nfsv3_fattrs fa; 166212125Srmacklem uint32_t cookiev0; 167212125Srmacklem uint32_t cookiev1; 168212125Srmacklem}; 169212125Srmacklem 170212125Srmacklemstruct nfsv3_readdir_entry { 171212125Srmacklem uint32_t follows; 172212125Srmacklem uint32_t fid0; 173212125Srmacklem uint32_t fid1; 174212125Srmacklem uint32_t len; 175212125Srmacklem uint32_t nameplus[0]; 176212125Srmacklem}; 177212125Srmacklem 178212125Srmacklemstruct nfs_iodesc { 179212125Srmacklem struct iodesc *iodesc; 180212125Srmacklem off_t off; 181212125Srmacklem uint32_t fhsize; 182212125Srmacklem u_char fh[NFS_V3MAXFHSIZE]; 183212125Srmacklem struct nfsv3_fattrs fa; /* all in network order */ 184252701Smav uint64_t cookie; 185212125Srmacklem}; 186212125Srmacklem#endif /* OLD_NFSV2 */ 187212125Srmacklem 188212125Srmacklem/* 18938451Smsmith * XXX interactions with tftp? See nfswrapper.c for a confusing 19038451Smsmith * issue. 19138451Smsmith */ 19239468Smsmithint nfs_open(const char *path, struct open_file *f); 19338451Smsmithstatic int nfs_close(struct open_file *f); 19438451Smsmithstatic int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 19538451Smsmithstatic int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 19638451Smsmithstatic off_t nfs_seek(struct open_file *f, off_t offset, int where); 19738451Smsmithstatic int nfs_stat(struct open_file *f, struct stat *sb); 19859853Spsstatic int nfs_readdir(struct open_file *f, struct dirent *d); 19938451Smsmith 20065496Smsmithstruct nfs_iodesc nfs_root_node; 20159824Sps 20238451Smsmithstruct fs_ops nfs_fsops = { 20359766Sjlemon "nfs", 20459766Sjlemon nfs_open, 20559766Sjlemon nfs_close, 20659766Sjlemon nfs_read, 20759766Sjlemon nfs_write, 20859766Sjlemon nfs_seek, 20959766Sjlemon nfs_stat, 21059853Sps nfs_readdir 21138451Smsmith}; 21238451Smsmith 213212125Srmacklem#ifdef OLD_NFSV2 21438451Smsmith/* 21538451Smsmith * Fetch the root file handle (call mount daemon) 21638451Smsmith * Return zero or error number. 21738451Smsmith */ 21838451Smsmithint 219197178Semastenfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) 22038451Smsmith{ 22192913Sobrien int len; 22238451Smsmith struct args { 22338451Smsmith n_long len; 22438451Smsmith char path[FNAME_SIZE]; 22538451Smsmith } *args; 22638451Smsmith struct repl { 22738451Smsmith n_long errno; 22838451Smsmith u_char fh[NFS_FHSIZE]; 22938451Smsmith } *repl; 23038451Smsmith struct { 23138451Smsmith n_long h[RPC_HEADER_WORDS]; 23238451Smsmith struct args d; 23338451Smsmith } sdata; 23438451Smsmith struct { 23538451Smsmith n_long h[RPC_HEADER_WORDS]; 23638451Smsmith struct repl d; 23738451Smsmith } rdata; 23838451Smsmith size_t cc; 239197178Semaste 24038451Smsmith#ifdef NFS_DEBUG 24138451Smsmith if (debug) 24238451Smsmith printf("nfs_getrootfh: %s\n", path); 24338451Smsmith#endif 24438451Smsmith 24538451Smsmith args = &sdata.d; 24638451Smsmith repl = &rdata.d; 24738451Smsmith 24838451Smsmith bzero(args, sizeof(*args)); 24938451Smsmith len = strlen(path); 25038451Smsmith if (len > sizeof(args->path)) 25138451Smsmith len = sizeof(args->path); 25238451Smsmith args->len = htonl(len); 25338451Smsmith bcopy(path, args->path, len); 25438451Smsmith len = 4 + roundup(len, 4); 25538451Smsmith 25638451Smsmith cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 25738451Smsmith args, len, repl, sizeof(*repl)); 25838451Smsmith if (cc == -1) { 25938451Smsmith /* errno was set by rpc_call */ 26038451Smsmith return (errno); 26138451Smsmith } 26238451Smsmith if (cc < 4) 26338451Smsmith return (EBADRPC); 26438451Smsmith if (repl->errno) 26538451Smsmith return (ntohl(repl->errno)); 26638451Smsmith bcopy(repl->fh, fhp, sizeof(repl->fh)); 26738451Smsmith return (0); 26838451Smsmith} 26938451Smsmith 27038451Smsmith/* 27138451Smsmith * Lookup a file. Store handle and attributes. 27238451Smsmith * Return zero or error number. 27338451Smsmith */ 27438451Smsmithint 275197178Semastenfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 27638451Smsmith{ 27792913Sobrien int len, rlen; 27838451Smsmith struct args { 27938451Smsmith u_char fh[NFS_FHSIZE]; 28038451Smsmith n_long len; 28138451Smsmith char name[FNAME_SIZE]; 28238451Smsmith } *args; 28338451Smsmith struct repl { 28438451Smsmith n_long errno; 28538451Smsmith u_char fh[NFS_FHSIZE]; 28638451Smsmith struct nfsv2_fattrs fa; 28738451Smsmith } *repl; 28838451Smsmith struct { 28938451Smsmith n_long h[RPC_HEADER_WORDS]; 29038451Smsmith struct args d; 29138451Smsmith } sdata; 29238451Smsmith struct { 29338451Smsmith n_long h[RPC_HEADER_WORDS]; 29438451Smsmith struct repl d; 29538451Smsmith } rdata; 29638451Smsmith ssize_t cc; 297197178Semaste 29838451Smsmith#ifdef NFS_DEBUG 29938451Smsmith if (debug) 30038451Smsmith printf("lookupfh: called\n"); 30138451Smsmith#endif 30238451Smsmith 30338451Smsmith args = &sdata.d; 30438451Smsmith repl = &rdata.d; 30538451Smsmith 30638451Smsmith bzero(args, sizeof(*args)); 30738451Smsmith bcopy(d->fh, args->fh, sizeof(args->fh)); 30838451Smsmith len = strlen(name); 30938451Smsmith if (len > sizeof(args->name)) 31038451Smsmith len = sizeof(args->name); 31138451Smsmith bcopy(name, args->name, len); 31238451Smsmith args->len = htonl(len); 31338451Smsmith len = 4 + roundup(len, 4); 31438451Smsmith len += NFS_FHSIZE; 31538451Smsmith 31638451Smsmith rlen = sizeof(*repl); 31738451Smsmith 31838451Smsmith cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 31938451Smsmith args, len, repl, rlen); 32038451Smsmith if (cc == -1) 32138451Smsmith return (errno); /* XXX - from rpc_call */ 32238451Smsmith if (cc < 4) 32338451Smsmith return (EIO); 32438451Smsmith if (repl->errno) { 32538451Smsmith /* saerrno.h now matches NFS error numbers. */ 32638451Smsmith return (ntohl(repl->errno)); 32738451Smsmith } 32838451Smsmith bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 32938451Smsmith bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 33038451Smsmith return (0); 33138451Smsmith} 33238451Smsmith 33338451Smsmith#ifndef NFS_NOSYMLINK 33438451Smsmith/* 33538451Smsmith * Get the destination of a symbolic link. 33638451Smsmith */ 33738451Smsmithint 338197178Semastenfs_readlink(struct nfs_iodesc *d, char *buf) 33938451Smsmith{ 34038451Smsmith struct { 34138451Smsmith n_long h[RPC_HEADER_WORDS]; 34238451Smsmith u_char fh[NFS_FHSIZE]; 34338451Smsmith } sdata; 34438451Smsmith struct { 34538451Smsmith n_long h[RPC_HEADER_WORDS]; 34638451Smsmith struct nfs_readlnk_repl d; 34738451Smsmith } rdata; 34838451Smsmith ssize_t cc; 34938451Smsmith 35038451Smsmith#ifdef NFS_DEBUG 35138451Smsmith if (debug) 35238451Smsmith printf("readlink: called\n"); 35338451Smsmith#endif 35438451Smsmith 35538451Smsmith bcopy(d->fh, sdata.fh, NFS_FHSIZE); 35638451Smsmith cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 35738451Smsmith sdata.fh, NFS_FHSIZE, 35838451Smsmith &rdata.d, sizeof(rdata.d)); 35938451Smsmith if (cc == -1) 36038451Smsmith return (errno); 36138451Smsmith 36238451Smsmith if (cc < 4) 36338451Smsmith return (EIO); 364197178Semaste 36538451Smsmith if (rdata.d.errno) 36638451Smsmith return (ntohl(rdata.d.errno)); 36738451Smsmith 36838451Smsmith rdata.d.len = ntohl(rdata.d.len); 36938451Smsmith if (rdata.d.len > NFS_MAXPATHLEN) 37038451Smsmith return (ENAMETOOLONG); 37138451Smsmith 37238451Smsmith bcopy(rdata.d.path, buf, rdata.d.len); 37338451Smsmith buf[rdata.d.len] = 0; 37438451Smsmith return (0); 37538451Smsmith} 37638451Smsmith#endif 37738451Smsmith 37838451Smsmith/* 37938451Smsmith * Read data from a file. 38038451Smsmith * Return transfer count or -1 (and set errno) 38138451Smsmith */ 38238451Smsmithssize_t 383197178Semastenfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 38438451Smsmith{ 38538451Smsmith struct nfs_read_args *args; 38638451Smsmith struct nfs_read_repl *repl; 38738451Smsmith struct { 38838451Smsmith n_long h[RPC_HEADER_WORDS]; 38938451Smsmith struct nfs_read_args d; 39038451Smsmith } sdata; 39138451Smsmith struct { 39238451Smsmith n_long h[RPC_HEADER_WORDS]; 39338451Smsmith struct nfs_read_repl d; 39438451Smsmith } rdata; 39538451Smsmith size_t cc; 39638451Smsmith long x; 39738451Smsmith int hlen, rlen; 39838451Smsmith 39938451Smsmith args = &sdata.d; 40038451Smsmith repl = &rdata.d; 40138451Smsmith 40238451Smsmith bcopy(d->fh, args->fh, NFS_FHSIZE); 40338451Smsmith args->off = htonl((n_long)off); 40438451Smsmith if (len > NFSREAD_SIZE) 40538451Smsmith len = NFSREAD_SIZE; 40638451Smsmith args->len = htonl((n_long)len); 40738451Smsmith args->xxx = htonl((n_long)0); 40838451Smsmith hlen = sizeof(*repl) - NFSREAD_SIZE; 40938451Smsmith 41038451Smsmith cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 41138451Smsmith args, sizeof(*args), 41238451Smsmith repl, sizeof(*repl)); 41338451Smsmith if (cc == -1) { 41438451Smsmith /* errno was already set by rpc_call */ 41538451Smsmith return (-1); 41638451Smsmith } 41738451Smsmith if (cc < hlen) { 41838451Smsmith errno = EBADRPC; 41938451Smsmith return (-1); 42038451Smsmith } 42138451Smsmith if (repl->errno) { 42238451Smsmith errno = ntohl(repl->errno); 42338451Smsmith return (-1); 42438451Smsmith } 42538451Smsmith rlen = cc - hlen; 42638451Smsmith x = ntohl(repl->count); 42738451Smsmith if (rlen < x) { 42838451Smsmith printf("nfsread: short packet, %d < %ld\n", rlen, x); 42938451Smsmith errno = EBADRPC; 43038451Smsmith return(-1); 43138451Smsmith } 43238451Smsmith bcopy(repl->data, addr, x); 43338451Smsmith return (x); 43438451Smsmith} 43538451Smsmith 43638451Smsmith/* 43738451Smsmith * Open a file. 43838451Smsmith * return zero or error number 43938451Smsmith */ 44038451Smsmithint 441197178Semastenfs_open(const char *upath, struct open_file *f) 44238451Smsmith{ 44338451Smsmith struct iodesc *desc; 44438451Smsmith struct nfs_iodesc *currfd; 445101112Sjake char buf[2 * NFS_FHSIZE + 3]; 446101112Sjake u_char *fh; 447101112Sjake char *cp; 448101112Sjake int i; 44938451Smsmith#ifndef NFS_NOSYMLINK 45038451Smsmith struct nfs_iodesc *newfd; 45138451Smsmith struct nfsv2_fattrs *fa; 452101112Sjake char *ncp; 45392913Sobrien int c; 45438451Smsmith char namebuf[NFS_MAXPATHLEN + 1]; 45538451Smsmith char linkbuf[NFS_MAXPATHLEN + 1]; 45638451Smsmith int nlinks = 0; 45738451Smsmith#endif 45838451Smsmith int error; 45939468Smsmith char *path; 46038451Smsmith 46138451Smsmith#ifdef NFS_DEBUG 46238451Smsmith if (debug) 463185155Sluigi printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 46438451Smsmith#endif 46538451Smsmith if (!rootpath[0]) { 46638451Smsmith printf("no rootpath, no nfs\n"); 46738451Smsmith return (ENXIO); 46838451Smsmith } 46938451Smsmith 470177935Sdfr /* 471177935Sdfr * This is silly - we should look at dv_type but that value is 472177935Sdfr * arch dependant and we can't use it here. 473177935Sdfr */ 474111776Smarcel#ifndef __i386__ 47599558Sjake if (strcmp(f->f_dev->dv_name, "net") != 0) 47699558Sjake return(EINVAL); 477177935Sdfr#else 478177935Sdfr if (strcmp(f->f_dev->dv_name, "pxe") != 0) 479177935Sdfr return(EINVAL); 48099558Sjake#endif 481111776Smarcel 48238451Smsmith if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 48338451Smsmith return(EINVAL); 48438451Smsmith 48538451Smsmith /* Bind to a reserved port. */ 48638451Smsmith desc->myport = htons(--rpc_port); 48738451Smsmith desc->destip = rootip; 48838451Smsmith if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 48938451Smsmith return (error); 490252700Smav nfs_root_node.fa.fa_type = htonl(NFDIR); 491252700Smav nfs_root_node.fa.fa_mode = htonl(0755); 492252700Smav nfs_root_node.fa.fa_nlink = htonl(2); 49338451Smsmith nfs_root_node.iodesc = desc; 49438451Smsmith 495101112Sjake fh = &nfs_root_node.fh[0]; 496101112Sjake buf[0] = 'X'; 497101112Sjake cp = &buf[1]; 498101112Sjake for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 499101112Sjake sprintf(cp, "%02x", fh[i]); 500101112Sjake sprintf(cp, "X"); 501101112Sjake setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 502101112Sjake setenv("boot.nfsroot.path", rootpath, 1); 503101112Sjake setenv("boot.nfsroot.nfshandle", buf, 1); 504101112Sjake 505252700Smav /* Allocate file system specific data structure */ 506252700Smav currfd = malloc(sizeof(*newfd)); 507252700Smav if (currfd == NULL) { 508252700Smav error = ENOMEM; 509252700Smav goto out; 510252700Smav } 511252700Smav 51238451Smsmith#ifndef NFS_NOSYMLINK 513252700Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 51438451Smsmith newfd = 0; 51538451Smsmith 51639468Smsmith cp = path = strdup(upath); 51739468Smsmith if (path == NULL) { 51839468Smsmith error = ENOMEM; 51939468Smsmith goto out; 52039468Smsmith } 52138451Smsmith while (*cp) { 52238451Smsmith /* 52338451Smsmith * Remove extra separators 52438451Smsmith */ 52538451Smsmith while (*cp == '/') 52638451Smsmith cp++; 52738451Smsmith 52838451Smsmith if (*cp == '\0') 52938451Smsmith break; 53038451Smsmith /* 53138451Smsmith * Check that current node is a directory. 53238451Smsmith */ 53338451Smsmith if (currfd->fa.fa_type != htonl(NFDIR)) { 53438451Smsmith error = ENOTDIR; 53538451Smsmith goto out; 53638451Smsmith } 537197178Semaste 53838451Smsmith /* allocate file system specific data structure */ 53938451Smsmith newfd = malloc(sizeof(*newfd)); 54038451Smsmith newfd->iodesc = currfd->iodesc; 541197178Semaste 54238451Smsmith /* 54338451Smsmith * Get next component of path name. 54438451Smsmith */ 54538451Smsmith { 54692913Sobrien int len = 0; 547197178Semaste 54838451Smsmith ncp = cp; 54938451Smsmith while ((c = *cp) != '\0' && c != '/') { 55038451Smsmith if (++len > NFS_MAXNAMLEN) { 55138451Smsmith error = ENOENT; 55238451Smsmith goto out; 55338451Smsmith } 55438451Smsmith cp++; 55538451Smsmith } 55638451Smsmith *cp = '\0'; 55738451Smsmith } 558197178Semaste 55938451Smsmith /* lookup a file handle */ 56038451Smsmith error = nfs_lookupfh(currfd, ncp, newfd); 56138451Smsmith *cp = c; 56238451Smsmith if (error) 56338451Smsmith goto out; 564197178Semaste 56538451Smsmith /* 56638451Smsmith * Check for symbolic link 56738451Smsmith */ 56838451Smsmith if (newfd->fa.fa_type == htonl(NFLNK)) { 56938451Smsmith int link_len, len; 570197178Semaste 57138451Smsmith error = nfs_readlink(newfd, linkbuf); 57238451Smsmith if (error) 57338451Smsmith goto out; 57438451Smsmith 57538451Smsmith link_len = strlen(linkbuf); 57638451Smsmith len = strlen(cp); 57738451Smsmith 57838451Smsmith if (link_len + len > MAXPATHLEN 57938451Smsmith || ++nlinks > MAXSYMLINKS) { 58038451Smsmith error = ENOENT; 58138451Smsmith goto out; 58238451Smsmith } 58338451Smsmith 58438451Smsmith bcopy(cp, &namebuf[link_len], len + 1); 58538451Smsmith bcopy(linkbuf, namebuf, link_len); 586197178Semaste 58738451Smsmith /* 58838451Smsmith * If absolute pathname, restart at root. 58938451Smsmith * If relative pathname, restart at parent directory. 59038451Smsmith */ 59138451Smsmith cp = namebuf; 592252700Smav if (*cp == '/') 593252700Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 59438451Smsmith 59538451Smsmith free(newfd); 59638451Smsmith newfd = 0; 597197178Semaste 59838451Smsmith continue; 59938451Smsmith } 600197178Semaste 601252700Smav free(currfd); 60238451Smsmith currfd = newfd; 60338451Smsmith newfd = 0; 60438451Smsmith } 60538451Smsmith 60638451Smsmith error = 0; 60738451Smsmith 60838451Smsmithout: 60938451Smsmith if (newfd) 61038451Smsmith free(newfd); 61139468Smsmith if (path) 61239468Smsmith free(path); 61338451Smsmith#else 61438451Smsmith currfd->iodesc = desc; 61538451Smsmith 61639468Smsmith error = nfs_lookupfh(&nfs_root_node, upath, currfd); 61738451Smsmith#endif 61838451Smsmith if (!error) { 619252700Smav currfd->off = 0; 62038451Smsmith f->f_fsdata = (void *)currfd; 62138451Smsmith return (0); 62238451Smsmith } 623197178Semaste 62438451Smsmith#ifdef NFS_DEBUG 62538451Smsmith if (debug) 62638451Smsmith printf("nfs_open: %s lookupfh failed: %s\n", 62738451Smsmith path, strerror(error)); 62838451Smsmith#endif 629252700Smav free(currfd); 63038451Smsmith 63138451Smsmith return (error); 63238451Smsmith} 63338451Smsmith 63438451Smsmithint 635197178Semastenfs_close(struct open_file *f) 63638451Smsmith{ 63792913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 63838451Smsmith 63938451Smsmith#ifdef NFS_DEBUG 64038451Smsmith if (debug) 64138451Smsmith printf("nfs_close: fp=0x%lx\n", (u_long)fp); 64238451Smsmith#endif 64338451Smsmith 644252700Smav if (fp) 64538451Smsmith free(fp); 64638451Smsmith f->f_fsdata = (void *)0; 647197178Semaste 64838451Smsmith return (0); 64938451Smsmith} 65038451Smsmith 65138451Smsmith/* 65238451Smsmith * read a portion of a file 65338451Smsmith */ 65438451Smsmithint 655197178Semastenfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 65638451Smsmith{ 65792913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 65892913Sobrien ssize_t cc; 65992913Sobrien char *addr = buf; 660197178Semaste 66138451Smsmith#ifdef NFS_DEBUG 66238451Smsmith if (debug) 66338451Smsmith printf("nfs_read: size=%lu off=%d\n", (u_long)size, 66438451Smsmith (int)fp->off); 66538451Smsmith#endif 66638451Smsmith while ((int)size > 0) { 66738451Smsmith twiddle(); 66838451Smsmith cc = nfs_readdata(fp, fp->off, (void *)addr, size); 66938451Smsmith /* XXX maybe should retry on certain errors */ 67038451Smsmith if (cc == -1) { 67138451Smsmith#ifdef NFS_DEBUG 67238451Smsmith if (debug) 67338451Smsmith printf("nfs_read: read: %s", strerror(errno)); 67438451Smsmith#endif 67538451Smsmith return (errno); /* XXX - from nfs_readdata */ 67638451Smsmith } 67738451Smsmith if (cc == 0) { 67838451Smsmith#ifdef NFS_DEBUG 67938451Smsmith if (debug) 68038451Smsmith printf("nfs_read: hit EOF unexpectantly"); 68138451Smsmith#endif 68238451Smsmith goto ret; 68338451Smsmith } 68438451Smsmith fp->off += cc; 68538451Smsmith addr += cc; 68638451Smsmith size -= cc; 68738451Smsmith } 68838451Smsmithret: 68938451Smsmith if (resid) 69038451Smsmith *resid = size; 69138451Smsmith 69238451Smsmith return (0); 69338451Smsmith} 69438451Smsmith 69538451Smsmith/* 69638451Smsmith * Not implemented. 69738451Smsmith */ 69838451Smsmithint 699197178Semastenfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 70038451Smsmith{ 70138451Smsmith return (EROFS); 70238451Smsmith} 70338451Smsmith 70438451Smsmithoff_t 705197178Semastenfs_seek(struct open_file *f, off_t offset, int where) 70638451Smsmith{ 70792913Sobrien struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 70838451Smsmith n_long size = ntohl(d->fa.fa_size); 70938451Smsmith 71038451Smsmith switch (where) { 71138451Smsmith case SEEK_SET: 71238451Smsmith d->off = offset; 71338451Smsmith break; 71438451Smsmith case SEEK_CUR: 71538451Smsmith d->off += offset; 71638451Smsmith break; 71738451Smsmith case SEEK_END: 71838451Smsmith d->off = size - offset; 71938451Smsmith break; 72038451Smsmith default: 721124811Sjhb errno = EINVAL; 72238451Smsmith return (-1); 72338451Smsmith } 72438451Smsmith 72538451Smsmith return (d->off); 72638451Smsmith} 72738451Smsmith 72838451Smsmith/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 72938451Smsmithint nfs_stat_types[8] = { 73038451Smsmith 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 73138451Smsmith 73238451Smsmithint 733197178Semastenfs_stat(struct open_file *f, struct stat *sb) 73438451Smsmith{ 73538451Smsmith struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 73692913Sobrien n_long ftype, mode; 73738451Smsmith 73838451Smsmith ftype = ntohl(fp->fa.fa_type); 73938451Smsmith mode = ntohl(fp->fa.fa_mode); 74038451Smsmith mode |= nfs_stat_types[ftype & 7]; 74138451Smsmith 74238451Smsmith sb->st_mode = mode; 74338451Smsmith sb->st_nlink = ntohl(fp->fa.fa_nlink); 74438451Smsmith sb->st_uid = ntohl(fp->fa.fa_uid); 74538451Smsmith sb->st_gid = ntohl(fp->fa.fa_gid); 74638451Smsmith sb->st_size = ntohl(fp->fa.fa_size); 74738451Smsmith 74838451Smsmith return (0); 74938451Smsmith} 75059853Sps 75159853Spsstatic int 75259853Spsnfs_readdir(struct open_file *f, struct dirent *d) 75359853Sps{ 75492913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 75559853Sps struct nfs_readdir_args *args; 75659853Sps struct nfs_readdir_data *rd; 75759853Sps struct nfs_readdir_off *roff = NULL; 75859853Sps static char *buf; 759252701Smav static struct nfs_iodesc *pfp = NULL; 76059853Sps static n_long cookie = 0; 76159853Sps size_t cc; 76259853Sps n_long eof; 763197178Semaste 76459853Sps struct { 76559853Sps n_long h[RPC_HEADER_WORDS]; 76659853Sps struct nfs_readdir_args d; 76759853Sps } sdata; 76859853Sps static struct { 76959853Sps n_long h[RPC_HEADER_WORDS]; 77059853Sps u_char d[NFS_READDIRSIZE]; 77159853Sps } rdata; 77259853Sps 773252701Smav if (fp != pfp || fp->off != cookie) { 774252701Smav pfp = NULL; 77559853Sps refill: 77659853Sps args = &sdata.d; 77759853Sps bzero(args, sizeof(*args)); 77859853Sps 77959853Sps bcopy(fp->fh, args->fh, NFS_FHSIZE); 780252701Smav args->cookie = htonl(fp->off); 78159853Sps args->count = htonl(NFS_READDIRSIZE); 782197178Semaste 78359853Sps cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 78459853Sps args, sizeof(*args), 78559853Sps rdata.d, sizeof(rdata.d)); 78659853Sps buf = rdata.d; 78759853Sps roff = (struct nfs_readdir_off *)buf; 78859853Sps if (ntohl(roff->cookie) != 0) 789124811Sjhb return EIO; 790252701Smav pfp = fp; 791252701Smav cookie = fp->off; 79259853Sps } 79359853Sps roff = (struct nfs_readdir_off *)buf; 79459853Sps 79559853Sps if (ntohl(roff->follows) == 0) { 79659853Sps eof = ntohl((roff+1)->cookie); 79759853Sps if (eof) { 79859853Sps cookie = 0; 799124811Sjhb return ENOENT; 80059853Sps } 80159853Sps goto refill; 80259853Sps } 80359853Sps 80459853Sps buf += sizeof(struct nfs_readdir_off); 80559853Sps rd = (struct nfs_readdir_data *)buf; 80659853Sps d->d_namlen = ntohl(rd->len); 80759853Sps bcopy(rd->name, d->d_name, d->d_namlen); 80859853Sps d->d_name[d->d_namlen] = '\0'; 80959853Sps 81059853Sps buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 81159853Sps roff = (struct nfs_readdir_off *)buf; 812252701Smav fp->off = cookie = ntohl(roff->cookie); 81359853Sps return 0; 81459853Sps} 815212125Srmacklem#else /* !OLD_NFSV2 */ 816212125Srmacklem/* 817212125Srmacklem * Fetch the root file handle (call mount daemon) 818212125Srmacklem * Return zero or error number. 819212125Srmacklem */ 820212125Srmacklemint 821212125Srmacklemnfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 822212125Srmacklem{ 823212125Srmacklem int len; 824212125Srmacklem struct args { 825212125Srmacklem uint32_t len; 826212125Srmacklem char path[FNAME_SIZE]; 827212125Srmacklem } *args; 828212125Srmacklem struct repl { 829212125Srmacklem uint32_t errno; 830212125Srmacklem uint32_t fhsize; 831212125Srmacklem u_char fh[NFS_V3MAXFHSIZE]; 832212125Srmacklem uint32_t authcnt; 833212125Srmacklem uint32_t auth[7]; 834212125Srmacklem } *repl; 835212125Srmacklem struct { 836212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 837212125Srmacklem struct args d; 838212125Srmacklem } sdata; 839212125Srmacklem struct { 840212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 841212125Srmacklem struct repl d; 842212125Srmacklem } rdata; 843212125Srmacklem size_t cc; 844212125Srmacklem 845212125Srmacklem#ifdef NFS_DEBUG 846212125Srmacklem if (debug) 847212125Srmacklem printf("nfs_getrootfh: %s\n", path); 848212125Srmacklem#endif 849212125Srmacklem 850212125Srmacklem args = &sdata.d; 851212125Srmacklem repl = &rdata.d; 852212125Srmacklem 853212125Srmacklem bzero(args, sizeof(*args)); 854212125Srmacklem len = strlen(path); 855212125Srmacklem if (len > sizeof(args->path)) 856212125Srmacklem len = sizeof(args->path); 857212125Srmacklem args->len = htonl(len); 858212125Srmacklem bcopy(path, args->path, len); 859212125Srmacklem len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 860212125Srmacklem 861212125Srmacklem cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 862212125Srmacklem args, len, repl, sizeof(*repl)); 863212125Srmacklem if (cc == -1) 864212125Srmacklem /* errno was set by rpc_call */ 865212125Srmacklem return (errno); 866212125Srmacklem if (cc < 2 * sizeof (uint32_t)) 867212125Srmacklem return (EBADRPC); 868212125Srmacklem if (repl->errno != 0) 869212125Srmacklem return (ntohl(repl->errno)); 870212125Srmacklem *fhlenp = ntohl(repl->fhsize); 871212125Srmacklem bcopy(repl->fh, fhp, *fhlenp); 872212125Srmacklem return (0); 873212125Srmacklem} 874212125Srmacklem 875212125Srmacklem/* 876212125Srmacklem * Lookup a file. Store handle and attributes. 877212125Srmacklem * Return zero or error number. 878212125Srmacklem */ 879212125Srmacklemint 880212125Srmacklemnfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 881212125Srmacklem{ 882212125Srmacklem int len, rlen, pos; 883212125Srmacklem struct args { 884212125Srmacklem uint32_t fhsize; 885212125Srmacklem uint32_t fhplusname[1 + 886212125Srmacklem (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 887212125Srmacklem } *args; 888212125Srmacklem struct repl { 889212125Srmacklem uint32_t errno; 890212125Srmacklem uint32_t fhsize; 891212125Srmacklem uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 892212125Srmacklem 2 * (sizeof(uint32_t) + 893212125Srmacklem sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 894212125Srmacklem } *repl; 895212125Srmacklem struct { 896212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 897212125Srmacklem struct args d; 898212125Srmacklem } sdata; 899212125Srmacklem struct { 900212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 901212125Srmacklem struct repl d; 902212125Srmacklem } rdata; 903212125Srmacklem ssize_t cc; 904212125Srmacklem 905212125Srmacklem#ifdef NFS_DEBUG 906212125Srmacklem if (debug) 907212125Srmacklem printf("lookupfh: called\n"); 908212125Srmacklem#endif 909212125Srmacklem 910212125Srmacklem args = &sdata.d; 911212125Srmacklem repl = &rdata.d; 912212125Srmacklem 913212125Srmacklem bzero(args, sizeof(*args)); 914212125Srmacklem args->fhsize = htonl(d->fhsize); 915212125Srmacklem bcopy(d->fh, args->fhplusname, d->fhsize); 916212125Srmacklem len = strlen(name); 917212125Srmacklem if (len > FNAME_SIZE) 918212125Srmacklem len = FNAME_SIZE; 919212125Srmacklem pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 920212125Srmacklem args->fhplusname[pos++] = htonl(len); 921212125Srmacklem bcopy(name, &args->fhplusname[pos], len); 922212125Srmacklem len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 923212125Srmacklem roundup(len, sizeof(uint32_t)); 924212125Srmacklem 925212125Srmacklem rlen = sizeof(*repl); 926212125Srmacklem 927212125Srmacklem cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 928212125Srmacklem args, len, repl, rlen); 929212125Srmacklem if (cc == -1) 930212125Srmacklem return (errno); /* XXX - from rpc_call */ 931212125Srmacklem if (cc < 2 * sizeof(uint32_t)) 932212125Srmacklem return (EIO); 933212125Srmacklem if (repl->errno != 0) 934212125Srmacklem /* saerrno.h now matches NFS error numbers. */ 935212125Srmacklem return (ntohl(repl->errno)); 936212125Srmacklem newfd->fhsize = ntohl(repl->fhsize); 937212125Srmacklem bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 938212125Srmacklem pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 939212125Srmacklem if (repl->fhplusattr[pos++] == 0) 940212125Srmacklem return (EIO); 941212125Srmacklem bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 942212125Srmacklem return (0); 943212125Srmacklem} 944212125Srmacklem 945212125Srmacklem#ifndef NFS_NOSYMLINK 946212125Srmacklem/* 947212125Srmacklem * Get the destination of a symbolic link. 948212125Srmacklem */ 949212125Srmacklemint 950212125Srmacklemnfs_readlink(struct nfs_iodesc *d, char *buf) 951212125Srmacklem{ 952212125Srmacklem struct args { 953212125Srmacklem uint32_t fhsize; 954212125Srmacklem u_char fh[NFS_V3MAXFHSIZE]; 955212125Srmacklem } *args; 956212125Srmacklem struct repl { 957212125Srmacklem uint32_t errno; 958212125Srmacklem uint32_t ok; 959212125Srmacklem struct nfsv3_fattrs fa; 960212125Srmacklem uint32_t len; 961212125Srmacklem u_char path[NFS_MAXPATHLEN]; 962212125Srmacklem } *repl; 963212125Srmacklem struct { 964212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 965212125Srmacklem struct args d; 966212125Srmacklem } sdata; 967212125Srmacklem struct { 968212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 969212125Srmacklem struct repl d; 970212125Srmacklem } rdata; 971212125Srmacklem ssize_t cc; 972212125Srmacklem 973212125Srmacklem#ifdef NFS_DEBUG 974212125Srmacklem if (debug) 975212125Srmacklem printf("readlink: called\n"); 976212125Srmacklem#endif 977212125Srmacklem 978212125Srmacklem args = &sdata.d; 979212125Srmacklem repl = &rdata.d; 980212125Srmacklem 981212125Srmacklem bzero(args, sizeof(*args)); 982212125Srmacklem args->fhsize = htonl(d->fhsize); 983212125Srmacklem bcopy(d->fh, args->fh, d->fhsize); 984212125Srmacklem cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 985212125Srmacklem args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 986212125Srmacklem repl, sizeof(*repl)); 987212125Srmacklem if (cc == -1) 988212125Srmacklem return (errno); 989212125Srmacklem 990212125Srmacklem if (cc < 2 * sizeof(uint32_t)) 991212125Srmacklem return (EIO); 992212125Srmacklem 993212125Srmacklem if (repl->errno != 0) 994212125Srmacklem return (ntohl(repl->errno)); 995212125Srmacklem 996212125Srmacklem if (repl->ok == 0) 997212125Srmacklem return (EIO); 998212125Srmacklem 999212125Srmacklem repl->len = ntohl(repl->len); 1000212125Srmacklem if (repl->len > NFS_MAXPATHLEN) 1001212125Srmacklem return (ENAMETOOLONG); 1002212125Srmacklem 1003212125Srmacklem bcopy(repl->path, buf, repl->len); 1004212125Srmacklem buf[repl->len] = 0; 1005212125Srmacklem return (0); 1006212125Srmacklem} 1007212125Srmacklem#endif 1008212125Srmacklem 1009212125Srmacklem/* 1010212125Srmacklem * Read data from a file. 1011212125Srmacklem * Return transfer count or -1 (and set errno) 1012212125Srmacklem */ 1013212125Srmacklemssize_t 1014212125Srmacklemnfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 1015212125Srmacklem{ 1016212125Srmacklem struct args { 1017212125Srmacklem uint32_t fhsize; 1018212125Srmacklem uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 1019212125Srmacklem } *args; 1020212125Srmacklem struct repl { 1021212125Srmacklem uint32_t errno; 1022212125Srmacklem uint32_t ok; 1023212125Srmacklem struct nfsv3_fattrs fa; 1024212125Srmacklem uint32_t count; 1025212125Srmacklem uint32_t eof; 1026212125Srmacklem uint32_t len; 1027212125Srmacklem u_char data[NFSREAD_SIZE]; 1028212125Srmacklem } *repl; 1029212125Srmacklem struct { 1030212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1031212125Srmacklem struct args d; 1032212125Srmacklem } sdata; 1033212125Srmacklem struct { 1034212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1035212125Srmacklem struct repl d; 1036212125Srmacklem } rdata; 1037212125Srmacklem size_t cc; 1038212125Srmacklem long x; 1039212125Srmacklem int hlen, rlen, pos; 1040212125Srmacklem 1041212125Srmacklem args = &sdata.d; 1042212125Srmacklem repl = &rdata.d; 1043212125Srmacklem 1044212125Srmacklem bzero(args, sizeof(*args)); 1045212125Srmacklem args->fhsize = htonl(d->fhsize); 1046212125Srmacklem bcopy(d->fh, args->fhoffcnt, d->fhsize); 1047212125Srmacklem pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1048212125Srmacklem args->fhoffcnt[pos++] = 0; 1049212125Srmacklem args->fhoffcnt[pos++] = htonl((uint32_t)off); 1050212125Srmacklem if (len > NFSREAD_SIZE) 1051212125Srmacklem len = NFSREAD_SIZE; 1052212125Srmacklem args->fhoffcnt[pos] = htonl((uint32_t)len); 1053212125Srmacklem hlen = sizeof(*repl) - NFSREAD_SIZE; 1054212125Srmacklem 1055212125Srmacklem cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 1056212125Srmacklem args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1057212125Srmacklem repl, sizeof(*repl)); 1058212125Srmacklem if (cc == -1) 1059212125Srmacklem /* errno was already set by rpc_call */ 1060212125Srmacklem return (-1); 1061212125Srmacklem if (cc < hlen) { 1062212125Srmacklem errno = EBADRPC; 1063212125Srmacklem return (-1); 1064212125Srmacklem } 1065212125Srmacklem if (repl->errno != 0) { 1066212125Srmacklem errno = ntohl(repl->errno); 1067212125Srmacklem return (-1); 1068212125Srmacklem } 1069212125Srmacklem rlen = cc - hlen; 1070212125Srmacklem x = ntohl(repl->count); 1071212125Srmacklem if (rlen < x) { 1072212125Srmacklem printf("nfsread: short packet, %d < %ld\n", rlen, x); 1073212125Srmacklem errno = EBADRPC; 1074212125Srmacklem return (-1); 1075212125Srmacklem } 1076212125Srmacklem bcopy(repl->data, addr, x); 1077212125Srmacklem return (x); 1078212125Srmacklem} 1079212125Srmacklem 1080212125Srmacklem/* 1081212125Srmacklem * Open a file. 1082212125Srmacklem * return zero or error number 1083212125Srmacklem */ 1084212125Srmacklemint 1085212125Srmacklemnfs_open(const char *upath, struct open_file *f) 1086212125Srmacklem{ 1087212125Srmacklem struct iodesc *desc; 1088212125Srmacklem struct nfs_iodesc *currfd; 1089212125Srmacklem char buf[2 * NFS_V3MAXFHSIZE + 3]; 1090212125Srmacklem u_char *fh; 1091212125Srmacklem char *cp; 1092212125Srmacklem int i; 1093212125Srmacklem#ifndef NFS_NOSYMLINK 1094212125Srmacklem struct nfs_iodesc *newfd; 1095212125Srmacklem struct nfsv3_fattrs *fa; 1096212125Srmacklem char *ncp; 1097212125Srmacklem int c; 1098212125Srmacklem char namebuf[NFS_MAXPATHLEN + 1]; 1099212125Srmacklem char linkbuf[NFS_MAXPATHLEN + 1]; 1100212125Srmacklem int nlinks = 0; 1101212125Srmacklem#endif 1102212125Srmacklem int error; 1103212125Srmacklem char *path; 1104212125Srmacklem 1105212125Srmacklem#ifdef NFS_DEBUG 1106212125Srmacklem if (debug) 1107212125Srmacklem printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 1108212125Srmacklem#endif 1109212125Srmacklem if (!rootpath[0]) { 1110212125Srmacklem printf("no rootpath, no nfs\n"); 1111212125Srmacklem return (ENXIO); 1112212125Srmacklem } 1113212125Srmacklem 1114212125Srmacklem /* 1115212125Srmacklem * This is silly - we should look at dv_type but that value is 1116212125Srmacklem * arch dependant and we can't use it here. 1117212125Srmacklem */ 1118212125Srmacklem#ifndef __i386__ 1119212125Srmacklem if (strcmp(f->f_dev->dv_name, "net") != 0) 1120212125Srmacklem return (EINVAL); 1121212125Srmacklem#else 1122212125Srmacklem if (strcmp(f->f_dev->dv_name, "pxe") != 0) 1123212125Srmacklem return (EINVAL); 1124212125Srmacklem#endif 1125212125Srmacklem 1126212125Srmacklem if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 1127212125Srmacklem return (EINVAL); 1128212125Srmacklem 1129212125Srmacklem /* Bind to a reserved port. */ 1130212125Srmacklem desc->myport = htons(--rpc_port); 1131212125Srmacklem desc->destip = rootip; 1132212125Srmacklem if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 1133212125Srmacklem nfs_root_node.fh))) 1134212125Srmacklem return (error); 1135252700Smav nfs_root_node.fa.fa_type = htonl(NFDIR); 1136252700Smav nfs_root_node.fa.fa_mode = htonl(0755); 1137252700Smav nfs_root_node.fa.fa_nlink = htonl(2); 1138212125Srmacklem nfs_root_node.iodesc = desc; 1139212125Srmacklem 1140212125Srmacklem fh = &nfs_root_node.fh[0]; 1141212125Srmacklem buf[0] = 'X'; 1142212125Srmacklem cp = &buf[1]; 1143212125Srmacklem for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 1144212125Srmacklem sprintf(cp, "%02x", fh[i]); 1145212125Srmacklem sprintf(cp, "X"); 1146212125Srmacklem setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 1147212125Srmacklem setenv("boot.nfsroot.path", rootpath, 1); 1148212125Srmacklem setenv("boot.nfsroot.nfshandle", buf, 1); 1149212125Srmacklem sprintf(buf, "%d", nfs_root_node.fhsize); 1150212125Srmacklem setenv("boot.nfsroot.nfshandlelen", buf, 1); 1151212125Srmacklem 1152252700Smav /* Allocate file system specific data structure */ 1153252700Smav currfd = malloc(sizeof(*newfd)); 1154252700Smav if (currfd == NULL) { 1155252700Smav error = ENOMEM; 1156252700Smav goto out; 1157252700Smav } 1158212125Srmacklem#ifndef NFS_NOSYMLINK 1159252700Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1160212125Srmacklem newfd = 0; 1161212125Srmacklem 1162212125Srmacklem cp = path = strdup(upath); 1163212125Srmacklem if (path == NULL) { 1164212125Srmacklem error = ENOMEM; 1165212125Srmacklem goto out; 1166212125Srmacklem } 1167212125Srmacklem while (*cp) { 1168212125Srmacklem /* 1169212125Srmacklem * Remove extra separators 1170212125Srmacklem */ 1171212125Srmacklem while (*cp == '/') 1172212125Srmacklem cp++; 1173212125Srmacklem 1174212125Srmacklem if (*cp == '\0') 1175212125Srmacklem break; 1176212125Srmacklem /* 1177212125Srmacklem * Check that current node is a directory. 1178212125Srmacklem */ 1179212125Srmacklem if (currfd->fa.fa_type != htonl(NFDIR)) { 1180212125Srmacklem error = ENOTDIR; 1181212125Srmacklem goto out; 1182212125Srmacklem } 1183212125Srmacklem 1184212125Srmacklem /* allocate file system specific data structure */ 1185212125Srmacklem newfd = malloc(sizeof(*newfd)); 1186212125Srmacklem if (newfd == NULL) { 1187212125Srmacklem error = ENOMEM; 1188212125Srmacklem goto out; 1189212125Srmacklem } 1190212125Srmacklem newfd->iodesc = currfd->iodesc; 1191212125Srmacklem 1192212125Srmacklem /* 1193212125Srmacklem * Get next component of path name. 1194212125Srmacklem */ 1195212125Srmacklem { 1196212125Srmacklem int len = 0; 1197212125Srmacklem 1198212125Srmacklem ncp = cp; 1199212125Srmacklem while ((c = *cp) != '\0' && c != '/') { 1200212125Srmacklem if (++len > NFS_MAXNAMLEN) { 1201212125Srmacklem error = ENOENT; 1202212125Srmacklem goto out; 1203212125Srmacklem } 1204212125Srmacklem cp++; 1205212125Srmacklem } 1206212125Srmacklem *cp = '\0'; 1207212125Srmacklem } 1208212125Srmacklem 1209212125Srmacklem /* lookup a file handle */ 1210212125Srmacklem error = nfs_lookupfh(currfd, ncp, newfd); 1211212125Srmacklem *cp = c; 1212212125Srmacklem if (error) 1213212125Srmacklem goto out; 1214212125Srmacklem 1215212125Srmacklem /* 1216212125Srmacklem * Check for symbolic link 1217212125Srmacklem */ 1218212125Srmacklem if (newfd->fa.fa_type == htonl(NFLNK)) { 1219212125Srmacklem int link_len, len; 1220212125Srmacklem 1221212125Srmacklem error = nfs_readlink(newfd, linkbuf); 1222212125Srmacklem if (error) 1223212125Srmacklem goto out; 1224212125Srmacklem 1225212125Srmacklem link_len = strlen(linkbuf); 1226212125Srmacklem len = strlen(cp); 1227212125Srmacklem 1228212125Srmacklem if (link_len + len > MAXPATHLEN 1229212125Srmacklem || ++nlinks > MAXSYMLINKS) { 1230212125Srmacklem error = ENOENT; 1231212125Srmacklem goto out; 1232212125Srmacklem } 1233212125Srmacklem 1234212125Srmacklem bcopy(cp, &namebuf[link_len], len + 1); 1235212125Srmacklem bcopy(linkbuf, namebuf, link_len); 1236212125Srmacklem 1237212125Srmacklem /* 1238212125Srmacklem * If absolute pathname, restart at root. 1239212125Srmacklem * If relative pathname, restart at parent directory. 1240212125Srmacklem */ 1241212125Srmacklem cp = namebuf; 1242252700Smav if (*cp == '/') 1243252700Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1244212125Srmacklem 1245212125Srmacklem free(newfd); 1246212125Srmacklem newfd = 0; 1247212125Srmacklem 1248212125Srmacklem continue; 1249212125Srmacklem } 1250212125Srmacklem 1251252700Smav free(currfd); 1252212125Srmacklem currfd = newfd; 1253212125Srmacklem newfd = 0; 1254212125Srmacklem } 1255212125Srmacklem 1256212125Srmacklem error = 0; 1257212125Srmacklem 1258212125Srmacklemout: 1259212125Srmacklem free(newfd); 1260212125Srmacklem free(path); 1261212125Srmacklem#else 1262252700Smav currfd->iodesc = desc; 1263212125Srmacklem 1264252700Smav error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1265212125Srmacklem#endif 1266212125Srmacklem if (!error) { 1267252700Smav currfd->off = 0; 1268252701Smav currfd->cookie = 0; 1269212125Srmacklem f->f_fsdata = (void *)currfd; 1270212125Srmacklem return (0); 1271212125Srmacklem } 1272212125Srmacklem 1273212125Srmacklem#ifdef NFS_DEBUG 1274212125Srmacklem if (debug) 1275212125Srmacklem printf("nfs_open: %s lookupfh failed: %s\n", 1276212125Srmacklem path, strerror(error)); 1277212125Srmacklem#endif 1278252700Smav free(currfd); 1279212125Srmacklem 1280212125Srmacklem return (error); 1281212125Srmacklem} 1282212125Srmacklem 1283212125Srmacklemint 1284212125Srmacklemnfs_close(struct open_file *f) 1285212125Srmacklem{ 1286212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1287212125Srmacklem 1288212125Srmacklem#ifdef NFS_DEBUG 1289212125Srmacklem if (debug) 1290212125Srmacklem printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1291212125Srmacklem#endif 1292212125Srmacklem 1293252700Smav if (fp) 1294212125Srmacklem free(fp); 1295212125Srmacklem f->f_fsdata = (void *)0; 1296212125Srmacklem 1297212125Srmacklem return (0); 1298212125Srmacklem} 1299212125Srmacklem 1300212125Srmacklem/* 1301212125Srmacklem * read a portion of a file 1302212125Srmacklem */ 1303212125Srmacklemint 1304212125Srmacklemnfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1305212125Srmacklem{ 1306212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1307212125Srmacklem ssize_t cc; 1308212125Srmacklem char *addr = buf; 1309212125Srmacklem 1310212125Srmacklem#ifdef NFS_DEBUG 1311212125Srmacklem if (debug) 1312212125Srmacklem printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1313212125Srmacklem (int)fp->off); 1314212125Srmacklem#endif 1315212125Srmacklem while ((int)size > 0) { 1316212125Srmacklem twiddle(); 1317212125Srmacklem cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1318212125Srmacklem /* XXX maybe should retry on certain errors */ 1319212125Srmacklem if (cc == -1) { 1320212125Srmacklem#ifdef NFS_DEBUG 1321212125Srmacklem if (debug) 1322212125Srmacklem printf("nfs_read: read: %s", strerror(errno)); 1323212125Srmacklem#endif 1324212125Srmacklem return (errno); /* XXX - from nfs_readdata */ 1325212125Srmacklem } 1326212125Srmacklem if (cc == 0) { 1327212125Srmacklem#ifdef NFS_DEBUG 1328212125Srmacklem if (debug) 1329212125Srmacklem printf("nfs_read: hit EOF unexpectantly"); 1330212125Srmacklem#endif 1331212125Srmacklem goto ret; 1332212125Srmacklem } 1333212125Srmacklem fp->off += cc; 1334212125Srmacklem addr += cc; 1335212125Srmacklem size -= cc; 1336212125Srmacklem } 1337212125Srmacklemret: 1338212125Srmacklem if (resid) 1339212125Srmacklem *resid = size; 1340212125Srmacklem 1341212125Srmacklem return (0); 1342212125Srmacklem} 1343212125Srmacklem 1344212125Srmacklem/* 1345212125Srmacklem * Not implemented. 1346212125Srmacklem */ 1347212125Srmacklemint 1348212125Srmacklemnfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1349212125Srmacklem{ 1350212125Srmacklem return (EROFS); 1351212125Srmacklem} 1352212125Srmacklem 1353212125Srmacklemoff_t 1354212125Srmacklemnfs_seek(struct open_file *f, off_t offset, int where) 1355212125Srmacklem{ 1356212125Srmacklem struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1357212125Srmacklem uint32_t size = ntohl(d->fa.fa_size.val[1]); 1358212125Srmacklem 1359212125Srmacklem switch (where) { 1360212125Srmacklem case SEEK_SET: 1361212125Srmacklem d->off = offset; 1362212125Srmacklem break; 1363212125Srmacklem case SEEK_CUR: 1364212125Srmacklem d->off += offset; 1365212125Srmacklem break; 1366212125Srmacklem case SEEK_END: 1367212125Srmacklem d->off = size - offset; 1368212125Srmacklem break; 1369212125Srmacklem default: 1370212125Srmacklem errno = EINVAL; 1371212125Srmacklem return (-1); 1372212125Srmacklem } 1373212125Srmacklem 1374212125Srmacklem return (d->off); 1375212125Srmacklem} 1376212125Srmacklem 1377212125Srmacklem/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1378212125Srmacklemint nfs_stat_types[9] = { 1379212125Srmacklem 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1380212125Srmacklem 1381212125Srmacklemint 1382212125Srmacklemnfs_stat(struct open_file *f, struct stat *sb) 1383212125Srmacklem{ 1384212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1385212125Srmacklem uint32_t ftype, mode; 1386212125Srmacklem 1387212125Srmacklem ftype = ntohl(fp->fa.fa_type); 1388212125Srmacklem mode = ntohl(fp->fa.fa_mode); 1389212125Srmacklem mode |= nfs_stat_types[ftype & 7]; 1390212125Srmacklem 1391212125Srmacklem sb->st_mode = mode; 1392212125Srmacklem sb->st_nlink = ntohl(fp->fa.fa_nlink); 1393212125Srmacklem sb->st_uid = ntohl(fp->fa.fa_uid); 1394212125Srmacklem sb->st_gid = ntohl(fp->fa.fa_gid); 1395212125Srmacklem sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1396212125Srmacklem 1397212125Srmacklem return (0); 1398212125Srmacklem} 1399212125Srmacklem 1400212125Srmacklemstatic int 1401212125Srmacklemnfs_readdir(struct open_file *f, struct dirent *d) 1402212125Srmacklem{ 1403212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1404212125Srmacklem struct nfsv3_readdir_repl *repl; 1405212125Srmacklem struct nfsv3_readdir_entry *rent; 1406212125Srmacklem static char *buf; 1407252701Smav static struct nfs_iodesc *pfp = NULL; 1408252701Smav static uint64_t cookie = 0; 1409212125Srmacklem size_t cc; 1410212125Srmacklem int pos; 1411212125Srmacklem 1412212125Srmacklem struct args { 1413212125Srmacklem uint32_t fhsize; 1414212125Srmacklem uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1415212125Srmacklem } *args; 1416212125Srmacklem struct { 1417212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1418212125Srmacklem struct args d; 1419212125Srmacklem } sdata; 1420212125Srmacklem static struct { 1421212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1422212125Srmacklem u_char d[NFS_READDIRSIZE]; 1423212125Srmacklem } rdata; 1424212125Srmacklem 1425252701Smav if (fp != pfp || fp->off != cookie) { 1426252701Smav pfp = NULL; 1427212125Srmacklem refill: 1428212125Srmacklem args = &sdata.d; 1429212125Srmacklem bzero(args, sizeof(*args)); 1430212125Srmacklem 1431212125Srmacklem args->fhsize = htonl(fp->fhsize); 1432212125Srmacklem bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1433212125Srmacklem pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1434252701Smav args->fhpluscookie[pos++] = htonl(fp->off >> 32); 1435252701Smav args->fhpluscookie[pos++] = htonl(fp->off); 1436252701Smav args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 1437252701Smav args->fhpluscookie[pos++] = htonl(fp->cookie); 1438212125Srmacklem args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1439212125Srmacklem 1440212125Srmacklem cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1441212125Srmacklem args, 6 * sizeof(uint32_t) + 1442212125Srmacklem roundup(fp->fhsize, sizeof(uint32_t)), 1443212125Srmacklem rdata.d, sizeof(rdata.d)); 1444212125Srmacklem buf = rdata.d; 1445212125Srmacklem repl = (struct nfsv3_readdir_repl *)buf; 1446212125Srmacklem if (repl->errno != 0) 1447212125Srmacklem return (ntohl(repl->errno)); 1448252701Smav pfp = fp; 1449252701Smav cookie = fp->off; 1450252701Smav fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 1451252701Smav ntohl(repl->cookiev1); 1452212125Srmacklem buf += sizeof (struct nfsv3_readdir_repl); 1453212125Srmacklem } 1454212125Srmacklem rent = (struct nfsv3_readdir_entry *)buf; 1455212125Srmacklem 1456212125Srmacklem if (rent->follows == 0) { 1457212125Srmacklem /* fid0 is actually eof */ 1458212125Srmacklem if (rent->fid0 != 0) { 1459252701Smav cookie = 0; 1460212125Srmacklem return (ENOENT); 1461212125Srmacklem } 1462212125Srmacklem goto refill; 1463212125Srmacklem } 1464212125Srmacklem 1465212125Srmacklem d->d_namlen = ntohl(rent->len); 1466212125Srmacklem bcopy(rent->nameplus, d->d_name, d->d_namlen); 1467212125Srmacklem d->d_name[d->d_namlen] = '\0'; 1468212125Srmacklem 1469212125Srmacklem pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 1470252701Smav fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 1471252701Smav ntohl(rent->nameplus[pos + 1]); 1472252701Smav pos += 2; 1473212125Srmacklem buf = (u_char *)&rent->nameplus[pos]; 1474212125Srmacklem return (0); 1475212125Srmacklem} 1476212125Srmacklem#endif /* OLD_NFSV2 */ 1477