Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <authsrv.h>
4 #include <fcall.h>
5 #include "tapefs.h"
7 Fid *fids;
8 Ram *ram;
9 int mfd[2];
10 char *user;
11 uchar mdata[Maxbuf+IOHDRSZ];
12 int messagesize = Maxbuf+IOHDRSZ;
13 Fcall rhdr;
14 Fcall thdr;
15 ulong path;
16 Idmap *uidmap;
17 Idmap *gidmap;
18 int replete;
19 int blocksize; /* for 32v */
20 int verbose;
21 int newtap; /* tap with time in sec */
23 Fid * newfid(int);
24 int ramstat(Ram*, uchar*, int);
25 void io(void);
26 void usage(void);
27 int perm(int);
29 char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*),
30 *rattach(Fid*), *rwalk(Fid*),
31 *ropen(Fid*), *rcreate(Fid*),
32 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
33 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
35 char *(*fcalls[Tmax])(Fid*);
36 void
37 initfcalls(void)
38 {
39 fcalls[Tflush]= rflush;
40 fcalls[Tversion]= rversion;
41 fcalls[Tauth]= rauth;
42 fcalls[Tattach]= rattach;
43 fcalls[Twalk]= rwalk;
44 fcalls[Topen]= ropen;
45 fcalls[Tcreate]= rcreate;
46 fcalls[Tread]= rread;
47 fcalls[Twrite]= rwrite;
48 fcalls[Tclunk]= rclunk;
49 fcalls[Tremove]= rremove;
50 fcalls[Tstat]= rstat;
51 fcalls[Twstat]= rwstat;
52 }
54 char Eperm[] = "permission denied";
55 char Enotdir[] = "not a directory";
56 char Enoauth[] = "tapefs: authentication not required";
57 char Enotexist[] = "file does not exist";
58 char Einuse[] = "file in use";
59 char Eexist[] = "file exists";
60 char Enotowner[] = "not owner";
61 char Eisopen[] = "file already open for I/O";
62 char Excl[] = "exclusive use file already open";
63 char Ename[] = "illegal name";
65 void
66 notifyf(void *a, char *s)
67 {
68 USED(a);
69 if(strncmp(s, "interrupt", 9) == 0)
70 noted(NCONT);
71 noted(NDFLT);
72 }
74 void
75 main(int argc, char *argv[])
76 {
77 Ram *r;
78 char *defmnt;
79 int p[2];
80 char buf[TICKREQLEN];
82 fmtinstall('F', fcallfmt);
83 initfcalls();
85 defmnt = "tapefs";
86 ARGBEGIN{
87 case 'm':
88 defmnt = ARGF();
89 break;
90 case 'p': /* password file */
91 uidmap = getpass(ARGF());
92 break;
93 case 'g': /* group file */
94 gidmap = getpass(ARGF());
95 break;
96 case 'v':
97 verbose++;
99 case 'n':
100 newtap++;
101 break;
102 default:
103 usage();
104 }ARGEND
106 if(argc==0)
107 error("no file to mount");
108 user = getuser();
109 if(user == nil)
110 user = "dmr";
111 ram = r = (Ram *)emalloc(sizeof(Ram));
112 r->busy = 1;
113 r->data = 0;
114 r->ndata = 0;
115 r->perm = DMDIR | 0775;
116 r->qid.path = 0;
117 r->qid.vers = 0;
118 r->qid.type = QTDIR;
119 r->parent = 0;
120 r->child = 0;
121 r->next = 0;
122 r->user = user;
123 r->group = user;
124 r->atime = time(0);
125 r->mtime = r->atime;
126 r->replete = 0;
127 r->name = estrdup(".");
128 populate(argv[0]);
129 r->replete |= replete;
130 if(pipe(p) < 0)
131 error("pipe failed");
132 mfd[0] = mfd[1] = p[0];
133 notify(notifyf);
135 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
136 case -1:
137 error("fork");
138 case 0:
139 close(p[1]);
140 notify(notifyf);
141 io();
142 break;
143 default:
144 close(p[0]); /* don't deadlock if child fails */
145 if(post9pservice(p[1], defmnt) < 0) {
146 sprint(buf, "post on `%s' failed", defmnt);
147 error(buf);
150 exits(0);
153 char*
154 rversion(Fid *unused)
156 Fid *f;
158 USED(unused);
160 if(rhdr.msize < 256)
161 return "version: message too small";
162 if(rhdr.msize > messagesize)
163 rhdr.msize = messagesize;
164 else
165 messagesize = rhdr.msize;
166 thdr.msize = messagesize;
167 if(strncmp(rhdr.version, "9P2000", 6) != 0)
168 return "unrecognized 9P version";
169 thdr.version = "9P2000";
171 for(f = fids; f; f = f->next)
172 if(f->busy)
173 rclunk(f);
174 return 0;
177 char*
178 rauth(Fid *unused)
180 USED(unused);
182 return Enoauth;
185 char*
186 rflush(Fid *f)
188 USED(f);
189 return 0;
192 char*
193 rattach(Fid *f)
195 /* no authentication! */
196 f->busy = 1;
197 f->rclose = 0;
198 f->ram = ram;
199 thdr.qid = f->ram->qid;
200 if(rhdr.uname[0])
201 f->user = strdup(rhdr.uname);
202 else
203 f->user = "none";
204 return 0;
207 char*
208 rwalk(Fid *f)
210 Fid *nf;
211 Ram *r;
212 char *err;
213 char *name;
214 Ram *dir;
215 int i;
217 nf = nil;
218 if(f->ram->busy == 0)
219 return Enotexist;
220 if(f->open)
221 return Eisopen;
222 if(rhdr.newfid != rhdr.fid){
223 nf = newfid(rhdr.newfid);
224 nf->busy = 1;
225 nf->open = 0;
226 nf->rclose = 0;
227 nf->ram = f->ram;
228 nf->user = f->user; /* no ref count; the leakage is minor */
229 f = nf;
232 thdr.nwqid = 0;
233 err = nil;
234 r = f->ram;
236 if(rhdr.nwname > 0){
237 for(i=0; i<rhdr.nwname; i++){
238 if((r->qid.type & QTDIR) == 0){
239 err = Enotdir;
240 break;
242 if(r->busy == 0){
243 err = Enotexist;
244 break;
246 r->atime = time(0);
247 name = rhdr.wname[i];
248 dir = r;
249 if(!perm(Pexec)){
250 err = Eperm;
251 break;
253 if(strcmp(name, "..") == 0){
254 r = dir->parent;
255 Accept:
256 if(i == MAXWELEM){
257 err = "name too long";
258 break;
260 thdr.wqid[thdr.nwqid++] = r->qid;
261 continue;
263 if(!dir->replete)
264 popdir(dir);
265 for(r=dir->child; r; r=r->next)
266 if(r->busy && strcmp(name, r->name)==0)
267 goto Accept;
268 break; /* file not found */
271 if(i==0 && err == nil)
272 err = Enotexist;
275 if(err!=nil || thdr.nwqid<rhdr.nwname){
276 if(nf){
277 nf->busy = 0;
278 nf->open = 0;
279 nf->ram = 0;
281 }else if(thdr.nwqid == rhdr.nwname)
282 f->ram = r;
284 return err;
288 char *
289 ropen(Fid *f)
291 Ram *r;
292 int mode, trunc;
294 if(f->open)
295 return Eisopen;
296 r = f->ram;
297 if(r->busy == 0)
298 return Enotexist;
299 if(r->perm & DMEXCL)
300 if(r->open)
301 return Excl;
302 mode = rhdr.mode;
303 if(r->qid.type & QTDIR){
304 if(mode != OREAD)
305 return Eperm;
306 thdr.qid = r->qid;
307 return 0;
309 if(mode & ORCLOSE)
310 return Eperm;
311 trunc = mode & OTRUNC;
312 mode &= OPERM;
313 if(mode==OWRITE || mode==ORDWR || trunc)
314 if(!perm(Pwrite))
315 return Eperm;
316 if(mode==OREAD || mode==ORDWR)
317 if(!perm(Pread))
318 return Eperm;
319 if(mode==OEXEC)
320 if(!perm(Pexec))
321 return Eperm;
322 if(trunc && (r->perm&DMAPPEND)==0){
323 r->ndata = 0;
324 dotrunc(r);
325 r->qid.vers++;
327 thdr.qid = r->qid;
328 thdr.iounit = messagesize-IOHDRSZ;
329 f->open = 1;
330 r->open++;
331 return 0;
334 char *
335 rcreate(Fid *f)
337 USED(f);
339 return Eperm;
342 char*
343 rread(Fid *f)
345 int i, len;
346 Ram *r;
347 char *buf;
348 uvlong off, end;
349 int n, cnt;
351 if(f->ram->busy == 0)
352 return Enotexist;
353 n = 0;
354 thdr.count = 0;
355 off = rhdr.offset;
356 end = rhdr.offset + rhdr.count;
357 cnt = rhdr.count;
358 if(cnt > messagesize-IOHDRSZ)
359 cnt = messagesize-IOHDRSZ;
360 buf = thdr.data;
361 if(f->ram->qid.type & QTDIR){
362 if(!f->ram->replete)
363 popdir(f->ram);
364 for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){
365 if(!r->busy)
366 continue;
367 len = ramstat(r, (uchar*)buf+n, cnt-n);
368 if(len <= BIT16SZ)
369 break;
370 if(i >= off)
371 n += len;
372 i += len;
374 thdr.count = n;
375 return 0;
377 r = f->ram;
378 if(off >= r->ndata)
379 return 0;
380 r->atime = time(0);
381 n = cnt;
382 if(off+n > r->ndata)
383 n = r->ndata - off;
384 thdr.data = doread(r, off, n);
385 thdr.count = n;
386 return 0;
389 char*
390 rwrite(Fid *f)
392 Ram *r;
393 ulong off;
394 int cnt;
396 r = f->ram;
397 if(dopermw(f->ram)==0)
398 return Eperm;
399 if(r->busy == 0)
400 return Enotexist;
401 off = rhdr.offset;
402 if(r->perm & DMAPPEND)
403 off = r->ndata;
404 cnt = rhdr.count;
405 if(r->qid.type & QTDIR)
406 return "file is a directory";
407 if(off > 100*1024*1024) /* sanity check */
408 return "write too big";
409 dowrite(r, rhdr.data, off, cnt);
410 r->qid.vers++;
411 r->mtime = time(0);
412 thdr.count = cnt;
413 return 0;
416 char *
417 rclunk(Fid *f)
419 if(f->open)
420 f->ram->open--;
421 f->busy = 0;
422 f->open = 0;
423 f->ram = 0;
424 return 0;
427 char *
428 rremove(Fid *f)
430 USED(f);
431 return Eperm;
434 char *
435 rstat(Fid *f)
437 if(f->ram->busy == 0)
438 return Enotexist;
439 thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ);
440 return 0;
443 char *
444 rwstat(Fid *f)
446 if(f->ram->busy == 0)
447 return Enotexist;
448 return Eperm;
451 int
452 ramstat(Ram *r, uchar *buf, int nbuf)
454 Dir dir;
456 dir.name = r->name;
457 dir.qid = r->qid;
458 dir.mode = r->perm;
459 dir.length = r->ndata;
460 dir.uid = r->user;
461 dir.gid = r->group;
462 dir.muid = r->user;
463 dir.atime = r->atime;
464 dir.mtime = r->mtime;
465 return convD2M(&dir, buf, nbuf);
468 Fid *
469 newfid(int fid)
471 Fid *f, *ff;
473 ff = 0;
474 for(f = fids; f; f = f->next)
475 if(f->fid == fid)
476 return f;
477 else if(!ff && !f->busy)
478 ff = f;
479 if(ff){
480 ff->fid = fid;
481 ff->open = 0;
482 ff->busy = 1;
484 f = emalloc(sizeof *f);
485 f->ram = 0;
486 f->fid = fid;
487 f->busy = 1;
488 f->open = 0;
489 f->next = fids;
490 fids = f;
491 return f;
494 void
495 io(void)
497 char *err;
498 int n, nerr;
499 char buf[ERRMAX];
501 errstr(buf, sizeof buf);
502 for(nerr=0, buf[0]='\0'; nerr<100; nerr++){
503 /*
504 * reading from a pipe or a network device
505 * will give an error after a few eof reads
506 * however, we cannot tell the difference
507 * between a zero-length read and an interrupt
508 * on the processes writing to us,
509 * so we wait for the error
510 */
511 n = read9pmsg(mfd[0], mdata, sizeof mdata);
512 if(n==0)
513 continue;
514 if(n < 0){
515 if(buf[0]=='\0')
516 errstr(buf, sizeof buf);
517 continue;
519 nerr = 0;
520 buf[0] = '\0';
521 if(convM2S(mdata, n, &rhdr) != n)
522 error("convert error in convM2S");
524 if(verbose)
525 fprint(2, "tapefs: <=%F\n", &rhdr);/**/
527 thdr.data = (char*)mdata + IOHDRSZ;
528 thdr.stat = mdata + IOHDRSZ;
529 if(!fcalls[rhdr.type])
530 err = "bad fcall type";
531 else
532 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
533 if(err){
534 thdr.type = Rerror;
535 thdr.ename = err;
536 }else{
537 thdr.type = rhdr.type + 1;
538 thdr.fid = rhdr.fid;
540 thdr.tag = rhdr.tag;
541 n = convS2M(&thdr, mdata, messagesize);
542 if(n <= 0)
543 error("convert error in convS2M");
544 if(verbose)
545 fprint(2, "tapefs: =>%F\n", &thdr);/**/
546 if(write(mfd[1], mdata, n) != n)
547 error("mount write");
549 if(buf[0]=='\0' || strstr(buf, "hungup"))
550 exits("");
551 fprint(2, "%s: mount read: %s\n", argv0, buf);
552 exits(buf);
555 int
556 perm(int p)
558 if(p==Pwrite)
559 return 0;
560 return 1;
563 void
564 error(char *s)
566 fprint(2, "%s: %s: ", argv0, s);
567 perror("");
568 exits(s);
571 char*
572 estrdup(char *s)
574 char *t;
576 t = emalloc(strlen(s)+1);
577 strcpy(t, s);
578 return t;
581 void *
582 emalloc(ulong n)
584 void *p;
585 p = mallocz(n, 1);
586 if(!p)
587 error("out of memory");
588 return p;
591 void *
592 erealloc(void *p, ulong n)
594 p = realloc(p, n);
595 if(!p)
596 error("out of memory");
597 return p;
600 void
601 usage(void)
603 fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0);
604 exits("usage");