usbd: added event file, removed usbdb
This commit is contained in:
parent
27fd88af23
commit
4792c6bef9
5 changed files with 245 additions and 327 deletions
|
@ -1,24 +1,7 @@
|
|||
typedef struct Rule Rule;
|
||||
typedef struct Cond Cond;
|
||||
typedef struct Hub Hub;
|
||||
typedef struct DHub DHub;
|
||||
typedef struct Port Port;
|
||||
|
||||
struct Rule {
|
||||
char **argv;
|
||||
int argc;
|
||||
Cond *cond;
|
||||
Rule *next;
|
||||
} *rulefirst, *rulelast;
|
||||
|
||||
RWLock rulelock;
|
||||
|
||||
struct Cond {
|
||||
int field;
|
||||
u32int value;
|
||||
Cond *and, *or;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Stack = 32*1024,
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
void parserules(char*);
|
||||
Rule* rulesmatch(Usbdev*);
|
||||
int startdev(Port*);
|
||||
void work(void);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
OFILES=\
|
||||
usbd.$O\
|
||||
rules.$O\
|
||||
hub.$O\
|
||||
|
||||
HFILES=\
|
||||
|
|
|
@ -1,241 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <ctype.h>
|
||||
#include "usb.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static char *pos;
|
||||
static int lineno;
|
||||
|
||||
static void
|
||||
skipempty(void)
|
||||
{
|
||||
char *s;
|
||||
|
||||
for(;;){
|
||||
s = pos;
|
||||
if(*s == 0)
|
||||
return;
|
||||
while(*s != '\n' && isspace(*s))
|
||||
s++;
|
||||
if(*s == '#')
|
||||
while(*s != 0 && *s != '\n')
|
||||
s++;
|
||||
if(*s != 0 && *s != '\n')
|
||||
return;
|
||||
pos = s;
|
||||
if(*pos != 0){
|
||||
pos++;
|
||||
lineno++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parsesh(int *argc, char ***argv)
|
||||
{
|
||||
char *e;
|
||||
|
||||
*argc = 0;
|
||||
*argv = nil;
|
||||
for(;;){
|
||||
while(isspace(*pos) && *pos != '\n')
|
||||
pos++;
|
||||
if(*pos == '\n' || *pos == 0 || *pos == '#')
|
||||
break;
|
||||
e = pos;
|
||||
while(*e != 0 && *e != '#' && !isspace(*e))
|
||||
e++;
|
||||
(*argc)++;
|
||||
*argv = realloc(*argv, (*argc + 2) * sizeof(char *));
|
||||
if(*argv == nil)
|
||||
sysfatal("realloc: %r");
|
||||
(*argv)[*argc - 1] = mallocz(e - pos + 1, 1);
|
||||
if((*argv)[*argc - 1] == nil)
|
||||
sysfatal("malloc: %r");
|
||||
memmove((*argv)[*argc - 1], pos, e - pos);
|
||||
pos = e;
|
||||
}
|
||||
if(*argv != nil){
|
||||
(*argv)[*argc] = nil;
|
||||
(*argv)[*argc + 1] = nil;
|
||||
}
|
||||
}
|
||||
|
||||
static Usbdev dummy;
|
||||
|
||||
struct field {
|
||||
char *s;
|
||||
void* v;
|
||||
} fields[] = {
|
||||
"class", &dummy.class,
|
||||
"vid", &dummy.vid,
|
||||
"did", &dummy.did,
|
||||
"csp", &dummy.csp,
|
||||
nil, nil,
|
||||
};
|
||||
|
||||
static int
|
||||
parsecond(Rule *r, Cond **last)
|
||||
{
|
||||
Cond *c, *cc, **l;
|
||||
char *e;
|
||||
struct field *f;
|
||||
|
||||
skipempty();
|
||||
if(!isspace(*pos))
|
||||
return 0;
|
||||
l = nil;
|
||||
for(;;){
|
||||
while(isspace(*pos) && *pos != '\n')
|
||||
pos++;
|
||||
if(*pos == '\n' || *pos == '#')
|
||||
return 1;
|
||||
e = pos;
|
||||
while(*e != 0 && *e != '\n' && *e != '=')
|
||||
e++;
|
||||
if(*e != '=')
|
||||
return -1;
|
||||
c = mallocz(sizeof(*c), 1);
|
||||
if(c == nil)
|
||||
sysfatal("malloc: %r");
|
||||
for(f = fields; f->s != nil; f++)
|
||||
if(strlen(f->s) == e - pos && strncmp(pos, f->s, e - pos) == 0){
|
||||
c->field = (int)((char*)f->v - (char*)&dummy);
|
||||
break;
|
||||
}
|
||||
if(f->s == nil)
|
||||
goto Error;
|
||||
pos = e + 1;
|
||||
c->value = strtol(pos, &e, 0);
|
||||
if(pos == e)
|
||||
goto Error;
|
||||
pos = e;
|
||||
if(l != nil)
|
||||
*l = c;
|
||||
else if(*last){
|
||||
for(cc = *last; cc != nil; cc = cc->and)
|
||||
cc->or = c;
|
||||
*last = c;
|
||||
}else
|
||||
*last = r->cond = c;
|
||||
l = &c->and;
|
||||
}
|
||||
Error:
|
||||
free(c);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
parserule(void)
|
||||
{
|
||||
Rule *r;
|
||||
int rc;
|
||||
Cond *c;
|
||||
|
||||
skipempty();
|
||||
if(*pos == 0)
|
||||
return 0;
|
||||
if(isspace(*pos))
|
||||
return -1;
|
||||
r = mallocz(sizeof(*r), 1);
|
||||
if(r == nil)
|
||||
sysfatal("malloc: %r");
|
||||
parsesh(&r->argc, &r->argv);
|
||||
c = nil;
|
||||
do
|
||||
rc = parsecond(r, &c);
|
||||
while(rc > 0);
|
||||
if(rc < 0)
|
||||
return -1;
|
||||
if(rulefirst != nil)
|
||||
rulelast->next = r;
|
||||
else
|
||||
rulefirst = r;
|
||||
rulelast = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
freerules(void)
|
||||
{
|
||||
Rule *r, *rr;
|
||||
Cond *c, *cc;
|
||||
|
||||
wlock(&rulelock);
|
||||
for(r = rulefirst; r != nil; r = rr){
|
||||
for(c = r->cond; c != nil; c = cc){
|
||||
cc = c->and;
|
||||
if(cc == nil)
|
||||
cc = c->or;
|
||||
free(c);
|
||||
}
|
||||
rr = r->next;
|
||||
free(r);
|
||||
}
|
||||
rulefirst = rulelast = nil;
|
||||
wunlock(&rulelock);
|
||||
}
|
||||
|
||||
static void
|
||||
printrules(void)
|
||||
{
|
||||
Rule *r;
|
||||
Cond *c;
|
||||
int i;
|
||||
|
||||
for(r = rulefirst; r != nil; r = r->next){
|
||||
for(i = 0; i < r->argc; i++)
|
||||
print("[%s] ", r->argv[i]);
|
||||
print("\n\t");
|
||||
for(c = r->cond; c != nil; ){
|
||||
print("%d=%ud", c->field, c->value);
|
||||
if(c->and == nil){
|
||||
print("\n\t");
|
||||
c = c->or;
|
||||
}else{
|
||||
print(" ");
|
||||
c = c->and;
|
||||
}
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
parserules(char *s)
|
||||
{
|
||||
int rc;
|
||||
|
||||
freerules();
|
||||
lineno = 1;
|
||||
pos = s;
|
||||
do
|
||||
rc = parserule();
|
||||
while(rc > 0);
|
||||
if(rc < 0)
|
||||
sysfatal("syntax error in line %d", lineno);
|
||||
}
|
||||
|
||||
Rule *
|
||||
rulesmatch(Usbdev *dev)
|
||||
{
|
||||
Rule *r;
|
||||
Cond *c;
|
||||
|
||||
for(r = rulefirst; r != nil; r = r->next){
|
||||
c = r->cond;
|
||||
while(c){
|
||||
if(*(u32int*)((char*)dev + c->field) == c->value){
|
||||
if(c->and == nil)
|
||||
goto yes;
|
||||
c = c->and;
|
||||
}else
|
||||
c = c->or;
|
||||
}
|
||||
}
|
||||
yes:
|
||||
return r;
|
||||
}
|
|
@ -7,87 +7,272 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
char *luser;
|
||||
char *rules;
|
||||
enum {
|
||||
Qroot,
|
||||
Qusbevent,
|
||||
Qmax
|
||||
};
|
||||
|
||||
char *names[] = {
|
||||
"",
|
||||
"usbevent",
|
||||
};
|
||||
|
||||
static File *usbdb;
|
||||
static char Enonexist[] = "does not exist";
|
||||
|
||||
typedef struct Event Event;
|
||||
|
||||
struct Event {
|
||||
char *data;
|
||||
int len;
|
||||
Event *link;
|
||||
int ref;
|
||||
};
|
||||
|
||||
static Event *evfirst, *evlast;
|
||||
static Req *reqfirst, *reqlast;
|
||||
static QLock evlock;
|
||||
|
||||
static void
|
||||
addreader(Req *req)
|
||||
{
|
||||
req->aux = nil;
|
||||
if(reqfirst == nil)
|
||||
reqfirst = req;
|
||||
else
|
||||
reqlast->aux = req;
|
||||
reqlast = req;
|
||||
}
|
||||
|
||||
static void
|
||||
fulfill(Req *req, Event *e)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = e->len;
|
||||
if(n > req->ifcall.count)
|
||||
n = req->ifcall.count;
|
||||
memmove(req->ofcall.data, e->data, n);
|
||||
req->ofcall.count = n;
|
||||
}
|
||||
|
||||
static void
|
||||
initevent(void)
|
||||
{
|
||||
evfirst = mallocz(sizeof(*evfirst), 1);
|
||||
if(evfirst == nil)
|
||||
sysfatal("malloc: %r");
|
||||
evlast = evfirst;
|
||||
}
|
||||
|
||||
static void
|
||||
readevent(Req *req)
|
||||
{
|
||||
Event *e;
|
||||
|
||||
qlock(&evlock);
|
||||
e = req->fid->aux;
|
||||
if(e == evlast){
|
||||
addreader(req);
|
||||
qunlock(&evlock);
|
||||
return;
|
||||
}
|
||||
fulfill(req, e);
|
||||
req->fid->aux = e->link;
|
||||
e->link->ref++;
|
||||
if(--e->ref == 0 && e == evfirst){
|
||||
evfirst = e->link;
|
||||
free(e->data);
|
||||
free(e);
|
||||
}
|
||||
qunlock(&evlock);
|
||||
respond(req, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
pushevent(char *data)
|
||||
{
|
||||
Event *e, *ee;
|
||||
Req *r, *rr;
|
||||
|
||||
qlock(&evlock);
|
||||
e = evlast;
|
||||
ee = emallocz(sizeof(Event), 1);
|
||||
if(ee == nil)
|
||||
sysfatal("malloc: %r");
|
||||
evlast = ee;
|
||||
e->data = data;
|
||||
e->len = strlen(data);
|
||||
e->link = ee;
|
||||
for(r = reqfirst; r != nil; r = rr){
|
||||
rr = r->aux;
|
||||
r->aux = nil;
|
||||
r->fid->aux = ee;
|
||||
ee->ref++;
|
||||
e->ref--;
|
||||
fulfill(r, e);
|
||||
respond(r, nil);
|
||||
}
|
||||
if(e->ref == 0 && e == evfirst){
|
||||
evfirst = ee;
|
||||
free(e->data);
|
||||
free(e);
|
||||
}
|
||||
reqfirst = nil;
|
||||
reqlast = nil;
|
||||
qunlock(&evlock);
|
||||
}
|
||||
|
||||
static int
|
||||
dirgen(int n, Dir *d, void *)
|
||||
{
|
||||
if(n >= Qmax - 1)
|
||||
return -1;
|
||||
d->qid.path = n + 1;
|
||||
d->qid.vers = 0;
|
||||
if(n >= 0)
|
||||
d->qid.type = 0;
|
||||
else
|
||||
d->qid.type = QTDIR;
|
||||
d->uid = strdup(getuser());
|
||||
d->gid = strdup(d->uid);
|
||||
d->muid = strdup(d->uid);
|
||||
d->name = strdup(names[n+1]);
|
||||
d->mode = 0555 | (d->qid.type << 24);
|
||||
d->atime = d->mtime = time(0);
|
||||
d->length = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
usbdattach(Req *req)
|
||||
{
|
||||
req->fid->qid = (Qid) {Qroot, 0, QTDIR};
|
||||
req->ofcall.qid = req->fid->qid;
|
||||
respond(req, nil);
|
||||
}
|
||||
|
||||
static char *
|
||||
usbdwalk(Fid *fid, char *name, Qid *qid)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(strcmp(name, "..") == 0){
|
||||
fid->qid = (Qid) {Qroot, 0, QTDIR};
|
||||
*qid = fid->qid;
|
||||
return nil;
|
||||
}
|
||||
if(fid->qid.path != Qroot)
|
||||
return "not a directory";
|
||||
for(i = 0; i < Qmax; i++)
|
||||
if(strcmp(name, names[i]) == 0){
|
||||
fid->qid = (Qid) {i, 0, 0};
|
||||
*qid = fid->qid;
|
||||
return nil;
|
||||
}
|
||||
return "does not exist";
|
||||
}
|
||||
|
||||
static void
|
||||
usbdread(Req *req)
|
||||
{
|
||||
if(usbdb->qid.path == req->fid->qid.path){
|
||||
readstr(req, rules);
|
||||
switch((long)req->fid->qid.path){
|
||||
case Qroot:
|
||||
dirread9p(req, dirgen, nil);
|
||||
respond(req, nil);
|
||||
return;
|
||||
break;
|
||||
case Qusbevent:
|
||||
readevent(req);
|
||||
break;
|
||||
default:
|
||||
respond(req, Enonexist);
|
||||
break;
|
||||
}
|
||||
respond(req, Enonexist);
|
||||
}
|
||||
|
||||
static void
|
||||
usbdstat(Req *req)
|
||||
{
|
||||
if(dirgen(req->fid->qid.path - 1, &req->d, nil) < 0)
|
||||
respond(req, "the front fell off");
|
||||
else
|
||||
respond(req, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
usbdopen(Req *req)
|
||||
{
|
||||
if(req->fid->qid.path == Qusbevent){
|
||||
qlock(&evlock);
|
||||
req->fid->aux = evlast;
|
||||
evlast->ref++;
|
||||
qunlock(&evlock);
|
||||
}
|
||||
respond(req, nil);
|
||||
}
|
||||
|
||||
static void
|
||||
usbddestroyfid(Fid *fid)
|
||||
{
|
||||
Event *e, *ee;
|
||||
|
||||
if(fid->qid.path == Qusbevent){
|
||||
qlock(&evlock);
|
||||
e = fid->aux;
|
||||
if(--e->ref == 0 && e == evfirst){
|
||||
while(e->ref == 0 && e != evlast){
|
||||
ee = e->link;
|
||||
free(e->data);
|
||||
free(e);
|
||||
e = ee;
|
||||
}
|
||||
evfirst = e;
|
||||
}
|
||||
qunlock(&evlock);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usbdflush(Req *req)
|
||||
{
|
||||
Req **l, *r;
|
||||
qlock(&evlock);
|
||||
l = &reqfirst;
|
||||
while(r = *l){
|
||||
if(r == req->oldreq){
|
||||
*l = r->aux;
|
||||
break;
|
||||
}
|
||||
l = &r->aux;
|
||||
}
|
||||
qunlock(&evlock);
|
||||
respond(req->oldreq, "interrupted");
|
||||
respond(req, nil);
|
||||
}
|
||||
|
||||
Srv usbdsrv = {
|
||||
.attach = usbdattach,
|
||||
.walk1 = usbdwalk,
|
||||
.read = usbdread,
|
||||
.stat = usbdstat,
|
||||
.open = usbdopen,
|
||||
.flush = usbdflush,
|
||||
.destroyfid = usbddestroyfid,
|
||||
};
|
||||
|
||||
static void
|
||||
readrules(void)
|
||||
{
|
||||
int fd, rc, n;
|
||||
char buf[4096];
|
||||
|
||||
fd = open("/lib/usbdb", OREAD);
|
||||
if(fd < 0)
|
||||
sysfatal("open /lib/usbdb: %r");
|
||||
rules = nil;
|
||||
n = 0;
|
||||
for(;;){
|
||||
rc = readn(fd, buf, sizeof buf);
|
||||
if(rc == 0)
|
||||
break;
|
||||
if(rc < 0)
|
||||
sysfatal("read: %r");
|
||||
rules = realloc(rules, 1 + n + rc);
|
||||
if(rules == nil)
|
||||
sysfatal("realloc: %r");
|
||||
memmove(rules + n, buf, rc);
|
||||
n += rc;
|
||||
rules[n] = 0;
|
||||
}
|
||||
if(rules == nil)
|
||||
rules = "";
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
startdev(Port *p)
|
||||
{
|
||||
Rule *r;
|
||||
char buf[14];
|
||||
Dev *d;
|
||||
Usbdev *u;
|
||||
|
||||
if(p->dev == nil || p->dev->usb == nil){
|
||||
if((d = p->dev) == nil || (u = p->dev->usb) == nil){
|
||||
fprint(2, "okay what?\n");
|
||||
return -1;
|
||||
}
|
||||
rlock(&rulelock);
|
||||
r = rulesmatch(p->dev->usb);
|
||||
if(r == nil || r->argv == nil){
|
||||
fprint(2, "no driver for device\n");
|
||||
runlock(&rulelock);
|
||||
return -1;
|
||||
}
|
||||
snprint(buf, sizeof buf, "%d", p->dev->id);
|
||||
r->argv[r->argc] = buf;
|
||||
pushevent(smprint("in id %d vid 0x%.4x did 0x%.4x csp 0x%.8x\n",
|
||||
d->id, u->vid, u->did, u->csp));
|
||||
closedev(p->dev);
|
||||
switch(fork()){
|
||||
case -1:
|
||||
fprint(2, "fork: %r");
|
||||
runlock(&rulelock);
|
||||
return -1;
|
||||
case 0:
|
||||
chdir("/bin");
|
||||
exec(r->argv[0], r->argv);
|
||||
sysfatal("exec: %r");
|
||||
}
|
||||
runlock(&rulelock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -96,13 +281,9 @@ main(int argc, char **argv)
|
|||
{
|
||||
int fd, i, nd;
|
||||
Dir *d;
|
||||
|
||||
readrules();
|
||||
parserules(rules);
|
||||
luser = getuser();
|
||||
|
||||
argc--; argv++;
|
||||
|
||||
initevent();
|
||||
rfork(RFNOTEG);
|
||||
switch(rfork(RFPROC|RFMEM)){
|
||||
case -1: sysfatal("rfork: %r");
|
||||
|
@ -124,7 +305,5 @@ main(int argc, char **argv)
|
|||
for(i = 0; i < argc; i++)
|
||||
rendezvous(work, strdup(argv[i]));
|
||||
rendezvous(work, nil);
|
||||
usbdsrv.tree = alloctree(luser, luser, 0555, nil);
|
||||
usbdb = createfile(usbdsrv.tree->root, "usbdb", luser, 0775, nil);
|
||||
postsharesrv(&usbdsrv, nil, "usb", "usbd", "b");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue