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];
478 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
481 printf("no rootpath, no nfs\n");
486 * This is silly - we should look at dv_type but that value is
487 * arch dependant and we can't use it here.
490 if (strcmp(f->f_dev->dv_name, "net") != 0)
493 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
497 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
500 /* Bind to a reserved port. */
501 desc->myport = htons(--rpc_port);
502 desc->destip = rootip;
503 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
505 nfs_root_node.fa.fa_type = htonl(NFDIR);
506 nfs_root_node.fa.fa_mode = htonl(0755);
507 nfs_root_node.fa.fa_nlink = htonl(2);
508 nfs_root_node.iodesc = desc;
510 fh = &nfs_root_node.fh[0];
513 for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
514 sprintf(cp, "%02x", fh[i]);
516 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
517 setenv("boot.nfsroot.path", rootpath, 1);
518 setenv("boot.nfsroot.nfshandle", buf, 1);
520 /* Allocate file system specific data structure */
521 currfd = malloc(sizeof(*newfd));
522 if (currfd == NULL) {
527 #ifndef NFS_NOSYMLINK
528 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
531 cp = path = strdup(upath);
538 * Remove extra separators
546 * Check that current node is a directory.
548 if (currfd->fa.fa_type != htonl(NFDIR)) {
553 /* allocate file system specific data structure */
554 newfd = malloc(sizeof(*newfd));
555 newfd->iodesc = currfd->iodesc;
558 * Get next component of path name.
564 while ((c = *cp) != '\0' && c != '/') {
565 if (++len > NFS_MAXNAMLEN) {
574 /* lookup a file handle */
575 error = nfs_lookupfh(currfd, ncp, newfd);
581 * Check for symbolic link
583 if (newfd->fa.fa_type == htonl(NFLNK)) {
586 error = nfs_readlink(newfd, linkbuf);
590 link_len = strlen(linkbuf);
593 if (link_len + len > MAXPATHLEN
594 || ++nlinks > MAXSYMLINKS) {
599 bcopy(cp, &namebuf[link_len], len + 1);
600 bcopy(linkbuf, namebuf, link_len);
603 * If absolute pathname, restart at root.
604 * If relative pathname, restart at parent directory.
608 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
627 currfd->iodesc = desc;
629 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
633 f->f_fsdata = (void *)currfd;
639 printf("nfs_open: %s lookupfh failed: %s\n",
640 path, strerror(error));
648 nfs_close(struct open_file *f)
650 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
654 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
659 f->f_fsdata = (void *)0;
665 * read a portion of a file
668 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
670 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
676 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
679 while ((int)size > 0) {
681 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
682 /* XXX maybe should retry on certain errors */
686 printf("nfs_read: read: %s", strerror(errno));
688 return (errno); /* XXX - from nfs_readdata */
693 printf("nfs_read: hit EOF unexpectantly");
712 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
718 nfs_seek(struct open_file *f, off_t offset, int where)
720 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
721 n_long size = ntohl(d->fa.fa_size);
731 d->off = size - offset;
741 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
742 int nfs_stat_types[8] = {
743 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
746 nfs_stat(struct open_file *f, struct stat *sb)
748 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
751 ftype = ntohl(fp->fa.fa_type);
752 mode = ntohl(fp->fa.fa_mode);
753 mode |= nfs_stat_types[ftype & 7];
756 sb->st_nlink = ntohl(fp->fa.fa_nlink);
757 sb->st_uid = ntohl(fp->fa.fa_uid);
758 sb->st_gid = ntohl(fp->fa.fa_gid);
759 sb->st_size = ntohl(fp->fa.fa_size);
765 nfs_readdir(struct open_file *f, struct dirent *d)
767 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
768 struct nfs_readdir_args *args;
769 struct nfs_readdir_data *rd;
770 struct nfs_readdir_off *roff = NULL;
772 static struct nfs_iodesc *pfp = NULL;
773 static n_long cookie = 0;
778 n_long h[RPC_HEADER_WORDS];
779 struct nfs_readdir_args d;
782 n_long h[RPC_HEADER_WORDS];
783 u_char d[NFS_READDIRSIZE];
786 if (fp != pfp || fp->off != cookie) {
790 bzero(args, sizeof(*args));
792 bcopy(fp->fh, args->fh, NFS_FHSIZE);
793 args->cookie = htonl(fp->off);
794 args->count = htonl(NFS_READDIRSIZE);
796 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
798 rdata.d, sizeof(rdata.d));
800 roff = (struct nfs_readdir_off *)buf;
801 if (ntohl(roff->cookie) != 0)
806 roff = (struct nfs_readdir_off *)buf;
808 if (ntohl(roff->follows) == 0) {
809 eof = ntohl((roff+1)->cookie);
817 buf += sizeof(struct nfs_readdir_off);
818 rd = (struct nfs_readdir_data *)buf;
819 d->d_namlen = ntohl(rd->len);
820 bcopy(rd->name, d->d_name, d->d_namlen);
821 d->d_name[d->d_namlen] = '\0';
823 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
824 roff = (struct nfs_readdir_off *)buf;
825 fp->off = cookie = ntohl(roff->cookie);
828 #else /* !OLD_NFSV2 */
830 * Fetch the root file handle (call mount daemon)
831 * Return zero or error number.
834 nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
839 char path[FNAME_SIZE];
844 u_char fh[NFS_V3MAXFHSIZE];
849 uint32_t h[RPC_HEADER_WORDS];
853 uint32_t h[RPC_HEADER_WORDS];
860 printf("nfs_getrootfh: %s\n", path);
866 bzero(args, sizeof(*args));
868 if (len > sizeof(args->path))
869 len = sizeof(args->path);
870 args->len = htonl(len);
871 bcopy(path, args->path, len);
872 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
874 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
875 args, len, repl, sizeof(*repl));
877 /* errno was set by rpc_call */
879 if (cc < 2 * sizeof (uint32_t))
881 if (repl->errno != 0)
882 return (ntohl(repl->errno));
883 *fhlenp = ntohl(repl->fhsize);
884 bcopy(repl->fh, fhp, *fhlenp);
889 * Lookup a file. Store handle and attributes.
890 * Return zero or error number.
893 nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
898 uint32_t fhplusname[1 +
899 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
904 uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
905 2 * (sizeof(uint32_t) +
906 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
909 uint32_t h[RPC_HEADER_WORDS];
913 uint32_t h[RPC_HEADER_WORDS];
920 printf("lookupfh: called\n");
926 bzero(args, sizeof(*args));
927 args->fhsize = htonl(d->fhsize);
928 bcopy(d->fh, args->fhplusname, d->fhsize);
930 if (len > FNAME_SIZE)
932 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
933 args->fhplusname[pos++] = htonl(len);
934 bcopy(name, &args->fhplusname[pos], len);
935 len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
936 roundup(len, sizeof(uint32_t));
938 rlen = sizeof(*repl);
940 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
941 args, len, repl, rlen);
943 return (errno); /* XXX - from rpc_call */
944 if (cc < 2 * sizeof(uint32_t))
946 if (repl->errno != 0)
947 /* saerrno.h now matches NFS error numbers. */
948 return (ntohl(repl->errno));
949 newfd->fhsize = ntohl(repl->fhsize);
950 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
951 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
952 if (repl->fhplusattr[pos++] == 0)
954 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
958 #ifndef NFS_NOSYMLINK
960 * Get the destination of a symbolic link.
963 nfs_readlink(struct nfs_iodesc *d, char *buf)
967 u_char fh[NFS_V3MAXFHSIZE];
972 struct nfsv3_fattrs fa;
974 u_char path[NFS_MAXPATHLEN];
977 uint32_t h[RPC_HEADER_WORDS];
981 uint32_t h[RPC_HEADER_WORDS];
988 printf("readlink: called\n");
994 bzero(args, sizeof(*args));
995 args->fhsize = htonl(d->fhsize);
996 bcopy(d->fh, args->fh, d->fhsize);
997 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
998 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
999 repl, sizeof(*repl));
1003 if (cc < 2 * sizeof(uint32_t))
1006 if (repl->errno != 0)
1007 return (ntohl(repl->errno));
1012 repl->len = ntohl(repl->len);
1013 if (repl->len > NFS_MAXPATHLEN)
1014 return (ENAMETOOLONG);
1016 bcopy(repl->path, buf, repl->len);
1023 * Read data from a file.
1024 * Return transfer count or -1 (and set errno)
1027 nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1031 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1036 struct nfsv3_fattrs fa;
1040 u_char data[NFSREAD_MAX_SIZE];
1043 uint32_t h[RPC_HEADER_WORDS];
1047 uint32_t h[RPC_HEADER_WORDS];
1052 int hlen, rlen, pos;
1057 bzero(args, sizeof(*args));
1058 args->fhsize = htonl(d->fhsize);
1059 bcopy(d->fh, args->fhoffcnt, d->fhsize);
1060 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1061 args->fhoffcnt[pos++] = 0;
1062 args->fhoffcnt[pos++] = htonl((uint32_t)off);
1063 if (len > nfs_read_size)
1064 len = nfs_read_size;
1065 args->fhoffcnt[pos] = htonl((uint32_t)len);
1066 hlen = offsetof(struct repl, data[0]);
1068 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1069 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1070 repl, sizeof(*repl));
1072 /* errno was already set by rpc_call */
1078 if (repl->errno != 0) {
1079 errno = ntohl(repl->errno);
1083 x = ntohl(repl->count);
1085 printf("nfsread: short packet, %d < %ld\n", rlen, x);
1089 bcopy(repl->data, addr, x);
1095 * return zero or error number
1098 nfs_open(const char *upath, struct open_file *f)
1100 struct iodesc *desc;
1101 struct nfs_iodesc *currfd;
1102 char buf[2 * NFS_V3MAXFHSIZE + 3];
1106 #ifndef NFS_NOSYMLINK
1107 struct nfs_iodesc *newfd;
1108 struct nfsv3_fattrs *fa;
1111 char namebuf[NFS_MAXPATHLEN + 1];
1112 char linkbuf[NFS_MAXPATHLEN + 1];
1120 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1123 printf("no rootpath, no nfs\n");
1128 * This is silly - we should look at dv_type but that value is
1129 * arch dependant and we can't use it here.
1132 if (strcmp(f->f_dev->dv_name, "net") != 0)
1135 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1139 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1142 /* Bind to a reserved port. */
1143 desc->myport = htons(--rpc_port);
1144 desc->destip = rootip;
1145 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1148 nfs_root_node.fa.fa_type = htonl(NFDIR);
1149 nfs_root_node.fa.fa_mode = htonl(0755);
1150 nfs_root_node.fa.fa_nlink = htonl(2);
1151 nfs_root_node.iodesc = desc;
1153 fh = &nfs_root_node.fh[0];
1156 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1157 sprintf(cp, "%02x", fh[i]);
1159 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
1160 setenv("boot.nfsroot.path", rootpath, 1);
1161 setenv("boot.nfsroot.nfshandle", buf, 1);
1162 sprintf(buf, "%d", nfs_root_node.fhsize);
1163 setenv("boot.nfsroot.nfshandlelen", buf, 1);
1165 /* Allocate file system specific data structure */
1166 currfd = malloc(sizeof(*newfd));
1167 if (currfd == NULL) {
1171 #ifndef NFS_NOSYMLINK
1172 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1175 cp = path = strdup(upath);
1182 * Remove extra separators
1190 * Check that current node is a directory.
1192 if (currfd->fa.fa_type != htonl(NFDIR)) {
1197 /* allocate file system specific data structure */
1198 newfd = malloc(sizeof(*newfd));
1199 if (newfd == NULL) {
1203 newfd->iodesc = currfd->iodesc;
1206 * Get next component of path name.
1212 while ((c = *cp) != '\0' && c != '/') {
1213 if (++len > NFS_MAXNAMLEN) {
1222 /* lookup a file handle */
1223 error = nfs_lookupfh(currfd, ncp, newfd);
1229 * Check for symbolic link
1231 if (newfd->fa.fa_type == htonl(NFLNK)) {
1234 error = nfs_readlink(newfd, linkbuf);
1238 link_len = strlen(linkbuf);
1241 if (link_len + len > MAXPATHLEN
1242 || ++nlinks > MAXSYMLINKS) {
1247 bcopy(cp, &namebuf[link_len], len + 1);
1248 bcopy(linkbuf, namebuf, link_len);
1251 * If absolute pathname, restart at root.
1252 * If relative pathname, restart at parent directory.
1256 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1275 currfd->iodesc = desc;
1277 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1282 f->f_fsdata = (void *)currfd;
1288 printf("nfs_open: %s lookupfh failed: %s\n",
1289 path, strerror(error));
1297 nfs_close(struct open_file *f)
1299 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1303 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1308 f->f_fsdata = (void *)0;
1314 * read a portion of a file
1317 nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1319 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1325 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1328 while ((int)size > 0) {
1330 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1331 /* XXX maybe should retry on certain errors */
1335 printf("nfs_read: read: %s", strerror(errno));
1337 return (errno); /* XXX - from nfs_readdata */
1342 printf("nfs_read: hit EOF unexpectantly");
1361 nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1367 nfs_seek(struct open_file *f, off_t offset, int where)
1369 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1370 uint32_t size = ntohl(d->fa.fa_size.val[1]);
1380 d->off = size - offset;
1390 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1391 int nfs_stat_types[9] = {
1392 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1395 nfs_stat(struct open_file *f, struct stat *sb)
1397 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1398 uint32_t ftype, mode;
1400 ftype = ntohl(fp->fa.fa_type);
1401 mode = ntohl(fp->fa.fa_mode);
1402 mode |= nfs_stat_types[ftype & 7];
1405 sb->st_nlink = ntohl(fp->fa.fa_nlink);
1406 sb->st_uid = ntohl(fp->fa.fa_uid);
1407 sb->st_gid = ntohl(fp->fa.fa_gid);
1408 sb->st_size = ntohl(fp->fa.fa_size.val[1]);
1414 nfs_readdir(struct open_file *f, struct dirent *d)
1416 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1417 struct nfsv3_readdir_repl *repl;
1418 struct nfsv3_readdir_entry *rent;
1420 static struct nfs_iodesc *pfp = NULL;
1421 static uint64_t cookie = 0;
1427 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1430 uint32_t h[RPC_HEADER_WORDS];
1434 uint32_t h[RPC_HEADER_WORDS];
1435 u_char d[NFS_READDIRSIZE];
1438 if (fp != pfp || fp->off != cookie) {
1442 bzero(args, sizeof(*args));
1444 args->fhsize = htonl(fp->fhsize);
1445 bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1446 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1447 args->fhpluscookie[pos++] = htonl(fp->off >> 32);
1448 args->fhpluscookie[pos++] = htonl(fp->off);
1449 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
1450 args->fhpluscookie[pos++] = htonl(fp->cookie);
1451 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1453 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1454 args, 6 * sizeof(uint32_t) +
1455 roundup(fp->fhsize, sizeof(uint32_t)),
1456 rdata.d, sizeof(rdata.d));
1458 repl = (struct nfsv3_readdir_repl *)buf;
1459 if (repl->errno != 0)
1460 return (ntohl(repl->errno));
1463 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
1464 ntohl(repl->cookiev1);
1465 buf += sizeof (struct nfsv3_readdir_repl);
1467 rent = (struct nfsv3_readdir_entry *)buf;
1469 if (rent->follows == 0) {
1470 /* fid0 is actually eof */
1471 if (rent->fid0 != 0) {
1478 d->d_namlen = ntohl(rent->len);
1479 bcopy(rent->nameplus, d->d_name, d->d_namlen);
1480 d->d_name[d->d_namlen] = '\0';
1482 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1483 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
1484 ntohl(rent->nameplus[pos + 1]);
1486 buf = (u_char *)&rent->nameplus[pos];
1489 #endif /* OLD_NFSV2 */