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