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