Deleted Added
sdiff udiff text old ( 59824 ) new ( 59853 )
full compact
1/* $FreeBSD: head/lib/libstand/nfs.c 59824 2000-05-01 10:53:21Z 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_iodesc {
95 struct iodesc *iodesc;
96 off_t off;
97 u_char fh[NFS_FHSIZE];
98 struct nfsv2_fattrs fa; /* all in network order */
99};
100
101/*
102 * XXX interactions with tftp? See nfswrapper.c for a confusing
103 * issue.
104 */
105int nfs_open(const char *path, struct open_file *f);
106static int nfs_close(struct open_file *f);
107static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
108static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
109static off_t nfs_seek(struct open_file *f, off_t offset, int where);
110static int nfs_stat(struct open_file *f, struct stat *sb);
111
112static struct nfs_iodesc nfs_root_node;
113
114struct fs_ops nfs_fsops = {
115 "nfs",
116 nfs_open,
117 nfs_close,
118 nfs_read,
119 nfs_write,
120 nfs_seek,
121 nfs_stat,
122 null_readdir
123};
124
125/*
126 * Fetch the root file handle (call mount daemon)
127 * Return zero or error number.
128 */
129int
130nfs_getrootfh(d, path, fhp)
131 register struct iodesc *d;
132 char *path;
133 u_char *fhp;
134{
135 register int len;
136 struct args {
137 n_long len;
138 char path[FNAME_SIZE];
139 } *args;
140 struct repl {
141 n_long errno;
142 u_char fh[NFS_FHSIZE];
143 } *repl;
144 struct {
145 n_long h[RPC_HEADER_WORDS];
146 struct args d;
147 } sdata;
148 struct {
149 n_long h[RPC_HEADER_WORDS];
150 struct repl d;
151 } rdata;
152 size_t cc;
153
154#ifdef NFS_DEBUG
155 if (debug)
156 printf("nfs_getrootfh: %s\n", path);
157#endif
158
159 args = &sdata.d;
160 repl = &rdata.d;
161
162 bzero(args, sizeof(*args));
163 len = strlen(path);
164 if (len > sizeof(args->path))
165 len = sizeof(args->path);
166 args->len = htonl(len);
167 bcopy(path, args->path, len);
168 len = 4 + roundup(len, 4);
169
170 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
171 args, len, repl, sizeof(*repl));
172 if (cc == -1) {
173 /* errno was set by rpc_call */
174 return (errno);
175 }
176 if (cc < 4)
177 return (EBADRPC);
178 if (repl->errno)
179 return (ntohl(repl->errno));
180 bcopy(repl->fh, fhp, sizeof(repl->fh));
181 return (0);
182}
183
184/*
185 * Lookup a file. Store handle and attributes.
186 * Return zero or error number.
187 */
188int
189nfs_lookupfh(d, name, newfd)
190 struct nfs_iodesc *d;
191 const char *name;
192 struct nfs_iodesc *newfd;
193{
194 register int len, rlen;
195 struct args {
196 u_char fh[NFS_FHSIZE];
197 n_long len;
198 char name[FNAME_SIZE];
199 } *args;
200 struct repl {
201 n_long errno;
202 u_char fh[NFS_FHSIZE];
203 struct nfsv2_fattrs fa;
204 } *repl;
205 struct {
206 n_long h[RPC_HEADER_WORDS];
207 struct args d;
208 } sdata;
209 struct {
210 n_long h[RPC_HEADER_WORDS];
211 struct repl d;
212 } rdata;
213 ssize_t cc;
214
215#ifdef NFS_DEBUG
216 if (debug)
217 printf("lookupfh: called\n");
218#endif
219
220 args = &sdata.d;
221 repl = &rdata.d;
222
223 bzero(args, sizeof(*args));
224 bcopy(d->fh, args->fh, sizeof(args->fh));
225 len = strlen(name);
226 if (len > sizeof(args->name))
227 len = sizeof(args->name);
228 bcopy(name, args->name, len);
229 args->len = htonl(len);
230 len = 4 + roundup(len, 4);
231 len += NFS_FHSIZE;
232
233 rlen = sizeof(*repl);
234
235 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
236 args, len, repl, rlen);
237 if (cc == -1)
238 return (errno); /* XXX - from rpc_call */
239 if (cc < 4)
240 return (EIO);
241 if (repl->errno) {
242 /* saerrno.h now matches NFS error numbers. */
243 return (ntohl(repl->errno));
244 }
245 bcopy( repl->fh, &newfd->fh, sizeof(newfd->fh));
246 bcopy(&repl->fa, &newfd->fa, sizeof(newfd->fa));
247 return (0);
248}
249
250#ifndef NFS_NOSYMLINK
251/*
252 * Get the destination of a symbolic link.
253 */
254int
255nfs_readlink(d, buf)
256 struct nfs_iodesc *d;
257 char *buf;
258{
259 struct {
260 n_long h[RPC_HEADER_WORDS];
261 u_char fh[NFS_FHSIZE];
262 } sdata;
263 struct {
264 n_long h[RPC_HEADER_WORDS];
265 struct nfs_readlnk_repl d;
266 } rdata;
267 ssize_t cc;
268
269#ifdef NFS_DEBUG
270 if (debug)
271 printf("readlink: called\n");
272#endif
273
274 bcopy(d->fh, sdata.fh, NFS_FHSIZE);
275 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READLINK,
276 sdata.fh, NFS_FHSIZE,
277 &rdata.d, sizeof(rdata.d));
278 if (cc == -1)
279 return (errno);
280
281 if (cc < 4)
282 return (EIO);
283
284 if (rdata.d.errno)
285 return (ntohl(rdata.d.errno));
286
287 rdata.d.len = ntohl(rdata.d.len);
288 if (rdata.d.len > NFS_MAXPATHLEN)
289 return (ENAMETOOLONG);
290
291 bcopy(rdata.d.path, buf, rdata.d.len);
292 buf[rdata.d.len] = 0;
293 return (0);
294}
295#endif
296
297/*
298 * Read data from a file.
299 * Return transfer count or -1 (and set errno)
300 */
301ssize_t
302nfs_readdata(d, off, addr, len)
303 struct nfs_iodesc *d;
304 off_t off;
305 void *addr;
306 size_t len;
307{
308 struct nfs_read_args *args;
309 struct nfs_read_repl *repl;
310 struct {
311 n_long h[RPC_HEADER_WORDS];
312 struct nfs_read_args d;
313 } sdata;
314 struct {
315 n_long h[RPC_HEADER_WORDS];
316 struct nfs_read_repl d;
317 } rdata;
318 size_t cc;
319 long x;
320 int hlen, rlen;
321
322 args = &sdata.d;
323 repl = &rdata.d;
324
325 bcopy(d->fh, args->fh, NFS_FHSIZE);
326 args->off = htonl((n_long)off);
327 if (len > NFSREAD_SIZE)
328 len = NFSREAD_SIZE;
329 args->len = htonl((n_long)len);
330 args->xxx = htonl((n_long)0);
331 hlen = sizeof(*repl) - NFSREAD_SIZE;
332
333 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
334 args, sizeof(*args),
335 repl, sizeof(*repl));
336 if (cc == -1) {
337 /* errno was already set by rpc_call */
338 return (-1);
339 }
340 if (cc < hlen) {
341 errno = EBADRPC;
342 return (-1);
343 }
344 if (repl->errno) {
345 errno = ntohl(repl->errno);
346 return (-1);
347 }
348 rlen = cc - hlen;
349 x = ntohl(repl->count);
350 if (rlen < x) {
351 printf("nfsread: short packet, %d < %ld\n", rlen, x);
352 errno = EBADRPC;
353 return(-1);
354 }
355 bcopy(repl->data, addr, x);
356 return (x);
357}
358
359/*
360 * Open a file.
361 * return zero or error number
362 */
363int
364nfs_open(upath, f)
365 const char *upath;
366 struct open_file *f;
367{
368 struct iodesc *desc;
369 struct nfs_iodesc *currfd;
370#ifndef NFS_NOSYMLINK
371 struct nfs_iodesc *newfd;
372 struct nfsv2_fattrs *fa;
373 register char *cp, *ncp;
374 register int c;
375 char namebuf[NFS_MAXPATHLEN + 1];
376 char linkbuf[NFS_MAXPATHLEN + 1];
377 int nlinks = 0;
378#endif
379 int error;
380 char *path;
381
382#ifdef NFS_DEBUG
383 if (debug)
384 printf("nfs_open: %s (rootpath=%s)\n", path, rootpath);
385#endif
386 if (!rootpath[0]) {
387 printf("no rootpath, no nfs\n");
388 return (ENXIO);
389 }
390
391 if (!(desc = socktodesc(*(int *)(f->f_devdata))))
392 return(EINVAL);
393
394 /* Bind to a reserved port. */
395 desc->myport = htons(--rpc_port);
396 desc->destip = rootip;
397 if ((error = nfs_getrootfh(desc, rootpath, nfs_root_node.fh)))
398 return (error);
399 nfs_root_node.iodesc = desc;
400
401#ifndef NFS_NOSYMLINK
402 /* Fake up attributes for the root dir. */
403 fa = &nfs_root_node.fa;
404 fa->fa_type = htonl(NFDIR);
405 fa->fa_mode = htonl(0755);
406 fa->fa_nlink = htonl(2);
407
408 currfd = &nfs_root_node;
409 newfd = 0;
410
411 cp = path = strdup(upath);
412 if (path == NULL) {
413 error = ENOMEM;
414 goto out;
415 }
416 while (*cp) {
417 /*
418 * Remove extra separators
419 */
420 while (*cp == '/')
421 cp++;
422
423 if (*cp == '\0')
424 break;
425 /*
426 * Check that current node is a directory.
427 */
428 if (currfd->fa.fa_type != htonl(NFDIR)) {
429 error = ENOTDIR;
430 goto out;
431 }
432
433 /* allocate file system specific data structure */
434 newfd = malloc(sizeof(*newfd));
435 newfd->iodesc = currfd->iodesc;
436 newfd->off = 0;
437
438 /*
439 * Get next component of path name.
440 */
441 {
442 register int len = 0;
443
444 ncp = cp;
445 while ((c = *cp) != '\0' && c != '/') {
446 if (++len > NFS_MAXNAMLEN) {
447 error = ENOENT;
448 goto out;
449 }
450 cp++;
451 }
452 *cp = '\0';
453 }
454
455 /* lookup a file handle */
456 error = nfs_lookupfh(currfd, ncp, newfd);
457 *cp = c;
458 if (error)
459 goto out;
460
461 /*
462 * Check for symbolic link
463 */
464 if (newfd->fa.fa_type == htonl(NFLNK)) {
465 int link_len, len;
466
467 error = nfs_readlink(newfd, linkbuf);
468 if (error)
469 goto out;
470
471 link_len = strlen(linkbuf);
472 len = strlen(cp);
473
474 if (link_len + len > MAXPATHLEN
475 || ++nlinks > MAXSYMLINKS) {
476 error = ENOENT;
477 goto out;
478 }
479
480 bcopy(cp, &namebuf[link_len], len + 1);
481 bcopy(linkbuf, namebuf, link_len);
482
483 /*
484 * If absolute pathname, restart at root.
485 * If relative pathname, restart at parent directory.
486 */
487 cp = namebuf;
488 if (*cp == '/') {
489 if (currfd != &nfs_root_node)
490 free(currfd);
491 currfd = &nfs_root_node;
492 }
493
494 free(newfd);
495 newfd = 0;
496
497 continue;
498 }
499
500 if (currfd != &nfs_root_node)
501 free(currfd);
502 currfd = newfd;
503 newfd = 0;
504 }
505
506 error = 0;
507
508out:
509 if (newfd)
510 free(newfd);
511 if (path)
512 free(path);
513#else
514 /* allocate file system specific data structure */
515 currfd = malloc(sizeof(*currfd));
516 currfd->iodesc = desc;
517 currfd->off = 0;
518
519 error = nfs_lookupfh(&nfs_root_node, upath, currfd);
520#endif
521 if (!error) {
522 f->f_fsdata = (void *)currfd;
523 return (0);
524 }
525
526#ifdef NFS_DEBUG
527 if (debug)
528 printf("nfs_open: %s lookupfh failed: %s\n",
529 path, strerror(error));
530#endif
531#ifndef NFS_NOSYMLINK
532 if (currfd != &nfs_root_node)
533#endif
534 free(currfd);
535
536 return (error);
537}
538
539int
540nfs_close(f)
541 struct open_file *f;
542{
543 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
544
545#ifdef NFS_DEBUG
546 if (debug)
547 printf("nfs_close: fp=0x%lx\n", (u_long)fp);
548#endif
549
550 if (fp != &nfs_root_node && fp)
551 free(fp);
552 f->f_fsdata = (void *)0;
553
554 return (0);
555}
556
557/*
558 * read a portion of a file
559 */
560int
561nfs_read(f, buf, size, resid)
562 struct open_file *f;
563 void *buf;
564 size_t size;
565 size_t *resid; /* out */
566{
567 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
568 register ssize_t cc;
569 register char *addr = buf;
570
571#ifdef NFS_DEBUG
572 if (debug)
573 printf("nfs_read: size=%lu off=%d\n", (u_long)size,
574 (int)fp->off);
575#endif
576 while ((int)size > 0) {
577 twiddle();
578 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
579 /* XXX maybe should retry on certain errors */
580 if (cc == -1) {
581#ifdef NFS_DEBUG
582 if (debug)
583 printf("nfs_read: read: %s", strerror(errno));
584#endif
585 return (errno); /* XXX - from nfs_readdata */
586 }
587 if (cc == 0) {
588#ifdef NFS_DEBUG
589 if (debug)
590 printf("nfs_read: hit EOF unexpectantly");
591#endif
592 goto ret;
593 }
594 fp->off += cc;
595 addr += cc;
596 size -= cc;
597 }
598ret:
599 if (resid)
600 *resid = size;
601
602 return (0);
603}
604
605/*
606 * Not implemented.
607 */
608int
609nfs_write(f, buf, size, resid)
610 struct open_file *f;
611 void *buf;
612 size_t size;
613 size_t *resid; /* out */
614{
615 return (EROFS);
616}
617
618off_t
619nfs_seek(f, offset, where)
620 struct open_file *f;
621 off_t offset;
622 int where;
623{
624 register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
625 n_long size = ntohl(d->fa.fa_size);
626
627 switch (where) {
628 case SEEK_SET:
629 d->off = offset;
630 break;
631 case SEEK_CUR:
632 d->off += offset;
633 break;
634 case SEEK_END:
635 d->off = size - offset;
636 break;
637 default:
638 return (-1);
639 }
640
641 return (d->off);
642}
643
644/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
645int nfs_stat_types[8] = {
646 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
647
648int
649nfs_stat(f, sb)
650 struct open_file *f;
651 struct stat *sb;
652{
653 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
654 register n_long ftype, mode;
655
656 ftype = ntohl(fp->fa.fa_type);
657 mode = ntohl(fp->fa.fa_mode);
658 mode |= nfs_stat_types[ftype & 7];
659
660 sb->st_mode = mode;
661 sb->st_nlink = ntohl(fp->fa.fa_nlink);
662 sb->st_uid = ntohl(fp->fa.fa_uid);
663 sb->st_gid = ntohl(fp->fa.fa_gid);
664 sb->st_size = ntohl(fp->fa.fa_size);
665
666 return (0);
667}