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 %} 28 29 %term EQUAL 1 30 %term LP 2 31 %term RP 3 32 %term SM 4 33 %term ARROW 5 34 %term COLON 6 35 %term DCOLON 7 36 %term NAME 8 37 %term STRING 9 38 %term INSTALL 10 39 %term NOTIFY 11 40 %term EXCEPT 12 41 %term PATTERN 13 42 %term SPECIAL 14 43 %term OPTION 15 44 45 %union { 46 int intval; 47 char *string; 48 struct subcmd *subcmd; 49 struct namelist *namel; 50 } 51 52 %type <intval> OPTION, options 53 %type <string> NAME, STRING 54 %type <subcmd> INSTALL, NOTIFY, EXCEPT, PATTERN, SPECIAL, cmdlist, cmd 55 %type <namel> namelist, names, opt_namelist 56 57 %% 58 59 file: /* VOID */ 60 | file command 61 ; 62 63 command: NAME EQUAL namelist = { 64 (void) lookup($1, INSERT, $3); 65 } 66 | namelist ARROW namelist cmdlist = { 67 insert(NULL, $1, $3, $4); 68 } 69 | NAME COLON namelist ARROW namelist cmdlist = { 70 insert($1, $3, $5, $6); 71 } 72 | namelist DCOLON NAME cmdlist = { 73 append(NULL, $1, $3, $4); 74 } 75 | NAME COLON namelist DCOLON NAME cmdlist = { 76 append($1, $3, $5, $6); 77 } 78 | error 79 ; 80 81 namelist: NAME = { 82 $$ = makenl($1); 83 } 84 | LP names RP = { 85 $$ = $2; 86 } 87 ; 88 89 names: /* VOID */ { 90 $$ = last_n = NULL; 91 } 92 | names NAME = { 93 if (last_n == NULL) 94 $$ = last_n = makenl($2); 95 else { 96 last_n->n_next = makenl($2); 97 last_n = last_n->n_next; 98 $$ = $1; 99 } 100 } 101 ; 102 103 cmdlist: /* VOID */ { 104 $$ = last_sc = NULL; 105 } 106 | cmdlist cmd = { 107 if (last_sc == NULL) 108 $$ = last_sc = $2; 109 else { 110 last_sc->sc_next = $2; 111 last_sc = $2; 112 $$ = $1; 113 } 114 } 115 ; 116 117 cmd: INSTALL options opt_namelist SM = { 118 register struct namelist *nl; 119 120 $1->sc_options = $2 | options; 121 if ($3 != NULL) { 122 nl = expand($3, E_VARS); 123 if (nl && nl->n_next != NULL) 124 yyerror("only one name allowed\n"); 125 $1->sc_name = nl ? nl->n_name: NULL; 126 if (nl) 127 free(nl); 128 } 129 $$ = $1; 130 } 131 | NOTIFY namelist SM = { 132 if ($2 != NULL) 133 $1->sc_args = expand($2, E_VARS); 134 $$ = $1; 135 } 136 | EXCEPT namelist SM = { 137 if ($2 != NULL) 138 $1->sc_args = expand($2, E_ALL); 139 $$ = $1; 140 } 141 | PATTERN namelist SM = { 142 struct namelist *nl; 143 char *cp, *re_comp(); 144 145 /* 146 * We dup the namelist in $2 because expand() 147 * destroys the list referred to in its first 148 * argument. 149 */ 150 for (nl = expand(dupnl($2), E_VARS); nl != NULL; 151 nl = nl->n_next) 152 if ((cp = re_comp(nl->n_name)) != NULL) 153 yyerror(cp); 154 $1->sc_args = expand($2, E_VARS); 155 $$ = $1; 156 } 157 | SPECIAL opt_namelist STRING SM = { 158 if ($2 != NULL) 159 $1->sc_args = expand($2, E_ALL); 160 $1->sc_name = $3; 161 $$ = $1; 162 } 163 ; 164 165 options: /* VOID */ = { 166 $$ = 0; 167 } 168 | options OPTION = { 169 $$ |= $2; 170 } 171 ; 172 173 opt_namelist: /* VOID */ = { 174 $$ = NULL; 175 } 176 | namelist = { 177 $$ = $1; 178 } 179 ; 180 181 %% 182 183 int yylineno = 1; 184 extern FILE *fin; 185 186 yylex() 187 { 188 static char yytext[INMAX]; 189 register int c; 190 register char *cp1, *cp2; 191 static char quotechars[] = "[]{}*?$"; 192 193 again: 194 switch (c = getc(fin)) { 195 case EOF: /* end of file */ 196 return(0); 197 198 case '#': /* start of comment */ 199 while ((c = getc(fin)) != EOF && c != '\n') 200 ; 201 if (c == EOF) 202 return(0); 203 case '\n': 204 yylineno++; 205 case ' ': 206 case '\t': /* skip blanks */ 207 goto again; 208 209 case '=': /* EQUAL */ 210 return(EQUAL); 211 212 case '(': /* LP */ 213 return(LP); 214 215 case ')': /* RP */ 216 return(RP); 217 218 case ';': /* SM */ 219 return(SM); 220 221 case '-': /* -> */ 222 if ((c = getc(fin)) == '>') 223 return(ARROW); 224 ungetc(c, fin); 225 c = '-'; 226 break; 227 228 case '"': /* STRING */ 229 cp1 = yytext; 230 cp2 = &yytext[INMAX - 1]; 231 for (;;) { 232 if (cp1 >= cp2) { 233 yyerror("command string too long\n"); 234 break; 235 } 236 c = getc(fin); 237 if (c == EOF || c == '"') 238 break; 239 if (c == '\\') { 240 if ((c = getc(fin)) == EOF) { 241 *cp1++ = '\\'; 242 break; 243 } 244 } 245 if (c == '\n') { 246 yylineno++; 247 c = ' '; /* can't send '\n' */ 248 } 249 *cp1++ = c; 250 } 251 if (c != '"') 252 yyerror("missing closing '\"'\n"); 253 *cp1 = '\0'; 254 yylval.string = makestr(yytext); 255 return(STRING); 256 257 case ':': /* : or :: */ 258 if ((c = getc(fin)) == ':') 259 return(DCOLON); 260 ungetc(c, fin); 261 return(COLON); 262 } 263 cp1 = yytext; 264 cp2 = &yytext[INMAX - 1]; 265 for (;;) { 266 if (cp1 >= cp2) { 267 yyerror("input line too long\n"); 268 break; 269 } 270 if (c == '\\') { 271 if ((c = getc(fin)) != EOF) { 272 if (any(c, quotechars)) 273 c |= QUOTE; 274 } else { 275 *cp1++ = '\\'; 276 break; 277 } 278 } 279 *cp1++ = c; 280 c = getc(fin); 281 if (c == EOF || any(c, " \"'\t()=;:\n")) { 282 ungetc(c, fin); 283 break; 284 } 285 } 286 *cp1 = '\0'; 287 if (yytext[0] == '-' && yytext[2] == '\0') { 288 switch (yytext[1]) { 289 case 'b': 290 yylval.intval = COMPARE; 291 return(OPTION); 292 293 case 'R': 294 yylval.intval = REMOVE; 295 return(OPTION); 296 297 case 'v': 298 yylval.intval = VERIFY; 299 return(OPTION); 300 301 case 'w': 302 yylval.intval = WHOLE; 303 return(OPTION); 304 305 case 'y': 306 yylval.intval = YOUNGER; 307 return(OPTION); 308 309 case 'h': 310 yylval.intval = FOLLOW; 311 return(OPTION); 312 313 case 'i': 314 yylval.intval = IGNLNKS; 315 return(OPTION); 316 } 317 } 318 if (!strcmp(yytext, "install")) 319 c = INSTALL; 320 else if (!strcmp(yytext, "notify")) 321 c = NOTIFY; 322 else if (!strcmp(yytext, "except")) 323 c = EXCEPT; 324 else if (!strcmp(yytext, "except_pat")) 325 c = PATTERN; 326 else if (!strcmp(yytext, "special")) 327 c = SPECIAL; 328 else { 329 yylval.string = makestr(yytext); 330 return(NAME); 331 } 332 yylval.subcmd = makesubcmd(c); 333 return(c); 334 } 335 336 any(c, str) 337 register int c; 338 register char *str; 339 { 340 while (*str) 341 if (c == *str++) 342 return(1); 343 return(0); 344 } 345 346 /* 347 * Insert or append ARROW command to list of hosts to be updated. 348 */ 349 insert(label, files, hosts, subcmds) 350 char *label; 351 struct namelist *files, *hosts; 352 struct subcmd *subcmds; 353 { 354 register struct cmd *c, *prev, *nc; 355 register struct namelist *h, *oldh; 356 357 files = expand(files, E_VARS|E_SHELL); 358 hosts = expand(hosts, E_ALL); 359 if (debug) { 360 printf("insert: files = "); 361 prnames(files); 362 printf("insert: hosts = "); 363 prnames(hosts); 364 if (cmds) 365 prcmd(cmds); 366 else 367 printf("insert: cmds NULL\n"); 368 } 369 for (h = hosts; h != NULL; oldh = h, h = h->n_next, free(oldh)) { 370 /* 371 * Search command list for an update to the same host. 372 */ 373 for (prev = NULL, c = cmds; c!=NULL; prev = c, c = c->c_next) { 374 if (strcmp(c->c_name, h->n_name) == 0) { 375 do { 376 prev = c; 377 c = c->c_next; 378 } while (c != NULL && 379 strcmp(c->c_name, h->n_name) == 0); 380 break; 381 } 382 } 383 /* 384 * Insert new command to update host. 385 */ 386 nc = ALLOC(cmd); 387 if (nc == NULL) 388 fatal("ran out of memory\n"); 389 nc->c_type = ARROW; 390 nc->c_name = h->n_name; 391 nc->c_label = label; 392 nc->c_files = files; 393 nc->c_cmds = subcmds; 394 nc->c_next = c; 395 if (prev == NULL) 396 cmds = nc; 397 else 398 prev->c_next = nc; 399 /* update last_cmd if appending nc to cmds */ 400 if (c == NULL) 401 last_cmd = nc; 402 } 403 } 404 405 /* 406 * Append DCOLON command to the end of the command list since these are always 407 * executed in the order they appear in the distfile. 408 */ 409 append(label, files, stamp, subcmds) 410 char *label; 411 struct namelist *files; 412 char *stamp; 413 struct subcmd *subcmds; 414 { 415 register struct cmd *c; 416 417 c = ALLOC(cmd); 418 if (c == NULL) 419 fatal("ran out of memory\n"); 420 c->c_type = DCOLON; 421 c->c_name = stamp; 422 c->c_label = label; 423 c->c_files = expand(files, E_ALL); 424 c->c_cmds = subcmds; 425 c->c_next = NULL; 426 if (cmds == NULL) 427 cmds = last_cmd = c; 428 else { 429 last_cmd->c_next = c; 430 last_cmd = c; 431 } 432 } 433 434 /* 435 * Error printing routine in parser. 436 */ 437 yyerror(s) 438 char *s; 439 { 440 extern int yychar; 441 442 nerrs++; 443 fflush(stdout); 444 fprintf(stderr, "rdist: line %d: %s\n", yylineno, s); 445 } 446 447 /* 448 * Return a copy of the string. 449 */ 450 char * 451 makestr(str) 452 char *str; 453 { 454 register char *cp, *s; 455 456 str = cp = malloc(strlen(s = str) + 1); 457 if (cp == NULL) 458 fatal("ran out of memory\n"); 459 while (*cp++ = *s++) 460 ; 461 return(str); 462 } 463 464 /* 465 * Allocate a namelist structure. 466 */ 467 struct namelist * 468 makenl(name) 469 char *name; 470 { 471 register struct namelist *nl; 472 473 nl = ALLOC(namelist); 474 if (nl == NULL) 475 fatal("ran out of memory\n"); 476 nl->n_name = name; 477 nl->n_next = NULL; 478 return(nl); 479 } 480 481 /* 482 * Duplicate an existing namelist structure. Only used by the PATTERN 483 * code, and then only because expand() is destructive. 484 */ 485 struct namelist * 486 dupnl(old) 487 struct namelist *old; 488 { 489 struct namelist *n; 490 struct namelist *new, *newhead = (struct namelist *) NULL; 491 struct namelist *prev = (struct namelist *) NULL; 492 493 for (n = old; n; n = n->n_next) { 494 new = ALLOC(namelist); 495 if (new == (struct namelist *) NULL) 496 fatal("ran out of memory\n"); 497 if (newhead == (struct namelist *) NULL) 498 newhead = new; 499 if (n->n_name) { 500 if ((new->n_name = strdup(n->n_name)) == (char *) NULL) 501 fatal("ran out of memory\n"); 502 } else 503 new->n_name = (char *) NULL; 504 if (prev) 505 prev->n_next = new; 506 prev = new; 507 } 508 if (prev) 509 prev->n_next = (struct namelist *) NULL; 510 511 return (newhead); 512 } 513 514 /* 515 * Make a sub command for lists of variables, commands, etc. 516 */ 517 struct subcmd * 518 makesubcmd(type, name) 519 int type; 520 register char *name; 521 { 522 register char *cp; 523 register struct subcmd *sc; 524 525 sc = ALLOC(subcmd); 526 if (sc == NULL) 527 fatal("ran out of memory\n"); 528 sc->sc_type = type; 529 sc->sc_args = NULL; 530 sc->sc_next = NULL; 531 sc->sc_name = NULL; 532 return(sc); 533 } 534