rules.c 13 KB

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