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, *defsrv;
79 int p[2];
80 char buf[TICKREQLEN];
82 fmtinstall('F', fcallfmt);
83 initfcalls();
85 defmnt = nil;
86 defsrv = nil;
87 ARGBEGIN{
88 case 'm':
89 defmnt = ARGF();
90 break;
91 case 's':
92 defsrv = ARGF();
93 break;
94 case 'p': /* password file */
95 uidmap = getpass(ARGF());
96 break;
97 case 'g': /* group file */
98 gidmap = getpass(ARGF());
99 break;
100 case 'v':
101 verbose++;
103 case 'n':
104 newtap++;
105 break;
106 default:
107 usage();
108 }ARGEND
110 if(argc==0)
111 error("no file to mount");
112 user = getuser();
113 if(user == nil)
114 user = "dmr";
115 ram = r = (Ram *)emalloc(sizeof(Ram));
116 r->busy = 1;
117 r->data = 0;
118 r->ndata = 0;
119 r->perm = DMDIR | 0775;
120 r->qid.path = 0;
121 r->qid.vers = 0;
122 r->qid.type = QTDIR;
123 r->parent = 0;
124 r->child = 0;
125 r->next = 0;
126 r->user = user;
127 r->group = user;
128 r->atime = time(0);
129 r->mtime = r->atime;
130 r->replete = 0;
131 r->name = estrdup(".");
132 populate(argv[0]);
133 r->replete |= replete;
134 if(pipe(p) < 0)
135 error("pipe failed");
136 mfd[0] = mfd[1] = p[0];
137 notify(notifyf);
139 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
140 case -1:
141 error("fork");
142 case 0:
143 close(p[1]);
144 notify(notifyf);
145 io();
146 break;
147 default:
148 close(p[0]); /* don't deadlock if child fails */
149 if(post9pservice(p[1], defsrv, defmnt) < 0){
150 sprint(buf, "post9pservice: %r");
151 error(buf);
154 exits(0);
157 char*
158 rversion(Fid *unused)
160 Fid *f;
162 USED(unused);
164 if(rhdr.msize < 256)
165 return "version: message too small";
166 if(rhdr.msize > messagesize)
167 rhdr.msize = messagesize;
168 else
169 messagesize = rhdr.msize;
170 thdr.msize = messagesize;
171 if(strncmp(rhdr.version, "9P2000", 6) != 0)
172 return "unrecognized 9P version";
173 thdr.version = "9P2000";
175 for(f = fids; f; f = f->next)
176 if(f->busy)
177 rclunk(f);
178 return 0;
181 char*
182 rauth(Fid *unused)
184 USED(unused);
186 return Enoauth;
189 char*
190 rflush(Fid *f)
192 USED(f);
193 return 0;
196 char*
197 rattach(Fid *f)
199 /* no authentication! */
200 f->busy = 1;
201 f->rclose = 0;
202 f->ram = ram;
203 thdr.qid = f->ram->qid;
204 if(rhdr.uname[0])
205 f->user = strdup(rhdr.uname);
206 else
207 f->user = "none";
208 return 0;
211 char*
212 rwalk(Fid *f)
214 Fid *nf;
215 Ram *r;
216 char *err;
217 char *name;
218 Ram *dir;
219 int i;
221 nf = nil;
222 if(f->ram->busy == 0)
223 return Enotexist;
224 if(f->open)
225 return Eisopen;
226 if(rhdr.newfid != rhdr.fid){
227 nf = newfid(rhdr.newfid);
228 nf->busy = 1;
229 nf->open = 0;
230 nf->rclose = 0;
231 nf->ram = f->ram;
232 nf->user = f->user; /* no ref count; the leakage is minor */
233 f = nf;
236 thdr.nwqid = 0;
237 err = nil;
238 r = f->ram;
240 if(rhdr.nwname > 0){
241 for(i=0; i<rhdr.nwname; i++){
242 if((r->qid.type & QTDIR) == 0){
243 err = Enotdir;
244 break;
246 if(r->busy == 0){
247 err = Enotexist;
248 break;
250 r->atime = time(0);
251 name = rhdr.wname[i];
252 dir = r;
253 if(!perm(Pexec)){
254 err = Eperm;
255 break;
257 if(strcmp(name, "..") == 0){
258 r = dir->parent;
259 Accept:
260 if(i == MAXWELEM){
261 err = "name too long";
262 break;
264 thdr.wqid[thdr.nwqid++] = r->qid;
265 continue;
267 if(!dir->replete)
268 popdir(dir);
269 for(r=dir->child; r; r=r->next)
270 if(r->busy && strcmp(name, r->name)==0)
271 goto Accept;
272 break; /* file not found */
275 if(i==0 && err == nil)
276 err = Enotexist;
279 if(err!=nil || thdr.nwqid<rhdr.nwname){
280 if(nf){
281 nf->busy = 0;
282 nf->open = 0;
283 nf->ram = 0;
285 }else if(thdr.nwqid == rhdr.nwname)
286 f->ram = r;
288 return err;
292 char *
293 ropen(Fid *f)
295 Ram *r;
296 int mode, trunc;
298 if(f->open)
299 return Eisopen;
300 r = f->ram;
301 if(r->busy == 0)
302 return Enotexist;
303 if(r->perm & DMEXCL)
304 if(r->open)
305 return Excl;
306 mode = rhdr.mode;
307 if(r->qid.type & QTDIR){
308 if(mode != OREAD)
309 return Eperm;
310 thdr.qid = r->qid;
311 return 0;
313 if(mode & ORCLOSE)
314 return Eperm;
315 trunc = mode & OTRUNC;
316 mode &= OPERM;
317 if(mode==OWRITE || mode==ORDWR || trunc)
318 if(!perm(Pwrite))
319 return Eperm;
320 if(mode==OREAD || mode==ORDWR)
321 if(!perm(Pread))
322 return Eperm;
323 if(mode==OEXEC)
324 if(!perm(Pexec))
325 return Eperm;
326 if(trunc && (r->perm&DMAPPEND)==0){
327 r->ndata = 0;
328 dotrunc(r);
329 r->qid.vers++;
331 thdr.qid = r->qid;
332 thdr.iounit = messagesize-IOHDRSZ;
333 f->open = 1;
334 r->open++;
335 return 0;
338 char *
339 rcreate(Fid *f)
341 USED(f);
343 return Eperm;
346 char*
347 rread(Fid *f)
349 int i, len;
350 Ram *r;
351 char *buf;
352 uvlong off, end;
353 int n, cnt;
355 if(f->ram->busy == 0)
356 return Enotexist;
357 n = 0;
358 thdr.count = 0;
359 off = rhdr.offset;
360 end = rhdr.offset + rhdr.count;
361 cnt = rhdr.count;
362 if(cnt > messagesize-IOHDRSZ)
363 cnt = messagesize-IOHDRSZ;
364 buf = thdr.data;
365 if(f->ram->qid.type & QTDIR){
366 if(!f->ram->replete)
367 popdir(f->ram);
368 for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){
369 if(!r->busy)
370 continue;
371 len = ramstat(r, (uchar*)buf+n, cnt-n);
372 if(len <= BIT16SZ)
373 break;
374 if(i >= off)
375 n += len;
376 i += len;
378 thdr.count = n;
379 return 0;
381 r = f->ram;
382 if(off >= r->ndata)
383 return 0;
384 r->atime = time(0);
385 n = cnt;
386 if(off+n > r->ndata)
387 n = r->ndata - off;
388 thdr.data = doread(r, off, n);
389 thdr.count = n;
390 return 0;
393 char*
394 rwrite(Fid *f)
396 Ram *r;
397 ulong off;
398 int cnt;
400 r = f->ram;
401 if(dopermw(f->ram)==0)
402 return Eperm;
403 if(r->busy == 0)
404 return Enotexist;
405 off = rhdr.offset;
406 if(r->perm & DMAPPEND)
407 off = r->ndata;
408 cnt = rhdr.count;
409 if(r->qid.type & QTDIR)
410 return "file is a directory";
411 if(off > 100*1024*1024) /* sanity check */
412 return "write too big";
413 dowrite(r, rhdr.data, off, cnt);
414 r->qid.vers++;
415 r->mtime = time(0);
416 thdr.count = cnt;
417 return 0;
420 char *
421 rclunk(Fid *f)
423 if(f->open)
424 f->ram->open--;
425 f->busy = 0;
426 f->open = 0;
427 f->ram = 0;
428 return 0;
431 char *
432 rremove(Fid *f)
434 USED(f);
435 return Eperm;
438 char *
439 rstat(Fid *f)
441 if(f->ram->busy == 0)
442 return Enotexist;
443 thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ);
444 return 0;
447 char *
448 rwstat(Fid *f)
450 if(f->ram->busy == 0)
451 return Enotexist;
452 return Eperm;
455 int
456 ramstat(Ram *r, uchar *buf, int nbuf)
458 Dir dir;
460 dir.name = r->name;
461 dir.qid = r->qid;
462 dir.mode = r->perm;
463 dir.length = r->ndata;
464 dir.uid = r->user;
465 dir.gid = r->group;
466 dir.muid = r->user;
467 dir.atime = r->atime;
468 dir.mtime = r->mtime;
469 return convD2M(&dir, buf, nbuf);
472 Fid *
473 newfid(int fid)
475 Fid *f, *ff;
477 ff = 0;
478 for(f = fids; f; f = f->next)
479 if(f->fid == fid)
480 return f;
481 else if(!ff && !f->busy)
482 ff = f;
483 if(ff){
484 ff->fid = fid;
485 ff->open = 0;
486 ff->busy = 1;
488 f = emalloc(sizeof *f);
489 f->ram = 0;
490 f->fid = fid;
491 f->busy = 1;
492 f->open = 0;
493 f->next = fids;
494 fids = f;
495 return f;
498 void
499 io(void)
501 char *err;
502 int n, nerr;
503 char buf[ERRMAX];
505 errstr(buf, sizeof buf);
506 for(nerr=0, buf[0]='\0'; nerr<100; nerr++){
507 /*
508 * reading from a pipe or a network device
509 * will give an error after a few eof reads
510 * however, we cannot tell the difference
511 * between a zero-length read and an interrupt
512 * on the processes writing to us,
513 * so we wait for the error
514 */
515 n = read9pmsg(mfd[0], mdata, sizeof mdata);
516 if(n==0)
517 continue;
518 if(n < 0){
519 if(buf[0]=='\0')
520 errstr(buf, sizeof buf);
521 continue;
523 nerr = 0;
524 buf[0] = '\0';
525 if(convM2S(mdata, n, &rhdr) != n)
526 error("convert error in convM2S");
528 if(verbose)
529 fprint(2, "tapefs: <=%F\n", &rhdr);/**/
531 thdr.data = (char*)mdata + IOHDRSZ;
532 thdr.stat = mdata + IOHDRSZ;
533 if(!fcalls[rhdr.type])
534 err = "bad fcall type";
535 else
536 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
537 if(err){
538 thdr.type = Rerror;
539 thdr.ename = err;
540 }else{
541 thdr.type = rhdr.type + 1;
542 thdr.fid = rhdr.fid;
544 thdr.tag = rhdr.tag;
545 n = convS2M(&thdr, mdata, messagesize);
546 if(n <= 0)
547 error("convert error in convS2M");
548 if(verbose)
549 fprint(2, "tapefs: =>%F\n", &thdr);/**/
550 if(write(mfd[1], mdata, n) != n)
551 error("mount write");
553 if(buf[0]=='\0' || strstr(buf, "hungup"))
554 exits("");
555 fprint(2, "%s: mount read: %s\n", argv0, buf);
556 exits(buf);
559 int
560 perm(int p)
562 if(p==Pwrite)
563 return 0;
564 return 1;
567 void
568 error(char *s)
570 fprint(2, "%s: %s: ", argv0, s);
571 perror("");
572 exits(s);
575 char*
576 estrdup(char *s)
578 char *t;
580 t = emalloc(strlen(s)+1);
581 strcpy(t, s);
582 return t;
585 void *
586 emalloc(ulong n)
588 void *p;
589 p = mallocz(n, 1);
590 if(!p)
591 error("out of memory");
592 return p;
595 void *
596 erealloc(void *p, ulong n)
598 p = realloc(p, n);
599 if(!p)
600 error("out of memory");
601 return p;
604 void
605 usage(void)
607 fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0);
608 exits("usage");