rules.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <regexp.h>
  5. #include <thread.h>
  6. #include <ctype.h>
  7. #include <plumb.h>
  8. #include "plumber.h"
  9. typedef struct Input Input;
  10. typedef struct Var Var;
  11. struct Input
  12. {
  13. char *file; /* name of file */
  14. Biobuf *fd; /* input buffer, if from real file */
  15. uchar *s; /* input string, if from /mnt/plumb/rules */
  16. uchar *end; /* end of input string */
  17. int lineno;
  18. Input *next; /* file to read after EOF on this one */
  19. };
  20. struct Var
  21. {
  22. char *name;
  23. char *value;
  24. char *qvalue;
  25. };
  26. static int parsing;
  27. static int nvars;
  28. static Var *vars;
  29. static Input *input;
  30. static char ebuf[4096];
  31. char *badports[] =
  32. {
  33. ".",
  34. "..",
  35. "send",
  36. nil
  37. };
  38. char *objects[] =
  39. {
  40. "arg",
  41. "attr",
  42. "data",
  43. "dst",
  44. "plumb",
  45. "src",
  46. "type",
  47. "wdir",
  48. nil
  49. };
  50. char *verbs[] =
  51. {
  52. "add",
  53. "client",
  54. "delete",
  55. "is",
  56. "isdir",
  57. "isfile",
  58. "matches",
  59. "set",
  60. "start",
  61. "to",
  62. nil
  63. };
  64. static void
  65. printinputstackrev(Input *in)
  66. {
  67. if(in == nil)
  68. return;
  69. printinputstackrev(in->next);
  70. fprint(2, "%s:%d: ", in->file, in->lineno);
  71. }
  72. void
  73. printinputstack(void)
  74. {
  75. printinputstackrev(input);
  76. }
  77. static void
  78. pushinput(char *name, int fd, uchar *str)
  79. {
  80. Input *in;
  81. int depth;
  82. depth = 0;
  83. for(in=input; in; in=in->next)
  84. if(depth++ >= 10) /* prevent deep C stack in plumber and bad include structure */
  85. parseerror("include stack too deep; max 10");
  86. in = emalloc(sizeof(Input));
  87. in->file = estrdup(name);
  88. in->next = input;
  89. input = in;
  90. if(str)
  91. in->s = str;
  92. else{
  93. in->fd = emalloc(sizeof(Biobuf));
  94. if(Binit(in->fd, fd, OREAD) < 0)
  95. parseerror("can't initialize Bio for rules file: %r");
  96. }
  97. }
  98. int
  99. popinput(void)
  100. {
  101. Input *in;
  102. in = input;
  103. if(in == nil)
  104. return 0;
  105. input = in->next;
  106. if(in->fd){
  107. Bterm(in->fd);
  108. free(in->fd);
  109. }
  110. free(in);
  111. return 1;
  112. }
  113. int
  114. getc(void)
  115. {
  116. if(input == nil)
  117. return Beof;
  118. if(input->fd)
  119. return Bgetc(input->fd);
  120. if(input->s < input->end)
  121. return *(input->s)++;
  122. return -1;
  123. }
  124. char*
  125. getline(void)
  126. {
  127. static int n = 0;
  128. static char *s, *incl;
  129. int c, i;
  130. i = 0;
  131. for(;;){
  132. c = getc();
  133. if(c < 0)
  134. return nil;
  135. if(i == n){
  136. n += 100;
  137. s = erealloc(s, n);
  138. }
  139. if(c<0 || c=='\0' || c=='\n')
  140. break;
  141. s[i++] = c;
  142. }
  143. s[i] = '\0';
  144. return s;
  145. }
  146. int
  147. lookup(char *s, char *tab[])
  148. {
  149. int i;
  150. for(i=0; tab[i]!=nil; i++)
  151. if(strcmp(s, tab[i])==0)
  152. return i;
  153. return -1;
  154. }
  155. Var*
  156. lookupvariable(char *s, int n)
  157. {
  158. int i;
  159. for(i=0; i<nvars; i++)
  160. if(n==strlen(vars[i].name) && memcmp(s, vars[i].name, n)==0)
  161. return vars+i;
  162. return nil;
  163. }
  164. char*
  165. variable(char *s, int n)
  166. {
  167. Var *var;
  168. var = lookupvariable(s, n);
  169. if(var)
  170. return var->qvalue;
  171. return nil;
  172. }
  173. void
  174. setvariable(char *s, int n, char *val, char *qval)
  175. {
  176. Var *var;
  177. var = lookupvariable(s, n);
  178. if(var){
  179. free(var->value);
  180. free(var->qvalue);
  181. }else{
  182. vars = erealloc(vars, (nvars+1)*sizeof(Var));
  183. var = vars+nvars++;
  184. var->name = emalloc(n+1);
  185. memmove(var->name, s, n);
  186. }
  187. var->value = estrdup(val);
  188. var->qvalue = estrdup(qval);
  189. }
  190. static char*
  191. nonnil(char *s)
  192. {
  193. if(s == nil)
  194. return "";
  195. return s;
  196. }
  197. static char*
  198. filename(Exec *e, char *name)
  199. {
  200. static char *buf; /* rock to hold value so we don't leak the strings */
  201. free(buf);
  202. /* if name is defined, used it */
  203. if(name!=nil && name[0]!='\0'){
  204. buf = estrdup(name);
  205. return cleanname(buf);
  206. }
  207. /* if data is an absolute file name, or wdir is empty, use it */
  208. if(e->msg->data[0]=='/' || e->msg->wdir==nil || e->msg->wdir[0]=='\0'){
  209. buf = estrdup(e->msg->data);
  210. return cleanname(buf);
  211. }
  212. buf = emalloc(strlen(e->msg->wdir)+1+strlen(e->msg->data)+1);
  213. sprint(buf, "%s/%s", e->msg->wdir, e->msg->data);
  214. return cleanname(buf);
  215. }
  216. char*
  217. dollar(Exec *e, char *s, int *namelen)
  218. {
  219. int n;
  220. static char *abuf;
  221. char *t;
  222. *namelen = 1;
  223. if(e!=nil && '0'<=s[0] && s[0]<='9')
  224. return nonnil(e->match[s[0]-'0']);
  225. for(t=s; isalnum(*t); t++)
  226. ;
  227. n = t-s;
  228. *namelen = n;
  229. if(e != nil){
  230. if(n == 3){
  231. if(memcmp(s, "src", 3) == 0)
  232. return nonnil(e->msg->src);
  233. if(memcmp(s, "dst", 3) == 0)
  234. return nonnil(e->msg->dst);
  235. if(memcmp(s, "dir", 3) == 0)
  236. return filename(e, e->dir);
  237. }
  238. if(n == 4){
  239. if(memcmp(s, "attr", 4) == 0){
  240. free(abuf);
  241. abuf = plumbpackattr(e->msg->attr);
  242. return nonnil(abuf);
  243. }
  244. if(memcmp(s, "data", 4) == 0)
  245. return nonnil(e->msg->data);
  246. if(memcmp(s, "file", 4) == 0)
  247. return filename(e, e->file);
  248. if(memcmp(s, "type", 4) == 0)
  249. return nonnil(e->msg->type);
  250. if(memcmp(s, "wdir", 3) == 0)
  251. return nonnil(e->msg->wdir);
  252. }
  253. }
  254. return variable(s, n);
  255. }
  256. /* expand one blank-terminated string, processing quotes and $ signs */
  257. char*
  258. expand(Exec *e, char *s, char **ends)
  259. {
  260. char *p, *ep, *val;
  261. int namelen, quoting;
  262. p = ebuf;
  263. ep = ebuf+sizeof ebuf-1;
  264. quoting = 0;
  265. while(p<ep && *s!='\0' && (quoting || (*s!=' ' && *s!='\t'))){
  266. if(*s == '\''){
  267. s++;
  268. if(!quoting)
  269. quoting = 1;
  270. else if(*s == '\''){
  271. *p++ = '\'';
  272. s++;
  273. }else
  274. quoting = 0;
  275. continue;
  276. }
  277. if(quoting || *s!='$'){
  278. *p++ = *s++;
  279. continue;
  280. }
  281. s++;
  282. val = dollar(e, s, &namelen);
  283. if(val == nil){
  284. *p++ = '$';
  285. continue;
  286. }
  287. if(ep-p < strlen(val))
  288. return "string-too-long";
  289. strcpy(p, val);
  290. p += strlen(val);
  291. s += namelen;
  292. }
  293. if(ends)
  294. *ends = s;
  295. *p = '\0';
  296. return ebuf;
  297. }
  298. void
  299. regerror(char *msg)
  300. {
  301. if(parsing){
  302. parsing = 0;
  303. parseerror("%s", msg);
  304. }
  305. error("%s", msg);
  306. }
  307. void
  308. parserule(Rule *r)
  309. {
  310. r->qarg = estrdup(expand(nil, r->arg, nil));
  311. switch(r->obj){
  312. case OArg:
  313. case OAttr:
  314. case OData:
  315. case ODst:
  316. case OType:
  317. case OWdir:
  318. case OSrc:
  319. if(r->verb==VClient || r->verb==VStart || r->verb==VTo)
  320. parseerror("%s not valid verb for object %s", verbs[r->verb], objects[r->obj]);
  321. if(r->obj!=OAttr && (r->verb==VAdd || r->verb==VDelete))
  322. parseerror("%s not valid verb for object %s", verbs[r->verb], objects[r->obj]);
  323. if(r->verb == VMatches){
  324. r->regex = regcomp(r->qarg);
  325. return;
  326. }
  327. break;
  328. case OPlumb:
  329. if(r->verb!=VClient && r->verb!=VStart && r->verb!=VTo)
  330. parseerror("%s not valid verb for object %s", verbs[r->verb], objects[r->obj]);
  331. break;
  332. }
  333. }
  334. int
  335. assignment(char *p)
  336. {
  337. char *var, *qval;
  338. int n;
  339. if(!isalpha(p[0]))
  340. return 0;
  341. for(var=p; isalnum(*p); p++)
  342. ;
  343. n = p-var;
  344. while(*p==' ' || *p=='\t')
  345. p++;
  346. if(*p++ != '=')
  347. return 0;
  348. while(*p==' ' || *p=='\t')
  349. p++;
  350. qval = expand(nil, p, nil);
  351. setvariable(var, n, p, qval);
  352. return 1;
  353. }
  354. int
  355. include(char *s)
  356. {
  357. char *t, *args[3], buf[128];
  358. int n, fd;
  359. if(strncmp(s, "include", 7) != 0)
  360. return 0;
  361. /* either an include or an error */
  362. n = tokenize(s, args, nelem(args));
  363. if(n < 2)
  364. goto Err;
  365. if(strcmp(args[0], "include") != 0)
  366. goto Err;
  367. if(args[1][0] == '#')
  368. goto Err;
  369. if(n>2 && args[2][0] != '#')
  370. goto Err;
  371. t = args[1];
  372. fd = open(t, OREAD);
  373. if(fd<0 && t[0]!='/' && strncmp(t, "./", 2)!=0 && strncmp(t, "../", 3)!=0){
  374. snprint(buf, sizeof buf, "/sys/lib/plumb/%s", t);
  375. t = buf;
  376. fd = open(t, OREAD);
  377. }
  378. if(fd < 0)
  379. parseerror("can't open %s for inclusion", t);
  380. pushinput(t, fd, nil);
  381. return 1;
  382. Err:
  383. parseerror("malformed include statement");
  384. return 0;
  385. }
  386. Rule*
  387. readrule(int *eof)
  388. {
  389. Rule *rp;
  390. char *line, *p;
  391. char *word;
  392. Top:
  393. line = getline();
  394. if(line == nil){
  395. /*
  396. * if input is from string, and bytes remain (input->end is within string),
  397. * morerules() will pop input and save remaining data. otherwise pop
  398. * the stack here, and if there's more input, keep reading.
  399. */
  400. if((input!=nil && input->end==nil) && popinput())
  401. goto Top;
  402. *eof = 1;
  403. return nil;
  404. }
  405. input->lineno++;
  406. for(p=line; *p==' ' || *p=='\t'; p++)
  407. ;
  408. if(*p=='\0' || *p=='#') /* empty or comment line */
  409. return nil;
  410. if(include(p))
  411. goto Top;
  412. if(assignment(p))
  413. return nil;
  414. rp = emalloc(sizeof(Rule));
  415. /* object */
  416. for(word=p; *p!=' ' && *p!='\t'; p++)
  417. if(*p == '\0')
  418. parseerror("malformed rule");
  419. *p++ = '\0';
  420. rp->obj = lookup(word, objects);
  421. if(rp->obj < 0){
  422. if(strcmp(word, "kind") == 0) /* backwards compatibility */
  423. rp->obj = OType;
  424. else
  425. parseerror("unknown object %s", word);
  426. }
  427. /* verb */
  428. while(*p==' ' || *p=='\t')
  429. p++;
  430. for(word=p; *p!=' ' && *p!='\t'; p++)
  431. if(*p == '\0')
  432. parseerror("malformed rule");
  433. *p++ = '\0';
  434. rp->verb = lookup(word, verbs);
  435. if(rp->verb < 0)
  436. parseerror("unknown verb %s", word);
  437. /* argument */
  438. while(*p==' ' || *p=='\t')
  439. p++;
  440. if(*p == '\0')
  441. parseerror("malformed rule");
  442. rp->arg = estrdup(p);
  443. parserule(rp);
  444. return rp;
  445. }
  446. void
  447. freerule(Rule *r)
  448. {
  449. free(r->arg);
  450. free(r->qarg);
  451. free(r->regex);
  452. }
  453. void
  454. freerules(Rule **r)
  455. {
  456. while(*r)
  457. freerule(*r++);
  458. }
  459. void
  460. freeruleset(Ruleset *rs)
  461. {
  462. freerules(rs->pat);
  463. free(rs->pat);
  464. freerules(rs->act);
  465. free(rs->act);
  466. free(rs->port);
  467. free(rs);
  468. }
  469. Ruleset*
  470. readruleset(void)
  471. {
  472. Ruleset *rs;
  473. Rule *r;
  474. int eof, inrule, i, ncmd;
  475. Again:
  476. eof = 0;
  477. rs = emalloc(sizeof(Ruleset));
  478. rs->pat = emalloc(sizeof(Rule*));
  479. rs->act = emalloc(sizeof(Rule*));
  480. inrule = 0;
  481. ncmd = 0;
  482. for(;;){
  483. r = readrule(&eof);
  484. if(eof)
  485. break;
  486. if(r==nil){
  487. if(inrule)
  488. break;
  489. continue;
  490. }
  491. inrule = 1;
  492. switch(r->obj){
  493. case OArg:
  494. case OAttr:
  495. case OData:
  496. case ODst:
  497. case OType:
  498. case OWdir:
  499. case OSrc:
  500. rs->npat++;
  501. rs->pat = erealloc(rs->pat, (rs->npat+1)*sizeof(Rule*));
  502. rs->pat[rs->npat-1] = r;
  503. rs->pat[rs->npat] = nil;
  504. break;
  505. case OPlumb:
  506. rs->nact++;
  507. rs->act = erealloc(rs->act, (rs->nact+1)*sizeof(Rule*));
  508. rs->act[rs->nact-1] = r;
  509. rs->act[rs->nact] = nil;
  510. if(r->verb == VTo){
  511. if(rs->npat>0 && rs->port != nil) /* npat==0 implies port declaration */
  512. parseerror("too many ports");
  513. if(lookup(r->qarg, badports) >= 0)
  514. parseerror("illegal port name %s", r->qarg);
  515. rs->port = estrdup(r->qarg);
  516. }else
  517. ncmd++; /* start or client rule */
  518. break;
  519. }
  520. }
  521. if(ncmd > 1){
  522. freeruleset(rs);
  523. parseerror("ruleset has more than one client or start action");
  524. }
  525. if(rs->npat>0 && rs->nact>0)
  526. return rs;
  527. if(rs->npat==0 && rs->nact==0){
  528. freeruleset(rs);
  529. return nil;
  530. }
  531. if(rs->nact==0 || rs->port==nil){
  532. freeruleset(rs);
  533. parseerror("ruleset must have patterns and actions");
  534. return nil;
  535. }
  536. /* declare ports */
  537. for(i=0; i<rs->nact; i++)
  538. if(rs->act[i]->verb != VTo){
  539. freeruleset(rs);
  540. parseerror("ruleset must have actions");
  541. return nil;
  542. }
  543. for(i=0; i<rs->nact; i++)
  544. addport(rs->act[i]->qarg);
  545. freeruleset(rs);
  546. goto Again;
  547. }
  548. Ruleset**
  549. readrules(char *name, int fd)
  550. {
  551. Ruleset *rs, **rules;
  552. int n;
  553. parsing = 1;
  554. pushinput(name, fd, nil);
  555. rules = emalloc(sizeof(Ruleset*));
  556. for(n=0; (rs=readruleset())!=nil; n++){
  557. rules = erealloc(rules, (n+2)*sizeof(Ruleset*));
  558. rules[n] = rs;
  559. rules[n+1] = nil;
  560. }
  561. popinput();
  562. parsing = 0;
  563. return rules;
  564. }
  565. char*
  566. concat(char *s, char *t)
  567. {
  568. if(t == nil)
  569. return s;
  570. if(s == nil)
  571. s = estrdup(t);
  572. else{
  573. s = erealloc(s, strlen(s)+strlen(t)+1);
  574. strcat(s, t);
  575. }
  576. return s;
  577. }
  578. char*
  579. printpat(Rule *r)
  580. {
  581. char *s;
  582. s = emalloc(strlen(objects[r->obj])+1+strlen(verbs[r->verb])+1+strlen(r->arg)+1+1);
  583. sprint(s, "%s\t%s\t%s\n", objects[r->obj], verbs[r->verb], r->arg);
  584. return s;
  585. }
  586. char*
  587. printvar(Var *v)
  588. {
  589. char *s;
  590. s = emalloc(strlen(v->name)+1+strlen(v->value)+2+1);
  591. sprint(s, "%s=%s\n\n", v->name, v->value);
  592. return s;
  593. }
  594. char*
  595. printrule(Ruleset *r)
  596. {
  597. int i;
  598. char *s;
  599. s = nil;
  600. for(i=0; i<r->npat; i++)
  601. s = concat(s, printpat(r->pat[i]));
  602. for(i=0; i<r->nact; i++)
  603. s = concat(s, printpat(r->act[i]));
  604. s = concat(s, "\n");
  605. return s;
  606. }
  607. char*
  608. printport(char *port)
  609. {
  610. char *s;
  611. s = nil;
  612. s = concat(s, "plumb to ");
  613. s = concat(s, port);
  614. s = concat(s, "\n");
  615. return s;
  616. }
  617. char*
  618. printrules(void)
  619. {
  620. int i;
  621. char *s;
  622. s = nil;
  623. for(i=0; i<nvars; i++)
  624. s = concat(s, printvar(&vars[i]));
  625. for(i=0; i<nports; i++)
  626. s = concat(s, printport(ports[i]));
  627. s = concat(s, "\n");
  628. for(i=0; rules[i]; i++)
  629. s = concat(s, printrule(rules[i]));
  630. return s;
  631. }
  632. char*
  633. stringof(char *s, int n)
  634. {
  635. char *t;
  636. t = emalloc(n+1);
  637. memmove(t, s, n);
  638. return t;
  639. }
  640. uchar*
  641. morerules(uchar *text, int done)
  642. {
  643. int n;
  644. Ruleset *rs;
  645. uchar *otext, *s, *endofrule;
  646. pushinput("<rules input>", -1, text);
  647. if(done)
  648. input->end = text+strlen((char*)text);
  649. else{
  650. /*
  651. * Help user by sending any full rules to parser so any parse errors will
  652. * occur on write rather than close. A heuristic will do: blank line ends rule.
  653. */
  654. endofrule = nil;
  655. for(s=text; *s!='\0'; s++)
  656. if(*s=='\n' && *++s=='\n')
  657. endofrule = s+1;
  658. if(endofrule == nil)
  659. return text;
  660. input->end = endofrule;
  661. }
  662. for(n=0; rules[n]; n++)
  663. ;
  664. while((rs=readruleset()) != nil){
  665. rules = erealloc(rules, (n+2)*sizeof(Ruleset*));
  666. rules[n++] = rs;
  667. rules[n] = nil;
  668. }
  669. otext =text;
  670. if(input == nil)
  671. text = (uchar*)estrdup("");
  672. else
  673. text = (uchar*)estrdup((char*)input->end);
  674. popinput();
  675. free(otext);
  676. return text;
  677. }
  678. char*
  679. writerules(char *s, int n)
  680. {
  681. static uchar *text;
  682. char *tmp;
  683. free(lasterror);
  684. lasterror = nil;
  685. parsing = 1;
  686. if(setjmp(parsejmp) == 0){
  687. tmp = stringof(s, n);
  688. text = (uchar*)concat((char*)text, tmp);
  689. free(tmp);
  690. text = morerules(text, s==nil);
  691. }
  692. if(s == nil){
  693. free(text);
  694. text = nil;
  695. }
  696. parsing = 0;
  697. makeports(rules);
  698. return lasterror;
  699. }