1 %{
2 /*
3 * Copyright (c) 1983 Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms are permitted
7 * provided that the above copyright notice and this paragraph are
8 * duplicated in all such forms and that any documentation,
9 * advertising materials, and other materials related to such
10 * distribution and use acknowledge that the software was developed
11 * by the University of California, Berkeley. The name of the
12 * University may not be used to endorse or promote products derived
13 * from this software without specific prior written permission.
14 *
15 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
16 * Use is subject to license terms.
17 */
18
19 #include "defs.h"
20
21 struct cmd *cmds = NULL;
22 struct cmd *last_cmd;
23 struct namelist *last_n;
24 struct subcmd *last_sc;
25
26 static void append(char *label, struct namelist *files, char *stamp,
27 struct subcmd *subcmds);
28 void yyerror(char *s);
29
30 %}
31
32 %term EQUAL 1
33 %term LP 2
34 %term RP 3
35 %term SM 4
36 %term ARROW 5
37 %term COLON 6
38 %term DCOLON 7
39 %term NAME 8
40 %term STRING 9
41 %term INSTALL 10
42 %term NOTIFY 11
43 %term EXCEPT 12
44 %term PATTERN 13
45 %term SPECIAL 14
46 %term OPTION 15
47
48 %union {
49 int intval;
50 char *string;
51 struct subcmd *subcmd;
52 struct namelist *namel;
53 }
54
55 %type <intval> OPTION, options
56 %type <string> NAME, STRING
57 %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
58 %type <namel> namelist, names, opt_namelist
59
60 %%
61
62 file: /* VOID */
63 | file command
64 ;
65
66 command: NAME EQUAL namelist = {
67 (void) lookup($1, INSERT, $3);
68 }
69 | namelist ARROW namelist cmdlist = {
70 insert(NULL, $1, $3, $4);
71 }
72 | NAME COLON namelist ARROW namelist cmdlist = {
73 insert($1, $3, $5, $6);
74 }
75 | namelist DCOLON NAME cmdlist = {
76 append(NULL, $1, $3, $4);
77 }
78 | NAME COLON namelist DCOLON NAME cmdlist = {
79 append($1, $3, $5, $6);
80 }
81 | error
82 ;
83
84 namelist: NAME = {
85 $$ = makenl($1);
86 }
87 | LP names RP = {
88 $$ = $2;
89 }
90 ;
91
92 names: /* VOID */ {
93 $$ = last_n = NULL;
94 }
95 | names NAME = {
96 if (last_n == NULL)
97 $$ = last_n = makenl($2);
98 else {
99 last_n->n_next = makenl($2);
100 last_n = last_n->n_next;
101 $$ = $1;
102 }
103 }
104 ;
105
106 cmdlist: /* VOID */ {
107 $$ = last_sc = NULL;
108 }
109 | cmdlist cmd = {
110 if (last_sc == NULL)
111 $$ = last_sc = $2;
112 else {
113 last_sc->sc_next = $2;
114 last_sc = $2;
115 $$ = $1;
116 }
117 }
118 ;
119
120 cmd: INSTALL options opt_namelist SM = {
121 register struct namelist *nl;
122
123 $1->sc_options = $2 | options;
124 if ($3 != NULL) {
125 nl = expand($3, E_VARS);
126 if (nl && nl->n_next != NULL)
127 yyerror("only one name allowed\n");
128 $1->sc_name = nl ? nl->n_name: NULL;
129 if (nl)
130 free(nl);
131 }
132 $$ = $1;
133 }
134 | NOTIFY namelist SM = {
135 if ($2 != NULL)
136 $1->sc_args = expand($2, E_VARS);
137 $$ = $1;
138 }
139 | EXCEPT namelist SM = {
140 if ($2 != NULL)
141 $1->sc_args = expand($2, E_ALL);
142 $$ = $1;
143 }
144 | PATTERN namelist SM = {
145 struct namelist *nl;
146 char *cp, *re_comp();
147
148 /*
149 * We dup the namelist in $2 because expand()
150 * destroys the list referred to in its first
151 * argument.
152 */
153 for (nl = expand(dupnl($2), E_VARS); nl != NULL;
154 nl = nl->n_next)
155 if ((cp = re_comp(nl->n_name)) != NULL)
156 yyerror(cp);
157 $1->sc_args = expand($2, E_VARS);
158 $$ = $1;
159 }
160 | SPECIAL opt_namelist STRING SM = {
161 if ($2 != NULL)
162 $1->sc_args = expand($2, E_ALL);
163 $1->sc_name = $3;
164 $$ = $1;
165 }
166 ;
167
168 options: /* VOID */ = {
169 $$ = 0;
170 }
171 | options OPTION = {
172 $$ |= $2;
173 }
174 ;
175
176 opt_namelist: /* VOID */ = {
177 $$ = NULL;
178 }
179 | namelist = {
180 $$ = $1;
181 }
182 ;
183
184 %%
185
186 int yylineno = 1;
187 extern FILE *fin;
188
189 int
yylex()190 yylex()
191 {
192 static char yytext[INMAX];
193 register int c;
194 register char *cp1, *cp2;
195 static char quotechars[] = "[]{}*?$";
196
197 again:
198 switch (c = getc(fin)) {
199 case EOF: /* end of file */
200 return(0);
201
202 case '#': /* start of comment */
203 while ((c = getc(fin)) != EOF && c != '\n')
204 ;
205 if (c == EOF)
206 return(0);
207 /* FALLTHROUGH */
208 case '\n':
209 yylineno++;
210 case ' ':
211 case '\t': /* skip blanks */
212 goto again;
213
214 case '=': /* EQUAL */
215 return(EQUAL);
216
217 case '(': /* LP */
218 return(LP);
219
220 case ')': /* RP */
221 return(RP);
222
223 case ';': /* SM */
224 return(SM);
225
226 case '-': /* -> */
227 if ((c = getc(fin)) == '>')
228 return(ARROW);
229 ungetc(c, fin);
230 c = '-';
231 break;
232
233 case '"': /* STRING */
234 cp1 = yytext;
235 cp2 = &yytext[INMAX - 1];
236 for (;;) {
237 if (cp1 >= cp2) {
238 yyerror("command string too long\n");
239 break;
240 }
241 c = getc(fin);
242 if (c == EOF || c == '"')
243 break;
244 if (c == '\\') {
245 if ((c = getc(fin)) == EOF) {
246 *cp1++ = '\\';
247 break;
248 }
249 }
250 if (c == '\n') {
251 yylineno++;
252 c = ' '; /* can't send '\n' */
253 }
254 *cp1++ = c;
255 }
256 if (c != '"')
257 yyerror("missing closing '\"'\n");
258 *cp1 = '\0';
259 yylval.string = makestr(yytext);
260 return(STRING);
261
262 case ':': /* : or :: */
263 if ((c = getc(fin)) == ':')
264 return(DCOLON);
265 ungetc(c, fin);
266 return(COLON);
267 }
268 cp1 = yytext;
269 cp2 = &yytext[INMAX - 1];
270 for (;;) {
271 if (cp1 >= cp2) {
272 yyerror("input line too long\n");
273 break;
274 }
275 if (c == '\\') {
276 if ((c = getc(fin)) != EOF) {
277 if (any(c, quotechars))
278 c |= QUOTE;
279 } else {
280 *cp1++ = '\\';
281 break;
282 }
283 }
284 *cp1++ = c;
285 c = getc(fin);
286 if (c == EOF || any(c, " \"'\t()=;:\n")) {
287 ungetc(c, fin);
288 break;
289 }
290 }
291 *cp1 = '\0';
292 if (yytext[0] == '-' && yytext[2] == '\0') {
293 switch (yytext[1]) {
294 case 'b':
295 yylval.intval = COMPARE;
296 return(OPTION);
297
298 case 'R':
299 yylval.intval = REMOVE;
300 return(OPTION);
301
302 case 'v':
303 yylval.intval = VERIFY;
304 return(OPTION);
305
306 case 'w':
307 yylval.intval = WHOLE;
308 return(OPTION);
309
310 case 'y':
311 yylval.intval = YOUNGER;
312 return(OPTION);
313
314 case 'h':
315 yylval.intval = FOLLOW;
316 return(OPTION);
317
318 case 'i':
319 yylval.intval = IGNLNKS;
320 return(OPTION);
321 }
322 }
323 if (!strcmp(yytext, "install"))
324 c = INSTALL;
325 else if (!strcmp(yytext, "notify"))
326 c = NOTIFY;
327 else if (!strcmp(yytext, "except"))
328 c = EXCEPT;
329 else if (!strcmp(yytext, "except_pat"))
330 c = PATTERN;
331 else if (!strcmp(yytext, "special"))
332 c = SPECIAL;
333 else {
334 yylval.string = makestr(yytext);
335 return(NAME);
336 }
337 yylval.subcmd = makesubcmd(c);
338 return(c);
339 }
340
341 int
any(c,str)342 any(c, str)
343 register int c;
344 register char *str;
345 {
346 while (*str)
347 if (c == *str++)
348 return(1);
349 return(0);
350 }
351
352 /*
353 * Insert or append ARROW command to list of hosts to be updated.
354 */
355 void
insert(label,files,hosts,subcmds)356 insert(label, files, hosts, subcmds)
357 char *label;
358 struct namelist *files, *hosts;
359 struct subcmd *subcmds;
360 {
361 register struct cmd *c, *prev, *nc;
362 register struct namelist *h, *oldh;
363
364 files = expand(files, E_VARS|E_SHELL);
365 hosts = expand(hosts, E_ALL);
366 if (debug) {
367 printf("insert: files = ");
368 prnames(files);
369 printf("insert: hosts = ");
370 prnames(hosts);
371 if (cmds)
372 prcmd(cmds);
373 else
374 printf("insert: cmds NULL\n");
375 }
376 for (h = hosts; h != NULL; oldh = h, h = h->n_next, free(oldh)) {
377 /*
378 * Search command list for an update to the same host.
379 */
380 for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
381 if (strcmp(c->c_name, h->n_name) == 0) {
382 do {
383 prev = c;
384 c = c->c_next;
385 } while (c != NULL &&
386 strcmp(c->c_name, h->n_name) == 0);
387 break;
388 }
389 }
390 /*
391 * Insert new command to update host.
392 */
393 nc = ALLOC(cmd);
394 if (nc == NULL)
395 fatal("ran out of memory\n");
396 nc->c_type = ARROW;
397 nc->c_name = h->n_name;
398 nc->c_label = label;
399 nc->c_files = files;
400 nc->c_cmds = subcmds;
401 nc->c_next = c;
402 if (prev == NULL)
403 cmds = nc;
404 else
405 prev->c_next = nc;
406 /* update last_cmd if appending nc to cmds */
407 if (c == NULL)
408 last_cmd = nc;
409 }
410 }
411
412 /*
413 * Append DCOLON command to the end of the command list since these are always
414 * executed in the order they appear in the distfile.
415 */
416 static void
append(label,files,stamp,subcmds)417 append(label, files, stamp, subcmds)
418 char *label;
419 struct namelist *files;
420 char *stamp;
421 struct subcmd *subcmds;
422 {
423 register struct cmd *c;
424
425 c = ALLOC(cmd);
426 if (c == NULL)
427 fatal("ran out of memory\n");
428 c->c_type = DCOLON;
429 c->c_name = stamp;
430 c->c_label = label;
431 c->c_files = expand(files, E_ALL);
432 c->c_cmds = subcmds;
433 c->c_next = NULL;
434 if (cmds == NULL)
435 cmds = last_cmd = c;
436 else {
437 last_cmd->c_next = c;
438 last_cmd = c;
439 }
440 }
441
442 /*
443 * Error printing routine in parser.
444 */
445 void
yyerror(s)446 yyerror(s)
447 char *s;
448 {
449 extern int yychar;
450
451 nerrs++;
452 fflush(stdout);
453 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
454 }
455
456 /*
457 * Return a copy of the string.
458 */
459 char *
makestr(str)460 makestr(str)
461 char *str;
462 {
463 register char *cp, *s;
464
465 str = cp = malloc(strlen(s = str) + 1);
466 if (cp == NULL)
467 fatal("ran out of memory\n");
468 while (*cp++ = *s++)
469 ;
470 return(str);
471 }
472
473 /*
474 * Allocate a namelist structure.
475 */
476 struct namelist *
makenl(name)477 makenl(name)
478 char *name;
479 {
480 register struct namelist *nl;
481
482 nl = ALLOC(namelist);
483 if (nl == NULL)
484 fatal("ran out of memory\n");
485 nl->n_name = name;
486 nl->n_next = NULL;
487 return(nl);
488 }
489
490 /*
491 * Duplicate an existing namelist structure. Only used by the PATTERN
492 * code, and then only because expand() is destructive.
493 */
494 struct namelist *
dupnl(old)495 dupnl(old)
496 struct namelist *old;
497 {
498 struct namelist *n;
499 struct namelist *new, *newhead = (struct namelist *) NULL;
500 struct namelist *prev = (struct namelist *) NULL;
501
502 for (n = old; n; n = n->n_next) {
503 new = ALLOC(namelist);
504 if (new == (struct namelist *) NULL)
505 fatal("ran out of memory\n");
506 if (newhead == (struct namelist *) NULL)
507 newhead = new;
508 if (n->n_name) {
509 if ((new->n_name = strdup(n->n_name)) == (char *) NULL)
510 fatal("ran out of memory\n");
511 } else
512 new->n_name = (char *) NULL;
513 if (prev)
514 prev->n_next = new;
515 prev = new;
516 }
517 if (prev)
518 prev->n_next = (struct namelist *) NULL;
519
520 return (newhead);
521 }
522
523 /*
524 * Make a sub command for lists of variables, commands, etc.
525 */
526 struct subcmd *
makesubcmd(type,name)527 makesubcmd(type, name)
528 int type;
529 register char *name;
530 {
531 register char *cp;
532 register struct subcmd *sc;
533
534 sc = ALLOC(subcmd);
535 if (sc == NULL)
536 fatal("ran out of memory\n");
537 sc->sc_type = type;
538 sc->sc_args = NULL;
539 sc->sc_next = NULL;
540 sc->sc_name = NULL;
541 return(sc);
542 }
543