Home | History | Annotate | Download | only in rdist
      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