xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.bin/rdist/gram.y (revision cdd3e9a818787b4def17c9f707f435885ce0ed31)
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 int yyerror(const 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 					(void) yyerror(
128 					    "only one name allowed\n");
129 				$1->sc_name = nl ? nl->n_name: NULL;
130 				if (nl)
131 					free(nl);
132 			}
133 			$$ = $1;
134 		}
135 		| NOTIFY namelist SM {
136 			if ($2 != NULL)
137 				$1->sc_args = expand($2, E_VARS);
138 			$$ = $1;
139 		}
140 		| EXCEPT namelist SM {
141 			if ($2 != NULL)
142 				$1->sc_args = expand($2, E_ALL);
143 			$$ = $1;
144 		}
145 		| PATTERN namelist SM {
146 			struct namelist *nl;
147 			char *cp, *re_comp();
148 
149 			/*
150 			 *	We dup the namelist in $2 because expand()
151 			 *	destroys the list referred to in its first
152 			 *	argument.
153 			 */
154 			for (nl = expand(dupnl($2), E_VARS); nl != NULL;
155 				nl = nl->n_next)
156 				if ((cp = re_comp(nl->n_name)) != NULL)
157 					(void) yyerror(cp);
158 			$1->sc_args = expand($2, E_VARS);
159 			$$ = $1;
160 		}
161 		| SPECIAL opt_namelist STRING SM {
162 			if ($2 != NULL)
163 				$1->sc_args = expand($2, E_ALL);
164 			$1->sc_name = $3;
165 			$$ = $1;
166 		}
167 		;
168 
169 options:	  /* VOID */ {
170 			$$ = 0;
171 		}
172 		| options OPTION {
173 			$$ |= $2;
174 		}
175 		;
176 
177 opt_namelist:	  /* VOID */ {
178 			$$ = NULL;
179 		}
180 		| namelist {
181 			$$ = $1;
182 		}
183 		;
184 
185 %%
186 
187 int	yylineno = 1;
188 extern	FILE *fin;
189 
190 int
191 yylex()
192 {
193 	static char yytext[INMAX];
194 	register int c;
195 	register char *cp1, *cp2;
196 	static char quotechars[] = "[]{}*?$";
197 
198 again:
199 	switch (c = getc(fin)) {
200 	case EOF:  /* end of file */
201 		return(0);
202 
203 	case '#':  /* start of comment */
204 		while ((c = getc(fin)) != EOF && c != '\n')
205 			;
206 		if (c == EOF)
207 			return(0);
208 		/* FALLTHROUGH */
209 	case '\n':
210 		yylineno++;
211 	case ' ':
212 	case '\t':  /* skip blanks */
213 		goto again;
214 
215 	case '=':  /* EQUAL */
216 		return(EQUAL);
217 
218 	case '(':  /* LP */
219 		return(LP);
220 
221 	case ')':  /* RP */
222 		return(RP);
223 
224 	case ';':  /* SM */
225 		return(SM);
226 
227 	case '-':  /* -> */
228 		if ((c = getc(fin)) == '>')
229 			return(ARROW);
230 		ungetc(c, fin);
231 		c = '-';
232 		break;
233 
234 	case '"':  /* STRING */
235 		cp1 = yytext;
236 		cp2 = &yytext[INMAX - 1];
237 		for (;;) {
238 			if (cp1 >= cp2) {
239 				(void) yyerror("command string too long\n");
240 				break;
241 			}
242 			c = getc(fin);
243 			if (c == EOF || c == '"')
244 				break;
245 			if (c == '\\') {
246 				if ((c = getc(fin)) == EOF) {
247 					*cp1++ = '\\';
248 					break;
249 				}
250 			}
251 			if (c == '\n') {
252 				yylineno++;
253 				c = ' '; /* can't send '\n' */
254 			}
255 			*cp1++ = c;
256 		}
257 		if (c != '"')
258 			(void) yyerror("missing closing '\"'\n");
259 		*cp1 = '\0';
260 		yylval.string = makestr(yytext);
261 		return(STRING);
262 
263 	case ':':  /* : or :: */
264 		if ((c = getc(fin)) == ':')
265 			return(DCOLON);
266 		ungetc(c, fin);
267 		return(COLON);
268 	}
269 	cp1 = yytext;
270 	cp2 = &yytext[INMAX - 1];
271 	for (;;) {
272 		if (cp1 >= cp2) {
273 			(void) yyerror("input line too long\n");
274 			break;
275 		}
276 		if (c == '\\') {
277 			if ((c = getc(fin)) != EOF) {
278 				if (any(c, quotechars))
279 					c |= QUOTE;
280 			} else {
281 				*cp1++ = '\\';
282 				break;
283 			}
284 		}
285 		*cp1++ = c;
286 		c = getc(fin);
287 		if (c == EOF || any(c, " \"'\t()=;:\n")) {
288 			ungetc(c, fin);
289 			break;
290 		}
291 	}
292 	*cp1 = '\0';
293 	if (yytext[0] == '-' && yytext[2] == '\0') {
294 		switch (yytext[1]) {
295 		case 'b':
296 			yylval.intval = COMPARE;
297 			return(OPTION);
298 
299 		case 'R':
300 			yylval.intval = REMOVE;
301 			return(OPTION);
302 
303 		case 'v':
304 			yylval.intval = VERIFY;
305 			return(OPTION);
306 
307 		case 'w':
308 			yylval.intval = WHOLE;
309 			return(OPTION);
310 
311 		case 'y':
312 			yylval.intval = YOUNGER;
313 			return(OPTION);
314 
315 		case 'h':
316 			yylval.intval = FOLLOW;
317 			return(OPTION);
318 
319 		case 'i':
320 			yylval.intval = IGNLNKS;
321 			return(OPTION);
322 		}
323 	}
324 	if (!strcmp(yytext, "install"))
325 		c = INSTALL;
326 	else if (!strcmp(yytext, "notify"))
327 		c = NOTIFY;
328 	else if (!strcmp(yytext, "except"))
329 		c = EXCEPT;
330 	else if (!strcmp(yytext, "except_pat"))
331 		c = PATTERN;
332 	else if (!strcmp(yytext, "special"))
333 		c = SPECIAL;
334 	else {
335 		yylval.string = makestr(yytext);
336 		return(NAME);
337 	}
338 	yylval.subcmd = makesubcmd(c);
339 	return(c);
340 }
341 
342 int
343 any(c, str)
344 	register int c;
345 	register char *str;
346 {
347 	while (*str)
348 		if (c == *str++)
349 			return(1);
350 	return(0);
351 }
352 
353 /*
354  * Insert or append ARROW command to list of hosts to be updated.
355  */
356 void
357 insert(label, files, hosts, subcmds)
358 	char *label;
359 	struct namelist *files, *hosts;
360 	struct subcmd *subcmds;
361 {
362 	register struct cmd *c, *prev, *nc;
363 	register struct namelist *h, *oldh;
364 
365 	files = expand(files, E_VARS|E_SHELL);
366 	hosts = expand(hosts, E_ALL);
367 if (debug) {
368 	printf("insert:  files = ");
369 	prnames(files);
370 	printf("insert:  hosts = ");
371 	prnames(hosts);
372 	if (cmds)
373 		prcmd(cmds);
374 	else
375 		printf("insert:  cmds NULL\n");
376 }
377 	for (h = hosts; h != NULL; oldh = h, h = h->n_next, free(oldh)) {
378 		/*
379 		 * Search command list for an update to the same host.
380 		 */
381 		for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) {
382 			if (strcmp(c->c_name, h->n_name) == 0) {
383 				do {
384 					prev = c;
385 					c = c->c_next;
386 				} while (c != NULL &&
387 					strcmp(c->c_name, h->n_name) == 0);
388 				break;
389 			}
390 		}
391 		/*
392 		 * Insert new command to update host.
393 		 */
394 		nc = ALLOC(cmd);
395 		if (nc == NULL)
396 			fatal("ran out of memory\n");
397 		nc->c_type = ARROW;
398 		nc->c_name = h->n_name;
399 		nc->c_label = label;
400 		nc->c_files = files;
401 		nc->c_cmds = subcmds;
402 		nc->c_next = c;
403 		if (prev == NULL)
404 			cmds = nc;
405 		else
406 			prev->c_next = nc;
407 		/* update last_cmd if appending nc to cmds */
408 		if (c == NULL)
409 			last_cmd = nc;
410 	}
411 }
412 
413 /*
414  * Append DCOLON command to the end of the command list since these are always
415  * executed in the order they appear in the distfile.
416  */
417 static void
418 append(label, files, stamp, subcmds)
419 	char *label;
420 	struct namelist *files;
421 	char *stamp;
422 	struct subcmd *subcmds;
423 {
424 	register struct cmd *c;
425 
426 	c = ALLOC(cmd);
427 	if (c == NULL)
428 		fatal("ran out of memory\n");
429 	c->c_type = DCOLON;
430 	c->c_name = stamp;
431 	c->c_label = label;
432 	c->c_files = expand(files, E_ALL);
433 	c->c_cmds = subcmds;
434 	c->c_next = NULL;
435 	if (cmds == NULL)
436 		cmds = last_cmd = c;
437 	else {
438 		last_cmd->c_next = c;
439 		last_cmd = c;
440 	}
441 }
442 
443 /*
444  * Error printing routine in parser.
445  */
446 int
447 yyerror(const char *s)
448 {
449 	extern int yychar;
450 
451 	nerrs++;
452 	fflush(stdout);
453 	fprintf(stderr, "rdist: line %d: %s\n", yylineno, s);
454 	return (0);
455 }
456 
457 /*
458  * Return a copy of the string.
459  */
460 char *
461 makestr(str)
462 	char *str;
463 {
464 	register char *cp, *s;
465 
466 	str = cp = malloc(strlen(s = str) + 1);
467 	if (cp == NULL)
468 		fatal("ran out of memory\n");
469 	while (*cp++ = *s++)
470 		;
471 	return(str);
472 }
473 
474 /*
475  * Allocate a namelist structure.
476  */
477 struct namelist *
478 makenl(name)
479 	char *name;
480 {
481 	register struct namelist *nl;
482 
483 	nl = ALLOC(namelist);
484 	if (nl == NULL)
485 		fatal("ran out of memory\n");
486 	nl->n_name = name;
487 	nl->n_next = NULL;
488 	return(nl);
489 }
490 
491 /*
492  * Duplicate an existing namelist structure.  Only used by the PATTERN
493  * code, and then only because expand() is destructive.
494  */
495 struct namelist *
496 dupnl(old)
497 	struct namelist *old;
498 {
499 	struct namelist *n;
500 	struct namelist *new, *newhead = (struct namelist *) NULL;
501 	struct namelist *prev = (struct namelist *) NULL;
502 
503 	for (n = old; n; n = n->n_next) {
504 		new = ALLOC(namelist);
505 		if (new == (struct namelist *) NULL)
506 			fatal("ran out of memory\n");
507 		if (newhead == (struct namelist *) NULL)
508 			newhead = new;
509 		if (n->n_name) {
510 			if ((new->n_name = strdup(n->n_name)) == (char *) NULL)
511 				fatal("ran out of memory\n");
512 		} else
513 			new->n_name = (char *) NULL;
514 		if (prev)
515 			prev->n_next = new;
516 		prev = new;
517 	}
518 	if (prev)
519 		prev->n_next = (struct namelist *) NULL;
520 
521 	return (newhead);
522 }
523 
524 /*
525  * Make a sub command for lists of variables, commands, etc.
526  */
527 struct subcmd *
528 makesubcmd(type, name)
529 	int type;
530 	register char *name;
531 {
532 	register char *cp;
533 	register struct subcmd *sc;
534 
535 	sc = ALLOC(subcmd);
536 	if (sc == NULL)
537 		fatal("ran out of memory\n");
538 	sc->sc_type = type;
539 	sc->sc_args = NULL;
540 	sc->sc_next = NULL;
541 	sc->sc_name = NULL;
542 	return(sc);
543 }
544