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