Deleted Added
full compact
1/* $FreeBSD: head/lib/libstand/nfs.c 59824 2000-05-01 10:53:21Z ps $ */
1/* $FreeBSD: head/lib/libstand/nfs.c 59853 2000-05-01 15:03:52Z ps $ */
2/* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */
3
4/*-
5 * Copyright (c) 1993 John Brezak
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/param.h>
33#include <sys/time.h>
34#include <sys/socket.h>
35#include <sys/stat.h>
36#include <string.h>
37
38#include <netinet/in.h>
39#include <netinet/in_systm.h>
40
41#include "rpcv2.h"
42#include "nfsv2.h"
43
44#include "stand.h"
45#include "net.h"
46#include "netif.h"
47#include "rpc.h"
48
49#define NFS_DEBUGxx
50
51/* Define our own NFS attributes without NQNFS stuff. */
52struct nfsv2_fattrs {
53 n_long fa_type;
54 n_long fa_mode;
55 n_long fa_nlink;
56 n_long fa_uid;
57 n_long fa_gid;
58 n_long fa_size;
59 n_long fa_blocksize;
60 n_long fa_rdev;
61 n_long fa_blocks;
62 n_long fa_fsid;
63 n_long fa_fileid;
64 struct nfsv2_time fa_atime;
65 struct nfsv2_time fa_mtime;
66 struct nfsv2_time fa_ctime;
67};
68
69
70struct nfs_read_args {
71 u_char fh[NFS_FHSIZE];
72 n_long off;
73 n_long len;
74 n_long xxx; /* XXX what's this for? */
75};
76
77/* Data part of nfs rpc reply (also the largest thing we receive) */
78#define NFSREAD_SIZE 1024
79struct nfs_read_repl {
80 n_long errno;
81 struct nfsv2_fattrs fa;
82 n_long count;
83 u_char data[NFSREAD_SIZE];
84};
85
86#ifndef NFS_NOSYMLINK
87struct nfs_readlnk_repl {
88 n_long errno;
89 n_long len;
90 char path[NFS_MAXPATHLEN];
91};
92#endif
93
94struct nfs_readdir_args {
95 u_char fh[NFS_FHSIZE];
96 n_long cookie;
97 n_long count;
98};
99
100struct nfs_readdir_data {
101 n_long fileid;
102 n_long len;
103 char name[0];
104};
105
106struct nfs_readdir_off {
107 n_long cookie;
108 n_long follows;
109};
110
111struct nfs_iodesc {
112 struct iodesc *iodesc;
113 off_t off;
114 u_char fh[NFS_FHSIZE];
115 struct nfsv2_fattrs fa; /* all in network order */
116};
117
118/*
119 * XXX interactions with tftp? See nfswrapper.c for a confusing
120 * issue.
121 */
122int nfs_open(const char *path, struct open_file *f);
123static int nfs_close(struct open_file *f);
124static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
125static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
126static off_t nfs_seek(struct open_file *f, off_t offset, int where);
127static int nfs_stat(struct open_file *f, struct stat *sb);
128static int nfs_readdir(struct open_file *f, struct dirent *d);
129
130static struct nfs_iodesc nfs_root_node;
131
132struct fs_ops nfs_fsops = {
133 "nfs",
134 nfs_open,
135 nfs_close,
136 nfs_read,
137 nfs_write,
138 nfs_seek,
139 nfs_stat,
122 null_readdir
140 nfs_readdir
141};
142
143/*
144 * Fetch the root file handle (call mount daemon)
145 * Return zero or error number.
146 */
147int
148nfs_getrootfh(d, path, fhp)
149 register struct iodesc *d;
150 char *path;
151 u_char *fhp;
152{
153 register int len;
154 struct args {
155 n_long len;
156 char path[FNAME_SIZE];
157 } *args;
158 struct repl {
159 n_long errno;
160 u_char fh[NFS_FHSIZE];
161 } *repl;
162 struct {
163 n_long h[RPC_HEADER_WORDS];
164 struct args d;
165 } sdata;
166 struct {
167 n_long h[RPC_HEADER_WORDS];
168 struct repl d;
169 } rdata;
170 size_t cc;
171
172#ifdef NFS_DEBUG
173 if (debug)
174 printf("nfs_getrootfh: %s\n", path);
175#endif
176
177 args = &sdata.d;
178 repl = &rdata.d;
179
180 bzero(args, sizeof(*args));
181 len = strlen(path);
182 if (len > sizeof(args->path))
183 len = sizeof(args->path);
184 args->len = htonl(len);
185 bcopy(path, args->path, len);
186 len = 4 + roundup(len, 4);
187
188 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
189 args, len, repl, sizeof(*repl));
190 if (cc == -1) {
191 /* errno was set by rpc_call */
192 return (errno);
193 }
194 if (cc < 4)
195 return (EBADRPC);
196 if (repl->errno)
197 return (ntohl(repl->errno));
198 bcopy(repl->fh, fhp, sizeof(repl->fh));
199 return (0);
200}
201
202/*
203 * Lookup a file. Store handle and attributes.
204 * Return zero or error number.
205 */
206int
207nfs_lookupfh(d, name, newfd)
208 struct nfs_iodesc *d;
209 const char *name;
210 struct nfs_iodesc *newfd;
211{
212 register int len, rlen;
213 struct args {
214 u_char fh[NFS_FHSIZE];
215 n_long len;
216 char name[FNAME_SIZE];
217 } *args;
218 struct repl {
219 n_long errno;
220 u_char fh[NFS_FHSIZE];
221 struct nfsv2_fattrs fa;
222 } *repl;
223 struct {
224 n_long h[RPC_HEADER_WORDS];
225 struct args d;
226 } sdata;
227 struct {
228 n_long h[RPC_HEADER_WORDS];
229 struct repl d;
230 } rdata;
231 ssize_t cc;
232
233#ifdef NFS_DEBUG
234 if (debug)
235 printf("lookupfh: called\n");
236#endif
237
238 args = &sdata.d;
239 repl = &rdata.d;
240
241 bzero(args, sizeof(*args));
242 bcopy(d->fh, args->fh, sizeof(args->fh));
243 len = strlen(name);
244 if (len > sizeof(args->name))
245 len = sizeof(args->name);
246 bcopy(name, args->name, len);
247 args->len = htonl(len);
248 len = 4 + roundup(len, 4);
249 len += NFS_FHSIZE;
250
251 rlen = sizeof(*repl);
252
253 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
254 args, len, repl, rlen);
255 if (cc == -1)
256 return (errno); /* XXX - from rpc_call */
257 if (cc < 4)
258 return (EIO);
259 if (repl->errno) {
260 /* saerrno.h now matches NFS error numbers. */
261 return (ntohl(repl->errno));
262 }
263 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
264 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
265 return (0);
266}
267
268#ifndef NFS_NOSYMLINK
269/*
270 * Get the destination of a symbolic link.
271 */
272int
273nfs_readlink(d, buf)
274 struct nfs_iodesc *d;
275 char *buf;
276{
277 struct {
278 n_long h[RPC_HEADER_WORDS];
279 u_char fh[NFS_FHSIZE];
280 } sdata;
281 struct {
282 n_long h[RPC_HEADER_WORDS];
283 struct nfs_readlnk_repl d;
284 } rdata;
285 ssize_t cc;
286
287#ifdef NFS_DEBUG
288 if (debug)
289 printf("readlink: called\n");
290#endif
291
292 bcopy(d->fh, sdata.fh, NFS_FHSIZE);
293 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
294 sdata.fh, NFS_FHSIZE,
295 &rdata.d, sizeof(rdata.d));
296 if (cc == -1)
297 return (errno);
298
299 if (cc < 4)
300 return (EIO);
301
302 if (rdata.d.errno)
303 return (ntohl(rdata.d.errno));
304
305 rdata.d.len = ntohl(rdata.d.len);
306 if (rdata.d.len > NFS_MAXPATHLEN)
307 return (ENAMETOOLONG);
308
309 bcopy(rdata.d.path, buf, rdata.d.len);
310 buf[rdata.d.len] = 0;
311 return (0);
312}
313#endif
314
315/*
316 * Read data from a file.
317 * Return transfer count or -1 (and set errno)
318 */
319ssize_t
320nfs_readdata(d, off, addr, len)
321 struct nfs_iodesc *d;
322 off_t off;
323 void *addr;
324 size_t len;
325{
326 struct nfs_read_args *args;
327 struct nfs_read_repl *repl;
328 struct {
329 n_long h[RPC_HEADER_WORDS];
330 struct nfs_read_args d;
331 } sdata;
332 struct {
333 n_long h[RPC_HEADER_WORDS];
334 struct nfs_read_repl d;
335 } rdata;
336 size_t cc;
337 long x;
338 int hlen, rlen;
339
340 args = &sdata.d;
341 repl = &rdata.d;
342
343 bcopy(d->fh, args->fh, NFS_FHSIZE);
344 args->off = htonl((n_long)off);
345 if (len > NFSREAD_SIZE)
346 len = NFSREAD_SIZE;
347 args->len = htonl((n_long)len);
348 args->xxx = htonl((n_long)0);
349 hlen = sizeof(*repl) - NFSREAD_SIZE;
350
351 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
352 args, sizeof(*args),
353 repl, sizeof(*repl));
354 if (cc == -1) {
355 /* errno was already set by rpc_call */
356 return (-1);
357 }
358 if (cc < hlen) {
359 errno = EBADRPC;
360 return (-1);
361 }
362 if (repl->errno) {
363 errno = ntohl(repl->errno);
364 return (-1);
365 }
366 rlen = cc - hlen;
367 x = ntohl(repl->count);
368 if (rlen < x) {
369 printf("nfsread: short packet, %d < %ld\n", rlen, x);
370 errno = EBADRPC;
371 return(-1);
372 }
373 bcopy(repl->data, addr, x);
374 return (x);
375}
376
377/*
378 * Open a file.
379 * return zero or error number
380 */
381int
382nfs_open(upath, f)
383 const char *upath;
384 struct open_file *f;
385{
386 struct iodesc *desc;
387 struct nfs_iodesc *currfd;
388#ifndef NFS_NOSYMLINK
389 struct nfs_iodesc *newfd;
390 struct nfsv2_fattrs *fa;
391 register char *cp, *ncp;
392 register int c;
393 char namebuf[NFS_MAXPATHLEN + 1];
394 char linkbuf[NFS_MAXPATHLEN + 1];
395 int nlinks = 0;
396#endif
397 int error;
398 char *path;
399
400#ifdef NFS_DEBUG
401 if (debug)
402 printf("nfs_open: %s (rootpath=%s)\n", path, rootpath);
403#endif
404 if (!rootpath[0]) {
405 printf("no rootpath, no nfs\n");
406 return (ENXIO);
407 }
408
409 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
410 return(EINVAL);
411
412 /* Bind to a reserved port. */
413 desc->myport = htons(--rpc_port);
414 desc->destip = rootip;
415 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
416 return (error);
417 nfs_root_node.iodesc = desc;
418
419#ifndef NFS_NOSYMLINK
420 /* Fake up attributes for the root dir. */
421 fa = &nfs_root_node.fa;
422 fa->fa_type = htonl(NFDIR);
423 fa->fa_mode = htonl(0755);
424 fa->fa_nlink = htonl(2);
425
426 currfd = &nfs_root_node;
427 newfd = 0;
428
429 cp = path = strdup(upath);
430 if (path == NULL) {
431 error = ENOMEM;
432 goto out;
433 }
434 while (*cp) {
435 /*
436 * Remove extra separators
437 */
438 while (*cp == '/')
439 cp++;
440
441 if (*cp == '\0')
442 break;
443 /*
444 * Check that current node is a directory.
445 */
446 if (currfd->fa.fa_type != htonl(NFDIR)) {
447 error = ENOTDIR;
448 goto out;
449 }
450
451 /* allocate file system specific data structure */
452 newfd = malloc(sizeof(*newfd));
453 newfd->iodesc = currfd->iodesc;
454 newfd->off = 0;
455
456 /*
457 * Get next component of path name.
458 */
459 {
460 register int len = 0;
461
462 ncp = cp;
463 while ((c = *cp) != '\0' && c != '/') {
464 if (++len > NFS_MAXNAMLEN) {
465 error = ENOENT;
466 goto out;
467 }
468 cp++;
469 }
470 *cp = '\0';
471 }
472
473 /* lookup a file handle */
474 error = nfs_lookupfh(currfd, ncp, newfd);
475 *cp = c;
476 if (error)
477 goto out;
478
479 /*
480 * Check for symbolic link
481 */
482 if (newfd->fa.fa_type == htonl(NFLNK)) {
483 int link_len, len;
484
485 error = nfs_readlink(newfd, linkbuf);
486 if (error)
487 goto out;
488
489 link_len = strlen(linkbuf);
490 len = strlen(cp);
491
492 if (link_len + len > MAXPATHLEN
493 || ++nlinks > MAXSYMLINKS) {
494 error = ENOENT;
495 goto out;
496 }
497
498 bcopy(cp, &namebuf[link_len], len + 1);
499 bcopy(linkbuf, namebuf, link_len);
500
501 /*
502 * If absolute pathname, restart at root.
503 * If relative pathname, restart at parent directory.
504 */
505 cp = namebuf;
506 if (*cp == '/') {
507 if (currfd != &nfs_root_node)
508 free(currfd);
509 currfd = &nfs_root_node;
510 }
511
512 free(newfd);
513 newfd = 0;
514
515 continue;
516 }
517
518 if (currfd != &nfs_root_node)
519 free(currfd);
520 currfd = newfd;
521 newfd = 0;
522 }
523
524 error = 0;
525
526out:
527 if (newfd)
528 free(newfd);
529 if (path)
530 free(path);
531#else
532 /* allocate file system specific data structure */
533 currfd = malloc(sizeof(*currfd));
534 currfd->iodesc = desc;
535 currfd->off = 0;
536
537 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
538#endif
539 if (!error) {
540 f->f_fsdata = (void *)currfd;
541 return (0);
542 }
543
544#ifdef NFS_DEBUG
545 if (debug)
546 printf("nfs_open: %s lookupfh failed: %s\n",
547 path, strerror(error));
548#endif
549#ifndef NFS_NOSYMLINK
550 if (currfd != &nfs_root_node)
551#endif
552 free(currfd);
553
554 return (error);
555}
556
557int
558nfs_close(f)
559 struct open_file *f;
560{
561 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
562
563#ifdef NFS_DEBUG
564 if (debug)
565 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
566#endif
567
568 if (fp != &nfs_root_node && fp)
569 free(fp);
570 f->f_fsdata = (void *)0;
571
572 return (0);
573}
574
575/*
576 * read a portion of a file
577 */
578int
579nfs_read(f, buf, size, resid)
580 struct open_file *f;
581 void *buf;
582 size_t size;
583 size_t *resid; /* out */
584{
585 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
586 register ssize_t cc;
587 register char *addr = buf;
588
589#ifdef NFS_DEBUG
590 if (debug)
591 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
592 (int)fp->off);
593#endif
594 while ((int)size > 0) {
595 twiddle();
596 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
597 /* XXX maybe should retry on certain errors */
598 if (cc == -1) {
599#ifdef NFS_DEBUG
600 if (debug)
601 printf("nfs_read: read: %s", strerror(errno));
602#endif
603 return (errno); /* XXX - from nfs_readdata */
604 }
605 if (cc == 0) {
606#ifdef NFS_DEBUG
607 if (debug)
608 printf("nfs_read: hit EOF unexpectantly");
609#endif
610 goto ret;
611 }
612 fp->off += cc;
613 addr += cc;
614 size -= cc;
615 }
616ret:
617 if (resid)
618 *resid = size;
619
620 return (0);
621}
622
623/*
624 * Not implemented.
625 */
626int
627nfs_write(f, buf, size, resid)
628 struct open_file *f;
629 void *buf;
630 size_t size;
631 size_t *resid; /* out */
632{
633 return (EROFS);
634}
635
636off_t
637nfs_seek(f, offset, where)
638 struct open_file *f;
639 off_t offset;
640 int where;
641{
642 register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
643 n_long size = ntohl(d->fa.fa_size);
644
645 switch (where) {
646 case SEEK_SET:
647 d->off = offset;
648 break;
649 case SEEK_CUR:
650 d->off += offset;
651 break;
652 case SEEK_END:
653 d->off = size - offset;
654 break;
655 default:
656 return (-1);
657 }
658
659 return (d->off);
660}
661
662/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
663int nfs_stat_types[8] = {
664 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
665
666int
667nfs_stat(f, sb)
668 struct open_file *f;
669 struct stat *sb;
670{
671 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
672 register n_long ftype, mode;
673
674 ftype = ntohl(fp->fa.fa_type);
675 mode = ntohl(fp->fa.fa_mode);
676 mode |= nfs_stat_types[ftype & 7];
677
678 sb->st_mode = mode;
679 sb->st_nlink = ntohl(fp->fa.fa_nlink);
680 sb->st_uid = ntohl(fp->fa.fa_uid);
681 sb->st_gid = ntohl(fp->fa.fa_gid);
682 sb->st_size = ntohl(fp->fa.fa_size);
683
684 return (0);
685}
686
687static int
688nfs_readdir(struct open_file *f, struct dirent *d)
689{
690 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
691 struct nfs_readdir_args *args;
692 struct nfs_readdir_data *rd;
693 struct nfs_readdir_off *roff = NULL;
694 static char *buf;
695 static n_long cookie = 0;
696 size_t cc;
697 n_long eof;
698
699 struct {
700 n_long h[RPC_HEADER_WORDS];
701 struct nfs_readdir_args d;
702 } sdata;
703 static struct {
704 n_long h[RPC_HEADER_WORDS];
705 u_char d[NFS_READDIRSIZE];
706 } rdata;
707
708 if (cookie == 0) {
709 refill:
710 args = &sdata.d;
711 bzero(args, sizeof(*args));
712
713 bcopy(fp->fh, args->fh, NFS_FHSIZE);
714 args->cookie = htonl(cookie);
715 args->count = htonl(NFS_READDIRSIZE);
716
717 cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READDIR,
718 args, sizeof(*args),
719 rdata.d, sizeof(rdata.d));
720 buf = rdata.d;
721 roff = (struct nfs_readdir_off *)buf;
722 if (ntohl(roff->cookie) != 0)
723 return 1;
724 }
725 roff = (struct nfs_readdir_off *)buf;
726
727 if (ntohl(roff->follows) == 0) {
728 eof = ntohl((roff+1)->cookie);
729 if (eof) {
730 cookie = 0;
731 return 1;
732 }
733 goto refill;
734 }
735
736 buf += sizeof(struct nfs_readdir_off);
737 rd = (struct nfs_readdir_data *)buf;
738 d->d_namlen = ntohl(rd->len);
739 bcopy(rd->name, d->d_name, d->d_namlen);
740 d->d_name[d->d_namlen] = '\0';
741
742 buf += (sizeof(struct nfs_readdir_data) + roundup(htonl(rd->len),4));
743 roff = (struct nfs_readdir_off *)buf;
744 cookie = ntohl(roff->cookie);
745 return 0;
746}