123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <regexp.h>
- #include <thread.h>
- #include <plumb.h>
- #include "plumber.h"
- static char*
- nonnil(char *s)
- {
- if(s == nil)
- return "";
- return s;
- }
- int
- verbis(int obj, Plumbmsg *m, Rule *r)
- {
- switch(obj){
- default:
- fprint(2, "unimplemented 'is' object %d\n", obj);
- break;
- case OData:
- return strcmp(m->data, r->qarg) == 0;
- case ODst:
- return strcmp(m->dst, r->qarg) == 0;
- case OType:
- return strcmp(m->type, r->qarg) == 0;
- case OWdir:
- return strcmp(m->wdir, r->qarg) == 0;
- case OSrc:
- return strcmp(m->src, r->qarg) == 0;
- }
- return 0;
- }
- static void
- setvar(Resub rs[10], char *match[10])
- {
- int i, n;
- for(i=0; i<10; i++){
- free(match[i]);
- match[i] = nil;
- }
- for(i=0; i<10 && rs[i].sp!=nil; i++){
- n = rs[i].ep-rs[i].sp;
- match[i] = emalloc(n+1);
- memmove(match[i], rs[i].sp, n);
- match[i][n] = '\0';
- }
- }
- int
- clickmatch(Reprog *re, char *text, Resub rs[10], int click)
- {
- char *clickp;
- int i, w;
- Rune r;
- /* click is in characters, not bytes */
- for(i=0; i<click && text[i]!='\0'; i+=w)
- w = chartorune(&r, text+i);
- clickp = text+i;
- for(i=0; i<=click; i++){
- memset(rs, 0, 10*sizeof(Resub));
- if(regexec(re, text+i, rs, 10))
- if(rs[0].sp<=clickp && clickp<=rs[0].ep)
- return 1;
- }
- return 0;
- }
- int
- verbmatches(int obj, Plumbmsg *m, Rule *r, Exec *e)
- {
- Resub rs[10];
- char *clickval, *alltext;
- int p0, p1, ntext;
- memset(rs, 0, sizeof rs);
- ntext = -1;
- switch(obj){
- default:
- fprint(2, "unimplemented 'matches' object %d\n", obj);
- break;
- case OData:
- clickval = plumblookup(m->attr, "click");
- if(clickval == nil){
- alltext = m->data;
- ntext = m->ndata;
- goto caseAlltext;
- }
- if(!clickmatch(r->regex, m->data, rs, atoi(clickval)))
- break;
- p0 = rs[0].sp - m->data;
- p1 = rs[0].ep - m->data;
- if(e->p0 >=0 && !(p0==e->p0 && p1==e->p1))
- break;
- e->clearclick = 1;
- e->setdata = 1;
- e->p0 = p0;
- e->p1 = p1;
- setvar(rs, e->match);
- return 1;
- case ODst:
- alltext = m->dst;
- goto caseAlltext;
- case OType:
- alltext = m->type;
- goto caseAlltext;
- case OWdir:
- alltext = m->wdir;
- goto caseAlltext;
- case OSrc:
- alltext = m->src;
- /* fall through */
- caseAlltext:
- /* must match full text */
- if(ntext < 0)
- ntext = strlen(alltext);
- if(!regexec(r->regex, alltext, rs, 10) || rs[0].sp!=alltext || rs[0].ep!=alltext+ntext)
- break;
- setvar(rs, e->match);
- return 1;
- }
- return 0;
- }
- int
- isfile(char *file, ulong maskon, ulong maskoff)
- {
- Dir *d;
- int mode;
- d = dirstat(file);
- if(d == nil)
- return 0;
- mode = d->mode;
- free(d);
- if((mode & maskon) == 0)
- return 0;
- if(mode & maskoff)
- return 0;
- return 1;
- }
- char*
- absolute(char *dir, char *file)
- {
- char *p;
- if(file[0] == '/')
- return estrdup(file);
- p = emalloc(strlen(dir)+1+strlen(file)+1);
- sprint(p, "%s/%s", dir, file);
- return cleanname(p);
- }
- int
- verbisfile(int obj, Plumbmsg *m, Rule *r, Exec *e, ulong maskon, ulong maskoff, char **var)
- {
- char *file;
- switch(obj){
- default:
- fprint(2, "unimplemented 'isfile' object %d\n", obj);
- break;
- case OArg:
- file = absolute(m->wdir, expand(e, r->arg, nil));
- if(isfile(file, maskon, maskoff)){
- *var = file;
- return 1;
- }
- free(file);
- break;
- case OData:
- case OWdir:
- file = absolute(m->wdir, obj==OData? m->data : m->wdir);
- if(isfile(file, maskon, maskoff)){
- *var = file;
- return 1;
- }
- free(file);
- break;
- }
- return 0;
- }
- int
- verbset(int obj, Plumbmsg *m, Rule *r, Exec *e)
- {
- char *new;
- switch(obj){
- default:
- fprint(2, "unimplemented 'is' object %d\n", obj);
- break;
- case OData:
- new = estrdup(expand(e, r->arg, nil));
- m->ndata = strlen(new);
- free(m->data);
- m->data = new;
- e->p0 = -1;
- e->p1 = -1;
- e->setdata = 0;
- return 1;
- case ODst:
- new = estrdup(expand(e, r->arg, nil));
- free(m->dst);
- m->dst = new;
- return 1;
- case OType:
- new = estrdup(expand(e, r->arg, nil));
- free(m->type);
- m->type = new;
- return 1;
- case OWdir:
- new = estrdup(expand(e, r->arg, nil));
- free(m->wdir);
- m->wdir = new;
- return 1;
- case OSrc:
- new = estrdup(expand(e, r->arg, nil));
- free(m->src);
- m->src = new;
- return 1;
- }
- return 0;
- }
- int
- verbadd(int obj, Plumbmsg *m, Rule *r, Exec *e)
- {
- switch(obj){
- default:
- fprint(2, "unimplemented 'add' object %d\n", obj);
- break;
- case OAttr:
- m->attr = plumbaddattr(m->attr, plumbunpackattr(expand(e, r->arg, nil)));
- return 1;
- }
- return 0;
- }
- int
- verbdelete(int obj, Plumbmsg *m, Rule *r, Exec *e)
- {
- char *a;
- switch(obj){
- default:
- fprint(2, "unimplemented 'delete' object %d\n", obj);
- break;
- case OAttr:
- a = expand(e, r->arg, nil);
- if(plumblookup(m->attr, a) == nil)
- break;
- m->attr = plumbdelattr(m->attr, a);
- return 1;
- }
- return 0;
- }
- int
- matchpat(Plumbmsg *m, Exec *e, Rule *r)
- {
- switch(r->verb){
- default:
- fprint(2, "unimplemented verb %d\n", r->verb);
- break;
- case VAdd:
- return verbadd(r->obj, m, r, e);
- case VDelete:
- return verbdelete(r->obj, m, r, e);
- case VIs:
- return verbis(r->obj, m, r);
- case VIsdir:
- return verbisfile(r->obj, m, r, e, DMDIR, 0, &e->dir);
- case VIsfile:
- return verbisfile(r->obj, m, r, e, ~DMDIR, DMDIR, &e->file);
- case VMatches:
- return verbmatches(r->obj, m, r, e);
- case VSet:
- verbset(r->obj, m, r, e);
- return 1;
- }
- return 0;
- }
- void
- freeexec(Exec *exec)
- {
- int i;
- if(exec == nil)
- return;
- free(exec->dir);
- free(exec->file);
- for(i=0; i<10; i++)
- free(exec->match[i]);
- free(exec);
- }
- Exec*
- newexec(Plumbmsg *m)
- {
- Exec *exec;
-
- exec = emalloc(sizeof(Exec));
- exec->msg = m;
- exec->p0 = -1;
- exec->p1 = -1;
- return exec;
- }
- void
- rewrite(Plumbmsg *m, Exec *e)
- {
- Plumbattr *a, *prev;
- if(e->clearclick){
- prev = nil;
- for(a=m->attr; a!=nil; a=a->next){
- if(strcmp(a->name, "click") == 0){
- if(prev == nil)
- m->attr = a->next;
- else
- prev->next = a->next;
- free(a->name);
- free(a->value);
- free(a);
- break;
- }
- prev = a;
- }
- if(e->setdata){
- free(m->data);
- m->data = estrdup(expand(e, "$0", nil));
- m->ndata = strlen(m->data);
- }
- }
- }
- char**
- buildargv(char *s, Exec *e)
- {
- char **av;
- int ac;
- ac = 0;
- av = nil;
- for(;;){
- av = erealloc(av, (ac+1) * sizeof(char*));
- av[ac] = nil;
- while(*s==' ' || *s=='\t')
- s++;
- if(*s == '\0')
- break;
- av[ac++] = estrdup(expand(e, s, &s));
- }
- return av;
- }
- Exec*
- matchruleset(Plumbmsg *m, Ruleset *rs)
- {
- int i;
- Exec *exec;
- if(m->dst!=nil && m->dst[0]!='\0' && rs->port!=nil && strcmp(m->dst, rs->port)!=0)
- return nil;
- exec = newexec(m);
- for(i=0; i<rs->npat; i++)
- if(!matchpat(m, exec, rs->pat[i])){
- freeexec(exec);
- return nil;
- }
- if(rs->port!=nil && (m->dst==nil || m->dst[0]=='\0')){
- free(m->dst);
- m->dst = estrdup(rs->port);
- }
- rewrite(m, exec);
- return exec;
- }
- enum
- {
- NARGS = 100,
- NARGCHAR = 8*1024,
- EXECSTACK = 4096+(NARGS+1)*sizeof(char*)+NARGCHAR
- };
- /* copy argv to stack and free the incoming strings, so we don't leak argument vectors */
- void
- stackargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR])
- {
- int i, n;
- char *s, *a;
- s = args;
- for(i=0; i<NARGS; i++){
- a = inargv[i];
- if(a == nil)
- break;
- n = strlen(a)+1;
- if((s-args)+n >= NARGCHAR) /* too many characters */
- break;
- argv[i] = s;
- memmove(s, a, n);
- s += n;
- free(a);
- }
- argv[i] = nil;
- }
- void
- execproc(void *v)
- {
- char **av;
- char buf[1024], *args[NARGS+1], argc[NARGCHAR];
- rfork(RFFDG);
- close(0);
- open("/dev/null", OREAD);
- av = v;
- stackargv(av, args, argc);
- free(av);
- procexec(nil, args[0], args);
- if(args[0][0]!='/' && strncmp(args[0], "./", 2)!=0 && strncmp(args[0], "../", 3)!=0)
- snprint(buf, sizeof buf, "/bin/%s", args[0]);
- procexec(nil, buf, args);
- threadexits("can't exec");
- }
- char*
- startup(Ruleset *rs, Exec *e)
- {
- char **argv;
- int i;
- if(rs != nil)
- for(i=0; i<rs->nact; i++){
- if(rs->act[i]->verb == VStart)
- goto Found;
- if(rs->act[i]->verb == VClient){
- if(e->msg->dst==nil || e->msg->dst[0]=='\0')
- return "no port for \"client\" rule";
- e->holdforclient = 1;
- goto Found;
- }
- }
- return "no start action for plumb message";
- Found:
- argv = buildargv(rs->act[i]->arg, e);
- if(argv[0] == nil)
- return "empty argument list";
- proccreate(execproc, argv, EXECSTACK);
- return nil;
- }
|