URI:
       tfsys.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
       ---
       tfsys.c (13315B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <draw.h>
            4 #include <thread.h>
            5 #include <cursor.h>
            6 #include <mouse.h>
            7 #include <keyboard.h>
            8 #include <frame.h>
            9 #include <fcall.h>
           10 #include <plumb.h>
           11 #include <libsec.h>
           12 #include "dat.h"
           13 #include "fns.h"
           14 
           15 static        int        sfd;
           16 
           17 enum
           18 {
           19         Nhash        = 16,
           20         DEBUG        = 0
           21 };
           22 
           23 static        Fid        *fids[Nhash];
           24 
           25 Fid        *newfid(int);
           26 
           27 static        Xfid*        fsysflush(Xfid*, Fid*);
           28 static        Xfid*        fsysauth(Xfid*, Fid*);
           29 static        Xfid*        fsysversion(Xfid*, Fid*);
           30 static        Xfid*        fsysattach(Xfid*, Fid*);
           31 static        Xfid*        fsyswalk(Xfid*, Fid*);
           32 static        Xfid*        fsysopen(Xfid*, Fid*);
           33 static        Xfid*        fsyscreate(Xfid*, Fid*);
           34 static        Xfid*        fsysread(Xfid*, Fid*);
           35 static        Xfid*        fsyswrite(Xfid*, Fid*);
           36 static        Xfid*        fsysclunk(Xfid*, Fid*);
           37 static        Xfid*        fsysremove(Xfid*, Fid*);
           38 static        Xfid*        fsysstat(Xfid*, Fid*);
           39 static        Xfid*        fsyswstat(Xfid*, Fid*);
           40 
           41 Xfid*         (*fcall[Tmax])(Xfid*, Fid*);
           42 
           43 static void
           44 initfcall(void)
           45 {
           46         fcall[Tflush]        = fsysflush;
           47         fcall[Tversion]        = fsysversion;
           48         fcall[Tauth]        = fsysauth;
           49         fcall[Tattach]        = fsysattach;
           50         fcall[Twalk]        = fsyswalk;
           51         fcall[Topen]        = fsysopen;
           52         fcall[Tcreate]        = fsyscreate;
           53         fcall[Tread]        = fsysread;
           54         fcall[Twrite]        = fsyswrite;
           55         fcall[Tclunk]        = fsysclunk;
           56         fcall[Tremove]= fsysremove;
           57         fcall[Tstat]        = fsysstat;
           58         fcall[Twstat]        = fsyswstat;
           59 }
           60 
           61 char Eperm[] = "permission denied";
           62 char Eexist[] = "file does not exist";
           63 char Enotdir[] = "not a directory";
           64 
           65 Dirtab dirtab[]=
           66 {
           67         { ".",                        QTDIR,        Qdir,                0500|DMDIR },
           68         { "acme",                QTDIR,        Qacme,        0500|DMDIR },
           69         { "cons",                QTFILE,        Qcons,        0600 },
           70         { "consctl",        QTFILE,        Qconsctl,        0000 },
           71         { "draw",                QTDIR,        Qdraw,        0000|DMDIR },        /* to suppress graphics progs started in acme */
           72         { "editout",        QTFILE,        Qeditout,        0200 },
           73         { "index",                QTFILE,        Qindex,        0400 },
           74         { "label",                QTFILE,        Qlabel,        0600 },
           75         { "log",                QTFILE,        Qlog,        0400 },
           76         { "new",                QTDIR,        Qnew,        0500|DMDIR },
           77         { nil, }
           78 };
           79 
           80 Dirtab dirtabw[]=
           81 {
           82         { ".",                        QTDIR,                Qdir,                        0500|DMDIR },
           83         { "addr",                QTFILE,                QWaddr,                0600 },
           84         { "body",                QTAPPEND,        QWbody,                0600|DMAPPEND },
           85         { "ctl",                QTFILE,                QWctl,                0600 },
           86         { "data",                QTFILE,                QWdata,                0600 },
           87         { "editout",        QTFILE,                QWeditout,        0200 },
           88         { "errors",                QTFILE,                QWerrors,                0200 },
           89         { "event",                QTFILE,                QWevent,                0600 },
           90         { "rdsel",                QTFILE,                QWrdsel,                0400 },
           91         { "wrsel",                QTFILE,                QWwrsel,                0200 },
           92         { "tag",                QTAPPEND,        QWtag,                0600|DMAPPEND },
           93         { "xdata",                QTFILE,                QWxdata,                0600 },
           94         { nil, }
           95 };
           96 
           97 typedef struct Mnt Mnt;
           98 struct Mnt
           99 {
          100         QLock        lk;
          101         int                id;
          102         Mntdir        *md;
          103 };
          104 
          105 Mnt        mnt;
          106 
          107 Xfid*        respond(Xfid*, Fcall*, char*);
          108 int                dostat(int, Dirtab*, uchar*, int, uint);
          109 uint        getclock(void);
          110 
          111 char        *user = "Wile E. Coyote";
          112 static int closing = 0;
          113 int        messagesize = Maxblock+IOHDRSZ;        /* good start */
          114 
          115 void        fsysproc(void *);
          116 
          117 void
          118 fsysinit(void)
          119 {
          120         int p[2];
          121         char *u;
          122 
          123         initfcall();
          124         if(pipe(p) < 0)
          125                 error("can't create pipe");
          126         if(post9pservice(p[0], "acme", mtpt) < 0)
          127                 error("can't post service");
          128         sfd = p[1];
          129         fmtinstall('F', fcallfmt);
          130         if((u = getuser()) != nil)
          131                 user = estrdup(u);
          132         proccreate(fsysproc, nil, STACK);
          133 }
          134 
          135 void
          136 fsysproc(void *v)
          137 {
          138         int n;
          139         Xfid *x;
          140         Fid *f;
          141         Fcall t;
          142         uchar *buf;
          143 
          144         threadsetname("fsysproc");
          145 
          146         USED(v);
          147         x = nil;
          148         for(;;){
          149                 buf = emalloc(messagesize+UTFmax);        /* overflow for appending partial rune in xfidwrite */
          150                 n = read9pmsg(sfd, buf, messagesize);
          151                 if(n <= 0){
          152                         if(closing)
          153                                 break;
          154                         error("i/o error on server channel");
          155                 }
          156                 if(x == nil){
          157                         sendp(cxfidalloc, nil);
          158                         x = recvp(cxfidalloc);
          159                 }
          160                 x->buf = buf;
          161                 if(convM2S(buf, n, &x->fcall) != n)
          162                         error("convert error in convM2S");
          163                 if(DEBUG)
          164                         fprint(2, "%F\n", &x->fcall);
          165                 if(fcall[x->fcall.type] == nil)
          166                         x = respond(x, &t, "bad fcall type");
          167                 else{
          168                         switch(x->fcall.type){
          169                         case Tversion:
          170                         case Tauth:
          171                         case Tflush:
          172                                 f = nil;
          173                                 break;
          174                         case Tattach:
          175                                 f = newfid(x->fcall.fid);
          176                                 break;
          177                         default:
          178                                 f = newfid(x->fcall.fid);
          179                                 if(!f->busy){
          180                                         x->f = f;
          181                                         x = respond(x, &t, "fid not in use");
          182                                         continue;
          183                                 }
          184                                 break;
          185                         }
          186                         x->f = f;
          187                         x  = (*fcall[x->fcall.type])(x, f);
          188                 }
          189         }
          190 }
          191 
          192 Mntdir*
          193 fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
          194 {
          195         Mntdir *m;
          196         int id;
          197 
          198         qlock(&mnt.lk);
          199         id = ++mnt.id;
          200         m = emalloc(sizeof *m);
          201         m->id = id;
          202         m->dir =  dir;
          203         m->ref = 1;        /* one for Command, one will be incremented in attach */
          204         m->ndir = ndir;
          205         m->next = mnt.md;
          206         m->incl = incl;
          207         m->nincl = nincl;
          208         mnt.md = m;
          209         qunlock(&mnt.lk);
          210         return m;
          211 }
          212 
          213 void
          214 fsysincid(Mntdir *m)
          215 {
          216         qlock(&mnt.lk);
          217         m->ref++;
          218         qunlock(&mnt.lk);
          219 }
          220 
          221 void
          222 fsysdelid(Mntdir *idm)
          223 {
          224         Mntdir *m, *prev;
          225         int i;
          226         char buf[64];
          227 
          228         if(idm == nil)
          229                 return;
          230         qlock(&mnt.lk);
          231         if(--idm->ref > 0){
          232                 qunlock(&mnt.lk);
          233                 return;
          234         }
          235         prev = nil;
          236         for(m=mnt.md; m; m=m->next){
          237                 if(m == idm){
          238                         if(prev)
          239                                 prev->next = m->next;
          240                         else
          241                                 mnt.md = m->next;
          242                         for(i=0; i<m->nincl; i++)
          243                                 free(m->incl[i]);
          244                         free(m->incl);
          245                         free(m->dir);
          246                         free(m);
          247                         qunlock(&mnt.lk);
          248                         return;
          249                 }
          250                 prev = m;
          251         }
          252         qunlock(&mnt.lk);
          253         sprint(buf, "fsysdelid: can't find id %d\n", idm->id);
          254         sendp(cerr, estrdup(buf));
          255 }
          256 
          257 /*
          258  * Called only in exec.c:/^run(), from a different FD group
          259  */
          260 Mntdir*
          261 fsysmount(Rune *dir, int ndir, Rune **incl, int nincl)
          262 {
          263         return fsysaddid(dir, ndir, incl, nincl);
          264 }
          265 
          266 void
          267 fsysclose(void)
          268 {
          269         closing = 1;
          270         /*
          271          * apparently this is not kosher on openbsd.
          272          * perhaps because fsysproc is reading from sfd right now,
          273          * the close hangs indefinitely.
          274         close(sfd);
          275          */
          276 }
          277 
          278 Xfid*
          279 respond(Xfid *x, Fcall *t, char *err)
          280 {
          281         int n;
          282 
          283         if(err){
          284                 t->type = Rerror;
          285                 t->ename = err;
          286         }else
          287                 t->type = x->fcall.type+1;
          288         t->fid = x->fcall.fid;
          289         t->tag = x->fcall.tag;
          290         if(x->buf == nil)
          291                 x->buf = emalloc(messagesize);
          292         n = convS2M(t, x->buf, messagesize);
          293         if(n <= 0)
          294                 error("convert error in convS2M");
          295         if(write(sfd, x->buf, n) != n)
          296                 error("write error in respond");
          297         free(x->buf);
          298         x->buf = nil;
          299         if(DEBUG)
          300                 fprint(2, "r: %F\n", t);
          301         return x;
          302 }
          303 
          304 static
          305 Xfid*
          306 fsysversion(Xfid *x, Fid *f)
          307 {
          308         Fcall t;
          309 
          310         USED(f);
          311         if(x->fcall.msize < 256)
          312                 return respond(x, &t, "version: message size too small");
          313         messagesize = x->fcall.msize;
          314         t.msize = messagesize;
          315         if(strncmp(x->fcall.version, "9P2000", 6) != 0)
          316                 return respond(x, &t, "unrecognized 9P version");
          317         t.version = "9P2000";
          318         return respond(x, &t, nil);
          319 }
          320 
          321 static
          322 Xfid*
          323 fsysauth(Xfid *x, Fid *f)
          324 {
          325         Fcall t;
          326 
          327         USED(f);
          328         return respond(x, &t, "acme: authentication not required");
          329 }
          330 
          331 static
          332 Xfid*
          333 fsysflush(Xfid *x, Fid *f)
          334 {
          335         USED(f);
          336         sendp(x->c, (void*)xfidflush);
          337         return nil;
          338 }
          339 
          340 static
          341 Xfid*
          342 fsysattach(Xfid *x, Fid *f)
          343 {
          344         Fcall t;
          345         int id;
          346         Mntdir *m;
          347         char buf[128];
          348 
          349         if(strcmp(x->fcall.uname, user) != 0)
          350                 return respond(x, &t, Eperm);
          351         f->busy = TRUE;
          352         f->open = FALSE;
          353         f->qid.path = Qdir;
          354         f->qid.type = QTDIR;
          355         f->qid.vers = 0;
          356         f->dir = dirtab;
          357         f->nrpart = 0;
          358         f->w = nil;
          359         t.qid = f->qid;
          360         f->mntdir = nil;
          361         id = atoi(x->fcall.aname);
          362         qlock(&mnt.lk);
          363         for(m=mnt.md; m; m=m->next)
          364                 if(m->id == id){
          365                         f->mntdir = m;
          366                         m->ref++;
          367                         break;
          368                 }
          369         if(m == nil && x->fcall.aname[0]){
          370                 snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname);
          371                 sendp(cerr, estrdup(buf));
          372         }
          373         qunlock(&mnt.lk);
          374         return respond(x, &t, nil);
          375 }
          376 
          377 static
          378 Xfid*
          379 fsyswalk(Xfid *x, Fid *f)
          380 {
          381         Fcall t;
          382         int c, i, j, id;
          383         Qid q;
          384         uchar type;
          385         ulong path;
          386         Fid *nf;
          387         Dirtab *d, *dir;
          388         Window *w;
          389         char *err;
          390 
          391         nf = nil;
          392         w = nil;
          393         if(f->open)
          394                 return respond(x, &t, "walk of open file");
          395         if(x->fcall.fid != x->fcall.newfid){
          396                 nf = newfid(x->fcall.newfid);
          397                 if(nf->busy)
          398                         return respond(x, &t, "newfid already in use");
          399                 nf->busy = TRUE;
          400                 nf->open = FALSE;
          401                 nf->mntdir = f->mntdir;
          402                 if(f->mntdir)
          403                         f->mntdir->ref++;
          404                 nf->dir = f->dir;
          405                 nf->qid = f->qid;
          406                 nf->w = f->w;
          407                 nf->nrpart = 0;        /* not open, so must be zero */
          408                 if(nf->w)
          409                         incref(&nf->w->ref);
          410                 f = nf;        /* walk f */
          411         }
          412 
          413         t.nwqid = 0;
          414         err = nil;
          415         dir = nil;
          416         id = WIN(f->qid);
          417         q = f->qid;
          418 
          419         if(x->fcall.nwname > 0){
          420                 for(i=0; i<x->fcall.nwname; i++){
          421                         if((q.type & QTDIR) == 0){
          422                                 err = Enotdir;
          423                                 break;
          424                         }
          425 
          426                         if(strcmp(x->fcall.wname[i], "..") == 0){
          427                                 type = QTDIR;
          428                                 path = Qdir;
          429                                 id = 0;
          430                                 if(w){
          431                                         winclose(w);
          432                                         w = nil;
          433                                 }
          434     Accept:
          435                                 if(i == MAXWELEM){
          436                                         err = "name too long";
          437                                         break;
          438                                 }
          439                                 q.type = type;
          440                                 q.vers = 0;
          441                                 q.path = QID(id, path);
          442                                 t.wqid[t.nwqid++] = q;
          443                                 continue;
          444                         }
          445 
          446                         /* is it a numeric name? */
          447                         for(j=0; (c=x->fcall.wname[i][j]); j++)
          448                                 if(c<'0' || '9'<c)
          449                                         goto Regular;
          450                         /* yes: it's a directory */
          451                         if(w)        /* name has form 27/23; get out before losing w */
          452                                 break;
          453                         id = atoi(x->fcall.wname[i]);
          454                         qlock(&row.lk);
          455                         w = lookid(id, FALSE);
          456                         if(w == nil){
          457                                 qunlock(&row.lk);
          458                                 break;
          459                         }
          460                         incref(&w->ref);        /* we'll drop reference at end if there's an error */
          461                         path = Qdir;
          462                         type = QTDIR;
          463                         qunlock(&row.lk);
          464                         dir = dirtabw;
          465                         goto Accept;
          466 
          467     Regular:
          468                         if(strcmp(x->fcall.wname[i], "new") == 0){
          469                                 if(w)
          470                                         error("w set in walk to new");
          471                                 sendp(cnewwindow, nil);        /* signal newwindowthread */
          472                                 w = recvp(cnewwindow);        /* receive new window */
          473                                 incref(&w->ref);
          474                                 type = QTDIR;
          475                                 path = QID(w->id, Qdir);
          476                                 id = w->id;
          477                                 dir = dirtabw;
          478                                 goto Accept;
          479                         }
          480 
          481                         if(id == 0)
          482                                 d = dirtab;
          483                         else
          484                                 d = dirtabw;
          485                         d++;        /* skip '.' */
          486                         for(; d->name; d++)
          487                                 if(strcmp(x->fcall.wname[i], d->name) == 0){
          488                                         path = d->qid;
          489                                         type = d->type;
          490                                         dir = d;
          491                                         goto Accept;
          492                                 }
          493 
          494                         break;        /* file not found */
          495                 }
          496 
          497                 if(i==0 && err == nil)
          498                         err = Eexist;
          499         }
          500 
          501         if(err!=nil || t.nwqid<x->fcall.nwname){
          502                 if(nf){
          503                         nf->busy = FALSE;
          504                         fsysdelid(nf->mntdir);
          505                 }
          506         }else if(t.nwqid  == x->fcall.nwname){
          507                 if(w){
          508                         f->w = w;
          509                         w = nil;        /* don't drop the reference */
          510                 }
          511                 if(dir)
          512                         f->dir = dir;
          513                 f->qid = q;
          514         }
          515 
          516         if(w != nil)
          517                 winclose(w);
          518 
          519         return respond(x, &t, err);
          520 }
          521 
          522 static
          523 Xfid*
          524 fsysopen(Xfid *x, Fid *f)
          525 {
          526         Fcall t;
          527         int m;
          528 
          529         /* can't truncate anything, so just disregard */
          530         x->fcall.mode &= ~(OTRUNC|OCEXEC);
          531         /* can't execute or remove anything */
          532         if(x->fcall.mode==OEXEC || (x->fcall.mode&ORCLOSE))
          533                 goto Deny;
          534         switch(x->fcall.mode){
          535         default:
          536                 goto Deny;
          537         case OREAD:
          538                 m = 0400;
          539                 break;
          540         case OWRITE:
          541                 m = 0200;
          542                 break;
          543         case ORDWR:
          544                 m = 0600;
          545                 break;
          546         }
          547         if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
          548                 goto Deny;
          549 
          550         sendp(x->c, (void*)xfidopen);
          551         return nil;
          552 
          553     Deny:
          554         return respond(x, &t, Eperm);
          555 }
          556 
          557 static
          558 Xfid*
          559 fsyscreate(Xfid *x, Fid *f)
          560 {
          561         Fcall t;
          562 
          563         USED(f);
          564         return respond(x, &t, Eperm);
          565 }
          566 
          567 static
          568 int
          569 idcmp(const void *a, const void *b)
          570 {
          571         return *(int*)a - *(int*)b;
          572 }
          573 
          574 static
          575 Xfid*
          576 fsysread(Xfid *x, Fid *f)
          577 {
          578         Fcall t;
          579         uchar *b;
          580         int i, id, n, o, e, j, k, *ids, nids;
          581         Dirtab *d, dt;
          582         Column *c;
          583         uint clock, len;
          584         char buf[16];
          585 
          586         if(f->qid.type & QTDIR){
          587                 if(FILE(f->qid) == Qacme){        /* empty dir */
          588                         t.data = nil;
          589                         t.count = 0;
          590                         respond(x, &t, nil);
          591                         return x;
          592                 }
          593                 o = x->fcall.offset;
          594                 e = x->fcall.offset+x->fcall.count;
          595                 clock = getclock();
          596                 b = emalloc(messagesize);
          597                 id = WIN(f->qid);
          598                 n = 0;
          599                 if(id > 0)
          600                         d = dirtabw;
          601                 else
          602                         d = dirtab;
          603                 d++;        /* first entry is '.' */
          604                 for(i=0; d->name!=nil && i<e; i+=len){
          605                         len = dostat(WIN(x->f->qid), d, b+n, x->fcall.count-n, clock);
          606                         if(len <= BIT16SZ)
          607                                 break;
          608                         if(i >= o)
          609                                 n += len;
          610                         d++;
          611                 }
          612                 if(id == 0){
          613                         qlock(&row.lk);
          614                         nids = 0;
          615                         ids = nil;
          616                         for(j=0; j<row.ncol; j++){
          617                                 c = row.col[j];
          618                                 for(k=0; k<c->nw; k++){
          619                                         ids = realloc(ids, (nids+1)*sizeof(int));
          620                                         ids[nids++] = c->w[k]->id;
          621                                 }
          622                         }
          623                         qunlock(&row.lk);
          624                         qsort(ids, nids, sizeof ids[0], idcmp);
          625                         j = 0;
          626                         dt.name = buf;
          627                         for(; j<nids && i<e; i+=len){
          628                                 k = ids[j];
          629                                 sprint(dt.name, "%d", k);
          630                                 dt.qid = QID(k, Qdir);
          631                                 dt.type = QTDIR;
          632                                 dt.perm = DMDIR|0700;
          633                                 len = dostat(k, &dt, b+n, x->fcall.count-n, clock);
          634                                 if(len == 0)
          635                                         break;
          636                                 if(i >= o)
          637                                         n += len;
          638                                 j++;
          639                         }
          640                         free(ids);
          641                 }
          642                 t.data = (char*)b;
          643                 t.count = n;
          644                 respond(x, &t, nil);
          645                 free(b);
          646                 return x;
          647         }
          648         sendp(x->c, (void*)xfidread);
          649         return nil;
          650 }
          651 
          652 static
          653 Xfid*
          654 fsyswrite(Xfid *x, Fid *f)
          655 {
          656         USED(f);
          657         sendp(x->c, (void*)xfidwrite);
          658         return nil;
          659 }
          660 
          661 static
          662 Xfid*
          663 fsysclunk(Xfid *x, Fid *f)
          664 {
          665         fsysdelid(f->mntdir);
          666         sendp(x->c, (void*)xfidclose);
          667         return nil;
          668 }
          669 
          670 static
          671 Xfid*
          672 fsysremove(Xfid *x, Fid *f)
          673 {
          674         Fcall t;
          675 
          676         USED(f);
          677         return respond(x, &t, Eperm);
          678 }
          679 
          680 static
          681 Xfid*
          682 fsysstat(Xfid *x, Fid *f)
          683 {
          684         Fcall t;
          685 
          686         t.stat = emalloc(messagesize-IOHDRSZ);
          687         t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
          688         x = respond(x, &t, nil);
          689         free(t.stat);
          690         return x;
          691 }
          692 
          693 static
          694 Xfid*
          695 fsyswstat(Xfid *x, Fid *f)
          696 {
          697         Fcall t;
          698 
          699         USED(f);
          700         return respond(x, &t, Eperm);
          701 }
          702 
          703 Fid*
          704 newfid(int fid)
          705 {
          706         Fid *f, *ff, **fh;
          707 
          708         ff = nil;
          709         fh = &fids[fid&(Nhash-1)];
          710         for(f=*fh; f; f=f->next)
          711                 if(f->fid == fid)
          712                         return f;
          713                 else if(ff==nil && f->busy==FALSE)
          714                         ff = f;
          715         if(ff){
          716                 ff->fid = fid;
          717                 return ff;
          718         }
          719         f = emalloc(sizeof *f);
          720         f->fid = fid;
          721         f->next = *fh;
          722         *fh = f;
          723         return f;
          724 }
          725 
          726 uint
          727 getclock(void)
          728 {
          729         return time(0);
          730 }
          731 
          732 int
          733 dostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
          734 {
          735         Dir d;
          736 
          737         d.qid.path = QID(id, dir->qid);
          738         d.qid.vers = 0;
          739         d.qid.type = dir->type;
          740         d.mode = dir->perm;
          741         d.length = 0;        /* would be nice to do better */
          742         d.name = dir->name;
          743         d.uid = user;
          744         d.gid = user;
          745         d.muid = user;
          746         d.atime = clock;
          747         d.mtime = clock;
          748         return convD2M(&d, buf, nbuf);
          749 }