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