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