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