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