1321964Ssjg/* $NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 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 73321964Ssjgstatic char rcsid[] = "$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 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 80321964Ssjg__RCSID("$NetBSD: compat.c,v 1.107 2017/07/20 19:29:54 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" 114292068Ssjg#include "metachar.h" 115236769Sobrien#include "pathnames.h" 116236769Sobrien 117236769Sobrien 118236769Sobrienstatic GNode *curTarg = NULL; 119236769Sobrienstatic GNode *ENDNode; 120237578Sobrienstatic void CompatInterrupt(int); 121321964Ssjgstatic pid_t compatChild; 122321964Ssjgstatic int compatSigno; 123236769Sobrien 124321964Ssjg/* 125321964Ssjg * CompatDeleteTarget -- delete a failed, interrupted, or otherwise 126321964Ssjg * duffed target if not inhibited by .PRECIOUS. 127321964Ssjg */ 128321964Ssjgstatic void 129321964SsjgCompatDeleteTarget(GNode *gn) 130321964Ssjg{ 131321964Ssjg if ((gn != NULL) && !Targ_Precious (gn)) { 132321964Ssjg char *p1; 133321964Ssjg char *file = Var_Value(TARGET, gn, &p1); 134321964Ssjg 135321964Ssjg if (!noExecute && eunlink(file) != -1) { 136321964Ssjg Error("*** %s removed", file); 137321964Ssjg } 138321964Ssjg 139321964Ssjg free(p1); 140321964Ssjg } 141321964Ssjg} 142321964Ssjg 143236769Sobrien/*- 144236769Sobrien *----------------------------------------------------------------------- 145236769Sobrien * CompatInterrupt -- 146236769Sobrien * Interrupt the creation of the current target and remove it if 147236769Sobrien * it ain't precious. 148236769Sobrien * 149236769Sobrien * Results: 150236769Sobrien * None. 151236769Sobrien * 152236769Sobrien * Side Effects: 153236769Sobrien * The target is removed and the process exits. If .INTERRUPT exists, 154236769Sobrien * its commands are run first WITH INTERRUPTS IGNORED.. 155236769Sobrien * 156321964Ssjg * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've 157321964Ssjg * left the logic alone for now. - dholland 20160826 158321964Ssjg * 159236769Sobrien *----------------------------------------------------------------------- 160236769Sobrien */ 161236769Sobrienstatic void 162236769SobrienCompatInterrupt(int signo) 163236769Sobrien{ 164236769Sobrien GNode *gn; 165236769Sobrien 166321964Ssjg CompatDeleteTarget(curTarg); 167321964Ssjg 168236769Sobrien if ((curTarg != NULL) && !Targ_Precious (curTarg)) { 169236769Sobrien /* 170236769Sobrien * Run .INTERRUPT only if hit with interrupt signal 171236769Sobrien */ 172236769Sobrien if (signo == SIGINT) { 173236769Sobrien gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 174236769Sobrien if (gn != NULL) { 175236769Sobrien Compat_Make(gn, gn); 176236769Sobrien } 177236769Sobrien } 178236769Sobrien } 179236769Sobrien if (signo == SIGQUIT) 180236769Sobrien _exit(signo); 181321964Ssjg /* 182321964Ssjg * If there is a child running, pass the signal on 183321964Ssjg * we will exist after it has exited. 184321964Ssjg */ 185321964Ssjg compatSigno = signo; 186321964Ssjg if (compatChild > 0) { 187321964Ssjg KILLPG(compatChild, signo); 188321964Ssjg } else { 189321964Ssjg bmake_signal(signo, SIG_DFL); 190321964Ssjg kill(myPid, signo); 191321964Ssjg } 192236769Sobrien} 193236769Sobrien 194236769Sobrien/*- 195236769Sobrien *----------------------------------------------------------------------- 196236769Sobrien * CompatRunCommand -- 197236769Sobrien * Execute the next command for a target. If the command returns an 198236769Sobrien * error, the node's made field is set to ERROR and creation stops. 199236769Sobrien * 200236769Sobrien * Input: 201236769Sobrien * cmdp Command to execute 202236769Sobrien * gnp Node from which the command came 203236769Sobrien * 204236769Sobrien * Results: 205236769Sobrien * 0 if the command succeeded, 1 if an error occurred. 206236769Sobrien * 207236769Sobrien * Side Effects: 208236769Sobrien * The node's 'made' field may be set to ERROR. 209236769Sobrien * 210236769Sobrien *----------------------------------------------------------------------- 211236769Sobrien */ 212236769Sobrienint 213236769SobrienCompatRunCommand(void *cmdp, void *gnp) 214236769Sobrien{ 215236769Sobrien char *cmdStart; /* Start of expanded command */ 216236769Sobrien char *cp, *bp; 217236769Sobrien Boolean silent, /* Don't print command */ 218236769Sobrien doIt; /* Execute even if -n */ 219236769Sobrien volatile Boolean errCheck; /* Check errors */ 220236769Sobrien WAIT_T reason; /* Reason for child's death */ 221236769Sobrien int status; /* Description of child's death */ 222236769Sobrien pid_t cpid; /* Child actually found */ 223236769Sobrien pid_t retstat; /* Result of wait */ 224236769Sobrien LstNode cmdNode; /* Node where current command is located */ 225236769Sobrien const char ** volatile av; /* Argument vector for thing to exec */ 226236769Sobrien char ** volatile mav;/* Copy of the argument vector for freeing */ 227236769Sobrien int argc; /* Number of arguments in av or 0 if not 228236769Sobrien * dynamically allocated */ 229236769Sobrien Boolean local; /* TRUE if command should be executed 230236769Sobrien * locally */ 231236769Sobrien Boolean useShell; /* TRUE if command should be executed 232236769Sobrien * using a shell */ 233236769Sobrien char * volatile cmd = (char *)cmdp; 234236769Sobrien GNode *gn = (GNode *)gnp; 235236769Sobrien 236236769Sobrien silent = gn->type & OP_SILENT; 237236769Sobrien errCheck = !(gn->type & OP_IGNORE); 238236769Sobrien doIt = FALSE; 239236769Sobrien 240236769Sobrien cmdNode = Lst_Member(gn->commands, cmd); 241321964Ssjg cmdStart = Var_Subst(NULL, cmd, gn, VARF_WANTRES); 242236769Sobrien 243236769Sobrien /* 244236769Sobrien * brk_string will return an argv with a NULL in av[0], thus causing 245236769Sobrien * execvp to choke and die horribly. Besides, how can we execute a null 246236769Sobrien * command? In any case, we warn the user that the command expanded to 247236769Sobrien * nothing (is this the right thing to do?). 248236769Sobrien */ 249236769Sobrien 250236769Sobrien if (*cmdStart == '\0') { 251236769Sobrien free(cmdStart); 252236769Sobrien return(0); 253236769Sobrien } 254236769Sobrien cmd = cmdStart; 255236769Sobrien Lst_Replace(cmdNode, cmdStart); 256236769Sobrien 257236769Sobrien if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { 258236769Sobrien (void)Lst_AtEnd(ENDNode->commands, cmdStart); 259236769Sobrien return(0); 260236769Sobrien } 261236769Sobrien if (strcmp(cmdStart, "...") == 0) { 262236769Sobrien gn->type |= OP_SAVE_CMDS; 263236769Sobrien return(0); 264236769Sobrien } 265236769Sobrien 266236769Sobrien while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { 267236769Sobrien switch (*cmd) { 268236769Sobrien case '@': 269236769Sobrien silent = DEBUG(LOUD) ? FALSE : TRUE; 270236769Sobrien break; 271236769Sobrien case '-': 272236769Sobrien errCheck = FALSE; 273236769Sobrien break; 274236769Sobrien case '+': 275236769Sobrien doIt = TRUE; 276292068Ssjg if (!shellName) /* we came here from jobs */ 277292068Ssjg Shell_Init(); 278236769Sobrien break; 279236769Sobrien } 280236769Sobrien cmd++; 281236769Sobrien } 282236769Sobrien 283236769Sobrien while (isspace((unsigned char)*cmd)) 284236769Sobrien cmd++; 285236769Sobrien 286236769Sobrien /* 287236769Sobrien * If we did not end up with a command, just skip it. 288236769Sobrien */ 289236769Sobrien if (!*cmd) 290236769Sobrien return (0); 291236769Sobrien 292236769Sobrien#if !defined(MAKE_NATIVE) 293236769Sobrien /* 294236769Sobrien * In a non-native build, the host environment might be weird enough 295236769Sobrien * that it's necessary to go through a shell to get the correct 296236769Sobrien * behaviour. Or perhaps the shell has been replaced with something 297236769Sobrien * that does extra logging, and that should not be bypassed. 298236769Sobrien */ 299236769Sobrien useShell = TRUE; 300236769Sobrien#else 301236769Sobrien /* 302236769Sobrien * Search for meta characters in the command. If there are no meta 303236769Sobrien * characters, there's no need to execute a shell to execute the 304236769Sobrien * command. 305292068Ssjg * 306292068Ssjg * Additionally variable assignments and empty commands 307292068Ssjg * go to the shell. Therefore treat '=' and ':' like shell 308292068Ssjg * meta characters as documented in make(1). 309236769Sobrien */ 310292068Ssjg 311292068Ssjg useShell = needshell(cmd, FALSE); 312236769Sobrien#endif 313236769Sobrien 314236769Sobrien /* 315236769Sobrien * Print the command before echoing if we're not supposed to be quiet for 316236769Sobrien * this one. We also print the command if -n given. 317236769Sobrien */ 318236769Sobrien if (!silent || NoExecute(gn)) { 319236769Sobrien printf("%s\n", cmd); 320236769Sobrien fflush(stdout); 321236769Sobrien } 322236769Sobrien 323236769Sobrien /* 324236769Sobrien * If we're not supposed to execute any commands, this is as far as 325236769Sobrien * we go... 326236769Sobrien */ 327236769Sobrien if (!doIt && NoExecute(gn)) { 328236769Sobrien return (0); 329236769Sobrien } 330236769Sobrien if (DEBUG(JOB)) 331236769Sobrien fprintf(debug_file, "Execute: '%s'\n", cmd); 332236769Sobrien 333236769Sobrienagain: 334236769Sobrien if (useShell) { 335236769Sobrien /* 336236769Sobrien * We need to pass the command off to the shell, typically 337236769Sobrien * because the command contains a "meta" character. 338236769Sobrien */ 339253883Ssjg static const char *shargv[5]; 340253883Ssjg int shargc; 341236769Sobrien 342253883Ssjg shargc = 0; 343253883Ssjg shargv[shargc++] = shellPath; 344236769Sobrien /* 345236769Sobrien * The following work for any of the builtin shell specs. 346236769Sobrien */ 347255127Ssjg if (errCheck && shellErrFlag) { 348253883Ssjg shargv[shargc++] = shellErrFlag; 349253883Ssjg } 350236769Sobrien if (DEBUG(SHELL)) 351253883Ssjg shargv[shargc++] = "-xc"; 352236769Sobrien else 353253883Ssjg shargv[shargc++] = "-c"; 354253883Ssjg shargv[shargc++] = cmd; 355253883Ssjg shargv[shargc++] = NULL; 356236769Sobrien av = shargv; 357236769Sobrien argc = 0; 358236769Sobrien bp = NULL; 359236769Sobrien mav = NULL; 360236769Sobrien } else { 361236769Sobrien /* 362236769Sobrien * No meta-characters, so no need to exec a shell. Break the command 363236769Sobrien * into words to form an argument vector we can execute. 364236769Sobrien */ 365236769Sobrien mav = brk_string(cmd, &argc, TRUE, &bp); 366236769Sobrien if (mav == NULL) { 367236769Sobrien useShell = 1; 368236769Sobrien goto again; 369236769Sobrien } 370236769Sobrien av = (void *)mav; 371236769Sobrien } 372236769Sobrien 373236769Sobrien local = TRUE; 374236769Sobrien 375236769Sobrien#ifdef USE_META 376236769Sobrien if (useMeta) { 377236769Sobrien meta_compat_start(); 378236769Sobrien } 379236769Sobrien#endif 380236769Sobrien 381236769Sobrien /* 382236769Sobrien * Fork and execute the single command. If the fork fails, we abort. 383236769Sobrien */ 384321964Ssjg compatChild = cpid = vFork(); 385236769Sobrien if (cpid < 0) { 386236769Sobrien Fatal("Could not fork"); 387236769Sobrien } 388236769Sobrien if (cpid == 0) { 389236769Sobrien Var_ExportVars(); 390236769Sobrien#ifdef USE_META 391236769Sobrien if (useMeta) { 392236769Sobrien meta_compat_child(); 393236769Sobrien } 394236769Sobrien#endif 395236769Sobrien if (local) 396236769Sobrien (void)execvp(av[0], (char *const *)UNCONST(av)); 397236769Sobrien else 398236769Sobrien (void)execv(av[0], (char *const *)UNCONST(av)); 399236769Sobrien execError("exec", av[0]); 400236769Sobrien _exit(1); 401236769Sobrien } 402321964Ssjg 403321964Ssjg free(mav); 404321964Ssjg free(bp); 405321964Ssjg 406236769Sobrien Lst_Replace(cmdNode, NULL); 407236769Sobrien 408236769Sobrien#ifdef USE_META 409236769Sobrien if (useMeta) { 410236769Sobrien meta_compat_parent(); 411236769Sobrien } 412236769Sobrien#endif 413236769Sobrien 414236769Sobrien /* 415236769Sobrien * The child is off and running. Now all we can do is wait... 416236769Sobrien */ 417236769Sobrien while (1) { 418236769Sobrien 419236769Sobrien while ((retstat = wait(&reason)) != cpid) { 420236769Sobrien if (retstat > 0) 421236769Sobrien JobReapChild(retstat, reason, FALSE); /* not ours? */ 422236769Sobrien if (retstat == -1 && errno != EINTR) { 423236769Sobrien break; 424236769Sobrien } 425236769Sobrien } 426236769Sobrien 427236769Sobrien if (retstat > -1) { 428236769Sobrien if (WIFSTOPPED(reason)) { 429236769Sobrien status = WSTOPSIG(reason); /* stopped */ 430236769Sobrien } else if (WIFEXITED(reason)) { 431236769Sobrien status = WEXITSTATUS(reason); /* exited */ 432236769Sobrien#if defined(USE_META) && defined(USE_FILEMON_ONCE) 433236769Sobrien if (useMeta) { 434236769Sobrien meta_cmd_finish(NULL); 435236769Sobrien } 436236769Sobrien#endif 437236769Sobrien if (status != 0) { 438236769Sobrien if (DEBUG(ERROR)) { 439236769Sobrien fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", 440236769Sobrien gn->name); 441236769Sobrien for (cp = cmd; *cp; ) { 442236769Sobrien if (isspace((unsigned char)*cp)) { 443236769Sobrien fprintf(debug_file, " "); 444236769Sobrien while (isspace((unsigned char)*cp)) 445236769Sobrien cp++; 446236769Sobrien } else { 447236769Sobrien fprintf(debug_file, "%c", *cp); 448236769Sobrien cp++; 449236769Sobrien } 450236769Sobrien } 451236769Sobrien fprintf(debug_file, "\n"); 452236769Sobrien } 453236769Sobrien printf("*** Error code %d", status); 454236769Sobrien } 455236769Sobrien } else { 456236769Sobrien status = WTERMSIG(reason); /* signaled */ 457236769Sobrien printf("*** Signal %d", status); 458236769Sobrien } 459236769Sobrien 460236769Sobrien 461236769Sobrien if (!WIFEXITED(reason) || (status != 0)) { 462236769Sobrien if (errCheck) { 463236769Sobrien#ifdef USE_META 464236769Sobrien if (useMeta) { 465236769Sobrien meta_job_error(NULL, gn, 0, status); 466236769Sobrien } 467236769Sobrien#endif 468236769Sobrien gn->made = ERROR; 469236769Sobrien if (keepgoing) { 470236769Sobrien /* 471236769Sobrien * Abort the current target, but let others 472236769Sobrien * continue. 473236769Sobrien */ 474236769Sobrien printf(" (continuing)\n"); 475321964Ssjg } else { 476321964Ssjg printf("\n"); 477236769Sobrien } 478321964Ssjg if (deleteOnError) { 479321964Ssjg CompatDeleteTarget(gn); 480321964Ssjg } 481236769Sobrien } else { 482236769Sobrien /* 483236769Sobrien * Continue executing commands for this target. 484236769Sobrien * If we return 0, this will happen... 485236769Sobrien */ 486236769Sobrien printf(" (ignored)\n"); 487236769Sobrien status = 0; 488236769Sobrien } 489236769Sobrien } 490236769Sobrien break; 491236769Sobrien } else { 492236769Sobrien Fatal("error in wait: %d: %s", retstat, strerror(errno)); 493236769Sobrien /*NOTREACHED*/ 494236769Sobrien } 495236769Sobrien } 496236769Sobrien free(cmdStart); 497321964Ssjg compatChild = 0; 498321964Ssjg if (compatSigno) { 499321964Ssjg bmake_signal(compatSigno, SIG_DFL); 500321964Ssjg kill(myPid, compatSigno); 501321964Ssjg } 502321964Ssjg 503236769Sobrien return (status); 504236769Sobrien} 505236769Sobrien 506236769Sobrien/*- 507236769Sobrien *----------------------------------------------------------------------- 508236769Sobrien * Compat_Make -- 509236769Sobrien * Make a target. 510236769Sobrien * 511236769Sobrien * Input: 512236769Sobrien * gnp The node to make 513236769Sobrien * pgnp Parent to abort if necessary 514236769Sobrien * 515236769Sobrien * Results: 516236769Sobrien * 0 517236769Sobrien * 518236769Sobrien * Side Effects: 519236769Sobrien * If an error is detected and not being ignored, the process exits. 520236769Sobrien * 521236769Sobrien *----------------------------------------------------------------------- 522236769Sobrien */ 523236769Sobrienint 524236769SobrienCompat_Make(void *gnp, void *pgnp) 525236769Sobrien{ 526236769Sobrien GNode *gn = (GNode *)gnp; 527236769Sobrien GNode *pgn = (GNode *)pgnp; 528236769Sobrien 529292068Ssjg if (!shellName) /* we came here from jobs */ 530292068Ssjg Shell_Init(); 531236769Sobrien if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) { 532236769Sobrien /* 533236769Sobrien * First mark ourselves to be made, then apply whatever transformations 534236769Sobrien * the suffix module thinks are necessary. Once that's done, we can 535236769Sobrien * descend and make all our children. If any of them has an error 536236769Sobrien * but the -k flag was given, our 'make' field will be set FALSE again. 537236769Sobrien * This is our signal to not attempt to do anything but abort our 538236769Sobrien * parent as well. 539236769Sobrien */ 540236769Sobrien gn->flags |= REMAKE; 541236769Sobrien gn->made = BEINGMADE; 542236769Sobrien if ((gn->type & OP_MADE) == 0) 543236769Sobrien Suff_FindDeps(gn); 544236769Sobrien Lst_ForEach(gn->children, Compat_Make, gn); 545236769Sobrien if ((gn->flags & REMAKE) == 0) { 546236769Sobrien gn->made = ABORTED; 547236769Sobrien pgn->flags &= ~REMAKE; 548236769Sobrien goto cohorts; 549236769Sobrien } 550236769Sobrien 551236769Sobrien if (Lst_Member(gn->iParents, pgn) != NULL) { 552236769Sobrien char *p1; 553236769Sobrien Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); 554321964Ssjg free(p1); 555236769Sobrien } 556236769Sobrien 557236769Sobrien /* 558236769Sobrien * All the children were made ok. Now cmgn->mtime contains the 559236769Sobrien * modification time of the newest child, we need to find out if we 560236769Sobrien * exist and when we were modified last. The criteria for datedness 561236769Sobrien * are defined by the Make_OODate function. 562236769Sobrien */ 563236769Sobrien if (DEBUG(MAKE)) { 564236769Sobrien fprintf(debug_file, "Examining %s...", gn->name); 565236769Sobrien } 566236769Sobrien if (! Make_OODate(gn)) { 567236769Sobrien gn->made = UPTODATE; 568236769Sobrien if (DEBUG(MAKE)) { 569236769Sobrien fprintf(debug_file, "up-to-date.\n"); 570236769Sobrien } 571236769Sobrien goto cohorts; 572236769Sobrien } else if (DEBUG(MAKE)) { 573236769Sobrien fprintf(debug_file, "out-of-date.\n"); 574236769Sobrien } 575236769Sobrien 576236769Sobrien /* 577236769Sobrien * If the user is just seeing if something is out-of-date, exit now 578236769Sobrien * to tell him/her "yes". 579236769Sobrien */ 580236769Sobrien if (queryFlag) { 581236769Sobrien exit(1); 582236769Sobrien } 583236769Sobrien 584236769Sobrien /* 585236769Sobrien * We need to be re-made. We also have to make sure we've got a $? 586236769Sobrien * variable. To be nice, we also define the $> variable using 587236769Sobrien * Make_DoAllVar(). 588236769Sobrien */ 589236769Sobrien Make_DoAllVar(gn); 590236769Sobrien 591236769Sobrien /* 592236769Sobrien * Alter our type to tell if errors should be ignored or things 593236769Sobrien * should not be printed so CompatRunCommand knows what to do. 594236769Sobrien */ 595236769Sobrien if (Targ_Ignore(gn)) { 596236769Sobrien gn->type |= OP_IGNORE; 597236769Sobrien } 598236769Sobrien if (Targ_Silent(gn)) { 599236769Sobrien gn->type |= OP_SILENT; 600236769Sobrien } 601236769Sobrien 602236769Sobrien if (Job_CheckCommands(gn, Fatal)) { 603236769Sobrien /* 604236769Sobrien * Our commands are ok, but we still have to worry about the -t 605236769Sobrien * flag... 606236769Sobrien */ 607236769Sobrien if (!touchFlag || (gn->type & OP_MAKE)) { 608236769Sobrien curTarg = gn; 609236769Sobrien#ifdef USE_META 610236769Sobrien if (useMeta && !NoExecute(gn)) { 611236769Sobrien meta_job_start(NULL, gn); 612236769Sobrien } 613236769Sobrien#endif 614236769Sobrien Lst_ForEach(gn->commands, CompatRunCommand, gn); 615236769Sobrien curTarg = NULL; 616236769Sobrien } else { 617236769Sobrien Job_Touch(gn, gn->type & OP_SILENT); 618236769Sobrien } 619236769Sobrien } else { 620236769Sobrien gn->made = ERROR; 621236769Sobrien } 622236769Sobrien#ifdef USE_META 623236769Sobrien if (useMeta && !NoExecute(gn)) { 624321964Ssjg if (meta_job_finish(NULL) != 0) 625321964Ssjg gn->made = ERROR; 626236769Sobrien } 627236769Sobrien#endif 628236769Sobrien 629236769Sobrien if (gn->made != ERROR) { 630236769Sobrien /* 631236769Sobrien * If the node was made successfully, mark it so, update 632236769Sobrien * its modification time and timestamp all its parents. Note 633236769Sobrien * that for .ZEROTIME targets, the timestamping isn't done. 634236769Sobrien * This is to keep its state from affecting that of its parent. 635236769Sobrien */ 636236769Sobrien gn->made = MADE; 637236769Sobrien pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; 638236769Sobrien if (!(gn->type & OP_EXEC)) { 639236769Sobrien pgn->flags |= CHILDMADE; 640236769Sobrien Make_TimeStamp(pgn, gn); 641236769Sobrien } 642236769Sobrien } else if (keepgoing) { 643236769Sobrien pgn->flags &= ~REMAKE; 644236769Sobrien } else { 645321964Ssjg PrintOnError(gn, "\nStop."); 646236769Sobrien exit(1); 647236769Sobrien } 648236769Sobrien } else if (gn->made == ERROR) { 649236769Sobrien /* 650236769Sobrien * Already had an error when making this beastie. Tell the parent 651236769Sobrien * to abort. 652236769Sobrien */ 653236769Sobrien pgn->flags &= ~REMAKE; 654236769Sobrien } else { 655236769Sobrien if (Lst_Member(gn->iParents, pgn) != NULL) { 656236769Sobrien char *p1; 657236769Sobrien Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0); 658321964Ssjg free(p1); 659236769Sobrien } 660236769Sobrien switch(gn->made) { 661236769Sobrien case BEINGMADE: 662236769Sobrien Error("Graph cycles through %s", gn->name); 663236769Sobrien gn->made = ERROR; 664236769Sobrien pgn->flags &= ~REMAKE; 665236769Sobrien break; 666236769Sobrien case MADE: 667236769Sobrien if ((gn->type & OP_EXEC) == 0) { 668236769Sobrien pgn->flags |= CHILDMADE; 669236769Sobrien Make_TimeStamp(pgn, gn); 670236769Sobrien } 671236769Sobrien break; 672236769Sobrien case UPTODATE: 673236769Sobrien if ((gn->type & OP_EXEC) == 0) { 674236769Sobrien Make_TimeStamp(pgn, gn); 675236769Sobrien } 676236769Sobrien break; 677236769Sobrien default: 678236769Sobrien break; 679236769Sobrien } 680236769Sobrien } 681236769Sobrien 682236769Sobriencohorts: 683236769Sobrien Lst_ForEach(gn->cohorts, Compat_Make, pgnp); 684236769Sobrien return (0); 685236769Sobrien} 686236769Sobrien 687236769Sobrien/*- 688236769Sobrien *----------------------------------------------------------------------- 689236769Sobrien * Compat_Run -- 690236769Sobrien * Initialize this mode and start making. 691236769Sobrien * 692236769Sobrien * Input: 693236769Sobrien * targs List of target nodes to re-create 694236769Sobrien * 695236769Sobrien * Results: 696236769Sobrien * None. 697236769Sobrien * 698236769Sobrien * Side Effects: 699236769Sobrien * Guess what? 700236769Sobrien * 701236769Sobrien *----------------------------------------------------------------------- 702236769Sobrien */ 703236769Sobrienvoid 704236769SobrienCompat_Run(Lst targs) 705236769Sobrien{ 706236769Sobrien GNode *gn = NULL;/* Current root target */ 707236769Sobrien int errors; /* Number of targets not remade due to errors */ 708236769Sobrien 709292068Ssjg if (!shellName) 710292068Ssjg Shell_Init(); 711236769Sobrien 712236769Sobrien if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) { 713236769Sobrien bmake_signal(SIGINT, CompatInterrupt); 714236769Sobrien } 715236769Sobrien if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) { 716236769Sobrien bmake_signal(SIGTERM, CompatInterrupt); 717236769Sobrien } 718236769Sobrien if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) { 719236769Sobrien bmake_signal(SIGHUP, CompatInterrupt); 720236769Sobrien } 721236769Sobrien if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 722236769Sobrien bmake_signal(SIGQUIT, CompatInterrupt); 723236769Sobrien } 724236769Sobrien 725236769Sobrien ENDNode = Targ_FindNode(".END", TARG_CREATE); 726236769Sobrien ENDNode->type = OP_SPECIAL; 727236769Sobrien /* 728236769Sobrien * If the user has defined a .BEGIN target, execute the commands attached 729236769Sobrien * to it. 730236769Sobrien */ 731236769Sobrien if (!queryFlag) { 732236769Sobrien gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); 733236769Sobrien if (gn != NULL) { 734236769Sobrien Compat_Make(gn, gn); 735236769Sobrien if (gn->made == ERROR) { 736321964Ssjg PrintOnError(gn, "\nStop."); 737236769Sobrien exit(1); 738236769Sobrien } 739236769Sobrien } 740236769Sobrien } 741236769Sobrien 742236769Sobrien /* 743236769Sobrien * Expand .USE nodes right now, because they can modify the structure 744236769Sobrien * of the tree. 745236769Sobrien */ 746236769Sobrien Make_ExpandUse(targs); 747236769Sobrien 748236769Sobrien /* 749236769Sobrien * For each entry in the list of targets to create, call Compat_Make on 750236769Sobrien * it to create the thing. Compat_Make will leave the 'made' field of gn 751236769Sobrien * in one of several states: 752236769Sobrien * UPTODATE gn was already up-to-date 753236769Sobrien * MADE gn was recreated successfully 754236769Sobrien * ERROR An error occurred while gn was being created 755236769Sobrien * ABORTED gn was not remade because one of its inferiors 756236769Sobrien * could not be made due to errors. 757236769Sobrien */ 758236769Sobrien errors = 0; 759236769Sobrien while (!Lst_IsEmpty (targs)) { 760236769Sobrien gn = (GNode *)Lst_DeQueue(targs); 761236769Sobrien Compat_Make(gn, gn); 762236769Sobrien 763236769Sobrien if (gn->made == UPTODATE) { 764236769Sobrien printf("`%s' is up to date.\n", gn->name); 765236769Sobrien } else if (gn->made == ABORTED) { 766236769Sobrien printf("`%s' not remade because of errors.\n", gn->name); 767236769Sobrien errors += 1; 768236769Sobrien } 769236769Sobrien } 770236769Sobrien 771236769Sobrien /* 772236769Sobrien * If the user has defined a .END target, run its commands. 773236769Sobrien */ 774236769Sobrien if (errors == 0) { 775236769Sobrien Compat_Make(ENDNode, ENDNode); 776236769Sobrien if (gn->made == ERROR) { 777321964Ssjg PrintOnError(gn, "\nStop."); 778236769Sobrien exit(1); 779236769Sobrien } 780236769Sobrien } 781236769Sobrien} 782