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 */ 184240780Smav 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); 490240774Smav nfs_root_node.fa.fa_type = htonl(NFDIR); 491240774Smav nfs_root_node.fa.fa_mode = htonl(0755); 492240774Smav 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 505240774Smav /* Allocate file system specific data structure */ 506240774Smav currfd = malloc(sizeof(*newfd)); 507240774Smav if (currfd == NULL) { 508240774Smav error = ENOMEM; 509240774Smav goto out; 510240774Smav } 511240774Smav 51238451Smsmith#ifndef NFS_NOSYMLINK 513240774Smav 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; 592240774Smav if (*cp == '/') 593240774Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 59438451Smsmith 59538451Smsmith free(newfd); 59638451Smsmith newfd = 0; 597197178Semaste 59838451Smsmith continue; 59938451Smsmith } 600197178Semaste 601240774Smav free(currfd); 60238451Smsmith currfd = newfd; 60338451Smsmith newfd = 0; 60438451Smsmith } 60538451Smsmith 60638451Smsmith error = 0; 60738451Smsmith 60838451Smsmithout: 609240881Skevlo free(newfd); 610240881Skevlo free(path); 61138451Smsmith#else 61238451Smsmith currfd->iodesc = desc; 61338451Smsmith 61439468Smsmith error = nfs_lookupfh(&nfs_root_node, upath, currfd); 61538451Smsmith#endif 61638451Smsmith if (!error) { 617240774Smav currfd->off = 0; 61838451Smsmith f->f_fsdata = (void *)currfd; 61938451Smsmith return (0); 62038451Smsmith } 621197178Semaste 62238451Smsmith#ifdef NFS_DEBUG 62338451Smsmith if (debug) 62438451Smsmith printf("nfs_open: %s lookupfh failed: %s\n", 62538451Smsmith path, strerror(error)); 62638451Smsmith#endif 627240774Smav free(currfd); 62838451Smsmith 62938451Smsmith return (error); 63038451Smsmith} 63138451Smsmith 63238451Smsmithint 633197178Semastenfs_close(struct open_file *f) 63438451Smsmith{ 63592913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 63638451Smsmith 63738451Smsmith#ifdef NFS_DEBUG 63838451Smsmith if (debug) 63938451Smsmith printf("nfs_close: fp=0x%lx\n", (u_long)fp); 64038451Smsmith#endif 64138451Smsmith 642240774Smav if (fp) 64338451Smsmith free(fp); 64438451Smsmith f->f_fsdata = (void *)0; 645197178Semaste 64638451Smsmith return (0); 64738451Smsmith} 64838451Smsmith 64938451Smsmith/* 65038451Smsmith * read a portion of a file 65138451Smsmith */ 65238451Smsmithint 653197178Semastenfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 65438451Smsmith{ 65592913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 65692913Sobrien ssize_t cc; 65792913Sobrien char *addr = buf; 658197178Semaste 65938451Smsmith#ifdef NFS_DEBUG 66038451Smsmith if (debug) 66138451Smsmith printf("nfs_read: size=%lu off=%d\n", (u_long)size, 66238451Smsmith (int)fp->off); 66338451Smsmith#endif 66438451Smsmith while ((int)size > 0) { 66538451Smsmith twiddle(); 66638451Smsmith cc = nfs_readdata(fp, fp->off, (void *)addr, size); 66738451Smsmith /* XXX maybe should retry on certain errors */ 66838451Smsmith if (cc == -1) { 66938451Smsmith#ifdef NFS_DEBUG 67038451Smsmith if (debug) 67138451Smsmith printf("nfs_read: read: %s", strerror(errno)); 67238451Smsmith#endif 67338451Smsmith return (errno); /* XXX - from nfs_readdata */ 67438451Smsmith } 67538451Smsmith if (cc == 0) { 67638451Smsmith#ifdef NFS_DEBUG 67738451Smsmith if (debug) 67838451Smsmith printf("nfs_read: hit EOF unexpectantly"); 67938451Smsmith#endif 68038451Smsmith goto ret; 68138451Smsmith } 68238451Smsmith fp->off += cc; 68338451Smsmith addr += cc; 68438451Smsmith size -= cc; 68538451Smsmith } 68638451Smsmithret: 68738451Smsmith if (resid) 68838451Smsmith *resid = size; 68938451Smsmith 69038451Smsmith return (0); 69138451Smsmith} 69238451Smsmith 69338451Smsmith/* 69438451Smsmith * Not implemented. 69538451Smsmith */ 69638451Smsmithint 697197178Semastenfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 69838451Smsmith{ 69938451Smsmith return (EROFS); 70038451Smsmith} 70138451Smsmith 70238451Smsmithoff_t 703197178Semastenfs_seek(struct open_file *f, off_t offset, int where) 70438451Smsmith{ 70592913Sobrien struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 70638451Smsmith n_long size = ntohl(d->fa.fa_size); 70738451Smsmith 70838451Smsmith switch (where) { 70938451Smsmith case SEEK_SET: 71038451Smsmith d->off = offset; 71138451Smsmith break; 71238451Smsmith case SEEK_CUR: 71338451Smsmith d->off += offset; 71438451Smsmith break; 71538451Smsmith case SEEK_END: 71638451Smsmith d->off = size - offset; 71738451Smsmith break; 71838451Smsmith default: 719124811Sjhb errno = EINVAL; 72038451Smsmith return (-1); 72138451Smsmith } 72238451Smsmith 72338451Smsmith return (d->off); 72438451Smsmith} 72538451Smsmith 72638451Smsmith/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 72738451Smsmithint nfs_stat_types[8] = { 72838451Smsmith 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 72938451Smsmith 73038451Smsmithint 731197178Semastenfs_stat(struct open_file *f, struct stat *sb) 73238451Smsmith{ 73338451Smsmith struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 73492913Sobrien n_long ftype, mode; 73538451Smsmith 73638451Smsmith ftype = ntohl(fp->fa.fa_type); 73738451Smsmith mode = ntohl(fp->fa.fa_mode); 73838451Smsmith mode |= nfs_stat_types[ftype & 7]; 73938451Smsmith 74038451Smsmith sb->st_mode = mode; 74138451Smsmith sb->st_nlink = ntohl(fp->fa.fa_nlink); 74238451Smsmith sb->st_uid = ntohl(fp->fa.fa_uid); 74338451Smsmith sb->st_gid = ntohl(fp->fa.fa_gid); 74438451Smsmith sb->st_size = ntohl(fp->fa.fa_size); 74538451Smsmith 74638451Smsmith return (0); 74738451Smsmith} 74859853Sps 74959853Spsstatic int 75059853Spsnfs_readdir(struct open_file *f, struct dirent *d) 75159853Sps{ 75292913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 75359853Sps struct nfs_readdir_args *args; 75459853Sps struct nfs_readdir_data *rd; 75559853Sps struct nfs_readdir_off *roff = NULL; 75659853Sps static char *buf; 757240780Smav static struct nfs_iodesc *pfp = NULL; 75859853Sps static n_long cookie = 0; 75959853Sps size_t cc; 76059853Sps n_long eof; 761197178Semaste 76259853Sps struct { 76359853Sps n_long h[RPC_HEADER_WORDS]; 76459853Sps struct nfs_readdir_args d; 76559853Sps } sdata; 76659853Sps static struct { 76759853Sps n_long h[RPC_HEADER_WORDS]; 76859853Sps u_char d[NFS_READDIRSIZE]; 76959853Sps } rdata; 77059853Sps 771240780Smav if (fp != pfp || fp->off != cookie) { 772240780Smav pfp = NULL; 77359853Sps refill: 77459853Sps args = &sdata.d; 77559853Sps bzero(args, sizeof(*args)); 77659853Sps 77759853Sps bcopy(fp->fh, args->fh, NFS_FHSIZE); 778240780Smav args->cookie = htonl(fp->off); 77959853Sps args->count = htonl(NFS_READDIRSIZE); 780197178Semaste 78159853Sps cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 78259853Sps args, sizeof(*args), 78359853Sps rdata.d, sizeof(rdata.d)); 78459853Sps buf = rdata.d; 78559853Sps roff = (struct nfs_readdir_off *)buf; 78659853Sps if (ntohl(roff->cookie) != 0) 787124811Sjhb return EIO; 788240780Smav pfp = fp; 789240780Smav cookie = fp->off; 79059853Sps } 79159853Sps roff = (struct nfs_readdir_off *)buf; 79259853Sps 79359853Sps if (ntohl(roff->follows) == 0) { 79459853Sps eof = ntohl((roff+1)->cookie); 79559853Sps if (eof) { 79659853Sps cookie = 0; 797124811Sjhb return ENOENT; 79859853Sps } 79959853Sps goto refill; 80059853Sps } 80159853Sps 80259853Sps buf += sizeof(struct nfs_readdir_off); 80359853Sps rd = (struct nfs_readdir_data *)buf; 80459853Sps d->d_namlen = ntohl(rd->len); 80559853Sps bcopy(rd->name, d->d_name, d->d_namlen); 80659853Sps d->d_name[d->d_namlen] = '\0'; 80759853Sps 80859853Sps buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 80959853Sps roff = (struct nfs_readdir_off *)buf; 810240780Smav fp->off = cookie = ntohl(roff->cookie); 81159853Sps return 0; 81259853Sps} 813212125Srmacklem#else /* !OLD_NFSV2 */ 814212125Srmacklem/* 815212125Srmacklem * Fetch the root file handle (call mount daemon) 816212125Srmacklem * Return zero or error number. 817212125Srmacklem */ 818212125Srmacklemint 819212125Srmacklemnfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 820212125Srmacklem{ 821212125Srmacklem int len; 822212125Srmacklem struct args { 823212125Srmacklem uint32_t len; 824212125Srmacklem char path[FNAME_SIZE]; 825212125Srmacklem } *args; 826212125Srmacklem struct repl { 827212125Srmacklem uint32_t errno; 828212125Srmacklem uint32_t fhsize; 829212125Srmacklem u_char fh[NFS_V3MAXFHSIZE]; 830212125Srmacklem uint32_t authcnt; 831212125Srmacklem uint32_t auth[7]; 832212125Srmacklem } *repl; 833212125Srmacklem struct { 834212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 835212125Srmacklem struct args d; 836212125Srmacklem } sdata; 837212125Srmacklem struct { 838212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 839212125Srmacklem struct repl d; 840212125Srmacklem } rdata; 841212125Srmacklem size_t cc; 842212125Srmacklem 843212125Srmacklem#ifdef NFS_DEBUG 844212125Srmacklem if (debug) 845212125Srmacklem printf("nfs_getrootfh: %s\n", path); 846212125Srmacklem#endif 847212125Srmacklem 848212125Srmacklem args = &sdata.d; 849212125Srmacklem repl = &rdata.d; 850212125Srmacklem 851212125Srmacklem bzero(args, sizeof(*args)); 852212125Srmacklem len = strlen(path); 853212125Srmacklem if (len > sizeof(args->path)) 854212125Srmacklem len = sizeof(args->path); 855212125Srmacklem args->len = htonl(len); 856212125Srmacklem bcopy(path, args->path, len); 857212125Srmacklem len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 858212125Srmacklem 859212125Srmacklem cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 860212125Srmacklem args, len, repl, sizeof(*repl)); 861212125Srmacklem if (cc == -1) 862212125Srmacklem /* errno was set by rpc_call */ 863212125Srmacklem return (errno); 864212125Srmacklem if (cc < 2 * sizeof (uint32_t)) 865212125Srmacklem return (EBADRPC); 866212125Srmacklem if (repl->errno != 0) 867212125Srmacklem return (ntohl(repl->errno)); 868212125Srmacklem *fhlenp = ntohl(repl->fhsize); 869212125Srmacklem bcopy(repl->fh, fhp, *fhlenp); 870212125Srmacklem return (0); 871212125Srmacklem} 872212125Srmacklem 873212125Srmacklem/* 874212125Srmacklem * Lookup a file. Store handle and attributes. 875212125Srmacklem * Return zero or error number. 876212125Srmacklem */ 877212125Srmacklemint 878212125Srmacklemnfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 879212125Srmacklem{ 880212125Srmacklem int len, rlen, pos; 881212125Srmacklem struct args { 882212125Srmacklem uint32_t fhsize; 883212125Srmacklem uint32_t fhplusname[1 + 884212125Srmacklem (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 885212125Srmacklem } *args; 886212125Srmacklem struct repl { 887212125Srmacklem uint32_t errno; 888212125Srmacklem uint32_t fhsize; 889212125Srmacklem uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 890212125Srmacklem 2 * (sizeof(uint32_t) + 891212125Srmacklem sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 892212125Srmacklem } *repl; 893212125Srmacklem struct { 894212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 895212125Srmacklem struct args d; 896212125Srmacklem } sdata; 897212125Srmacklem struct { 898212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 899212125Srmacklem struct repl d; 900212125Srmacklem } rdata; 901212125Srmacklem ssize_t cc; 902212125Srmacklem 903212125Srmacklem#ifdef NFS_DEBUG 904212125Srmacklem if (debug) 905212125Srmacklem printf("lookupfh: called\n"); 906212125Srmacklem#endif 907212125Srmacklem 908212125Srmacklem args = &sdata.d; 909212125Srmacklem repl = &rdata.d; 910212125Srmacklem 911212125Srmacklem bzero(args, sizeof(*args)); 912212125Srmacklem args->fhsize = htonl(d->fhsize); 913212125Srmacklem bcopy(d->fh, args->fhplusname, d->fhsize); 914212125Srmacklem len = strlen(name); 915212125Srmacklem if (len > FNAME_SIZE) 916212125Srmacklem len = FNAME_SIZE; 917212125Srmacklem pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 918212125Srmacklem args->fhplusname[pos++] = htonl(len); 919212125Srmacklem bcopy(name, &args->fhplusname[pos], len); 920212125Srmacklem len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 921212125Srmacklem roundup(len, sizeof(uint32_t)); 922212125Srmacklem 923212125Srmacklem rlen = sizeof(*repl); 924212125Srmacklem 925212125Srmacklem cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 926212125Srmacklem args, len, repl, rlen); 927212125Srmacklem if (cc == -1) 928212125Srmacklem return (errno); /* XXX - from rpc_call */ 929212125Srmacklem if (cc < 2 * sizeof(uint32_t)) 930212125Srmacklem return (EIO); 931212125Srmacklem if (repl->errno != 0) 932212125Srmacklem /* saerrno.h now matches NFS error numbers. */ 933212125Srmacklem return (ntohl(repl->errno)); 934212125Srmacklem newfd->fhsize = ntohl(repl->fhsize); 935212125Srmacklem bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 936212125Srmacklem pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 937212125Srmacklem if (repl->fhplusattr[pos++] == 0) 938212125Srmacklem return (EIO); 939212125Srmacklem bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 940212125Srmacklem return (0); 941212125Srmacklem} 942212125Srmacklem 943212125Srmacklem#ifndef NFS_NOSYMLINK 944212125Srmacklem/* 945212125Srmacklem * Get the destination of a symbolic link. 946212125Srmacklem */ 947212125Srmacklemint 948212125Srmacklemnfs_readlink(struct nfs_iodesc *d, char *buf) 949212125Srmacklem{ 950212125Srmacklem struct args { 951212125Srmacklem uint32_t fhsize; 952212125Srmacklem u_char fh[NFS_V3MAXFHSIZE]; 953212125Srmacklem } *args; 954212125Srmacklem struct repl { 955212125Srmacklem uint32_t errno; 956212125Srmacklem uint32_t ok; 957212125Srmacklem struct nfsv3_fattrs fa; 958212125Srmacklem uint32_t len; 959212125Srmacklem u_char path[NFS_MAXPATHLEN]; 960212125Srmacklem } *repl; 961212125Srmacklem struct { 962212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 963212125Srmacklem struct args d; 964212125Srmacklem } sdata; 965212125Srmacklem struct { 966212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 967212125Srmacklem struct repl d; 968212125Srmacklem } rdata; 969212125Srmacklem ssize_t cc; 970212125Srmacklem 971212125Srmacklem#ifdef NFS_DEBUG 972212125Srmacklem if (debug) 973212125Srmacklem printf("readlink: called\n"); 974212125Srmacklem#endif 975212125Srmacklem 976212125Srmacklem args = &sdata.d; 977212125Srmacklem repl = &rdata.d; 978212125Srmacklem 979212125Srmacklem bzero(args, sizeof(*args)); 980212125Srmacklem args->fhsize = htonl(d->fhsize); 981212125Srmacklem bcopy(d->fh, args->fh, d->fhsize); 982212125Srmacklem cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 983212125Srmacklem args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 984212125Srmacklem repl, sizeof(*repl)); 985212125Srmacklem if (cc == -1) 986212125Srmacklem return (errno); 987212125Srmacklem 988212125Srmacklem if (cc < 2 * sizeof(uint32_t)) 989212125Srmacklem return (EIO); 990212125Srmacklem 991212125Srmacklem if (repl->errno != 0) 992212125Srmacklem return (ntohl(repl->errno)); 993212125Srmacklem 994212125Srmacklem if (repl->ok == 0) 995212125Srmacklem return (EIO); 996212125Srmacklem 997212125Srmacklem repl->len = ntohl(repl->len); 998212125Srmacklem if (repl->len > NFS_MAXPATHLEN) 999212125Srmacklem return (ENAMETOOLONG); 1000212125Srmacklem 1001212125Srmacklem bcopy(repl->path, buf, repl->len); 1002212125Srmacklem buf[repl->len] = 0; 1003212125Srmacklem return (0); 1004212125Srmacklem} 1005212125Srmacklem#endif 1006212125Srmacklem 1007212125Srmacklem/* 1008212125Srmacklem * Read data from a file. 1009212125Srmacklem * Return transfer count or -1 (and set errno) 1010212125Srmacklem */ 1011212125Srmacklemssize_t 1012212125Srmacklemnfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 1013212125Srmacklem{ 1014212125Srmacklem struct args { 1015212125Srmacklem uint32_t fhsize; 1016212125Srmacklem uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 1017212125Srmacklem } *args; 1018212125Srmacklem struct repl { 1019212125Srmacklem uint32_t errno; 1020212125Srmacklem uint32_t ok; 1021212125Srmacklem struct nfsv3_fattrs fa; 1022212125Srmacklem uint32_t count; 1023212125Srmacklem uint32_t eof; 1024212125Srmacklem uint32_t len; 1025212125Srmacklem u_char data[NFSREAD_SIZE]; 1026212125Srmacklem } *repl; 1027212125Srmacklem struct { 1028212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1029212125Srmacklem struct args d; 1030212125Srmacklem } sdata; 1031212125Srmacklem struct { 1032212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1033212125Srmacklem struct repl d; 1034212125Srmacklem } rdata; 1035212125Srmacklem size_t cc; 1036212125Srmacklem long x; 1037212125Srmacklem int hlen, rlen, pos; 1038212125Srmacklem 1039212125Srmacklem args = &sdata.d; 1040212125Srmacklem repl = &rdata.d; 1041212125Srmacklem 1042212125Srmacklem bzero(args, sizeof(*args)); 1043212125Srmacklem args->fhsize = htonl(d->fhsize); 1044212125Srmacklem bcopy(d->fh, args->fhoffcnt, d->fhsize); 1045212125Srmacklem pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1046212125Srmacklem args->fhoffcnt[pos++] = 0; 1047212125Srmacklem args->fhoffcnt[pos++] = htonl((uint32_t)off); 1048212125Srmacklem if (len > NFSREAD_SIZE) 1049212125Srmacklem len = NFSREAD_SIZE; 1050212125Srmacklem args->fhoffcnt[pos] = htonl((uint32_t)len); 1051212125Srmacklem hlen = sizeof(*repl) - NFSREAD_SIZE; 1052212125Srmacklem 1053212125Srmacklem cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 1054212125Srmacklem args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1055212125Srmacklem repl, sizeof(*repl)); 1056212125Srmacklem if (cc == -1) 1057212125Srmacklem /* errno was already set by rpc_call */ 1058212125Srmacklem return (-1); 1059212125Srmacklem if (cc < hlen) { 1060212125Srmacklem errno = EBADRPC; 1061212125Srmacklem return (-1); 1062212125Srmacklem } 1063212125Srmacklem if (repl->errno != 0) { 1064212125Srmacklem errno = ntohl(repl->errno); 1065212125Srmacklem return (-1); 1066212125Srmacklem } 1067212125Srmacklem rlen = cc - hlen; 1068212125Srmacklem x = ntohl(repl->count); 1069212125Srmacklem if (rlen < x) { 1070212125Srmacklem printf("nfsread: short packet, %d < %ld\n", rlen, x); 1071212125Srmacklem errno = EBADRPC; 1072212125Srmacklem return (-1); 1073212125Srmacklem } 1074212125Srmacklem bcopy(repl->data, addr, x); 1075212125Srmacklem return (x); 1076212125Srmacklem} 1077212125Srmacklem 1078212125Srmacklem/* 1079212125Srmacklem * Open a file. 1080212125Srmacklem * return zero or error number 1081212125Srmacklem */ 1082212125Srmacklemint 1083212125Srmacklemnfs_open(const char *upath, struct open_file *f) 1084212125Srmacklem{ 1085212125Srmacklem struct iodesc *desc; 1086212125Srmacklem struct nfs_iodesc *currfd; 1087212125Srmacklem char buf[2 * NFS_V3MAXFHSIZE + 3]; 1088212125Srmacklem u_char *fh; 1089212125Srmacklem char *cp; 1090212125Srmacklem int i; 1091212125Srmacklem#ifndef NFS_NOSYMLINK 1092212125Srmacklem struct nfs_iodesc *newfd; 1093212125Srmacklem struct nfsv3_fattrs *fa; 1094212125Srmacklem char *ncp; 1095212125Srmacklem int c; 1096212125Srmacklem char namebuf[NFS_MAXPATHLEN + 1]; 1097212125Srmacklem char linkbuf[NFS_MAXPATHLEN + 1]; 1098212125Srmacklem int nlinks = 0; 1099212125Srmacklem#endif 1100212125Srmacklem int error; 1101212125Srmacklem char *path; 1102212125Srmacklem 1103212125Srmacklem#ifdef NFS_DEBUG 1104212125Srmacklem if (debug) 1105212125Srmacklem printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 1106212125Srmacklem#endif 1107212125Srmacklem if (!rootpath[0]) { 1108212125Srmacklem printf("no rootpath, no nfs\n"); 1109212125Srmacklem return (ENXIO); 1110212125Srmacklem } 1111212125Srmacklem 1112212125Srmacklem /* 1113212125Srmacklem * This is silly - we should look at dv_type but that value is 1114212125Srmacklem * arch dependant and we can't use it here. 1115212125Srmacklem */ 1116212125Srmacklem#ifndef __i386__ 1117212125Srmacklem if (strcmp(f->f_dev->dv_name, "net") != 0) 1118212125Srmacklem return (EINVAL); 1119212125Srmacklem#else 1120212125Srmacklem if (strcmp(f->f_dev->dv_name, "pxe") != 0) 1121212125Srmacklem return (EINVAL); 1122212125Srmacklem#endif 1123212125Srmacklem 1124212125Srmacklem if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 1125212125Srmacklem return (EINVAL); 1126212125Srmacklem 1127212125Srmacklem /* Bind to a reserved port. */ 1128212125Srmacklem desc->myport = htons(--rpc_port); 1129212125Srmacklem desc->destip = rootip; 1130212125Srmacklem if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 1131212125Srmacklem nfs_root_node.fh))) 1132212125Srmacklem return (error); 1133240774Smav nfs_root_node.fa.fa_type = htonl(NFDIR); 1134240774Smav nfs_root_node.fa.fa_mode = htonl(0755); 1135240774Smav nfs_root_node.fa.fa_nlink = htonl(2); 1136212125Srmacklem nfs_root_node.iodesc = desc; 1137212125Srmacklem 1138212125Srmacklem fh = &nfs_root_node.fh[0]; 1139212125Srmacklem buf[0] = 'X'; 1140212125Srmacklem cp = &buf[1]; 1141212125Srmacklem for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 1142212125Srmacklem sprintf(cp, "%02x", fh[i]); 1143212125Srmacklem sprintf(cp, "X"); 1144212125Srmacklem setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 1145212125Srmacklem setenv("boot.nfsroot.path", rootpath, 1); 1146212125Srmacklem setenv("boot.nfsroot.nfshandle", buf, 1); 1147212125Srmacklem sprintf(buf, "%d", nfs_root_node.fhsize); 1148212125Srmacklem setenv("boot.nfsroot.nfshandlelen", buf, 1); 1149212125Srmacklem 1150240774Smav /* Allocate file system specific data structure */ 1151240774Smav currfd = malloc(sizeof(*newfd)); 1152240774Smav if (currfd == NULL) { 1153240774Smav error = ENOMEM; 1154240774Smav goto out; 1155240774Smav } 1156212125Srmacklem#ifndef NFS_NOSYMLINK 1157240774Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1158212125Srmacklem newfd = 0; 1159212125Srmacklem 1160212125Srmacklem cp = path = strdup(upath); 1161212125Srmacklem if (path == NULL) { 1162212125Srmacklem error = ENOMEM; 1163212125Srmacklem goto out; 1164212125Srmacklem } 1165212125Srmacklem while (*cp) { 1166212125Srmacklem /* 1167212125Srmacklem * Remove extra separators 1168212125Srmacklem */ 1169212125Srmacklem while (*cp == '/') 1170212125Srmacklem cp++; 1171212125Srmacklem 1172212125Srmacklem if (*cp == '\0') 1173212125Srmacklem break; 1174212125Srmacklem /* 1175212125Srmacklem * Check that current node is a directory. 1176212125Srmacklem */ 1177212125Srmacklem if (currfd->fa.fa_type != htonl(NFDIR)) { 1178212125Srmacklem error = ENOTDIR; 1179212125Srmacklem goto out; 1180212125Srmacklem } 1181212125Srmacklem 1182212125Srmacklem /* allocate file system specific data structure */ 1183212125Srmacklem newfd = malloc(sizeof(*newfd)); 1184212125Srmacklem if (newfd == NULL) { 1185212125Srmacklem error = ENOMEM; 1186212125Srmacklem goto out; 1187212125Srmacklem } 1188212125Srmacklem newfd->iodesc = currfd->iodesc; 1189212125Srmacklem 1190212125Srmacklem /* 1191212125Srmacklem * Get next component of path name. 1192212125Srmacklem */ 1193212125Srmacklem { 1194212125Srmacklem int len = 0; 1195212125Srmacklem 1196212125Srmacklem ncp = cp; 1197212125Srmacklem while ((c = *cp) != '\0' && c != '/') { 1198212125Srmacklem if (++len > NFS_MAXNAMLEN) { 1199212125Srmacklem error = ENOENT; 1200212125Srmacklem goto out; 1201212125Srmacklem } 1202212125Srmacklem cp++; 1203212125Srmacklem } 1204212125Srmacklem *cp = '\0'; 1205212125Srmacklem } 1206212125Srmacklem 1207212125Srmacklem /* lookup a file handle */ 1208212125Srmacklem error = nfs_lookupfh(currfd, ncp, newfd); 1209212125Srmacklem *cp = c; 1210212125Srmacklem if (error) 1211212125Srmacklem goto out; 1212212125Srmacklem 1213212125Srmacklem /* 1214212125Srmacklem * Check for symbolic link 1215212125Srmacklem */ 1216212125Srmacklem if (newfd->fa.fa_type == htonl(NFLNK)) { 1217212125Srmacklem int link_len, len; 1218212125Srmacklem 1219212125Srmacklem error = nfs_readlink(newfd, linkbuf); 1220212125Srmacklem if (error) 1221212125Srmacklem goto out; 1222212125Srmacklem 1223212125Srmacklem link_len = strlen(linkbuf); 1224212125Srmacklem len = strlen(cp); 1225212125Srmacklem 1226212125Srmacklem if (link_len + len > MAXPATHLEN 1227212125Srmacklem || ++nlinks > MAXSYMLINKS) { 1228212125Srmacklem error = ENOENT; 1229212125Srmacklem goto out; 1230212125Srmacklem } 1231212125Srmacklem 1232212125Srmacklem bcopy(cp, &namebuf[link_len], len + 1); 1233212125Srmacklem bcopy(linkbuf, namebuf, link_len); 1234212125Srmacklem 1235212125Srmacklem /* 1236212125Srmacklem * If absolute pathname, restart at root. 1237212125Srmacklem * If relative pathname, restart at parent directory. 1238212125Srmacklem */ 1239212125Srmacklem cp = namebuf; 1240240774Smav if (*cp == '/') 1241240774Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1242212125Srmacklem 1243212125Srmacklem free(newfd); 1244212125Srmacklem newfd = 0; 1245212125Srmacklem 1246212125Srmacklem continue; 1247212125Srmacklem } 1248212125Srmacklem 1249240774Smav free(currfd); 1250212125Srmacklem currfd = newfd; 1251212125Srmacklem newfd = 0; 1252212125Srmacklem } 1253212125Srmacklem 1254212125Srmacklem error = 0; 1255212125Srmacklem 1256212125Srmacklemout: 1257240881Skevlo free(newfd); 1258240881Skevlo free(path); 1259212125Srmacklem#else 1260240774Smav currfd->iodesc = desc; 1261212125Srmacklem 1262240774Smav error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1263212125Srmacklem#endif 1264212125Srmacklem if (!error) { 1265240774Smav currfd->off = 0; 1266240780Smav currfd->cookie = 0; 1267212125Srmacklem f->f_fsdata = (void *)currfd; 1268212125Srmacklem return (0); 1269212125Srmacklem } 1270212125Srmacklem 1271212125Srmacklem#ifdef NFS_DEBUG 1272212125Srmacklem if (debug) 1273212125Srmacklem printf("nfs_open: %s lookupfh failed: %s\n", 1274212125Srmacklem path, strerror(error)); 1275212125Srmacklem#endif 1276240774Smav free(currfd); 1277212125Srmacklem 1278212125Srmacklem return (error); 1279212125Srmacklem} 1280212125Srmacklem 1281212125Srmacklemint 1282212125Srmacklemnfs_close(struct open_file *f) 1283212125Srmacklem{ 1284212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1285212125Srmacklem 1286212125Srmacklem#ifdef NFS_DEBUG 1287212125Srmacklem if (debug) 1288212125Srmacklem printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1289212125Srmacklem#endif 1290212125Srmacklem 1291240774Smav if (fp) 1292212125Srmacklem free(fp); 1293212125Srmacklem f->f_fsdata = (void *)0; 1294212125Srmacklem 1295212125Srmacklem return (0); 1296212125Srmacklem} 1297212125Srmacklem 1298212125Srmacklem/* 1299212125Srmacklem * read a portion of a file 1300212125Srmacklem */ 1301212125Srmacklemint 1302212125Srmacklemnfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1303212125Srmacklem{ 1304212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1305212125Srmacklem ssize_t cc; 1306212125Srmacklem char *addr = buf; 1307212125Srmacklem 1308212125Srmacklem#ifdef NFS_DEBUG 1309212125Srmacklem if (debug) 1310212125Srmacklem printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1311212125Srmacklem (int)fp->off); 1312212125Srmacklem#endif 1313212125Srmacklem while ((int)size > 0) { 1314212125Srmacklem twiddle(); 1315212125Srmacklem cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1316212125Srmacklem /* XXX maybe should retry on certain errors */ 1317212125Srmacklem if (cc == -1) { 1318212125Srmacklem#ifdef NFS_DEBUG 1319212125Srmacklem if (debug) 1320212125Srmacklem printf("nfs_read: read: %s", strerror(errno)); 1321212125Srmacklem#endif 1322212125Srmacklem return (errno); /* XXX - from nfs_readdata */ 1323212125Srmacklem } 1324212125Srmacklem if (cc == 0) { 1325212125Srmacklem#ifdef NFS_DEBUG 1326212125Srmacklem if (debug) 1327212125Srmacklem printf("nfs_read: hit EOF unexpectantly"); 1328212125Srmacklem#endif 1329212125Srmacklem goto ret; 1330212125Srmacklem } 1331212125Srmacklem fp->off += cc; 1332212125Srmacklem addr += cc; 1333212125Srmacklem size -= cc; 1334212125Srmacklem } 1335212125Srmacklemret: 1336212125Srmacklem if (resid) 1337212125Srmacklem *resid = size; 1338212125Srmacklem 1339212125Srmacklem return (0); 1340212125Srmacklem} 1341212125Srmacklem 1342212125Srmacklem/* 1343212125Srmacklem * Not implemented. 1344212125Srmacklem */ 1345212125Srmacklemint 1346212125Srmacklemnfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1347212125Srmacklem{ 1348212125Srmacklem return (EROFS); 1349212125Srmacklem} 1350212125Srmacklem 1351212125Srmacklemoff_t 1352212125Srmacklemnfs_seek(struct open_file *f, off_t offset, int where) 1353212125Srmacklem{ 1354212125Srmacklem struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1355212125Srmacklem uint32_t size = ntohl(d->fa.fa_size.val[1]); 1356212125Srmacklem 1357212125Srmacklem switch (where) { 1358212125Srmacklem case SEEK_SET: 1359212125Srmacklem d->off = offset; 1360212125Srmacklem break; 1361212125Srmacklem case SEEK_CUR: 1362212125Srmacklem d->off += offset; 1363212125Srmacklem break; 1364212125Srmacklem case SEEK_END: 1365212125Srmacklem d->off = size - offset; 1366212125Srmacklem break; 1367212125Srmacklem default: 1368212125Srmacklem errno = EINVAL; 1369212125Srmacklem return (-1); 1370212125Srmacklem } 1371212125Srmacklem 1372212125Srmacklem return (d->off); 1373212125Srmacklem} 1374212125Srmacklem 1375212125Srmacklem/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1376212125Srmacklemint nfs_stat_types[9] = { 1377212125Srmacklem 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1378212125Srmacklem 1379212125Srmacklemint 1380212125Srmacklemnfs_stat(struct open_file *f, struct stat *sb) 1381212125Srmacklem{ 1382212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1383212125Srmacklem uint32_t ftype, mode; 1384212125Srmacklem 1385212125Srmacklem ftype = ntohl(fp->fa.fa_type); 1386212125Srmacklem mode = ntohl(fp->fa.fa_mode); 1387212125Srmacklem mode |= nfs_stat_types[ftype & 7]; 1388212125Srmacklem 1389212125Srmacklem sb->st_mode = mode; 1390212125Srmacklem sb->st_nlink = ntohl(fp->fa.fa_nlink); 1391212125Srmacklem sb->st_uid = ntohl(fp->fa.fa_uid); 1392212125Srmacklem sb->st_gid = ntohl(fp->fa.fa_gid); 1393212125Srmacklem sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1394212125Srmacklem 1395212125Srmacklem return (0); 1396212125Srmacklem} 1397212125Srmacklem 1398212125Srmacklemstatic int 1399212125Srmacklemnfs_readdir(struct open_file *f, struct dirent *d) 1400212125Srmacklem{ 1401212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1402212125Srmacklem struct nfsv3_readdir_repl *repl; 1403212125Srmacklem struct nfsv3_readdir_entry *rent; 1404212125Srmacklem static char *buf; 1405240780Smav static struct nfs_iodesc *pfp = NULL; 1406240780Smav static uint64_t cookie = 0; 1407212125Srmacklem size_t cc; 1408212125Srmacklem int pos; 1409212125Srmacklem 1410212125Srmacklem struct args { 1411212125Srmacklem uint32_t fhsize; 1412212125Srmacklem uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1413212125Srmacklem } *args; 1414212125Srmacklem struct { 1415212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1416212125Srmacklem struct args d; 1417212125Srmacklem } sdata; 1418212125Srmacklem static struct { 1419212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1420212125Srmacklem u_char d[NFS_READDIRSIZE]; 1421212125Srmacklem } rdata; 1422212125Srmacklem 1423240780Smav if (fp != pfp || fp->off != cookie) { 1424240780Smav pfp = NULL; 1425212125Srmacklem refill: 1426212125Srmacklem args = &sdata.d; 1427212125Srmacklem bzero(args, sizeof(*args)); 1428212125Srmacklem 1429212125Srmacklem args->fhsize = htonl(fp->fhsize); 1430212125Srmacklem bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1431212125Srmacklem pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1432240780Smav args->fhpluscookie[pos++] = htonl(fp->off >> 32); 1433240780Smav args->fhpluscookie[pos++] = htonl(fp->off); 1434240780Smav args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 1435240780Smav args->fhpluscookie[pos++] = htonl(fp->cookie); 1436212125Srmacklem args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1437212125Srmacklem 1438212125Srmacklem cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1439212125Srmacklem args, 6 * sizeof(uint32_t) + 1440212125Srmacklem roundup(fp->fhsize, sizeof(uint32_t)), 1441212125Srmacklem rdata.d, sizeof(rdata.d)); 1442212125Srmacklem buf = rdata.d; 1443212125Srmacklem repl = (struct nfsv3_readdir_repl *)buf; 1444212125Srmacklem if (repl->errno != 0) 1445212125Srmacklem return (ntohl(repl->errno)); 1446240780Smav pfp = fp; 1447240780Smav cookie = fp->off; 1448240780Smav fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 1449240780Smav ntohl(repl->cookiev1); 1450212125Srmacklem buf += sizeof (struct nfsv3_readdir_repl); 1451212125Srmacklem } 1452212125Srmacklem rent = (struct nfsv3_readdir_entry *)buf; 1453212125Srmacklem 1454212125Srmacklem if (rent->follows == 0) { 1455212125Srmacklem /* fid0 is actually eof */ 1456212125Srmacklem if (rent->fid0 != 0) { 1457240780Smav cookie = 0; 1458212125Srmacklem return (ENOENT); 1459212125Srmacklem } 1460212125Srmacklem goto refill; 1461212125Srmacklem } 1462212125Srmacklem 1463212125Srmacklem d->d_namlen = ntohl(rent->len); 1464212125Srmacklem bcopy(rent->nameplus, d->d_name, d->d_namlen); 1465212125Srmacklem d->d_name[d->d_namlen] = '\0'; 1466212125Srmacklem 1467212125Srmacklem pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 1468252468Smav fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 1469252468Smav ntohl(rent->nameplus[pos + 1]); 1470252468Smav pos += 2; 1471212125Srmacklem buf = (u_char *)&rent->nameplus[pos]; 1472212125Srmacklem return (0); 1473212125Srmacklem} 1474212125Srmacklem#endif /* OLD_NFSV2 */ 1475