dev.c - vx32 - Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log
Files
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)
   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; jqid.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; mdri++) {
   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 }