Deleted Added
full compact
nfs.c (252700) nfs.c (252701)
1/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */
2
3/*-
4 * Copyright (c) 1993 John Brezak
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
17 *
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.
29 */
30
31#include <sys/cdefs.h>
1/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */
2
3/*-
4 * Copyright (c) 1993 John Brezak
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
17 *
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.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/9/lib/libstand/nfs.c 252700 2013-07-04 15:19:45Z mav $");
32__FBSDID("$FreeBSD: stable/9/lib/libstand/nfs.c 252701 2013-07-04 15:21:27Z mav $");
33
34#include <sys/param.h>
35#include <sys/time.h>
36#include <sys/socket.h>
37#include <sys/stat.h>
38#include <string.h>
39
40#include <netinet/in.h>
41#include <netinet/in_systm.h>
42
43#include "rpcv2.h"
44#include "nfsv2.h"
45
46#include "stand.h"
47#include "net.h"
48#include "netif.h"
49#include "rpc.h"
50
51#define NFS_DEBUGxx
52
53#define NFSREAD_SIZE 1024
54
55/* Define our own NFS attributes without NQNFS stuff. */
56#ifdef OLD_NFSV2
57struct nfsv2_fattrs {
58 n_long fa_type;
59 n_long fa_mode;
60 n_long fa_nlink;
61 n_long fa_uid;
62 n_long fa_gid;
63 n_long fa_size;
64 n_long fa_blocksize;
65 n_long fa_rdev;
66 n_long fa_blocks;
67 n_long fa_fsid;
68 n_long fa_fileid;
69 struct nfsv2_time fa_atime;
70 struct nfsv2_time fa_mtime;
71 struct nfsv2_time fa_ctime;
72};
73
74struct nfs_read_args {
75 u_char fh[NFS_FHSIZE];
76 n_long off;
77 n_long len;
78 n_long xxx; /* XXX what's this for? */
79};
80
81/* Data part of nfs rpc reply (also the largest thing we receive) */
82struct nfs_read_repl {
83 n_long errno;
84 struct nfsv2_fattrs fa;
85 n_long count;
86 u_char data[NFSREAD_SIZE];
87};
88
89#ifndef NFS_NOSYMLINK
90struct nfs_readlnk_repl {
91 n_long errno;
92 n_long len;
93 char path[NFS_MAXPATHLEN];
94};
95#endif
96
97struct nfs_readdir_args {
98 u_char fh[NFS_FHSIZE];
99 n_long cookie;
100 n_long count;
101};
102
103struct nfs_readdir_data {
104 n_long fileid;
105 n_long len;
106 char name[0];
107};
108
109struct nfs_readdir_off {
110 n_long cookie;
111 n_long follows;
112};
113
114struct nfs_iodesc {
115 struct iodesc *iodesc;
116 off_t off;
117 u_char fh[NFS_FHSIZE];
118 struct nfsv2_fattrs fa; /* all in network order */
119};
120#else /* !OLD_NFSV2 */
121
122/* NFSv3 definitions */
123#define NFS_V3MAXFHSIZE 64
124#define NFS_VER3 3
125#define RPCMNT_VER3 3
126#define NFSPROCV3_LOOKUP 3
127#define NFSPROCV3_READLINK 5
128#define NFSPROCV3_READ 6
129#define NFSPROCV3_READDIR 16
130
131typedef struct {
132 uint32_t val[2];
133} n_quad;
134
135struct nfsv3_time {
136 uint32_t nfs_sec;
137 uint32_t nfs_nsec;
138};
139
140struct nfsv3_fattrs {
141 uint32_t fa_type;
142 uint32_t fa_mode;
143 uint32_t fa_nlink;
144 uint32_t fa_uid;
145 uint32_t fa_gid;
146 n_quad fa_size;
147 n_quad fa_used;
148 n_quad fa_rdev;
149 n_quad fa_fsid;
150 n_quad fa_fileid;
151 struct nfsv3_time fa_atime;
152 struct nfsv3_time fa_mtime;
153 struct nfsv3_time fa_ctime;
154};
155
156/*
157 * For NFSv3, the file handle is variable in size, so most fixed sized
158 * structures for arguments won't work. For most cases, a structure
159 * that starts with any fixed size section is followed by an array
160 * that covers the maximum size required.
161 */
162struct nfsv3_readdir_repl {
163 uint32_t errno;
164 uint32_t ok;
165 struct nfsv3_fattrs fa;
166 uint32_t cookiev0;
167 uint32_t cookiev1;
168};
169
170struct nfsv3_readdir_entry {
171 uint32_t follows;
172 uint32_t fid0;
173 uint32_t fid1;
174 uint32_t len;
175 uint32_t nameplus[0];
176};
177
178struct nfs_iodesc {
179 struct iodesc *iodesc;
180 off_t off;
181 uint32_t fhsize;
182 u_char fh[NFS_V3MAXFHSIZE];
183 struct nfsv3_fattrs fa; /* all in network order */
33
34#include <sys/param.h>
35#include <sys/time.h>
36#include <sys/socket.h>
37#include <sys/stat.h>
38#include <string.h>
39
40#include <netinet/in.h>
41#include <netinet/in_systm.h>
42
43#include "rpcv2.h"
44#include "nfsv2.h"
45
46#include "stand.h"
47#include "net.h"
48#include "netif.h"
49#include "rpc.h"
50
51#define NFS_DEBUGxx
52
53#define NFSREAD_SIZE 1024
54
55/* Define our own NFS attributes without NQNFS stuff. */
56#ifdef OLD_NFSV2
57struct nfsv2_fattrs {
58 n_long fa_type;
59 n_long fa_mode;
60 n_long fa_nlink;
61 n_long fa_uid;
62 n_long fa_gid;
63 n_long fa_size;
64 n_long fa_blocksize;
65 n_long fa_rdev;
66 n_long fa_blocks;
67 n_long fa_fsid;
68 n_long fa_fileid;
69 struct nfsv2_time fa_atime;
70 struct nfsv2_time fa_mtime;
71 struct nfsv2_time fa_ctime;
72};
73
74struct nfs_read_args {
75 u_char fh[NFS_FHSIZE];
76 n_long off;
77 n_long len;
78 n_long xxx; /* XXX what's this for? */
79};
80
81/* Data part of nfs rpc reply (also the largest thing we receive) */
82struct nfs_read_repl {
83 n_long errno;
84 struct nfsv2_fattrs fa;
85 n_long count;
86 u_char data[NFSREAD_SIZE];
87};
88
89#ifndef NFS_NOSYMLINK
90struct nfs_readlnk_repl {
91 n_long errno;
92 n_long len;
93 char path[NFS_MAXPATHLEN];
94};
95#endif
96
97struct nfs_readdir_args {
98 u_char fh[NFS_FHSIZE];
99 n_long cookie;
100 n_long count;
101};
102
103struct nfs_readdir_data {
104 n_long fileid;
105 n_long len;
106 char name[0];
107};
108
109struct nfs_readdir_off {
110 n_long cookie;
111 n_long follows;
112};
113
114struct nfs_iodesc {
115 struct iodesc *iodesc;
116 off_t off;
117 u_char fh[NFS_FHSIZE];
118 struct nfsv2_fattrs fa; /* all in network order */
119};
120#else /* !OLD_NFSV2 */
121
122/* NFSv3 definitions */
123#define NFS_V3MAXFHSIZE 64
124#define NFS_VER3 3
125#define RPCMNT_VER3 3
126#define NFSPROCV3_LOOKUP 3
127#define NFSPROCV3_READLINK 5
128#define NFSPROCV3_READ 6
129#define NFSPROCV3_READDIR 16
130
131typedef struct {
132 uint32_t val[2];
133} n_quad;
134
135struct nfsv3_time {
136 uint32_t nfs_sec;
137 uint32_t nfs_nsec;
138};
139
140struct nfsv3_fattrs {
141 uint32_t fa_type;
142 uint32_t fa_mode;
143 uint32_t fa_nlink;
144 uint32_t fa_uid;
145 uint32_t fa_gid;
146 n_quad fa_size;
147 n_quad fa_used;
148 n_quad fa_rdev;
149 n_quad fa_fsid;
150 n_quad fa_fileid;
151 struct nfsv3_time fa_atime;
152 struct nfsv3_time fa_mtime;
153 struct nfsv3_time fa_ctime;
154};
155
156/*
157 * For NFSv3, the file handle is variable in size, so most fixed sized
158 * structures for arguments won't work. For most cases, a structure
159 * that starts with any fixed size section is followed by an array
160 * that covers the maximum size required.
161 */
162struct nfsv3_readdir_repl {
163 uint32_t errno;
164 uint32_t ok;
165 struct nfsv3_fattrs fa;
166 uint32_t cookiev0;
167 uint32_t cookiev1;
168};
169
170struct nfsv3_readdir_entry {
171 uint32_t follows;
172 uint32_t fid0;
173 uint32_t fid1;
174 uint32_t len;
175 uint32_t nameplus[0];
176};
177
178struct nfs_iodesc {
179 struct iodesc *iodesc;
180 off_t off;
181 uint32_t fhsize;
182 u_char fh[NFS_V3MAXFHSIZE];
183 struct nfsv3_fattrs fa; /* all in network order */
184 uint64_t cookie;
184};
185#endif /* OLD_NFSV2 */
186
187/*
188 * XXX interactions with tftp? See nfswrapper.c for a confusing
189 * issue.
190 */
191int nfs_open(const char *path, struct open_file *f);
192static int nfs_close(struct open_file *f);
193static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
194static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
195static off_t nfs_seek(struct open_file *f, off_t offset, int where);
196static int nfs_stat(struct open_file *f, struct stat *sb);
197static int nfs_readdir(struct open_file *f, struct dirent *d);
198
199struct nfs_iodesc nfs_root_node;
200
201struct fs_ops nfs_fsops = {
202 "nfs",
203 nfs_open,
204 nfs_close,
205 nfs_read,
206 nfs_write,
207 nfs_seek,
208 nfs_stat,
209 nfs_readdir
210};
211
212#ifdef OLD_NFSV2
213/*
214 * Fetch the root file handle (call mount daemon)
215 * Return zero or error number.
216 */
217int
218nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
219{
220 int len;
221 struct args {
222 n_long len;
223 char path[FNAME_SIZE];
224 } *args;
225 struct repl {
226 n_long errno;
227 u_char fh[NFS_FHSIZE];
228 } *repl;
229 struct {
230 n_long h[RPC_HEADER_WORDS];
231 struct args d;
232 } sdata;
233 struct {
234 n_long h[RPC_HEADER_WORDS];
235 struct repl d;
236 } rdata;
237 size_t cc;
238
239#ifdef NFS_DEBUG
240 if (debug)
241 printf("nfs_getrootfh: %s\n", path);
242#endif
243
244 args = &sdata.d;
245 repl = &rdata.d;
246
247 bzero(args, sizeof(*args));
248 len = strlen(path);
249 if (len > sizeof(args->path))
250 len = sizeof(args->path);
251 args->len = htonl(len);
252 bcopy(path, args->path, len);
253 len = 4 + roundup(len, 4);
254
255 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
256 args, len, repl, sizeof(*repl));
257 if (cc == -1) {
258 /* errno was set by rpc_call */
259 return (errno);
260 }
261 if (cc < 4)
262 return (EBADRPC);
263 if (repl->errno)
264 return (ntohl(repl->errno));
265 bcopy(repl->fh, fhp, sizeof(repl->fh));
266 return (0);
267}
268
269/*
270 * Lookup a file. Store handle and attributes.
271 * Return zero or error number.
272 */
273int
274nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
275{
276 int len, rlen;
277 struct args {
278 u_char fh[NFS_FHSIZE];
279 n_long len;
280 char name[FNAME_SIZE];
281 } *args;
282 struct repl {
283 n_long errno;
284 u_char fh[NFS_FHSIZE];
285 struct nfsv2_fattrs fa;
286 } *repl;
287 struct {
288 n_long h[RPC_HEADER_WORDS];
289 struct args d;
290 } sdata;
291 struct {
292 n_long h[RPC_HEADER_WORDS];
293 struct repl d;
294 } rdata;
295 ssize_t cc;
296
297#ifdef NFS_DEBUG
298 if (debug)
299 printf("lookupfh: called\n");
300#endif
301
302 args = &sdata.d;
303 repl = &rdata.d;
304
305 bzero(args, sizeof(*args));
306 bcopy(d->fh, args->fh, sizeof(args->fh));
307 len = strlen(name);
308 if (len > sizeof(args->name))
309 len = sizeof(args->name);
310 bcopy(name, args->name, len);
311 args->len = htonl(len);
312 len = 4 + roundup(len, 4);
313 len += NFS_FHSIZE;
314
315 rlen = sizeof(*repl);
316
317 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
318 args, len, repl, rlen);
319 if (cc == -1)
320 return (errno); /* XXX - from rpc_call */
321 if (cc < 4)
322 return (EIO);
323 if (repl->errno) {
324 /* saerrno.h now matches NFS error numbers. */
325 return (ntohl(repl->errno));
326 }
327 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
328 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
329 return (0);
330}
331
332#ifndef NFS_NOSYMLINK
333/*
334 * Get the destination of a symbolic link.
335 */
336int
337nfs_readlink(struct nfs_iodesc *d, char *buf)
338{
339 struct {
340 n_long h[RPC_HEADER_WORDS];
341 u_char fh[NFS_FHSIZE];
342 } sdata;
343 struct {
344 n_long h[RPC_HEADER_WORDS];
345 struct nfs_readlnk_repl d;
346 } rdata;
347 ssize_t cc;
348
349#ifdef NFS_DEBUG
350 if (debug)
351 printf("readlink: called\n");
352#endif
353
354 bcopy(d->fh, sdata.fh, NFS_FHSIZE);
355 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
356 sdata.fh, NFS_FHSIZE,
357 &rdata.d, sizeof(rdata.d));
358 if (cc == -1)
359 return (errno);
360
361 if (cc < 4)
362 return (EIO);
363
364 if (rdata.d.errno)
365 return (ntohl(rdata.d.errno));
366
367 rdata.d.len = ntohl(rdata.d.len);
368 if (rdata.d.len > NFS_MAXPATHLEN)
369 return (ENAMETOOLONG);
370
371 bcopy(rdata.d.path, buf, rdata.d.len);
372 buf[rdata.d.len] = 0;
373 return (0);
374}
375#endif
376
377/*
378 * Read data from a file.
379 * Return transfer count or -1 (and set errno)
380 */
381ssize_t
382nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
383{
384 struct nfs_read_args *args;
385 struct nfs_read_repl *repl;
386 struct {
387 n_long h[RPC_HEADER_WORDS];
388 struct nfs_read_args d;
389 } sdata;
390 struct {
391 n_long h[RPC_HEADER_WORDS];
392 struct nfs_read_repl d;
393 } rdata;
394 size_t cc;
395 long x;
396 int hlen, rlen;
397
398 args = &sdata.d;
399 repl = &rdata.d;
400
401 bcopy(d->fh, args->fh, NFS_FHSIZE);
402 args->off = htonl((n_long)off);
403 if (len > NFSREAD_SIZE)
404 len = NFSREAD_SIZE;
405 args->len = htonl((n_long)len);
406 args->xxx = htonl((n_long)0);
407 hlen = sizeof(*repl) - NFSREAD_SIZE;
408
409 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
410 args, sizeof(*args),
411 repl, sizeof(*repl));
412 if (cc == -1) {
413 /* errno was already set by rpc_call */
414 return (-1);
415 }
416 if (cc < hlen) {
417 errno = EBADRPC;
418 return (-1);
419 }
420 if (repl->errno) {
421 errno = ntohl(repl->errno);
422 return (-1);
423 }
424 rlen = cc - hlen;
425 x = ntohl(repl->count);
426 if (rlen < x) {
427 printf("nfsread: short packet, %d < %ld\n", rlen, x);
428 errno = EBADRPC;
429 return(-1);
430 }
431 bcopy(repl->data, addr, x);
432 return (x);
433}
434
435/*
436 * Open a file.
437 * return zero or error number
438 */
439int
440nfs_open(const char *upath, struct open_file *f)
441{
442 struct iodesc *desc;
443 struct nfs_iodesc *currfd;
444 char buf[2 * NFS_FHSIZE + 3];
445 u_char *fh;
446 char *cp;
447 int i;
448#ifndef NFS_NOSYMLINK
449 struct nfs_iodesc *newfd;
450 struct nfsv2_fattrs *fa;
451 char *ncp;
452 int c;
453 char namebuf[NFS_MAXPATHLEN + 1];
454 char linkbuf[NFS_MAXPATHLEN + 1];
455 int nlinks = 0;
456#endif
457 int error;
458 char *path;
459
460#ifdef NFS_DEBUG
461 if (debug)
462 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
463#endif
464 if (!rootpath[0]) {
465 printf("no rootpath, no nfs\n");
466 return (ENXIO);
467 }
468
469 /*
470 * This is silly - we should look at dv_type but that value is
471 * arch dependant and we can't use it here.
472 */
473#ifndef __i386__
474 if (strcmp(f->f_dev->dv_name, "net") != 0)
475 return(EINVAL);
476#else
477 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
478 return(EINVAL);
479#endif
480
481 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
482 return(EINVAL);
483
484 /* Bind to a reserved port. */
485 desc->myport = htons(--rpc_port);
486 desc->destip = rootip;
487 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
488 return (error);
489 nfs_root_node.fa.fa_type = htonl(NFDIR);
490 nfs_root_node.fa.fa_mode = htonl(0755);
491 nfs_root_node.fa.fa_nlink = htonl(2);
492 nfs_root_node.iodesc = desc;
493
494 fh = &nfs_root_node.fh[0];
495 buf[0] = 'X';
496 cp = &buf[1];
497 for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
498 sprintf(cp, "%02x", fh[i]);
499 sprintf(cp, "X");
500 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
501 setenv("boot.nfsroot.path", rootpath, 1);
502 setenv("boot.nfsroot.nfshandle", buf, 1);
503
504 /* Allocate file system specific data structure */
505 currfd = malloc(sizeof(*newfd));
506 if (currfd == NULL) {
507 error = ENOMEM;
508 goto out;
509 }
510
511#ifndef NFS_NOSYMLINK
512 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
513 newfd = 0;
514
515 cp = path = strdup(upath);
516 if (path == NULL) {
517 error = ENOMEM;
518 goto out;
519 }
520 while (*cp) {
521 /*
522 * Remove extra separators
523 */
524 while (*cp == '/')
525 cp++;
526
527 if (*cp == '\0')
528 break;
529 /*
530 * Check that current node is a directory.
531 */
532 if (currfd->fa.fa_type != htonl(NFDIR)) {
533 error = ENOTDIR;
534 goto out;
535 }
536
537 /* allocate file system specific data structure */
538 newfd = malloc(sizeof(*newfd));
539 newfd->iodesc = currfd->iodesc;
540
541 /*
542 * Get next component of path name.
543 */
544 {
545 int len = 0;
546
547 ncp = cp;
548 while ((c = *cp) != '\0' && c != '/') {
549 if (++len > NFS_MAXNAMLEN) {
550 error = ENOENT;
551 goto out;
552 }
553 cp++;
554 }
555 *cp = '\0';
556 }
557
558 /* lookup a file handle */
559 error = nfs_lookupfh(currfd, ncp, newfd);
560 *cp = c;
561 if (error)
562 goto out;
563
564 /*
565 * Check for symbolic link
566 */
567 if (newfd->fa.fa_type == htonl(NFLNK)) {
568 int link_len, len;
569
570 error = nfs_readlink(newfd, linkbuf);
571 if (error)
572 goto out;
573
574 link_len = strlen(linkbuf);
575 len = strlen(cp);
576
577 if (link_len + len > MAXPATHLEN
578 || ++nlinks > MAXSYMLINKS) {
579 error = ENOENT;
580 goto out;
581 }
582
583 bcopy(cp, &namebuf[link_len], len + 1);
584 bcopy(linkbuf, namebuf, link_len);
585
586 /*
587 * If absolute pathname, restart at root.
588 * If relative pathname, restart at parent directory.
589 */
590 cp = namebuf;
591 if (*cp == '/')
592 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
593
594 free(newfd);
595 newfd = 0;
596
597 continue;
598 }
599
600 free(currfd);
601 currfd = newfd;
602 newfd = 0;
603 }
604
605 error = 0;
606
607out:
608 if (newfd)
609 free(newfd);
610 if (path)
611 free(path);
612#else
613 currfd->iodesc = desc;
614
615 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
616#endif
617 if (!error) {
618 currfd->off = 0;
619 f->f_fsdata = (void *)currfd;
620 return (0);
621 }
622
623#ifdef NFS_DEBUG
624 if (debug)
625 printf("nfs_open: %s lookupfh failed: %s\n",
626 path, strerror(error));
627#endif
628 free(currfd);
629
630 return (error);
631}
632
633int
634nfs_close(struct open_file *f)
635{
636 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
637
638#ifdef NFS_DEBUG
639 if (debug)
640 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
641#endif
642
643 if (fp)
644 free(fp);
645 f->f_fsdata = (void *)0;
646
647 return (0);
648}
649
650/*
651 * read a portion of a file
652 */
653int
654nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
655{
656 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
657 ssize_t cc;
658 char *addr = buf;
659
660#ifdef NFS_DEBUG
661 if (debug)
662 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
663 (int)fp->off);
664#endif
665 while ((int)size > 0) {
666 twiddle();
667 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
668 /* XXX maybe should retry on certain errors */
669 if (cc == -1) {
670#ifdef NFS_DEBUG
671 if (debug)
672 printf("nfs_read: read: %s", strerror(errno));
673#endif
674 return (errno); /* XXX - from nfs_readdata */
675 }
676 if (cc == 0) {
677#ifdef NFS_DEBUG
678 if (debug)
679 printf("nfs_read: hit EOF unexpectantly");
680#endif
681 goto ret;
682 }
683 fp->off += cc;
684 addr += cc;
685 size -= cc;
686 }
687ret:
688 if (resid)
689 *resid = size;
690
691 return (0);
692}
693
694/*
695 * Not implemented.
696 */
697int
698nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
699{
700 return (EROFS);
701}
702
703off_t
704nfs_seek(struct open_file *f, off_t offset, int where)
705{
706 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
707 n_long size = ntohl(d->fa.fa_size);
708
709 switch (where) {
710 case SEEK_SET:
711 d->off = offset;
712 break;
713 case SEEK_CUR:
714 d->off += offset;
715 break;
716 case SEEK_END:
717 d->off = size - offset;
718 break;
719 default:
720 errno = EINVAL;
721 return (-1);
722 }
723
724 return (d->off);
725}
726
727/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
728int nfs_stat_types[8] = {
729 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
730
731int
732nfs_stat(struct open_file *f, struct stat *sb)
733{
734 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
735 n_long ftype, mode;
736
737 ftype = ntohl(fp->fa.fa_type);
738 mode = ntohl(fp->fa.fa_mode);
739 mode |= nfs_stat_types[ftype & 7];
740
741 sb->st_mode = mode;
742 sb->st_nlink = ntohl(fp->fa.fa_nlink);
743 sb->st_uid = ntohl(fp->fa.fa_uid);
744 sb->st_gid = ntohl(fp->fa.fa_gid);
745 sb->st_size = ntohl(fp->fa.fa_size);
746
747 return (0);
748}
749
750static int
751nfs_readdir(struct open_file *f, struct dirent *d)
752{
753 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
754 struct nfs_readdir_args *args;
755 struct nfs_readdir_data *rd;
756 struct nfs_readdir_off *roff = NULL;
757 static char *buf;
185};
186#endif /* OLD_NFSV2 */
187
188/*
189 * XXX interactions with tftp? See nfswrapper.c for a confusing
190 * issue.
191 */
192int nfs_open(const char *path, struct open_file *f);
193static int nfs_close(struct open_file *f);
194static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
195static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
196static off_t nfs_seek(struct open_file *f, off_t offset, int where);
197static int nfs_stat(struct open_file *f, struct stat *sb);
198static int nfs_readdir(struct open_file *f, struct dirent *d);
199
200struct nfs_iodesc nfs_root_node;
201
202struct fs_ops nfs_fsops = {
203 "nfs",
204 nfs_open,
205 nfs_close,
206 nfs_read,
207 nfs_write,
208 nfs_seek,
209 nfs_stat,
210 nfs_readdir
211};
212
213#ifdef OLD_NFSV2
214/*
215 * Fetch the root file handle (call mount daemon)
216 * Return zero or error number.
217 */
218int
219nfs_getrootfh(struct iodesc *d, char *path, u_char *fhp)
220{
221 int len;
222 struct args {
223 n_long len;
224 char path[FNAME_SIZE];
225 } *args;
226 struct repl {
227 n_long errno;
228 u_char fh[NFS_FHSIZE];
229 } *repl;
230 struct {
231 n_long h[RPC_HEADER_WORDS];
232 struct args d;
233 } sdata;
234 struct {
235 n_long h[RPC_HEADER_WORDS];
236 struct repl d;
237 } rdata;
238 size_t cc;
239
240#ifdef NFS_DEBUG
241 if (debug)
242 printf("nfs_getrootfh: %s\n", path);
243#endif
244
245 args = &sdata.d;
246 repl = &rdata.d;
247
248 bzero(args, sizeof(*args));
249 len = strlen(path);
250 if (len > sizeof(args->path))
251 len = sizeof(args->path);
252 args->len = htonl(len);
253 bcopy(path, args->path, len);
254 len = 4 + roundup(len, 4);
255
256 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
257 args, len, repl, sizeof(*repl));
258 if (cc == -1) {
259 /* errno was set by rpc_call */
260 return (errno);
261 }
262 if (cc < 4)
263 return (EBADRPC);
264 if (repl->errno)
265 return (ntohl(repl->errno));
266 bcopy(repl->fh, fhp, sizeof(repl->fh));
267 return (0);
268}
269
270/*
271 * Lookup a file. Store handle and attributes.
272 * Return zero or error number.
273 */
274int
275nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
276{
277 int len, rlen;
278 struct args {
279 u_char fh[NFS_FHSIZE];
280 n_long len;
281 char name[FNAME_SIZE];
282 } *args;
283 struct repl {
284 n_long errno;
285 u_char fh[NFS_FHSIZE];
286 struct nfsv2_fattrs fa;
287 } *repl;
288 struct {
289 n_long h[RPC_HEADER_WORDS];
290 struct args d;
291 } sdata;
292 struct {
293 n_long h[RPC_HEADER_WORDS];
294 struct repl d;
295 } rdata;
296 ssize_t cc;
297
298#ifdef NFS_DEBUG
299 if (debug)
300 printf("lookupfh: called\n");
301#endif
302
303 args = &sdata.d;
304 repl = &rdata.d;
305
306 bzero(args, sizeof(*args));
307 bcopy(d->fh, args->fh, sizeof(args->fh));
308 len = strlen(name);
309 if (len > sizeof(args->name))
310 len = sizeof(args->name);
311 bcopy(name, args->name, len);
312 args->len = htonl(len);
313 len = 4 + roundup(len, 4);
314 len += NFS_FHSIZE;
315
316 rlen = sizeof(*repl);
317
318 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
319 args, len, repl, rlen);
320 if (cc == -1)
321 return (errno); /* XXX - from rpc_call */
322 if (cc < 4)
323 return (EIO);
324 if (repl->errno) {
325 /* saerrno.h now matches NFS error numbers. */
326 return (ntohl(repl->errno));
327 }
328 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
329 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
330 return (0);
331}
332
333#ifndef NFS_NOSYMLINK
334/*
335 * Get the destination of a symbolic link.
336 */
337int
338nfs_readlink(struct nfs_iodesc *d, char *buf)
339{
340 struct {
341 n_long h[RPC_HEADER_WORDS];
342 u_char fh[NFS_FHSIZE];
343 } sdata;
344 struct {
345 n_long h[RPC_HEADER_WORDS];
346 struct nfs_readlnk_repl d;
347 } rdata;
348 ssize_t cc;
349
350#ifdef NFS_DEBUG
351 if (debug)
352 printf("readlink: called\n");
353#endif
354
355 bcopy(d->fh, sdata.fh, NFS_FHSIZE);
356 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
357 sdata.fh, NFS_FHSIZE,
358 &rdata.d, sizeof(rdata.d));
359 if (cc == -1)
360 return (errno);
361
362 if (cc < 4)
363 return (EIO);
364
365 if (rdata.d.errno)
366 return (ntohl(rdata.d.errno));
367
368 rdata.d.len = ntohl(rdata.d.len);
369 if (rdata.d.len > NFS_MAXPATHLEN)
370 return (ENAMETOOLONG);
371
372 bcopy(rdata.d.path, buf, rdata.d.len);
373 buf[rdata.d.len] = 0;
374 return (0);
375}
376#endif
377
378/*
379 * Read data from a file.
380 * Return transfer count or -1 (and set errno)
381 */
382ssize_t
383nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
384{
385 struct nfs_read_args *args;
386 struct nfs_read_repl *repl;
387 struct {
388 n_long h[RPC_HEADER_WORDS];
389 struct nfs_read_args d;
390 } sdata;
391 struct {
392 n_long h[RPC_HEADER_WORDS];
393 struct nfs_read_repl d;
394 } rdata;
395 size_t cc;
396 long x;
397 int hlen, rlen;
398
399 args = &sdata.d;
400 repl = &rdata.d;
401
402 bcopy(d->fh, args->fh, NFS_FHSIZE);
403 args->off = htonl((n_long)off);
404 if (len > NFSREAD_SIZE)
405 len = NFSREAD_SIZE;
406 args->len = htonl((n_long)len);
407 args->xxx = htonl((n_long)0);
408 hlen = sizeof(*repl) - NFSREAD_SIZE;
409
410 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
411 args, sizeof(*args),
412 repl, sizeof(*repl));
413 if (cc == -1) {
414 /* errno was already set by rpc_call */
415 return (-1);
416 }
417 if (cc < hlen) {
418 errno = EBADRPC;
419 return (-1);
420 }
421 if (repl->errno) {
422 errno = ntohl(repl->errno);
423 return (-1);
424 }
425 rlen = cc - hlen;
426 x = ntohl(repl->count);
427 if (rlen < x) {
428 printf("nfsread: short packet, %d < %ld\n", rlen, x);
429 errno = EBADRPC;
430 return(-1);
431 }
432 bcopy(repl->data, addr, x);
433 return (x);
434}
435
436/*
437 * Open a file.
438 * return zero or error number
439 */
440int
441nfs_open(const char *upath, struct open_file *f)
442{
443 struct iodesc *desc;
444 struct nfs_iodesc *currfd;
445 char buf[2 * NFS_FHSIZE + 3];
446 u_char *fh;
447 char *cp;
448 int i;
449#ifndef NFS_NOSYMLINK
450 struct nfs_iodesc *newfd;
451 struct nfsv2_fattrs *fa;
452 char *ncp;
453 int c;
454 char namebuf[NFS_MAXPATHLEN + 1];
455 char linkbuf[NFS_MAXPATHLEN + 1];
456 int nlinks = 0;
457#endif
458 int error;
459 char *path;
460
461#ifdef NFS_DEBUG
462 if (debug)
463 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
464#endif
465 if (!rootpath[0]) {
466 printf("no rootpath, no nfs\n");
467 return (ENXIO);
468 }
469
470 /*
471 * This is silly - we should look at dv_type but that value is
472 * arch dependant and we can't use it here.
473 */
474#ifndef __i386__
475 if (strcmp(f->f_dev->dv_name, "net") != 0)
476 return(EINVAL);
477#else
478 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
479 return(EINVAL);
480#endif
481
482 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
483 return(EINVAL);
484
485 /* Bind to a reserved port. */
486 desc->myport = htons(--rpc_port);
487 desc->destip = rootip;
488 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
489 return (error);
490 nfs_root_node.fa.fa_type = htonl(NFDIR);
491 nfs_root_node.fa.fa_mode = htonl(0755);
492 nfs_root_node.fa.fa_nlink = htonl(2);
493 nfs_root_node.iodesc = desc;
494
495 fh = &nfs_root_node.fh[0];
496 buf[0] = 'X';
497 cp = &buf[1];
498 for (i = 0; i < NFS_FHSIZE; i++, cp += 2)
499 sprintf(cp, "%02x", fh[i]);
500 sprintf(cp, "X");
501 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
502 setenv("boot.nfsroot.path", rootpath, 1);
503 setenv("boot.nfsroot.nfshandle", buf, 1);
504
505 /* Allocate file system specific data structure */
506 currfd = malloc(sizeof(*newfd));
507 if (currfd == NULL) {
508 error = ENOMEM;
509 goto out;
510 }
511
512#ifndef NFS_NOSYMLINK
513 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
514 newfd = 0;
515
516 cp = path = strdup(upath);
517 if (path == NULL) {
518 error = ENOMEM;
519 goto out;
520 }
521 while (*cp) {
522 /*
523 * Remove extra separators
524 */
525 while (*cp == '/')
526 cp++;
527
528 if (*cp == '\0')
529 break;
530 /*
531 * Check that current node is a directory.
532 */
533 if (currfd->fa.fa_type != htonl(NFDIR)) {
534 error = ENOTDIR;
535 goto out;
536 }
537
538 /* allocate file system specific data structure */
539 newfd = malloc(sizeof(*newfd));
540 newfd->iodesc = currfd->iodesc;
541
542 /*
543 * Get next component of path name.
544 */
545 {
546 int len = 0;
547
548 ncp = cp;
549 while ((c = *cp) != '\0' && c != '/') {
550 if (++len > NFS_MAXNAMLEN) {
551 error = ENOENT;
552 goto out;
553 }
554 cp++;
555 }
556 *cp = '\0';
557 }
558
559 /* lookup a file handle */
560 error = nfs_lookupfh(currfd, ncp, newfd);
561 *cp = c;
562 if (error)
563 goto out;
564
565 /*
566 * Check for symbolic link
567 */
568 if (newfd->fa.fa_type == htonl(NFLNK)) {
569 int link_len, len;
570
571 error = nfs_readlink(newfd, linkbuf);
572 if (error)
573 goto out;
574
575 link_len = strlen(linkbuf);
576 len = strlen(cp);
577
578 if (link_len + len > MAXPATHLEN
579 || ++nlinks > MAXSYMLINKS) {
580 error = ENOENT;
581 goto out;
582 }
583
584 bcopy(cp, &namebuf[link_len], len + 1);
585 bcopy(linkbuf, namebuf, link_len);
586
587 /*
588 * If absolute pathname, restart at root.
589 * If relative pathname, restart at parent directory.
590 */
591 cp = namebuf;
592 if (*cp == '/')
593 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
594
595 free(newfd);
596 newfd = 0;
597
598 continue;
599 }
600
601 free(currfd);
602 currfd = newfd;
603 newfd = 0;
604 }
605
606 error = 0;
607
608out:
609 if (newfd)
610 free(newfd);
611 if (path)
612 free(path);
613#else
614 currfd->iodesc = desc;
615
616 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
617#endif
618 if (!error) {
619 currfd->off = 0;
620 f->f_fsdata = (void *)currfd;
621 return (0);
622 }
623
624#ifdef NFS_DEBUG
625 if (debug)
626 printf("nfs_open: %s lookupfh failed: %s\n",
627 path, strerror(error));
628#endif
629 free(currfd);
630
631 return (error);
632}
633
634int
635nfs_close(struct open_file *f)
636{
637 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
638
639#ifdef NFS_DEBUG
640 if (debug)
641 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
642#endif
643
644 if (fp)
645 free(fp);
646 f->f_fsdata = (void *)0;
647
648 return (0);
649}
650
651/*
652 * read a portion of a file
653 */
654int
655nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
656{
657 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
658 ssize_t cc;
659 char *addr = buf;
660
661#ifdef NFS_DEBUG
662 if (debug)
663 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
664 (int)fp->off);
665#endif
666 while ((int)size > 0) {
667 twiddle();
668 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
669 /* XXX maybe should retry on certain errors */
670 if (cc == -1) {
671#ifdef NFS_DEBUG
672 if (debug)
673 printf("nfs_read: read: %s", strerror(errno));
674#endif
675 return (errno); /* XXX - from nfs_readdata */
676 }
677 if (cc == 0) {
678#ifdef NFS_DEBUG
679 if (debug)
680 printf("nfs_read: hit EOF unexpectantly");
681#endif
682 goto ret;
683 }
684 fp->off += cc;
685 addr += cc;
686 size -= cc;
687 }
688ret:
689 if (resid)
690 *resid = size;
691
692 return (0);
693}
694
695/*
696 * Not implemented.
697 */
698int
699nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
700{
701 return (EROFS);
702}
703
704off_t
705nfs_seek(struct open_file *f, off_t offset, int where)
706{
707 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
708 n_long size = ntohl(d->fa.fa_size);
709
710 switch (where) {
711 case SEEK_SET:
712 d->off = offset;
713 break;
714 case SEEK_CUR:
715 d->off += offset;
716 break;
717 case SEEK_END:
718 d->off = size - offset;
719 break;
720 default:
721 errno = EINVAL;
722 return (-1);
723 }
724
725 return (d->off);
726}
727
728/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
729int nfs_stat_types[8] = {
730 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
731
732int
733nfs_stat(struct open_file *f, struct stat *sb)
734{
735 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
736 n_long ftype, mode;
737
738 ftype = ntohl(fp->fa.fa_type);
739 mode = ntohl(fp->fa.fa_mode);
740 mode |= nfs_stat_types[ftype & 7];
741
742 sb->st_mode = mode;
743 sb->st_nlink = ntohl(fp->fa.fa_nlink);
744 sb->st_uid = ntohl(fp->fa.fa_uid);
745 sb->st_gid = ntohl(fp->fa.fa_gid);
746 sb->st_size = ntohl(fp->fa.fa_size);
747
748 return (0);
749}
750
751static int
752nfs_readdir(struct open_file *f, struct dirent *d)
753{
754 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
755 struct nfs_readdir_args *args;
756 struct nfs_readdir_data *rd;
757 struct nfs_readdir_off *roff = NULL;
758 static char *buf;
759 static struct nfs_iodesc *pfp = NULL;
758 static n_long cookie = 0;
759 size_t cc;
760 n_long eof;
761
762 struct {
763 n_long h[RPC_HEADER_WORDS];
764 struct nfs_readdir_args d;
765 } sdata;
766 static struct {
767 n_long h[RPC_HEADER_WORDS];
768 u_char d[NFS_READDIRSIZE];
769 } rdata;
770
760 static n_long cookie = 0;
761 size_t cc;
762 n_long eof;
763
764 struct {
765 n_long h[RPC_HEADER_WORDS];
766 struct nfs_readdir_args d;
767 } sdata;
768 static struct {
769 n_long h[RPC_HEADER_WORDS];
770 u_char d[NFS_READDIRSIZE];
771 } rdata;
772
771 if (cookie == 0) {
773 if (fp != pfp || fp->off != cookie) {
774 pfp = NULL;
772 refill:
773 args = &sdata.d;
774 bzero(args, sizeof(*args));
775
776 bcopy(fp->fh, args->fh, NFS_FHSIZE);
775 refill:
776 args = &sdata.d;
777 bzero(args, sizeof(*args));
778
779 bcopy(fp->fh, args->fh, NFS_FHSIZE);
777 args->cookie = htonl(cookie);
780 args->cookie = htonl(fp->off);
778 args->count = htonl(NFS_READDIRSIZE);
779
780 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
781 args, sizeof(*args),
782 rdata.d, sizeof(rdata.d));
783 buf = rdata.d;
784 roff = (struct nfs_readdir_off *)buf;
785 if (ntohl(roff->cookie) != 0)
786 return EIO;
781 args->count = htonl(NFS_READDIRSIZE);
782
783 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
784 args, sizeof(*args),
785 rdata.d, sizeof(rdata.d));
786 buf = rdata.d;
787 roff = (struct nfs_readdir_off *)buf;
788 if (ntohl(roff->cookie) != 0)
789 return EIO;
790 pfp = fp;
791 cookie = fp->off;
787 }
788 roff = (struct nfs_readdir_off *)buf;
789
790 if (ntohl(roff->follows) == 0) {
791 eof = ntohl((roff+1)->cookie);
792 if (eof) {
793 cookie = 0;
794 return ENOENT;
795 }
796 goto refill;
797 }
798
799 buf += sizeof(struct nfs_readdir_off);
800 rd = (struct nfs_readdir_data *)buf;
801 d->d_namlen = ntohl(rd->len);
802 bcopy(rd->name, d->d_name, d->d_namlen);
803 d->d_name[d->d_namlen] = '\0';
804
805 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
806 roff = (struct nfs_readdir_off *)buf;
792 }
793 roff = (struct nfs_readdir_off *)buf;
794
795 if (ntohl(roff->follows) == 0) {
796 eof = ntohl((roff+1)->cookie);
797 if (eof) {
798 cookie = 0;
799 return ENOENT;
800 }
801 goto refill;
802 }
803
804 buf += sizeof(struct nfs_readdir_off);
805 rd = (struct nfs_readdir_data *)buf;
806 d->d_namlen = ntohl(rd->len);
807 bcopy(rd->name, d->d_name, d->d_namlen);
808 d->d_name[d->d_namlen] = '\0';
809
810 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
811 roff = (struct nfs_readdir_off *)buf;
807 cookie = ntohl(roff->cookie);
812 fp->off = cookie = ntohl(roff->cookie);
808 return 0;
809}
810#else /* !OLD_NFSV2 */
811/*
812 * Fetch the root file handle (call mount daemon)
813 * Return zero or error number.
814 */
815int
816nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
817{
818 int len;
819 struct args {
820 uint32_t len;
821 char path[FNAME_SIZE];
822 } *args;
823 struct repl {
824 uint32_t errno;
825 uint32_t fhsize;
826 u_char fh[NFS_V3MAXFHSIZE];
827 uint32_t authcnt;
828 uint32_t auth[7];
829 } *repl;
830 struct {
831 uint32_t h[RPC_HEADER_WORDS];
832 struct args d;
833 } sdata;
834 struct {
835 uint32_t h[RPC_HEADER_WORDS];
836 struct repl d;
837 } rdata;
838 size_t cc;
839
840#ifdef NFS_DEBUG
841 if (debug)
842 printf("nfs_getrootfh: %s\n", path);
843#endif
844
845 args = &sdata.d;
846 repl = &rdata.d;
847
848 bzero(args, sizeof(*args));
849 len = strlen(path);
850 if (len > sizeof(args->path))
851 len = sizeof(args->path);
852 args->len = htonl(len);
853 bcopy(path, args->path, len);
854 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
855
856 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
857 args, len, repl, sizeof(*repl));
858 if (cc == -1)
859 /* errno was set by rpc_call */
860 return (errno);
861 if (cc < 2 * sizeof (uint32_t))
862 return (EBADRPC);
863 if (repl->errno != 0)
864 return (ntohl(repl->errno));
865 *fhlenp = ntohl(repl->fhsize);
866 bcopy(repl->fh, fhp, *fhlenp);
867 return (0);
868}
869
870/*
871 * Lookup a file. Store handle and attributes.
872 * Return zero or error number.
873 */
874int
875nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
876{
877 int len, rlen, pos;
878 struct args {
879 uint32_t fhsize;
880 uint32_t fhplusname[1 +
881 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
882 } *args;
883 struct repl {
884 uint32_t errno;
885 uint32_t fhsize;
886 uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
887 2 * (sizeof(uint32_t) +
888 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
889 } *repl;
890 struct {
891 uint32_t h[RPC_HEADER_WORDS];
892 struct args d;
893 } sdata;
894 struct {
895 uint32_t h[RPC_HEADER_WORDS];
896 struct repl d;
897 } rdata;
898 ssize_t cc;
899
900#ifdef NFS_DEBUG
901 if (debug)
902 printf("lookupfh: called\n");
903#endif
904
905 args = &sdata.d;
906 repl = &rdata.d;
907
908 bzero(args, sizeof(*args));
909 args->fhsize = htonl(d->fhsize);
910 bcopy(d->fh, args->fhplusname, d->fhsize);
911 len = strlen(name);
912 if (len > FNAME_SIZE)
913 len = FNAME_SIZE;
914 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
915 args->fhplusname[pos++] = htonl(len);
916 bcopy(name, &args->fhplusname[pos], len);
917 len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
918 roundup(len, sizeof(uint32_t));
919
920 rlen = sizeof(*repl);
921
922 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
923 args, len, repl, rlen);
924 if (cc == -1)
925 return (errno); /* XXX - from rpc_call */
926 if (cc < 2 * sizeof(uint32_t))
927 return (EIO);
928 if (repl->errno != 0)
929 /* saerrno.h now matches NFS error numbers. */
930 return (ntohl(repl->errno));
931 newfd->fhsize = ntohl(repl->fhsize);
932 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
933 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
934 if (repl->fhplusattr[pos++] == 0)
935 return (EIO);
936 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
937 return (0);
938}
939
940#ifndef NFS_NOSYMLINK
941/*
942 * Get the destination of a symbolic link.
943 */
944int
945nfs_readlink(struct nfs_iodesc *d, char *buf)
946{
947 struct args {
948 uint32_t fhsize;
949 u_char fh[NFS_V3MAXFHSIZE];
950 } *args;
951 struct repl {
952 uint32_t errno;
953 uint32_t ok;
954 struct nfsv3_fattrs fa;
955 uint32_t len;
956 u_char path[NFS_MAXPATHLEN];
957 } *repl;
958 struct {
959 uint32_t h[RPC_HEADER_WORDS];
960 struct args d;
961 } sdata;
962 struct {
963 uint32_t h[RPC_HEADER_WORDS];
964 struct repl d;
965 } rdata;
966 ssize_t cc;
967
968#ifdef NFS_DEBUG
969 if (debug)
970 printf("readlink: called\n");
971#endif
972
973 args = &sdata.d;
974 repl = &rdata.d;
975
976 bzero(args, sizeof(*args));
977 args->fhsize = htonl(d->fhsize);
978 bcopy(d->fh, args->fh, d->fhsize);
979 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
980 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
981 repl, sizeof(*repl));
982 if (cc == -1)
983 return (errno);
984
985 if (cc < 2 * sizeof(uint32_t))
986 return (EIO);
987
988 if (repl->errno != 0)
989 return (ntohl(repl->errno));
990
991 if (repl->ok == 0)
992 return (EIO);
993
994 repl->len = ntohl(repl->len);
995 if (repl->len > NFS_MAXPATHLEN)
996 return (ENAMETOOLONG);
997
998 bcopy(repl->path, buf, repl->len);
999 buf[repl->len] = 0;
1000 return (0);
1001}
1002#endif
1003
1004/*
1005 * Read data from a file.
1006 * Return transfer count or -1 (and set errno)
1007 */
1008ssize_t
1009nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1010{
1011 struct args {
1012 uint32_t fhsize;
1013 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1014 } *args;
1015 struct repl {
1016 uint32_t errno;
1017 uint32_t ok;
1018 struct nfsv3_fattrs fa;
1019 uint32_t count;
1020 uint32_t eof;
1021 uint32_t len;
1022 u_char data[NFSREAD_SIZE];
1023 } *repl;
1024 struct {
1025 uint32_t h[RPC_HEADER_WORDS];
1026 struct args d;
1027 } sdata;
1028 struct {
1029 uint32_t h[RPC_HEADER_WORDS];
1030 struct repl d;
1031 } rdata;
1032 size_t cc;
1033 long x;
1034 int hlen, rlen, pos;
1035
1036 args = &sdata.d;
1037 repl = &rdata.d;
1038
1039 bzero(args, sizeof(*args));
1040 args->fhsize = htonl(d->fhsize);
1041 bcopy(d->fh, args->fhoffcnt, d->fhsize);
1042 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1043 args->fhoffcnt[pos++] = 0;
1044 args->fhoffcnt[pos++] = htonl((uint32_t)off);
1045 if (len > NFSREAD_SIZE)
1046 len = NFSREAD_SIZE;
1047 args->fhoffcnt[pos] = htonl((uint32_t)len);
1048 hlen = sizeof(*repl) - NFSREAD_SIZE;
1049
1050 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1051 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1052 repl, sizeof(*repl));
1053 if (cc == -1)
1054 /* errno was already set by rpc_call */
1055 return (-1);
1056 if (cc < hlen) {
1057 errno = EBADRPC;
1058 return (-1);
1059 }
1060 if (repl->errno != 0) {
1061 errno = ntohl(repl->errno);
1062 return (-1);
1063 }
1064 rlen = cc - hlen;
1065 x = ntohl(repl->count);
1066 if (rlen < x) {
1067 printf("nfsread: short packet, %d < %ld\n", rlen, x);
1068 errno = EBADRPC;
1069 return (-1);
1070 }
1071 bcopy(repl->data, addr, x);
1072 return (x);
1073}
1074
1075/*
1076 * Open a file.
1077 * return zero or error number
1078 */
1079int
1080nfs_open(const char *upath, struct open_file *f)
1081{
1082 struct iodesc *desc;
1083 struct nfs_iodesc *currfd;
1084 char buf[2 * NFS_V3MAXFHSIZE + 3];
1085 u_char *fh;
1086 char *cp;
1087 int i;
1088#ifndef NFS_NOSYMLINK
1089 struct nfs_iodesc *newfd;
1090 struct nfsv3_fattrs *fa;
1091 char *ncp;
1092 int c;
1093 char namebuf[NFS_MAXPATHLEN + 1];
1094 char linkbuf[NFS_MAXPATHLEN + 1];
1095 int nlinks = 0;
1096#endif
1097 int error;
1098 char *path;
1099
1100#ifdef NFS_DEBUG
1101 if (debug)
1102 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1103#endif
1104 if (!rootpath[0]) {
1105 printf("no rootpath, no nfs\n");
1106 return (ENXIO);
1107 }
1108
1109 /*
1110 * This is silly - we should look at dv_type but that value is
1111 * arch dependant and we can't use it here.
1112 */
1113#ifndef __i386__
1114 if (strcmp(f->f_dev->dv_name, "net") != 0)
1115 return (EINVAL);
1116#else
1117 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1118 return (EINVAL);
1119#endif
1120
1121 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1122 return (EINVAL);
1123
1124 /* Bind to a reserved port. */
1125 desc->myport = htons(--rpc_port);
1126 desc->destip = rootip;
1127 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1128 nfs_root_node.fh)))
1129 return (error);
1130 nfs_root_node.fa.fa_type = htonl(NFDIR);
1131 nfs_root_node.fa.fa_mode = htonl(0755);
1132 nfs_root_node.fa.fa_nlink = htonl(2);
1133 nfs_root_node.iodesc = desc;
1134
1135 fh = &nfs_root_node.fh[0];
1136 buf[0] = 'X';
1137 cp = &buf[1];
1138 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1139 sprintf(cp, "%02x", fh[i]);
1140 sprintf(cp, "X");
1141 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
1142 setenv("boot.nfsroot.path", rootpath, 1);
1143 setenv("boot.nfsroot.nfshandle", buf, 1);
1144 sprintf(buf, "%d", nfs_root_node.fhsize);
1145 setenv("boot.nfsroot.nfshandlelen", buf, 1);
1146
1147 /* Allocate file system specific data structure */
1148 currfd = malloc(sizeof(*newfd));
1149 if (currfd == NULL) {
1150 error = ENOMEM;
1151 goto out;
1152 }
1153#ifndef NFS_NOSYMLINK
1154 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1155 newfd = 0;
1156
1157 cp = path = strdup(upath);
1158 if (path == NULL) {
1159 error = ENOMEM;
1160 goto out;
1161 }
1162 while (*cp) {
1163 /*
1164 * Remove extra separators
1165 */
1166 while (*cp == '/')
1167 cp++;
1168
1169 if (*cp == '\0')
1170 break;
1171 /*
1172 * Check that current node is a directory.
1173 */
1174 if (currfd->fa.fa_type != htonl(NFDIR)) {
1175 error = ENOTDIR;
1176 goto out;
1177 }
1178
1179 /* allocate file system specific data structure */
1180 newfd = malloc(sizeof(*newfd));
1181 if (newfd == NULL) {
1182 error = ENOMEM;
1183 goto out;
1184 }
1185 newfd->iodesc = currfd->iodesc;
1186
1187 /*
1188 * Get next component of path name.
1189 */
1190 {
1191 int len = 0;
1192
1193 ncp = cp;
1194 while ((c = *cp) != '\0' && c != '/') {
1195 if (++len > NFS_MAXNAMLEN) {
1196 error = ENOENT;
1197 goto out;
1198 }
1199 cp++;
1200 }
1201 *cp = '\0';
1202 }
1203
1204 /* lookup a file handle */
1205 error = nfs_lookupfh(currfd, ncp, newfd);
1206 *cp = c;
1207 if (error)
1208 goto out;
1209
1210 /*
1211 * Check for symbolic link
1212 */
1213 if (newfd->fa.fa_type == htonl(NFLNK)) {
1214 int link_len, len;
1215
1216 error = nfs_readlink(newfd, linkbuf);
1217 if (error)
1218 goto out;
1219
1220 link_len = strlen(linkbuf);
1221 len = strlen(cp);
1222
1223 if (link_len + len > MAXPATHLEN
1224 || ++nlinks > MAXSYMLINKS) {
1225 error = ENOENT;
1226 goto out;
1227 }
1228
1229 bcopy(cp, &namebuf[link_len], len + 1);
1230 bcopy(linkbuf, namebuf, link_len);
1231
1232 /*
1233 * If absolute pathname, restart at root.
1234 * If relative pathname, restart at parent directory.
1235 */
1236 cp = namebuf;
1237 if (*cp == '/')
1238 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1239
1240 free(newfd);
1241 newfd = 0;
1242
1243 continue;
1244 }
1245
1246 free(currfd);
1247 currfd = newfd;
1248 newfd = 0;
1249 }
1250
1251 error = 0;
1252
1253out:
1254 free(newfd);
1255 free(path);
1256#else
1257 currfd->iodesc = desc;
1258
1259 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1260#endif
1261 if (!error) {
1262 currfd->off = 0;
813 return 0;
814}
815#else /* !OLD_NFSV2 */
816/*
817 * Fetch the root file handle (call mount daemon)
818 * Return zero or error number.
819 */
820int
821nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
822{
823 int len;
824 struct args {
825 uint32_t len;
826 char path[FNAME_SIZE];
827 } *args;
828 struct repl {
829 uint32_t errno;
830 uint32_t fhsize;
831 u_char fh[NFS_V3MAXFHSIZE];
832 uint32_t authcnt;
833 uint32_t auth[7];
834 } *repl;
835 struct {
836 uint32_t h[RPC_HEADER_WORDS];
837 struct args d;
838 } sdata;
839 struct {
840 uint32_t h[RPC_HEADER_WORDS];
841 struct repl d;
842 } rdata;
843 size_t cc;
844
845#ifdef NFS_DEBUG
846 if (debug)
847 printf("nfs_getrootfh: %s\n", path);
848#endif
849
850 args = &sdata.d;
851 repl = &rdata.d;
852
853 bzero(args, sizeof(*args));
854 len = strlen(path);
855 if (len > sizeof(args->path))
856 len = sizeof(args->path);
857 args->len = htonl(len);
858 bcopy(path, args->path, len);
859 len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
860
861 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
862 args, len, repl, sizeof(*repl));
863 if (cc == -1)
864 /* errno was set by rpc_call */
865 return (errno);
866 if (cc < 2 * sizeof (uint32_t))
867 return (EBADRPC);
868 if (repl->errno != 0)
869 return (ntohl(repl->errno));
870 *fhlenp = ntohl(repl->fhsize);
871 bcopy(repl->fh, fhp, *fhlenp);
872 return (0);
873}
874
875/*
876 * Lookup a file. Store handle and attributes.
877 * Return zero or error number.
878 */
879int
880nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
881{
882 int len, rlen, pos;
883 struct args {
884 uint32_t fhsize;
885 uint32_t fhplusname[1 +
886 (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
887 } *args;
888 struct repl {
889 uint32_t errno;
890 uint32_t fhsize;
891 uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
892 2 * (sizeof(uint32_t) +
893 sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
894 } *repl;
895 struct {
896 uint32_t h[RPC_HEADER_WORDS];
897 struct args d;
898 } sdata;
899 struct {
900 uint32_t h[RPC_HEADER_WORDS];
901 struct repl d;
902 } rdata;
903 ssize_t cc;
904
905#ifdef NFS_DEBUG
906 if (debug)
907 printf("lookupfh: called\n");
908#endif
909
910 args = &sdata.d;
911 repl = &rdata.d;
912
913 bzero(args, sizeof(*args));
914 args->fhsize = htonl(d->fhsize);
915 bcopy(d->fh, args->fhplusname, d->fhsize);
916 len = strlen(name);
917 if (len > FNAME_SIZE)
918 len = FNAME_SIZE;
919 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
920 args->fhplusname[pos++] = htonl(len);
921 bcopy(name, &args->fhplusname[pos], len);
922 len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
923 roundup(len, sizeof(uint32_t));
924
925 rlen = sizeof(*repl);
926
927 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
928 args, len, repl, rlen);
929 if (cc == -1)
930 return (errno); /* XXX - from rpc_call */
931 if (cc < 2 * sizeof(uint32_t))
932 return (EIO);
933 if (repl->errno != 0)
934 /* saerrno.h now matches NFS error numbers. */
935 return (ntohl(repl->errno));
936 newfd->fhsize = ntohl(repl->fhsize);
937 bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
938 pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
939 if (repl->fhplusattr[pos++] == 0)
940 return (EIO);
941 bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
942 return (0);
943}
944
945#ifndef NFS_NOSYMLINK
946/*
947 * Get the destination of a symbolic link.
948 */
949int
950nfs_readlink(struct nfs_iodesc *d, char *buf)
951{
952 struct args {
953 uint32_t fhsize;
954 u_char fh[NFS_V3MAXFHSIZE];
955 } *args;
956 struct repl {
957 uint32_t errno;
958 uint32_t ok;
959 struct nfsv3_fattrs fa;
960 uint32_t len;
961 u_char path[NFS_MAXPATHLEN];
962 } *repl;
963 struct {
964 uint32_t h[RPC_HEADER_WORDS];
965 struct args d;
966 } sdata;
967 struct {
968 uint32_t h[RPC_HEADER_WORDS];
969 struct repl d;
970 } rdata;
971 ssize_t cc;
972
973#ifdef NFS_DEBUG
974 if (debug)
975 printf("readlink: called\n");
976#endif
977
978 args = &sdata.d;
979 repl = &rdata.d;
980
981 bzero(args, sizeof(*args));
982 args->fhsize = htonl(d->fhsize);
983 bcopy(d->fh, args->fh, d->fhsize);
984 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
985 args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
986 repl, sizeof(*repl));
987 if (cc == -1)
988 return (errno);
989
990 if (cc < 2 * sizeof(uint32_t))
991 return (EIO);
992
993 if (repl->errno != 0)
994 return (ntohl(repl->errno));
995
996 if (repl->ok == 0)
997 return (EIO);
998
999 repl->len = ntohl(repl->len);
1000 if (repl->len > NFS_MAXPATHLEN)
1001 return (ENAMETOOLONG);
1002
1003 bcopy(repl->path, buf, repl->len);
1004 buf[repl->len] = 0;
1005 return (0);
1006}
1007#endif
1008
1009/*
1010 * Read data from a file.
1011 * Return transfer count or -1 (and set errno)
1012 */
1013ssize_t
1014nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
1015{
1016 struct args {
1017 uint32_t fhsize;
1018 uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
1019 } *args;
1020 struct repl {
1021 uint32_t errno;
1022 uint32_t ok;
1023 struct nfsv3_fattrs fa;
1024 uint32_t count;
1025 uint32_t eof;
1026 uint32_t len;
1027 u_char data[NFSREAD_SIZE];
1028 } *repl;
1029 struct {
1030 uint32_t h[RPC_HEADER_WORDS];
1031 struct args d;
1032 } sdata;
1033 struct {
1034 uint32_t h[RPC_HEADER_WORDS];
1035 struct repl d;
1036 } rdata;
1037 size_t cc;
1038 long x;
1039 int hlen, rlen, pos;
1040
1041 args = &sdata.d;
1042 repl = &rdata.d;
1043
1044 bzero(args, sizeof(*args));
1045 args->fhsize = htonl(d->fhsize);
1046 bcopy(d->fh, args->fhoffcnt, d->fhsize);
1047 pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1048 args->fhoffcnt[pos++] = 0;
1049 args->fhoffcnt[pos++] = htonl((uint32_t)off);
1050 if (len > NFSREAD_SIZE)
1051 len = NFSREAD_SIZE;
1052 args->fhoffcnt[pos] = htonl((uint32_t)len);
1053 hlen = sizeof(*repl) - NFSREAD_SIZE;
1054
1055 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
1056 args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
1057 repl, sizeof(*repl));
1058 if (cc == -1)
1059 /* errno was already set by rpc_call */
1060 return (-1);
1061 if (cc < hlen) {
1062 errno = EBADRPC;
1063 return (-1);
1064 }
1065 if (repl->errno != 0) {
1066 errno = ntohl(repl->errno);
1067 return (-1);
1068 }
1069 rlen = cc - hlen;
1070 x = ntohl(repl->count);
1071 if (rlen < x) {
1072 printf("nfsread: short packet, %d < %ld\n", rlen, x);
1073 errno = EBADRPC;
1074 return (-1);
1075 }
1076 bcopy(repl->data, addr, x);
1077 return (x);
1078}
1079
1080/*
1081 * Open a file.
1082 * return zero or error number
1083 */
1084int
1085nfs_open(const char *upath, struct open_file *f)
1086{
1087 struct iodesc *desc;
1088 struct nfs_iodesc *currfd;
1089 char buf[2 * NFS_V3MAXFHSIZE + 3];
1090 u_char *fh;
1091 char *cp;
1092 int i;
1093#ifndef NFS_NOSYMLINK
1094 struct nfs_iodesc *newfd;
1095 struct nfsv3_fattrs *fa;
1096 char *ncp;
1097 int c;
1098 char namebuf[NFS_MAXPATHLEN + 1];
1099 char linkbuf[NFS_MAXPATHLEN + 1];
1100 int nlinks = 0;
1101#endif
1102 int error;
1103 char *path;
1104
1105#ifdef NFS_DEBUG
1106 if (debug)
1107 printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
1108#endif
1109 if (!rootpath[0]) {
1110 printf("no rootpath, no nfs\n");
1111 return (ENXIO);
1112 }
1113
1114 /*
1115 * This is silly - we should look at dv_type but that value is
1116 * arch dependant and we can't use it here.
1117 */
1118#ifndef __i386__
1119 if (strcmp(f->f_dev->dv_name, "net") != 0)
1120 return (EINVAL);
1121#else
1122 if (strcmp(f->f_dev->dv_name, "pxe") != 0)
1123 return (EINVAL);
1124#endif
1125
1126 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
1127 return (EINVAL);
1128
1129 /* Bind to a reserved port. */
1130 desc->myport = htons(--rpc_port);
1131 desc->destip = rootip;
1132 if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
1133 nfs_root_node.fh)))
1134 return (error);
1135 nfs_root_node.fa.fa_type = htonl(NFDIR);
1136 nfs_root_node.fa.fa_mode = htonl(0755);
1137 nfs_root_node.fa.fa_nlink = htonl(2);
1138 nfs_root_node.iodesc = desc;
1139
1140 fh = &nfs_root_node.fh[0];
1141 buf[0] = 'X';
1142 cp = &buf[1];
1143 for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
1144 sprintf(cp, "%02x", fh[i]);
1145 sprintf(cp, "X");
1146 setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
1147 setenv("boot.nfsroot.path", rootpath, 1);
1148 setenv("boot.nfsroot.nfshandle", buf, 1);
1149 sprintf(buf, "%d", nfs_root_node.fhsize);
1150 setenv("boot.nfsroot.nfshandlelen", buf, 1);
1151
1152 /* Allocate file system specific data structure */
1153 currfd = malloc(sizeof(*newfd));
1154 if (currfd == NULL) {
1155 error = ENOMEM;
1156 goto out;
1157 }
1158#ifndef NFS_NOSYMLINK
1159 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1160 newfd = 0;
1161
1162 cp = path = strdup(upath);
1163 if (path == NULL) {
1164 error = ENOMEM;
1165 goto out;
1166 }
1167 while (*cp) {
1168 /*
1169 * Remove extra separators
1170 */
1171 while (*cp == '/')
1172 cp++;
1173
1174 if (*cp == '\0')
1175 break;
1176 /*
1177 * Check that current node is a directory.
1178 */
1179 if (currfd->fa.fa_type != htonl(NFDIR)) {
1180 error = ENOTDIR;
1181 goto out;
1182 }
1183
1184 /* allocate file system specific data structure */
1185 newfd = malloc(sizeof(*newfd));
1186 if (newfd == NULL) {
1187 error = ENOMEM;
1188 goto out;
1189 }
1190 newfd->iodesc = currfd->iodesc;
1191
1192 /*
1193 * Get next component of path name.
1194 */
1195 {
1196 int len = 0;
1197
1198 ncp = cp;
1199 while ((c = *cp) != '\0' && c != '/') {
1200 if (++len > NFS_MAXNAMLEN) {
1201 error = ENOENT;
1202 goto out;
1203 }
1204 cp++;
1205 }
1206 *cp = '\0';
1207 }
1208
1209 /* lookup a file handle */
1210 error = nfs_lookupfh(currfd, ncp, newfd);
1211 *cp = c;
1212 if (error)
1213 goto out;
1214
1215 /*
1216 * Check for symbolic link
1217 */
1218 if (newfd->fa.fa_type == htonl(NFLNK)) {
1219 int link_len, len;
1220
1221 error = nfs_readlink(newfd, linkbuf);
1222 if (error)
1223 goto out;
1224
1225 link_len = strlen(linkbuf);
1226 len = strlen(cp);
1227
1228 if (link_len + len > MAXPATHLEN
1229 || ++nlinks > MAXSYMLINKS) {
1230 error = ENOENT;
1231 goto out;
1232 }
1233
1234 bcopy(cp, &namebuf[link_len], len + 1);
1235 bcopy(linkbuf, namebuf, link_len);
1236
1237 /*
1238 * If absolute pathname, restart at root.
1239 * If relative pathname, restart at parent directory.
1240 */
1241 cp = namebuf;
1242 if (*cp == '/')
1243 bcopy(&nfs_root_node, currfd, sizeof(*currfd));
1244
1245 free(newfd);
1246 newfd = 0;
1247
1248 continue;
1249 }
1250
1251 free(currfd);
1252 currfd = newfd;
1253 newfd = 0;
1254 }
1255
1256 error = 0;
1257
1258out:
1259 free(newfd);
1260 free(path);
1261#else
1262 currfd->iodesc = desc;
1263
1264 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
1265#endif
1266 if (!error) {
1267 currfd->off = 0;
1268 currfd->cookie = 0;
1263 f->f_fsdata = (void *)currfd;
1264 return (0);
1265 }
1266
1267#ifdef NFS_DEBUG
1268 if (debug)
1269 printf("nfs_open: %s lookupfh failed: %s\n",
1270 path, strerror(error));
1271#endif
1272 free(currfd);
1273
1274 return (error);
1275}
1276
1277int
1278nfs_close(struct open_file *f)
1279{
1280 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1281
1282#ifdef NFS_DEBUG
1283 if (debug)
1284 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1285#endif
1286
1287 if (fp)
1288 free(fp);
1289 f->f_fsdata = (void *)0;
1290
1291 return (0);
1292}
1293
1294/*
1295 * read a portion of a file
1296 */
1297int
1298nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1299{
1300 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1301 ssize_t cc;
1302 char *addr = buf;
1303
1304#ifdef NFS_DEBUG
1305 if (debug)
1306 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1307 (int)fp->off);
1308#endif
1309 while ((int)size > 0) {
1310 twiddle();
1311 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1312 /* XXX maybe should retry on certain errors */
1313 if (cc == -1) {
1314#ifdef NFS_DEBUG
1315 if (debug)
1316 printf("nfs_read: read: %s", strerror(errno));
1317#endif
1318 return (errno); /* XXX - from nfs_readdata */
1319 }
1320 if (cc == 0) {
1321#ifdef NFS_DEBUG
1322 if (debug)
1323 printf("nfs_read: hit EOF unexpectantly");
1324#endif
1325 goto ret;
1326 }
1327 fp->off += cc;
1328 addr += cc;
1329 size -= cc;
1330 }
1331ret:
1332 if (resid)
1333 *resid = size;
1334
1335 return (0);
1336}
1337
1338/*
1339 * Not implemented.
1340 */
1341int
1342nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1343{
1344 return (EROFS);
1345}
1346
1347off_t
1348nfs_seek(struct open_file *f, off_t offset, int where)
1349{
1350 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1351 uint32_t size = ntohl(d->fa.fa_size.val[1]);
1352
1353 switch (where) {
1354 case SEEK_SET:
1355 d->off = offset;
1356 break;
1357 case SEEK_CUR:
1358 d->off += offset;
1359 break;
1360 case SEEK_END:
1361 d->off = size - offset;
1362 break;
1363 default:
1364 errno = EINVAL;
1365 return (-1);
1366 }
1367
1368 return (d->off);
1369}
1370
1371/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1372int nfs_stat_types[9] = {
1373 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1374
1375int
1376nfs_stat(struct open_file *f, struct stat *sb)
1377{
1378 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1379 uint32_t ftype, mode;
1380
1381 ftype = ntohl(fp->fa.fa_type);
1382 mode = ntohl(fp->fa.fa_mode);
1383 mode |= nfs_stat_types[ftype & 7];
1384
1385 sb->st_mode = mode;
1386 sb->st_nlink = ntohl(fp->fa.fa_nlink);
1387 sb->st_uid = ntohl(fp->fa.fa_uid);
1388 sb->st_gid = ntohl(fp->fa.fa_gid);
1389 sb->st_size = ntohl(fp->fa.fa_size.val[1]);
1390
1391 return (0);
1392}
1393
1394static int
1395nfs_readdir(struct open_file *f, struct dirent *d)
1396{
1397 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1398 struct nfsv3_readdir_repl *repl;
1399 struct nfsv3_readdir_entry *rent;
1400 static char *buf;
1269 f->f_fsdata = (void *)currfd;
1270 return (0);
1271 }
1272
1273#ifdef NFS_DEBUG
1274 if (debug)
1275 printf("nfs_open: %s lookupfh failed: %s\n",
1276 path, strerror(error));
1277#endif
1278 free(currfd);
1279
1280 return (error);
1281}
1282
1283int
1284nfs_close(struct open_file *f)
1285{
1286 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1287
1288#ifdef NFS_DEBUG
1289 if (debug)
1290 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
1291#endif
1292
1293 if (fp)
1294 free(fp);
1295 f->f_fsdata = (void *)0;
1296
1297 return (0);
1298}
1299
1300/*
1301 * read a portion of a file
1302 */
1303int
1304nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
1305{
1306 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1307 ssize_t cc;
1308 char *addr = buf;
1309
1310#ifdef NFS_DEBUG
1311 if (debug)
1312 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
1313 (int)fp->off);
1314#endif
1315 while ((int)size > 0) {
1316 twiddle();
1317 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
1318 /* XXX maybe should retry on certain errors */
1319 if (cc == -1) {
1320#ifdef NFS_DEBUG
1321 if (debug)
1322 printf("nfs_read: read: %s", strerror(errno));
1323#endif
1324 return (errno); /* XXX - from nfs_readdata */
1325 }
1326 if (cc == 0) {
1327#ifdef NFS_DEBUG
1328 if (debug)
1329 printf("nfs_read: hit EOF unexpectantly");
1330#endif
1331 goto ret;
1332 }
1333 fp->off += cc;
1334 addr += cc;
1335 size -= cc;
1336 }
1337ret:
1338 if (resid)
1339 *resid = size;
1340
1341 return (0);
1342}
1343
1344/*
1345 * Not implemented.
1346 */
1347int
1348nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
1349{
1350 return (EROFS);
1351}
1352
1353off_t
1354nfs_seek(struct open_file *f, off_t offset, int where)
1355{
1356 struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
1357 uint32_t size = ntohl(d->fa.fa_size.val[1]);
1358
1359 switch (where) {
1360 case SEEK_SET:
1361 d->off = offset;
1362 break;
1363 case SEEK_CUR:
1364 d->off += offset;
1365 break;
1366 case SEEK_END:
1367 d->off = size - offset;
1368 break;
1369 default:
1370 errno = EINVAL;
1371 return (-1);
1372 }
1373
1374 return (d->off);
1375}
1376
1377/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
1378int nfs_stat_types[9] = {
1379 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
1380
1381int
1382nfs_stat(struct open_file *f, struct stat *sb)
1383{
1384 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1385 uint32_t ftype, mode;
1386
1387 ftype = ntohl(fp->fa.fa_type);
1388 mode = ntohl(fp->fa.fa_mode);
1389 mode |= nfs_stat_types[ftype & 7];
1390
1391 sb->st_mode = mode;
1392 sb->st_nlink = ntohl(fp->fa.fa_nlink);
1393 sb->st_uid = ntohl(fp->fa.fa_uid);
1394 sb->st_gid = ntohl(fp->fa.fa_gid);
1395 sb->st_size = ntohl(fp->fa.fa_size.val[1]);
1396
1397 return (0);
1398}
1399
1400static int
1401nfs_readdir(struct open_file *f, struct dirent *d)
1402{
1403 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
1404 struct nfsv3_readdir_repl *repl;
1405 struct nfsv3_readdir_entry *rent;
1406 static char *buf;
1401 static uint32_t cookie0 = 0;
1402 static uint32_t cookie1 = 0;
1407 static struct nfs_iodesc *pfp = NULL;
1408 static uint64_t cookie = 0;
1403 size_t cc;
1409 size_t cc;
1404 static uint32_t cookieverf0 = 0;
1405 static uint32_t cookieverf1 = 0;
1406 int pos;
1407
1408 struct args {
1409 uint32_t fhsize;
1410 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1411 } *args;
1412 struct {
1413 uint32_t h[RPC_HEADER_WORDS];
1414 struct args d;
1415 } sdata;
1416 static struct {
1417 uint32_t h[RPC_HEADER_WORDS];
1418 u_char d[NFS_READDIRSIZE];
1419 } rdata;
1420
1410 int pos;
1411
1412 struct args {
1413 uint32_t fhsize;
1414 uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
1415 } *args;
1416 struct {
1417 uint32_t h[RPC_HEADER_WORDS];
1418 struct args d;
1419 } sdata;
1420 static struct {
1421 uint32_t h[RPC_HEADER_WORDS];
1422 u_char d[NFS_READDIRSIZE];
1423 } rdata;
1424
1421 if (cookie0 == 0 && cookie1 == 0) {
1425 if (fp != pfp || fp->off != cookie) {
1426 pfp = NULL;
1422 refill:
1423 args = &sdata.d;
1424 bzero(args, sizeof(*args));
1425
1426 args->fhsize = htonl(fp->fhsize);
1427 bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1428 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1427 refill:
1428 args = &sdata.d;
1429 bzero(args, sizeof(*args));
1430
1431 args->fhsize = htonl(fp->fhsize);
1432 bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
1433 pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
1429 args->fhpluscookie[pos++] = cookie0;
1430 args->fhpluscookie[pos++] = cookie1;
1431 args->fhpluscookie[pos++] = cookieverf0;
1432 args->fhpluscookie[pos++] = cookieverf1;
1434 args->fhpluscookie[pos++] = htonl(fp->off >> 32);
1435 args->fhpluscookie[pos++] = htonl(fp->off);
1436 args->fhpluscookie[pos++] = htonl(fp->cookie >> 32);
1437 args->fhpluscookie[pos++] = htonl(fp->cookie);
1433 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1434
1435 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1436 args, 6 * sizeof(uint32_t) +
1437 roundup(fp->fhsize, sizeof(uint32_t)),
1438 rdata.d, sizeof(rdata.d));
1439 buf = rdata.d;
1440 repl = (struct nfsv3_readdir_repl *)buf;
1441 if (repl->errno != 0)
1442 return (ntohl(repl->errno));
1438 args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
1439
1440 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
1441 args, 6 * sizeof(uint32_t) +
1442 roundup(fp->fhsize, sizeof(uint32_t)),
1443 rdata.d, sizeof(rdata.d));
1444 buf = rdata.d;
1445 repl = (struct nfsv3_readdir_repl *)buf;
1446 if (repl->errno != 0)
1447 return (ntohl(repl->errno));
1443 cookieverf0 = repl->cookiev0;
1444 cookieverf1 = repl->cookiev1;
1448 pfp = fp;
1449 cookie = fp->off;
1450 fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) |
1451 ntohl(repl->cookiev1);
1445 buf += sizeof (struct nfsv3_readdir_repl);
1446 }
1447 rent = (struct nfsv3_readdir_entry *)buf;
1448
1449 if (rent->follows == 0) {
1450 /* fid0 is actually eof */
1451 if (rent->fid0 != 0) {
1452 buf += sizeof (struct nfsv3_readdir_repl);
1453 }
1454 rent = (struct nfsv3_readdir_entry *)buf;
1455
1456 if (rent->follows == 0) {
1457 /* fid0 is actually eof */
1458 if (rent->fid0 != 0) {
1452 cookie0 = 0;
1453 cookie1 = 0;
1454 cookieverf0 = 0;
1455 cookieverf1 = 0;
1459 cookie = 0;
1456 return (ENOENT);
1457 }
1458 goto refill;
1459 }
1460
1461 d->d_namlen = ntohl(rent->len);
1462 bcopy(rent->nameplus, d->d_name, d->d_namlen);
1463 d->d_name[d->d_namlen] = '\0';
1464
1465 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1460 return (ENOENT);
1461 }
1462 goto refill;
1463 }
1464
1465 d->d_namlen = ntohl(rent->len);
1466 bcopy(rent->nameplus, d->d_name, d->d_namlen);
1467 d->d_name[d->d_namlen] = '\0';
1468
1469 pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
1466 cookie0 = rent->nameplus[pos++];
1467 cookie1 = rent->nameplus[pos++];
1470 fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) |
1471 ntohl(rent->nameplus[pos + 1]);
1472 pos += 2;
1468 buf = (u_char *)&rent->nameplus[pos];
1469 return (0);
1470}
1471#endif /* OLD_NFSV2 */
1473 buf = (u_char *)&rent->nameplus[pos];
1474 return (0);
1475}
1476#endif /* OLD_NFSV2 */