The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/dev.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "../port/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*, char*, int, ulong)
  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*)
  427 {
  428         error(Eperm);
  429 }
  430 
  431 int
  432 devwstat(Chan*, uchar*, int)
  433 {
  434         error(Eperm);
  435         return 0;
  436 }
  437 
  438 void
  439 devpower(int)
  440 {
  441         error(Eperm);
  442 }
  443 
  444 int
  445 devconfig(int, char *, DevConf *)
  446 {
  447         error(Eperm);
  448         return 0;
  449 }

Cache object: a5cff5387280d90b145f0ebe574809cc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.