xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.bin/rdist/gram.y (revision 598f4ceed9327d2d6c2325dd67cae3aa06f7fea6)
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 static void append(char *label, struct namelist *files, char *stamp,
28     struct subcmd *subcmds);
29 void yyerror(char *s);
30 
31 %}
32 
33 %term EQUAL	1
34 %term LP	2
35 %term RP	3
36 %term SM	4
37 %term ARROW	5
38 %term COLON	6
39 %term DCOLON	7
40 %term NAME	8
41 %term STRING	9
42 %term INSTALL	10
43 %term NOTIFY	11
44 %term EXCEPT	12
45 %term PATTERN	13
46 %term SPECIAL	14
47 %term OPTION	15
48 
49 %union {
50 	int intval;
51 	char *string;
52 	struct subcmd *subcmd;
53 	struct namelist *namel;
54 }
55 
56 %type <intval> OPTION, options
57 %type <string> NAME, STRING
58 %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd
59 %type <namel> namelist, names, opt_namelist
60 
61 %%
62 
63 file:		  /* VOID */
64 		| file command
65 		;
66 
67 command:	  NAME EQUAL namelist = {
68 			(void) lookup($1, INSERT, $3);
69 		}
70 		| namelist ARROW namelist cmdlist = {
71 			insert(NULL, $1, $3, $4);
72 		}
73 		| NAME COLON namelist ARROW namelist cmdlist = {
74 			insert($1, $3, $5, $6);
75 		}
76 		| namelist DCOLON NAME cmdlist = {
77 			append(NULL, $1, $3, $4);
78 		}
79 		| NAME COLON namelist DCOLON NAME cmdlist = {
80 			append($1, $3, $5, $6);
81 		}
82 		| error
83 		;
84 
85 namelist:	  NAME = {
86 			$$ = makenl($1);
87 		}
88 		| LP names RP = {
89 			$$ = $2;
90 		}
91 		;
92 
93 names:		  /* VOID */ {
94 			$$ = last_n = NULL;
95 		}
96 		| names NAME = {
97 			if (last_n == NULL)
98 				$$ = last_n = makenl($2);
99 			else {
100 				last_n->n_next = makenl($2);
101 				last_n = last_n->n_next;
102 				$$ = $1;
103 			}
104 		}
105 		;
106 
107 cmdlist:	  /* VOID */ {
108 			$$ = last_sc = NULL;
109 		}
110 		| cmdlist cmd = {
111 			if (last_sc == NULL)
112 				$$ = last_sc = $2;
113 			else {
114 				last_sc->sc_next = $2;
115 				last_sc = $2;
116 				$$ = $1;
117 			}
118 		}
119 		;
120 
121 cmd:		  INSTALL options opt_namelist SM = {
122 			register struct namelist *nl;
123 
124 			$1->sc_options = $2 | options;
125 			if ($3 != NULL) {
126 				nl = expand($3, E_VARS);
127 				if (nl && nl->n_next != NULL)
128 					yyerror("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 					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 	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
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
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
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
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 *
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 *
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 *
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 *
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