match.c 8.0 KB

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