Changeset 51 in kBuild for trunk/src/kmk/compat.c
- Timestamp:
- Apr 7, 2003 1:30:32 AM (22 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/compat.c
r35 r51 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * 21 * 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)compat.c 41 static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/compat.c,v 1.16.2.2 2000/07/01 12:24:21 ps Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * compat.c -- 50 * 51 * 52 * 53 * 54 * 51 * The routines in this file implement the full-compatibility 52 * mode of PMake. Most of the special functionality of PMake 53 * is available in this mode. Things not supported: 54 * - different shells. 55 * - friendly variable substitution. 55 56 * 56 57 * Interface: 57 * Compat_RunInitialize things for this module and recreate58 * 58 * Compat_Run Initialize things for this module and recreate 59 * thems as need creatin' 59 60 */ 60 61 … … 87 88 */ 88 89 89 static char 90 91 static GNode 92 static GNode 90 static char meta[256]; 91 92 static GNode *curTarg = NILGNODE; 93 static GNode *ENDNode; 93 94 static void CompatInterrupt __P((int)); 94 95 static int CompatRunCommand __P((ClientData, ClientData)); … … 96 97 97 98 static char *sh_builtin[] = { 98 99 99 "alias", "cd", "eval", "exec", "exit", "read", "set", "ulimit", 100 "unalias", "umask", "unset", "wait", ":", 0}; 100 101 101 102 /*- 102 103 *----------------------------------------------------------------------- 103 104 * CompatInterrupt -- 104 * 105 * 105 * Interrupt the creation of the current target and remove it if 106 * it ain't precious. 106 107 * 107 108 * Results: 108 * 109 * None. 109 110 * 110 111 * Side Effects: 111 * 112 * 112 * The target is removed and the process exits. If .INTERRUPT exists, 113 * its commands are run first WITH INTERRUPTS IGNORED.. 113 114 * 114 115 *----------------------------------------------------------------------- … … 116 117 static void 117 118 CompatInterrupt (signo) 118 int 119 int signo; 119 120 { 120 121 GNode *gn; 121 122 122 123 if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) { 123 char*p1;124 char*file = Var_Value (TARGET, curTarg, &p1);125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 124 char *p1; 125 char *file = Var_Value (TARGET, curTarg, &p1); 126 127 if (!noExecute && eunlink(file) != -1) { 128 printf ("*** %s removed\n", file); 129 } 130 efree(p1); 131 132 /* 133 * Run .INTERRUPT only if hit with interrupt signal 134 */ 135 if (signo == SIGINT) { 136 gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 137 if (gn != NILGNODE) { 138 Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); 139 } 140 } 140 141 141 142 } 142 143 #if !(defined(OS2) && defined(__IBMC__)) 143 144 if (signo == SIGQUIT) 144 145 exit(signo); 145 146 #endif 146 147 (void) signal(signo, SIG_DFL); … … 152 153 *----------------------------------------------------------------------- 153 154 * shellneed -- 154 * 155 * 155 156 * Results: 156 * 157 * 157 * Returns 1 if a specified line must be executed by the shell, 158 * 0 if it can be run via execve, and -1 if the command is a no-op. 158 159 * 159 160 * Side Effects: 160 * 161 * 161 * None. 162 * 162 163 *----------------------------------------------------------------------- 163 164 */ 164 165 static int 165 166 shellneed (cmd) 166 167 char *cmd; 167 168 { 168 169 170 171 172 173 174 175 169 char **av, **p; 170 int ac; 171 172 av = brk_string(cmd, &ac, TRUE); 173 for(p = sh_builtin; *p != 0; p++) 174 if (strcmp(av[1], *p) == 0) 175 return (1); 176 return (0); 176 177 } 177 178 … … 180 181 *----------------------------------------------------------------------- 181 182 * CompatRunCommand -- 182 * 183 * 183 * Execute the next command for a target. If the command returns an 184 * error, the node's made field is set to ERROR and creation stops. 184 185 * 185 186 * Results: 186 * 187 * 0 if the command succeeded, 1 if an error occurred. 187 188 * 188 189 * Side Effects: 189 * 190 * The node's 'made' field may be set to ERROR. 190 191 * 191 192 *----------------------------------------------------------------------- … … 193 194 static int 194 195 CompatRunCommand (cmdp, gnp) 195 ClientData cmdp; 196 ClientData gnp; 196 ClientData cmdp; /* Command to execute */ 197 ClientData gnp; /* Node from which the command came */ 197 198 { 198 char *cmdStart;/* Start of expanded command */199 char *cmdStart; /* Start of expanded command */ 199 200 register char *cp; 200 Boolean silent,/* Don't print command */201 errCheck;/* Check errors */202 int reason;/* Reason for child's death */203 int status;/* Description of child's death */204 int cpid;/* Child actually found */205 ReturnStatus stat; 206 LstNode cmdNode;/* Node where current command is located */207 char **av;/* Argument vector for thing to exec */208 int argc;/* Number of arguments in av or 0 if not209 210 Boolean local;/* TRUE if command should be executed211 212 int internal;/* Various values.. */213 char 214 GNode 201 Boolean silent, /* Don't print command */ 202 errCheck; /* Check errors */ 203 int reason; /* Reason for child's death */ 204 int status; /* Description of child's death */ 205 int cpid; /* Child actually found */ 206 ReturnStatus stat; /* Status of fork */ 207 LstNode cmdNode; /* Node where current command is located */ 208 char **av; /* Argument vector for thing to exec */ 209 int argc; /* Number of arguments in av or 0 if not 210 * dynamically allocated */ 211 Boolean local; /* TRUE if command should be executed 212 * locally */ 213 int internal; /* Various values.. */ 214 char *cmd = (char *) cmdp; 215 GNode *gn = (GNode *) gnp; 215 216 216 217 /* … … 236 237 237 238 if (*cmdStart == '\0') { 238 239 240 239 efree(cmdStart); 240 Error("%s expands to empty string", cmd); 241 return(0); 241 242 } else { 242 243 cmd = cmdStart; 243 244 } 244 245 Lst_Replace (cmdNode, (ClientData)cmdStart); 245 246 246 247 if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { 247 248 248 (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart); 249 return(0); 249 250 } else if (strcmp(cmdStart, "...") == 0) { 250 251 251 gn->type |= OP_SAVE_CMDS; 252 return(0); 252 253 } 253 254 254 255 while ((*cmd == '@') || (*cmd == '-')) { 255 256 257 258 259 260 256 if (*cmd == '@') { 257 silent = DEBUG(LOUD) ? FALSE : TRUE; 258 } else { 259 errCheck = FALSE; 260 } 261 cmd++; 261 262 } 262 263 263 264 while (isspace((unsigned char)*cmd)) 264 265 cmd++; 265 266 266 267 /* … … 270 271 */ 271 272 for (cp = cmd; !meta[(unsigned char)*cp]; cp++) { 272 273 continue; 273 274 } 274 275 … … 278 279 */ 279 280 if (!silent || noExecute) { 280 281 281 printf ("%s\n", cmd); 282 fflush(stdout); 282 283 } 283 284 … … 287 288 */ 288 289 if (noExecute) { 289 290 return (0); 290 291 } 291 292 292 293 if (*cp != '\0') { 293 294 295 296 297 298 299 static char*shargv[4] = { "/bin/sh" };300 301 302 303 304 305 294 /* 295 * If *cp isn't the null character, we hit a "meta" character and 296 * need to pass the command off to the shell. We give the shell the 297 * -e flag as well as -c if it's supposed to exit when it hits an 298 * error. 299 */ 300 static char *shargv[4] = { "/bin/sh" }; 301 302 shargv[1] = (errCheck ? "-ec" : "-c"); 303 shargv[2] = cmd; 304 shargv[3] = (char *)NULL; 305 av = shargv; 306 argc = 0; 306 307 } else if ((internal = shellneed(cmd))) { 307 308 309 310 311 static char*shargv[4] = { "/bin/sh" };312 313 314 315 316 317 318 319 320 321 322 308 /* 309 * This command must be passed by the shell for other reasons.. 310 * or.. possibly not at all. 311 */ 312 static char *shargv[4] = { "/bin/sh" }; 313 314 if (internal == -1) { 315 /* Command does not need to be executed */ 316 return (0); 317 } 318 319 shargv[1] = (errCheck ? "-ec" : "-c"); 320 shargv[2] = cmd; 321 shargv[3] = (char *)NULL; 322 av = shargv; 323 argc = 0; 323 324 } else { 324 325 326 327 328 329 330 331 325 /* 326 * No meta-characters, so no need to exec a shell. Break the command 327 * into words to form an argument vector we can execute. 328 * brk_string sticks our name in av[0], so we have to 329 * skip over it... 330 */ 331 av = brk_string(cmd, &argc, TRUE); 332 av += 1; 332 333 } 333 334 … … 342 343 cpid = vfork(); 343 344 if (cpid < 0) { 344 345 Fatal("Could not fork"); 345 346 } 346 347 if (cpid == 0) { 347 348 349 350 351 352 353 354 355 356 348 if (local) { 349 execvp(av[0], av); 350 (void) write (2, av[0], strlen (av[0])); 351 (void) write (2, ":", 1); 352 (void) write (2, strerror(errno), strlen(strerror(errno))); 353 (void) write (2, "\n", 1); 354 } else { 355 (void)execv(av[0], av); 356 } 357 exit(1); 357 358 } 358 359 #endif … … 365 366 */ 366 367 if (!DEBUG(GRAPH2)) { 367 368 368 efree(cmdStart); 369 Lst_Replace (cmdNode, cmdp); 369 370 } 370 371 … … 374 375 while (1) { 375 376 376 377 378 379 380 381 382 383 384 status = WSTOPSIG(reason);/* stopped */385 386 status = WEXITSTATUS(reason);/* exited */387 388 389 390 391 status = WTERMSIG(reason);/* signaled */392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 377 while ((stat = wait(&reason)) != cpid) { 378 if (stat == -1 && errno != EINTR) { 379 break; 380 } 381 } 382 383 if (stat > -1) { 384 if (WIFSTOPPED(reason)) { 385 status = WSTOPSIG(reason); /* stopped */ 386 } else if (WIFEXITED(reason)) { 387 status = WEXITSTATUS(reason); /* exited */ 388 if (status != 0) { 389 printf ("*** Error code %d", status); 390 } 391 } else { 392 status = WTERMSIG(reason); /* signaled */ 393 printf ("*** Signal %d", status); 394 } 395 396 397 if (!WIFEXITED(reason) || (status != 0)) { 398 if (errCheck) { 399 gn->made = ERROR; 400 if (keepgoing) { 401 /* 402 * Abort the current target, but let others 403 * continue. 404 */ 405 printf (" (continuing)\n"); 406 } 407 } else { 408 /* 409 * Continue executing commands for this target. 410 * If we return 0, this will happen... 411 */ 412 printf (" (ignored)\n"); 413 status = 0; 414 } 415 } 416 break; 417 } else { 418 Fatal ("error in wait: %d", stat); 419 /*NOTREACHED*/ 420 } 420 421 } 421 422 … … 427 428 *----------------------------------------------------------------------- 428 429 * CompatMake -- 429 * 430 * Make a target. 430 431 * 431 432 * Results: 432 * 433 * 0 433 434 * 434 435 * Side Effects: 435 * 436 * If an error is detected and not being ignored, the process exits. 436 437 * 437 438 *----------------------------------------------------------------------- … … 439 440 static int 440 441 CompatMake (gnp, pgnp) 441 ClientData gnp;/* The node to make */442 ClientData pgnp; 442 ClientData gnp; /* The node to make */ 443 ClientData pgnp; /* Parent to abort if necessary */ 443 444 { 444 445 GNode *gn = (GNode *) gnp; 445 446 GNode *pgn = (GNode *) pgnp; 446 447 if (gn->type & OP_USE) { 447 448 Make_HandleUse(gn, pgn); 448 449 } else if (gn->made == UNMADE) { 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 450 /* 451 * First mark ourselves to be made, then apply whatever transformations 452 * the suffix module thinks are necessary. Once that's done, we can 453 * descend and make all our children. If any of them has an error 454 * but the -k flag was given, our 'make' field will be set FALSE again. 455 * This is our signal to not attempt to do anything but abort our 456 * parent as well. 457 */ 458 gn->make = TRUE; 459 gn->made = BEINGMADE; 460 Suff_FindDeps (gn); 461 Lst_ForEach (gn->children, CompatMake, (ClientData)gn); 462 if (!gn->make) { 463 gn->made = ABORTED; 464 pgn->make = FALSE; 465 return (0); 466 } 467 468 if (Lst_Member (gn->iParents, pgn) != NILLNODE) { 469 char *p1; 470 Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn); 471 efree(p1); 472 } 473 474 /* 475 * All the children were made ok. Now cmtime contains the modification 476 * time of the newest child, we need to find out if we exist and when 477 * we were modified last. The criteria for datedness are defined by the 478 * Make_OODate function. 479 */ 480 if (DEBUG(MAKE)) { 481 printf("Examining %s...", gn->name); 482 } 483 if (! Make_OODate(gn)) { 484 gn->made = UPTODATE; 485 if (DEBUG(MAKE)) { 486 printf("up-to-date.\n"); 487 } 488 return (0); 489 } else if (DEBUG(MAKE)) { 490 printf("out-of-date.\n"); 491 } 492 493 /* 494 * If the user is just seeing if something is out-of-date, exit now 495 * to tell him/her "yes". 496 */ 497 if (queryFlag) { 498 exit (-1); 499 } 500 501 /* 502 * We need to be re-made. We also have to make sure we've got a $? 503 * variable. To be nice, we also define the $> variable using 504 * Make_DoAllVar(). 505 */ 506 Make_DoAllVar(gn); 507 508 /* 509 * Alter our type to tell if errors should be ignored or things 510 * should not be printed so CompatRunCommand knows what to do. 511 */ 512 if (Targ_Ignore (gn)) { 513 gn->type |= OP_IGNORE; 514 } 515 if (Targ_Silent (gn)) { 516 gn->type |= OP_SILENT; 517 } 518 519 if (Job_CheckCommands (gn, Fatal)) { 520 /* 521 * Our commands are ok, but we still have to worry about the -t 522 * flag... 523 */ 524 if (!touchFlag) { 525 curTarg = gn; 526 Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn); 527 curTarg = NILGNODE; 528 } else { 529 Job_Touch (gn, gn->type & OP_SILENT); 530 } 531 } else { 532 gn->made = ERROR; 533 } 534 535 if (gn->made != ERROR) { 536 /* 537 * If the node was made successfully, mark it so, update 538 * its modification time and timestamp all its parents. Note 539 * that for .ZEROTIME targets, the timestamping isn't done. 540 * This is to keep its state from affecting that of its parent. 541 */ 542 gn->made = MADE; 542 543 #ifndef RECHECK 543 544 545 546 547 548 549 550 551 *yacc -d parse.y552 *cc -c y.tab.c553 *mv y.tab.o parse.o554 *cmp -s y.tab.h parse.h || mv y.tab.h parse.h555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 544 /* 545 * We can't re-stat the thing, but we can at least take care of 546 * rules where a target depends on a source that actually creates 547 * the target, but only if it has changed, e.g. 548 * 549 * parse.h : parse.o 550 * 551 * parse.o : parse.y 552 * yacc -d parse.y 553 * cc -c y.tab.c 554 * mv y.tab.o parse.o 555 * cmp -s y.tab.h parse.h || mv y.tab.h parse.h 556 * 557 * In this case, if the definitions produced by yacc haven't 558 * changed from before, parse.h won't have been updated and 559 * gn->mtime will reflect the current modification time for 560 * parse.h. This is something of a kludge, I admit, but it's a 561 * useful one.. 562 * 563 * XXX: People like to use a rule like 564 * 565 * FRC: 566 * 567 * To force things that depend on FRC to be made, so we have to 568 * check for gn->children being empty as well... 569 */ 570 if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) { 571 gn->mtime = now; 572 } 572 573 #else 573 574 575 576 577 *cmp -s y.tab.h parse.h || cp y.tab.h parse.h578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 574 /* 575 * This is what Make does and it's actually a good thing, as it 576 * allows rules like 577 * 578 * cmp -s y.tab.h parse.h || cp y.tab.h parse.h 579 * 580 * to function as intended. Unfortunately, thanks to the stateless 581 * nature of NFS (and the speed of this program), there are times 582 * when the modification time of a file created on a remote 583 * machine will not be modified before the stat() implied by 584 * the Dir_MTime occurs, thus leading us to believe that the file 585 * is unchanged, wreaking havoc with files that depend on this one. 586 * 587 * I have decided it is better to make too much than to make too 588 * little, so this stuff is commented out unless you're sure it's 589 * ok. 590 * -- ardeb 1/12/88 591 */ 592 if (noExecute || Dir_MTime(gn) == 0) { 593 gn->mtime = now; 594 } 595 if (gn->cmtime > gn->mtime) 596 gn->mtime = gn->cmtime; 597 if (DEBUG(MAKE)) { 598 printf("update time: %s\n", Targ_FmtTime(gn->mtime)); 599 } 599 600 #endif 600 601 602 603 604 605 606 607 608 609 610 611 612 601 if (!(gn->type & OP_EXEC)) { 602 pgn->childMade = TRUE; 603 Make_TimeStamp(pgn, gn); 604 } 605 } else if (keepgoing) { 606 pgn->make = FALSE; 607 } else { 608 char *p1; 609 610 printf ("\n\nStop in %s.\n", Var_Value(".CURDIR", gn, &p1)); 611 efree(p1); 612 exit (1); 613 } 613 614 } else if (gn->made == ERROR) { 614 615 616 617 618 615 /* 616 * Already had an error when making this beastie. Tell the parent 617 * to abort. 618 */ 619 pgn->make = FALSE; 619 620 } else { 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 621 if (Lst_Member (gn->iParents, pgn) != NILLNODE) { 622 char *p1; 623 Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn); 624 efree(p1); 625 } 626 switch(gn->made) { 627 case BEINGMADE: 628 Error("Graph cycles through %s\n", gn->name); 629 gn->made = ERROR; 630 pgn->make = FALSE; 631 break; 632 case MADE: 633 if ((gn->type & OP_EXEC) == 0) { 634 pgn->childMade = TRUE; 635 Make_TimeStamp(pgn, gn); 636 } 637 break; 638 case UPTODATE: 639 if ((gn->type & OP_EXEC) == 0) { 640 Make_TimeStamp(pgn, gn); 641 } 642 break; 643 default: 644 break; 645 } 645 646 } 646 647 … … 652 653 *----------------------------------------------------------------------- 653 654 * Compat_Run -- 654 * 655 * Initialize this mode and start making. 655 656 * 656 657 * Results: 657 * 658 * None. 658 659 * 659 660 * Side Effects: 660 * 661 * Guess what? 661 662 * 662 663 *----------------------------------------------------------------------- … … 664 665 void 665 666 Compat_Run(targs) 666 Lst 667 Lst targs; /* List of target nodes to re-create */ 667 668 { 668 char *cp;/* Pointer to string of shell meta-characters */669 GNode 670 int 669 char *cp; /* Pointer to string of shell meta-characters */ 670 GNode *gn = NULL;/* Current root target */ 671 int errors; /* Number of targets not remade due to errors */ 671 672 672 673 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 673 674 signal(SIGINT, CompatInterrupt); 674 675 } 675 676 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 676 677 signal(SIGTERM, CompatInterrupt); 677 678 } 678 679 #if !(defined(OS2) && defined(__IBMC__)) 679 680 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 680 681 signal(SIGHUP, CompatInterrupt); 681 682 } 682 683 #endif 683 684 #if !(defined(OS2) && defined(__IBMC__)) 684 685 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 685 686 signal(SIGQUIT, CompatInterrupt); 686 687 } 687 688 #endif 688 689 689 690 for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) { 690 691 meta[(unsigned char) *cp] = 1; 691 692 } 692 693 /* … … 701 702 */ 702 703 if (!queryFlag) { 703 704 705 704 gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); 705 if (gn != NILGNODE) { 706 Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); 706 707 if (gn->made == ERROR) { 707 708 printf("\n\nStop.\n"); 708 709 exit(1); 709 710 } 710 711 } 711 712 } 712 713 … … 715 716 * it to create the thing. CompatMake will leave the 'made' field of gn 716 717 * in one of several states: 717 * UPTODATEgn was already up-to-date718 * MADEgn was recreated successfully719 * ERRORAn error occurred while gn was being created720 * ABORTEDgn was not remade because one of its inferiors721 * 718 * UPTODATE gn was already up-to-date 719 * MADE gn was recreated successfully 720 * ERROR An error occurred while gn was being created 721 * ABORTED gn was not remade because one of its inferiors 722 * could not be made due to errors. 722 723 */ 723 724 errors = 0; 724 725 while (!Lst_IsEmpty (targs)) { 725 726 727 728 729 730 731 732 733 726 gn = (GNode *) Lst_DeQueue (targs); 727 CompatMake (gn, gn); 728 729 if (gn->made == UPTODATE) { 730 printf ("`%s' is up to date.\n", gn->name); 731 } else if (gn->made == ABORTED) { 732 printf ("`%s' not remade because of errors.\n", gn->name); 733 errors += 1; 734 } 734 735 } 735 736 … … 738 739 */ 739 740 if (errors == 0) { 740 741 Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn); 741 742 } 742 743 }
Note:
See TracChangeset
for help on using the changeset viewer.