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 verbose;20 int newtap; /* tap with time in sec */22 Fid * newfid(int);23 int ramstat(Ram*, uchar*, int);24 void io(void);25 void usage(void);26 int perm(int);28 char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*),29 *rattach(Fid*), *rwalk(Fid*),30 *ropen(Fid*), *rcreate(Fid*),31 *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),32 *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);34 char *(*fcalls[])(Fid*) = {35 [Tflush] rflush,36 [Tversion] rversion,37 [Tauth] rauth,38 [Tattach] rattach,39 [Twalk] rwalk,40 [Topen] ropen,41 [Tcreate] rcreate,42 [Tread] rread,43 [Twrite] rwrite,44 [Tclunk] rclunk,45 [Tremove] rremove,46 [Tstat] rstat,47 [Twstat] rwstat,48 };50 char Eperm[] = "permission denied";51 char Enotdir[] = "not a directory";52 char Enoauth[] = "tapefs: authentication not required";53 char Enotexist[] = "file does not exist";54 char Einuse[] = "file in use";55 char Eexist[] = "file exists";56 char Enotowner[] = "not owner";57 char Eisopen[] = "file already open for I/O";58 char Excl[] = "exclusive use file already open";59 char Ename[] = "illegal name";61 void62 notifyf(void *a, char *s)63 {64 USED(a);65 if(strncmp(s, "interrupt", 9) == 0)66 noted(NCONT);67 noted(NDFLT);68 }70 void71 main(int argc, char *argv[])72 {73 Ram *r;74 char *defmnt;75 int p[2];76 char buf[TICKREQLEN];78 fmtinstall('F', fcallfmt);80 defmnt = "tapefs";81 ARGBEGIN{82 case 'm':83 defmnt = ARGF();84 break;85 case 'p': /* password file */86 uidmap = getpass(ARGF());87 break;88 case 'g': /* group file */89 gidmap = getpass(ARGF());90 break;91 case 'v':92 verbose++;94 case 'n':95 newtap++;96 break;97 default:98 usage();99 }ARGEND101 if(argc==0)102 error("no file to mount");103 user = getuser();104 if(user == nil)105 user = "dmr";106 ram = r = (Ram *)emalloc(sizeof(Ram));107 r->busy = 1;108 r->data = 0;109 r->ndata = 0;110 r->perm = DMDIR | 0775;111 r->qid.path = 0;112 r->qid.vers = 0;113 r->qid.type = QTDIR;114 r->parent = 0;115 r->child = 0;116 r->next = 0;117 r->user = user;118 r->group = user;119 r->atime = time(0);120 r->mtime = r->atime;121 r->replete = 0;122 r->name = estrdup(".");123 populate(argv[0]);124 r->replete |= replete;125 if(pipe(p) < 0)126 error("pipe failed");127 mfd[0] = mfd[1] = p[0];128 notify(notifyf);130 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){131 case -1:132 error("fork");133 case 0:134 close(p[1]);135 notify(notifyf);136 io();137 break;138 default:139 close(p[0]); /* don't deadlock if child fails */140 if(post9pservice(p[1], defmnt) < 0) {141 sprint(buf, "post on `%s' failed", defmnt);142 error(buf);143 }144 }145 exits(0);146 }148 char*149 rversion(Fid *unused)150 {151 Fid *f;153 USED(unused);155 if(rhdr.msize < 256)156 return "version: message too small";157 if(rhdr.msize > messagesize)158 rhdr.msize = messagesize;159 else160 messagesize = rhdr.msize;161 thdr.msize = messagesize;162 if(strncmp(rhdr.version, "9P2000", 6) != 0)163 return "unrecognized 9P version";164 thdr.version = "9P2000";166 for(f = fids; f; f = f->next)167 if(f->busy)168 rclunk(f);169 return 0;170 }172 char*173 rauth(Fid *unused)174 {175 USED(unused);177 return Enoauth;178 }180 char*181 rflush(Fid *f)182 {183 USED(f);184 return 0;185 }187 char*188 rattach(Fid *f)189 {190 /* no authentication! */191 f->busy = 1;192 f->rclose = 0;193 f->ram = ram;194 thdr.qid = f->ram->qid;195 if(rhdr.uname[0])196 f->user = strdup(rhdr.uname);197 else198 f->user = "none";199 return 0;200 }202 char*203 rwalk(Fid *f)204 {205 Fid *nf;206 Ram *r;207 char *err;208 char *name;209 Ram *dir;210 int i;212 nf = nil;213 if(f->ram->busy == 0)214 return Enotexist;215 if(f->open)216 return Eisopen;217 if(rhdr.newfid != rhdr.fid){218 nf = newfid(rhdr.newfid);219 nf->busy = 1;220 nf->open = 0;221 nf->rclose = 0;222 nf->ram = f->ram;223 nf->user = f->user; /* no ref count; the leakage is minor */224 f = nf;225 }227 thdr.nwqid = 0;228 err = nil;229 r = f->ram;231 if(rhdr.nwname > 0){232 for(i=0; i<rhdr.nwname; i++){233 if((r->qid.type & QTDIR) == 0){234 err = Enotdir;235 break;236 }237 if(r->busy == 0){238 err = Enotexist;239 break;240 }241 r->atime = time(0);242 name = rhdr.wname[i];243 dir = r;244 if(!perm(Pexec)){245 err = Eperm;246 break;247 }248 if(strcmp(name, "..") == 0){249 r = dir->parent;250 Accept:251 if(i == MAXWELEM){252 err = "name too long";253 break;254 }255 thdr.wqid[thdr.nwqid++] = r->qid;256 continue;257 }258 if(!dir->replete)259 popdir(dir);260 for(r=dir->child; r; r=r->next)261 if(r->busy && strcmp(name, r->name)==0)262 goto Accept;263 break; /* file not found */264 }266 if(i==0 && err == nil)267 err = Enotexist;268 }270 if(err!=nil || thdr.nwqid<rhdr.nwname){271 if(nf){272 nf->busy = 0;273 nf->open = 0;274 nf->ram = 0;275 }276 }else if(thdr.nwqid == rhdr.nwname)277 f->ram = r;279 return err;281 }283 char *284 ropen(Fid *f)285 {286 Ram *r;287 int mode, trunc;289 if(f->open)290 return Eisopen;291 r = f->ram;292 if(r->busy == 0)293 return Enotexist;294 if(r->perm & DMEXCL)295 if(r->open)296 return Excl;297 mode = rhdr.mode;298 if(r->qid.type & QTDIR){299 if(mode != OREAD)300 return Eperm;301 thdr.qid = r->qid;302 return 0;303 }304 if(mode & ORCLOSE)305 return Eperm;306 trunc = mode & OTRUNC;307 mode &= OPERM;308 if(mode==OWRITE || mode==ORDWR || trunc)309 if(!perm(Pwrite))310 return Eperm;311 if(mode==OREAD || mode==ORDWR)312 if(!perm(Pread))313 return Eperm;314 if(mode==OEXEC)315 if(!perm(Pexec))316 return Eperm;317 if(trunc && (r->perm&DMAPPEND)==0){318 r->ndata = 0;319 dotrunc(r);320 r->qid.vers++;321 }322 thdr.qid = r->qid;323 thdr.iounit = messagesize-IOHDRSZ;324 f->open = 1;325 r->open++;326 return 0;327 }329 char *330 rcreate(Fid *f)331 {332 USED(f);334 return Eperm;335 }337 char*338 rread(Fid *f)339 {340 int i, len;341 Ram *r;342 char *buf;343 uvlong off, end;344 int n, cnt;346 if(f->ram->busy == 0)347 return Enotexist;348 n = 0;349 thdr.count = 0;350 off = rhdr.offset;351 end = rhdr.offset + rhdr.count;352 cnt = rhdr.count;353 if(cnt > messagesize-IOHDRSZ)354 cnt = messagesize-IOHDRSZ;355 buf = thdr.data;356 if(f->ram->qid.type & QTDIR){357 if(!f->ram->replete)358 popdir(f->ram);359 for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){360 if(!r->busy)361 continue;362 len = ramstat(r, (uchar*)buf+n, cnt-n);363 if(len <= BIT16SZ)364 break;365 if(i >= off)366 n += len;367 i += len;368 }369 thdr.count = n;370 return 0;371 }372 r = f->ram;373 if(off >= r->ndata)374 return 0;375 r->atime = time(0);376 n = cnt;377 if(off+n > r->ndata)378 n = r->ndata - off;379 thdr.data = doread(r, off, n);380 thdr.count = n;381 return 0;382 }384 char*385 rwrite(Fid *f)386 {387 Ram *r;388 ulong off;389 int cnt;391 r = f->ram;392 if(dopermw(f->ram)==0)393 return Eperm;394 if(r->busy == 0)395 return Enotexist;396 off = rhdr.offset;397 if(r->perm & DMAPPEND)398 off = r->ndata;399 cnt = rhdr.count;400 if(r->qid.type & QTDIR)401 return "file is a directory";402 if(off > 100*1024*1024) /* sanity check */403 return "write too big";404 dowrite(r, rhdr.data, off, cnt);405 r->qid.vers++;406 r->mtime = time(0);407 thdr.count = cnt;408 return 0;409 }411 char *412 rclunk(Fid *f)413 {414 if(f->open)415 f->ram->open--;416 f->busy = 0;417 f->open = 0;418 f->ram = 0;419 return 0;420 }422 char *423 rremove(Fid *f)424 {425 USED(f);426 return Eperm;427 }429 char *430 rstat(Fid *f)431 {432 if(f->ram->busy == 0)433 return Enotexist;434 thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ);435 return 0;436 }438 char *439 rwstat(Fid *f)440 {441 if(f->ram->busy == 0)442 return Enotexist;443 return Eperm;444 }446 int447 ramstat(Ram *r, uchar *buf, int nbuf)448 {449 Dir dir;451 dir.name = r->name;452 dir.qid = r->qid;453 dir.mode = r->perm;454 dir.length = r->ndata;455 dir.uid = r->user;456 dir.gid = r->group;457 dir.muid = r->user;458 dir.atime = r->atime;459 dir.mtime = r->mtime;460 return convD2M(&dir, buf, nbuf);461 }463 Fid *464 newfid(int fid)465 {466 Fid *f, *ff;468 ff = 0;469 for(f = fids; f; f = f->next)470 if(f->fid == fid)471 return f;472 else if(!ff && !f->busy)473 ff = f;474 if(ff){475 ff->fid = fid;476 ff->open = 0;477 ff->busy = 1;478 }479 f = emalloc(sizeof *f);480 f->ram = 0;481 f->fid = fid;482 f->busy = 1;483 f->open = 0;484 f->next = fids;485 fids = f;486 return f;487 }489 void490 io(void)491 {492 char *err;493 int n, nerr;494 char buf[ERRMAX];496 errstr(buf, sizeof buf);497 for(nerr=0, buf[0]='\0'; nerr<100; nerr++){498 /*499 * reading from a pipe or a network device500 * will give an error after a few eof reads501 * however, we cannot tell the difference502 * between a zero-length read and an interrupt503 * on the processes writing to us,504 * so we wait for the error505 */506 n = read9pmsg(mfd[0], mdata, sizeof mdata);507 if(n==0)508 continue;509 if(n < 0){510 if(buf[0]=='\0')511 errstr(buf, sizeof buf);512 continue;513 }514 nerr = 0;515 buf[0] = '\0';516 if(convM2S(mdata, n, &rhdr) != n)517 error("convert error in convM2S");519 if(verbose)520 fprint(2, "tapefs: <=%F\n", &rhdr);/**/522 thdr.data = (char*)mdata + IOHDRSZ;523 thdr.stat = mdata + IOHDRSZ;524 if(!fcalls[rhdr.type])525 err = "bad fcall type";526 else527 err = (*fcalls[rhdr.type])(newfid(rhdr.fid));528 if(err){529 thdr.type = Rerror;530 thdr.ename = err;531 }else{532 thdr.type = rhdr.type + 1;533 thdr.fid = rhdr.fid;534 }535 thdr.tag = rhdr.tag;536 n = convS2M(&thdr, mdata, messagesize);537 if(n <= 0)538 error("convert error in convS2M");539 if(verbose)540 fprint(2, "tapefs: =>%F\n", &thdr);/**/541 if(write(mfd[1], mdata, n) != n)542 error("mount write");543 }544 if(buf[0]=='\0' || strstr(buf, "hungup"))545 exits("");546 fprint(2, "%s: mount read: %s\n", argv0, buf);547 exits(buf);548 }550 int551 perm(int p)552 {553 if(p==Pwrite)554 return 0;555 return 1;556 }558 void559 error(char *s)560 {561 fprint(2, "%s: %s: ", argv0, s);562 perror("");563 exits(s);564 }566 char*567 estrdup(char *s)568 {569 char *t;571 t = emalloc(strlen(s)+1);572 strcpy(t, s);573 return t;574 }576 void *577 emalloc(ulong n)578 {579 void *p;580 p = mallocz(n, 1);581 if(!p)582 error("out of memory");583 return p;584 }586 void *587 erealloc(void *p, ulong n)588 {589 p = realloc(p, n);590 if(!p)591 error("out of memory");592 return p;593 }595 void596 usage(void)597 {598 fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0);599 exits("usage");600 }