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