242 lines
3.6 KiB
C
242 lines
3.6 KiB
C
#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;
|
|
}
|