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