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