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