1 /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */
4 * Copyright (c) 1993 John Brezak
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
36 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <netinet/in_systm.h>
54 #define NFSREAD_MIN_SIZE 1024
55 #define NFSREAD_MAX_SIZE 4096
57 /* Define our own NFS attributes without NQNFS stuff. */
71 struct nfsv2_time fa_atime;
72 struct nfsv2_time fa_mtime;
73 struct nfsv2_time fa_ctime;
76 struct nfs_read_args {
77 u_char fh[NFS_FHSIZE];
80 n_long xxx; /* XXX what's this for? */
83 /* Data part of nfs rpc reply (also the largest thing we receive) */
84 struct nfs_read_repl {
86 struct nfsv2_fattrs fa;
88 u_char data[NFSREAD_MAX_SIZE];
92 struct nfs_readlnk_repl {
95 char path[NFS_MAXPATHLEN];
99 struct nfs_readdir_args {
100 u_char fh[NFS_FHSIZE];
105 struct nfs_readdir_data {
111 struct nfs_readdir_off {
117 struct iodesc *iodesc;
119 u_char fh[NFS_FHSIZE];
120 struct nfsv2_fattrs fa; /* all in network order */
122 #else /* !OLD_NFSV2 */
124 /* NFSv3 definitions */
125 #define NFS_V3MAXFHSIZE 64
127 #define RPCMNT_VER3 3
128 #define NFSPROCV3_LOOKUP 3
129 #define NFSPROCV3_READLINK 5
130 #define NFSPROCV3_READ 6
131 #define NFSPROCV3_READDIR 16
142 struct nfsv3_fattrs {
153 struct nfsv3_time fa_atime;
154 struct nfsv3_time fa_mtime;
155 struct nfsv3_time fa_ctime;
159 * For NFSv3, the file handle is variable in size, so most fixed sized
160 * structures for arguments won't work. For most cases, a structure
161 * that starts with any fixed size section is followed by an array
162 * that covers the maximum size required.
164 struct nfsv3_readdir_repl {
167 struct nfsv3_fattrs fa;
172 struct nfsv3_readdir_entry {
177 uint32_t nameplus[0];
181 struct iodesc *iodesc;
184 u_char fh[NFS_V3MAXFHSIZE];
185 struct nfsv3_fattrs fa; /* all in network order */
188 #endif /* OLD_NFSV2 */
191 * XXX interactions with tftp? See nfswrapper.c for a confusing
194 int nfs_open(const char *path, struct open_file *f);
195 static int nfs_close(struct open_file *f);
196 static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
197 static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
198 static off_t nfs_seek(struct open_file *f, off_t offset, int where);
199 static int nfs_stat(struct open_file *f, struct stat *sb);
200 static int nfs_readdir(struct open_file *f, struct dirent *d);
202 struct nfs_iodesc nfs_root_node;
204 struct fs_ops nfs_fsops = {
215 static int nfs_read_size = NFSREAD_MIN_SIZE;
219 * Fetch the root file handle (call mount daemon)
220 * Return zero or error number.
223 nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
228 char path[FNAME_SIZE];
232 u_char fh[NFS_FHSIZE];
235 n_long h[RPC_HEADER_WORDS];
239 n_long h[RPC_HEADER_WORDS];
246 printf("nfs_getrootfh: %s\n", path);
252 bzero(args, sizeof(*args));
254 if (len > sizeof(args->path))
255 len = sizeof(args->path);
256 args->len = htonl(len);
257 bcopy(path, args->path, len);
258 len = 4 + roundup(len, 4);
260 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
261 args, len, repl, sizeof(*repl));
263 /* errno was set by rpc_call */
269 return (ntohl(repl->errno));
270 bcopy(repl->fh, fhp, sizeof(repl->fh));
273 * Improve boot performance over NFS
275 if (getenv("nfs.read_size") != NULL)
276 nfs_read_size = strtol(getenv("nfs.read_size"), NULL, 0);
277 if (nfs_read_size < NFSREAD_MIN_SIZE)
278 nfs_read_size = NFSREAD_MIN_SIZE;
279 if (nfs_read_size > NFSREAD_MAX_SIZE)
280 nfs_read_size = NFSREAD_MAX_SIZE;
286 * Lookup a file. Store handle and attributes.
287 * Return zero or error number.
290 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
294 u_char fh[NFS_FHSIZE];
296 char name[FNAME_SIZE];
300 u_char fh[NFS_FHSIZE];
301 struct nfsv2_fattrs fa;
304 n_long h[RPC_HEADER_WORDS];
308 n_long h[RPC_HEADER_WORDS];
315 printf("lookupfh: called\n");
321 bzero(args, sizeof(*args));
322 bcopy(d->fh, args->fh, sizeof(args->fh));
324 if (len > sizeof(args->name))
325 len = sizeof(args->name);
326 bcopy(name, args->name, len);
327 args->len = htonl(len);
328 len = 4 + roundup(len, 4);
331 rlen = sizeof(*repl);
333 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
334 args, len, repl, rlen);
336 return (errno); /* XXX - from rpc_call */
340 /* saerrno.h now matches NFS error numbers. */
341 return (ntohl(repl->errno));
343 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
344 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
348 #ifndef NFS_NOSYMLINK
350 * Get the destination of a symbolic link.
353 nfs_readlink(struct nfs_iodesc *d, char *buf)
356 n_long h[RPC_HEADER_WORDS];
357 u_char fh[NFS_FHSIZE];
360 n_long h[RPC_HEADER_WORDS];
361 struct nfs_readlnk_repl d;
367 printf("readlink: called\n");
370 bcopy(d->fh, sdata.fh, NFS_FHSIZE);
371 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
372 sdata.fh, NFS_FHSIZE,
373 &rdata.d, sizeof(rdata.d));
381 return (ntohl(rdata.d.errno));
383 rdata.d.len = ntohl(rdata.d.len);
384 if (rdata.d.len > NFS_MAXPATHLEN)
385 return (ENAMETOOLONG);
387 bcopy(rdata.d.path, buf, rdata.d.len);
388 buf[rdata.d.len] = 0;
394 * Read data from a file.
395 * Return transfer count or -1 (and set errno)
398 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
400 struct nfs_read_args *args;
401 struct nfs_read_repl *repl;
403 n_long h[RPC_HEADER_WORDS];
404 struct nfs_read_args d;
407 n_long h[RPC_HEADER_WORDS];
408 struct nfs_read_repl d;
417 bcopy(d->fh, args->fh, NFS_FHSIZE);
418 args->off = htonl((n_long)off);
419 if (len > nfs_read_size)
421 args->len = htonl((n_long)len);
422 args->xxx = htonl((n_long)0);
423 hlen = offsetof(struct nfs_read_rpl, data[0]);
425 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
427 repl, sizeof(*repl));
429 /* errno was already set by rpc_call */
437 errno = ntohl(repl->errno);
441 x = ntohl(repl->count);
443 printf("nfsread: short packet, %d < %ld\n", rlen, x);
447 bcopy(repl->data, addr, x);
453 * return zero or error number
456 nfs_open(const char *upath, struct open_file *f)
459 struct nfs_iodesc *currfd;
460 char buf[2 * NFS_FHSIZE + 3];
464 #ifndef NFS_NOSYMLINK
465 struct nfs_iodesc *newfd;
466 struct nfsv2_fattrs *fa;
469 char namebuf[NFS_MAXPATHLEN + 1];
470 char linkbuf[NFS_MAXPATHLEN + 1];
476 if (netproto != NET_NFS)
481 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
484 printf("no rootpath, no nfs\n");
489 * This is silly - we should look at dv_type but that value is
490 * arch dependant and we can't use it here.
493 if (strcmp(f->f_dev->dv_name, "net") != 0)
496 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
500 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
503 /* Bind to a reserved port. */
504 desc->myport = htons(--rpc_port);
505 desc->destip = rootip;
506 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
508 nfs_root_node.fa.fa_type = htonl(NFDIR);
509 nfs_root_node.fa.fa_mode = htonl(0755);
510 nfs_root_node.fa.fa_nlink = htonl(2);
511 nfs_root_node.iodesc = desc;
513 fh = &nfs_root_node.fh[0];
516 for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
517 sprintf(cp, "%02x", fh[i]);
519 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
520 setenv("boot.nfsroot.path", rootpath, 1);
521 setenv("boot.nfsroot.nfshandle", buf, 1);
523 /* Allocate file system specific data structure */
524 currfd = malloc(sizeof(*newfd));
525 if (currfd == NULL) {
530 #ifndef NFS_NOSYMLINK
531 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
534 cp = path = strdup(upath);
541 * Remove extra separators
549 * Check that current node is a directory.
551 if (currfd->fa.fa_type != htonl(NFDIR)) {
556 /* allocate file system specific data structure */
557 newfd = malloc(sizeof(*newfd));
558 newfd->iodesc = currfd->iodesc;
561 * Get next component of path name.
567 while ((c = *cp) != '\0' && c != '/') {
568 if (++len > NFS_MAXNAMLEN) {
577 /* lookup a file handle */
578 error = nfs_lookupfh(currfd, ncp, newfd);
584 * Check for symbolic link
586 if (newfd->fa.fa_type == htonl(NFLNK)) {
589 error = nfs_readlink(newfd, linkbuf);
593 link_len = strlen(linkbuf);
596 if (link_len + len > MAXPATHLEN
597 || ++nlinks > MAXSYMLINKS) {
602 bcopy(cp, &namebuf[link_len], len + 1);
603 bcopy(linkbuf, namebuf, link_len);
606 * If absolute pathname, restart at root.
607 * If relative pathname, restart at parent directory.
611 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
630 currfd->iodesc = desc;
632 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
636 f->f_fsdata = (void *)currfd;
642 printf("nfs_open: %s lookupfh failed: %s\n",
643 path, strerror(error));
651 nfs_close(struct open_file *f)
653 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
657 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
662 f->f_fsdata = (void *)0;
668 * read a portion of a file
671 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
673 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
679 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
682 while ((int)size > 0) {
684 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
685 /* XXX maybe should retry on certain errors */
689 printf("nfs_read: read: %s", strerror(errno));
691 return (errno); /* XXX - from nfs_readdata */
696 printf("nfs_read: hit EOF unexpectantly");
715 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
721 nfs_seek(struct open_file *f, off_t offset, int where)
723 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
724 n_long size = ntohl(d->fa.fa_size);
734 d->off = size - offset;
744 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
745 int nfs_stat_types[8] = {
746 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
749 nfs_stat(struct open_file *f, struct stat *sb)
751 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
754 ftype = ntohl(fp->fa.fa_type);
755 mode = ntohl(fp->fa.fa_mode);
756 mode |= nfs_stat_types[ftype & 7];
759 sb->st_nlink = ntohl(fp->fa.fa_nlink);
760 sb->st_uid = ntohl(fp->fa.fa_uid);
761 sb->st_gid = ntohl(fp->fa.fa_gid);
762 sb->st_size = ntohl(fp->fa.fa_size);
768 nfs_readdir(struct open_file *f, struct dirent *d)
770 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
771 struct nfs_readdir_args *args;
772 struct nfs_readdir_data *rd;
773 struct nfs_readdir_off *roff = NULL;
775 static struct nfs_iodesc *pfp = NULL;
776 static n_long cookie = 0;
781 n_long h[RPC_HEADER_WORDS];
782 struct nfs_readdir_args d;
785 n_long h[RPC_HEADER_WORDS];
786 u_char d[NFS_READDIRSIZE];
789 if (fp != pfp || fp->off != cookie) {
793 bzero(args, sizeof(*args));
795 bcopy(fp->fh, args->fh, NFS_FHSIZE);
796 args->cookie = htonl(fp->off);
797 args->count = htonl(NFS_READDIRSIZE);
799 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
801 rdata.d, sizeof(rdata.d));
803 roff = (struct nfs_readdir_off *)buf;
804 if (ntohl(roff->cookie) != 0)
809 roff = (struct nfs_readdir_off *)buf;
811 if (ntohl(roff->follows) == 0) {
812 eof = ntohl((roff+1)->cookie);
820 buf += sizeof(struct nfs_readdir_off);
821 rd = (struct nfs_readdir_data *)buf;
822 d->d_namlen = ntohl(rd->len);
823 bcopy(rd->name, d->d_name, d->d_namlen);
824 d->d_name[d->d_namlen] = '\0';
826 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
827 roff = (struct nfs_readdir_off *)buf;
828 fp->off = cookie = ntohl(roff->cookie);
831 #else /* !OLD_NFSV2 */
833 * Fetch the root file handle (call mount daemon)
834 * Return zero or error number.
837 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
842 char path[FNAME_SIZE];
847 u_char fh[NFS_V3MAXFHSIZE];
852 uint32_t h[RPC_HEADER_WORDS];
856 uint32_t h[RPC_HEADER_WORDS];
863 printf("nfs_getrootfh: %s\n", path);
869 bzero(args, sizeof(*args));
871 if (len > sizeof(args->path))
872 len = sizeof(args->path);
873 args->len = htonl(len);
874 bcopy(path, args->path, len);
875 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
877 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
878 args, len, repl, sizeof(*repl));
880 /* errno was set by rpc_call */
882 if (cc < 2 * sizeof (uint32_t))
884 if (repl->errno != 0)
885 return (ntohl(repl->errno));
886 *fhlenp = ntohl(repl->fhsize);
887 bcopy(repl->fh, fhp, *fhlenp);
892 * Lookup a file. Store handle and attributes.
893 * Return zero or error number.
896 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
901 uint32_t fhplusname[1 +
902 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
907 uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
908 2 * (sizeof(uint32_t) +
909 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
912 uint32_t h[RPC_HEADER_WORDS];
916 uint32_t h[RPC_HEADER_WORDS];
923 printf("lookupfh: called\n");
929 bzero(args, sizeof(*args));
930 args->fhsize = htonl(d->fhsize);
931 bcopy(d->fh, args->fhplusname, d->fhsize);
933 if (len > FNAME_SIZE)
935 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
936 args->fhplusname[pos++] = htonl(len);
937 bcopy(name, &args->fhplusname[pos], len);
938 len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
939 roundup(len, sizeof(uint32_t));
941 rlen = sizeof(*repl);
943 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
944 args, len, repl, rlen);
946 return (errno); /* XXX - from rpc_call */
947 if (cc < 2 * sizeof(uint32_t))
949 if (repl->errno != 0)
950 /* saerrno.h now matches NFS error numbers. */
951 return (ntohl(repl->errno));
952 newfd->fhsize = ntohl(repl->fhsize);
953 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
954 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
955 if (repl->fhplusattr[pos++] == 0)
957 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
961 #ifndef NFS_NOSYMLINK
963 * Get the destination of a symbolic link.
966 nfs_readlink(struct nfs_iodesc *d, char *buf)
970 u_char fh[NFS_V3MAXFHSIZE];
975 struct nfsv3_fattrs fa;
977 u_char path[NFS_MAXPATHLEN];
980 uint32_t h[RPC_HEADER_WORDS];
984 uint32_t h[RPC_HEADER_WORDS];
991 printf("readlink: called\n");
997 bzero(args, sizeof(*args));
998 args->fhsize = htonl(d->fhsize);
999 bcopy(d->fh, args->fh, d->fhsize);
1000 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
1001 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1002 repl, sizeof(*repl));
1006 if (cc < 2 * sizeof(uint32_t))
1009 if (repl->errno != 0)
1010 return (ntohl(repl->errno));
1015 repl->len = ntohl(repl->len);
1016 if (repl->len > NFS_MAXPATHLEN)
1017 return (ENAMETOOLONG);
1019 bcopy(repl->path, buf, repl->len);
1026 * Read data from a file.
1027 * Return transfer count or -1 (and set errno)
1030 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1034 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1039 struct nfsv3_fattrs fa;
1043 u_char data[NFSREAD_MAX_SIZE];
1046 uint32_t h[RPC_HEADER_WORDS];
1050 uint32_t h[RPC_HEADER_WORDS];
1055 int hlen, rlen, pos;
1060 bzero(args, sizeof(*args));
1061 args->fhsize = htonl(d->fhsize);
1062 bcopy(d->fh, args->fhoffcnt, d->fhsize);
1063 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1064 args->fhoffcnt[pos++] = 0;
1065 args->fhoffcnt[pos++] = htonl((uint32_t)off);
1066 if (len > nfs_read_size)
1067 len = nfs_read_size;
1068 args->fhoffcnt[pos] = htonl((uint32_t)len);
1069 hlen = offsetof(struct repl, data[0]);
1071 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1072 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1073 repl, sizeof(*repl));
1075 /* errno was already set by rpc_call */
1081 if (repl->errno != 0) {
1082 errno = ntohl(repl->errno);
1086 x = ntohl(repl->count);
1088 printf("nfsread: short packet, %d < %ld\n", rlen, x);
1092 bcopy(repl->data, addr, x);
1098 * return zero or error number
1101 nfs_open(const char *upath, struct open_file *f)
1103 struct iodesc *desc;
1104 struct nfs_iodesc *currfd;
1105 char buf[2 * NFS_V3MAXFHSIZE + 3];
1109 #ifndef NFS_NOSYMLINK
1110 struct nfs_iodesc *newfd;
1111 struct nfsv3_fattrs *fa;
1114 char namebuf[NFS_MAXPATHLEN + 1];
1115 char linkbuf[NFS_MAXPATHLEN + 1];
1121 if (netproto != NET_NFS)
1126 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1129 printf("no rootpath, no nfs\n");
1134 * This is silly - we should look at dv_type but that value is
1135 * arch dependant and we can't use it here.
1138 if (strcmp(f->f_dev->dv_name, "net") != 0)
1141 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1145 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1148 /* Bind to a reserved port. */
1149 desc->myport = htons(--rpc_port);
1150 desc->destip = rootip;
1151 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1154 nfs_root_node.fa.fa_type = htonl(NFDIR);
1155 nfs_root_node.fa.fa_mode = htonl(0755);
1156 nfs_root_node.fa.fa_nlink = htonl(2);
1157 nfs_root_node.iodesc = desc;
1159 fh = &nfs_root_node.fh[0];
1162 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1163 sprintf(cp, "%02x", fh[i]);
1165 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
1166 setenv("boot.nfsroot.path", rootpath, 1);
1167 setenv("boot.nfsroot.nfshandle", buf, 1);
1168 sprintf(buf, "%d", nfs_root_node.fhsize);
1169 setenv("boot.nfsroot.nfshandlelen", buf, 1);
1171 /* Allocate file system specific data structure */
1172 currfd = malloc(sizeof(*newfd));
1173 if (currfd == NULL) {
1177 #ifndef NFS_NOSYMLINK
1178 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1181 cp = path = strdup(upath);
1188 * Remove extra separators
1196 * Check that current node is a directory.
1198 if (currfd->fa.fa_type != htonl(NFDIR)) {
1203 /* allocate file system specific data structure */
1204 newfd = malloc(sizeof(*newfd));
1205 if (newfd == NULL) {
1209 newfd->iodesc = currfd->iodesc;
1212 * Get next component of path name.
1218 while ((c = *cp) != '\0' && c != '/') {
1219 if (++len > NFS_MAXNAMLEN) {
1228 /* lookup a file handle */
1229 error = nfs_lookupfh(currfd, ncp, newfd);
1235 * Check for symbolic link
1237 if (newfd->fa.fa_type == htonl(NFLNK)) {
1240 error = nfs_readlink(newfd, linkbuf);
1244 link_len = strlen(linkbuf);
1247 if (link_len + len > MAXPATHLEN
1248 || ++nlinks > MAXSYMLINKS) {
1253 bcopy(cp, &namebuf[link_len], len + 1);
1254 bcopy(linkbuf, namebuf, link_len);
1257 * If absolute pathname, restart at root.
1258 * If relative pathname, restart at parent directory.
1262 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1281 currfd->iodesc = desc;
1283 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1288 f->f_fsdata = (void *)currfd;
1294 printf("nfs_open: %s lookupfh failed: %s\n",
1295 path, strerror(error));
1303 nfs_close(struct open_file *f)
1305 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1309 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1314 f->f_fsdata = (void *)0;
1320 * read a portion of a file
1323 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1325 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1331 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1334 while ((int)size > 0) {
1336 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1337 /* XXX maybe should retry on certain errors */
1341 printf("nfs_read: read: %s", strerror(errno));
1343 return (errno); /* XXX - from nfs_readdata */
1348 printf("nfs_read: hit EOF unexpectantly");
1367 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1373 nfs_seek(struct open_file *f, off_t offset, int where)
1375 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1376 uint32_t size = ntohl(d->fa.fa_size.val[1]);
1386 d->off = size - offset;
1396 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1397 int nfs_stat_types[9] = {
1398 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1401 nfs_stat(struct open_file *f, struct stat *sb)
1403 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1404 uint32_t ftype, mode;
1406 ftype = ntohl(fp->fa.fa_type);
1407 mode = ntohl(fp->fa.fa_mode);
1408 mode |= nfs_stat_types[ftype & 7];
1411 sb->st_nlink = ntohl(fp->fa.fa_nlink);
1412 sb->st_uid = ntohl(fp->fa.fa_uid);
1413 sb->st_gid = ntohl(fp->fa.fa_gid);
1414 sb->st_size = ntohl(fp->fa.fa_size.val[1]);
1420 nfs_readdir(struct open_file *f, struct dirent *d)
1422 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1423 struct nfsv3_readdir_repl *repl;
1424 struct nfsv3_readdir_entry *rent;
1426 static struct nfs_iodesc *pfp = NULL;
1427 static uint64_t cookie = 0;
1433 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1436 uint32_t h[RPC_HEADER_WORDS];
1440 uint32_t h[RPC_HEADER_WORDS];
1441 u_char d[NFS_READDIRSIZE];
1444 if (fp != pfp || fp->off != cookie) {
1448 bzero(args, sizeof(*args));
1450 args->fhsize = htonl(fp->fhsize);
1451 bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1452 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1453 args->fhpluscookie[pos++] = htonl(fp->off >> 32);
1454 args->fhpluscookie[pos++] = htonl(fp->off);
1455 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
1456 args->fhpluscookie[pos++] = htonl(fp->cookie);
1457 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1459 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1460 args, 6 * sizeof(uint32_t) +
1461 roundup(fp->fhsize, sizeof(uint32_t)),
1462 rdata.d, sizeof(rdata.d));
1464 repl = (struct nfsv3_readdir_repl *)buf;
1465 if (repl->errno != 0)
1466 return (ntohl(repl->errno));
1469 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
1470 ntohl(repl->cookiev1);
1471 buf += sizeof (struct nfsv3_readdir_repl);
1473 rent = (struct nfsv3_readdir_entry *)buf;
1475 if (rent->follows == 0) {
1476 /* fid0 is actually eof */
1477 if (rent->fid0 != 0) {
1484 d->d_namlen = ntohl(rent->len);
1485 bcopy(rent->nameplus, d->d_name, d->d_namlen);
1486 d->d_name[d->d_namlen] = '\0';
1488 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1489 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
1490 ntohl(rent->nameplus[pos + 1]);
1492 buf = (u_char *)&rent->nameplus[pos];
1495 #endif /* OLD_NFSV2 */