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: stable/10/lib/libstand/nfs.c 307203 2016-10-13 08:09:40Z sephe $"); 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> 39307203Ssephe#include <stddef.h> 4038451Smsmith 4138451Smsmith#include <netinet/in.h> 4238451Smsmith#include <netinet/in_systm.h> 4338451Smsmith 4438451Smsmith#include "rpcv2.h" 4538451Smsmith#include "nfsv2.h" 4638451Smsmith 4738451Smsmith#include "stand.h" 4838451Smsmith#include "net.h" 4938451Smsmith#include "netif.h" 5038451Smsmith#include "rpc.h" 5138451Smsmith 5238451Smsmith#define NFS_DEBUGxx 5338451Smsmith 54307203Ssephe#define NFSREAD_MIN_SIZE 1024 55307203Ssephe#define NFSREAD_MAX_SIZE 4096 56212125Srmacklem 5738451Smsmith/* Define our own NFS attributes without NQNFS stuff. */ 58212125Srmacklem#ifdef OLD_NFSV2 5938451Smsmithstruct nfsv2_fattrs { 6038451Smsmith n_long fa_type; 6138451Smsmith n_long fa_mode; 6238451Smsmith n_long fa_nlink; 6338451Smsmith n_long fa_uid; 6438451Smsmith n_long fa_gid; 6538451Smsmith n_long fa_size; 6638451Smsmith n_long fa_blocksize; 6738451Smsmith n_long fa_rdev; 6838451Smsmith n_long fa_blocks; 6938451Smsmith n_long fa_fsid; 7038451Smsmith n_long fa_fileid; 7138451Smsmith struct nfsv2_time fa_atime; 7238451Smsmith struct nfsv2_time fa_mtime; 7338451Smsmith struct nfsv2_time fa_ctime; 7438451Smsmith}; 7538451Smsmith 7638451Smsmithstruct nfs_read_args { 7738451Smsmith u_char fh[NFS_FHSIZE]; 7838451Smsmith n_long off; 7938451Smsmith n_long len; 8038451Smsmith n_long xxx; /* XXX what's this for? */ 8138451Smsmith}; 8238451Smsmith 8338451Smsmith/* Data part of nfs rpc reply (also the largest thing we receive) */ 8438451Smsmithstruct nfs_read_repl { 8538451Smsmith n_long errno; 8638451Smsmith struct nfsv2_fattrs fa; 8738451Smsmith n_long count; 88307203Ssephe u_char data[NFSREAD_MAX_SIZE]; 8938451Smsmith}; 9038451Smsmith 9138451Smsmith#ifndef NFS_NOSYMLINK 9238451Smsmithstruct nfs_readlnk_repl { 9338451Smsmith n_long errno; 9438451Smsmith n_long len; 9538451Smsmith char path[NFS_MAXPATHLEN]; 9638451Smsmith}; 9738451Smsmith#endif 9838451Smsmith 9959853Spsstruct nfs_readdir_args { 10059853Sps u_char fh[NFS_FHSIZE]; 10159853Sps n_long cookie; 10259853Sps n_long count; 10359853Sps}; 10459853Sps 10559853Spsstruct nfs_readdir_data { 10659853Sps n_long fileid; 10759853Sps n_long len; 10859853Sps char name[0]; 10959853Sps}; 11059853Sps 11159853Spsstruct nfs_readdir_off { 11259853Sps n_long cookie; 11359853Sps n_long follows; 11459853Sps}; 11559853Sps 11638451Smsmithstruct nfs_iodesc { 11738451Smsmith struct iodesc *iodesc; 11838451Smsmith off_t off; 11938451Smsmith u_char fh[NFS_FHSIZE]; 12038451Smsmith struct nfsv2_fattrs fa; /* all in network order */ 12138451Smsmith}; 122212125Srmacklem#else /* !OLD_NFSV2 */ 12338451Smsmith 124212125Srmacklem/* NFSv3 definitions */ 125212125Srmacklem#define NFS_V3MAXFHSIZE 64 126212125Srmacklem#define NFS_VER3 3 127212125Srmacklem#define RPCMNT_VER3 3 128212125Srmacklem#define NFSPROCV3_LOOKUP 3 129212125Srmacklem#define NFSPROCV3_READLINK 5 130212125Srmacklem#define NFSPROCV3_READ 6 131212125Srmacklem#define NFSPROCV3_READDIR 16 132212125Srmacklem 133212125Srmacklemtypedef struct { 134212125Srmacklem uint32_t val[2]; 135212125Srmacklem} n_quad; 136212125Srmacklem 137212125Srmacklemstruct nfsv3_time { 138212125Srmacklem uint32_t nfs_sec; 139212125Srmacklem uint32_t nfs_nsec; 140212125Srmacklem}; 141212125Srmacklem 142212125Srmacklemstruct nfsv3_fattrs { 143212125Srmacklem uint32_t fa_type; 144212125Srmacklem uint32_t fa_mode; 145212125Srmacklem uint32_t fa_nlink; 146212125Srmacklem uint32_t fa_uid; 147212125Srmacklem uint32_t fa_gid; 148212125Srmacklem n_quad fa_size; 149212125Srmacklem n_quad fa_used; 150212125Srmacklem n_quad fa_rdev; 151212125Srmacklem n_quad fa_fsid; 152212125Srmacklem n_quad fa_fileid; 153212125Srmacklem struct nfsv3_time fa_atime; 154212125Srmacklem struct nfsv3_time fa_mtime; 155212125Srmacklem struct nfsv3_time fa_ctime; 156212125Srmacklem}; 157212125Srmacklem 15838451Smsmith/* 159212125Srmacklem * For NFSv3, the file handle is variable in size, so most fixed sized 160212125Srmacklem * structures for arguments won't work. For most cases, a structure 161212125Srmacklem * that starts with any fixed size section is followed by an array 162212125Srmacklem * that covers the maximum size required. 163212125Srmacklem */ 164212125Srmacklemstruct nfsv3_readdir_repl { 165212125Srmacklem uint32_t errno; 166212125Srmacklem uint32_t ok; 167212125Srmacklem struct nfsv3_fattrs fa; 168212125Srmacklem uint32_t cookiev0; 169212125Srmacklem uint32_t cookiev1; 170212125Srmacklem}; 171212125Srmacklem 172212125Srmacklemstruct nfsv3_readdir_entry { 173212125Srmacklem uint32_t follows; 174212125Srmacklem uint32_t fid0; 175212125Srmacklem uint32_t fid1; 176212125Srmacklem uint32_t len; 177212125Srmacklem uint32_t nameplus[0]; 178212125Srmacklem}; 179212125Srmacklem 180212125Srmacklemstruct nfs_iodesc { 181212125Srmacklem struct iodesc *iodesc; 182212125Srmacklem off_t off; 183212125Srmacklem uint32_t fhsize; 184212125Srmacklem u_char fh[NFS_V3MAXFHSIZE]; 185212125Srmacklem struct nfsv3_fattrs fa; /* all in network order */ 186240780Smav uint64_t cookie; 187212125Srmacklem}; 188212125Srmacklem#endif /* OLD_NFSV2 */ 189212125Srmacklem 190212125Srmacklem/* 19138451Smsmith * XXX interactions with tftp? See nfswrapper.c for a confusing 19238451Smsmith * issue. 19338451Smsmith */ 19439468Smsmithint nfs_open(const char *path, struct open_file *f); 19538451Smsmithstatic int nfs_close(struct open_file *f); 19638451Smsmithstatic int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 19738451Smsmithstatic int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 19838451Smsmithstatic off_t nfs_seek(struct open_file *f, off_t offset, int where); 19938451Smsmithstatic int nfs_stat(struct open_file *f, struct stat *sb); 20059853Spsstatic int nfs_readdir(struct open_file *f, struct dirent *d); 20138451Smsmith 20265496Smsmithstruct nfs_iodesc nfs_root_node; 20359824Sps 20438451Smsmithstruct fs_ops nfs_fsops = { 20559766Sjlemon "nfs", 20659766Sjlemon nfs_open, 20759766Sjlemon nfs_close, 20859766Sjlemon nfs_read, 20959766Sjlemon nfs_write, 21059766Sjlemon nfs_seek, 21159766Sjlemon nfs_stat, 21259853Sps nfs_readdir 21338451Smsmith}; 21438451Smsmith 215307203Ssephestatic int nfs_read_size = NFSREAD_MIN_SIZE; 216307203Ssephe 217212125Srmacklem#ifdef OLD_NFSV2 21838451Smsmith/* 21938451Smsmith * Fetch the root file handle (call mount daemon) 22038451Smsmith * Return zero or error number. 22138451Smsmith */ 22238451Smsmithint 223197178Semastenfs_getrootfh(struct iodesc *d, char *path, u_char *fhp) 22438451Smsmith{ 22592913Sobrien int len; 22638451Smsmith struct args { 22738451Smsmith n_long len; 22838451Smsmith char path[FNAME_SIZE]; 22938451Smsmith } *args; 23038451Smsmith struct repl { 23138451Smsmith n_long errno; 23238451Smsmith u_char fh[NFS_FHSIZE]; 23338451Smsmith } *repl; 23438451Smsmith struct { 23538451Smsmith n_long h[RPC_HEADER_WORDS]; 23638451Smsmith struct args d; 23738451Smsmith } sdata; 23838451Smsmith struct { 23938451Smsmith n_long h[RPC_HEADER_WORDS]; 24038451Smsmith struct repl d; 24138451Smsmith } rdata; 24238451Smsmith size_t cc; 243197178Semaste 24438451Smsmith#ifdef NFS_DEBUG 24538451Smsmith if (debug) 24638451Smsmith printf("nfs_getrootfh: %s\n", path); 24738451Smsmith#endif 24838451Smsmith 24938451Smsmith args = &sdata.d; 25038451Smsmith repl = &rdata.d; 25138451Smsmith 25238451Smsmith bzero(args, sizeof(*args)); 25338451Smsmith len = strlen(path); 25438451Smsmith if (len > sizeof(args->path)) 25538451Smsmith len = sizeof(args->path); 25638451Smsmith args->len = htonl(len); 25738451Smsmith bcopy(path, args->path, len); 25838451Smsmith len = 4 + roundup(len, 4); 25938451Smsmith 26038451Smsmith cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 26138451Smsmith args, len, repl, sizeof(*repl)); 26238451Smsmith if (cc == -1) { 26338451Smsmith /* errno was set by rpc_call */ 26438451Smsmith return (errno); 26538451Smsmith } 26638451Smsmith if (cc < 4) 26738451Smsmith return (EBADRPC); 26838451Smsmith if (repl->errno) 26938451Smsmith return (ntohl(repl->errno)); 27038451Smsmith bcopy(repl->fh, fhp, sizeof(repl->fh)); 271307203Ssephe 272307203Ssephe /* 273307203Ssephe * Improve boot performance over NFS 274307203Ssephe */ 275307203Ssephe if (getenv("nfs.read_size") != NULL) 276307203Ssephe nfs_read_size = strtol(getenv("nfs.read_size"), NULL, 0); 277307203Ssephe if (nfs_read_size < NFSREAD_MIN_SIZE) 278307203Ssephe nfs_read_size = NFSREAD_MIN_SIZE; 279307203Ssephe if (nfs_read_size > NFSREAD_MAX_SIZE) 280307203Ssephe nfs_read_size = NFSREAD_MAX_SIZE; 281307203Ssephe 28238451Smsmith return (0); 28338451Smsmith} 28438451Smsmith 28538451Smsmith/* 28638451Smsmith * Lookup a file. Store handle and attributes. 28738451Smsmith * Return zero or error number. 28838451Smsmith */ 28938451Smsmithint 290197178Semastenfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 29138451Smsmith{ 29292913Sobrien int len, rlen; 29338451Smsmith struct args { 29438451Smsmith u_char fh[NFS_FHSIZE]; 29538451Smsmith n_long len; 29638451Smsmith char name[FNAME_SIZE]; 29738451Smsmith } *args; 29838451Smsmith struct repl { 29938451Smsmith n_long errno; 30038451Smsmith u_char fh[NFS_FHSIZE]; 30138451Smsmith struct nfsv2_fattrs fa; 30238451Smsmith } *repl; 30338451Smsmith struct { 30438451Smsmith n_long h[RPC_HEADER_WORDS]; 30538451Smsmith struct args d; 30638451Smsmith } sdata; 30738451Smsmith struct { 30838451Smsmith n_long h[RPC_HEADER_WORDS]; 30938451Smsmith struct repl d; 31038451Smsmith } rdata; 31138451Smsmith ssize_t cc; 312197178Semaste 31338451Smsmith#ifdef NFS_DEBUG 31438451Smsmith if (debug) 31538451Smsmith printf("lookupfh: called\n"); 31638451Smsmith#endif 31738451Smsmith 31838451Smsmith args = &sdata.d; 31938451Smsmith repl = &rdata.d; 32038451Smsmith 32138451Smsmith bzero(args, sizeof(*args)); 32238451Smsmith bcopy(d->fh, args->fh, sizeof(args->fh)); 32338451Smsmith len = strlen(name); 32438451Smsmith if (len > sizeof(args->name)) 32538451Smsmith len = sizeof(args->name); 32638451Smsmith bcopy(name, args->name, len); 32738451Smsmith args->len = htonl(len); 32838451Smsmith len = 4 + roundup(len, 4); 32938451Smsmith len += NFS_FHSIZE; 33038451Smsmith 33138451Smsmith rlen = sizeof(*repl); 33238451Smsmith 33338451Smsmith cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 33438451Smsmith args, len, repl, rlen); 33538451Smsmith if (cc == -1) 33638451Smsmith return (errno); /* XXX - from rpc_call */ 33738451Smsmith if (cc < 4) 33838451Smsmith return (EIO); 33938451Smsmith if (repl->errno) { 34038451Smsmith /* saerrno.h now matches NFS error numbers. */ 34138451Smsmith return (ntohl(repl->errno)); 34238451Smsmith } 34338451Smsmith bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh)); 34438451Smsmith bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa)); 34538451Smsmith return (0); 34638451Smsmith} 34738451Smsmith 34838451Smsmith#ifndef NFS_NOSYMLINK 34938451Smsmith/* 35038451Smsmith * Get the destination of a symbolic link. 35138451Smsmith */ 35238451Smsmithint 353197178Semastenfs_readlink(struct nfs_iodesc *d, char *buf) 35438451Smsmith{ 35538451Smsmith struct { 35638451Smsmith n_long h[RPC_HEADER_WORDS]; 35738451Smsmith u_char fh[NFS_FHSIZE]; 35838451Smsmith } sdata; 35938451Smsmith struct { 36038451Smsmith n_long h[RPC_HEADER_WORDS]; 36138451Smsmith struct nfs_readlnk_repl d; 36238451Smsmith } rdata; 36338451Smsmith ssize_t cc; 36438451Smsmith 36538451Smsmith#ifdef NFS_DEBUG 36638451Smsmith if (debug) 36738451Smsmith printf("readlink: called\n"); 36838451Smsmith#endif 36938451Smsmith 37038451Smsmith bcopy(d->fh, sdata.fh, NFS_FHSIZE); 37138451Smsmith cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK, 37238451Smsmith sdata.fh, NFS_FHSIZE, 37338451Smsmith &rdata.d, sizeof(rdata.d)); 37438451Smsmith if (cc == -1) 37538451Smsmith return (errno); 37638451Smsmith 37738451Smsmith if (cc < 4) 37838451Smsmith return (EIO); 379197178Semaste 38038451Smsmith if (rdata.d.errno) 38138451Smsmith return (ntohl(rdata.d.errno)); 38238451Smsmith 38338451Smsmith rdata.d.len = ntohl(rdata.d.len); 38438451Smsmith if (rdata.d.len > NFS_MAXPATHLEN) 38538451Smsmith return (ENAMETOOLONG); 38638451Smsmith 38738451Smsmith bcopy(rdata.d.path, buf, rdata.d.len); 38838451Smsmith buf[rdata.d.len] = 0; 38938451Smsmith return (0); 39038451Smsmith} 39138451Smsmith#endif 39238451Smsmith 39338451Smsmith/* 39438451Smsmith * Read data from a file. 39538451Smsmith * Return transfer count or -1 (and set errno) 39638451Smsmith */ 39738451Smsmithssize_t 398197178Semastenfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 39938451Smsmith{ 40038451Smsmith struct nfs_read_args *args; 40138451Smsmith struct nfs_read_repl *repl; 40238451Smsmith struct { 40338451Smsmith n_long h[RPC_HEADER_WORDS]; 40438451Smsmith struct nfs_read_args d; 40538451Smsmith } sdata; 40638451Smsmith struct { 40738451Smsmith n_long h[RPC_HEADER_WORDS]; 40838451Smsmith struct nfs_read_repl d; 40938451Smsmith } rdata; 41038451Smsmith size_t cc; 41138451Smsmith long x; 41238451Smsmith int hlen, rlen; 41338451Smsmith 41438451Smsmith args = &sdata.d; 41538451Smsmith repl = &rdata.d; 41638451Smsmith 41738451Smsmith bcopy(d->fh, args->fh, NFS_FHSIZE); 41838451Smsmith args->off = htonl((n_long)off); 419307203Ssephe if (len > nfs_read_size) 420307203Ssephe len = nfs_read_size; 42138451Smsmith args->len = htonl((n_long)len); 42238451Smsmith args->xxx = htonl((n_long)0); 423307203Ssephe hlen = offsetof(struct nfs_read_rpl, data[0]); 42438451Smsmith 42538451Smsmith cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 42638451Smsmith args, sizeof(*args), 42738451Smsmith repl, sizeof(*repl)); 42838451Smsmith if (cc == -1) { 42938451Smsmith /* errno was already set by rpc_call */ 43038451Smsmith return (-1); 43138451Smsmith } 43238451Smsmith if (cc < hlen) { 43338451Smsmith errno = EBADRPC; 43438451Smsmith return (-1); 43538451Smsmith } 43638451Smsmith if (repl->errno) { 43738451Smsmith errno = ntohl(repl->errno); 43838451Smsmith return (-1); 43938451Smsmith } 44038451Smsmith rlen = cc - hlen; 44138451Smsmith x = ntohl(repl->count); 44238451Smsmith if (rlen < x) { 44338451Smsmith printf("nfsread: short packet, %d < %ld\n", rlen, x); 44438451Smsmith errno = EBADRPC; 44538451Smsmith return(-1); 44638451Smsmith } 44738451Smsmith bcopy(repl->data, addr, x); 44838451Smsmith return (x); 44938451Smsmith} 45038451Smsmith 45138451Smsmith/* 45238451Smsmith * Open a file. 45338451Smsmith * return zero or error number 45438451Smsmith */ 45538451Smsmithint 456197178Semastenfs_open(const char *upath, struct open_file *f) 45738451Smsmith{ 45838451Smsmith struct iodesc *desc; 45938451Smsmith struct nfs_iodesc *currfd; 460101112Sjake char buf[2 * NFS_FHSIZE + 3]; 461101112Sjake u_char *fh; 462101112Sjake char *cp; 463101112Sjake int i; 46438451Smsmith#ifndef NFS_NOSYMLINK 46538451Smsmith struct nfs_iodesc *newfd; 46638451Smsmith struct nfsv2_fattrs *fa; 467101112Sjake char *ncp; 46892913Sobrien int c; 46938451Smsmith char namebuf[NFS_MAXPATHLEN + 1]; 47038451Smsmith char linkbuf[NFS_MAXPATHLEN + 1]; 47138451Smsmith int nlinks = 0; 47238451Smsmith#endif 47338451Smsmith int error; 47439468Smsmith char *path; 47538451Smsmith 47638451Smsmith#ifdef NFS_DEBUG 47738451Smsmith if (debug) 478185155Sluigi printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 47938451Smsmith#endif 48038451Smsmith if (!rootpath[0]) { 48138451Smsmith printf("no rootpath, no nfs\n"); 48238451Smsmith return (ENXIO); 48338451Smsmith } 48438451Smsmith 485177935Sdfr /* 486177935Sdfr * This is silly - we should look at dv_type but that value is 487177935Sdfr * arch dependant and we can't use it here. 488177935Sdfr */ 489111776Smarcel#ifndef __i386__ 49099558Sjake if (strcmp(f->f_dev->dv_name, "net") != 0) 49199558Sjake return(EINVAL); 492177935Sdfr#else 493177935Sdfr if (strcmp(f->f_dev->dv_name, "pxe") != 0) 494177935Sdfr return(EINVAL); 49599558Sjake#endif 496111776Smarcel 49738451Smsmith if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 49838451Smsmith return(EINVAL); 49938451Smsmith 50038451Smsmith /* Bind to a reserved port. */ 50138451Smsmith desc->myport = htons(--rpc_port); 50238451Smsmith desc->destip = rootip; 50338451Smsmith if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh))) 50438451Smsmith return (error); 505240774Smav nfs_root_node.fa.fa_type = htonl(NFDIR); 506240774Smav nfs_root_node.fa.fa_mode = htonl(0755); 507240774Smav nfs_root_node.fa.fa_nlink = htonl(2); 50838451Smsmith nfs_root_node.iodesc = desc; 50938451Smsmith 510101112Sjake fh = &nfs_root_node.fh[0]; 511101112Sjake buf[0] = 'X'; 512101112Sjake cp = &buf[1]; 513101112Sjake for (i = 0; i < NFS_FHSIZE; i++, cp += 2) 514101112Sjake sprintf(cp, "%02x", fh[i]); 515101112Sjake sprintf(cp, "X"); 516101112Sjake setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 517101112Sjake setenv("boot.nfsroot.path", rootpath, 1); 518101112Sjake setenv("boot.nfsroot.nfshandle", buf, 1); 519101112Sjake 520240774Smav /* Allocate file system specific data structure */ 521240774Smav currfd = malloc(sizeof(*newfd)); 522240774Smav if (currfd == NULL) { 523240774Smav error = ENOMEM; 524240774Smav goto out; 525240774Smav } 526240774Smav 52738451Smsmith#ifndef NFS_NOSYMLINK 528240774Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 52938451Smsmith newfd = 0; 53038451Smsmith 53139468Smsmith cp = path = strdup(upath); 53239468Smsmith if (path == NULL) { 53339468Smsmith error = ENOMEM; 53439468Smsmith goto out; 53539468Smsmith } 53638451Smsmith while (*cp) { 53738451Smsmith /* 53838451Smsmith * Remove extra separators 53938451Smsmith */ 54038451Smsmith while (*cp == '/') 54138451Smsmith cp++; 54238451Smsmith 54338451Smsmith if (*cp == '\0') 54438451Smsmith break; 54538451Smsmith /* 54638451Smsmith * Check that current node is a directory. 54738451Smsmith */ 54838451Smsmith if (currfd->fa.fa_type != htonl(NFDIR)) { 54938451Smsmith error = ENOTDIR; 55038451Smsmith goto out; 55138451Smsmith } 552197178Semaste 55338451Smsmith /* allocate file system specific data structure */ 55438451Smsmith newfd = malloc(sizeof(*newfd)); 55538451Smsmith newfd->iodesc = currfd->iodesc; 556197178Semaste 55738451Smsmith /* 55838451Smsmith * Get next component of path name. 55938451Smsmith */ 56038451Smsmith { 56192913Sobrien int len = 0; 562197178Semaste 56338451Smsmith ncp = cp; 56438451Smsmith while ((c = *cp) != '\0' && c != '/') { 56538451Smsmith if (++len > NFS_MAXNAMLEN) { 56638451Smsmith error = ENOENT; 56738451Smsmith goto out; 56838451Smsmith } 56938451Smsmith cp++; 57038451Smsmith } 57138451Smsmith *cp = '\0'; 57238451Smsmith } 573197178Semaste 57438451Smsmith /* lookup a file handle */ 57538451Smsmith error = nfs_lookupfh(currfd, ncp, newfd); 57638451Smsmith *cp = c; 57738451Smsmith if (error) 57838451Smsmith goto out; 579197178Semaste 58038451Smsmith /* 58138451Smsmith * Check for symbolic link 58238451Smsmith */ 58338451Smsmith if (newfd->fa.fa_type == htonl(NFLNK)) { 58438451Smsmith int link_len, len; 585197178Semaste 58638451Smsmith error = nfs_readlink(newfd, linkbuf); 58738451Smsmith if (error) 58838451Smsmith goto out; 58938451Smsmith 59038451Smsmith link_len = strlen(linkbuf); 59138451Smsmith len = strlen(cp); 59238451Smsmith 59338451Smsmith if (link_len + len > MAXPATHLEN 59438451Smsmith || ++nlinks > MAXSYMLINKS) { 59538451Smsmith error = ENOENT; 59638451Smsmith goto out; 59738451Smsmith } 59838451Smsmith 59938451Smsmith bcopy(cp, &namebuf[link_len], len + 1); 60038451Smsmith bcopy(linkbuf, namebuf, link_len); 601197178Semaste 60238451Smsmith /* 60338451Smsmith * If absolute pathname, restart at root. 60438451Smsmith * If relative pathname, restart at parent directory. 60538451Smsmith */ 60638451Smsmith cp = namebuf; 607240774Smav if (*cp == '/') 608240774Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 60938451Smsmith 61038451Smsmith free(newfd); 61138451Smsmith newfd = 0; 612197178Semaste 61338451Smsmith continue; 61438451Smsmith } 615197178Semaste 616240774Smav free(currfd); 61738451Smsmith currfd = newfd; 61838451Smsmith newfd = 0; 61938451Smsmith } 62038451Smsmith 62138451Smsmith error = 0; 62238451Smsmith 62338451Smsmithout: 624240881Skevlo free(newfd); 625240881Skevlo free(path); 62638451Smsmith#else 62738451Smsmith currfd->iodesc = desc; 62838451Smsmith 62939468Smsmith error = nfs_lookupfh(&nfs_root_node, upath, currfd); 63038451Smsmith#endif 63138451Smsmith if (!error) { 632240774Smav currfd->off = 0; 63338451Smsmith f->f_fsdata = (void *)currfd; 63438451Smsmith return (0); 63538451Smsmith } 636197178Semaste 63738451Smsmith#ifdef NFS_DEBUG 63838451Smsmith if (debug) 63938451Smsmith printf("nfs_open: %s lookupfh failed: %s\n", 64038451Smsmith path, strerror(error)); 64138451Smsmith#endif 642240774Smav free(currfd); 64338451Smsmith 64438451Smsmith return (error); 64538451Smsmith} 64638451Smsmith 64738451Smsmithint 648197178Semastenfs_close(struct open_file *f) 64938451Smsmith{ 65092913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 65138451Smsmith 65238451Smsmith#ifdef NFS_DEBUG 65338451Smsmith if (debug) 65438451Smsmith printf("nfs_close: fp=0x%lx\n", (u_long)fp); 65538451Smsmith#endif 65638451Smsmith 657240774Smav if (fp) 65838451Smsmith free(fp); 65938451Smsmith f->f_fsdata = (void *)0; 660197178Semaste 66138451Smsmith return (0); 66238451Smsmith} 66338451Smsmith 66438451Smsmith/* 66538451Smsmith * read a portion of a file 66638451Smsmith */ 66738451Smsmithint 668197178Semastenfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 66938451Smsmith{ 67092913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 67192913Sobrien ssize_t cc; 67292913Sobrien char *addr = buf; 673197178Semaste 67438451Smsmith#ifdef NFS_DEBUG 67538451Smsmith if (debug) 67638451Smsmith printf("nfs_read: size=%lu off=%d\n", (u_long)size, 67738451Smsmith (int)fp->off); 67838451Smsmith#endif 67938451Smsmith while ((int)size > 0) { 680278602Sian twiddle(16); 68138451Smsmith cc = nfs_readdata(fp, fp->off, (void *)addr, size); 68238451Smsmith /* XXX maybe should retry on certain errors */ 68338451Smsmith if (cc == -1) { 68438451Smsmith#ifdef NFS_DEBUG 68538451Smsmith if (debug) 68638451Smsmith printf("nfs_read: read: %s", strerror(errno)); 68738451Smsmith#endif 68838451Smsmith return (errno); /* XXX - from nfs_readdata */ 68938451Smsmith } 69038451Smsmith if (cc == 0) { 69138451Smsmith#ifdef NFS_DEBUG 69238451Smsmith if (debug) 69338451Smsmith printf("nfs_read: hit EOF unexpectantly"); 69438451Smsmith#endif 69538451Smsmith goto ret; 69638451Smsmith } 69738451Smsmith fp->off += cc; 69838451Smsmith addr += cc; 69938451Smsmith size -= cc; 70038451Smsmith } 70138451Smsmithret: 70238451Smsmith if (resid) 70338451Smsmith *resid = size; 70438451Smsmith 70538451Smsmith return (0); 70638451Smsmith} 70738451Smsmith 70838451Smsmith/* 70938451Smsmith * Not implemented. 71038451Smsmith */ 71138451Smsmithint 712197178Semastenfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 71338451Smsmith{ 71438451Smsmith return (EROFS); 71538451Smsmith} 71638451Smsmith 71738451Smsmithoff_t 718197178Semastenfs_seek(struct open_file *f, off_t offset, int where) 71938451Smsmith{ 72092913Sobrien struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 72138451Smsmith n_long size = ntohl(d->fa.fa_size); 72238451Smsmith 72338451Smsmith switch (where) { 72438451Smsmith case SEEK_SET: 72538451Smsmith d->off = offset; 72638451Smsmith break; 72738451Smsmith case SEEK_CUR: 72838451Smsmith d->off += offset; 72938451Smsmith break; 73038451Smsmith case SEEK_END: 73138451Smsmith d->off = size - offset; 73238451Smsmith break; 73338451Smsmith default: 734124811Sjhb errno = EINVAL; 73538451Smsmith return (-1); 73638451Smsmith } 73738451Smsmith 73838451Smsmith return (d->off); 73938451Smsmith} 74038451Smsmith 74138451Smsmith/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */ 74238451Smsmithint nfs_stat_types[8] = { 74338451Smsmith 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 }; 74438451Smsmith 74538451Smsmithint 746197178Semastenfs_stat(struct open_file *f, struct stat *sb) 74738451Smsmith{ 74838451Smsmith struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 74992913Sobrien n_long ftype, mode; 75038451Smsmith 75138451Smsmith ftype = ntohl(fp->fa.fa_type); 75238451Smsmith mode = ntohl(fp->fa.fa_mode); 75338451Smsmith mode |= nfs_stat_types[ftype & 7]; 75438451Smsmith 75538451Smsmith sb->st_mode = mode; 75638451Smsmith sb->st_nlink = ntohl(fp->fa.fa_nlink); 75738451Smsmith sb->st_uid = ntohl(fp->fa.fa_uid); 75838451Smsmith sb->st_gid = ntohl(fp->fa.fa_gid); 75938451Smsmith sb->st_size = ntohl(fp->fa.fa_size); 76038451Smsmith 76138451Smsmith return (0); 76238451Smsmith} 76359853Sps 76459853Spsstatic int 76559853Spsnfs_readdir(struct open_file *f, struct dirent *d) 76659853Sps{ 76792913Sobrien struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 76859853Sps struct nfs_readdir_args *args; 76959853Sps struct nfs_readdir_data *rd; 77059853Sps struct nfs_readdir_off *roff = NULL; 77159853Sps static char *buf; 772240780Smav static struct nfs_iodesc *pfp = NULL; 77359853Sps static n_long cookie = 0; 77459853Sps size_t cc; 77559853Sps n_long eof; 776197178Semaste 77759853Sps struct { 77859853Sps n_long h[RPC_HEADER_WORDS]; 77959853Sps struct nfs_readdir_args d; 78059853Sps } sdata; 78159853Sps static struct { 78259853Sps n_long h[RPC_HEADER_WORDS]; 78359853Sps u_char d[NFS_READDIRSIZE]; 78459853Sps } rdata; 78559853Sps 786240780Smav if (fp != pfp || fp->off != cookie) { 787240780Smav pfp = NULL; 78859853Sps refill: 78959853Sps args = &sdata.d; 79059853Sps bzero(args, sizeof(*args)); 79159853Sps 79259853Sps bcopy(fp->fh, args->fh, NFS_FHSIZE); 793240780Smav args->cookie = htonl(fp->off); 79459853Sps args->count = htonl(NFS_READDIRSIZE); 795197178Semaste 79659853Sps cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR, 79759853Sps args, sizeof(*args), 79859853Sps rdata.d, sizeof(rdata.d)); 79959853Sps buf = rdata.d; 80059853Sps roff = (struct nfs_readdir_off *)buf; 80159853Sps if (ntohl(roff->cookie) != 0) 802124811Sjhb return EIO; 803240780Smav pfp = fp; 804240780Smav cookie = fp->off; 80559853Sps } 80659853Sps roff = (struct nfs_readdir_off *)buf; 80759853Sps 80859853Sps if (ntohl(roff->follows) == 0) { 80959853Sps eof = ntohl((roff+1)->cookie); 81059853Sps if (eof) { 81159853Sps cookie = 0; 812124811Sjhb return ENOENT; 81359853Sps } 81459853Sps goto refill; 81559853Sps } 81659853Sps 81759853Sps buf += sizeof(struct nfs_readdir_off); 81859853Sps rd = (struct nfs_readdir_data *)buf; 81959853Sps d->d_namlen = ntohl(rd->len); 82059853Sps bcopy(rd->name, d->d_name, d->d_namlen); 82159853Sps d->d_name[d->d_namlen] = '\0'; 82259853Sps 82359853Sps buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4)); 82459853Sps roff = (struct nfs_readdir_off *)buf; 825240780Smav fp->off = cookie = ntohl(roff->cookie); 82659853Sps return 0; 82759853Sps} 828212125Srmacklem#else /* !OLD_NFSV2 */ 829212125Srmacklem/* 830212125Srmacklem * Fetch the root file handle (call mount daemon) 831212125Srmacklem * Return zero or error number. 832212125Srmacklem */ 833212125Srmacklemint 834212125Srmacklemnfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 835212125Srmacklem{ 836212125Srmacklem int len; 837212125Srmacklem struct args { 838212125Srmacklem uint32_t len; 839212125Srmacklem char path[FNAME_SIZE]; 840212125Srmacklem } *args; 841212125Srmacklem struct repl { 842212125Srmacklem uint32_t errno; 843212125Srmacklem uint32_t fhsize; 844212125Srmacklem u_char fh[NFS_V3MAXFHSIZE]; 845212125Srmacklem uint32_t authcnt; 846212125Srmacklem uint32_t auth[7]; 847212125Srmacklem } *repl; 848212125Srmacklem struct { 849212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 850212125Srmacklem struct args d; 851212125Srmacklem } sdata; 852212125Srmacklem struct { 853212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 854212125Srmacklem struct repl d; 855212125Srmacklem } rdata; 856212125Srmacklem size_t cc; 857212125Srmacklem 858212125Srmacklem#ifdef NFS_DEBUG 859212125Srmacklem if (debug) 860212125Srmacklem printf("nfs_getrootfh: %s\n", path); 861212125Srmacklem#endif 862212125Srmacklem 863212125Srmacklem args = &sdata.d; 864212125Srmacklem repl = &rdata.d; 865212125Srmacklem 866212125Srmacklem bzero(args, sizeof(*args)); 867212125Srmacklem len = strlen(path); 868212125Srmacklem if (len > sizeof(args->path)) 869212125Srmacklem len = sizeof(args->path); 870212125Srmacklem args->len = htonl(len); 871212125Srmacklem bcopy(path, args->path, len); 872212125Srmacklem len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 873212125Srmacklem 874212125Srmacklem cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 875212125Srmacklem args, len, repl, sizeof(*repl)); 876212125Srmacklem if (cc == -1) 877212125Srmacklem /* errno was set by rpc_call */ 878212125Srmacklem return (errno); 879212125Srmacklem if (cc < 2 * sizeof (uint32_t)) 880212125Srmacklem return (EBADRPC); 881212125Srmacklem if (repl->errno != 0) 882212125Srmacklem return (ntohl(repl->errno)); 883212125Srmacklem *fhlenp = ntohl(repl->fhsize); 884212125Srmacklem bcopy(repl->fh, fhp, *fhlenp); 885212125Srmacklem return (0); 886212125Srmacklem} 887212125Srmacklem 888212125Srmacklem/* 889212125Srmacklem * Lookup a file. Store handle and attributes. 890212125Srmacklem * Return zero or error number. 891212125Srmacklem */ 892212125Srmacklemint 893212125Srmacklemnfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 894212125Srmacklem{ 895212125Srmacklem int len, rlen, pos; 896212125Srmacklem struct args { 897212125Srmacklem uint32_t fhsize; 898212125Srmacklem uint32_t fhplusname[1 + 899212125Srmacklem (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 900212125Srmacklem } *args; 901212125Srmacklem struct repl { 902212125Srmacklem uint32_t errno; 903212125Srmacklem uint32_t fhsize; 904212125Srmacklem uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 905212125Srmacklem 2 * (sizeof(uint32_t) + 906212125Srmacklem sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 907212125Srmacklem } *repl; 908212125Srmacklem struct { 909212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 910212125Srmacklem struct args d; 911212125Srmacklem } sdata; 912212125Srmacklem struct { 913212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 914212125Srmacklem struct repl d; 915212125Srmacklem } rdata; 916212125Srmacklem ssize_t cc; 917212125Srmacklem 918212125Srmacklem#ifdef NFS_DEBUG 919212125Srmacklem if (debug) 920212125Srmacklem printf("lookupfh: called\n"); 921212125Srmacklem#endif 922212125Srmacklem 923212125Srmacklem args = &sdata.d; 924212125Srmacklem repl = &rdata.d; 925212125Srmacklem 926212125Srmacklem bzero(args, sizeof(*args)); 927212125Srmacklem args->fhsize = htonl(d->fhsize); 928212125Srmacklem bcopy(d->fh, args->fhplusname, d->fhsize); 929212125Srmacklem len = strlen(name); 930212125Srmacklem if (len > FNAME_SIZE) 931212125Srmacklem len = FNAME_SIZE; 932212125Srmacklem pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 933212125Srmacklem args->fhplusname[pos++] = htonl(len); 934212125Srmacklem bcopy(name, &args->fhplusname[pos], len); 935212125Srmacklem len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 936212125Srmacklem roundup(len, sizeof(uint32_t)); 937212125Srmacklem 938212125Srmacklem rlen = sizeof(*repl); 939212125Srmacklem 940212125Srmacklem cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 941212125Srmacklem args, len, repl, rlen); 942212125Srmacklem if (cc == -1) 943212125Srmacklem return (errno); /* XXX - from rpc_call */ 944212125Srmacklem if (cc < 2 * sizeof(uint32_t)) 945212125Srmacklem return (EIO); 946212125Srmacklem if (repl->errno != 0) 947212125Srmacklem /* saerrno.h now matches NFS error numbers. */ 948212125Srmacklem return (ntohl(repl->errno)); 949212125Srmacklem newfd->fhsize = ntohl(repl->fhsize); 950212125Srmacklem bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 951212125Srmacklem pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 952212125Srmacklem if (repl->fhplusattr[pos++] == 0) 953212125Srmacklem return (EIO); 954212125Srmacklem bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 955212125Srmacklem return (0); 956212125Srmacklem} 957212125Srmacklem 958212125Srmacklem#ifndef NFS_NOSYMLINK 959212125Srmacklem/* 960212125Srmacklem * Get the destination of a symbolic link. 961212125Srmacklem */ 962212125Srmacklemint 963212125Srmacklemnfs_readlink(struct nfs_iodesc *d, char *buf) 964212125Srmacklem{ 965212125Srmacklem struct args { 966212125Srmacklem uint32_t fhsize; 967212125Srmacklem u_char fh[NFS_V3MAXFHSIZE]; 968212125Srmacklem } *args; 969212125Srmacklem struct repl { 970212125Srmacklem uint32_t errno; 971212125Srmacklem uint32_t ok; 972212125Srmacklem struct nfsv3_fattrs fa; 973212125Srmacklem uint32_t len; 974212125Srmacklem u_char path[NFS_MAXPATHLEN]; 975212125Srmacklem } *repl; 976212125Srmacklem struct { 977212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 978212125Srmacklem struct args d; 979212125Srmacklem } sdata; 980212125Srmacklem struct { 981212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 982212125Srmacklem struct repl d; 983212125Srmacklem } rdata; 984212125Srmacklem ssize_t cc; 985212125Srmacklem 986212125Srmacklem#ifdef NFS_DEBUG 987212125Srmacklem if (debug) 988212125Srmacklem printf("readlink: called\n"); 989212125Srmacklem#endif 990212125Srmacklem 991212125Srmacklem args = &sdata.d; 992212125Srmacklem repl = &rdata.d; 993212125Srmacklem 994212125Srmacklem bzero(args, sizeof(*args)); 995212125Srmacklem args->fhsize = htonl(d->fhsize); 996212125Srmacklem bcopy(d->fh, args->fh, d->fhsize); 997212125Srmacklem cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 998212125Srmacklem args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 999212125Srmacklem repl, sizeof(*repl)); 1000212125Srmacklem if (cc == -1) 1001212125Srmacklem return (errno); 1002212125Srmacklem 1003212125Srmacklem if (cc < 2 * sizeof(uint32_t)) 1004212125Srmacklem return (EIO); 1005212125Srmacklem 1006212125Srmacklem if (repl->errno != 0) 1007212125Srmacklem return (ntohl(repl->errno)); 1008212125Srmacklem 1009212125Srmacklem if (repl->ok == 0) 1010212125Srmacklem return (EIO); 1011212125Srmacklem 1012212125Srmacklem repl->len = ntohl(repl->len); 1013212125Srmacklem if (repl->len > NFS_MAXPATHLEN) 1014212125Srmacklem return (ENAMETOOLONG); 1015212125Srmacklem 1016212125Srmacklem bcopy(repl->path, buf, repl->len); 1017212125Srmacklem buf[repl->len] = 0; 1018212125Srmacklem return (0); 1019212125Srmacklem} 1020212125Srmacklem#endif 1021212125Srmacklem 1022212125Srmacklem/* 1023212125Srmacklem * Read data from a file. 1024212125Srmacklem * Return transfer count or -1 (and set errno) 1025212125Srmacklem */ 1026212125Srmacklemssize_t 1027212125Srmacklemnfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 1028212125Srmacklem{ 1029212125Srmacklem struct args { 1030212125Srmacklem uint32_t fhsize; 1031212125Srmacklem uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 1032212125Srmacklem } *args; 1033212125Srmacklem struct repl { 1034212125Srmacklem uint32_t errno; 1035212125Srmacklem uint32_t ok; 1036212125Srmacklem struct nfsv3_fattrs fa; 1037212125Srmacklem uint32_t count; 1038212125Srmacklem uint32_t eof; 1039212125Srmacklem uint32_t len; 1040307203Ssephe u_char data[NFSREAD_MAX_SIZE]; 1041212125Srmacklem } *repl; 1042212125Srmacklem struct { 1043212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1044212125Srmacklem struct args d; 1045212125Srmacklem } sdata; 1046212125Srmacklem struct { 1047212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1048212125Srmacklem struct repl d; 1049212125Srmacklem } rdata; 1050212125Srmacklem size_t cc; 1051212125Srmacklem long x; 1052212125Srmacklem int hlen, rlen, pos; 1053212125Srmacklem 1054212125Srmacklem args = &sdata.d; 1055212125Srmacklem repl = &rdata.d; 1056212125Srmacklem 1057212125Srmacklem bzero(args, sizeof(*args)); 1058212125Srmacklem args->fhsize = htonl(d->fhsize); 1059212125Srmacklem bcopy(d->fh, args->fhoffcnt, d->fhsize); 1060212125Srmacklem pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1061212125Srmacklem args->fhoffcnt[pos++] = 0; 1062212125Srmacklem args->fhoffcnt[pos++] = htonl((uint32_t)off); 1063307203Ssephe if (len > nfs_read_size) 1064307203Ssephe len = nfs_read_size; 1065212125Srmacklem args->fhoffcnt[pos] = htonl((uint32_t)len); 1066307203Ssephe hlen = offsetof(struct repl, data[0]); 1067212125Srmacklem 1068212125Srmacklem cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 1069212125Srmacklem args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 1070212125Srmacklem repl, sizeof(*repl)); 1071212125Srmacklem if (cc == -1) 1072212125Srmacklem /* errno was already set by rpc_call */ 1073212125Srmacklem return (-1); 1074212125Srmacklem if (cc < hlen) { 1075212125Srmacklem errno = EBADRPC; 1076212125Srmacklem return (-1); 1077212125Srmacklem } 1078212125Srmacklem if (repl->errno != 0) { 1079212125Srmacklem errno = ntohl(repl->errno); 1080212125Srmacklem return (-1); 1081212125Srmacklem } 1082212125Srmacklem rlen = cc - hlen; 1083212125Srmacklem x = ntohl(repl->count); 1084212125Srmacklem if (rlen < x) { 1085212125Srmacklem printf("nfsread: short packet, %d < %ld\n", rlen, x); 1086212125Srmacklem errno = EBADRPC; 1087212125Srmacklem return (-1); 1088212125Srmacklem } 1089212125Srmacklem bcopy(repl->data, addr, x); 1090212125Srmacklem return (x); 1091212125Srmacklem} 1092212125Srmacklem 1093212125Srmacklem/* 1094212125Srmacklem * Open a file. 1095212125Srmacklem * return zero or error number 1096212125Srmacklem */ 1097212125Srmacklemint 1098212125Srmacklemnfs_open(const char *upath, struct open_file *f) 1099212125Srmacklem{ 1100212125Srmacklem struct iodesc *desc; 1101212125Srmacklem struct nfs_iodesc *currfd; 1102212125Srmacklem char buf[2 * NFS_V3MAXFHSIZE + 3]; 1103212125Srmacklem u_char *fh; 1104212125Srmacklem char *cp; 1105212125Srmacklem int i; 1106212125Srmacklem#ifndef NFS_NOSYMLINK 1107212125Srmacklem struct nfs_iodesc *newfd; 1108212125Srmacklem struct nfsv3_fattrs *fa; 1109212125Srmacklem char *ncp; 1110212125Srmacklem int c; 1111212125Srmacklem char namebuf[NFS_MAXPATHLEN + 1]; 1112212125Srmacklem char linkbuf[NFS_MAXPATHLEN + 1]; 1113212125Srmacklem int nlinks = 0; 1114212125Srmacklem#endif 1115212125Srmacklem int error; 1116212125Srmacklem char *path; 1117212125Srmacklem 1118212125Srmacklem#ifdef NFS_DEBUG 1119212125Srmacklem if (debug) 1120212125Srmacklem printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 1121212125Srmacklem#endif 1122212125Srmacklem if (!rootpath[0]) { 1123212125Srmacklem printf("no rootpath, no nfs\n"); 1124212125Srmacklem return (ENXIO); 1125212125Srmacklem } 1126212125Srmacklem 1127212125Srmacklem /* 1128212125Srmacklem * This is silly - we should look at dv_type but that value is 1129212125Srmacklem * arch dependant and we can't use it here. 1130212125Srmacklem */ 1131212125Srmacklem#ifndef __i386__ 1132212125Srmacklem if (strcmp(f->f_dev->dv_name, "net") != 0) 1133212125Srmacklem return (EINVAL); 1134212125Srmacklem#else 1135212125Srmacklem if (strcmp(f->f_dev->dv_name, "pxe") != 0) 1136212125Srmacklem return (EINVAL); 1137212125Srmacklem#endif 1138212125Srmacklem 1139212125Srmacklem if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 1140212125Srmacklem return (EINVAL); 1141212125Srmacklem 1142212125Srmacklem /* Bind to a reserved port. */ 1143212125Srmacklem desc->myport = htons(--rpc_port); 1144212125Srmacklem desc->destip = rootip; 1145212125Srmacklem if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 1146212125Srmacklem nfs_root_node.fh))) 1147212125Srmacklem return (error); 1148240774Smav nfs_root_node.fa.fa_type = htonl(NFDIR); 1149240774Smav nfs_root_node.fa.fa_mode = htonl(0755); 1150240774Smav nfs_root_node.fa.fa_nlink = htonl(2); 1151212125Srmacklem nfs_root_node.iodesc = desc; 1152212125Srmacklem 1153212125Srmacklem fh = &nfs_root_node.fh[0]; 1154212125Srmacklem buf[0] = 'X'; 1155212125Srmacklem cp = &buf[1]; 1156212125Srmacklem for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 1157212125Srmacklem sprintf(cp, "%02x", fh[i]); 1158212125Srmacklem sprintf(cp, "X"); 1159212125Srmacklem setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 1160212125Srmacklem setenv("boot.nfsroot.path", rootpath, 1); 1161212125Srmacklem setenv("boot.nfsroot.nfshandle", buf, 1); 1162212125Srmacklem sprintf(buf, "%d", nfs_root_node.fhsize); 1163212125Srmacklem setenv("boot.nfsroot.nfshandlelen", buf, 1); 1164212125Srmacklem 1165240774Smav /* Allocate file system specific data structure */ 1166240774Smav currfd = malloc(sizeof(*newfd)); 1167240774Smav if (currfd == NULL) { 1168240774Smav error = ENOMEM; 1169240774Smav goto out; 1170240774Smav } 1171212125Srmacklem#ifndef NFS_NOSYMLINK 1172240774Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1173212125Srmacklem newfd = 0; 1174212125Srmacklem 1175212125Srmacklem cp = path = strdup(upath); 1176212125Srmacklem if (path == NULL) { 1177212125Srmacklem error = ENOMEM; 1178212125Srmacklem goto out; 1179212125Srmacklem } 1180212125Srmacklem while (*cp) { 1181212125Srmacklem /* 1182212125Srmacklem * Remove extra separators 1183212125Srmacklem */ 1184212125Srmacklem while (*cp == '/') 1185212125Srmacklem cp++; 1186212125Srmacklem 1187212125Srmacklem if (*cp == '\0') 1188212125Srmacklem break; 1189212125Srmacklem /* 1190212125Srmacklem * Check that current node is a directory. 1191212125Srmacklem */ 1192212125Srmacklem if (currfd->fa.fa_type != htonl(NFDIR)) { 1193212125Srmacklem error = ENOTDIR; 1194212125Srmacklem goto out; 1195212125Srmacklem } 1196212125Srmacklem 1197212125Srmacklem /* allocate file system specific data structure */ 1198212125Srmacklem newfd = malloc(sizeof(*newfd)); 1199212125Srmacklem if (newfd == NULL) { 1200212125Srmacklem error = ENOMEM; 1201212125Srmacklem goto out; 1202212125Srmacklem } 1203212125Srmacklem newfd->iodesc = currfd->iodesc; 1204212125Srmacklem 1205212125Srmacklem /* 1206212125Srmacklem * Get next component of path name. 1207212125Srmacklem */ 1208212125Srmacklem { 1209212125Srmacklem int len = 0; 1210212125Srmacklem 1211212125Srmacklem ncp = cp; 1212212125Srmacklem while ((c = *cp) != '\0' && c != '/') { 1213212125Srmacklem if (++len > NFS_MAXNAMLEN) { 1214212125Srmacklem error = ENOENT; 1215212125Srmacklem goto out; 1216212125Srmacklem } 1217212125Srmacklem cp++; 1218212125Srmacklem } 1219212125Srmacklem *cp = '\0'; 1220212125Srmacklem } 1221212125Srmacklem 1222212125Srmacklem /* lookup a file handle */ 1223212125Srmacklem error = nfs_lookupfh(currfd, ncp, newfd); 1224212125Srmacklem *cp = c; 1225212125Srmacklem if (error) 1226212125Srmacklem goto out; 1227212125Srmacklem 1228212125Srmacklem /* 1229212125Srmacklem * Check for symbolic link 1230212125Srmacklem */ 1231212125Srmacklem if (newfd->fa.fa_type == htonl(NFLNK)) { 1232212125Srmacklem int link_len, len; 1233212125Srmacklem 1234212125Srmacklem error = nfs_readlink(newfd, linkbuf); 1235212125Srmacklem if (error) 1236212125Srmacklem goto out; 1237212125Srmacklem 1238212125Srmacklem link_len = strlen(linkbuf); 1239212125Srmacklem len = strlen(cp); 1240212125Srmacklem 1241212125Srmacklem if (link_len + len > MAXPATHLEN 1242212125Srmacklem || ++nlinks > MAXSYMLINKS) { 1243212125Srmacklem error = ENOENT; 1244212125Srmacklem goto out; 1245212125Srmacklem } 1246212125Srmacklem 1247212125Srmacklem bcopy(cp, &namebuf[link_len], len + 1); 1248212125Srmacklem bcopy(linkbuf, namebuf, link_len); 1249212125Srmacklem 1250212125Srmacklem /* 1251212125Srmacklem * If absolute pathname, restart at root. 1252212125Srmacklem * If relative pathname, restart at parent directory. 1253212125Srmacklem */ 1254212125Srmacklem cp = namebuf; 1255240774Smav if (*cp == '/') 1256240774Smav bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 1257212125Srmacklem 1258212125Srmacklem free(newfd); 1259212125Srmacklem newfd = 0; 1260212125Srmacklem 1261212125Srmacklem continue; 1262212125Srmacklem } 1263212125Srmacklem 1264240774Smav free(currfd); 1265212125Srmacklem currfd = newfd; 1266212125Srmacklem newfd = 0; 1267212125Srmacklem } 1268212125Srmacklem 1269212125Srmacklem error = 0; 1270212125Srmacklem 1271212125Srmacklemout: 1272240881Skevlo free(newfd); 1273240881Skevlo free(path); 1274212125Srmacklem#else 1275240774Smav currfd->iodesc = desc; 1276212125Srmacklem 1277240774Smav error = nfs_lookupfh(&nfs_root_node, upath, currfd); 1278212125Srmacklem#endif 1279212125Srmacklem if (!error) { 1280240774Smav currfd->off = 0; 1281240780Smav currfd->cookie = 0; 1282212125Srmacklem f->f_fsdata = (void *)currfd; 1283212125Srmacklem return (0); 1284212125Srmacklem } 1285212125Srmacklem 1286212125Srmacklem#ifdef NFS_DEBUG 1287212125Srmacklem if (debug) 1288212125Srmacklem printf("nfs_open: %s lookupfh failed: %s\n", 1289212125Srmacklem path, strerror(error)); 1290212125Srmacklem#endif 1291240774Smav free(currfd); 1292212125Srmacklem 1293212125Srmacklem return (error); 1294212125Srmacklem} 1295212125Srmacklem 1296212125Srmacklemint 1297212125Srmacklemnfs_close(struct open_file *f) 1298212125Srmacklem{ 1299212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1300212125Srmacklem 1301212125Srmacklem#ifdef NFS_DEBUG 1302212125Srmacklem if (debug) 1303212125Srmacklem printf("nfs_close: fp=0x%lx\n", (u_long)fp); 1304212125Srmacklem#endif 1305212125Srmacklem 1306240774Smav if (fp) 1307212125Srmacklem free(fp); 1308212125Srmacklem f->f_fsdata = (void *)0; 1309212125Srmacklem 1310212125Srmacklem return (0); 1311212125Srmacklem} 1312212125Srmacklem 1313212125Srmacklem/* 1314212125Srmacklem * read a portion of a file 1315212125Srmacklem */ 1316212125Srmacklemint 1317212125Srmacklemnfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 1318212125Srmacklem{ 1319212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1320212125Srmacklem ssize_t cc; 1321212125Srmacklem char *addr = buf; 1322212125Srmacklem 1323212125Srmacklem#ifdef NFS_DEBUG 1324212125Srmacklem if (debug) 1325212125Srmacklem printf("nfs_read: size=%lu off=%d\n", (u_long)size, 1326212125Srmacklem (int)fp->off); 1327212125Srmacklem#endif 1328212125Srmacklem while ((int)size > 0) { 1329278602Sian twiddle(16); 1330212125Srmacklem cc = nfs_readdata(fp, fp->off, (void *)addr, size); 1331212125Srmacklem /* XXX maybe should retry on certain errors */ 1332212125Srmacklem if (cc == -1) { 1333212125Srmacklem#ifdef NFS_DEBUG 1334212125Srmacklem if (debug) 1335212125Srmacklem printf("nfs_read: read: %s", strerror(errno)); 1336212125Srmacklem#endif 1337212125Srmacklem return (errno); /* XXX - from nfs_readdata */ 1338212125Srmacklem } 1339212125Srmacklem if (cc == 0) { 1340212125Srmacklem#ifdef NFS_DEBUG 1341212125Srmacklem if (debug) 1342212125Srmacklem printf("nfs_read: hit EOF unexpectantly"); 1343212125Srmacklem#endif 1344212125Srmacklem goto ret; 1345212125Srmacklem } 1346212125Srmacklem fp->off += cc; 1347212125Srmacklem addr += cc; 1348212125Srmacklem size -= cc; 1349212125Srmacklem } 1350212125Srmacklemret: 1351212125Srmacklem if (resid) 1352212125Srmacklem *resid = size; 1353212125Srmacklem 1354212125Srmacklem return (0); 1355212125Srmacklem} 1356212125Srmacklem 1357212125Srmacklem/* 1358212125Srmacklem * Not implemented. 1359212125Srmacklem */ 1360212125Srmacklemint 1361212125Srmacklemnfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 1362212125Srmacklem{ 1363212125Srmacklem return (EROFS); 1364212125Srmacklem} 1365212125Srmacklem 1366212125Srmacklemoff_t 1367212125Srmacklemnfs_seek(struct open_file *f, off_t offset, int where) 1368212125Srmacklem{ 1369212125Srmacklem struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 1370212125Srmacklem uint32_t size = ntohl(d->fa.fa_size.val[1]); 1371212125Srmacklem 1372212125Srmacklem switch (where) { 1373212125Srmacklem case SEEK_SET: 1374212125Srmacklem d->off = offset; 1375212125Srmacklem break; 1376212125Srmacklem case SEEK_CUR: 1377212125Srmacklem d->off += offset; 1378212125Srmacklem break; 1379212125Srmacklem case SEEK_END: 1380212125Srmacklem d->off = size - offset; 1381212125Srmacklem break; 1382212125Srmacklem default: 1383212125Srmacklem errno = EINVAL; 1384212125Srmacklem return (-1); 1385212125Srmacklem } 1386212125Srmacklem 1387212125Srmacklem return (d->off); 1388212125Srmacklem} 1389212125Srmacklem 1390212125Srmacklem/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 1391212125Srmacklemint nfs_stat_types[9] = { 1392212125Srmacklem 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 1393212125Srmacklem 1394212125Srmacklemint 1395212125Srmacklemnfs_stat(struct open_file *f, struct stat *sb) 1396212125Srmacklem{ 1397212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1398212125Srmacklem uint32_t ftype, mode; 1399212125Srmacklem 1400212125Srmacklem ftype = ntohl(fp->fa.fa_type); 1401212125Srmacklem mode = ntohl(fp->fa.fa_mode); 1402212125Srmacklem mode |= nfs_stat_types[ftype & 7]; 1403212125Srmacklem 1404212125Srmacklem sb->st_mode = mode; 1405212125Srmacklem sb->st_nlink = ntohl(fp->fa.fa_nlink); 1406212125Srmacklem sb->st_uid = ntohl(fp->fa.fa_uid); 1407212125Srmacklem sb->st_gid = ntohl(fp->fa.fa_gid); 1408212125Srmacklem sb->st_size = ntohl(fp->fa.fa_size.val[1]); 1409212125Srmacklem 1410212125Srmacklem return (0); 1411212125Srmacklem} 1412212125Srmacklem 1413212125Srmacklemstatic int 1414212125Srmacklemnfs_readdir(struct open_file *f, struct dirent *d) 1415212125Srmacklem{ 1416212125Srmacklem struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 1417212125Srmacklem struct nfsv3_readdir_repl *repl; 1418212125Srmacklem struct nfsv3_readdir_entry *rent; 1419212125Srmacklem static char *buf; 1420240780Smav static struct nfs_iodesc *pfp = NULL; 1421240780Smav static uint64_t cookie = 0; 1422212125Srmacklem size_t cc; 1423212125Srmacklem int pos; 1424212125Srmacklem 1425212125Srmacklem struct args { 1426212125Srmacklem uint32_t fhsize; 1427212125Srmacklem uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 1428212125Srmacklem } *args; 1429212125Srmacklem struct { 1430212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1431212125Srmacklem struct args d; 1432212125Srmacklem } sdata; 1433212125Srmacklem static struct { 1434212125Srmacklem uint32_t h[RPC_HEADER_WORDS]; 1435212125Srmacklem u_char d[NFS_READDIRSIZE]; 1436212125Srmacklem } rdata; 1437212125Srmacklem 1438240780Smav if (fp != pfp || fp->off != cookie) { 1439240780Smav pfp = NULL; 1440212125Srmacklem refill: 1441212125Srmacklem args = &sdata.d; 1442212125Srmacklem bzero(args, sizeof(*args)); 1443212125Srmacklem 1444212125Srmacklem args->fhsize = htonl(fp->fhsize); 1445212125Srmacklem bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 1446212125Srmacklem pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 1447240780Smav args->fhpluscookie[pos++] = htonl(fp->off >> 32); 1448240780Smav args->fhpluscookie[pos++] = htonl(fp->off); 1449240780Smav args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 1450240780Smav args->fhpluscookie[pos++] = htonl(fp->cookie); 1451212125Srmacklem args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 1452212125Srmacklem 1453212125Srmacklem cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 1454212125Srmacklem args, 6 * sizeof(uint32_t) + 1455212125Srmacklem roundup(fp->fhsize, sizeof(uint32_t)), 1456212125Srmacklem rdata.d, sizeof(rdata.d)); 1457212125Srmacklem buf = rdata.d; 1458212125Srmacklem repl = (struct nfsv3_readdir_repl *)buf; 1459212125Srmacklem if (repl->errno != 0) 1460212125Srmacklem return (ntohl(repl->errno)); 1461240780Smav pfp = fp; 1462240780Smav cookie = fp->off; 1463240780Smav fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 1464240780Smav ntohl(repl->cookiev1); 1465212125Srmacklem buf += sizeof (struct nfsv3_readdir_repl); 1466212125Srmacklem } 1467212125Srmacklem rent = (struct nfsv3_readdir_entry *)buf; 1468212125Srmacklem 1469212125Srmacklem if (rent->follows == 0) { 1470212125Srmacklem /* fid0 is actually eof */ 1471212125Srmacklem if (rent->fid0 != 0) { 1472240780Smav cookie = 0; 1473212125Srmacklem return (ENOENT); 1474212125Srmacklem } 1475212125Srmacklem goto refill; 1476212125Srmacklem } 1477212125Srmacklem 1478212125Srmacklem d->d_namlen = ntohl(rent->len); 1479212125Srmacklem bcopy(rent->nameplus, d->d_name, d->d_namlen); 1480212125Srmacklem d->d_name[d->d_namlen] = '\0'; 1481212125Srmacklem 1482212125Srmacklem pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 1483252468Smav fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 1484252468Smav ntohl(rent->nameplus[pos + 1]); 1485252468Smav pos += 2; 1486212125Srmacklem buf = (u_char *)&rent->nameplus[pos]; 1487212125Srmacklem return (0); 1488212125Srmacklem} 1489212125Srmacklem#endif /* OLD_NFSV2 */ 1490