compat.c revision 236769
1236769Sobrien/* $NetBSD: compat.c,v 1.88 2012/06/05 17:31:04 sjg Exp $ */ 2236769Sobrien 3236769Sobrien/* 4236769Sobrien * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 5236769Sobrien * All rights reserved. 6236769Sobrien * 7236769Sobrien * This code is derived from software contributed to Berkeley by 8236769Sobrien * Adam de Boor. 9236769Sobrien * 10236769Sobrien * Redistribution and use in source and binary forms, with or without 11236769Sobrien * modification, are permitted provided that the following conditions 12236769Sobrien * are met: 13236769Sobrien * 1. Redistributions of source code must retain the above copyright 14236769Sobrien * notice, this list of conditions and the following disclaimer. 15236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 16236769Sobrien * notice, this list of conditions and the following disclaimer in the 17236769Sobrien * documentation and/or other materials provided with the distribution. 18236769Sobrien * 3. Neither the name of the University nor the names of its contributors 19236769Sobrien * may be used to endorse or promote products derived from this software 20236769Sobrien * without specific prior written permission. 21236769Sobrien * 22236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32236769Sobrien * SUCH DAMAGE. 33236769Sobrien */ 34236769Sobrien 35236769Sobrien/* 36236769Sobrien * Copyright (c) 1988, 1989 by Adam de Boor 37236769Sobrien * Copyright (c) 1989 by Berkeley Softworks 38236769Sobrien * All rights reserved. 39236769Sobrien * 40236769Sobrien * This code is derived from software contributed to Berkeley by 41236769Sobrien * Adam de Boor. 42236769Sobrien * 43236769Sobrien * Redistribution and use in source and binary forms, with or without 44236769Sobrien * modification, are permitted provided that the following conditions 45236769Sobrien * are met: 46236769Sobrien * 1. Redistributions of source code must retain the above copyright 47236769Sobrien * notice, this list of conditions and the following disclaimer. 48236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 49236769Sobrien * notice, this list of conditions and the following disclaimer in the 50236769Sobrien * documentation and/or other materials provided with the distribution. 51236769Sobrien * 3. All advertising materials mentioning features or use of this software 52236769Sobrien * must display the following acknowledgement: 53236769Sobrien * This product includes software developed by the University of 54236769Sobrien * California, Berkeley and its contributors. 55236769Sobrien * 4. Neither the name of the University nor the names of its contributors 56236769Sobrien * may be used to endorse or promote products derived from this software 57236769Sobrien * without specific prior written permission. 58236769Sobrien * 59236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69236769Sobrien * SUCH DAMAGE. 70236769Sobrien */ 71236769Sobrien 72236769Sobrien#ifndef MAKE_NATIVE 73236769Sobrienstatic char rcsid[] = "$NetBSD: compat.c,v 1.88 2012/06/05 17:31:04 sjg Exp $"; 74236769Sobrien#else 75236769Sobrien#include <sys/cdefs.h> 76236769Sobrien#ifndef lint 77236769Sobrien#if 0 78236769Sobrienstatic char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; 79236769Sobrien#else 80236769Sobrien__RCSID("$NetBSD: compat.c,v 1.88 2012/06/05 17:31:04 sjg Exp $"); 81236769Sobrien#endif 82236769Sobrien#endif /* not lint */ 83236769Sobrien#endif 84236769Sobrien 85236769Sobrien/*- 86236769Sobrien * compat.c -- 87236769Sobrien * The routines in this file implement the full-compatibility 88236769Sobrien * mode of PMake. Most of the special functionality of PMake 89236769Sobrien * is available in this mode. Things not supported: 90236769Sobrien * - different shells. 91236769Sobrien * - friendly variable substitution. 92236769Sobrien * 93236769Sobrien * Interface: 94236769Sobrien * Compat_Run Initialize things for this module and recreate 95236769Sobrien * thems as need creatin' 96236769Sobrien */ 97236769Sobrien 98236769Sobrien#ifdef HAVE_CONFIG_H 99236769Sobrien# include "config.h" 100236769Sobrien#endif 101236769Sobrien#include <sys/types.h> 102236769Sobrien#include <sys/stat.h> 103236769Sobrien#include "wait.h" 104236769Sobrien 105236769Sobrien#include <ctype.h> 106236769Sobrien#include <errno.h> 107236769Sobrien#include <signal.h> 108236769Sobrien#include <stdio.h> 109236769Sobrien 110236769Sobrien#include "make.h" 111236769Sobrien#include "hash.h" 112236769Sobrien#include "dir.h" 113236769Sobrien#include "job.h" 114236769Sobrien#include "pathnames.h" 115236769Sobrien 116236769Sobrien/* 117236769Sobrien * The following array is used to make a fast determination of which 118236769Sobrien * characters are interpreted specially by the shell. If a command 119236769Sobrien * contains any of these characters, it is executed by the shell, not 120236769Sobrien * directly by us. 121236769Sobrien */ 122236769Sobrien 123236769Sobrienstatic char meta[256]; 124236769Sobrien 125236769Sobrienstatic GNode *curTarg = NULL; 126236769Sobrienstatic GNode *ENDNode; 127236769Sobrienstatic void CompatInterrupt(int) __dead; 128236769Sobrien 129236769Sobrienstatic void 130236769SobrienCompat_Init(void) 131236769Sobrien{ 132236769Sobrien const char *cp; 133236769Sobrien 134236769Sobrien Shell_Init(); /* setup default shell */ 135236769Sobrien 136236769Sobrien for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) { 137236769Sobrien meta[(unsigned char) *cp] = 1; 138236769Sobrien } 139236769Sobrien /* 140236769Sobrien * The null character serves as a sentinel in the string. 141236769Sobrien */ 142236769Sobrien meta[0] = 1; 143236769Sobrien} 144236769Sobrien 145236769Sobrien/*- 146236769Sobrien *----------------------------------------------------------------------- 147236769Sobrien * CompatInterrupt -- 148236769Sobrien * Interrupt the creation of the current target and remove it if 149236769Sobrien * it ain't precious. 150236769Sobrien * 151236769Sobrien * Results: 152236769Sobrien * None. 153236769Sobrien * 154236769Sobrien * Side Effects: 155236769Sobrien * The target is removed and the process exits. If .INTERRUPT exists, 156236769Sobrien * its commands are run first WITH INTERRUPTS IGNORED.. 157236769Sobrien * 158236769Sobrien *----------------------------------------------------------------------- 159236769Sobrien */ 160236769Sobrienstatic void 161236769SobrienCompatInterrupt(int signo) 162236769Sobrien{ 163236769Sobrien GNode *gn; 164236769Sobrien 165236769Sobrien if ((curTarg != NULL) && !Targ_Precious (curTarg)) { 166236769Sobrien char *p1; 167236769Sobrien char *file = Var_Value(TARGET, curTarg, &p1); 168236769Sobrien 169236769Sobrien if (!noExecute && eunlink(file) != -1) { 170236769Sobrien Error("*** %s removed", file); 171236769Sobrien } 172236769Sobrien if (p1) 173236769Sobrien free(p1); 174236769Sobrien 175236769Sobrien /* 176236769Sobrien * Run .INTERRUPT only if hit with interrupt signal 177236769Sobrien */ 178236769Sobrien if (signo == SIGINT) { 179236769Sobrien gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 180236769Sobrien if (gn != NULL) { 181236769Sobrien Compat_Make(gn, gn); 182236769Sobrien } 183236769Sobrien } 184236769Sobrien 185236769Sobrien } 186236769Sobrien if (signo == SIGQUIT) 187236769Sobrien _exit(signo); 188236769Sobrien bmake_signal(signo, SIG_DFL); 189236769Sobrien kill(myPid, signo); 190236769Sobrien} 191236769Sobrien 192236769Sobrien/*- 193236769Sobrien *----------------------------------------------------------------------- 194236769Sobrien * CompatRunCommand -- 195236769Sobrien * Execute the next command for a target. If the command returns an 196236769Sobrien * error, the node's made field is set to ERROR and creation stops. 197236769Sobrien * 198236769Sobrien * Input: 199236769Sobrien * cmdp Command to execute 200236769Sobrien * gnp Node from which the command came 201236769Sobrien * 202236769Sobrien * Results: 203236769Sobrien * 0 if the command succeeded, 1 if an error occurred. 204236769Sobrien * 205236769Sobrien * Side Effects: 206236769Sobrien * The node's 'made' field may be set to ERROR. 207236769Sobrien * 208236769Sobrien *----------------------------------------------------------------------- 209236769Sobrien */ 210236769Sobrienint 211236769SobrienCompatRunCommand(void *cmdp, void *gnp) 212236769Sobrien{ 213236769Sobrien char *cmdStart; /* Start of expanded command */ 214236769Sobrien char *cp, *bp; 215236769Sobrien Boolean silent, /* Don't print command */ 216236769Sobrien doIt; /* Execute even if -n */ 217236769Sobrien volatile Boolean errCheck; /* Check errors */ 218236769Sobrien WAIT_T reason; /* Reason for child's death */ 219236769Sobrien int status; /* Description of child's death */ 220236769Sobrien pid_t cpid; /* Child actually found */ 221236769Sobrien pid_t retstat; /* Result of wait */ 222236769Sobrien LstNode cmdNode; /* Node where current command is located */ 223236769Sobrien const char ** volatile av; /* Argument vector for thing to exec */ 224236769Sobrien char ** volatile mav;/* Copy of the argument vector for freeing */ 225236769Sobrien int argc; /* Number of arguments in av or 0 if not 226236769Sobrien * dynamically allocated */ 227236769Sobrien Boolean local; /* TRUE if command should be executed 228236769Sobrien * locally */ 229236769Sobrien Boolean useShell; /* TRUE if command should be executed 230236769Sobrien * using a shell */ 231236769Sobrien char * volatile cmd = (char *)cmdp; 232236769Sobrien GNode *gn = (GNode *)gnp; 233236769Sobrien 234236769Sobrien silent = gn->type & OP_SILENT; 235236769Sobrien errCheck = !(gn->type & OP_IGNORE); 236236769Sobrien doIt = FALSE; 237236769Sobrien 238236769Sobrien cmdNode = Lst_Member(gn->commands, cmd); 239236769Sobrien cmdStart = Var_Subst(NULL, cmd, gn, FALSE); 240236769Sobrien 241236769Sobrien /* 242236769Sobrien * brk_string will return an argv with a NULL in av[0], thus causing 243236769Sobrien * execvp to choke and die horribly. Besides, how can we execute a null 244236769Sobrien * command? In any case, we warn the user that the command expanded to 245236769Sobrien * nothing (is this the right thing to do?). 246236769Sobrien */ 247236769Sobrien 248236769Sobrien if (*cmdStart == '\0') { 249236769Sobrien free(cmdStart); 250236769Sobrien Error("%s expands to empty string", cmd); 251236769Sobrien return(0); 252236769Sobrien } 253236769Sobrien cmd = cmdStart; 254236769Sobrien Lst_Replace(cmdNode, cmdStart); 255236769Sobrien 256236769Sobrien if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { 257236769Sobrien (void)Lst_AtEnd(ENDNode->commands, cmdStart); 258236769Sobrien return(0); 259236769Sobrien } 260236769Sobrien if (strcmp(cmdStart, "...") == 0) { 261236769Sobrien gn->type |= OP_SAVE_CMDS; 262236769Sobrien return(0); 263236769Sobrien } 264236769Sobrien 265236769Sobrien while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { 266236769Sobrien switch (*cmd) { 267236769Sobrien case '@': 268236769Sobrien silent = DEBUG(LOUD) ? FALSE : TRUE; 269236769Sobrien break; 270236769Sobrien case '-': 271236769Sobrien errCheck = FALSE; 272236769Sobrien break; 273236769Sobrien case '+': 274236769Sobrien doIt = TRUE; 275236769Sobrien if (!meta[0]) /* we came here from jobs */ 276236769Sobrien Compat_Init(); 277236769Sobrien break; 278236769Sobrien } 279236769Sobrien cmd++; 280236769Sobrien } 281236769Sobrien 282236769Sobrien while (isspace((unsigned char)*cmd)) 283236769Sobrien cmd++; 284236769Sobrien 285236769Sobrien /* 286236769Sobrien * If we did not end up with a command, just skip it. 287236769Sobrien */ 288236769Sobrien if (!*cmd) 289236769Sobrien return (0); 290236769Sobrien 291236769Sobrien#if !defined(MAKE_NATIVE) 292236769Sobrien /* 293236769Sobrien * In a non-native build, the host environment might be weird enough 294236769Sobrien * that it's necessary to go through a shell to get the correct 295236769Sobrien * behaviour. Or perhaps the shell has been replaced with something 296236769Sobrien * that does extra logging, and that should not be bypassed. 297236769Sobrien */ 298236769Sobrien useShell = TRUE; 299236769Sobrien#else 300236769Sobrien /* 301236769Sobrien * Search for meta characters in the command. If there are no meta 302236769Sobrien * characters, there's no need to execute a shell to execute the 303236769Sobrien * command. 304236769Sobrien */ 305236769Sobrien for (cp = cmd; !meta[(unsigned char)*cp]; cp++) { 306236769Sobrien continue; 307236769Sobrien } 308236769Sobrien useShell = (*cp != '\0'); 309236769Sobrien#endif 310236769Sobrien 311236769Sobrien /* 312236769Sobrien * Print the command before echoing if we're not supposed to be quiet for 313236769Sobrien * this one. We also print the command if -n given. 314236769Sobrien */ 315236769Sobrien if (!silent || NoExecute(gn)) { 316236769Sobrien printf("%s\n", cmd); 317236769Sobrien fflush(stdout); 318236769Sobrien } 319236769Sobrien 320236769Sobrien /* 321236769Sobrien * If we're not supposed to execute any commands, this is as far as 322236769Sobrien * we go... 323236769Sobrien */ 324236769Sobrien if (!doIt && NoExecute(gn)) { 325236769Sobrien return (0); 326236769Sobrien } 327236769Sobrien if (DEBUG(JOB)) 328236769Sobrien fprintf(debug_file, "Execute: '%s'\n", cmd); 329236769Sobrien 330236769Sobrienagain: 331236769Sobrien if (useShell) { 332236769Sobrien /* 333236769Sobrien * We need to pass the command off to the shell, typically 334236769Sobrien * because the command contains a "meta" character. 335236769Sobrien */ 336236769Sobrien static const char *shargv[4]; 337236769Sobrien 338236769Sobrien shargv[0] = shellPath; 339236769Sobrien /* 340236769Sobrien * The following work for any of the builtin shell specs. 341236769Sobrien */ 342236769Sobrien if (DEBUG(SHELL)) 343236769Sobrien shargv[1] = "-xc"; 344236769Sobrien else 345236769Sobrien shargv[1] = "-c"; 346236769Sobrien shargv[2] = cmd; 347236769Sobrien shargv[3] = NULL; 348236769Sobrien av = shargv; 349236769Sobrien argc = 0; 350236769Sobrien bp = NULL; 351236769Sobrien mav = NULL; 352236769Sobrien } else { 353236769Sobrien /* 354236769Sobrien * No meta-characters, so no need to exec a shell. Break the command 355236769Sobrien * into words to form an argument vector we can execute. 356236769Sobrien */ 357236769Sobrien mav = brk_string(cmd, &argc, TRUE, &bp); 358236769Sobrien if (mav == NULL) { 359236769Sobrien useShell = 1; 360236769Sobrien goto again; 361236769Sobrien } 362236769Sobrien av = (void *)mav; 363236769Sobrien } 364236769Sobrien 365236769Sobrien local = TRUE; 366236769Sobrien 367236769Sobrien#ifdef USE_META 368236769Sobrien if (useMeta) { 369236769Sobrien meta_compat_start(); 370236769Sobrien } 371236769Sobrien#endif 372236769Sobrien 373236769Sobrien /* 374236769Sobrien * Fork and execute the single command. If the fork fails, we abort. 375236769Sobrien */ 376236769Sobrien cpid = vFork(); 377236769Sobrien if (cpid < 0) { 378236769Sobrien Fatal("Could not fork"); 379236769Sobrien } 380236769Sobrien if (cpid == 0) { 381236769Sobrien Check_Cwd(av); 382236769Sobrien Var_ExportVars(); 383236769Sobrien#ifdef USE_META 384236769Sobrien if (useMeta) { 385236769Sobrien meta_compat_child(); 386236769Sobrien } 387236769Sobrien#endif 388236769Sobrien if (local) 389236769Sobrien (void)execvp(av[0], (char *const *)UNCONST(av)); 390236769Sobrien else 391236769Sobrien (void)execv(av[0], (char *const *)UNCONST(av)); 392236769Sobrien execError("exec", av[0]); 393236769Sobrien _exit(1); 394236769Sobrien } 395236769Sobrien if (mav) 396236769Sobrien free(mav); 397236769Sobrien if (bp) 398236769Sobrien free(bp); 399236769Sobrien Lst_Replace(cmdNode, NULL); 400236769Sobrien 401236769Sobrien#ifdef USE_META 402236769Sobrien if (useMeta) { 403236769Sobrien meta_compat_parent(); 404236769Sobrien } 405236769Sobrien#endif 406236769Sobrien 407236769Sobrien /* 408236769Sobrien * The child is off and running. Now all we can do is wait... 409236769Sobrien */ 410236769Sobrien while (1) { 411236769Sobrien 412236769Sobrien while ((retstat = wait(&reason)) != cpid) { 413236769Sobrien if (retstat > 0) 414236769Sobrien JobReapChild(retstat, reason, FALSE); /* not ours? */ 415236769Sobrien if (retstat == -1 && errno != EINTR) { 416236769Sobrien break; 417236769Sobrien } 418236769Sobrien } 419236769Sobrien 420236769Sobrien if (retstat > -1) { 421236769Sobrien if (WIFSTOPPED(reason)) { 422236769Sobrien status = WSTOPSIG(reason); /* stopped */ 423236769Sobrien } else if (WIFEXITED(reason)) { 424236769Sobrien status = WEXITSTATUS(reason); /* exited */ 425236769Sobrien#if defined(USE_META) && defined(USE_FILEMON_ONCE) 426236769Sobrien if (useMeta) { 427236769Sobrien meta_cmd_finish(NULL); 428236769Sobrien } 429236769Sobrien#endif 430236769Sobrien if (status != 0) { 431236769Sobrien if (DEBUG(ERROR)) { 432236769Sobrien fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", 433236769Sobrien gn->name); 434236769Sobrien for (cp = cmd; *cp; ) { 435236769Sobrien if (isspace((unsigned char)*cp)) { 436236769Sobrien fprintf(debug_file, " "); 437236769Sobrien while (isspace((unsigned char)*cp)) 438236769Sobrien cp++; 439236769Sobrien } else { 440236769Sobrien fprintf(debug_file, "%c", *cp); 441236769Sobrien cp++; 442236769Sobrien } 443236769Sobrien } 444236769Sobrien fprintf(debug_file, "\n"); 445236769Sobrien } 446236769Sobrien printf("*** Error code %d", status); 447236769Sobrien } 448236769Sobrien } else { 449236769Sobrien status = WTERMSIG(reason); /* signaled */ 450236769Sobrien printf("*** Signal %d", status); 451236769Sobrien } 452236769Sobrien 453236769Sobrien 454236769Sobrien if (!WIFEXITED(reason) || (status != 0)) { 455236769Sobrien if (errCheck) { 456236769Sobrien#ifdef USE_META 457236769Sobrien if (useMeta) { 458236769Sobrien meta_job_error(NULL, gn, 0, status); 459236769Sobrien } 460236769Sobrien#endif 461236769Sobrien gn->made = ERROR; 462236769Sobrien if (keepgoing) { 463236769Sobrien /* 464236769Sobrien * Abort the current target, but let others 465236769Sobrien * continue. 466236769Sobrien */ 467236769Sobrien printf(" (continuing)\n"); 468236769Sobrien } 469236769Sobrien } else { 470236769Sobrien /* 471236769Sobrien * Continue executing commands for this target. 472236769Sobrien * If we return 0, this will happen... 473236769Sobrien */ 474236769Sobrien printf(" (ignored)\n"); 475236769Sobrien status = 0; 476236769Sobrien } 477236769Sobrien } 478236769Sobrien break; 479236769Sobrien } else { 480236769Sobrien Fatal("error in wait: %d: %s", retstat, strerror(errno)); 481236769Sobrien /*NOTREACHED*/ 482236769Sobrien } 483236769Sobrien } 484236769Sobrien free(cmdStart); 485236769Sobrien 486236769Sobrien return (status); 487236769Sobrien} 488236769Sobrien 489236769Sobrien/*- 490236769Sobrien *----------------------------------------------------------------------- 491236769Sobrien * Compat_Make -- 492236769Sobrien * Make a target. 493236769Sobrien * 494236769Sobrien * Input: 495236769Sobrien * gnp The node to make 496236769Sobrien * pgnp Parent to abort if necessary 497236769Sobrien * 498236769Sobrien * Results: 499236769Sobrien * 0 500236769Sobrien * 501236769Sobrien * Side Effects: 502236769Sobrien * If an error is detected and not being ignored, the process exits. 503236769Sobrien * 504236769Sobrien *----------------------------------------------------------------------- 505236769Sobrien */ 506236769Sobrienint 507236769SobrienCompat_Make(void *gnp, void *pgnp) 508236769Sobrien{ 509236769Sobrien GNode *gn = (GNode *)gnp; 510236769Sobrien GNode *pgn = (GNode *)pgnp; 511236769Sobrien 512236769Sobrien if (!meta[0]) /* we came here from jobs */ 513236769Sobrien Compat_Init(); 514236769Sobrien if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { 515236769Sobrien /* 516236769Sobrien * First mark ourselves to be made, then apply whatever transformations 517236769Sobrien * the suffix module thinks are necessary. Once that's done, we can 518236769Sobrien * descend and make all our children. If any of them has an error 519236769Sobrien * but the -k flag was given, our 'make' field will be set FALSE again. 520236769Sobrien * This is our signal to not attempt to do anything but abort our 521236769Sobrien * parent as well. 522236769Sobrien */ 523236769Sobrien gn->flags |= REMAKE; 524236769Sobrien gn->made = BEINGMADE; 525236769Sobrien if ((gn->type & OP_MADE) == 0) 526236769Sobrien Suff_FindDeps(gn); 527236769Sobrien Lst_ForEach(gn->children, Compat_Make, gn); 528236769Sobrien if ((gn->flags & REMAKE) == 0) { 529236769Sobrien gn->made = ABORTED; 530236769Sobrien pgn->flags &= ~REMAKE; 531236769Sobrien goto cohorts; 532236769Sobrien } 533236769Sobrien 534236769Sobrien if (Lst_Member(gn->iParents, pgn) != NULL) { 535236769Sobrien char *p1; 536236769Sobrien Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); 537236769Sobrien if (p1) 538236769Sobrien free(p1); 539236769Sobrien } 540236769Sobrien 541236769Sobrien /* 542236769Sobrien * All the children were made ok. Now cmgn->mtime contains the 543236769Sobrien * modification time of the newest child, we need to find out if we 544236769Sobrien * exist and when we were modified last. The criteria for datedness 545236769Sobrien * are defined by the Make_OODate function. 546236769Sobrien */ 547236769Sobrien if (DEBUG(MAKE)) { 548236769Sobrien fprintf(debug_file, "Examining %s...", gn->name); 549236769Sobrien } 550236769Sobrien if (! Make_OODate(gn)) { 551236769Sobrien gn->made = UPTODATE; 552236769Sobrien if (DEBUG(MAKE)) { 553236769Sobrien fprintf(debug_file, "up-to-date.\n"); 554236769Sobrien } 555236769Sobrien goto cohorts; 556236769Sobrien } else if (DEBUG(MAKE)) { 557236769Sobrien fprintf(debug_file, "out-of-date.\n"); 558236769Sobrien } 559236769Sobrien 560236769Sobrien /* 561236769Sobrien * If the user is just seeing if something is out-of-date, exit now 562236769Sobrien * to tell him/her "yes". 563236769Sobrien */ 564236769Sobrien if (queryFlag) { 565236769Sobrien exit(1); 566236769Sobrien } 567236769Sobrien 568236769Sobrien /* 569236769Sobrien * We need to be re-made. We also have to make sure we've got a $? 570236769Sobrien * variable. To be nice, we also define the $> variable using 571236769Sobrien * Make_DoAllVar(). 572236769Sobrien */ 573236769Sobrien Make_DoAllVar(gn); 574236769Sobrien 575236769Sobrien /* 576236769Sobrien * Alter our type to tell if errors should be ignored or things 577236769Sobrien * should not be printed so CompatRunCommand knows what to do. 578236769Sobrien */ 579236769Sobrien if (Targ_Ignore(gn)) { 580236769Sobrien gn->type |= OP_IGNORE; 581236769Sobrien } 582236769Sobrien if (Targ_Silent(gn)) { 583236769Sobrien gn->type |= OP_SILENT; 584236769Sobrien } 585236769Sobrien 586236769Sobrien if (Job_CheckCommands(gn, Fatal)) { 587236769Sobrien /* 588236769Sobrien * Our commands are ok, but we still have to worry about the -t 589236769Sobrien * flag... 590236769Sobrien */ 591236769Sobrien if (!touchFlag || (gn->type & OP_MAKE)) { 592236769Sobrien curTarg = gn; 593236769Sobrien#ifdef USE_META 594236769Sobrien if (useMeta && !NoExecute(gn)) { 595236769Sobrien meta_job_start(NULL, gn); 596236769Sobrien } 597236769Sobrien#endif 598236769Sobrien Lst_ForEach(gn->commands, CompatRunCommand, gn); 599236769Sobrien curTarg = NULL; 600236769Sobrien } else { 601236769Sobrien Job_Touch(gn, gn->type & OP_SILENT); 602236769Sobrien } 603236769Sobrien } else { 604236769Sobrien gn->made = ERROR; 605236769Sobrien } 606236769Sobrien#ifdef USE_META 607236769Sobrien if (useMeta && !NoExecute(gn)) { 608236769Sobrien meta_job_finish(NULL); 609236769Sobrien } 610236769Sobrien#endif 611236769Sobrien 612236769Sobrien if (gn->made != ERROR) { 613236769Sobrien /* 614236769Sobrien * If the node was made successfully, mark it so, update 615236769Sobrien * its modification time and timestamp all its parents. Note 616236769Sobrien * that for .ZEROTIME targets, the timestamping isn't done. 617236769Sobrien * This is to keep its state from affecting that of its parent. 618236769Sobrien */ 619236769Sobrien gn->made = MADE; 620236769Sobrien pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; 621236769Sobrien if (!(gn->type & OP_EXEC)) { 622236769Sobrien pgn->flags |= CHILDMADE; 623236769Sobrien Make_TimeStamp(pgn, gn); 624236769Sobrien } 625236769Sobrien } else if (keepgoing) { 626236769Sobrien pgn->flags &= ~REMAKE; 627236769Sobrien } else { 628236769Sobrien PrintOnError(gn, "\n\nStop."); 629236769Sobrien exit(1); 630236769Sobrien } 631236769Sobrien } else if (gn->made == ERROR) { 632236769Sobrien /* 633236769Sobrien * Already had an error when making this beastie. Tell the parent 634236769Sobrien * to abort. 635236769Sobrien */ 636236769Sobrien pgn->flags &= ~REMAKE; 637236769Sobrien } else { 638236769Sobrien if (Lst_Member(gn->iParents, pgn) != NULL) { 639236769Sobrien char *p1; 640236769Sobrien Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); 641236769Sobrien if (p1) 642236769Sobrien free(p1); 643236769Sobrien } 644236769Sobrien switch(gn->made) { 645236769Sobrien case BEINGMADE: 646236769Sobrien Error("Graph cycles through %s", gn->name); 647236769Sobrien gn->made = ERROR; 648236769Sobrien pgn->flags &= ~REMAKE; 649236769Sobrien break; 650236769Sobrien case MADE: 651236769Sobrien if ((gn->type & OP_EXEC) == 0) { 652236769Sobrien pgn->flags |= CHILDMADE; 653236769Sobrien Make_TimeStamp(pgn, gn); 654236769Sobrien } 655236769Sobrien break; 656236769Sobrien case UPTODATE: 657236769Sobrien if ((gn->type & OP_EXEC) == 0) { 658236769Sobrien Make_TimeStamp(pgn, gn); 659236769Sobrien } 660236769Sobrien break; 661236769Sobrien default: 662236769Sobrien break; 663236769Sobrien } 664236769Sobrien } 665236769Sobrien 666236769Sobriencohorts: 667236769Sobrien Lst_ForEach(gn->cohorts, Compat_Make, pgnp); 668236769Sobrien return (0); 669236769Sobrien} 670236769Sobrien 671236769Sobrien/*- 672236769Sobrien *----------------------------------------------------------------------- 673236769Sobrien * Compat_Run -- 674236769Sobrien * Initialize this mode and start making. 675236769Sobrien * 676236769Sobrien * Input: 677236769Sobrien * targs List of target nodes to re-create 678236769Sobrien * 679236769Sobrien * Results: 680236769Sobrien * None. 681236769Sobrien * 682236769Sobrien * Side Effects: 683236769Sobrien * Guess what? 684236769Sobrien * 685236769Sobrien *----------------------------------------------------------------------- 686236769Sobrien */ 687236769Sobrienvoid 688236769SobrienCompat_Run(Lst targs) 689236769Sobrien{ 690236769Sobrien GNode *gn = NULL;/* Current root target */ 691236769Sobrien int errors; /* Number of targets not remade due to errors */ 692236769Sobrien 693236769Sobrien Compat_Init(); 694236769Sobrien 695236769Sobrien if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { 696236769Sobrien bmake_signal(SIGINT, CompatInterrupt); 697236769Sobrien } 698236769Sobrien if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { 699236769Sobrien bmake_signal(SIGTERM, CompatInterrupt); 700236769Sobrien } 701236769Sobrien if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { 702236769Sobrien bmake_signal(SIGHUP, CompatInterrupt); 703236769Sobrien } 704236769Sobrien if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 705236769Sobrien bmake_signal(SIGQUIT, CompatInterrupt); 706236769Sobrien } 707236769Sobrien 708236769Sobrien ENDNode = Targ_FindNode(".END", TARG_CREATE); 709236769Sobrien ENDNode->type = OP_SPECIAL; 710236769Sobrien /* 711236769Sobrien * If the user has defined a .BEGIN target, execute the commands attached 712236769Sobrien * to it. 713236769Sobrien */ 714236769Sobrien if (!queryFlag) { 715236769Sobrien gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); 716236769Sobrien if (gn != NULL) { 717236769Sobrien Compat_Make(gn, gn); 718236769Sobrien if (gn->made == ERROR) { 719236769Sobrien PrintOnError(gn, "\n\nStop."); 720236769Sobrien exit(1); 721236769Sobrien } 722236769Sobrien } 723236769Sobrien } 724236769Sobrien 725236769Sobrien /* 726236769Sobrien * Expand .USE nodes right now, because they can modify the structure 727236769Sobrien * of the tree. 728236769Sobrien */ 729236769Sobrien Make_ExpandUse(targs); 730236769Sobrien 731236769Sobrien /* 732236769Sobrien * For each entry in the list of targets to create, call Compat_Make on 733236769Sobrien * it to create the thing. Compat_Make will leave the 'made' field of gn 734236769Sobrien * in one of several states: 735236769Sobrien * UPTODATE gn was already up-to-date 736236769Sobrien * MADE gn was recreated successfully 737236769Sobrien * ERROR An error occurred while gn was being created 738236769Sobrien * ABORTED gn was not remade because one of its inferiors 739236769Sobrien * could not be made due to errors. 740236769Sobrien */ 741236769Sobrien errors = 0; 742236769Sobrien while (!Lst_IsEmpty (targs)) { 743236769Sobrien gn = (GNode *)Lst_DeQueue(targs); 744236769Sobrien Compat_Make(gn, gn); 745236769Sobrien 746236769Sobrien if (gn->made == UPTODATE) { 747236769Sobrien printf("`%s' is up to date.\n", gn->name); 748236769Sobrien } else if (gn->made == ABORTED) { 749236769Sobrien printf("`%s' not remade because of errors.\n", gn->name); 750236769Sobrien errors += 1; 751236769Sobrien } 752236769Sobrien } 753236769Sobrien 754236769Sobrien /* 755236769Sobrien * If the user has defined a .END target, run its commands. 756236769Sobrien */ 757236769Sobrien if (errors == 0) { 758236769Sobrien Compat_Make(ENDNode, ENDNode); 759236769Sobrien if (gn->made == ERROR) { 760236769Sobrien PrintOnError(gn, "\n\nStop."); 761236769Sobrien exit(1); 762236769Sobrien } 763236769Sobrien } 764236769Sobrien} 765