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