match.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <regexp.h>
  13. #include <thread.h>
  14. #include <plumb.h>
  15. #include "plumber.h"
  16. int
  17. verbis(int obj, Plumbmsg *m, Rule *r)
  18. {
  19. switch(obj){
  20. default:
  21. fprint(2, "unimplemented 'is' object %d\n", obj);
  22. break;
  23. case OData:
  24. return strcmp(m->data, r->qarg) == 0;
  25. case ODst:
  26. return strcmp(m->dst, r->qarg) == 0;
  27. case OType:
  28. return strcmp(m->type, r->qarg) == 0;
  29. case OWdir:
  30. return strcmp(m->wdir, r->qarg) == 0;
  31. case OSrc:
  32. return strcmp(m->src, r->qarg) == 0;
  33. }
  34. return 0;
  35. }
  36. static void
  37. setvar(Resub rs[10], char *match[10])
  38. {
  39. int i, n;
  40. for(i=0; i<10; i++){
  41. free(match[i]);
  42. match[i] = nil;
  43. }
  44. for(i=0; i<10 && rs[i].sp!=nil; i++){
  45. n = rs[i].ep-rs[i].sp;
  46. match[i] = emalloc(n+1);
  47. memmove(match[i], rs[i].sp, n);
  48. match[i][n] = '\0';
  49. }
  50. }
  51. int
  52. clickmatch(Reprog *re, char *text, Resub rs[10], int click)
  53. {
  54. char *clickp;
  55. int i, w;
  56. Rune r;
  57. /* click is in characters, not bytes */
  58. for(i=0; i<click && text[i]!='\0'; i+=w)
  59. w = chartorune(&r, text+i);
  60. clickp = text+i;
  61. for(i=0; i<=click; i++){
  62. memset(rs, 0, 10*sizeof(Resub));
  63. if(regexec(re, text+i, rs, 10))
  64. if(rs[0].sp<=clickp && clickp<=rs[0].ep)
  65. return 1;
  66. }
  67. return 0;
  68. }
  69. int
  70. verbmatches(int obj, Plumbmsg *m, Rule *r, Exec *e)
  71. {
  72. Resub rs[10];
  73. char *clickval, *alltext;
  74. int p0, p1, ntext;
  75. memset(rs, 0, sizeof rs);
  76. ntext = -1;
  77. switch(obj){
  78. default:
  79. fprint(2, "unimplemented 'matches' object %d\n", obj);
  80. break;
  81. case OData:
  82. clickval = plumblookup(m->attr, "click");
  83. if(clickval == nil){
  84. alltext = m->data;
  85. ntext = m->ndata;
  86. goto caseAlltext;
  87. }
  88. if(!clickmatch(r->regex, m->data, rs, atoi(clickval)))
  89. break;
  90. p0 = rs[0].sp - m->data;
  91. p1 = rs[0].ep - m->data;
  92. if(e->p0 >=0 && !(p0==e->p0 && p1==e->p1))
  93. break;
  94. e->clearclick = 1;
  95. e->setdata = 1;
  96. e->p0 = p0;
  97. e->p1 = p1;
  98. setvar(rs, e->match);
  99. return 1;
  100. case ODst:
  101. alltext = m->dst;
  102. goto caseAlltext;
  103. case OType:
  104. alltext = m->type;
  105. goto caseAlltext;
  106. case OWdir:
  107. alltext = m->wdir;
  108. goto caseAlltext;
  109. case OSrc:
  110. alltext = m->src;
  111. /* fall through */
  112. caseAlltext:
  113. /* must match full text */
  114. if(ntext < 0)
  115. ntext = strlen(alltext);
  116. if(!regexec(r->regex, alltext, rs, 10) || rs[0].sp!=alltext || rs[0].ep!=alltext+ntext)
  117. break;
  118. setvar(rs, e->match);
  119. return 1;
  120. }
  121. return 0;
  122. }
  123. int
  124. isfile(char *file, uint32_t maskon, uint32_t maskoff)
  125. {
  126. Dir *d;
  127. int mode;
  128. d = dirstat(file);
  129. if(d == nil)
  130. return 0;
  131. mode = d->mode;
  132. free(d);
  133. if((mode & maskon) == 0)
  134. return 0;
  135. if(mode & maskoff)
  136. return 0;
  137. return 1;
  138. }
  139. char*
  140. absolute(char *dir, char *file)
  141. {
  142. char *p;
  143. if(file[0] == '/')
  144. return estrdup(file);
  145. p = emalloc(strlen(dir)+1+strlen(file)+1);
  146. sprint(p, "%s/%s", dir, file);
  147. return cleanname(p);
  148. }
  149. int
  150. verbisfile(int obj, Plumbmsg *m, Rule *r, Exec *e, uint32_t maskon,
  151. uint32_t maskoff, char **var)
  152. {
  153. char *file;
  154. switch(obj){
  155. default:
  156. fprint(2, "unimplemented 'isfile' object %d\n", obj);
  157. break;
  158. case OArg:
  159. file = absolute(m->wdir, expand(e, r->arg, nil));
  160. if(isfile(file, maskon, maskoff)){
  161. *var = file;
  162. return 1;
  163. }
  164. free(file);
  165. break;
  166. case OData:
  167. case OWdir:
  168. file = absolute(m->wdir, obj==OData? m->data : m->wdir);
  169. if(isfile(file, maskon, maskoff)){
  170. *var = file;
  171. return 1;
  172. }
  173. free(file);
  174. break;
  175. }
  176. return 0;
  177. }
  178. int
  179. verbset(int obj, Plumbmsg *m, Rule *r, Exec *e)
  180. {
  181. char *new;
  182. switch(obj){
  183. default:
  184. fprint(2, "unimplemented 'is' object %d\n", obj);
  185. break;
  186. case OData:
  187. new = estrdup(expand(e, r->arg, nil));
  188. m->ndata = strlen(new);
  189. free(m->data);
  190. m->data = new;
  191. e->p0 = -1;
  192. e->p1 = -1;
  193. e->setdata = 0;
  194. return 1;
  195. case ODst:
  196. new = estrdup(expand(e, r->arg, nil));
  197. free(m->dst);
  198. m->dst = new;
  199. return 1;
  200. case OType:
  201. new = estrdup(expand(e, r->arg, nil));
  202. free(m->type);
  203. m->type = new;
  204. return 1;
  205. case OWdir:
  206. new = estrdup(expand(e, r->arg, nil));
  207. free(m->wdir);
  208. m->wdir = new;
  209. return 1;
  210. case OSrc:
  211. new = estrdup(expand(e, r->arg, nil));
  212. free(m->src);
  213. m->src = new;
  214. return 1;
  215. }
  216. return 0;
  217. }
  218. int
  219. verbadd(int obj, Plumbmsg *m, Rule *r, Exec *e)
  220. {
  221. switch(obj){
  222. default:
  223. fprint(2, "unimplemented 'add' object %d\n", obj);
  224. break;
  225. case OAttr:
  226. m->attr = plumbaddattr(m->attr, plumbunpackattr(expand(e, r->arg, nil)));
  227. return 1;
  228. }
  229. return 0;
  230. }
  231. int
  232. verbdelete(int obj, Plumbmsg *m, Rule *r, Exec *e)
  233. {
  234. char *a;
  235. switch(obj){
  236. default:
  237. fprint(2, "unimplemented 'delete' object %d\n", obj);
  238. break;
  239. case OAttr:
  240. a = expand(e, r->arg, nil);
  241. if(plumblookup(m->attr, a) == nil)
  242. break;
  243. m->attr = plumbdelattr(m->attr, a);
  244. return 1;
  245. }
  246. return 0;
  247. }
  248. int
  249. matchpat(Plumbmsg *m, Exec *e, Rule *r)
  250. {
  251. switch(r->verb){
  252. default:
  253. fprint(2, "unimplemented verb %d\n", r->verb);
  254. break;
  255. case VAdd:
  256. return verbadd(r->obj, m, r, e);
  257. case VDelete:
  258. return verbdelete(r->obj, m, r, e);
  259. case VIs:
  260. return verbis(r->obj, m, r);
  261. case VIsdir:
  262. return verbisfile(r->obj, m, r, e, DMDIR, 0, &e->dir);
  263. case VIsfile:
  264. return verbisfile(r->obj, m, r, e, ~DMDIR, DMDIR, &e->file);
  265. case VMatches:
  266. return verbmatches(r->obj, m, r, e);
  267. case VSet:
  268. verbset(r->obj, m, r, e);
  269. return 1;
  270. }
  271. return 0;
  272. }
  273. void
  274. freeexec(Exec *exec)
  275. {
  276. int i;
  277. if(exec == nil)
  278. return;
  279. free(exec->dir);
  280. free(exec->file);
  281. for(i=0; i<10; i++)
  282. free(exec->match[i]);
  283. free(exec);
  284. }
  285. Exec*
  286. newexec(Plumbmsg *m)
  287. {
  288. Exec *exec;
  289. exec = emalloc(sizeof(Exec));
  290. exec->msg = m;
  291. exec->p0 = -1;
  292. exec->p1 = -1;
  293. return exec;
  294. }
  295. void
  296. rewrite(Plumbmsg *m, Exec *e)
  297. {
  298. Plumbattr *a, *prev;
  299. if(e->clearclick){
  300. prev = nil;
  301. for(a=m->attr; a!=nil; a=a->next){
  302. if(strcmp(a->name, "click") == 0){
  303. if(prev == nil)
  304. m->attr = a->next;
  305. else
  306. prev->next = a->next;
  307. free(a->name);
  308. free(a->value);
  309. free(a);
  310. break;
  311. }
  312. prev = a;
  313. }
  314. if(e->setdata){
  315. free(m->data);
  316. m->data = estrdup(expand(e, "$0", nil));
  317. m->ndata = strlen(m->data);
  318. }
  319. }
  320. }
  321. char**
  322. buildargv(char *s, Exec *e)
  323. {
  324. char **av;
  325. int ac;
  326. ac = 0;
  327. av = nil;
  328. for(;;){
  329. av = erealloc(av, (ac+1) * sizeof(char*));
  330. av[ac] = nil;
  331. while(*s==' ' || *s=='\t')
  332. s++;
  333. if(*s == '\0')
  334. break;
  335. av[ac++] = estrdup(expand(e, s, &s));
  336. }
  337. return av;
  338. }
  339. Exec*
  340. matchruleset(Plumbmsg *m, Ruleset *rs)
  341. {
  342. int i;
  343. Exec *exec;
  344. if(m->dst!=nil && m->dst[0]!='\0' && rs->port!=nil && strcmp(m->dst, rs->port)!=0)
  345. return nil;
  346. exec = newexec(m);
  347. for(i=0; i<rs->npat; i++)
  348. if(!matchpat(m, exec, rs->pat[i])){
  349. freeexec(exec);
  350. return nil;
  351. }
  352. if(rs->port!=nil && (m->dst==nil || m->dst[0]=='\0')){
  353. free(m->dst);
  354. m->dst = estrdup(rs->port);
  355. }
  356. rewrite(m, exec);
  357. return exec;
  358. }
  359. enum
  360. {
  361. NARGS = 100,
  362. NARGCHAR = 8*1024,
  363. EXECSTACK = 8192+(NARGS+1)*sizeof(char*)+NARGCHAR
  364. };
  365. /* copy argv to stack and free the incoming strings, so we don't leak argument vectors */
  366. void
  367. stackargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR])
  368. {
  369. int i, n;
  370. char *s, *a;
  371. s = args;
  372. for(i=0; i<NARGS; i++){
  373. a = inargv[i];
  374. if(a == nil)
  375. break;
  376. n = strlen(a)+1;
  377. if((s-args)+n >= NARGCHAR) /* too many characters */
  378. break;
  379. argv[i] = s;
  380. memmove(s, a, n);
  381. s += n;
  382. free(a);
  383. }
  384. argv[i] = nil;
  385. }
  386. void
  387. execproc(void *v)
  388. {
  389. char **av;
  390. char buf[1024], *args[NARGS+1], argc[NARGCHAR];
  391. rfork(RFFDG);
  392. close(0);
  393. open("/dev/null", OREAD);
  394. av = v;
  395. stackargv(av, args, argc);
  396. free(av);
  397. procexec(nil, args[0], args);
  398. if(args[0][0]!='/' && strncmp(args[0], "./", 2)!=0 && strncmp(args[0], "../", 3)!=0)
  399. snprint(buf, sizeof buf, "/bin/%s", args[0]);
  400. procexec(nil, buf, args);
  401. threadexits("can't exec");
  402. }
  403. char*
  404. startup(Ruleset *rs, Exec *e)
  405. {
  406. char **argv;
  407. int i;
  408. if(rs != nil)
  409. for(i=0; i<rs->nact; i++){
  410. if(rs->act[i]->verb == VStart)
  411. goto Found;
  412. if(rs->act[i]->verb == VClient){
  413. if(e->msg->dst==nil || e->msg->dst[0]=='\0')
  414. return "no port for \"client\" rule";
  415. e->holdforclient = 1;
  416. goto Found;
  417. }
  418. }
  419. return "no start action for plumb message";
  420. Found:
  421. argv = buildargv(rs->act[i]->arg, e);
  422. if(argv[0] == nil)
  423. return "empty argument list";
  424. proccreate(execproc, argv, EXECSTACK);
  425. return nil;
  426. }