Annotation of src/usr.bin/rdist/gram.y, Revision 1.10
1.1 deraadt 1: %{
1.10 ! guenther 2: /* $OpenBSD: gram.y,v 1.9 2009/10/27 23:59:42 deraadt Exp $ */
1.4 millert 3:
1.1 deraadt 4: /*
1.2 dm 5: * Copyright (c) 1993 Michael A. Cooper
6: * Copyright (c) 1993 Regents of the University of California.
7: * All rights reserved.
1.1 deraadt 8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
1.8 millert 17: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: */
33:
1.7 millert 34: #include "defs.h"
1.2 dm 35:
1.7 millert 36: static struct namelist *addnl __P((struct namelist *, struct namelist *));
37: static struct namelist *subnl __P((struct namelist *, struct namelist *));
38: static struct namelist *andnl __P((struct namelist *, struct namelist *));
39: static int innl __P((struct namelist *nl, char *p));
1.1 deraadt 40:
41: struct cmd *cmds = NULL;
42: struct cmd *last_cmd;
43: struct namelist *last_n;
44: struct subcmd *last_sc;
1.2 dm 45: int parendepth = 0;
1.1 deraadt 46:
47: %}
48:
1.2 dm 49: %term ARROW 1
50: %term COLON 2
51: %term DCOLON 3
52: %term NAME 4
53: %term STRING 5
54: %term INSTALL 6
55: %term NOTIFY 7
56: %term EXCEPT 8
57: %term PATTERN 9
58: %term SPECIAL 10
59: %term CMDSPECIAL 11
60: %term OPTION 12
1.1 deraadt 61:
62: %union {
1.2 dm 63: opt_t optval;
64: char *string;
65: struct subcmd *subcmd;
66: struct namelist *namel;
1.1 deraadt 67: }
68:
1.2 dm 69: %type <optval> OPTION, options
1.1 deraadt 70: %type <string> NAME, STRING
1.2 dm 71: %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, CMDSPECIAL, cmdlist, cmd
72: %type <namel> namelist, names, opt_namelist nlist
1.1 deraadt 73:
74: %%
75:
76: file: /* VOID */
77: | file command
78: ;
79:
1.2 dm 80: command: NAME '=' namelist = {
1.1 deraadt 81: (void) lookup($1, INSERT, $3);
82: }
83: | namelist ARROW namelist cmdlist = {
1.2 dm 84: insert((char *)NULL, $1, $3, $4);
1.1 deraadt 85: }
86: | NAME COLON namelist ARROW namelist cmdlist = {
87: insert($1, $3, $5, $6);
88: }
89: | namelist DCOLON NAME cmdlist = {
1.2 dm 90: append((char *)NULL, $1, $3, $4);
1.1 deraadt 91: }
92: | NAME COLON namelist DCOLON NAME cmdlist = {
93: append($1, $3, $5, $6);
94: }
95: | error
96: ;
97:
1.2 dm 98: namelist: nlist {
99: $$ = $1;
100: }
101: | nlist '-' nlist {
102: $$ = subnl($1, $3);
103: }
104: | nlist '+' nlist {
105: $$ = addnl($1, $3);
106: }
107: | nlist '&' nlist {
108: $$ = andnl($1, $3);
109: }
110: ;
111:
112: nlist: NAME = {
1.1 deraadt 113: $$ = makenl($1);
114: }
1.2 dm 115: | '(' names ')' = {
1.1 deraadt 116: $$ = $2;
117: }
118: ;
119:
120: names: /* VOID */ {
121: $$ = last_n = NULL;
122: }
123: | names NAME = {
124: if (last_n == NULL)
125: $$ = last_n = makenl($2);
126: else {
127: last_n->n_next = makenl($2);
128: last_n = last_n->n_next;
129: $$ = $1;
130: }
131: }
132: ;
133:
134: cmdlist: /* VOID */ {
135: $$ = last_sc = NULL;
136: }
137: | cmdlist cmd = {
138: if (last_sc == NULL)
139: $$ = last_sc = $2;
140: else {
141: last_sc->sc_next = $2;
142: last_sc = $2;
143: $$ = $1;
144: }
145: }
146: ;
147:
1.2 dm 148: cmd: INSTALL options opt_namelist ';' = {
1.7 millert 149: struct namelist *nl;
1.1 deraadt 150:
151: $1->sc_options = $2 | options;
152: if ($3 != NULL) {
153: nl = expand($3, E_VARS);
154: if (nl) {
155: if (nl->n_next != NULL)
156: yyerror("only one name allowed\n");
157: $1->sc_name = nl->n_name;
158: free(nl);
159: } else
160: $1->sc_name = NULL;
161: }
162: $$ = $1;
163: }
1.2 dm 164: | NOTIFY namelist ';' = {
1.1 deraadt 165: if ($2 != NULL)
166: $1->sc_args = expand($2, E_VARS);
167: $$ = $1;
168: }
1.2 dm 169: | EXCEPT namelist ';' = {
1.1 deraadt 170: if ($2 != NULL)
171: $1->sc_args = expand($2, E_ALL);
172: $$ = $1;
173: }
1.2 dm 174: | PATTERN namelist ';' = {
1.1 deraadt 175: struct namelist *nl;
1.6 millert 176: char ebuf[BUFSIZ];
177: regex_t reg;
178: int ecode;
179:
180: for (nl = $2; nl != NULL; nl = nl->n_next) {
181: /* check for a valid regex */
182: ecode = regcomp(®, nl->n_name, REG_NOSUB);
183: if (ecode) {
184: regerror(ecode, ®, ebuf,
185: sizeof(ebuf));
186: yyerror(ebuf);
187: }
188: regfree(®);
189: }
1.1 deraadt 190: $1->sc_args = expand($2, E_VARS);
191: $$ = $1;
192: }
1.2 dm 193: | SPECIAL opt_namelist STRING ';' = {
194: if ($2 != NULL)
195: $1->sc_args = expand($2, E_ALL);
196: $1->sc_name = $3;
197: $$ = $1;
198: }
199: | CMDSPECIAL opt_namelist STRING ';' = {
1.1 deraadt 200: if ($2 != NULL)
201: $1->sc_args = expand($2, E_ALL);
202: $1->sc_name = $3;
203: $$ = $1;
204: }
205: ;
206:
207: options: /* VOID */ = {
208: $$ = 0;
209: }
210: | options OPTION = {
211: $$ |= $2;
212: }
213: ;
214:
215: opt_namelist: /* VOID */ = {
216: $$ = NULL;
217: }
218: | namelist = {
219: $$ = $1;
220: }
221: ;
222:
223: %%
224:
225: int yylineno = 1;
226: extern FILE *fin;
227:
1.7 millert 228: int
229: yylex(void)
1.1 deraadt 230: {
231: static char yytext[INMAX];
1.7 millert 232: int c;
233: char *cp1, *cp2;
1.1 deraadt 234: static char quotechars[] = "[]{}*?$";
235:
236: again:
237: switch (c = getc(fin)) {
238: case EOF: /* end of file */
239: return(0);
240:
241: case '#': /* start of comment */
242: while ((c = getc(fin)) != EOF && c != '\n')
243: ;
244: if (c == EOF)
245: return(0);
246: case '\n':
247: yylineno++;
248: case ' ':
249: case '\t': /* skip blanks */
250: goto again;
251:
252: case '=': /* EQUAL */
1.2 dm 253: case ';': /* SM */
254: case '+':
255: case '&':
256: return(c);
1.1 deraadt 257:
258: case '(': /* LP */
1.2 dm 259: ++parendepth;
260: return(c);
1.1 deraadt 261:
262: case ')': /* RP */
1.2 dm 263: --parendepth;
264: return(c);
1.1 deraadt 265:
266: case '-': /* -> */
267: if ((c = getc(fin)) == '>')
268: return(ARROW);
1.2 dm 269: (void) ungetc(c, fin);
1.1 deraadt 270: c = '-';
271: break;
272:
273: case '"': /* STRING */
274: cp1 = yytext;
275: cp2 = &yytext[INMAX - 1];
276: for (;;) {
277: if (cp1 >= cp2) {
278: yyerror("command string too long\n");
279: break;
280: }
281: c = getc(fin);
282: if (c == EOF || c == '"')
283: break;
284: if (c == '\\') {
285: if ((c = getc(fin)) == EOF) {
286: *cp1++ = '\\';
287: break;
288: }
289: }
290: if (c == '\n') {
291: yylineno++;
292: c = ' '; /* can't send '\n' */
293: }
294: *cp1++ = c;
295: }
296: if (c != '"')
297: yyerror("missing closing '\"'\n");
298: *cp1 = '\0';
1.7 millert 299: yylval.string = xstrdup(yytext);
1.1 deraadt 300: return(STRING);
301:
302: case ':': /* : or :: */
303: if ((c = getc(fin)) == ':')
304: return(DCOLON);
1.2 dm 305: (void) ungetc(c, fin);
1.1 deraadt 306: return(COLON);
307: }
308: cp1 = yytext;
309: cp2 = &yytext[INMAX - 1];
310: for (;;) {
311: if (cp1 >= cp2) {
312: yyerror("input line too long\n");
313: break;
314: }
315: if (c == '\\') {
316: if ((c = getc(fin)) != EOF) {
317: if (any(c, quotechars))
1.2 dm 318: *cp1++ = QUOTECHAR;
1.1 deraadt 319: } else {
320: *cp1++ = '\\';
321: break;
322: }
323: }
324: *cp1++ = c;
325: c = getc(fin);
326: if (c == EOF || any(c, " \"'\t()=;:\n")) {
1.2 dm 327: (void) ungetc(c, fin);
1.1 deraadt 328: break;
329: }
330: }
331: *cp1 = '\0';
1.2 dm 332: if (yytext[0] == '-' && yytext[1] == CNULL)
333: return '-';
334: if (yytext[0] == '-' && parendepth <= 0) {
335: opt_t opt = 0;
336: static char ebuf[BUFSIZ];
337:
1.1 deraadt 338: switch (yytext[1]) {
1.2 dm 339: case 'o':
340: if (parsedistopts(&yytext[2], &opt, TRUE)) {
1.7 millert 341: (void) snprintf(ebuf, sizeof(ebuf),
342: "Bad distfile options \"%s\".",
343: &yytext[2]);
1.2 dm 344: yyerror(ebuf);
345: }
346: break;
347:
348: /*
349: * These options are obsoleted by -o.
350: */
351: case 'b': opt = DO_COMPARE; break;
352: case 'R': opt = DO_REMOVE; break;
353: case 'v': opt = DO_VERIFY; break;
354: case 'w': opt = DO_WHOLE; break;
355: case 'y': opt = DO_YOUNGER; break;
356: case 'h': opt = DO_FOLLOW; break;
357: case 'i': opt = DO_IGNLNKS; break;
358: case 'q': opt = DO_QUIET; break;
359: case 'x': opt = DO_NOEXEC; break;
360: case 'N': opt = DO_CHKNFS; break;
361: case 'O': opt = DO_CHKREADONLY; break;
362: case 's': opt = DO_SAVETARGETS; break;
363: case 'r': opt = DO_NODESCEND; break;
364:
365: default:
1.7 millert 366: (void) snprintf(ebuf, sizeof(ebuf),
367: "Unknown option \"%s\".", yytext);
1.2 dm 368: yyerror(ebuf);
1.1 deraadt 369: }
1.2 dm 370:
371: yylval.optval = opt;
372: return(OPTION);
1.1 deraadt 373: }
374: if (!strcmp(yytext, "install"))
375: c = INSTALL;
376: else if (!strcmp(yytext, "notify"))
377: c = NOTIFY;
378: else if (!strcmp(yytext, "except"))
379: c = EXCEPT;
380: else if (!strcmp(yytext, "except_pat"))
381: c = PATTERN;
382: else if (!strcmp(yytext, "special"))
383: c = SPECIAL;
1.2 dm 384: else if (!strcmp(yytext, "cmdspecial"))
385: c = CMDSPECIAL;
1.1 deraadt 386: else {
1.7 millert 387: yylval.string = xstrdup(yytext);
1.1 deraadt 388: return(NAME);
389: }
390: yylval.subcmd = makesubcmd(c);
391: return(c);
392: }
393:
1.2 dm 394: /*
395: * XXX We should use strchr(), but most versions can't handle
396: * some of the characters we use.
397: */
1.7 millert 398: int any(int c, char *str)
1.1 deraadt 399: {
400: while (*str)
401: if (c == *str++)
402: return(1);
403: return(0);
404: }
405:
406: /*
407: * Insert or append ARROW command to list of hosts to be updated.
408: */
1.4 millert 409: void
1.7 millert 410: insert(char *label, struct namelist *files, struct namelist *hosts,
411: struct subcmd *subcmds)
1.1 deraadt 412: {
1.7 millert 413: struct cmd *c, *prev, *nc;
414: struct namelist *h, *lasth;
1.2 dm 415:
1.10 ! guenther 416: debugmsg(DM_CALL, "insert(%s, %p, %p, %p) start, files = %s",
1.2 dm 417: label == NULL ? "(null)" : label,
418: files, hosts, subcmds, getnlstr(files));
1.1 deraadt 419:
420: files = expand(files, E_VARS|E_SHELL);
421: hosts = expand(hosts, E_ALL);
1.2 dm 422: for (h = hosts; h != NULL; lasth = h, h = h->n_next,
423: free((char *)lasth)) {
1.1 deraadt 424: /*
425: * Search command list for an update to the same host.
426: */
427: for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
428: if (strcmp(c->c_name, h->n_name) == 0) {
429: do {
430: prev = c;
431: c = c->c_next;
432: } while (c != NULL &&
433: strcmp(c->c_name, h->n_name) == 0);
434: break;
435: }
436: }
437: /*
438: * Insert new command to update host.
439: */
440: nc = ALLOC(cmd);
441: nc->c_type = ARROW;
442: nc->c_name = h->n_name;
443: nc->c_label = label;
444: nc->c_files = files;
445: nc->c_cmds = subcmds;
1.2 dm 446: nc->c_flags = 0;
1.1 deraadt 447: nc->c_next = c;
448: if (prev == NULL)
449: cmds = nc;
450: else
451: prev->c_next = nc;
452: /* update last_cmd if appending nc to cmds */
453: if (c == NULL)
454: last_cmd = nc;
455: }
456: }
457:
458: /*
459: * Append DCOLON command to the end of the command list since these are always
460: * executed in the order they appear in the distfile.
461: */
1.4 millert 462: void
1.7 millert 463: append(char *label, struct namelist *files, char *stamp, struct subcmd *subcmds)
1.1 deraadt 464: {
1.7 millert 465: struct cmd *c;
1.1 deraadt 466:
467: c = ALLOC(cmd);
468: c->c_type = DCOLON;
469: c->c_name = stamp;
470: c->c_label = label;
471: c->c_files = expand(files, E_ALL);
472: c->c_cmds = subcmds;
473: c->c_next = NULL;
474: if (cmds == NULL)
475: cmds = last_cmd = c;
476: else {
477: last_cmd->c_next = c;
478: last_cmd = c;
479: }
480: }
481:
482: /*
483: * Error printing routine in parser.
484: */
1.4 millert 485: void
1.7 millert 486: yyerror(char *s)
1.1 deraadt 487: {
1.2 dm 488: error("Error in distfile: line %d: %s", yylineno, s);
1.1 deraadt 489: }
490:
491: /*
492: * Allocate a namelist structure.
493: */
494: struct namelist *
1.7 millert 495: makenl(char *name)
1.1 deraadt 496: {
1.7 millert 497: struct namelist *nl;
1.1 deraadt 498:
1.2 dm 499: debugmsg(DM_CALL, "makenl(%s)", name == NULL ? "null" : name);
500:
1.1 deraadt 501: nl = ALLOC(namelist);
502: nl->n_name = name;
1.6 millert 503: nl->n_regex = NULL;
1.1 deraadt 504: nl->n_next = NULL;
1.2 dm 505:
1.1 deraadt 506: return(nl);
507: }
508:
1.2 dm 509:
510: /*
511: * Is the name p in the namelist nl?
512: */
513: static int
1.7 millert 514: innl(struct namelist *nl, char *p)
1.2 dm 515: {
516: for ( ; nl; nl = nl->n_next)
517: if (!strcmp(p, nl->n_name))
518: return(1);
519: return(0);
520: }
521:
522: /*
523: * Join two namelists.
524: */
525: static struct namelist *
1.7 millert 526: addnl(struct namelist *n1, struct namelist *n2)
1.2 dm 527: {
528: struct namelist *nl, *prev;
529:
530: n1 = expand(n1, E_VARS);
531: n2 = expand(n2, E_VARS);
532: for (prev = NULL, nl = NULL; n1; n1 = n1->n_next, prev = nl) {
533: nl = makenl(n1->n_name);
534: nl->n_next = prev;
535: }
536: for (; n2; n2 = n2->n_next)
537: if (!innl(nl, n2->n_name)) {
538: nl = makenl(n2->n_name);
539: nl->n_next = prev;
540: prev = nl;
541: }
542: return(prev);
543: }
544:
545: /*
546: * Copy n1 except for elements that are in n2.
547: */
548: static struct namelist *
1.7 millert 549: subnl(struct namelist *n1, struct namelist *n2)
1.2 dm 550: {
551: struct namelist *nl, *prev;
552:
553: n1 = expand(n1, E_VARS);
554: n2 = expand(n2, E_VARS);
555: for (prev = NULL; n1; n1 = n1->n_next)
556: if (!innl(n2, n1->n_name)) {
557: nl = makenl(n1->n_name);
558: nl->n_next = prev;
559: prev = nl;
560: }
561: return(prev);
562: }
563:
564: /*
565: * Copy all items of n1 that are also in n2.
566: */
567: static struct namelist *
1.7 millert 568: andnl(struct namelist *n1, struct namelist *n2)
1.2 dm 569: {
570: struct namelist *nl, *prev;
571:
572: n1 = expand(n1, E_VARS);
573: n2 = expand(n2, E_VARS);
574: for (prev = NULL; n1; n1 = n1->n_next)
575: if (innl(n2, n1->n_name)) {
576: nl = makenl(n1->n_name);
577: nl->n_next = prev;
578: prev = nl;
579: }
580: return(prev);
581: }
582:
1.1 deraadt 583: /*
584: * Make a sub command for lists of variables, commands, etc.
585: */
1.7 millert 586: struct subcmd *
587: makesubcmd(int type)
1.1 deraadt 588: {
1.7 millert 589: struct subcmd *sc;
1.1 deraadt 590:
591: sc = ALLOC(subcmd);
592: sc->sc_type = type;
593: sc->sc_args = NULL;
594: sc->sc_next = NULL;
595: sc->sc_name = NULL;
1.2 dm 596:
1.1 deraadt 597: return(sc);
598: }