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