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