dev.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dev.c (8241B)
       ---
            1 #include        "u.h"
            2 #include        "lib.h"
            3 #include        "mem.h"
            4 #include        "dat.h"
            5 #include        "fns.h"
            6 #include        "error.h"
            7 
            8 extern ulong        kerndate;
            9 
           10 void
           11 mkqid(Qid *q, vlong path, ulong vers, int type)
           12 {
           13         q->type = type;
           14         q->vers = vers;
           15         q->path = path;
           16 }
           17 
           18 int
           19 devno(int c, int user)
           20 {
           21         int i;
           22 
           23         for(i = 0; devtab[i] != nil; i++) {
           24                 if(devtab[i]->dc == c)
           25                         return i;
           26         }
           27         if(user == 0)
           28                 panic("devno %C %#ux", c, c);
           29 
           30         return -1;
           31 }
           32 
           33 void
           34 devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
           35 {
           36         db->name = n;
           37         if(c->flag&CMSG)
           38                 qid.type |= QTMOUNT;
           39         db->qid = qid;
           40         db->type = devtab[c->type]->dc;
           41         db->dev = c->dev;
           42         db->mode = perm;
           43         db->mode |= qid.type << 24;
           44         db->atime = seconds();
           45         db->mtime = kerndate;
           46         db->length = length;
           47         db->uid = user;
           48         db->gid = eve;
           49         db->muid = user;
           50 }
           51 
           52 /*
           53  * (here, Devgen is the prototype; devgen is the function in dev.c.)
           54  * 
           55  * a Devgen is expected to return the directory entry for ".."
           56  * if you pass it s==DEVDOTDOT (-1).  otherwise...
           57  * 
           58  * there are two contradictory rules.
           59  * 
           60  * (i) if c is a directory, a Devgen is expected to list its children
           61  * as you iterate s.
           62  * 
           63  * (ii) whether or not c is a directory, a Devgen is expected to list
           64  * its siblings as you iterate s.
           65  * 
           66  * devgen always returns the list of children in the root
           67  * directory.  thus it follows (i) when c is the root and (ii) otherwise.
           68  * many other Devgens follow (i) when c is a directory and (ii) otherwise.
           69  * 
           70  * devwalk assumes (i).  it knows that devgen breaks (i)
           71  * for children that are themselves directories, and explicitly catches them.
           72  * 
           73  * devstat assumes (ii).  if the Devgen in question follows (i)
           74  * for this particular c, devstat will not find the necessary info.
           75  * with our particular Devgen functions, this happens only for
           76  * directories, so devstat makes something up, assuming
           77  * c->name, c->qid, eve, DMDIR|0555.
           78  * 
           79  * devdirread assumes (i).  the callers have to make sure
           80  * that the Devgen satisfies (i) for the chan being read.
           81  */
           82 /*
           83  * the zeroth element of the table MUST be the directory itself for ..
           84 */
           85 int
           86 devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
           87 {
           88         if(tab == 0)
           89                 return -1;
           90         if(i == DEVDOTDOT){
           91                 /* nothing */
           92         }else if(name){
           93                 for(i=1; i<ntab; i++)
           94                         if(strcmp(tab[i].name, name) == 0)
           95                                 break;
           96                 if(i==ntab)
           97                         return -1;
           98                 tab += i;
           99         }else{
          100                 /* skip over the first element, that for . itself */
          101                 i++;
          102                 if(i >= ntab)
          103                         return -1;
          104                 tab += i;
          105         }
          106         devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
          107         return 1;
          108 }
          109 
          110 void
          111 devreset(void)
          112 {
          113 }
          114 
          115 void
          116 devinit(void)
          117 {
          118 }
          119 
          120 void
          121 devshutdown(void)
          122 {
          123 }
          124 
          125 Chan*
          126 devattach(int tc, char *spec)
          127 {
          128         int n;
          129         Chan *c;
          130         char *buf;
          131 
          132         c = newchan();
          133         mkqid(&c->qid, 0, 0, QTDIR);
          134         c->type = devno(tc, 0);
          135         if(spec == nil)
          136                 spec = "";
          137         n = 1+UTFmax+strlen(spec)+1;
          138         buf = smalloc(n);
          139         snprint(buf, n, "#%C%s", tc, spec);
          140         c->path = newpath(buf);
          141         free(buf);
          142         return c;
          143 }
          144 
          145 
          146 Chan*
          147 devclone(Chan *c)
          148 {
          149         Chan *nc;
          150 
          151         if(c->flag & COPEN)
          152                 panic("clone of open file type %C\n", devtab[c->type]->dc);
          153 
          154         nc = newchan();
          155 
          156         nc->type = c->type;
          157         nc->dev = c->dev;
          158         nc->mode = c->mode;
          159         nc->qid = c->qid;
          160         nc->offset = c->offset;
          161         nc->umh = nil;
          162         nc->aux = c->aux;
          163         nc->mqid = c->mqid;
          164         nc->mcp = c->mcp;
          165         return nc;
          166 }
          167 
          168 Walkqid*
          169 devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen)
          170 {
          171         int i, j, alloc;
          172         Walkqid *wq;
          173         char *n;
          174         Dir dir;
          175 
          176         if(nname > 0)
          177                 isdir(c);
          178 
          179         alloc = 0;
          180         wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
          181         if(waserror()){
          182                 if(alloc && wq->clone!=nil)
          183                         cclose(wq->clone);
          184                 free(wq);
          185                 return nil;
          186         }
          187         if(nc == nil){
          188                 nc = devclone(c);
          189                 nc->type = 0;        /* device doesn't know about this channel yet */
          190                 alloc = 1;
          191         }
          192         wq->clone = nc;
          193 
          194         for(j=0; j<nname; j++){
          195                 if(!(nc->qid.type&QTDIR)){
          196                         if(j==0)
          197                                 error(Enotdir);
          198                         goto Done;
          199                 }
          200                 n = name[j];
          201                 if(strcmp(n, ".") == 0){
          202     Accept:
          203                         wq->qid[wq->nqid++] = nc->qid;
          204                         continue;
          205                 }
          206                 if(strcmp(n, "..") == 0){
          207                         if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){
          208                                 print("devgen walk .. in dev%s %llux broken\n",
          209                                         devtab[nc->type]->name, nc->qid.path);
          210                                 error("broken devgen");
          211                         }
          212                         nc->qid = dir.qid;
          213                         goto Accept;
          214                 }
          215                 /*
          216                  * Ugly problem: If we're using devgen, make sure we're
          217                  * walking the directory itself, represented by the first
          218                  * entry in the table, and not trying to step into a sub-
          219                  * directory of the table, e.g. /net/net. Devgen itself
          220                  * should take care of the problem, but it doesn't have
          221                  * the necessary information (that we're doing a walk).
          222                  */
          223                 if(gen==devgen && nc->qid.path!=tab[0].qid.path)
          224                         goto Notfound;
          225                 for(i=0;; i++) {
          226                         switch((*gen)(nc, n, tab, ntab, i, &dir)){
          227                         case -1:
          228                         Notfound:
          229                                 if(j == 0)
          230                                         error(Enonexist);
          231                                 kstrcpy(up->errstr, Enonexist, ERRMAX);
          232                                 goto Done;
          233                         case 0:
          234                                 continue;
          235                         case 1:
          236                                 if(strcmp(n, dir.name) == 0){
          237                                         nc->qid = dir.qid;
          238                                         goto Accept;
          239                                 }
          240                                 continue;
          241                         }
          242                 }
          243         }
          244         /*
          245          * We processed at least one name, so will return some data.
          246          * If we didn't process all nname entries succesfully, we drop
          247          * the cloned channel and return just the Qids of the walks.
          248          */
          249 Done:
          250         poperror();
          251         if(wq->nqid < nname){
          252                 if(alloc)
          253                         cclose(wq->clone);
          254                 wq->clone = nil;
          255         }else if(wq->clone){
          256                 /* attach cloned channel to same device */
          257                 wq->clone->type = c->type;
          258         }
          259         return wq;
          260 }
          261 
          262 int
          263 devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
          264 {
          265         int i;
          266         Dir dir;
          267         char *p, *elem;
          268 
          269         for(i=0;; i++){
          270                 switch((*gen)(c, nil, tab, ntab, i, &dir)){
          271                 case -1:
          272                         if(c->qid.type & QTDIR){
          273                                 if(c->path == nil)
          274                                         elem = "???";
          275                                 else if(strcmp(c->path->s, "/") == 0)
          276                                         elem = "/";
          277                                 else
          278                                         for(elem=p=c->path->s; *p; p++)
          279                                                 if(*p == '/')
          280                                                         elem = p+1;
          281                                 devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
          282                                 n = convD2M(&dir, db, n);
          283                                 if(n == 0)
          284                                         error(Ebadarg);
          285                                 return n;
          286                         }
          287 
          288                         error(Enonexist);
          289                 case 0:
          290                         break;
          291                 case 1:
          292                         if(c->qid.path == dir.qid.path) {
          293                                 if(c->flag&CMSG)
          294                                         dir.mode |= DMMOUNT;
          295                                 n = convD2M(&dir, db, n);
          296                                 if(n == 0)
          297                                         error(Ebadarg);
          298                                 return n;
          299                         }
          300                         break;
          301                 }
          302         }
          303 }
          304 
          305 long
          306 devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
          307 {
          308         long m, dsz;
          309         Dir dir;
          310 
          311         for(m=0; m<n; c->dri++) {
          312                 switch((*gen)(c, nil, tab, ntab, c->dri, &dir)){
          313                 case -1:
          314                         return m;
          315 
          316                 case 0:
          317                         break;
          318 
          319                 case 1:
          320                         dsz = convD2M(&dir, (uchar*)d, n-m);
          321                         if(dsz <= BIT16SZ){        /* <= not < because this isn't stat; read is stuck */
          322                                 if(m == 0)
          323                                         error(Eshort);
          324                                 return m;
          325                         }
          326                         m += dsz;
          327                         d += dsz;
          328                         break;
          329                 }
          330         }
          331 
          332         return m;
          333 }
          334 
          335 /*
          336  * error(Eperm) if open permission not granted for up->user.
          337  */
          338 void
          339 devpermcheck(char *fileuid, ulong perm, int omode)
          340 {
          341         ulong t;
          342         static int access[] = { 0400, 0200, 0600, 0100 };
          343 
          344         if(strcmp(up->user, fileuid) == 0)
          345                 perm <<= 0;
          346         else
          347         if(strcmp(up->user, eve) == 0)
          348                 perm <<= 3;
          349         else
          350                 perm <<= 6;
          351 
          352         t = access[omode&3];
          353         if((t&perm) != t)
          354                 error(Eperm);
          355 }
          356 
          357 Chan*
          358 devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
          359 {
          360         int i;
          361         Dir dir;
          362 
          363         for(i=0;; i++) {
          364                 switch((*gen)(c, nil, tab, ntab, i, &dir)){
          365                 case -1:
          366                         goto Return;
          367                 case 0:
          368                         break;
          369                 case 1:
          370                         if(c->qid.path == dir.qid.path) {
          371                                 devpermcheck(dir.uid, dir.mode, omode);
          372                                 goto Return;
          373                         }
          374                         break;
          375                 }
          376         }
          377 Return:
          378         c->offset = 0;
          379         if((c->qid.type&QTDIR) && omode!=OREAD)
          380                 error(Eperm);
          381         c->mode = openmode(omode);
          382         c->flag |= COPEN;
          383         return c;
          384 }
          385 
          386 void
          387 devcreate(Chan *c, char *name, int mode, ulong perm)
          388 {
          389         error(Eperm);
          390 }
          391 
          392 Block*
          393 devbread(Chan *c, long n, ulong offset)
          394 {
          395         Block *bp;
          396 
          397         bp = allocb(n);
          398         if(bp == 0)
          399                 error(Enomem);
          400         if(waserror()) {
          401                 freeb(bp);
          402                 nexterror();
          403         }
          404         bp->wp += devtab[c->type]->read(c, bp->wp, n, offset);
          405         poperror();
          406         return bp;
          407 }
          408 
          409 long
          410 devbwrite(Chan *c, Block *bp, ulong offset)
          411 {
          412         long n;
          413 
          414         if(waserror()) {
          415                 freeb(bp);
          416                 nexterror();
          417         }
          418         n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);
          419         poperror();
          420         freeb(bp);
          421 
          422         return n;
          423 }
          424 
          425 void
          426 devremove(Chan *c)
          427 {
          428         error(Eperm);
          429 }
          430 
          431 int
          432 devwstat(Chan *c, uchar *stat, int nstat)
          433 {
          434         error(Eperm);
          435         return 0;
          436 }
          437 
          438 void
          439 devpower(int toggle)
          440 {
          441         error(Eperm);
          442 }
          443 
          444 int
          445 devconfig(int toggle, char *name, DevConf *conf)
          446 {
          447         error(Eperm);
          448         return 0;
          449 }