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 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 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