nfs.c revision 1.6 1 /* $NetBSD: nfs.c,v 1.6 1995/02/20 11:04:12 mycroft 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 struct nfs_call_data {
51 u_char fh[NFS_FHSIZE];
52 u_long off;
53 u_long len;
54 u_long xxx; /* XXX what's this for? */
55 };
56
57 /* Data part of nfs rpc reply (also the largest thing we receive) */
58 struct nfs_reply_data {
59 u_long errno;
60 struct nfsv2_fattr fa;
61 u_long count;
62 u_char data[1200];
63 };
64 #define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data)
65
66 struct nfs_iodesc {
67 off_t off;
68 size_t size;
69 u_char *fh;
70 struct iodesc *iodesc;
71 };
72
73 /* Fetch (mount) file handle */
74 static int
75 getmountfh(d, path, fhp)
76 register struct iodesc *d;
77 char *path;
78 u_char *fhp;
79 {
80 register int len;
81 struct {
82 u_long len;
83 char path[FNAME_SIZE];
84 } wbuf;
85 struct {
86 u_long errno;
87 u_char fh[NFS_FHSIZE];
88 } rbuf;
89 size_t cc;
90
91 #ifdef NFS_DEBUG
92 if (debug)
93 printf("getmountfh: called\n");
94 #endif
95
96 bzero(&wbuf, sizeof(wbuf));
97 len = strlen(path);
98 if (len > sizeof(wbuf.path))
99 len = sizeof(wbuf.path);
100 bcopy(path, wbuf.path, len);
101 wbuf.len = htonl(len);
102 len = sizeof(wbuf) - sizeof(wbuf.path) + roundup(len, sizeof(long));
103
104 if ((cc = callrpc(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
105 &wbuf, len, &rbuf, sizeof(rbuf))) == -1)
106 return (-1);
107 if (cc < sizeof(rbuf.errno))
108 panic("getmountfh: callrpc small read");
109 if (rbuf.errno) {
110 errno = ntohl(rbuf.errno);
111 return (-1);
112 }
113 bcopy(rbuf.fh, fhp, sizeof(rbuf.fh));
114 return (0);
115 }
116
117 /* Fetch file timestamp and size */
118 static int
119 getnfsinfo(d, tp, sp, fp, mp, up, gp)
120 register struct nfs_iodesc *d;
121 register time_t *tp;
122 u_long *sp, *fp;
123 mode_t *mp;
124 uid_t *up;
125 gid_t *gp;
126 {
127 register int rlen;
128 register u_long t;
129 struct {
130 u_long errno;
131 struct nfsv2_fattr fa;
132 } rbuf;
133 size_t cc;
134
135 #ifdef NFS_DEBUG
136 if (debug)
137 printf("getnfsinfo: called\n");
138 #endif
139 rlen = sizeof(rbuf);
140 #if NFSX_FATTR(1) > NFSX_FATTR(0)
141 /* nqnfs makes this more painful than it needs to be */
142 rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
143 #endif
144 if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_GETATTR,
145 d->fh, NFS_FHSIZE, &rbuf, rlen)) == -1)
146 return (-1);
147 if (cc < sizeof(rbuf.errno))
148 panic("getnfsinfo: callrpc small read");
149 if (rbuf.errno) {
150 errno = ntohl(rbuf.errno);
151 return (-1);
152 }
153 if (tp) {
154 *tp = ntohl(rbuf.fa.fa_nfsmtime.nfs_sec);
155 t = ntohl(rbuf.fa.fa_nfsatime.nfs_sec);
156 if (*tp < t)
157 *tp = t;
158 }
159 if (sp)
160 *sp = ntohl(rbuf.fa.fa_nfssize);
161 if (fp)
162 *fp = ntohl(rbuf.fa.fa_type);
163 if (mp)
164 *mp = ntohl(rbuf.fa.fa_mode);
165 if (up)
166 *up = ntohl(rbuf.fa.fa_uid);
167 if (gp)
168 *gp = ntohl(rbuf.fa.fa_gid);
169 return(0);
170 }
171
172 /* Lookup a file. Optionally return timestamp and size */
173 static int
174 lookupfh(d, name, fhp, tp, sp, fp)
175 struct nfs_iodesc *d;
176 char *name;
177 u_char *fhp;
178 time_t *tp;
179 u_long *sp, *fp;
180 {
181 register int len, rlen;
182 struct {
183 u_char fh[NFS_FHSIZE];
184 u_long len;
185 char name[FNAME_SIZE];
186 } wbuf;
187 struct {
188 u_long errno;
189 u_char fh[NFS_FHSIZE];
190 struct nfsv2_fattr fa;
191 } rbuf;
192 size_t cc;
193
194 #ifdef NFS_DEBUG
195 if (debug)
196 printf("lookupfh: called\n");
197 #endif
198
199 bzero(&wbuf, sizeof(wbuf));
200 bcopy(d->fh, wbuf.fh, sizeof(wbuf.fh));
201 len = strlen(name);
202 if (len > sizeof(wbuf.name))
203 len = sizeof(wbuf.name);
204 bcopy(name, wbuf.name, len);
205 wbuf.len = htonl(len);
206 len = sizeof(wbuf) - sizeof(wbuf.name) + roundup(len, sizeof(long));
207
208 rlen = sizeof(rbuf);
209 #ifdef NFSX_FATTR
210 #if NFSX_FATTR(1) > NFSX_FATTR(0)
211 /* nqnfs makes this more painful than it needs to be */
212 rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
213 #endif
214 #endif
215
216 if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
217 &wbuf, len, &rbuf, rlen)) == -1)
218 return (-1);
219 if (cc < sizeof(rbuf.errno))
220 panic("lookupfh: callrpc small read");
221 if (rbuf.errno) {
222 errno = ntohl(rbuf.errno);
223 return (-1);
224 }
225 bcopy(rbuf.fh, fhp, sizeof(rbuf.fh));
226 if (tp)
227 *tp = ntohl(rbuf.fa.fa_nfsctime.nfs_sec);
228 if (sp)
229 *sp = ntohl(rbuf.fa.fa_nfssize);
230 if (fp)
231 *fp = ntohl(rbuf.fa.fa_type);
232 return (0);
233 }
234
235 /* Read data from a file */
236 static size_t
237 readdata(d, off, addr, len)
238 register struct nfs_iodesc *d;
239 register off_t off;
240 register void *addr;
241 register size_t len;
242 {
243 size_t cc;
244 struct nfs_call_data wbuf;
245 struct nfs_reply_data rbuf;
246
247 bcopy(d->fh, wbuf.fh, NFS_FHSIZE);
248 wbuf.off = txdr_unsigned(off);
249 if (len > NFSREAD_SIZE)
250 len = NFSREAD_SIZE;
251 wbuf.len = txdr_unsigned(len);
252 wbuf.xxx = txdr_unsigned(0);
253
254 cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ,
255 &wbuf, sizeof(wbuf),
256 &rbuf, sizeof(rbuf) - NFSREAD_SIZE + len);
257 if (cc == -1 || cc < sizeof(rbuf) - NFSREAD_SIZE)
258 return (-1);
259
260 cc -= sizeof(rbuf) - NFSREAD_SIZE;
261 bcopy(rbuf.data, addr, cc);
262 return (cc);
263 }
264
265 static struct iodesc *mountfs;
266 static u_char mountfh[NFS_FHSIZE];
267 static time_t mounttime;
268
269 /*
270 * nfs_mount - mount this nfs filesystem to a host
271 */
272 int
273 nfs_mount(sock, ip, path)
274 int sock;
275 n_long ip;
276 char *path;
277 {
278 struct iodesc *desc;
279 struct nfs_iodesc *fp;
280 u_long ftype;
281
282 if (!(desc = socktodesc(sock))) {
283 errno = EINVAL;
284 return(-1);
285 }
286 bcopy(&desc->myea[4], &desc->myport, 2);
287 desc->destip = ip;
288 getmountfh(desc, path, mountfh);
289
290 fp = alloc(sizeof(struct nfs_iodesc));
291 fp->iodesc = desc;
292 fp->fh = mountfh;
293 fp->off = 0;
294 if (getnfsinfo(fp, &mounttime, NULL, &ftype, NULL, NULL, NULL) < 0) {
295 free(fp, sizeof(struct nfs_iodesc));
296 return(-1);
297 }
298
299 if (ftype != NFDIR) {
300 free(fp, sizeof(struct nfs_iodesc));
301 errno = EINVAL;
302 printf("nfs_mount: bad mount ftype %d", ftype);
303 return(-1);
304 }
305 #ifdef NFS_DEBUG
306 if (debug)
307 printf("nfs_mount: got fh for %s, mtime=%d, ftype=%d\n",
308 path, mounttime, ftype);
309 #endif
310 mountfs = desc;
311 free(fp, sizeof(struct nfs_iodesc));
312
313 return(0);
314 }
315
316 /*
317 * Open a file.
318 */
319 int
320 nfs_open(path, f)
321 char *path;
322 struct open_file *f;
323 {
324 register struct nfs_iodesc *fp;
325 u_char *imagefh;
326 u_long size, ftype;
327 int rc = 0;
328
329 #ifdef NFS_DEBUG
330 if (debug)
331 printf("nfs_open: %s\n", path);
332 #endif
333 if (!mountfs) {
334 errno = EIO;
335 printf("nfs_open: must mount first.\n");
336 return(-1);
337 }
338
339 /* allocate file system specific data structure */
340 fp = alloc(sizeof(struct nfs_iodesc));
341 fp->iodesc = mountfs;
342 fp->fh = mountfh;
343 fp->off = 0;
344
345 f->f_fsdata = (void *)fp;
346 imagefh = alloc(NFS_FHSIZE);
347 bzero(imagefh, NFS_FHSIZE);
348
349 /* lookup a file handle */
350 rc = lookupfh(fp, path, imagefh, NULL, &size, &ftype);
351 if (rc < 0) {
352 #ifdef NFS_DEBUG
353 if (debug)
354 printf("nfs_open: %s lookupfh failed: %s\n", path, strerror(errno));
355 #endif
356 f->f_fsdata = (void *)0;
357 free(fp, sizeof(struct nfs_iodesc));
358 free(imagefh, NFS_FHSIZE);
359 return(rc);
360 }
361 fp->fh = imagefh;
362
363 #ifdef NFS_DEBUG
364 if (debug)
365 printf("nfs_open: %s success, size=%d ftype=%d\n",
366 path, size, ftype);
367 #endif
368 fp->size = size;
369
370 return(rc);
371 }
372
373 int
374 nfs_close(f)
375 struct open_file *f;
376 {
377 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
378
379 #ifdef NFS_DEBUG
380 if (debug)
381 printf("nfs_close: called\n");
382 #endif
383 f->f_fsdata = (void *)0;
384 if (fp == (struct nfs_iodesc *)0)
385 return (0);
386
387 free(fp->fh, NFS_FHSIZE);
388 free(fp, sizeof(struct nfs_iodesc));
389
390 return (0);
391 }
392
393 /*
394 * read a portion of a file
395 */
396 int
397 nfs_read(f, addr, size, resid)
398 struct open_file *f;
399 char *addr;
400 u_int size;
401 u_int *resid; /* out */
402 {
403 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
404 register size_t cc;
405
406 #ifdef NFS_DEBUG
407 if (debug)
408 printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
409 #endif
410 while (size > 0) {
411 cc = readdata(fp->iodesc, fp->off, (void *)addr, size);
412 /* XXX maybe should retry on certain errors */
413 if (cc == -1) {
414 #ifdef NFS_DEBUG
415 if (debug)
416 printf("nfs_read: read: %s", strerror(errno));
417 #endif
418 return (-1);
419 }
420 if (cc == 0) {
421 if (debug)
422 printf("nfs_read: hit EOF unexpectantly");
423 goto ret;
424 }
425 fp->off += cc;
426 addr += cc;
427 size -= cc;
428 }
429 ret:
430 if (resid)
431 *resid = size;
432
433 return (0);
434 }
435
436 /*
437 * Not implemented.
438 */
439 int
440 nfs_write(f, start, size, resid)
441 struct open_file *f;
442 char *start;
443 u_int size;
444 u_int *resid; /* out */
445 {
446 errno = EROFS;
447
448 return (-1);
449 }
450
451 off_t
452 nfs_seek(f, offset, where)
453 struct open_file *f;
454 off_t offset;
455 int where;
456 {
457 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
458
459 switch (where) {
460 case SEEK_SET:
461 fp->off = offset;
462 break;
463 case SEEK_CUR:
464 fp->off += offset;
465 break;
466 case SEEK_END:
467 fp->off = fp->size - offset;
468 break;
469 default:
470 return (-1);
471 }
472 return (fp->off);
473 }
474
475 int
476 nfs_stat(f, sb)
477 struct open_file *f;
478 struct stat *sb;
479 {
480 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
481 mode_t mode = 0;
482 u_long ftype = 0;
483
484 #ifdef NFS_DEBUG
485 if (debug)
486 printf("nfs_stat: called\n");
487 #endif
488
489 if (getnfsinfo(fp, &mounttime, &sb->st_size, &ftype, &mode, &sb->st_uid, &sb->st_gid) < 0)
490 return(-1);
491
492 /* create a mode */
493 switch (ftype) {
494 case NFNON:
495 sb->st_mode = 0;
496 break;
497 case NFREG:
498 sb->st_mode = S_IFREG;
499 break;
500 case NFDIR:
501 sb->st_mode = S_IFDIR;
502 break;
503 case NFBLK:
504 sb->st_mode = S_IFBLK;
505 break;
506 case NFCHR:
507 sb->st_mode = S_IFCHR;
508 break;
509 case NFLNK:
510 sb->st_mode = S_IFLNK;
511 break;
512 }
513 sb->st_mode |= mode;
514
515 return (0);
516 }
517