nfs.c revision 1.5 1 /* $NetBSD: nfs.c,v 1.5 1995/02/19 23:51:39 mycroft 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 <nfs/rpcv2.h>
41 #include <nfs/nfsv2.h>
42
43 #include "stand.h"
44 #include "net.h"
45 #include "netif.h"
46 #include "nfs.h"
47 #include "rpc.h"
48
49 struct nfs_call_data {
50 u_char fh[NFS_FHSIZE];
51 u_long off;
52 u_long len;
53 u_long xxx; /* XXX what's this for? */
54 };
55
56 /* Data part of nfs rpc reply (also the largest thing we receive) */
57 struct nfs_reply_data {
58 u_long errno;
59 struct nfsv2_fattr fa;
60 u_long count;
61 u_char data[1200];
62 };
63 #define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data)
64
65 /* max number of nfs reads pending */
66 #define NFS_COUNT 10
67
68 static struct nfsstate {
69 u_long off;
70 u_long len;
71 int done;
72 void *addr;
73 u_long xid;
74 } nfsstate[NFS_COUNT];
75
76 static u_long nfscc;
77
78 struct nfs_iodesc {
79 off_t off;
80 size_t size;
81 u_char *fh;
82 struct iodesc *iodesc;
83 };
84
85 /* Fetch (mount) file handle */
86 static int
87 getmountfh(d, path, fhp)
88 register struct iodesc *d;
89 char *path;
90 u_char *fhp;
91 {
92 register int len;
93 struct {
94 u_long len;
95 char path[FNAME_SIZE];
96 } sdata;
97 struct {
98 u_long errno;
99 u_char fh[NFS_FHSIZE];
100 } rdata;
101 int cc;
102
103 #ifdef NFS_DEBUG
104 if (debug)
105 printf("getmountfh: called\n");
106 #endif
107 bzero(&sdata, sizeof(sdata));
108 len = strlen(path);
109 if (len > sizeof(sdata.path))
110 len = sizeof(sdata.path);
111 bcopy(path, sdata.path, len);
112 sdata.len = htonl(len);
113 len = sizeof(sdata) - sizeof(sdata.path) + roundup(len, sizeof(long));
114
115 if ((cc = callrpc(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
116 &sdata, len, &rdata, sizeof(rdata))) < 0)
117 return(-1);
118 if (cc < sizeof(rdata.errno))
119 panic("getmountfh: callrpc small read");
120 if (rdata.errno) {
121 errno = ntohl(rdata.errno);
122 return(-1);
123 }
124 bcopy(rdata.fh, fhp, sizeof(rdata.fh));
125 return(0);
126 }
127
128 /* Fetch file timestamp and size */
129 static int
130 getnfsinfo(d, tp, sp, fp, mp, up, gp)
131 register struct nfs_iodesc *d;
132 register time_t *tp;
133 u_long *sp, *fp;
134 mode_t *mp;
135 uid_t *up;
136 gid_t *gp;
137 {
138 register int rlen;
139 register u_long t;
140 struct {
141 u_long errno;
142 struct nfsv2_fattr fa;
143 } rdata;
144 int cc;
145
146 #ifdef NFS_DEBUG
147 if (debug)
148 printf("getnfsinfo: called\n");
149 #endif
150 rlen = sizeof(rdata);
151 #ifdef NFSX_FATTR
152 #if NFSX_FATTR(1) > NFSX_FATTR(0)
153 /* nqnfs makes this more painful than it needs to be */
154 rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
155 #endif
156 #endif
157 if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_GETATTR,
158 d->fh, NFS_FHSIZE, &rdata, rlen)) < 0)
159 return(-1);
160 if (cc < sizeof(rdata.errno))
161 panic("getnfsinfo: callrpc small read");
162 if (rdata.errno) {
163 errno = ntohl(rdata.errno);
164 return(-1);
165 }
166 if (tp) {
167 *tp = ntohl(rdata.fa.fa_nfsmtime.nfs_sec);
168 t = ntohl(rdata.fa.fa_nfsatime.nfs_sec);
169 if (*tp < t)
170 *tp = t;
171 }
172 if (sp)
173 *sp = ntohl(rdata.fa.fa_nfssize);
174 if (fp)
175 *fp = ntohl(rdata.fa.fa_type);
176 if (mp)
177 *mp = ntohl(rdata.fa.fa_mode);
178 if (up)
179 *up = ntohl(rdata.fa.fa_uid);
180 if (gp)
181 *gp = ntohl(rdata.fa.fa_gid);
182 return(0);
183 }
184
185 /* Lookup a file. Optionally return timestamp and size */
186 static int
187 lookupfh(d, name, fhp, tp, sp, fp)
188 struct nfs_iodesc *d;
189 char *name;
190 u_char *fhp;
191 time_t *tp;
192 u_long *sp, *fp;
193 {
194 register int len, rlen;
195 struct {
196 u_char fh[NFS_FHSIZE];
197 u_long len;
198 char name[FNAME_SIZE];
199 } sdata;
200 struct {
201 u_long errno;
202 u_char fh[NFS_FHSIZE];
203 struct nfsv2_fattr fa;
204 } rdata;
205 int cc;
206
207 #ifdef NFS_DEBUG
208 if (debug)
209 printf("lookupfh: called\n");
210 #endif
211
212 bzero(&sdata, sizeof(sdata));
213 bcopy(d->fh, sdata.fh, sizeof(sdata.fh));
214 len = strlen(name);
215 if (len > sizeof(sdata.name))
216 len = sizeof(sdata.name);
217 bcopy(name, sdata.name, len);
218 sdata.len = htonl(len);
219 len = sizeof(sdata) - sizeof(sdata.name) + roundup(len, sizeof(long));
220
221 rlen = sizeof(rdata);
222 #if 0
223 #ifdef NFSX_FATTR
224 #if NFSX_FATTR(1) > NFSX_FATTR(0)
225 /* nqnfs makes this more painful than it needs to be */
226 rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
227 #endif
228 #endif
229 #endif
230 if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
231 &sdata, len, &rdata, rlen)) < 0)
232 return (-1);
233 if (cc < sizeof(rdata.errno))
234 panic("lookupfh: callrpc small read");
235 if (rdata.errno) {
236 errno = ntohl(rdata.errno);
237 return(-1);
238 }
239 bcopy(rdata.fh, fhp, sizeof(rdata.fh));
240 if (tp)
241 *tp = ntohl(rdata.fa.fa_nfsctime.nfs_sec);
242 if (sp)
243 *sp = ntohl(rdata.fa.fa_nfssize);
244 if (fp)
245 *fp = ntohl(rdata.fa.fa_type);
246 return (0);
247 }
248
249 static int
250 sendreaddata(d, pkt, len)
251 register struct nfs_iodesc *d;
252 register void *pkt;
253 register int len;
254 {
255 register int i;
256 register u_long cc;
257 register struct rpc_call *rpc;
258 register struct nfs_call_data *nfs;
259 register struct nfsstate *ns;
260
261 #ifdef NFS_DEBUG
262 if (debug)
263 printf("sendreaddata: called\n");
264 #endif
265
266 if (len != sizeof(*rpc) + sizeof(*nfs))
267 panic("sendreaddata: bad buffer (%d != %d)",
268 len, sizeof(*rpc) + sizeof(*nfs));
269 rpc = pkt;
270 nfs = (struct nfs_call_data *)(rpc + 1);
271 for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) {
272 if (ns->done)
273 continue;
274
275 rpc->rp_xid = ns->xid;
276 nfs->off = htonl(ns->off);
277 nfs->len = htonl(ns->len);
278 cc = sendudp(d->iodesc, rpc, len);
279
280 if (cc != len)
281 panic("sendreaddata: short write (%d != %d)", cc, len);
282 }
283 /* XXX we may have actually sent a lot more bytes... */
284
285 return (len);
286 }
287
288 /* Returns char count if done else -1 (and errno == 0) */
289 static int
290 recvreaddata(d, pkt, len)
291 register struct nfs_iodesc *d;
292 register void *pkt;
293 int len;
294 {
295 register int i;
296 register struct rpc_reply *rpc;
297 register struct nfs_reply_data *nfs;
298 register struct nfsstate *ns;
299
300 #ifdef NFS_DEBUG
301 if (debug)
302 printf("recvreaddata: called\n");
303 #endif
304 rpc = (struct rpc_reply *)checkudp(d->iodesc, pkt, &len);
305 if (rpc == NULL || len < sizeof(*rpc)) {
306 errno = 0;
307 return (-1);
308 }
309 len -= sizeof(*rpc);
310
311 NTOHL(rpc->rp_direction);
312 NTOHL(rpc->rp_stat);
313
314 if (rpc->rp_direction != REPLY || rpc->rp_stat != MSG_ACCEPTED) {
315 errno = 0;
316 return (-1);
317 }
318
319 for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns)
320 if (rpc->rp_xid == ns->xid)
321 break;
322 if (i >= NFS_COUNT) {
323 errno = 0;
324 return (-1);
325 }
326
327 if (ns->done) {
328 errno = 0;
329 return (-1);
330 }
331 #ifdef NFS_DEBUG
332 if (debug)
333 printf("recvreaddata: ns=%x\n", (u_int)ns);
334 #endif
335 nfs = (struct nfs_reply_data *)(rpc + 1);
336 if (len < sizeof(nfs->errno))
337 panic("recvreaddata: bad read %d", len);
338 if (nfs->errno) {
339 errno = ntohl(nfs->errno);
340 return (-1);
341 }
342 if (len < sizeof(*nfs) - sizeof(nfs->data))
343 panic("recvreaddata: less than nfs sized %d", len);
344 len -= sizeof(*nfs) - sizeof(nfs->data);
345
346 if (len < nfs->count)
347 panic("recvreaddata: short read (%d < %d)", len, nfs->count);
348 len = nfs->count;
349 if (len > ns->len)
350 panic("recvreaddata: huge read (%d > %d)", len, ns->len);
351
352
353 #ifdef NFS_DEBUG
354 if (debug)
355 printf("recvreaddata: read %d bytes.\n", len);
356 #endif
357 bcopy(nfs->data, ns->addr, len);
358 ns->done = 1;
359 nfscc += len;
360
361 if (len < ns->len) {
362 /* If first packet assume no more data to read */
363 if (i == 0)
364 return (0);
365
366 /* Short read, assume we are at EOF */
367 ++i;
368 ++ns;
369 while (i < NFS_COUNT) {
370 ns->done = 1;
371 ++i;
372 ++ns;
373 }
374 }
375
376 for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns)
377 if (!ns->done) {
378 errno = 0;
379 return (-1);
380 }
381
382 /* Return data count (thus indicating success) */
383 return (nfscc);
384 }
385
386 /* Read data from a file */
387 static int
388 readdata(d, off, addr, len)
389 register struct nfs_iodesc *d;
390 register off_t off;
391 register void *addr;
392 register u_long len;
393 {
394 register int i, cc;
395 register struct rpc_call *rpc;
396 register struct nfsstate *ns;
397 struct {
398 u_char header[HEADER_SIZE];
399 struct rpc_call rpc;
400 struct nfs_call_data nfs;
401 } sdata;
402 struct {
403 u_char header[HEADER_SIZE];
404 struct rpc_call rpc;
405 struct nfs_reply_data nfs;
406 } rdata;
407
408 #ifdef NFS_DEBUG
409 if (debug)
410 printf("readdata: addr=%x, off=%d len=%d\n", (u_int)addr, (u_int)off, len);
411 #endif
412 if (len == 0)
413 return (0);
414 d->iodesc->destport = getport(d->iodesc, NFS_PROG, NFS_VER2);
415
416 bzero(&sdata, sizeof(sdata));
417
418 for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) {
419 if (len <= 0) {
420 ns->done = 1;
421 continue;
422 }
423 ns->done = 0;
424
425 ns->xid = d->iodesc->xid;
426 ++d->iodesc->xid;
427
428 ns->off = (u_int)off;
429 ns->len = len;
430 if (ns->len > NFSREAD_SIZE)
431 ns->len = NFSREAD_SIZE;
432 #ifdef notdef
433 /* XXX to align or not align? It doesn't seem to speed things up... */
434 if ((ns->off % NFSREAD_SIZE) != 0)
435 ns->len -= off % NFSREAD_SIZE;
436 #endif
437
438 off += ns->len;
439 len -= ns->len;
440
441 ns->addr = addr;
442 addr += NFSREAD_SIZE;
443 }
444
445 rpc = &sdata.rpc;
446 rpc->rp_rpcvers = htonl(RPC_MSG_VERSION);
447 rpc->rp_prog = htonl(NFS_PROG);
448 rpc->rp_vers = htonl(NFS_VER2);
449 rpc->rp_proc = htonl(NFSPROC_READ);
450 bcopy(d->fh, sdata.nfs.fh, sizeof(sdata.nfs.fh));
451
452 nfscc = 0;
453 cc = sendrecv(d->iodesc,
454 sendreaddata, &sdata.rpc,
455 sizeof(struct rpc_call) + sizeof(struct nfs_call_data),
456 recvreaddata,
457 ((u_char *)&rdata.rpc) - HEADER_SIZE, HEADER_SIZE +
458 sizeof(struct rpc_call) + sizeof(struct nfs_reply_data));
459 return (cc);
460 }
461
462 static struct iodesc *mountfs;
463 static u_char mountfh[NFS_FHSIZE];
464 static time_t mounttime;
465
466 /*
467 * nfs_mount - mount this nfs filesystem to a host
468 */
469 int
470 nfs_mount(sock, ip, path)
471 int sock;
472 n_long ip;
473 char *path;
474 {
475 struct iodesc *desc;
476 struct nfs_iodesc *fp;
477 u_long ftype;
478
479 if (!(desc = socktodesc(sock))) {
480 errno = EINVAL;
481 return(-1);
482 }
483 bcopy(&desc->myea[4], &desc->myport, 2);
484 desc->destip = ip;
485 getmountfh(desc, path, mountfh);
486
487 fp = alloc(sizeof(struct nfs_iodesc));
488 fp->iodesc = desc;
489 fp->fh = mountfh;
490 fp->off = 0;
491 if (getnfsinfo(fp, &mounttime, NULL, &ftype, NULL, NULL, NULL) < 0) {
492 free(fp, sizeof(struct nfs_iodesc));
493 return(-1);
494 }
495
496 if (ftype != NFDIR) {
497 free(fp, sizeof(struct nfs_iodesc));
498 errno = EINVAL;
499 printf("nfs_mount: bad mount ftype %d", ftype);
500 return(-1);
501 }
502 #ifdef NFS_DEBUG
503 if (debug)
504 printf("nfs_mount: got fh for %s, mtime=%d, ftype=%d\n",
505 path, mounttime, ftype);
506 #endif
507 mountfs = desc;
508 free(fp, sizeof(struct nfs_iodesc));
509
510 return(0);
511 }
512
513 /*
514 * Open a file.
515 */
516 int
517 nfs_open(path, f)
518 char *path;
519 struct open_file *f;
520 {
521 register struct nfs_iodesc *fp;
522 u_char *imagefh;
523 u_long size, ftype;
524 int rc = 0;
525
526 #ifdef NFS_DEBUG
527 if (debug)
528 printf("nfs_open: %s\n", path);
529 #endif
530 if (!mountfs) {
531 errno = EIO;
532 printf("nfs_open: must mount first.\n");
533 return(-1);
534 }
535
536 /* allocate file system specific data structure */
537 fp = alloc(sizeof(struct nfs_iodesc));
538 fp->iodesc = mountfs;
539 fp->fh = mountfh;
540 fp->off = 0;
541
542 f->f_fsdata = (void *)fp;
543 imagefh = alloc(NFS_FHSIZE);
544 bzero(imagefh, NFS_FHSIZE);
545
546 /* lookup a file handle */
547 rc = lookupfh(fp, path, imagefh, NULL, &size, &ftype);
548 if (rc < 0) {
549 #ifdef NFS_DEBUG
550 if (debug)
551 printf("nfs_open: %s lookupfh failed: %s\n", path, strerror(errno));
552 #endif
553 f->f_fsdata = (void *)0;
554 free(fp, sizeof(struct nfs_iodesc));
555 free(imagefh, NFS_FHSIZE);
556 return(rc);
557 }
558 fp->fh = imagefh;
559
560 #ifdef NFS_DEBUG
561 if (debug)
562 printf("nfs_open: %s success, size=%d ftype=%d\n",
563 path, size, ftype);
564 #endif
565 fp->size = size;
566
567 return(rc);
568 }
569
570 int
571 nfs_close(f)
572 struct open_file *f;
573 {
574 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
575
576 #ifdef NFS_DEBUG
577 if (debug)
578 printf("nfs_close: called\n");
579 #endif
580 f->f_fsdata = (void *)0;
581 if (fp == (struct nfs_iodesc *)0)
582 return (0);
583
584 free(fp->fh, NFS_FHSIZE);
585 free(fp, sizeof(struct nfs_iodesc));
586
587 return (0);
588 }
589
590 /*
591 * read a portion of a file
592 */
593 int
594 nfs_read(f, addr, size, resid)
595 struct open_file *f;
596 char *addr;
597 u_int size;
598 u_int *resid; /* out */
599 {
600 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
601 register int cc;
602
603 #ifdef NFS_DEBUG
604 if (debug)
605 printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
606 #endif
607 while (size > 0) {
608 cc = readdata(fp->iodesc, fp->off, (void *)addr, size);
609 if (cc <= 0) {
610 /* XXX maybe should retry on certain errors */
611 if (cc < 0) {
612 #ifdef NFS_DEBUG
613 if (debug)
614 printf("nfs_read: read: %s",
615 strerror(errno));
616 #endif
617 return (-1);
618 }
619 if (debug)
620 printf("nfs_read: hit EOF unexpectantly");
621 goto ret;
622 }
623 fp->off += cc;
624 addr += cc;
625 size -= cc;
626 }
627 ret:
628 if (resid)
629 *resid = size;
630
631 return (0);
632 }
633
634 /*
635 * Not implemented.
636 */
637 int
638 nfs_write(f, start, size, resid)
639 struct open_file *f;
640 char *start;
641 u_int size;
642 u_int *resid; /* out */
643 {
644 errno = EROFS;
645
646 return (-1);
647 }
648
649 off_t
650 nfs_seek(f, offset, where)
651 struct open_file *f;
652 off_t offset;
653 int where;
654 {
655 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
656
657 switch (where) {
658 case SEEK_SET:
659 fp->off = offset;
660 break;
661 case SEEK_CUR:
662 fp->off += offset;
663 break;
664 case SEEK_END:
665 fp->off = fp->size - offset;
666 break;
667 default:
668 return (-1);
669 }
670 return (fp->off);
671 }
672
673 int
674 nfs_stat(f, sb)
675 struct open_file *f;
676 struct stat *sb;
677 {
678 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
679 mode_t mode = 0;
680 u_long ftype = 0;
681
682 #ifdef NFS_DEBUG
683 if (debug)
684 printf("nfs_stat: called\n");
685 #endif
686 if (getnfsinfo(fp, &mounttime, &sb->st_size, &ftype, &mode, &sb->st_uid, &sb->st_gid) < 0)
687 return(-1);
688
689 /* create a mode */
690 switch (ftype) {
691 case NFNON:
692 sb->st_mode = 0;
693 break;
694 case NFREG:
695 sb->st_mode = S_IFREG;
696 break;
697 case NFDIR:
698 sb->st_mode = S_IFDIR;
699 break;
700 case NFBLK:
701 sb->st_mode = S_IFBLK;
702 break;
703 case NFCHR:
704 sb->st_mode = S_IFCHR;
705 break;
706 case NFLNK:
707 sb->st_mode = S_IFLNK;
708 break;
709 }
710 sb->st_mode |= mode;
711
712 return (0);
713 }
714