usbd: added event file, removed usbdb

This commit is contained in:
aiju 2011-07-28 17:31:45 +02:00
parent 27fd88af23
commit 4792c6bef9
5 changed files with 245 additions and 327 deletions

View file

@ -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,

View file

@ -1,4 +1,2 @@
void parserules(char*);
Rule* rulesmatch(Usbdev*);
int startdev(Port*);
void work(void);

View file

@ -2,7 +2,6 @@
OFILES=\
usbd.$O\
rules.$O\
hub.$O\
HFILES=\

View file

@ -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;
}

View file

@ -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");
}