17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <regexp.h>
57dd7cddfSDavid du Colombier #include <thread.h>
67dd7cddfSDavid du Colombier #include <ctype.h>
77dd7cddfSDavid du Colombier #include <plumb.h>
87dd7cddfSDavid du Colombier #include "plumber.h"
97dd7cddfSDavid du Colombier
107dd7cddfSDavid du Colombier typedef struct Input Input;
117dd7cddfSDavid du Colombier typedef struct Var Var;
127dd7cddfSDavid du Colombier
137dd7cddfSDavid du Colombier struct Input
147dd7cddfSDavid du Colombier {
157dd7cddfSDavid du Colombier char *file; /* name of file */
167dd7cddfSDavid du Colombier Biobuf *fd; /* input buffer, if from real file */
177dd7cddfSDavid du Colombier uchar *s; /* input string, if from /mnt/plumb/rules */
187dd7cddfSDavid du Colombier uchar *end; /* end of input string */
197dd7cddfSDavid du Colombier int lineno;
207dd7cddfSDavid du Colombier Input *next; /* file to read after EOF on this one */
217dd7cddfSDavid du Colombier };
227dd7cddfSDavid du Colombier
237dd7cddfSDavid du Colombier struct Var
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier char *name;
267dd7cddfSDavid du Colombier char *value;
277dd7cddfSDavid du Colombier char *qvalue;
287dd7cddfSDavid du Colombier };
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier static int parsing;
317dd7cddfSDavid du Colombier static int nvars;
327dd7cddfSDavid du Colombier static Var *vars;
337dd7cddfSDavid du Colombier static Input *input;
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier static char ebuf[4096];
367dd7cddfSDavid du Colombier
377dd7cddfSDavid du Colombier char *badports[] =
387dd7cddfSDavid du Colombier {
397dd7cddfSDavid du Colombier ".",
407dd7cddfSDavid du Colombier "..",
417dd7cddfSDavid du Colombier "send",
427dd7cddfSDavid du Colombier nil
437dd7cddfSDavid du Colombier };
447dd7cddfSDavid du Colombier
457dd7cddfSDavid du Colombier char *objects[] =
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier "arg",
487dd7cddfSDavid du Colombier "attr",
497dd7cddfSDavid du Colombier "data",
507dd7cddfSDavid du Colombier "dst",
517dd7cddfSDavid du Colombier "plumb",
527dd7cddfSDavid du Colombier "src",
537dd7cddfSDavid du Colombier "type",
5459cc4ca5SDavid du Colombier "wdir",
557dd7cddfSDavid du Colombier nil
567dd7cddfSDavid du Colombier };
577dd7cddfSDavid du Colombier
587dd7cddfSDavid du Colombier char *verbs[] =
597dd7cddfSDavid du Colombier {
607dd7cddfSDavid du Colombier "add",
617dd7cddfSDavid du Colombier "client",
627dd7cddfSDavid du Colombier "delete",
637dd7cddfSDavid du Colombier "is",
647dd7cddfSDavid du Colombier "isdir",
657dd7cddfSDavid du Colombier "isfile",
667dd7cddfSDavid du Colombier "matches",
677dd7cddfSDavid du Colombier "set",
687dd7cddfSDavid du Colombier "start",
697dd7cddfSDavid du Colombier "to",
707dd7cddfSDavid du Colombier nil
717dd7cddfSDavid du Colombier };
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier static void
printinputstackrev(Input * in)747dd7cddfSDavid du Colombier printinputstackrev(Input *in)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier if(in == nil)
777dd7cddfSDavid du Colombier return;
787dd7cddfSDavid du Colombier printinputstackrev(in->next);
799a747e4fSDavid du Colombier fprint(2, "%s:%d: ", in->file, in->lineno);
807dd7cddfSDavid du Colombier }
817dd7cddfSDavid du Colombier
827dd7cddfSDavid du Colombier void
printinputstack(void)837dd7cddfSDavid du Colombier printinputstack(void)
847dd7cddfSDavid du Colombier {
857dd7cddfSDavid du Colombier printinputstackrev(input);
867dd7cddfSDavid du Colombier }
877dd7cddfSDavid du Colombier
887dd7cddfSDavid du Colombier static void
pushinput(char * name,int fd,uchar * str)897dd7cddfSDavid du Colombier pushinput(char *name, int fd, uchar *str)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier Input *in;
927dd7cddfSDavid du Colombier int depth;
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier depth = 0;
957dd7cddfSDavid du Colombier for(in=input; in; in=in->next)
967dd7cddfSDavid du Colombier if(depth++ >= 10) /* prevent deep C stack in plumber and bad include structure */
977dd7cddfSDavid du Colombier parseerror("include stack too deep; max 10");
987dd7cddfSDavid du Colombier
997dd7cddfSDavid du Colombier in = emalloc(sizeof(Input));
1007dd7cddfSDavid du Colombier in->file = estrdup(name);
1017dd7cddfSDavid du Colombier in->next = input;
1027dd7cddfSDavid du Colombier input = in;
1037dd7cddfSDavid du Colombier if(str)
1047dd7cddfSDavid du Colombier in->s = str;
1057dd7cddfSDavid du Colombier else{
1067dd7cddfSDavid du Colombier in->fd = emalloc(sizeof(Biobuf));
1077dd7cddfSDavid du Colombier if(Binit(in->fd, fd, OREAD) < 0)
1087dd7cddfSDavid du Colombier parseerror("can't initialize Bio for rules file: %r");
1097dd7cddfSDavid du Colombier }
1107dd7cddfSDavid du Colombier
1117dd7cddfSDavid du Colombier }
1127dd7cddfSDavid du Colombier
1137dd7cddfSDavid du Colombier int
popinput(void)1147dd7cddfSDavid du Colombier popinput(void)
1157dd7cddfSDavid du Colombier {
1167dd7cddfSDavid du Colombier Input *in;
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier in = input;
1197dd7cddfSDavid du Colombier if(in == nil)
1207dd7cddfSDavid du Colombier return 0;
1217dd7cddfSDavid du Colombier input = in->next;
1227dd7cddfSDavid du Colombier if(in->fd){
1237dd7cddfSDavid du Colombier Bterm(in->fd);
1247dd7cddfSDavid du Colombier free(in->fd);
1257dd7cddfSDavid du Colombier }
126*9b7bf7dfSDavid du Colombier free(in->file);
1277dd7cddfSDavid du Colombier free(in);
1287dd7cddfSDavid du Colombier return 1;
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier
1317dd7cddfSDavid du Colombier int
getc(void)1327dd7cddfSDavid du Colombier getc(void)
1337dd7cddfSDavid du Colombier {
1347dd7cddfSDavid du Colombier if(input == nil)
1357dd7cddfSDavid du Colombier return Beof;
1367dd7cddfSDavid du Colombier if(input->fd)
1377dd7cddfSDavid du Colombier return Bgetc(input->fd);
1387dd7cddfSDavid du Colombier if(input->s < input->end)
1397dd7cddfSDavid du Colombier return *(input->s)++;
1407dd7cddfSDavid du Colombier return -1;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier
1437dd7cddfSDavid du Colombier char*
getline(void)1447dd7cddfSDavid du Colombier getline(void)
1457dd7cddfSDavid du Colombier {
1467dd7cddfSDavid du Colombier static int n = 0;
1477dd7cddfSDavid du Colombier static char *s, *incl;
1487dd7cddfSDavid du Colombier int c, i;
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier i = 0;
1517dd7cddfSDavid du Colombier for(;;){
1527dd7cddfSDavid du Colombier c = getc();
1537dd7cddfSDavid du Colombier if(c < 0)
1547dd7cddfSDavid du Colombier return nil;
1557dd7cddfSDavid du Colombier if(i == n){
1567dd7cddfSDavid du Colombier n += 100;
1577dd7cddfSDavid du Colombier s = erealloc(s, n);
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier if(c<0 || c=='\0' || c=='\n')
1607dd7cddfSDavid du Colombier break;
1617dd7cddfSDavid du Colombier s[i++] = c;
1627dd7cddfSDavid du Colombier }
1637dd7cddfSDavid du Colombier s[i] = '\0';
1647dd7cddfSDavid du Colombier return s;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier
1677dd7cddfSDavid du Colombier int
lookup(char * s,char * tab[])1687dd7cddfSDavid du Colombier lookup(char *s, char *tab[])
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier int i;
1717dd7cddfSDavid du Colombier
1727dd7cddfSDavid du Colombier for(i=0; tab[i]!=nil; i++)
1737dd7cddfSDavid du Colombier if(strcmp(s, tab[i])==0)
1747dd7cddfSDavid du Colombier return i;
1757dd7cddfSDavid du Colombier return -1;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier
1787dd7cddfSDavid du Colombier Var*
lookupvariable(char * s,int n)1797dd7cddfSDavid du Colombier lookupvariable(char *s, int n)
1807dd7cddfSDavid du Colombier {
1817dd7cddfSDavid du Colombier int i;
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier for(i=0; i<nvars; i++)
1847dd7cddfSDavid du Colombier if(n==strlen(vars[i].name) && memcmp(s, vars[i].name, n)==0)
1857dd7cddfSDavid du Colombier return vars+i;
1867dd7cddfSDavid du Colombier return nil;
1877dd7cddfSDavid du Colombier }
1887dd7cddfSDavid du Colombier
1897dd7cddfSDavid du Colombier char*
variable(char * s,int n)1907dd7cddfSDavid du Colombier variable(char *s, int n)
1917dd7cddfSDavid du Colombier {
1927dd7cddfSDavid du Colombier Var *var;
1937dd7cddfSDavid du Colombier
1947dd7cddfSDavid du Colombier var = lookupvariable(s, n);
1957dd7cddfSDavid du Colombier if(var)
1967dd7cddfSDavid du Colombier return var->qvalue;
1977dd7cddfSDavid du Colombier return nil;
1987dd7cddfSDavid du Colombier }
1997dd7cddfSDavid du Colombier
2007dd7cddfSDavid du Colombier void
setvariable(char * s,int n,char * val,char * qval)2017dd7cddfSDavid du Colombier setvariable(char *s, int n, char *val, char *qval)
2027dd7cddfSDavid du Colombier {
2037dd7cddfSDavid du Colombier Var *var;
2047dd7cddfSDavid du Colombier
2057dd7cddfSDavid du Colombier var = lookupvariable(s, n);
2067dd7cddfSDavid du Colombier if(var){
2077dd7cddfSDavid du Colombier free(var->value);
2087dd7cddfSDavid du Colombier free(var->qvalue);
2097dd7cddfSDavid du Colombier }else{
2107dd7cddfSDavid du Colombier vars = erealloc(vars, (nvars+1)*sizeof(Var));
2117dd7cddfSDavid du Colombier var = vars+nvars++;
2127dd7cddfSDavid du Colombier var->name = emalloc(n+1);
2137dd7cddfSDavid du Colombier memmove(var->name, s, n);
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier var->value = estrdup(val);
2167dd7cddfSDavid du Colombier var->qvalue = estrdup(qval);
2177dd7cddfSDavid du Colombier }
2187dd7cddfSDavid du Colombier
2197dd7cddfSDavid du Colombier static char*
nonnil(char * s)2207dd7cddfSDavid du Colombier nonnil(char *s)
2217dd7cddfSDavid du Colombier {
2227dd7cddfSDavid du Colombier if(s == nil)
2237dd7cddfSDavid du Colombier return "";
2247dd7cddfSDavid du Colombier return s;
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier
2277dd7cddfSDavid du Colombier static char*
filename(Exec * e,char * name)2287dd7cddfSDavid du Colombier filename(Exec *e, char *name)
2297dd7cddfSDavid du Colombier {
2307dd7cddfSDavid du Colombier static char *buf; /* rock to hold value so we don't leak the strings */
2317dd7cddfSDavid du Colombier
2327dd7cddfSDavid du Colombier free(buf);
2337dd7cddfSDavid du Colombier /* if name is defined, used it */
2347dd7cddfSDavid du Colombier if(name!=nil && name[0]!='\0'){
2357dd7cddfSDavid du Colombier buf = estrdup(name);
2367dd7cddfSDavid du Colombier return cleanname(buf);
2377dd7cddfSDavid du Colombier }
2387dd7cddfSDavid du Colombier /* if data is an absolute file name, or wdir is empty, use it */
2397dd7cddfSDavid du Colombier if(e->msg->data[0]=='/' || e->msg->wdir==nil || e->msg->wdir[0]=='\0'){
2407dd7cddfSDavid du Colombier buf = estrdup(e->msg->data);
2417dd7cddfSDavid du Colombier return cleanname(buf);
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier buf = emalloc(strlen(e->msg->wdir)+1+strlen(e->msg->data)+1);
2447dd7cddfSDavid du Colombier sprint(buf, "%s/%s", e->msg->wdir, e->msg->data);
2457dd7cddfSDavid du Colombier return cleanname(buf);
2467dd7cddfSDavid du Colombier }
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier char*
dollar(Exec * e,char * s,int * namelen)2497dd7cddfSDavid du Colombier dollar(Exec *e, char *s, int *namelen)
2507dd7cddfSDavid du Colombier {
2517dd7cddfSDavid du Colombier int n;
2527dd7cddfSDavid du Colombier static char *abuf;
2537dd7cddfSDavid du Colombier char *t;
2547dd7cddfSDavid du Colombier
2557dd7cddfSDavid du Colombier *namelen = 1;
2567dd7cddfSDavid du Colombier if(e!=nil && '0'<=s[0] && s[0]<='9')
2577dd7cddfSDavid du Colombier return nonnil(e->match[s[0]-'0']);
2587dd7cddfSDavid du Colombier
2597dd7cddfSDavid du Colombier for(t=s; isalnum(*t); t++)
2607dd7cddfSDavid du Colombier ;
2617dd7cddfSDavid du Colombier n = t-s;
2627dd7cddfSDavid du Colombier *namelen = n;
2637dd7cddfSDavid du Colombier
2647dd7cddfSDavid du Colombier if(e != nil){
2657dd7cddfSDavid du Colombier if(n == 3){
2667dd7cddfSDavid du Colombier if(memcmp(s, "src", 3) == 0)
2677dd7cddfSDavid du Colombier return nonnil(e->msg->src);
2687dd7cddfSDavid du Colombier if(memcmp(s, "dst", 3) == 0)
2697dd7cddfSDavid du Colombier return nonnil(e->msg->dst);
2707dd7cddfSDavid du Colombier if(memcmp(s, "dir", 3) == 0)
2717dd7cddfSDavid du Colombier return filename(e, e->dir);
2727dd7cddfSDavid du Colombier }
2737dd7cddfSDavid du Colombier if(n == 4){
2747dd7cddfSDavid du Colombier if(memcmp(s, "attr", 4) == 0){
2757dd7cddfSDavid du Colombier free(abuf);
2767dd7cddfSDavid du Colombier abuf = plumbpackattr(e->msg->attr);
2777dd7cddfSDavid du Colombier return nonnil(abuf);
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier if(memcmp(s, "data", 4) == 0)
2807dd7cddfSDavid du Colombier return nonnil(e->msg->data);
2817dd7cddfSDavid du Colombier if(memcmp(s, "file", 4) == 0)
2827dd7cddfSDavid du Colombier return filename(e, e->file);
2837dd7cddfSDavid du Colombier if(memcmp(s, "type", 4) == 0)
2847dd7cddfSDavid du Colombier return nonnil(e->msg->type);
2857dd7cddfSDavid du Colombier if(memcmp(s, "wdir", 3) == 0)
2867dd7cddfSDavid du Colombier return nonnil(e->msg->wdir);
2877dd7cddfSDavid du Colombier }
2887dd7cddfSDavid du Colombier }
2897dd7cddfSDavid du Colombier
2907dd7cddfSDavid du Colombier return variable(s, n);
2917dd7cddfSDavid du Colombier }
2927dd7cddfSDavid du Colombier
2937dd7cddfSDavid du Colombier /* expand one blank-terminated string, processing quotes and $ signs */
2947dd7cddfSDavid du Colombier char*
expand(Exec * e,char * s,char ** ends)2957dd7cddfSDavid du Colombier expand(Exec *e, char *s, char **ends)
2967dd7cddfSDavid du Colombier {
2977dd7cddfSDavid du Colombier char *p, *ep, *val;
2987dd7cddfSDavid du Colombier int namelen, quoting;
2997dd7cddfSDavid du Colombier
3007dd7cddfSDavid du Colombier p = ebuf;
3017dd7cddfSDavid du Colombier ep = ebuf+sizeof ebuf-1;
3027dd7cddfSDavid du Colombier quoting = 0;
3037dd7cddfSDavid du Colombier while(p<ep && *s!='\0' && (quoting || (*s!=' ' && *s!='\t'))){
3047dd7cddfSDavid du Colombier if(*s == '\''){
3057dd7cddfSDavid du Colombier s++;
3067dd7cddfSDavid du Colombier if(!quoting)
3077dd7cddfSDavid du Colombier quoting = 1;
3087dd7cddfSDavid du Colombier else if(*s == '\''){
3097dd7cddfSDavid du Colombier *p++ = '\'';
3107dd7cddfSDavid du Colombier s++;
3117dd7cddfSDavid du Colombier }else
3127dd7cddfSDavid du Colombier quoting = 0;
3137dd7cddfSDavid du Colombier continue;
3147dd7cddfSDavid du Colombier }
3157dd7cddfSDavid du Colombier if(quoting || *s!='$'){
3167dd7cddfSDavid du Colombier *p++ = *s++;
3177dd7cddfSDavid du Colombier continue;
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier s++;
3207dd7cddfSDavid du Colombier val = dollar(e, s, &namelen);
3217dd7cddfSDavid du Colombier if(val == nil){
3227dd7cddfSDavid du Colombier *p++ = '$';
3237dd7cddfSDavid du Colombier continue;
3247dd7cddfSDavid du Colombier }
3257dd7cddfSDavid du Colombier if(ep-p < strlen(val))
3267dd7cddfSDavid du Colombier return "string-too-long";
3277dd7cddfSDavid du Colombier strcpy(p, val);
3287dd7cddfSDavid du Colombier p += strlen(val);
3297dd7cddfSDavid du Colombier s += namelen;
3307dd7cddfSDavid du Colombier }
3317dd7cddfSDavid du Colombier if(ends)
3327dd7cddfSDavid du Colombier *ends = s;
3337dd7cddfSDavid du Colombier *p = '\0';
3347dd7cddfSDavid du Colombier return ebuf;
3357dd7cddfSDavid du Colombier }
3367dd7cddfSDavid du Colombier
3377dd7cddfSDavid du Colombier void
regerror(char * msg)3387dd7cddfSDavid du Colombier regerror(char *msg)
3397dd7cddfSDavid du Colombier {
3407dd7cddfSDavid du Colombier if(parsing){
3417dd7cddfSDavid du Colombier parsing = 0;
3427dd7cddfSDavid du Colombier parseerror("%s", msg);
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier error("%s", msg);
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier void
parserule(Rule * r)3487dd7cddfSDavid du Colombier parserule(Rule *r)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier r->qarg = estrdup(expand(nil, r->arg, nil));
3517dd7cddfSDavid du Colombier switch(r->obj){
3527dd7cddfSDavid du Colombier case OArg:
3537dd7cddfSDavid du Colombier case OAttr:
3547dd7cddfSDavid du Colombier case OData:
3557dd7cddfSDavid du Colombier case ODst:
3567dd7cddfSDavid du Colombier case OType:
35759cc4ca5SDavid du Colombier case OWdir:
3587dd7cddfSDavid du Colombier case OSrc:
3597dd7cddfSDavid du Colombier if(r->verb==VClient || r->verb==VStart || r->verb==VTo)
3607dd7cddfSDavid du Colombier parseerror("%s not valid verb for object %s", verbs[r->verb], objects[r->obj]);
3617dd7cddfSDavid du Colombier if(r->obj!=OAttr && (r->verb==VAdd || r->verb==VDelete))
3627dd7cddfSDavid du Colombier parseerror("%s not valid verb for object %s", verbs[r->verb], objects[r->obj]);
3637dd7cddfSDavid du Colombier if(r->verb == VMatches){
3647dd7cddfSDavid du Colombier r->regex = regcomp(r->qarg);
3657dd7cddfSDavid du Colombier return;
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier break;
3687dd7cddfSDavid du Colombier case OPlumb:
3697dd7cddfSDavid du Colombier if(r->verb!=VClient && r->verb!=VStart && r->verb!=VTo)
3707dd7cddfSDavid du Colombier parseerror("%s not valid verb for object %s", verbs[r->verb], objects[r->obj]);
3717dd7cddfSDavid du Colombier break;
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier }
3747dd7cddfSDavid du Colombier
3757dd7cddfSDavid du Colombier int
assignment(char * p)3767dd7cddfSDavid du Colombier assignment(char *p)
3777dd7cddfSDavid du Colombier {
3787dd7cddfSDavid du Colombier char *var, *qval;
3797dd7cddfSDavid du Colombier int n;
3807dd7cddfSDavid du Colombier
3817dd7cddfSDavid du Colombier if(!isalpha(p[0]))
3827dd7cddfSDavid du Colombier return 0;
3837dd7cddfSDavid du Colombier for(var=p; isalnum(*p); p++)
3847dd7cddfSDavid du Colombier ;
3857dd7cddfSDavid du Colombier n = p-var;
3867dd7cddfSDavid du Colombier while(*p==' ' || *p=='\t')
3877dd7cddfSDavid du Colombier p++;
3887dd7cddfSDavid du Colombier if(*p++ != '=')
3897dd7cddfSDavid du Colombier return 0;
3907dd7cddfSDavid du Colombier while(*p==' ' || *p=='\t')
3917dd7cddfSDavid du Colombier p++;
3927dd7cddfSDavid du Colombier qval = expand(nil, p, nil);
3937dd7cddfSDavid du Colombier setvariable(var, n, p, qval);
3947dd7cddfSDavid du Colombier return 1;
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier
3977dd7cddfSDavid du Colombier int
include(char * s)3987dd7cddfSDavid du Colombier include(char *s)
3997dd7cddfSDavid du Colombier {
4007dd7cddfSDavid du Colombier char *t, *args[3], buf[128];
4017dd7cddfSDavid du Colombier int n, fd;
4027dd7cddfSDavid du Colombier
4037dd7cddfSDavid du Colombier if(strncmp(s, "include", 7) != 0)
4047dd7cddfSDavid du Colombier return 0;
4057dd7cddfSDavid du Colombier /* either an include or an error */
4067dd7cddfSDavid du Colombier n = tokenize(s, args, nelem(args));
4077dd7cddfSDavid du Colombier if(n < 2)
4087dd7cddfSDavid du Colombier goto Err;
4097dd7cddfSDavid du Colombier if(strcmp(args[0], "include") != 0)
4107dd7cddfSDavid du Colombier goto Err;
4117dd7cddfSDavid du Colombier if(args[1][0] == '#')
4127dd7cddfSDavid du Colombier goto Err;
4137dd7cddfSDavid du Colombier if(n>2 && args[2][0] != '#')
4147dd7cddfSDavid du Colombier goto Err;
4157dd7cddfSDavid du Colombier t = args[1];
4167dd7cddfSDavid du Colombier fd = open(t, OREAD);
4177dd7cddfSDavid du Colombier if(fd<0 && t[0]!='/' && strncmp(t, "./", 2)!=0 && strncmp(t, "../", 3)!=0){
4187dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "/sys/lib/plumb/%s", t);
4197dd7cddfSDavid du Colombier t = buf;
4207dd7cddfSDavid du Colombier fd = open(t, OREAD);
4217dd7cddfSDavid du Colombier }
4227dd7cddfSDavid du Colombier if(fd < 0)
4237dd7cddfSDavid du Colombier parseerror("can't open %s for inclusion", t);
4247dd7cddfSDavid du Colombier pushinput(t, fd, nil);
4257dd7cddfSDavid du Colombier return 1;
4267dd7cddfSDavid du Colombier
4277dd7cddfSDavid du Colombier Err:
4287dd7cddfSDavid du Colombier parseerror("malformed include statement");
4297dd7cddfSDavid du Colombier return 0;
4307dd7cddfSDavid du Colombier }
4317dd7cddfSDavid du Colombier
4327dd7cddfSDavid du Colombier Rule*
readrule(int * eof)4337dd7cddfSDavid du Colombier readrule(int *eof)
4347dd7cddfSDavid du Colombier {
4357dd7cddfSDavid du Colombier Rule *rp;
4367dd7cddfSDavid du Colombier char *line, *p;
4377dd7cddfSDavid du Colombier char *word;
4387dd7cddfSDavid du Colombier
4397dd7cddfSDavid du Colombier Top:
4407dd7cddfSDavid du Colombier line = getline();
4417dd7cddfSDavid du Colombier if(line == nil){
4427dd7cddfSDavid du Colombier /*
4437dd7cddfSDavid du Colombier * if input is from string, and bytes remain (input->end is within string),
4447dd7cddfSDavid du Colombier * morerules() will pop input and save remaining data. otherwise pop
4457dd7cddfSDavid du Colombier * the stack here, and if there's more input, keep reading.
4467dd7cddfSDavid du Colombier */
4477dd7cddfSDavid du Colombier if((input!=nil && input->end==nil) && popinput())
4487dd7cddfSDavid du Colombier goto Top;
4497dd7cddfSDavid du Colombier *eof = 1;
4507dd7cddfSDavid du Colombier return nil;
4517dd7cddfSDavid du Colombier }
4527dd7cddfSDavid du Colombier input->lineno++;
4537dd7cddfSDavid du Colombier
4547dd7cddfSDavid du Colombier for(p=line; *p==' ' || *p=='\t'; p++)
4557dd7cddfSDavid du Colombier ;
4567dd7cddfSDavid du Colombier if(*p=='\0' || *p=='#') /* empty or comment line */
4577dd7cddfSDavid du Colombier return nil;
4587dd7cddfSDavid du Colombier
4597dd7cddfSDavid du Colombier if(include(p))
4607dd7cddfSDavid du Colombier goto Top;
4617dd7cddfSDavid du Colombier
4627dd7cddfSDavid du Colombier if(assignment(p))
4637dd7cddfSDavid du Colombier return nil;
4647dd7cddfSDavid du Colombier
4657dd7cddfSDavid du Colombier rp = emalloc(sizeof(Rule));
4667dd7cddfSDavid du Colombier
4677dd7cddfSDavid du Colombier /* object */
4687dd7cddfSDavid du Colombier for(word=p; *p!=' ' && *p!='\t'; p++)
4697dd7cddfSDavid du Colombier if(*p == '\0')
4707dd7cddfSDavid du Colombier parseerror("malformed rule");
4717dd7cddfSDavid du Colombier *p++ = '\0';
4727dd7cddfSDavid du Colombier rp->obj = lookup(word, objects);
4737dd7cddfSDavid du Colombier if(rp->obj < 0){
4747dd7cddfSDavid du Colombier if(strcmp(word, "kind") == 0) /* backwards compatibility */
4757dd7cddfSDavid du Colombier rp->obj = OType;
4767dd7cddfSDavid du Colombier else
4777dd7cddfSDavid du Colombier parseerror("unknown object %s", word);
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier
4807dd7cddfSDavid du Colombier /* verb */
4817dd7cddfSDavid du Colombier while(*p==' ' || *p=='\t')
4827dd7cddfSDavid du Colombier p++;
4837dd7cddfSDavid du Colombier for(word=p; *p!=' ' && *p!='\t'; p++)
4847dd7cddfSDavid du Colombier if(*p == '\0')
4857dd7cddfSDavid du Colombier parseerror("malformed rule");
4867dd7cddfSDavid du Colombier *p++ = '\0';
4877dd7cddfSDavid du Colombier rp->verb = lookup(word, verbs);
4887dd7cddfSDavid du Colombier if(rp->verb < 0)
4897dd7cddfSDavid du Colombier parseerror("unknown verb %s", word);
4907dd7cddfSDavid du Colombier
4917dd7cddfSDavid du Colombier /* argument */
4927dd7cddfSDavid du Colombier while(*p==' ' || *p=='\t')
4937dd7cddfSDavid du Colombier p++;
4947dd7cddfSDavid du Colombier if(*p == '\0')
4957dd7cddfSDavid du Colombier parseerror("malformed rule");
4967dd7cddfSDavid du Colombier rp->arg = estrdup(p);
4977dd7cddfSDavid du Colombier
4987dd7cddfSDavid du Colombier parserule(rp);
4997dd7cddfSDavid du Colombier
5007dd7cddfSDavid du Colombier return rp;
5017dd7cddfSDavid du Colombier }
5027dd7cddfSDavid du Colombier
5037dd7cddfSDavid du Colombier void
freerule(Rule * r)5047dd7cddfSDavid du Colombier freerule(Rule *r)
5057dd7cddfSDavid du Colombier {
5067dd7cddfSDavid du Colombier free(r->arg);
5077dd7cddfSDavid du Colombier free(r->qarg);
5087dd7cddfSDavid du Colombier free(r->regex);
5097dd7cddfSDavid du Colombier }
5107dd7cddfSDavid du Colombier
5117dd7cddfSDavid du Colombier void
freerules(Rule ** r)5127dd7cddfSDavid du Colombier freerules(Rule **r)
5137dd7cddfSDavid du Colombier {
5147dd7cddfSDavid du Colombier while(*r)
5157dd7cddfSDavid du Colombier freerule(*r++);
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier
5187dd7cddfSDavid du Colombier void
freeruleset(Ruleset * rs)5197dd7cddfSDavid du Colombier freeruleset(Ruleset *rs)
5207dd7cddfSDavid du Colombier {
5217dd7cddfSDavid du Colombier freerules(rs->pat);
5227dd7cddfSDavid du Colombier free(rs->pat);
5237dd7cddfSDavid du Colombier freerules(rs->act);
5247dd7cddfSDavid du Colombier free(rs->act);
5257dd7cddfSDavid du Colombier free(rs->port);
5267dd7cddfSDavid du Colombier free(rs);
5277dd7cddfSDavid du Colombier }
5287dd7cddfSDavid du Colombier
5297dd7cddfSDavid du Colombier Ruleset*
readruleset(void)5307dd7cddfSDavid du Colombier readruleset(void)
5317dd7cddfSDavid du Colombier {
5327dd7cddfSDavid du Colombier Ruleset *rs;
5337dd7cddfSDavid du Colombier Rule *r;
5347dd7cddfSDavid du Colombier int eof, inrule, i, ncmd;
5357dd7cddfSDavid du Colombier
5367dd7cddfSDavid du Colombier Again:
5377dd7cddfSDavid du Colombier eof = 0;
5387dd7cddfSDavid du Colombier rs = emalloc(sizeof(Ruleset));
5397dd7cddfSDavid du Colombier rs->pat = emalloc(sizeof(Rule*));
5407dd7cddfSDavid du Colombier rs->act = emalloc(sizeof(Rule*));
5417dd7cddfSDavid du Colombier inrule = 0;
5427dd7cddfSDavid du Colombier ncmd = 0;
5437dd7cddfSDavid du Colombier for(;;){
5447dd7cddfSDavid du Colombier r = readrule(&eof);
5457dd7cddfSDavid du Colombier if(eof)
5467dd7cddfSDavid du Colombier break;
5477dd7cddfSDavid du Colombier if(r==nil){
5487dd7cddfSDavid du Colombier if(inrule)
5497dd7cddfSDavid du Colombier break;
5507dd7cddfSDavid du Colombier continue;
5517dd7cddfSDavid du Colombier }
5527dd7cddfSDavid du Colombier inrule = 1;
5537dd7cddfSDavid du Colombier switch(r->obj){
5547dd7cddfSDavid du Colombier case OArg:
5557dd7cddfSDavid du Colombier case OAttr:
5567dd7cddfSDavid du Colombier case OData:
5577dd7cddfSDavid du Colombier case ODst:
5587dd7cddfSDavid du Colombier case OType:
55959cc4ca5SDavid du Colombier case OWdir:
5607dd7cddfSDavid du Colombier case OSrc:
5617dd7cddfSDavid du Colombier rs->npat++;
5627dd7cddfSDavid du Colombier rs->pat = erealloc(rs->pat, (rs->npat+1)*sizeof(Rule*));
5637dd7cddfSDavid du Colombier rs->pat[rs->npat-1] = r;
5647dd7cddfSDavid du Colombier rs->pat[rs->npat] = nil;
5657dd7cddfSDavid du Colombier break;
5667dd7cddfSDavid du Colombier case OPlumb:
5677dd7cddfSDavid du Colombier rs->nact++;
5687dd7cddfSDavid du Colombier rs->act = erealloc(rs->act, (rs->nact+1)*sizeof(Rule*));
5697dd7cddfSDavid du Colombier rs->act[rs->nact-1] = r;
5707dd7cddfSDavid du Colombier rs->act[rs->nact] = nil;
5717dd7cddfSDavid du Colombier if(r->verb == VTo){
5727dd7cddfSDavid du Colombier if(rs->npat>0 && rs->port != nil) /* npat==0 implies port declaration */
5737dd7cddfSDavid du Colombier parseerror("too many ports");
5747dd7cddfSDavid du Colombier if(lookup(r->qarg, badports) >= 0)
5757dd7cddfSDavid du Colombier parseerror("illegal port name %s", r->qarg);
576*9b7bf7dfSDavid du Colombier if(rs->port)
577*9b7bf7dfSDavid du Colombier free(rs->port);
5787dd7cddfSDavid du Colombier rs->port = estrdup(r->qarg);
5797dd7cddfSDavid du Colombier }else
5807dd7cddfSDavid du Colombier ncmd++; /* start or client rule */
5817dd7cddfSDavid du Colombier break;
5827dd7cddfSDavid du Colombier }
5837dd7cddfSDavid du Colombier }
5847dd7cddfSDavid du Colombier if(ncmd > 1){
5857dd7cddfSDavid du Colombier freeruleset(rs);
5867dd7cddfSDavid du Colombier parseerror("ruleset has more than one client or start action");
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier if(rs->npat>0 && rs->nact>0)
5897dd7cddfSDavid du Colombier return rs;
5907dd7cddfSDavid du Colombier if(rs->npat==0 && rs->nact==0){
5917dd7cddfSDavid du Colombier freeruleset(rs);
5927dd7cddfSDavid du Colombier return nil;
5937dd7cddfSDavid du Colombier }
5947dd7cddfSDavid du Colombier if(rs->nact==0 || rs->port==nil){
5957dd7cddfSDavid du Colombier freeruleset(rs);
5967dd7cddfSDavid du Colombier parseerror("ruleset must have patterns and actions");
5977dd7cddfSDavid du Colombier return nil;
5987dd7cddfSDavid du Colombier }
5997dd7cddfSDavid du Colombier
6007dd7cddfSDavid du Colombier /* declare ports */
6017dd7cddfSDavid du Colombier for(i=0; i<rs->nact; i++)
6027dd7cddfSDavid du Colombier if(rs->act[i]->verb != VTo){
6037dd7cddfSDavid du Colombier freeruleset(rs);
6047dd7cddfSDavid du Colombier parseerror("ruleset must have actions");
6057dd7cddfSDavid du Colombier return nil;
6067dd7cddfSDavid du Colombier }
6077dd7cddfSDavid du Colombier for(i=0; i<rs->nact; i++)
6087dd7cddfSDavid du Colombier addport(rs->act[i]->qarg);
6097dd7cddfSDavid du Colombier freeruleset(rs);
6107dd7cddfSDavid du Colombier goto Again;
6117dd7cddfSDavid du Colombier }
6127dd7cddfSDavid du Colombier
6137dd7cddfSDavid du Colombier Ruleset**
readrules(char * name,int fd)6147dd7cddfSDavid du Colombier readrules(char *name, int fd)
6157dd7cddfSDavid du Colombier {
6167dd7cddfSDavid du Colombier Ruleset *rs, **rules;
6177dd7cddfSDavid du Colombier int n;
6187dd7cddfSDavid du Colombier
6197dd7cddfSDavid du Colombier parsing = 1;
6207dd7cddfSDavid du Colombier pushinput(name, fd, nil);
6217dd7cddfSDavid du Colombier rules = emalloc(sizeof(Ruleset*));
6227dd7cddfSDavid du Colombier for(n=0; (rs=readruleset())!=nil; n++){
6237dd7cddfSDavid du Colombier rules = erealloc(rules, (n+2)*sizeof(Ruleset*));
6247dd7cddfSDavid du Colombier rules[n] = rs;
6257dd7cddfSDavid du Colombier rules[n+1] = nil;
6267dd7cddfSDavid du Colombier }
6277dd7cddfSDavid du Colombier popinput();
6287dd7cddfSDavid du Colombier parsing = 0;
6297dd7cddfSDavid du Colombier return rules;
6307dd7cddfSDavid du Colombier }
6317dd7cddfSDavid du Colombier
6327dd7cddfSDavid du Colombier char*
concat(char * s,char * t)6337dd7cddfSDavid du Colombier concat(char *s, char *t)
6347dd7cddfSDavid du Colombier {
6357dd7cddfSDavid du Colombier if(t == nil)
6367dd7cddfSDavid du Colombier return s;
6377dd7cddfSDavid du Colombier if(s == nil)
6387dd7cddfSDavid du Colombier s = estrdup(t);
6397dd7cddfSDavid du Colombier else{
6407dd7cddfSDavid du Colombier s = erealloc(s, strlen(s)+strlen(t)+1);
6417dd7cddfSDavid du Colombier strcat(s, t);
6427dd7cddfSDavid du Colombier }
6437dd7cddfSDavid du Colombier return s;
6447dd7cddfSDavid du Colombier }
6457dd7cddfSDavid du Colombier
6467dd7cddfSDavid du Colombier char*
printpat(Rule * r)6477dd7cddfSDavid du Colombier printpat(Rule *r)
6487dd7cddfSDavid du Colombier {
6497dd7cddfSDavid du Colombier char *s;
6507dd7cddfSDavid du Colombier
6517dd7cddfSDavid du Colombier s = emalloc(strlen(objects[r->obj])+1+strlen(verbs[r->verb])+1+strlen(r->arg)+1+1);
6527dd7cddfSDavid du Colombier sprint(s, "%s\t%s\t%s\n", objects[r->obj], verbs[r->verb], r->arg);
6537dd7cddfSDavid du Colombier return s;
6547dd7cddfSDavid du Colombier }
6557dd7cddfSDavid du Colombier
6567dd7cddfSDavid du Colombier char*
printvar(Var * v)6577dd7cddfSDavid du Colombier printvar(Var *v)
6587dd7cddfSDavid du Colombier {
6597dd7cddfSDavid du Colombier char *s;
6607dd7cddfSDavid du Colombier
6617dd7cddfSDavid du Colombier s = emalloc(strlen(v->name)+1+strlen(v->value)+2+1);
6627dd7cddfSDavid du Colombier sprint(s, "%s=%s\n\n", v->name, v->value);
6637dd7cddfSDavid du Colombier return s;
6647dd7cddfSDavid du Colombier }
6657dd7cddfSDavid du Colombier
6667dd7cddfSDavid du Colombier char*
printrule(Ruleset * r)6677dd7cddfSDavid du Colombier printrule(Ruleset *r)
6687dd7cddfSDavid du Colombier {
6697dd7cddfSDavid du Colombier int i;
6707dd7cddfSDavid du Colombier char *s;
6717dd7cddfSDavid du Colombier
6727dd7cddfSDavid du Colombier s = nil;
6737dd7cddfSDavid du Colombier for(i=0; i<r->npat; i++)
6747dd7cddfSDavid du Colombier s = concat(s, printpat(r->pat[i]));
6757dd7cddfSDavid du Colombier for(i=0; i<r->nact; i++)
6767dd7cddfSDavid du Colombier s = concat(s, printpat(r->act[i]));
6777dd7cddfSDavid du Colombier s = concat(s, "\n");
6787dd7cddfSDavid du Colombier return s;
6797dd7cddfSDavid du Colombier }
6807dd7cddfSDavid du Colombier
6817dd7cddfSDavid du Colombier char*
printport(char * port)6827dd7cddfSDavid du Colombier printport(char *port)
6837dd7cddfSDavid du Colombier {
6847dd7cddfSDavid du Colombier char *s;
6857dd7cddfSDavid du Colombier
6867dd7cddfSDavid du Colombier s = nil;
6877dd7cddfSDavid du Colombier s = concat(s, "plumb to ");
6887dd7cddfSDavid du Colombier s = concat(s, port);
6897dd7cddfSDavid du Colombier s = concat(s, "\n");
6907dd7cddfSDavid du Colombier return s;
6917dd7cddfSDavid du Colombier }
6927dd7cddfSDavid du Colombier
6937dd7cddfSDavid du Colombier char*
printrules(void)6947dd7cddfSDavid du Colombier printrules(void)
6957dd7cddfSDavid du Colombier {
6967dd7cddfSDavid du Colombier int i;
6977dd7cddfSDavid du Colombier char *s;
6987dd7cddfSDavid du Colombier
6997dd7cddfSDavid du Colombier s = nil;
7007dd7cddfSDavid du Colombier for(i=0; i<nvars; i++)
7017dd7cddfSDavid du Colombier s = concat(s, printvar(&vars[i]));
7027dd7cddfSDavid du Colombier for(i=0; i<nports; i++)
7037dd7cddfSDavid du Colombier s = concat(s, printport(ports[i]));
7047dd7cddfSDavid du Colombier s = concat(s, "\n");
7057dd7cddfSDavid du Colombier for(i=0; rules[i]; i++)
7067dd7cddfSDavid du Colombier s = concat(s, printrule(rules[i]));
7077dd7cddfSDavid du Colombier return s;
7087dd7cddfSDavid du Colombier }
7097dd7cddfSDavid du Colombier
7107dd7cddfSDavid du Colombier char*
stringof(char * s,int n)7117dd7cddfSDavid du Colombier stringof(char *s, int n)
7127dd7cddfSDavid du Colombier {
7137dd7cddfSDavid du Colombier char *t;
7147dd7cddfSDavid du Colombier
7157dd7cddfSDavid du Colombier t = emalloc(n+1);
7167dd7cddfSDavid du Colombier memmove(t, s, n);
7177dd7cddfSDavid du Colombier return t;
7187dd7cddfSDavid du Colombier }
7197dd7cddfSDavid du Colombier
7207dd7cddfSDavid du Colombier uchar*
morerules(uchar * text,int done)7217dd7cddfSDavid du Colombier morerules(uchar *text, int done)
7227dd7cddfSDavid du Colombier {
7237dd7cddfSDavid du Colombier int n;
7247dd7cddfSDavid du Colombier Ruleset *rs;
7257dd7cddfSDavid du Colombier uchar *otext, *s, *endofrule;
7267dd7cddfSDavid du Colombier
7277dd7cddfSDavid du Colombier pushinput("<rules input>", -1, text);
7287dd7cddfSDavid du Colombier if(done)
7297dd7cddfSDavid du Colombier input->end = text+strlen((char*)text);
7307dd7cddfSDavid du Colombier else{
7317dd7cddfSDavid du Colombier /*
7327dd7cddfSDavid du Colombier * Help user by sending any full rules to parser so any parse errors will
7337dd7cddfSDavid du Colombier * occur on write rather than close. A heuristic will do: blank line ends rule.
7347dd7cddfSDavid du Colombier */
7357dd7cddfSDavid du Colombier endofrule = nil;
7367dd7cddfSDavid du Colombier for(s=text; *s!='\0'; s++)
7377dd7cddfSDavid du Colombier if(*s=='\n' && *++s=='\n')
7387dd7cddfSDavid du Colombier endofrule = s+1;
7397dd7cddfSDavid du Colombier if(endofrule == nil)
7407dd7cddfSDavid du Colombier return text;
7417dd7cddfSDavid du Colombier input->end = endofrule;
7427dd7cddfSDavid du Colombier }
7437dd7cddfSDavid du Colombier for(n=0; rules[n]; n++)
7447dd7cddfSDavid du Colombier ;
7457dd7cddfSDavid du Colombier while((rs=readruleset()) != nil){
7467dd7cddfSDavid du Colombier rules = erealloc(rules, (n+2)*sizeof(Ruleset*));
7477dd7cddfSDavid du Colombier rules[n++] = rs;
7487dd7cddfSDavid du Colombier rules[n] = nil;
7497dd7cddfSDavid du Colombier }
7507dd7cddfSDavid du Colombier otext =text;
7517dd7cddfSDavid du Colombier if(input == nil)
7527dd7cddfSDavid du Colombier text = (uchar*)estrdup("");
7537dd7cddfSDavid du Colombier else
7547dd7cddfSDavid du Colombier text = (uchar*)estrdup((char*)input->end);
7557dd7cddfSDavid du Colombier popinput();
7567dd7cddfSDavid du Colombier free(otext);
7577dd7cddfSDavid du Colombier return text;
7587dd7cddfSDavid du Colombier }
7597dd7cddfSDavid du Colombier
7607dd7cddfSDavid du Colombier char*
writerules(char * s,int n)7617dd7cddfSDavid du Colombier writerules(char *s, int n)
7627dd7cddfSDavid du Colombier {
7637dd7cddfSDavid du Colombier static uchar *text;
7647dd7cddfSDavid du Colombier char *tmp;
7657dd7cddfSDavid du Colombier
7667dd7cddfSDavid du Colombier free(lasterror);
7677dd7cddfSDavid du Colombier lasterror = nil;
7687dd7cddfSDavid du Colombier parsing = 1;
7697dd7cddfSDavid du Colombier if(setjmp(parsejmp) == 0){
7707dd7cddfSDavid du Colombier tmp = stringof(s, n);
7717dd7cddfSDavid du Colombier text = (uchar*)concat((char*)text, tmp);
7727dd7cddfSDavid du Colombier free(tmp);
7737dd7cddfSDavid du Colombier text = morerules(text, s==nil);
7747dd7cddfSDavid du Colombier }
7757dd7cddfSDavid du Colombier if(s == nil){
7767dd7cddfSDavid du Colombier free(text);
7777dd7cddfSDavid du Colombier text = nil;
7787dd7cddfSDavid du Colombier }
7797dd7cddfSDavid du Colombier parsing = 0;
7807dd7cddfSDavid du Colombier makeports(rules);
7817dd7cddfSDavid du Colombier return lasterror;
7827dd7cddfSDavid du Colombier }
783