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