xref: /plan9/sys/src/cmd/plumb/match.c (revision 853458f38e7eb3a48cfa3a36aefdb799375e398a)
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 <plumb.h>
77dd7cddfSDavid du Colombier #include "plumber.h"
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier static char*
nonnil(char * s)107dd7cddfSDavid du Colombier nonnil(char *s)
117dd7cddfSDavid du Colombier {
127dd7cddfSDavid du Colombier 	if(s == nil)
137dd7cddfSDavid du Colombier 		return "";
147dd7cddfSDavid du Colombier 	return s;
157dd7cddfSDavid du Colombier }
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier int
verbis(int obj,Plumbmsg * m,Rule * r)187dd7cddfSDavid du Colombier verbis(int obj, Plumbmsg *m, Rule *r)
197dd7cddfSDavid du Colombier {
207dd7cddfSDavid du Colombier 	switch(obj){
217dd7cddfSDavid du Colombier 	default:
227dd7cddfSDavid du Colombier 		fprint(2, "unimplemented 'is' object %d\n", obj);
237dd7cddfSDavid du Colombier 		break;
247dd7cddfSDavid du Colombier 	case OData:
257dd7cddfSDavid du Colombier 		return strcmp(m->data, r->qarg) == 0;
267dd7cddfSDavid du Colombier 	case ODst:
277dd7cddfSDavid du Colombier 		return strcmp(m->dst, r->qarg) == 0;
287dd7cddfSDavid du Colombier 	case OType:
297dd7cddfSDavid du Colombier 		return strcmp(m->type, r->qarg) == 0;
3059cc4ca5SDavid du Colombier 	case OWdir:
3159cc4ca5SDavid du Colombier 		return strcmp(m->wdir, r->qarg) == 0;
327dd7cddfSDavid du Colombier 	case OSrc:
337dd7cddfSDavid du Colombier 		return strcmp(m->src, r->qarg) == 0;
347dd7cddfSDavid du Colombier 	}
357dd7cddfSDavid du Colombier 	return 0;
367dd7cddfSDavid du Colombier }
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier static void
setvar(Resub rs[10],char * match[10])397dd7cddfSDavid du Colombier setvar(Resub rs[10], char *match[10])
407dd7cddfSDavid du Colombier {
417dd7cddfSDavid du Colombier 	int i, n;
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier 	for(i=0; i<10; i++){
447dd7cddfSDavid du Colombier 		free(match[i]);
457dd7cddfSDavid du Colombier 		match[i] = nil;
467dd7cddfSDavid du Colombier 	}
477dd7cddfSDavid du Colombier 	for(i=0; i<10 && rs[i].sp!=nil; i++){
487dd7cddfSDavid du Colombier 		n = rs[i].ep-rs[i].sp;
497dd7cddfSDavid du Colombier 		match[i] = emalloc(n+1);
507dd7cddfSDavid du Colombier 		memmove(match[i], rs[i].sp, n);
517dd7cddfSDavid du Colombier 		match[i][n] = '\0';
527dd7cddfSDavid du Colombier 	}
537dd7cddfSDavid du Colombier }
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier int
clickmatch(Reprog * re,char * text,Resub rs[10],int click)567dd7cddfSDavid du Colombier clickmatch(Reprog *re, char *text, Resub rs[10], int click)
577dd7cddfSDavid du Colombier {
587dd7cddfSDavid du Colombier 	char *clickp;
597dd7cddfSDavid du Colombier 	int i, w;
607dd7cddfSDavid du Colombier 	Rune r;
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier 	/* click is in characters, not bytes */
637dd7cddfSDavid du Colombier 	for(i=0; i<click && text[i]!='\0'; i+=w)
647dd7cddfSDavid du Colombier 		w = chartorune(&r, text+i);
657dd7cddfSDavid du Colombier 	clickp = text+i;
667dd7cddfSDavid du Colombier 	for(i=0; i<=click; i++){
677dd7cddfSDavid du Colombier 		memset(rs, 0, 10*sizeof(Resub));
687dd7cddfSDavid du Colombier 		if(regexec(re, text+i, rs, 10))
697dd7cddfSDavid du Colombier 			if(rs[0].sp<=clickp && clickp<=rs[0].ep)
707dd7cddfSDavid du Colombier 				return 1;
717dd7cddfSDavid du Colombier 	}
727dd7cddfSDavid du Colombier 	return 0;
737dd7cddfSDavid du Colombier }
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier int
verbmatches(int obj,Plumbmsg * m,Rule * r,Exec * e)767dd7cddfSDavid du Colombier verbmatches(int obj, Plumbmsg *m, Rule *r, Exec *e)
777dd7cddfSDavid du Colombier {
787dd7cddfSDavid du Colombier 	Resub rs[10];
797dd7cddfSDavid du Colombier 	char *clickval, *alltext;
8059cc4ca5SDavid du Colombier 	int p0, p1, ntext;
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier 	memset(rs, 0, sizeof rs);
8359cc4ca5SDavid du Colombier 	ntext = -1;
847dd7cddfSDavid du Colombier 	switch(obj){
857dd7cddfSDavid du Colombier 	default:
867dd7cddfSDavid du Colombier 		fprint(2, "unimplemented 'matches' object %d\n", obj);
877dd7cddfSDavid du Colombier 		break;
887dd7cddfSDavid du Colombier 	case OData:
897dd7cddfSDavid du Colombier 		clickval = plumblookup(m->attr, "click");
907dd7cddfSDavid du Colombier 		if(clickval == nil){
917dd7cddfSDavid du Colombier 			alltext = m->data;
9259cc4ca5SDavid du Colombier 			ntext = m->ndata;
937dd7cddfSDavid du Colombier 			goto caseAlltext;
947dd7cddfSDavid du Colombier 		}
957dd7cddfSDavid du Colombier 		if(!clickmatch(r->regex, m->data, rs, atoi(clickval)))
967dd7cddfSDavid du Colombier 			break;
977dd7cddfSDavid du Colombier 		p0 = rs[0].sp - m->data;
987dd7cddfSDavid du Colombier 		p1 = rs[0].ep - m->data;
997dd7cddfSDavid du Colombier 		if(e->p0 >=0 && !(p0==e->p0 && p1==e->p1))
1007dd7cddfSDavid du Colombier 			break;
1017dd7cddfSDavid du Colombier 		e->clearclick = 1;
1027dd7cddfSDavid du Colombier 		e->setdata = 1;
1037dd7cddfSDavid du Colombier 		e->p0 = p0;
1047dd7cddfSDavid du Colombier 		e->p1 = p1;
1057dd7cddfSDavid du Colombier 		setvar(rs, e->match);
1067dd7cddfSDavid du Colombier 		return 1;
1077dd7cddfSDavid du Colombier 	case ODst:
10859cc4ca5SDavid du Colombier 		alltext = m->dst;
10959cc4ca5SDavid du Colombier 		goto caseAlltext;
1107dd7cddfSDavid du Colombier 	case OType:
1117dd7cddfSDavid du Colombier 		alltext = m->type;
11259cc4ca5SDavid du Colombier 		goto caseAlltext;
11359cc4ca5SDavid du Colombier 	case OWdir:
11459cc4ca5SDavid du Colombier 		alltext = m->wdir;
11559cc4ca5SDavid du Colombier 		goto caseAlltext;
11659cc4ca5SDavid du Colombier 	case OSrc:
11759cc4ca5SDavid du Colombier 		alltext = m->src;
1187dd7cddfSDavid du Colombier 		/* fall through */
1197dd7cddfSDavid du Colombier 	caseAlltext:
1207dd7cddfSDavid du Colombier 		/* must match full text */
12159cc4ca5SDavid du Colombier 		if(ntext < 0)
12259cc4ca5SDavid du Colombier 			ntext = strlen(alltext);
12359cc4ca5SDavid du Colombier 		if(!regexec(r->regex, alltext, rs, 10) || rs[0].sp!=alltext || rs[0].ep!=alltext+ntext)
1247dd7cddfSDavid du Colombier 			break;
1257dd7cddfSDavid du Colombier 		setvar(rs, e->match);
1267dd7cddfSDavid du Colombier 		return 1;
1277dd7cddfSDavid du Colombier 	}
1287dd7cddfSDavid du Colombier 	return 0;
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier int
isfile(char * file,ulong maskon,ulong maskoff)1327dd7cddfSDavid du Colombier isfile(char *file, ulong maskon, ulong maskoff)
1337dd7cddfSDavid du Colombier {
1349a747e4fSDavid du Colombier 	Dir *d;
1359a747e4fSDavid du Colombier 	int mode;
1367dd7cddfSDavid du Colombier 
1379a747e4fSDavid du Colombier 	d = dirstat(file);
1389a747e4fSDavid du Colombier 	if(d == nil)
1397dd7cddfSDavid du Colombier 		return 0;
1409a747e4fSDavid du Colombier 	mode = d->mode;
1419a747e4fSDavid du Colombier 	free(d);
1429a747e4fSDavid du Colombier 	if((mode & maskon) == 0)
1437dd7cddfSDavid du Colombier 		return 0;
1449a747e4fSDavid du Colombier 	if(mode & maskoff)
1457dd7cddfSDavid du Colombier 		return 0;
1467dd7cddfSDavid du Colombier 	return 1;
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier char*
absolute(char * dir,char * file)1507dd7cddfSDavid du Colombier absolute(char *dir, char *file)
1517dd7cddfSDavid du Colombier {
1527dd7cddfSDavid du Colombier 	char *p;
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier 	if(file[0] == '/')
1557dd7cddfSDavid du Colombier 		return estrdup(file);
1567dd7cddfSDavid du Colombier 	p = emalloc(strlen(dir)+1+strlen(file)+1);
1577dd7cddfSDavid du Colombier 	sprint(p, "%s/%s", dir, file);
1587dd7cddfSDavid du Colombier 	return cleanname(p);
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier int
verbisfile(int obj,Plumbmsg * m,Rule * r,Exec * e,ulong maskon,ulong maskoff,char ** var)1627dd7cddfSDavid du Colombier verbisfile(int obj, Plumbmsg *m, Rule *r, Exec *e, ulong maskon, ulong maskoff, char **var)
1637dd7cddfSDavid du Colombier {
1647dd7cddfSDavid du Colombier 	char *file;
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier 	switch(obj){
1677dd7cddfSDavid du Colombier 	default:
1687dd7cddfSDavid du Colombier 		fprint(2, "unimplemented 'isfile' object %d\n", obj);
1697dd7cddfSDavid du Colombier 		break;
1707dd7cddfSDavid du Colombier 	case OArg:
1717dd7cddfSDavid du Colombier 		file = absolute(m->wdir, expand(e, r->arg, nil));
1727dd7cddfSDavid du Colombier 		if(isfile(file, maskon, maskoff)){
1737dd7cddfSDavid du Colombier 			*var = file;
1747dd7cddfSDavid du Colombier 			return 1;
1757dd7cddfSDavid du Colombier 		}
1767dd7cddfSDavid du Colombier 		free(file);
1777dd7cddfSDavid du Colombier 		break;
1787dd7cddfSDavid du Colombier 	case OData:
17959cc4ca5SDavid du Colombier 	case OWdir:
18059cc4ca5SDavid du Colombier 		file = absolute(m->wdir, obj==OData? m->data : m->wdir);
1817dd7cddfSDavid du Colombier 		if(isfile(file, maskon, maskoff)){
1827dd7cddfSDavid du Colombier 			*var = file;
1837dd7cddfSDavid du Colombier 			return 1;
1847dd7cddfSDavid du Colombier 		}
1857dd7cddfSDavid du Colombier 		free(file);
1867dd7cddfSDavid du Colombier 		break;
1877dd7cddfSDavid du Colombier 	}
1887dd7cddfSDavid du Colombier 	return 0;
1897dd7cddfSDavid du Colombier }
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier int
verbset(int obj,Plumbmsg * m,Rule * r,Exec * e)1927dd7cddfSDavid du Colombier verbset(int obj, Plumbmsg *m, Rule *r, Exec *e)
1937dd7cddfSDavid du Colombier {
1947dd7cddfSDavid du Colombier 	char *new;
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier 	switch(obj){
1977dd7cddfSDavid du Colombier 	default:
1987dd7cddfSDavid du Colombier 		fprint(2, "unimplemented 'is' object %d\n", obj);
1997dd7cddfSDavid du Colombier 		break;
2007dd7cddfSDavid du Colombier 	case OData:
2017dd7cddfSDavid du Colombier 		new = estrdup(expand(e, r->arg, nil));
2027dd7cddfSDavid du Colombier 		m->ndata = strlen(new);
2037dd7cddfSDavid du Colombier 		free(m->data);
2047dd7cddfSDavid du Colombier 		m->data = new;
2057dd7cddfSDavid du Colombier 		e->p0 = -1;
2067dd7cddfSDavid du Colombier 		e->p1 = -1;
2077dd7cddfSDavid du Colombier 		e->setdata = 0;
2087dd7cddfSDavid du Colombier 		return 1;
2097dd7cddfSDavid du Colombier 	case ODst:
2107dd7cddfSDavid du Colombier 		new = estrdup(expand(e, r->arg, nil));
2117dd7cddfSDavid du Colombier 		free(m->dst);
2127dd7cddfSDavid du Colombier 		m->dst = new;
2137dd7cddfSDavid du Colombier 		return 1;
2147dd7cddfSDavid du Colombier 	case OType:
2157dd7cddfSDavid du Colombier 		new = estrdup(expand(e, r->arg, nil));
2167dd7cddfSDavid du Colombier 		free(m->type);
2177dd7cddfSDavid du Colombier 		m->type = new;
2187dd7cddfSDavid du Colombier 		return 1;
21959cc4ca5SDavid du Colombier 	case OWdir:
22059cc4ca5SDavid du Colombier 		new = estrdup(expand(e, r->arg, nil));
22159cc4ca5SDavid du Colombier 		free(m->wdir);
22259cc4ca5SDavid du Colombier 		m->wdir = new;
22359cc4ca5SDavid du Colombier 		return 1;
2247dd7cddfSDavid du Colombier 	case OSrc:
2257dd7cddfSDavid du Colombier 		new = estrdup(expand(e, r->arg, nil));
2267dd7cddfSDavid du Colombier 		free(m->src);
2277dd7cddfSDavid du Colombier 		m->src = new;
2287dd7cddfSDavid du Colombier 		return 1;
2297dd7cddfSDavid du Colombier 	}
2307dd7cddfSDavid du Colombier 	return 0;
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier int
verbadd(int obj,Plumbmsg * m,Rule * r,Exec * e)2347dd7cddfSDavid du Colombier verbadd(int obj, Plumbmsg *m, Rule *r, Exec *e)
2357dd7cddfSDavid du Colombier {
2367dd7cddfSDavid du Colombier 	switch(obj){
2377dd7cddfSDavid du Colombier 	default:
2387dd7cddfSDavid du Colombier 		fprint(2, "unimplemented 'add' object %d\n", obj);
2397dd7cddfSDavid du Colombier 		break;
2407dd7cddfSDavid du Colombier 	case OAttr:
2417dd7cddfSDavid du Colombier 		m->attr = plumbaddattr(m->attr, plumbunpackattr(expand(e, r->arg, nil)));
2427dd7cddfSDavid du Colombier 		return 1;
2437dd7cddfSDavid du Colombier 	}
2447dd7cddfSDavid du Colombier 	return 0;
2457dd7cddfSDavid du Colombier }
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier int
verbdelete(int obj,Plumbmsg * m,Rule * r,Exec * e)2487dd7cddfSDavid du Colombier verbdelete(int obj, Plumbmsg *m, Rule *r, Exec *e)
2497dd7cddfSDavid du Colombier {
2507dd7cddfSDavid du Colombier 	char *a;
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier 	switch(obj){
2537dd7cddfSDavid du Colombier 	default:
2547dd7cddfSDavid du Colombier 		fprint(2, "unimplemented 'delete' object %d\n", obj);
2557dd7cddfSDavid du Colombier 		break;
2567dd7cddfSDavid du Colombier 	case OAttr:
2577dd7cddfSDavid du Colombier 		a = expand(e, r->arg, nil);
2587dd7cddfSDavid du Colombier 		if(plumblookup(m->attr, a) == nil)
2597dd7cddfSDavid du Colombier 			break;
2607dd7cddfSDavid du Colombier 		m->attr = plumbdelattr(m->attr, a);
2617dd7cddfSDavid du Colombier 		return 1;
2627dd7cddfSDavid du Colombier 	}
2637dd7cddfSDavid du Colombier 	return 0;
2647dd7cddfSDavid du Colombier }
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier int
matchpat(Plumbmsg * m,Exec * e,Rule * r)2677dd7cddfSDavid du Colombier matchpat(Plumbmsg *m, Exec *e, Rule *r)
2687dd7cddfSDavid du Colombier {
2697dd7cddfSDavid du Colombier 	switch(r->verb){
2707dd7cddfSDavid du Colombier 	default:
2717dd7cddfSDavid du Colombier 		fprint(2, "unimplemented verb %d\n", r->verb);
2727dd7cddfSDavid du Colombier 		break;
2737dd7cddfSDavid du Colombier 	case VAdd:
2747dd7cddfSDavid du Colombier 		return verbadd(r->obj, m, r, e);
2757dd7cddfSDavid du Colombier 	case VDelete:
2767dd7cddfSDavid du Colombier 		return verbdelete(r->obj, m, r, e);
2777dd7cddfSDavid du Colombier 	case VIs:
2787dd7cddfSDavid du Colombier 		return verbis(r->obj, m, r);
2797dd7cddfSDavid du Colombier 	case VIsdir:
2809a747e4fSDavid du Colombier 		return verbisfile(r->obj, m, r, e, DMDIR, 0, &e->dir);
2817dd7cddfSDavid du Colombier 	case VIsfile:
2829a747e4fSDavid du Colombier 		return verbisfile(r->obj, m, r, e, ~DMDIR, DMDIR, &e->file);
2837dd7cddfSDavid du Colombier 	case VMatches:
2847dd7cddfSDavid du Colombier 		return verbmatches(r->obj, m, r, e);
2857dd7cddfSDavid du Colombier 	case VSet:
2867dd7cddfSDavid du Colombier 		verbset(r->obj, m, r, e);
2877dd7cddfSDavid du Colombier 		return 1;
2887dd7cddfSDavid du Colombier 	}
2897dd7cddfSDavid du Colombier 	return 0;
2907dd7cddfSDavid du Colombier }
2917dd7cddfSDavid du Colombier 
2927dd7cddfSDavid du Colombier void
freeexec(Exec * exec)2937dd7cddfSDavid du Colombier freeexec(Exec *exec)
2947dd7cddfSDavid du Colombier {
2957dd7cddfSDavid du Colombier 	int i;
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier 	if(exec == nil)
2987dd7cddfSDavid du Colombier 		return;
2997dd7cddfSDavid du Colombier 	free(exec->dir);
3007dd7cddfSDavid du Colombier 	free(exec->file);
3017dd7cddfSDavid du Colombier 	for(i=0; i<10; i++)
3027dd7cddfSDavid du Colombier 		free(exec->match[i]);
3037dd7cddfSDavid du Colombier 	free(exec);
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier Exec*
newexec(Plumbmsg * m)3077dd7cddfSDavid du Colombier newexec(Plumbmsg *m)
3087dd7cddfSDavid du Colombier {
3097dd7cddfSDavid du Colombier 	Exec *exec;
3107dd7cddfSDavid du Colombier 
3117dd7cddfSDavid du Colombier 	exec = emalloc(sizeof(Exec));
3127dd7cddfSDavid du Colombier 	exec->msg = m;
3137dd7cddfSDavid du Colombier 	exec->p0 = -1;
3147dd7cddfSDavid du Colombier 	exec->p1 = -1;
3157dd7cddfSDavid du Colombier 	return exec;
3167dd7cddfSDavid du Colombier }
3177dd7cddfSDavid du Colombier 
3187dd7cddfSDavid du Colombier void
rewrite(Plumbmsg * m,Exec * e)3197dd7cddfSDavid du Colombier rewrite(Plumbmsg *m, Exec *e)
3207dd7cddfSDavid du Colombier {
3217dd7cddfSDavid du Colombier 	Plumbattr *a, *prev;
3227dd7cddfSDavid du Colombier 
3237dd7cddfSDavid du Colombier 	if(e->clearclick){
3247dd7cddfSDavid du Colombier 		prev = nil;
3257dd7cddfSDavid du Colombier 		for(a=m->attr; a!=nil; a=a->next){
3267dd7cddfSDavid du Colombier 			if(strcmp(a->name, "click") == 0){
3277dd7cddfSDavid du Colombier 				if(prev == nil)
3287dd7cddfSDavid du Colombier 					m->attr = a->next;
3297dd7cddfSDavid du Colombier 				else
3307dd7cddfSDavid du Colombier 					prev->next = a->next;
3317dd7cddfSDavid du Colombier 				free(a->name);
3327dd7cddfSDavid du Colombier 				free(a->value);
3337dd7cddfSDavid du Colombier 				free(a);
3347dd7cddfSDavid du Colombier 				break;
3357dd7cddfSDavid du Colombier 			}
3367dd7cddfSDavid du Colombier 			prev = a;
3377dd7cddfSDavid du Colombier 		}
3387dd7cddfSDavid du Colombier 		if(e->setdata){
3397dd7cddfSDavid du Colombier 			free(m->data);
3407dd7cddfSDavid du Colombier 			m->data = estrdup(expand(e, "$0", nil));
3417dd7cddfSDavid du Colombier 			m->ndata = strlen(m->data);
3427dd7cddfSDavid du Colombier 		}
3437dd7cddfSDavid du Colombier 	}
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier char**
buildargv(char * s,Exec * e)3477dd7cddfSDavid du Colombier buildargv(char *s, Exec *e)
3487dd7cddfSDavid du Colombier {
3497dd7cddfSDavid du Colombier 	char **av;
3507dd7cddfSDavid du Colombier 	int ac;
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 	ac = 0;
3537dd7cddfSDavid du Colombier 	av = nil;
3547dd7cddfSDavid du Colombier 	for(;;){
3557dd7cddfSDavid du Colombier 		av = erealloc(av, (ac+1) * sizeof(char*));
3567dd7cddfSDavid du Colombier 		av[ac] = nil;
3577dd7cddfSDavid du Colombier 		while(*s==' ' || *s=='\t')
3587dd7cddfSDavid du Colombier 			s++;
3597dd7cddfSDavid du Colombier 		if(*s == '\0')
3607dd7cddfSDavid du Colombier 			break;
3617dd7cddfSDavid du Colombier 		av[ac++] = estrdup(expand(e, s, &s));
3627dd7cddfSDavid du Colombier 	}
3637dd7cddfSDavid du Colombier 	return av;
3647dd7cddfSDavid du Colombier }
3657dd7cddfSDavid du Colombier 
3667dd7cddfSDavid du Colombier Exec*
matchruleset(Plumbmsg * m,Ruleset * rs)3677dd7cddfSDavid du Colombier matchruleset(Plumbmsg *m, Ruleset *rs)
3687dd7cddfSDavid du Colombier {
3697dd7cddfSDavid du Colombier 	int i;
3707dd7cddfSDavid du Colombier 	Exec *exec;
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier 	if(m->dst!=nil && m->dst[0]!='\0' && rs->port!=nil && strcmp(m->dst, rs->port)!=0)
3737dd7cddfSDavid du Colombier 		return nil;
3747dd7cddfSDavid du Colombier 	exec = newexec(m);
3757dd7cddfSDavid du Colombier 	for(i=0; i<rs->npat; i++)
3767dd7cddfSDavid du Colombier 		if(!matchpat(m, exec, rs->pat[i])){
3777dd7cddfSDavid du Colombier 			freeexec(exec);
3787dd7cddfSDavid du Colombier 			return nil;
3797dd7cddfSDavid du Colombier 		}
3807dd7cddfSDavid du Colombier 	if(rs->port!=nil && (m->dst==nil || m->dst[0]=='\0')){
3817dd7cddfSDavid du Colombier 		free(m->dst);
3827dd7cddfSDavid du Colombier 		m->dst = estrdup(rs->port);
3837dd7cddfSDavid du Colombier 	}
3847dd7cddfSDavid du Colombier 	rewrite(m, exec);
3857dd7cddfSDavid du Colombier 	return exec;
3867dd7cddfSDavid du Colombier }
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier enum
3897dd7cddfSDavid du Colombier {
3907dd7cddfSDavid du Colombier 	NARGS		= 100,
3917dd7cddfSDavid du Colombier 	NARGCHAR	= 8*1024,
392*853458f3SDavid du Colombier 	EXECSTACK 	= 8192+(NARGS+1)*sizeof(char*)+NARGCHAR
3937dd7cddfSDavid du Colombier };
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier /* copy argv to stack and free the incoming strings, so we don't leak argument vectors */
3967dd7cddfSDavid du Colombier void
stackargv(char ** inargv,char * argv[NARGS+1],char args[NARGCHAR])3977dd7cddfSDavid du Colombier stackargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR])
3987dd7cddfSDavid du Colombier {
3997dd7cddfSDavid du Colombier 	int i, n;
4007dd7cddfSDavid du Colombier 	char *s, *a;
4017dd7cddfSDavid du Colombier 
4027dd7cddfSDavid du Colombier 	s = args;
4037dd7cddfSDavid du Colombier 	for(i=0; i<NARGS; i++){
4047dd7cddfSDavid du Colombier 		a = inargv[i];
4057dd7cddfSDavid du Colombier 		if(a == nil)
4067dd7cddfSDavid du Colombier 			break;
4077dd7cddfSDavid du Colombier 		n = strlen(a)+1;
4087dd7cddfSDavid du Colombier 		if((s-args)+n >= NARGCHAR)	/* too many characters */
4097dd7cddfSDavid du Colombier 			break;
4107dd7cddfSDavid du Colombier 		argv[i] = s;
4117dd7cddfSDavid du Colombier 		memmove(s, a, n);
4127dd7cddfSDavid du Colombier 		s += n;
4137dd7cddfSDavid du Colombier 		free(a);
4147dd7cddfSDavid du Colombier 	}
4157dd7cddfSDavid du Colombier 	argv[i] = nil;
4167dd7cddfSDavid du Colombier }
4177dd7cddfSDavid du Colombier 
4187dd7cddfSDavid du Colombier 
4197dd7cddfSDavid du Colombier void
execproc(void * v)4207dd7cddfSDavid du Colombier execproc(void *v)
4217dd7cddfSDavid du Colombier {
4227dd7cddfSDavid du Colombier 	char **av;
4237dd7cddfSDavid du Colombier 	char buf[1024], *args[NARGS+1], argc[NARGCHAR];
4247dd7cddfSDavid du Colombier 
4257dd7cddfSDavid du Colombier 	rfork(RFFDG);
42639734e7eSDavid du Colombier 	close(0);
42739734e7eSDavid du Colombier 	open("/dev/null", OREAD);
4287dd7cddfSDavid du Colombier 	av = v;
4297dd7cddfSDavid du Colombier 	stackargv(av, args, argc);
4307dd7cddfSDavid du Colombier 	free(av);
4317dd7cddfSDavid du Colombier 	procexec(nil, args[0], args);
4327dd7cddfSDavid du Colombier 	if(args[0][0]!='/' && strncmp(args[0], "./", 2)!=0 && strncmp(args[0], "../", 3)!=0)
4337dd7cddfSDavid du Colombier 		snprint(buf, sizeof buf, "/bin/%s", args[0]);
4347dd7cddfSDavid du Colombier 	procexec(nil, buf, args);
4357dd7cddfSDavid du Colombier 	threadexits("can't exec");
4367dd7cddfSDavid du Colombier }
4377dd7cddfSDavid du Colombier 
4387dd7cddfSDavid du Colombier char*
startup(Ruleset * rs,Exec * e)4397dd7cddfSDavid du Colombier startup(Ruleset *rs, Exec *e)
4407dd7cddfSDavid du Colombier {
4417dd7cddfSDavid du Colombier 	char **argv;
4427dd7cddfSDavid du Colombier 	int i;
4437dd7cddfSDavid du Colombier 
4447dd7cddfSDavid du Colombier 	if(rs != nil)
4457dd7cddfSDavid du Colombier 		for(i=0; i<rs->nact; i++){
4467dd7cddfSDavid du Colombier 			if(rs->act[i]->verb == VStart)
4477dd7cddfSDavid du Colombier 				goto Found;
4487dd7cddfSDavid du Colombier 			if(rs->act[i]->verb == VClient){
4497dd7cddfSDavid du Colombier 				if(e->msg->dst==nil || e->msg->dst[0]=='\0')
4507dd7cddfSDavid du Colombier 					return "no port for \"client\" rule";
4517dd7cddfSDavid du Colombier 				e->holdforclient = 1;
4527dd7cddfSDavid du Colombier 				goto Found;
4537dd7cddfSDavid du Colombier 			}
4547dd7cddfSDavid du Colombier 		}
4557dd7cddfSDavid du Colombier 	return "no start action for plumb message";
4567dd7cddfSDavid du Colombier 
4577dd7cddfSDavid du Colombier Found:
4587dd7cddfSDavid du Colombier 	argv = buildargv(rs->act[i]->arg, e);
4597dd7cddfSDavid du Colombier 	if(argv[0] == nil)
4607dd7cddfSDavid du Colombier 		return "empty argument list";
4617dd7cddfSDavid du Colombier 	proccreate(execproc, argv, EXECSTACK);
4627dd7cddfSDavid du Colombier 	return nil;
4637dd7cddfSDavid du Colombier }
464