compat.c revision 253883
1253883Ssjg/* $NetBSD: compat.c,v 1.92 2013/07/05 22:14:56 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 73253883Ssjgstatic char rcsid[] = "$NetBSD: compat.c,v 1.92 2013/07/05 22:14:56 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 80253883Ssjg__RCSID("$NetBSD: compat.c,v 1.92 2013/07/05 22:14:56 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; 127237578Sobrienstatic void CompatInterrupt(int); 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 return(0); 251236769Sobrien } 252236769Sobrien cmd = cmdStart; 253236769Sobrien Lst_Replace(cmdNode, cmdStart); 254236769Sobrien 255236769Sobrien if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { 256236769Sobrien (void)Lst_AtEnd(ENDNode->commands, cmdStart); 257236769Sobrien return(0); 258236769Sobrien } 259236769Sobrien if (strcmp(cmdStart, "...") == 0) { 260236769Sobrien gn->type |= OP_SAVE_CMDS; 261236769Sobrien return(0); 262236769Sobrien } 263236769Sobrien 264236769Sobrien while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { 265236769Sobrien switch (*cmd) { 266236769Sobrien case '@': 267236769Sobrien silent = DEBUG(LOUD) ? FALSE : TRUE; 268236769Sobrien break; 269236769Sobrien case '-': 270236769Sobrien errCheck = FALSE; 271236769Sobrien break; 272236769Sobrien case '+': 273236769Sobrien doIt = TRUE; 274236769Sobrien if (!meta[0]) /* we came here from jobs */ 275236769Sobrien Compat_Init(); 276236769Sobrien break; 277236769Sobrien } 278236769Sobrien cmd++; 279236769Sobrien } 280236769Sobrien 281236769Sobrien while (isspace((unsigned char)*cmd)) 282236769Sobrien cmd++; 283236769Sobrien 284236769Sobrien /* 285236769Sobrien * If we did not end up with a command, just skip it. 286236769Sobrien */ 287236769Sobrien if (!*cmd) 288236769Sobrien return (0); 289236769Sobrien 290236769Sobrien#if !defined(MAKE_NATIVE) 291236769Sobrien /* 292236769Sobrien * In a non-native build, the host environment might be weird enough 293236769Sobrien * that it's necessary to go through a shell to get the correct 294236769Sobrien * behaviour. Or perhaps the shell has been replaced with something 295236769Sobrien * that does extra logging, and that should not be bypassed. 296236769Sobrien */ 297236769Sobrien useShell = TRUE; 298236769Sobrien#else 299236769Sobrien /* 300236769Sobrien * Search for meta characters in the command. If there are no meta 301236769Sobrien * characters, there's no need to execute a shell to execute the 302236769Sobrien * command. 303236769Sobrien */ 304236769Sobrien for (cp = cmd; !meta[(unsigned char)*cp]; cp++) { 305236769Sobrien continue; 306236769Sobrien } 307236769Sobrien useShell = (*cp != '\0'); 308236769Sobrien#endif 309236769Sobrien 310236769Sobrien /* 311236769Sobrien * Print the command before echoing if we're not supposed to be quiet for 312236769Sobrien * this one. We also print the command if -n given. 313236769Sobrien */ 314236769Sobrien if (!silent || NoExecute(gn)) { 315236769Sobrien printf("%s\n", cmd); 316236769Sobrien fflush(stdout); 317236769Sobrien } 318236769Sobrien 319236769Sobrien /* 320236769Sobrien * If we're not supposed to execute any commands, this is as far as 321236769Sobrien * we go... 322236769Sobrien */ 323236769Sobrien if (!doIt && NoExecute(gn)) { 324236769Sobrien return (0); 325236769Sobrien } 326236769Sobrien if (DEBUG(JOB)) 327236769Sobrien fprintf(debug_file, "Execute: '%s'\n", cmd); 328236769Sobrien 329236769Sobrienagain: 330236769Sobrien if (useShell) { 331236769Sobrien /* 332236769Sobrien * We need to pass the command off to the shell, typically 333236769Sobrien * because the command contains a "meta" character. 334236769Sobrien */ 335253883Ssjg static const char *shargv[5]; 336253883Ssjg int shargc; 337236769Sobrien 338253883Ssjg shargc = 0; 339253883Ssjg shargv[shargc++] = shellPath; 340236769Sobrien /* 341236769Sobrien * The following work for any of the builtin shell specs. 342236769Sobrien */ 343253883Ssjg if (shellErrFlag) { 344253883Ssjg shargv[shargc++] = shellErrFlag; 345253883Ssjg } 346236769Sobrien if (DEBUG(SHELL)) 347253883Ssjg shargv[shargc++] = "-xc"; 348236769Sobrien else 349253883Ssjg shargv[shargc++] = "-c"; 350253883Ssjg shargv[shargc++] = cmd; 351253883Ssjg shargv[shargc++] = NULL; 352236769Sobrien av = shargv; 353236769Sobrien argc = 0; 354236769Sobrien bp = NULL; 355236769Sobrien mav = NULL; 356236769Sobrien } else { 357236769Sobrien /* 358236769Sobrien * No meta-characters, so no need to exec a shell. Break the command 359236769Sobrien * into words to form an argument vector we can execute. 360236769Sobrien */ 361236769Sobrien mav = brk_string(cmd, &argc, TRUE, &bp); 362236769Sobrien if (mav == NULL) { 363236769Sobrien useShell = 1; 364236769Sobrien goto again; 365236769Sobrien } 366236769Sobrien av = (void *)mav; 367236769Sobrien } 368236769Sobrien 369236769Sobrien local = TRUE; 370236769Sobrien 371236769Sobrien#ifdef USE_META 372236769Sobrien if (useMeta) { 373236769Sobrien meta_compat_start(); 374236769Sobrien } 375236769Sobrien#endif 376236769Sobrien 377236769Sobrien /* 378236769Sobrien * Fork and execute the single command. If the fork fails, we abort. 379236769Sobrien */ 380236769Sobrien cpid = vFork(); 381236769Sobrien if (cpid < 0) { 382236769Sobrien Fatal("Could not fork"); 383236769Sobrien } 384236769Sobrien if (cpid == 0) { 385236769Sobrien Var_ExportVars(); 386236769Sobrien#ifdef USE_META 387236769Sobrien if (useMeta) { 388236769Sobrien meta_compat_child(); 389236769Sobrien } 390236769Sobrien#endif 391236769Sobrien if (local) 392236769Sobrien (void)execvp(av[0], (char *const *)UNCONST(av)); 393236769Sobrien else 394236769Sobrien (void)execv(av[0], (char *const *)UNCONST(av)); 395236769Sobrien execError("exec", av[0]); 396236769Sobrien _exit(1); 397236769Sobrien } 398236769Sobrien if (mav) 399236769Sobrien free(mav); 400236769Sobrien if (bp) 401236769Sobrien free(bp); 402236769Sobrien Lst_Replace(cmdNode, NULL); 403236769Sobrien 404236769Sobrien#ifdef USE_META 405236769Sobrien if (useMeta) { 406236769Sobrien meta_compat_parent(); 407236769Sobrien } 408236769Sobrien#endif 409236769Sobrien 410236769Sobrien /* 411236769Sobrien * The child is off and running. Now all we can do is wait... 412236769Sobrien */ 413236769Sobrien while (1) { 414236769Sobrien 415236769Sobrien while ((retstat = wait(&reason)) != cpid) { 416236769Sobrien if (retstat > 0) 417236769Sobrien JobReapChild(retstat, reason, FALSE); /* not ours? */ 418236769Sobrien if (retstat == -1 && errno != EINTR) { 419236769Sobrien break; 420236769Sobrien } 421236769Sobrien } 422236769Sobrien 423236769Sobrien if (retstat > -1) { 424236769Sobrien if (WIFSTOPPED(reason)) { 425236769Sobrien status = WSTOPSIG(reason); /* stopped */ 426236769Sobrien } else if (WIFEXITED(reason)) { 427236769Sobrien status = WEXITSTATUS(reason); /* exited */ 428236769Sobrien#if defined(USE_META) && defined(USE_FILEMON_ONCE) 429236769Sobrien if (useMeta) { 430236769Sobrien meta_cmd_finish(NULL); 431236769Sobrien } 432236769Sobrien#endif 433236769Sobrien if (status != 0) { 434236769Sobrien if (DEBUG(ERROR)) { 435236769Sobrien fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", 436236769Sobrien gn->name); 437236769Sobrien for (cp = cmd; *cp; ) { 438236769Sobrien if (isspace((unsigned char)*cp)) { 439236769Sobrien fprintf(debug_file, " "); 440236769Sobrien while (isspace((unsigned char)*cp)) 441236769Sobrien cp++; 442236769Sobrien } else { 443236769Sobrien fprintf(debug_file, "%c", *cp); 444236769Sobrien cp++; 445236769Sobrien } 446236769Sobrien } 447236769Sobrien fprintf(debug_file, "\n"); 448236769Sobrien } 449236769Sobrien printf("*** Error code %d", status); 450236769Sobrien } 451236769Sobrien } else { 452236769Sobrien status = WTERMSIG(reason); /* signaled */ 453236769Sobrien printf("*** Signal %d", status); 454236769Sobrien } 455236769Sobrien 456236769Sobrien 457236769Sobrien if (!WIFEXITED(reason) || (status != 0)) { 458236769Sobrien if (errCheck) { 459236769Sobrien#ifdef USE_META 460236769Sobrien if (useMeta) { 461236769Sobrien meta_job_error(NULL, gn, 0, status); 462236769Sobrien } 463236769Sobrien#endif 464236769Sobrien gn->made = ERROR; 465236769Sobrien if (keepgoing) { 466236769Sobrien /* 467236769Sobrien * Abort the current target, but let others 468236769Sobrien * continue. 469236769Sobrien */ 470236769Sobrien printf(" (continuing)\n"); 471236769Sobrien } 472236769Sobrien } else { 473236769Sobrien /* 474236769Sobrien * Continue executing commands for this target. 475236769Sobrien * If we return 0, this will happen... 476236769Sobrien */ 477236769Sobrien printf(" (ignored)\n"); 478236769Sobrien status = 0; 479236769Sobrien } 480236769Sobrien } 481236769Sobrien break; 482236769Sobrien } else { 483236769Sobrien Fatal("error in wait: %d: %s", retstat, strerror(errno)); 484236769Sobrien /*NOTREACHED*/ 485236769Sobrien } 486236769Sobrien } 487236769Sobrien free(cmdStart); 488236769Sobrien 489236769Sobrien return (status); 490236769Sobrien} 491236769Sobrien 492236769Sobrien/*- 493236769Sobrien *----------------------------------------------------------------------- 494236769Sobrien * Compat_Make -- 495236769Sobrien * Make a target. 496236769Sobrien * 497236769Sobrien * Input: 498236769Sobrien * gnp The node to make 499236769Sobrien * pgnp Parent to abort if necessary 500236769Sobrien * 501236769Sobrien * Results: 502236769Sobrien * 0 503236769Sobrien * 504236769Sobrien * Side Effects: 505236769Sobrien * If an error is detected and not being ignored, the process exits. 506236769Sobrien * 507236769Sobrien *----------------------------------------------------------------------- 508236769Sobrien */ 509236769Sobrienint 510236769SobrienCompat_Make(void *gnp, void *pgnp) 511236769Sobrien{ 512236769Sobrien GNode *gn = (GNode *)gnp; 513236769Sobrien GNode *pgn = (GNode *)pgnp; 514236769Sobrien 515236769Sobrien if (!meta[0]) /* we came here from jobs */ 516236769Sobrien Compat_Init(); 517236769Sobrien if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { 518236769Sobrien /* 519236769Sobrien * First mark ourselves to be made, then apply whatever transformations 520236769Sobrien * the suffix module thinks are necessary. Once that's done, we can 521236769Sobrien * descend and make all our children. If any of them has an error 522236769Sobrien * but the -k flag was given, our 'make' field will be set FALSE again. 523236769Sobrien * This is our signal to not attempt to do anything but abort our 524236769Sobrien * parent as well. 525236769Sobrien */ 526236769Sobrien gn->flags |= REMAKE; 527236769Sobrien gn->made = BEINGMADE; 528236769Sobrien if ((gn->type & OP_MADE) == 0) 529236769Sobrien Suff_FindDeps(gn); 530236769Sobrien Lst_ForEach(gn->children, Compat_Make, gn); 531236769Sobrien if ((gn->flags & REMAKE) == 0) { 532236769Sobrien gn->made = ABORTED; 533236769Sobrien pgn->flags &= ~REMAKE; 534236769Sobrien goto cohorts; 535236769Sobrien } 536236769Sobrien 537236769Sobrien if (Lst_Member(gn->iParents, pgn) != NULL) { 538236769Sobrien char *p1; 539236769Sobrien Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); 540236769Sobrien if (p1) 541236769Sobrien free(p1); 542236769Sobrien } 543236769Sobrien 544236769Sobrien /* 545236769Sobrien * All the children were made ok. Now cmgn->mtime contains the 546236769Sobrien * modification time of the newest child, we need to find out if we 547236769Sobrien * exist and when we were modified last. The criteria for datedness 548236769Sobrien * are defined by the Make_OODate function. 549236769Sobrien */ 550236769Sobrien if (DEBUG(MAKE)) { 551236769Sobrien fprintf(debug_file, "Examining %s...", gn->name); 552236769Sobrien } 553236769Sobrien if (! Make_OODate(gn)) { 554236769Sobrien gn->made = UPTODATE; 555236769Sobrien if (DEBUG(MAKE)) { 556236769Sobrien fprintf(debug_file, "up-to-date.\n"); 557236769Sobrien } 558236769Sobrien goto cohorts; 559236769Sobrien } else if (DEBUG(MAKE)) { 560236769Sobrien fprintf(debug_file, "out-of-date.\n"); 561236769Sobrien } 562236769Sobrien 563236769Sobrien /* 564236769Sobrien * If the user is just seeing if something is out-of-date, exit now 565236769Sobrien * to tell him/her "yes". 566236769Sobrien */ 567236769Sobrien if (queryFlag) { 568236769Sobrien exit(1); 569236769Sobrien } 570236769Sobrien 571236769Sobrien /* 572236769Sobrien * We need to be re-made. We also have to make sure we've got a $? 573236769Sobrien * variable. To be nice, we also define the $> variable using 574236769Sobrien * Make_DoAllVar(). 575236769Sobrien */ 576236769Sobrien Make_DoAllVar(gn); 577236769Sobrien 578236769Sobrien /* 579236769Sobrien * Alter our type to tell if errors should be ignored or things 580236769Sobrien * should not be printed so CompatRunCommand knows what to do. 581236769Sobrien */ 582236769Sobrien if (Targ_Ignore(gn)) { 583236769Sobrien gn->type |= OP_IGNORE; 584236769Sobrien } 585236769Sobrien if (Targ_Silent(gn)) { 586236769Sobrien gn->type |= OP_SILENT; 587236769Sobrien } 588236769Sobrien 589236769Sobrien if (Job_CheckCommands(gn, Fatal)) { 590236769Sobrien /* 591236769Sobrien * Our commands are ok, but we still have to worry about the -t 592236769Sobrien * flag... 593236769Sobrien */ 594236769Sobrien if (!touchFlag || (gn->type & OP_MAKE)) { 595236769Sobrien curTarg = gn; 596236769Sobrien#ifdef USE_META 597236769Sobrien if (useMeta && !NoExecute(gn)) { 598236769Sobrien meta_job_start(NULL, gn); 599236769Sobrien } 600236769Sobrien#endif 601236769Sobrien Lst_ForEach(gn->commands, CompatRunCommand, gn); 602236769Sobrien curTarg = NULL; 603236769Sobrien } else { 604236769Sobrien Job_Touch(gn, gn->type & OP_SILENT); 605236769Sobrien } 606236769Sobrien } else { 607236769Sobrien gn->made = ERROR; 608236769Sobrien } 609236769Sobrien#ifdef USE_META 610236769Sobrien if (useMeta && !NoExecute(gn)) { 611236769Sobrien meta_job_finish(NULL); 612236769Sobrien } 613236769Sobrien#endif 614236769Sobrien 615236769Sobrien if (gn->made != ERROR) { 616236769Sobrien /* 617236769Sobrien * If the node was made successfully, mark it so, update 618236769Sobrien * its modification time and timestamp all its parents. Note 619236769Sobrien * that for .ZEROTIME targets, the timestamping isn't done. 620236769Sobrien * This is to keep its state from affecting that of its parent. 621236769Sobrien */ 622236769Sobrien gn->made = MADE; 623236769Sobrien pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; 624236769Sobrien if (!(gn->type & OP_EXEC)) { 625236769Sobrien pgn->flags |= CHILDMADE; 626236769Sobrien Make_TimeStamp(pgn, gn); 627236769Sobrien } 628236769Sobrien } else if (keepgoing) { 629236769Sobrien pgn->flags &= ~REMAKE; 630236769Sobrien } else { 631236769Sobrien PrintOnError(gn, "\n\nStop."); 632236769Sobrien exit(1); 633236769Sobrien } 634236769Sobrien } else if (gn->made == ERROR) { 635236769Sobrien /* 636236769Sobrien * Already had an error when making this beastie. Tell the parent 637236769Sobrien * to abort. 638236769Sobrien */ 639236769Sobrien pgn->flags &= ~REMAKE; 640236769Sobrien } else { 641236769Sobrien if (Lst_Member(gn->iParents, pgn) != NULL) { 642236769Sobrien char *p1; 643236769Sobrien Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); 644236769Sobrien if (p1) 645236769Sobrien free(p1); 646236769Sobrien } 647236769Sobrien switch(gn->made) { 648236769Sobrien case BEINGMADE: 649236769Sobrien Error("Graph cycles through %s", gn->name); 650236769Sobrien gn->made = ERROR; 651236769Sobrien pgn->flags &= ~REMAKE; 652236769Sobrien break; 653236769Sobrien case MADE: 654236769Sobrien if ((gn->type & OP_EXEC) == 0) { 655236769Sobrien pgn->flags |= CHILDMADE; 656236769Sobrien Make_TimeStamp(pgn, gn); 657236769Sobrien } 658236769Sobrien break; 659236769Sobrien case UPTODATE: 660236769Sobrien if ((gn->type & OP_EXEC) == 0) { 661236769Sobrien Make_TimeStamp(pgn, gn); 662236769Sobrien } 663236769Sobrien break; 664236769Sobrien default: 665236769Sobrien break; 666236769Sobrien } 667236769Sobrien } 668236769Sobrien 669236769Sobriencohorts: 670236769Sobrien Lst_ForEach(gn->cohorts, Compat_Make, pgnp); 671236769Sobrien return (0); 672236769Sobrien} 673236769Sobrien 674236769Sobrien/*- 675236769Sobrien *----------------------------------------------------------------------- 676236769Sobrien * Compat_Run -- 677236769Sobrien * Initialize this mode and start making. 678236769Sobrien * 679236769Sobrien * Input: 680236769Sobrien * targs List of target nodes to re-create 681236769Sobrien * 682236769Sobrien * Results: 683236769Sobrien * None. 684236769Sobrien * 685236769Sobrien * Side Effects: 686236769Sobrien * Guess what? 687236769Sobrien * 688236769Sobrien *----------------------------------------------------------------------- 689236769Sobrien */ 690236769Sobrienvoid 691236769SobrienCompat_Run(Lst targs) 692236769Sobrien{ 693236769Sobrien GNode *gn = NULL;/* Current root target */ 694236769Sobrien int errors; /* Number of targets not remade due to errors */ 695236769Sobrien 696236769Sobrien Compat_Init(); 697236769Sobrien 698236769Sobrien if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { 699236769Sobrien bmake_signal(SIGINT, CompatInterrupt); 700236769Sobrien } 701236769Sobrien if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { 702236769Sobrien bmake_signal(SIGTERM, CompatInterrupt); 703236769Sobrien } 704236769Sobrien if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { 705236769Sobrien bmake_signal(SIGHUP, CompatInterrupt); 706236769Sobrien } 707236769Sobrien if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 708236769Sobrien bmake_signal(SIGQUIT, CompatInterrupt); 709236769Sobrien } 710236769Sobrien 711236769Sobrien ENDNode = Targ_FindNode(".END", TARG_CREATE); 712236769Sobrien ENDNode->type = OP_SPECIAL; 713236769Sobrien /* 714236769Sobrien * If the user has defined a .BEGIN target, execute the commands attached 715236769Sobrien * to it. 716236769Sobrien */ 717236769Sobrien if (!queryFlag) { 718236769Sobrien gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); 719236769Sobrien if (gn != NULL) { 720236769Sobrien Compat_Make(gn, gn); 721236769Sobrien if (gn->made == ERROR) { 722236769Sobrien PrintOnError(gn, "\n\nStop."); 723236769Sobrien exit(1); 724236769Sobrien } 725236769Sobrien } 726236769Sobrien } 727236769Sobrien 728236769Sobrien /* 729236769Sobrien * Expand .USE nodes right now, because they can modify the structure 730236769Sobrien * of the tree. 731236769Sobrien */ 732236769Sobrien Make_ExpandUse(targs); 733236769Sobrien 734236769Sobrien /* 735236769Sobrien * For each entry in the list of targets to create, call Compat_Make on 736236769Sobrien * it to create the thing. Compat_Make will leave the 'made' field of gn 737236769Sobrien * in one of several states: 738236769Sobrien * UPTODATE gn was already up-to-date 739236769Sobrien * MADE gn was recreated successfully 740236769Sobrien * ERROR An error occurred while gn was being created 741236769Sobrien * ABORTED gn was not remade because one of its inferiors 742236769Sobrien * could not be made due to errors. 743236769Sobrien */ 744236769Sobrien errors = 0; 745236769Sobrien while (!Lst_IsEmpty (targs)) { 746236769Sobrien gn = (GNode *)Lst_DeQueue(targs); 747236769Sobrien Compat_Make(gn, gn); 748236769Sobrien 749236769Sobrien if (gn->made == UPTODATE) { 750236769Sobrien printf("`%s' is up to date.\n", gn->name); 751236769Sobrien } else if (gn->made == ABORTED) { 752236769Sobrien printf("`%s' not remade because of errors.\n", gn->name); 753236769Sobrien errors += 1; 754236769Sobrien } 755236769Sobrien } 756236769Sobrien 757236769Sobrien /* 758236769Sobrien * If the user has defined a .END target, run its commands. 759236769Sobrien */ 760236769Sobrien if (errors == 0) { 761236769Sobrien Compat_Make(ENDNode, ENDNode); 762236769Sobrien if (gn->made == ERROR) { 763236769Sobrien PrintOnError(gn, "\n\nStop."); 764236769Sobrien exit(1); 765236769Sobrien } 766236769Sobrien } 767236769Sobrien} 768