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