1 /* 2 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 3 * Copyright (c) 1988, 1989 by Adam de Boor 4 * Copyright (c) 1989 by Berkeley Softworks 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * %sccs.include.redist.c% 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)compat.c 5.8 (Berkeley) 10/26/91"; 15 #endif /* not lint */ 16 17 /*- 18 * compat.c -- 19 * The routines in this file implement the full-compatibility 20 * mode of PMake. Most of the special functionality of PMake 21 * is available in this mode. Things not supported: 22 * - different shells. 23 * - friendly variable substitution. 24 * 25 * Interface: 26 * Compat_Run Initialize things for this module and recreate 27 * thems as need creatin' 28 */ 29 30 #include <stdio.h> 31 #include <sys/types.h> 32 #include <sys/wait.h> 33 #include <sys/errno.h> 34 #include <signal.h> 35 #include <ctype.h> 36 #include "make.h" 37 extern int errno; 38 39 /* 40 * The following array is used to make a fast determination of which 41 * characters are interpreted specially by the shell. If a command 42 * contains any of these characters, it is executed by the shell, not 43 * directly by us. 44 */ 45 46 static char meta[256]; 47 48 static GNode *curTarg = NILGNODE; 49 static GNode *ENDNode; 50 static int CompatRunCommand(); 51 52 /*- 53 *----------------------------------------------------------------------- 54 * CompatInterrupt -- 55 * Interrupt the creation of the current target and remove it if 56 * it ain't precious. 57 * 58 * Results: 59 * None. 60 * 61 * Side Effects: 62 * The target is removed and the process exits. If .INTERRUPT exists, 63 * its commands are run first WITH INTERRUPTS IGNORED.. 64 * 65 *----------------------------------------------------------------------- 66 */ 67 static void 68 CompatInterrupt (signo) 69 int signo; 70 { 71 GNode *gn; 72 73 if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) { 74 char *file = Var_Value (TARGET, curTarg); 75 76 if (unlink (file) == SUCCESS) { 77 printf ("*** %s removed\n", file); 78 } 79 80 /* 81 * Run .INTERRUPT only if hit with interrupt signal 82 */ 83 if (signo == SIGINT) { 84 gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 85 if (gn != NILGNODE) { 86 Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); 87 } 88 } 89 } 90 exit (0); 91 } 92 93 /*- 94 *----------------------------------------------------------------------- 95 * CompatRunCommand -- 96 * Execute the next command for a target. If the command returns an 97 * error, the node's made field is set to ERROR and creation stops. 98 * 99 * Results: 100 * 0 if the command succeeded, 1 if an error occurred. 101 * 102 * Side Effects: 103 * The node's 'made' field may be set to ERROR. 104 * 105 *----------------------------------------------------------------------- 106 */ 107 static int 108 CompatRunCommand (cmd, gn) 109 char *cmd; /* Command to execute */ 110 GNode *gn; /* Node from which the command came */ 111 { 112 char *cmdStart; /* Start of expanded command */ 113 register char *cp; 114 Boolean silent, /* Don't print command */ 115 errCheck; /* Check errors */ 116 union wait reason; /* Reason for child's death */ 117 int status; /* Description of child's death */ 118 int cpid; /* Child actually found */ 119 int numWritten; /* Number of bytes written for error message */ 120 ReturnStatus stat; /* Status of fork */ 121 LstNode cmdNode; /* Node where current command is located */ 122 char **av; /* Argument vector for thing to exec */ 123 int argc; /* Number of arguments in av or 0 if not 124 * dynamically allocated */ 125 Boolean local; /* TRUE if command should be executed 126 * locally */ 127 128 silent = gn->type & OP_SILENT; 129 errCheck = !(gn->type & OP_IGNORE); 130 131 cmdNode = Lst_Member (gn->commands, (ClientData)cmd); 132 cmdStart = Var_Subst (cmd, gn, FALSE); 133 134 /* 135 * brk_string will return an argv with a NULL in av[1], thus causing 136 * execvp to choke and die horribly. Besides, how can we execute a null 137 * command? In any case, we warn the user that the command expanded to 138 * nothing (is this the right thing to do?). 139 */ 140 141 if (*cmdStart == '\0') { 142 Error("%s expands to empty string", cmd); 143 return(0); 144 } else { 145 cmd = cmdStart; 146 } 147 Lst_Replace (cmdNode, (ClientData)cmdStart); 148 149 if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { 150 (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart); 151 return(0); 152 } else if (strcmp(cmdStart, "...") == 0) { 153 gn->type |= OP_SAVE_CMDS; 154 return(0); 155 } 156 157 while ((*cmd == '@') || (*cmd == '-')) { 158 if (*cmd == '@') { 159 silent = TRUE; 160 } else { 161 errCheck = FALSE; 162 } 163 cmd++; 164 } 165 166 /* 167 * Search for meta characters in the command. If there are no meta 168 * characters, there's no need to execute a shell to execute the 169 * command. 170 */ 171 for (cp = cmd; !meta[*cp]; cp++) { 172 continue; 173 } 174 175 /* 176 * Print the command before echoing if we're not supposed to be quiet for 177 * this one. We also print the command if -n given. 178 */ 179 if (!silent || noExecute) { 180 printf ("%s\n", cmd); 181 fflush(stdout); 182 } 183 184 /* 185 * If we're not supposed to execute any commands, this is as far as 186 * we go... 187 */ 188 if (noExecute) { 189 return (0); 190 } 191 192 if (*cp != '\0') { 193 /* 194 * If *cp isn't the null character, we hit a "meta" character and 195 * need to pass the command off to the shell. We give the shell the 196 * -e flag as well as -c if it's supposed to exit when it hits an 197 * error. 198 */ 199 static char *shargv[4] = { "/bin/sh" }; 200 201 shargv[1] = (errCheck ? "-ec" : "-c"); 202 shargv[2] = cmd; 203 shargv[3] = (char *)NULL; 204 av = shargv; 205 argc = 0; 206 } else { 207 /* 208 * No meta-characters, so no need to exec a shell. Break the command 209 * into words to form an argument vector we can execute. 210 * brk_string sticks our name in av[0], so we have to 211 * skip over it... 212 */ 213 av = brk_string(cmd, &argc); 214 av += 1; 215 } 216 217 local = TRUE; 218 219 /* 220 * Fork and execute the single command. If the fork fails, we abort. 221 */ 222 cpid = vfork(); 223 if (cpid < 0) { 224 Fatal("Could not fork"); 225 } 226 if (cpid == 0) { 227 if (local) { 228 execvp(av[0], av); 229 numWritten = write (2, av[0], strlen (av[0])); 230 numWritten = write (2, ": not found\n", sizeof(": not found")); 231 } else { 232 (void)execv(av[0], av); 233 } 234 exit(1); 235 } 236 237 /* 238 * The child is off and running. Now all we can do is wait... 239 */ 240 while (1) { 241 int id; 242 243 if (!local) { 244 id = 0; 245 } 246 247 while ((stat = wait((int *)&reason)) != cpid) { 248 if (stat == -1 && errno != EINTR) { 249 break; 250 } 251 } 252 253 if (stat > -1) { 254 if (WIFSTOPPED(reason)) { 255 status = reason.w_stopval; /* stopped */ 256 } else if (WIFEXITED(reason)) { 257 status = reason.w_retcode; /* exited */ 258 if (status != 0) { 259 printf ("*** Error code %d", status); 260 } 261 } else { 262 status = reason.w_termsig; /* signaled */ 263 printf ("*** Signal %d", status); 264 } 265 266 267 if (!WIFEXITED(reason) || (status != 0)) { 268 if (errCheck) { 269 gn->made = ERROR; 270 if (keepgoing) { 271 /* 272 * Abort the current target, but let others 273 * continue. 274 */ 275 printf (" (continuing)\n"); 276 } 277 } else { 278 /* 279 * Continue executing commands for this target. 280 * If we return 0, this will happen... 281 */ 282 printf (" (ignored)\n"); 283 status = 0; 284 } 285 } 286 break; 287 } else { 288 Fatal ("error in wait: %d", stat); 289 /*NOTREACHED*/ 290 } 291 } 292 293 return (status); 294 } 295 296 /*- 297 *----------------------------------------------------------------------- 298 * CompatMake -- 299 * Make a target. 300 * 301 * Results: 302 * 0 303 * 304 * Side Effects: 305 * If an error is detected and not being ignored, the process exits. 306 * 307 *----------------------------------------------------------------------- 308 */ 309 static int 310 CompatMake (gn, pgn) 311 GNode *gn; /* The node to make */ 312 GNode *pgn; /* Parent to abort if necessary */ 313 { 314 if (gn->type & OP_USE) { 315 Make_HandleUse(gn, pgn); 316 } else if (gn->made == UNMADE) { 317 /* 318 * First mark ourselves to be made, then apply whatever transformations 319 * the suffix module thinks are necessary. Once that's done, we can 320 * descend and make all our children. If any of them has an error 321 * but the -k flag was given, our 'make' field will be set FALSE again. 322 * This is our signal to not attempt to do anything but abort our 323 * parent as well. 324 */ 325 gn->make = TRUE; 326 gn->made = BEINGMADE; 327 Suff_FindDeps (gn); 328 Lst_ForEach (gn->children, CompatMake, (ClientData)gn); 329 if (!gn->make) { 330 gn->made = ABORTED; 331 pgn->make = FALSE; 332 return (0); 333 } 334 335 if (Lst_Member (gn->iParents, pgn) != NILLNODE) { 336 Var_Set (IMPSRC, Var_Value(TARGET, gn), pgn); 337 } 338 339 /* 340 * All the children were made ok. Now cmtime contains the modification 341 * time of the newest child, we need to find out if we exist and when 342 * we were modified last. The criteria for datedness are defined by the 343 * Make_OODate function. 344 */ 345 if (DEBUG(MAKE)) { 346 printf("Examining %s...", gn->name); 347 } 348 if (! Make_OODate(gn)) { 349 gn->made = UPTODATE; 350 if (DEBUG(MAKE)) { 351 printf("up-to-date.\n"); 352 } 353 return (0); 354 } else if (DEBUG(MAKE)) { 355 printf("out-of-date.\n"); 356 } 357 358 /* 359 * If the user is just seeing if something is out-of-date, exit now 360 * to tell him/her "yes". 361 */ 362 if (queryFlag) { 363 exit (-1); 364 } 365 366 /* 367 * We need to be re-made. We also have to make sure we've got a $? 368 * variable. To be nice, we also define the $> variable using 369 * Make_DoAllVar(). 370 */ 371 Make_DoAllVar(gn); 372 373 /* 374 * Alter our type to tell if errors should be ignored or things 375 * should not be printed so CompatRunCommand knows what to do. 376 */ 377 if (Targ_Ignore (gn)) { 378 gn->type |= OP_IGNORE; 379 } 380 if (Targ_Silent (gn)) { 381 gn->type |= OP_SILENT; 382 } 383 384 if (Job_CheckCommands (gn, Fatal)) { 385 /* 386 * Our commands are ok, but we still have to worry about the -t 387 * flag... 388 */ 389 if (!touchFlag) { 390 curTarg = gn; 391 Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn); 392 curTarg = NILGNODE; 393 } else { 394 Job_Touch (gn, gn->type & OP_SILENT); 395 } 396 } else { 397 gn->made = ERROR; 398 } 399 400 if (gn->made != ERROR) { 401 /* 402 * If the node was made successfully, mark it so, update 403 * its modification time and timestamp all its parents. Note 404 * that for .ZEROTIME targets, the timestamping isn't done. 405 * This is to keep its state from affecting that of its parent. 406 */ 407 gn->made = MADE; 408 #ifndef RECHECK 409 /* 410 * We can't re-stat the thing, but we can at least take care of 411 * rules where a target depends on a source that actually creates 412 * the target, but only if it has changed, e.g. 413 * 414 * parse.h : parse.o 415 * 416 * parse.o : parse.y 417 * yacc -d parse.y 418 * cc -c y.tab.c 419 * mv y.tab.o parse.o 420 * cmp -s y.tab.h parse.h || mv y.tab.h parse.h 421 * 422 * In this case, if the definitions produced by yacc haven't 423 * changed from before, parse.h won't have been updated and 424 * gn->mtime will reflect the current modification time for 425 * parse.h. This is something of a kludge, I admit, but it's a 426 * useful one.. 427 * 428 * XXX: People like to use a rule like 429 * 430 * FRC: 431 * 432 * To force things that depend on FRC to be made, so we have to 433 * check for gn->children being empty as well... 434 */ 435 if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) { 436 gn->mtime = now; 437 } 438 #else 439 /* 440 * This is what Make does and it's actually a good thing, as it 441 * allows rules like 442 * 443 * cmp -s y.tab.h parse.h || cp y.tab.h parse.h 444 * 445 * to function as intended. Unfortunately, thanks to the stateless 446 * nature of NFS (and the speed of this program), there are times 447 * when the modification time of a file created on a remote 448 * machine will not be modified before the stat() implied by 449 * the Dir_MTime occurs, thus leading us to believe that the file 450 * is unchanged, wreaking havoc with files that depend on this one. 451 * 452 * I have decided it is better to make too much than to make too 453 * little, so this stuff is commented out unless you're sure it's 454 * ok. 455 * -- ardeb 1/12/88 456 */ 457 if (noExecute || Dir_MTime(gn) == 0) { 458 gn->mtime = now; 459 } 460 if (DEBUG(MAKE)) { 461 printf("update time: %s\n", Targ_FmtTime(gn->mtime)); 462 } 463 #endif 464 if (!(gn->type & OP_EXEC)) { 465 pgn->childMade = TRUE; 466 Make_TimeStamp(pgn, gn); 467 } 468 } else if (keepgoing) { 469 pgn->make = FALSE; 470 } else { 471 printf ("\n\nStop.\n"); 472 exit (1); 473 } 474 } else if (gn->made == ERROR) { 475 /* 476 * Already had an error when making this beastie. Tell the parent 477 * to abort. 478 */ 479 pgn->make = FALSE; 480 } else { 481 if (Lst_Member (gn->iParents, pgn) != NILLNODE) { 482 Var_Set (IMPSRC, Var_Value(TARGET, gn), pgn); 483 } 484 switch(gn->made) { 485 case BEINGMADE: 486 Error("Graph cycles through %s\n", gn->name); 487 gn->made = ERROR; 488 pgn->make = FALSE; 489 break; 490 case MADE: 491 if ((gn->type & OP_EXEC) == 0) { 492 pgn->childMade = TRUE; 493 Make_TimeStamp(pgn, gn); 494 } 495 break; 496 case UPTODATE: 497 if ((gn->type & OP_EXEC) == 0) { 498 Make_TimeStamp(pgn, gn); 499 } 500 break; 501 } 502 } 503 504 return (0); 505 } 506 507 /*- 508 *----------------------------------------------------------------------- 509 * Compat_Run -- 510 * Initialize this mode and start making. 511 * 512 * Results: 513 * None. 514 * 515 * Side Effects: 516 * Guess what? 517 * 518 *----------------------------------------------------------------------- 519 */ 520 void 521 Compat_Run(targs) 522 Lst targs; /* List of target nodes to re-create */ 523 { 524 char *cp; /* Pointer to string of shell meta-characters */ 525 GNode *gn; /* Current root target */ 526 int errors; /* Number of targets not remade due to errors */ 527 528 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 529 signal(SIGINT, CompatInterrupt); 530 } 531 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 532 signal(SIGTERM, CompatInterrupt); 533 } 534 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 535 signal(SIGHUP, CompatInterrupt); 536 } 537 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 538 signal(SIGQUIT, CompatInterrupt); 539 } 540 541 for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) { 542 meta[*cp] = 1; 543 } 544 /* 545 * The null character serves as a sentinel in the string. 546 */ 547 meta[0] = 1; 548 549 ENDNode = Targ_FindNode(".END", TARG_CREATE); 550 /* 551 * If the user has defined a .BEGIN target, execute the commands attached 552 * to it. 553 */ 554 if (!queryFlag) { 555 gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); 556 if (gn != NILGNODE) { 557 Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); 558 } 559 } 560 561 /* 562 * For each entry in the list of targets to create, call CompatMake on 563 * it to create the thing. CompatMake will leave the 'made' field of gn 564 * in one of several states: 565 * UPTODATE gn was already up-to-date 566 * MADE gn was recreated successfully 567 * ERROR An error occurred while gn was being created 568 * ABORTED gn was not remade because one of its inferiors 569 * could not be made due to errors. 570 */ 571 errors = 0; 572 while (!Lst_IsEmpty (targs)) { 573 gn = (GNode *) Lst_DeQueue (targs); 574 CompatMake (gn, gn); 575 576 if (gn->made == UPTODATE) { 577 printf ("`%s' is up to date.\n", gn->name); 578 } else if (gn->made == ABORTED) { 579 printf ("`%s' not remade because of errors.\n", gn->name); 580 errors += 1; 581 } 582 } 583 584 /* 585 * If the user has defined a .END target, run its commands. 586 */ 587 if (errors == 0) { 588 Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn); 589 } 590 } 591