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