nfs.c revision 1.13 1 /* $NetBSD: nfs.c,v 1.13 1996/02/26 21:50:09 scottr 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 "nfsv2.h"
42 #include <nfs/xdr_subs.h>
43
44 #include "stand.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_iodesc {
86 struct iodesc *iodesc;
87 off_t off;
88 u_char fh[NFS_FHSIZE];
89 struct nfsv2_fattrs fa; /* all in network order */
90 };
91
92 struct nfs_iodesc nfs_root_node;
93
94
95 /*
96 * Fetch the root file handle (call mount daemon)
97 * On error, return non-zero and set errno.
98 */
99 int
100 nfs_getrootfh(d, path, fhp)
101 register struct iodesc *d;
102 char *path;
103 u_char *fhp;
104 {
105 register int len;
106 struct args {
107 n_long len;
108 char path[FNAME_SIZE];
109 } *args;
110 struct repl {
111 n_long errno;
112 u_char fh[NFS_FHSIZE];
113 } *repl;
114 struct {
115 n_long h[RPC_HEADER_WORDS];
116 struct args d;
117 } sdata;
118 struct {
119 n_long h[RPC_HEADER_WORDS];
120 struct repl d;
121 } rdata;
122 size_t cc;
123
124 #ifdef NFS_DEBUG
125 if (debug)
126 printf("nfs_getrootfh: %s\n", path);
127 #endif
128
129 args = &sdata.d;
130 repl = &rdata.d;
131
132 bzero(args, sizeof(*args));
133 len = strlen(path);
134 if (len > sizeof(args->path))
135 len = sizeof(args->path);
136 args->len = htonl(len);
137 bcopy(path, args->path, len);
138 len = 4 + roundup(len, 4);
139
140 cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
141 args, len, repl, sizeof(*repl));
142 if (cc == -1) {
143 /* errno was set by rpc_call */
144 return (-1);
145 }
146 if (cc < 4) {
147 errno = EBADRPC;
148 return (-1);
149 }
150 if (repl->errno) {
151 errno = ntohl(repl->errno);
152 return (-1);
153 }
154 bcopy(repl->fh, fhp, sizeof(repl->fh));
155 return (0);
156 }
157
158 /*
159 * Lookup a file. Store handle and attributes.
160 * Return zero or error number.
161 */
162 int
163 nfs_lookupfh(d, name, newfd)
164 struct nfs_iodesc *d;
165 char *name;
166 struct nfs_iodesc *newfd;
167 {
168 register 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 * Read data from a file.
226 * Return transfer count or -1 (and set errno)
227 */
228 ssize_t
229 nfs_readdata(d, off, addr, len)
230 struct nfs_iodesc *d;
231 off_t off;
232 void *addr;
233 size_t len;
234 {
235 struct nfs_read_args *args;
236 struct nfs_read_repl *repl;
237 struct {
238 n_long h[RPC_HEADER_WORDS];
239 struct nfs_read_args d;
240 } sdata;
241 struct {
242 n_long h[RPC_HEADER_WORDS];
243 struct nfs_read_repl d;
244 } rdata;
245 size_t cc;
246 long x;
247 int hlen, rlen;
248
249 args = &sdata.d;
250 repl = &rdata.d;
251
252 bcopy(d->fh, args->fh, NFS_FHSIZE);
253 args->off = txdr_unsigned(off);
254 if (len > NFSREAD_SIZE)
255 len = NFSREAD_SIZE;
256 args->len = txdr_unsigned(len);
257 args->xxx = txdr_unsigned(0);
258 hlen = sizeof(*repl) - NFSREAD_SIZE;
259
260 cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
261 args, sizeof(*args),
262 repl, sizeof(*repl));
263 if (cc == -1) {
264 /* errno was already set by rpc_call */
265 return (-1);
266 }
267 if (cc < hlen) {
268 errno = EBADRPC;
269 return (-1);
270 }
271 if (repl->errno) {
272 errno = ntohl(repl->errno);
273 return (-1);
274 }
275 rlen = cc - hlen;
276 x = ntohl(repl->count);
277 if (rlen < x) {
278 printf("nfsread: short packet, %d < %d\n", rlen, x);
279 errno = EBADRPC;
280 return(-1);
281 }
282 bcopy(repl->data, addr, x);
283 return (x);
284 }
285
286 /*
287 * nfs_mount - mount this nfs filesystem to a host
288 * On error, return non-zero and set errno.
289 */
290 int
291 nfs_mount(sock, ip, path)
292 int sock;
293 struct in_addr ip;
294 char *path;
295 {
296 struct iodesc *desc;
297 struct nfsv2_fattrs *fa;
298
299 if (!(desc = socktodesc(sock))) {
300 errno = EINVAL;
301 return(-1);
302 }
303
304 /* Bind to a reserved port. */
305 desc->myport = htons(--rpc_port);
306 desc->destip = ip;
307 if (nfs_getrootfh(desc, path, nfs_root_node.fh))
308 return (-1);
309 nfs_root_node.iodesc = desc;
310 /* Fake up attributes for the root dir. */
311 fa = &nfs_root_node.fa;
312 fa->fa_type = htonl(NFDIR);
313 fa->fa_mode = htonl(0755);
314 fa->fa_nlink = htonl(2);
315
316 #ifdef NFS_DEBUG
317 if (debug)
318 printf("nfs_mount: got fh for %s\n", path);
319 #endif
320
321 return(0);
322 }
323
324 /*
325 * Open a file.
326 * return zero or error number
327 */
328 int
329 nfs_open(path, f)
330 char *path;
331 struct open_file *f;
332 {
333 struct nfs_iodesc *newfd;
334 int error = 0;
335
336 #ifdef NFS_DEBUG
337 if (debug)
338 printf("nfs_open: %s\n", path);
339 #endif
340 if (nfs_root_node.iodesc == NULL) {
341 printf("nfs_open: must mount first.\n");
342 return (ENXIO);
343 }
344
345 /* allocate file system specific data structure */
346 newfd = alloc(sizeof(*newfd));
347 newfd->iodesc = nfs_root_node.iodesc;
348 newfd->off = 0;
349
350 /* lookup a file handle */
351 error = nfs_lookupfh(&nfs_root_node, path, newfd);
352 if (!error) {
353 f->f_fsdata = (void *)newfd;
354 return (0);
355 }
356
357 #ifdef NFS_DEBUG
358 if (debug)
359 printf("nfs_open: %s lookupfh failed: %s\n",
360 path, strerror(error));
361 #endif
362 free(newfd, sizeof(*newfd));
363 return (error);
364 }
365
366 int
367 nfs_close(f)
368 struct open_file *f;
369 {
370 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
371
372 #ifdef NFS_DEBUG
373 if (debug)
374 printf("nfs_close: fp=0x%x\n", fp);
375 #endif
376
377 if (fp)
378 free(fp, sizeof(struct nfs_iodesc));
379 f->f_fsdata = (void *)0;
380
381 return (0);
382 }
383
384 /*
385 * read a portion of a file
386 */
387 int
388 nfs_read(f, buf, size, resid)
389 struct open_file *f;
390 void *buf;
391 size_t size;
392 size_t *resid; /* out */
393 {
394 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
395 register ssize_t cc;
396 register char *addr = buf;
397
398 #ifdef NFS_DEBUG
399 if (debug)
400 printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
401 #endif
402 while ((int)size > 0) {
403 twiddle();
404 cc = nfs_readdata(fp, fp->off, (void *)addr, size);
405 /* XXX maybe should retry on certain errors */
406 if (cc == -1) {
407 #ifdef NFS_DEBUG
408 if (debug)
409 printf("nfs_read: read: %s", strerror(errno));
410 #endif
411 return (errno); /* XXX - from nfs_readdata */
412 }
413 if (cc == 0) {
414 if (debug)
415 printf("nfs_read: hit EOF unexpectantly");
416 goto ret;
417 }
418 fp->off += cc;
419 addr += cc;
420 size -= cc;
421 }
422 ret:
423 if (resid)
424 *resid = size;
425
426 return (0);
427 }
428
429 /*
430 * Not implemented.
431 */
432 int
433 nfs_write(f, buf, size, resid)
434 struct open_file *f;
435 void *buf;
436 size_t size;
437 size_t *resid; /* out */
438 {
439 return (EROFS);
440 }
441
442 off_t
443 nfs_seek(f, offset, where)
444 struct open_file *f;
445 off_t offset;
446 int where;
447 {
448 register struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
449 n_long size = ntohl(d->fa.fa_size);
450
451 switch (where) {
452 case SEEK_SET:
453 d->off = offset;
454 break;
455 case SEEK_CUR:
456 d->off += offset;
457 break;
458 case SEEK_END:
459 d->off = size - offset;
460 break;
461 default:
462 return (-1);
463 }
464
465 return (d->off);
466 }
467
468 /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 */
469 int nfs_stat_types[8] = {
470 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, 0 };
471
472 int
473 nfs_stat(f, sb)
474 struct open_file *f;
475 struct stat *sb;
476 {
477 struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
478 register n_long ftype, mode;
479
480 ftype = ntohl(fp->fa.fa_type);
481 mode = ntohl(fp->fa.fa_mode);
482 mode |= nfs_stat_types[ftype & 7];
483
484 sb->st_mode = mode;
485 sb->st_nlink = ntohl(fp->fa.fa_nlink);
486 sb->st_uid = ntohl(fp->fa.fa_uid);
487 sb->st_gid = ntohl(fp->fa.fa_gid);
488 sb->st_size = ntohl(fp->fa.fa_size);
489
490 return (0);
491 }
492