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