URI:
       tfs.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tfs.c (9945B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <authsrv.h>
            4 #include <fcall.h>
            5 #include "tapefs.h"
            6 
            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 */
           22 
           23 Fid *        newfid(int);
           24 int        ramstat(Ram*, uchar*, int);
           25 void        io(void);
           26 void        usage(void);
           27 int        perm(int);
           28 
           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*);
           34 
           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 }
           53 
           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";
           64 
           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 }
           73 
           74 void
           75 main(int argc, char *argv[])
           76 {
           77         Ram *r;
           78         char *defmnt, *defsrv;
           79         int p[2];
           80         char buf[TICKREQLEN];
           81 
           82         fmtinstall('F', fcallfmt);
           83         initfcalls();
           84 
           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++;
          102 
          103         case 'n':
          104                 newtap++;
          105                 break;
          106         default:
          107                 usage();
          108         }ARGEND
          109 
          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);
          138 
          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);
          152                 }
          153         }
          154         exits(0);
          155 }
          156 
          157 char*
          158 rversion(Fid *unused)
          159 {
          160         Fid *f;
          161 
          162         USED(unused);
          163 
          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";
          174 
          175         for(f = fids; f; f = f->next)
          176                 if(f->busy)
          177                         rclunk(f);
          178         return 0;
          179 }
          180 
          181 char*
          182 rauth(Fid *unused)
          183 {
          184         USED(unused);
          185 
          186         return Enoauth;
          187 }
          188 
          189 char*
          190 rflush(Fid *f)
          191 {
          192         USED(f);
          193         return 0;
          194 }
          195 
          196 char*
          197 rattach(Fid *f)
          198 {
          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;
          209 }
          210 
          211 char*
          212 rwalk(Fid *f)
          213 {
          214         Fid *nf;
          215         Ram *r;
          216         char *err;
          217         char *name;
          218         Ram *dir;
          219         int i;
          220 
          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;
          234         }
          235 
          236         thdr.nwqid = 0;
          237         err = nil;
          238         r = f->ram;
          239 
          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;
          245                         }
          246                         if(r->busy == 0){
          247                                 err = Enotexist;
          248                                 break;
          249                         }
          250                         r->atime = time(0);
          251                         name = rhdr.wname[i];
          252                         dir = r;
          253                         if(!perm(Pexec)){
          254                                 err = Eperm;
          255                                 break;
          256                         }
          257                         if(strcmp(name, "..") == 0){
          258                                 r = dir->parent;
          259    Accept:
          260                                 if(i == MAXWELEM){
          261                                         err = "name too long";
          262                                         break;
          263                                 }
          264                                  thdr.wqid[thdr.nwqid++] = r->qid;
          265                                 continue;
          266                         }
          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 */
          273                 }
          274 
          275                 if(i==0 && err == nil)
          276                         err = Enotexist;
          277         }
          278 
          279         if(err!=nil || thdr.nwqid<rhdr.nwname){
          280                 if(nf){
          281                         nf->busy = 0;
          282                         nf->open = 0;
          283                         nf->ram = 0;
          284                 }
          285         }else if(thdr.nwqid  == rhdr.nwname)
          286                 f->ram = r;
          287 
          288         return err;
          289 
          290 }
          291 
          292 char *
          293 ropen(Fid *f)
          294 {
          295         Ram *r;
          296         int mode, trunc;
          297 
          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;
          312         }
          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++;
          330         }
          331         thdr.qid = r->qid;
          332         thdr.iounit = messagesize-IOHDRSZ;
          333         f->open = 1;
          334         r->open++;
          335         return 0;
          336 }
          337 
          338 char *
          339 rcreate(Fid *f)
          340 {
          341         USED(f);
          342 
          343         return Eperm;
          344 }
          345 
          346 char*
          347 rread(Fid *f)
          348 {
          349         int i, len;
          350         Ram *r;
          351         char *buf;
          352         uvlong off, end;
          353         int n, cnt;
          354 
          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;
          377                 }
          378                 thdr.count = n;
          379                 return 0;
          380         }
          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;
          391 }
          392 
          393 char*
          394 rwrite(Fid *f)
          395 {
          396         Ram *r;
          397         ulong off;
          398         int cnt;
          399 
          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;
          418 }
          419 
          420 char *
          421 rclunk(Fid *f)
          422 {
          423         if(f->open)
          424                 f->ram->open--;
          425         f->busy = 0;
          426         f->open = 0;
          427         f->ram = 0;
          428         return 0;
          429 }
          430 
          431 char *
          432 rremove(Fid *f)
          433 {
          434         USED(f);
          435         return Eperm;
          436 }
          437 
          438 char *
          439 rstat(Fid *f)
          440 {
          441         if(f->ram->busy == 0)
          442                 return Enotexist;
          443         thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ);
          444         return 0;
          445 }
          446 
          447 char *
          448 rwstat(Fid *f)
          449 {
          450         if(f->ram->busy == 0)
          451                 return Enotexist;
          452         return Eperm;
          453 }
          454 
          455 int
          456 ramstat(Ram *r, uchar *buf, int nbuf)
          457 {
          458         Dir dir;
          459 
          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);
          470 }
          471 
          472 Fid *
          473 newfid(int fid)
          474 {
          475         Fid *f, *ff;
          476 
          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;
          487         }
          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;
          496 }
          497 
          498 void
          499 io(void)
          500 {
          501         char *err;
          502         int n, nerr;
          503         char buf[ERRMAX];
          504 
          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;
          522                 }
          523                 nerr = 0;
          524                 buf[0] = '\0';
          525                 if(convM2S(mdata, n, &rhdr) != n)
          526                         error("convert error in convM2S");
          527 
          528                 if(verbose)
          529                         fprint(2, "tapefs: <=%F\n", &rhdr);/**/
          530 
          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;
          543                 }
          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");
          552         }
          553         if(buf[0]=='\0' || strstr(buf, "hungup"))
          554                 exits("");
          555         fprint(2, "%s: mount read: %s\n", argv0, buf);
          556         exits(buf);
          557 }
          558 
          559 int
          560 perm(int p)
          561 {
          562         if(p==Pwrite)
          563                 return 0;
          564         return 1;
          565 }
          566 
          567 void
          568 error(char *s)
          569 {
          570         fprint(2, "%s: %s: ", argv0, s);
          571         perror("");
          572         exits(s);
          573 }
          574 
          575 char*
          576 estrdup(char *s)
          577 {
          578         char *t;
          579 
          580         t = emalloc(strlen(s)+1);
          581         strcpy(t, s);
          582         return t;
          583 }
          584 
          585 void *
          586 emalloc(ulong n)
          587 {
          588         void *p;
          589         p = mallocz(n, 1);
          590         if(!p)
          591                 error("out of memory");
          592         return p;
          593 }
          594 
          595 void *
          596 erealloc(void *p, ulong n)
          597 {
          598         p = realloc(p, n);
          599         if(!p)
          600                 error("out of memory");
          601         return p;
          602 }
          603 
          604 void
          605 usage(void)
          606 {
          607         fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0);
          608         exits("usage");
          609 }