xref: /dflybsd-src/contrib/bmake/compat.c (revision 9e7ae5a0527a977cab412aede3a532cfe2903bbb)
1*6eef5f0cSAntonio Huete Jimenez /*	$NetBSD: compat.c,v 1.241 2022/08/17 20:10:29 rillig Exp $	*/
201e196c8SJohn Marino 
301e196c8SJohn Marino /*
401e196c8SJohn Marino  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
501e196c8SJohn Marino  * All rights reserved.
601e196c8SJohn Marino  *
701e196c8SJohn Marino  * This code is derived from software contributed to Berkeley by
801e196c8SJohn Marino  * Adam de Boor.
901e196c8SJohn Marino  *
1001e196c8SJohn Marino  * Redistribution and use in source and binary forms, with or without
1101e196c8SJohn Marino  * modification, are permitted provided that the following conditions
1201e196c8SJohn Marino  * are met:
1301e196c8SJohn Marino  * 1. Redistributions of source code must retain the above copyright
1401e196c8SJohn Marino  *    notice, this list of conditions and the following disclaimer.
1501e196c8SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
1601e196c8SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
1701e196c8SJohn Marino  *    documentation and/or other materials provided with the distribution.
1801e196c8SJohn Marino  * 3. Neither the name of the University nor the names of its contributors
1901e196c8SJohn Marino  *    may be used to endorse or promote products derived from this software
2001e196c8SJohn Marino  *    without specific prior written permission.
2101e196c8SJohn Marino  *
2201e196c8SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2301e196c8SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2401e196c8SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2501e196c8SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2601e196c8SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2701e196c8SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2801e196c8SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2901e196c8SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3001e196c8SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3101e196c8SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3201e196c8SJohn Marino  * SUCH DAMAGE.
3301e196c8SJohn Marino  */
3401e196c8SJohn Marino 
3501e196c8SJohn Marino /*
3601e196c8SJohn Marino  * Copyright (c) 1988, 1989 by Adam de Boor
3701e196c8SJohn Marino  * Copyright (c) 1989 by Berkeley Softworks
3801e196c8SJohn Marino  * All rights reserved.
3901e196c8SJohn Marino  *
4001e196c8SJohn Marino  * This code is derived from software contributed to Berkeley by
4101e196c8SJohn Marino  * Adam de Boor.
4201e196c8SJohn Marino  *
4301e196c8SJohn Marino  * Redistribution and use in source and binary forms, with or without
4401e196c8SJohn Marino  * modification, are permitted provided that the following conditions
4501e196c8SJohn Marino  * are met:
4601e196c8SJohn Marino  * 1. Redistributions of source code must retain the above copyright
4701e196c8SJohn Marino  *    notice, this list of conditions and the following disclaimer.
4801e196c8SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
4901e196c8SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
5001e196c8SJohn Marino  *    documentation and/or other materials provided with the distribution.
5101e196c8SJohn Marino  * 3. All advertising materials mentioning features or use of this software
5201e196c8SJohn Marino  *    must display the following acknowledgement:
5301e196c8SJohn Marino  *	This product includes software developed by the University of
5401e196c8SJohn Marino  *	California, Berkeley and its contributors.
5501e196c8SJohn Marino  * 4. Neither the name of the University nor the names of its contributors
5601e196c8SJohn Marino  *    may be used to endorse or promote products derived from this software
5701e196c8SJohn Marino  *    without specific prior written permission.
5801e196c8SJohn Marino  *
5901e196c8SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
6001e196c8SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6101e196c8SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6201e196c8SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6301e196c8SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6401e196c8SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6501e196c8SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6601e196c8SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6701e196c8SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6801e196c8SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6901e196c8SJohn Marino  * SUCH DAMAGE.
7001e196c8SJohn Marino  */
7101e196c8SJohn Marino 
72a34d5fb1SAntonio Huete Jimenez /*
73*6eef5f0cSAntonio Huete Jimenez  * This file implements the full-compatibility mode of make, which makes the
74*6eef5f0cSAntonio Huete Jimenez  * targets without parallelism and without a custom shell.
7501e196c8SJohn Marino  *
7601e196c8SJohn Marino  * Interface:
77*6eef5f0cSAntonio Huete Jimenez  *	Compat_MakeAll	Initialize this module and make the given targets.
7801e196c8SJohn Marino  */
7901e196c8SJohn Marino 
8001e196c8SJohn Marino #ifdef HAVE_CONFIG_H
8101e196c8SJohn Marino # include   "config.h"
8201e196c8SJohn Marino #endif
8301e196c8SJohn Marino #include <sys/types.h>
8401e196c8SJohn Marino #include <sys/stat.h>
8501e196c8SJohn Marino #include "wait.h"
8601e196c8SJohn Marino 
8701e196c8SJohn Marino #include <errno.h>
8801e196c8SJohn Marino #include <signal.h>
8901e196c8SJohn Marino 
9001e196c8SJohn Marino #include "make.h"
9101e196c8SJohn Marino #include "dir.h"
9201e196c8SJohn Marino #include "job.h"
93f445c897SJohn Marino #include "metachar.h"
9401e196c8SJohn Marino #include "pathnames.h"
9501e196c8SJohn Marino 
96a34d5fb1SAntonio Huete Jimenez /*	"@(#)compat.c	8.2 (Berkeley) 3/19/94"	*/
97*6eef5f0cSAntonio Huete Jimenez MAKE_RCSID("$NetBSD: compat.c,v 1.241 2022/08/17 20:10:29 rillig Exp $");
9801e196c8SJohn Marino 
9901e196c8SJohn Marino static GNode *curTarg = NULL;
100ca58f742SDaniel Fojt static pid_t compatChild;
101ca58f742SDaniel Fojt static int compatSigno;
102ca58f742SDaniel Fojt 
103ca58f742SDaniel Fojt /*
104a34d5fb1SAntonio Huete Jimenez  * CompatDeleteTarget -- delete the file of a failed, interrupted, or
105a34d5fb1SAntonio Huete Jimenez  * otherwise duffed target if not inhibited by .PRECIOUS.
106ca58f742SDaniel Fojt  */
107ca58f742SDaniel Fojt static void
CompatDeleteTarget(GNode * gn)108ca58f742SDaniel Fojt CompatDeleteTarget(GNode *gn)
109ca58f742SDaniel Fojt {
110*6eef5f0cSAntonio Huete Jimenez 	if (gn != NULL && !GNode_IsPrecious(gn)) {
111a34d5fb1SAntonio Huete Jimenez 		const char *file = GNode_VarTarget(gn);
112ca58f742SDaniel Fojt 
113*6eef5f0cSAntonio Huete Jimenez 		if (!opts.noExecute && unlink_file(file)) {
114ca58f742SDaniel Fojt 			Error("*** %s removed", file);
115ca58f742SDaniel Fojt 		}
116ca58f742SDaniel Fojt 	}
117ca58f742SDaniel Fojt }
11801e196c8SJohn Marino 
119a34d5fb1SAntonio Huete Jimenez /*
120a34d5fb1SAntonio Huete Jimenez  * Interrupt the creation of the current target and remove it if it ain't
121a34d5fb1SAntonio Huete Jimenez  * precious. Then exit.
12201e196c8SJohn Marino  *
123a34d5fb1SAntonio Huete Jimenez  * If .INTERRUPT exists, its commands are run first WITH INTERRUPTS IGNORED.
12401e196c8SJohn Marino  *
125ca58f742SDaniel Fojt  * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've
126ca58f742SDaniel Fojt  * left the logic alone for now. - dholland 20160826
12701e196c8SJohn Marino  */
12801e196c8SJohn Marino static void
CompatInterrupt(int signo)12901e196c8SJohn Marino CompatInterrupt(int signo)
13001e196c8SJohn Marino {
131ca58f742SDaniel Fojt 	CompatDeleteTarget(curTarg);
132ca58f742SDaniel Fojt 
133*6eef5f0cSAntonio Huete Jimenez 	if (curTarg != NULL && !GNode_IsPrecious(curTarg)) {
13401e196c8SJohn Marino 		/*
13501e196c8SJohn Marino 		 * Run .INTERRUPT only if hit with interrupt signal
13601e196c8SJohn Marino 		 */
13701e196c8SJohn Marino 		if (signo == SIGINT) {
138a34d5fb1SAntonio Huete Jimenez 			GNode *gn = Targ_FindNode(".INTERRUPT");
13901e196c8SJohn Marino 			if (gn != NULL) {
14001e196c8SJohn Marino 				Compat_Make(gn, gn);
14101e196c8SJohn Marino 			}
14201e196c8SJohn Marino 		}
14301e196c8SJohn Marino 	}
144a34d5fb1SAntonio Huete Jimenez 
14501e196c8SJohn Marino 	if (signo == SIGQUIT)
14601e196c8SJohn Marino 		_exit(signo);
147a34d5fb1SAntonio Huete Jimenez 
148ca58f742SDaniel Fojt 	/*
149a34d5fb1SAntonio Huete Jimenez 	 * If there is a child running, pass the signal on.
150a34d5fb1SAntonio Huete Jimenez 	 * We will exist after it has exited.
151ca58f742SDaniel Fojt 	 */
152ca58f742SDaniel Fojt 	compatSigno = signo;
153ca58f742SDaniel Fojt 	if (compatChild > 0) {
154ca58f742SDaniel Fojt 		KILLPG(compatChild, signo);
155ca58f742SDaniel Fojt 	} else {
15601e196c8SJohn Marino 		bmake_signal(signo, SIG_DFL);
15701e196c8SJohn Marino 		kill(myPid, signo);
15801e196c8SJohn Marino 	}
159ca58f742SDaniel Fojt }
160a34d5fb1SAntonio Huete Jimenez 
161a34d5fb1SAntonio Huete Jimenez static void
DebugFailedTarget(const char * cmd,const GNode * gn)162*6eef5f0cSAntonio Huete Jimenez DebugFailedTarget(const char *cmd, const GNode *gn)
16301e196c8SJohn Marino {
164a34d5fb1SAntonio Huete Jimenez 	const char *p = cmd;
165a34d5fb1SAntonio Huete Jimenez 	debug_printf("\n*** Failed target:  %s\n*** Failed command: ",
166a34d5fb1SAntonio Huete Jimenez 	    gn->name);
16701e196c8SJohn Marino 
168*6eef5f0cSAntonio Huete Jimenez 	/*
169*6eef5f0cSAntonio Huete Jimenez 	 * Replace runs of whitespace with a single space, to reduce the
170*6eef5f0cSAntonio Huete Jimenez 	 * amount of whitespace for multi-line command lines.
171*6eef5f0cSAntonio Huete Jimenez 	 */
172a34d5fb1SAntonio Huete Jimenez 	while (*p != '\0') {
173a34d5fb1SAntonio Huete Jimenez 		if (ch_isspace(*p)) {
174a34d5fb1SAntonio Huete Jimenez 			debug_printf(" ");
175a34d5fb1SAntonio Huete Jimenez 			cpp_skip_whitespace(&p);
176a34d5fb1SAntonio Huete Jimenez 		} else {
177a34d5fb1SAntonio Huete Jimenez 			debug_printf("%c", *p);
178a34d5fb1SAntonio Huete Jimenez 			p++;
17901e196c8SJohn Marino 		}
18001e196c8SJohn Marino 	}
181a34d5fb1SAntonio Huete Jimenez 	debug_printf("\n");
18201e196c8SJohn Marino }
18301e196c8SJohn Marino 
184*6eef5f0cSAntonio Huete Jimenez static bool
UseShell(const char * cmd MAKE_ATTR_UNUSED)185a34d5fb1SAntonio Huete Jimenez UseShell(const char *cmd MAKE_ATTR_UNUSED)
186a34d5fb1SAntonio Huete Jimenez {
187*6eef5f0cSAntonio Huete Jimenez #if defined(FORCE_USE_SHELL) || !defined(MAKE_NATIVE)
18801e196c8SJohn Marino 	/*
18901e196c8SJohn Marino 	 * In a non-native build, the host environment might be weird enough
19001e196c8SJohn Marino 	 * that it's necessary to go through a shell to get the correct
19101e196c8SJohn Marino 	 * behaviour.  Or perhaps the shell has been replaced with something
19201e196c8SJohn Marino 	 * that does extra logging, and that should not be bypassed.
19301e196c8SJohn Marino 	 */
194*6eef5f0cSAntonio Huete Jimenez 	return true;
19501e196c8SJohn Marino #else
19601e196c8SJohn Marino 	/*
19701e196c8SJohn Marino 	 * Search for meta characters in the command. If there are no meta
19801e196c8SJohn Marino 	 * characters, there's no need to execute a shell to execute the
19901e196c8SJohn Marino 	 * command.
200f445c897SJohn Marino 	 *
201f445c897SJohn Marino 	 * Additionally variable assignments and empty commands
202f445c897SJohn Marino 	 * go to the shell. Therefore treat '=' and ':' like shell
203f445c897SJohn Marino 	 * meta characters as documented in make(1).
20401e196c8SJohn Marino 	 */
205f445c897SJohn Marino 
206a34d5fb1SAntonio Huete Jimenez 	return needshell(cmd);
20701e196c8SJohn Marino #endif
208a34d5fb1SAntonio Huete Jimenez }
20901e196c8SJohn Marino 
21001e196c8SJohn Marino /*
211a34d5fb1SAntonio Huete Jimenez  * Execute the next command for a target. If the command returns an error,
212a34d5fb1SAntonio Huete Jimenez  * the node's made field is set to ERROR and creation stops.
213a34d5fb1SAntonio Huete Jimenez  *
214a34d5fb1SAntonio Huete Jimenez  * Input:
215a34d5fb1SAntonio Huete Jimenez  *	cmdp		Command to execute
216a34d5fb1SAntonio Huete Jimenez  *	gn		Node from which the command came
217a34d5fb1SAntonio Huete Jimenez  *	ln		List node that contains the command
218a34d5fb1SAntonio Huete Jimenez  *
219a34d5fb1SAntonio Huete Jimenez  * Results:
220*6eef5f0cSAntonio Huete Jimenez  *	true if the command succeeded.
22101e196c8SJohn Marino  */
222*6eef5f0cSAntonio Huete Jimenez bool
Compat_RunCommand(const char * cmdp,GNode * gn,StringListNode * ln)223a34d5fb1SAntonio Huete Jimenez Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
224a34d5fb1SAntonio Huete Jimenez {
225a34d5fb1SAntonio Huete Jimenez 	char *cmdStart;		/* Start of expanded command */
226a34d5fb1SAntonio Huete Jimenez 	char *bp;
227*6eef5f0cSAntonio Huete Jimenez 	bool silent;		/* Don't print command */
228*6eef5f0cSAntonio Huete Jimenez 	bool doIt;		/* Execute even if -n */
229*6eef5f0cSAntonio Huete Jimenez 	volatile bool errCheck;	/* Check errors */
230a34d5fb1SAntonio Huete Jimenez 	WAIT_T reason;		/* Reason for child's death */
231a34d5fb1SAntonio Huete Jimenez 	WAIT_T status;		/* Description of child's death */
232a34d5fb1SAntonio Huete Jimenez 	pid_t cpid;		/* Child actually found */
233a34d5fb1SAntonio Huete Jimenez 	pid_t retstat;		/* Result of wait */
234a34d5fb1SAntonio Huete Jimenez 	const char **volatile av; /* Argument vector for thing to exec */
235a34d5fb1SAntonio Huete Jimenez 	char **volatile mav;	/* Copy of the argument vector for freeing */
236*6eef5f0cSAntonio Huete Jimenez 	bool useShell;		/* True if command should be executed using a
237*6eef5f0cSAntonio Huete Jimenez 				 * shell */
238a34d5fb1SAntonio Huete Jimenez 	const char *volatile cmd = cmdp;
239a34d5fb1SAntonio Huete Jimenez 
240*6eef5f0cSAntonio Huete Jimenez 	silent = (gn->type & OP_SILENT) != OP_NONE;
241a34d5fb1SAntonio Huete Jimenez 	errCheck = !(gn->type & OP_IGNORE);
242*6eef5f0cSAntonio Huete Jimenez 	doIt = false;
243a34d5fb1SAntonio Huete Jimenez 
244a34d5fb1SAntonio Huete Jimenez 	(void)Var_Subst(cmd, gn, VARE_WANTRES, &cmdStart);
245a34d5fb1SAntonio Huete Jimenez 	/* TODO: handle errors */
246a34d5fb1SAntonio Huete Jimenez 
247a34d5fb1SAntonio Huete Jimenez 	if (cmdStart[0] == '\0') {
248a34d5fb1SAntonio Huete Jimenez 		free(cmdStart);
249*6eef5f0cSAntonio Huete Jimenez 		return true;
250a34d5fb1SAntonio Huete Jimenez 	}
251a34d5fb1SAntonio Huete Jimenez 	cmd = cmdStart;
252a34d5fb1SAntonio Huete Jimenez 	LstNode_Set(ln, cmdStart);
253a34d5fb1SAntonio Huete Jimenez 
254a34d5fb1SAntonio Huete Jimenez 	if (gn->type & OP_SAVE_CMDS) {
255a34d5fb1SAntonio Huete Jimenez 		GNode *endNode = Targ_GetEndNode();
256a34d5fb1SAntonio Huete Jimenez 		if (gn != endNode) {
257a34d5fb1SAntonio Huete Jimenez 			/*
258a34d5fb1SAntonio Huete Jimenez 			 * Append the expanded command, to prevent the
259a34d5fb1SAntonio Huete Jimenez 			 * local variables from being interpreted in the
260a34d5fb1SAntonio Huete Jimenez 			 * scope of the .END node.
261a34d5fb1SAntonio Huete Jimenez 			 *
262a34d5fb1SAntonio Huete Jimenez 			 * A probably unintended side effect of this is that
263a34d5fb1SAntonio Huete Jimenez 			 * the expanded command will be expanded again in the
264a34d5fb1SAntonio Huete Jimenez 			 * .END node.  Therefore, a literal '$' in these
265a34d5fb1SAntonio Huete Jimenez 			 * commands must be written as '$$$$' instead of the
266a34d5fb1SAntonio Huete Jimenez 			 * usual '$$'.
267a34d5fb1SAntonio Huete Jimenez 			 */
268a34d5fb1SAntonio Huete Jimenez 			Lst_Append(&endNode->commands, cmdStart);
269*6eef5f0cSAntonio Huete Jimenez 			return true;
270a34d5fb1SAntonio Huete Jimenez 		}
271a34d5fb1SAntonio Huete Jimenez 	}
272a34d5fb1SAntonio Huete Jimenez 	if (strcmp(cmdStart, "...") == 0) {
273a34d5fb1SAntonio Huete Jimenez 		gn->type |= OP_SAVE_CMDS;
274*6eef5f0cSAntonio Huete Jimenez 		return true;
275a34d5fb1SAntonio Huete Jimenez 	}
276a34d5fb1SAntonio Huete Jimenez 
277a34d5fb1SAntonio Huete Jimenez 	for (;;) {
278a34d5fb1SAntonio Huete Jimenez 		if (*cmd == '@')
279a34d5fb1SAntonio Huete Jimenez 			silent = !DEBUG(LOUD);
280a34d5fb1SAntonio Huete Jimenez 		else if (*cmd == '-')
281*6eef5f0cSAntonio Huete Jimenez 			errCheck = false;
282a34d5fb1SAntonio Huete Jimenez 		else if (*cmd == '+') {
283*6eef5f0cSAntonio Huete Jimenez 			doIt = true;
284a34d5fb1SAntonio Huete Jimenez 			if (shellName == NULL)	/* we came here from jobs */
285a34d5fb1SAntonio Huete Jimenez 				Shell_Init();
286a34d5fb1SAntonio Huete Jimenez 		} else
287a34d5fb1SAntonio Huete Jimenez 			break;
288a34d5fb1SAntonio Huete Jimenez 		cmd++;
289a34d5fb1SAntonio Huete Jimenez 	}
290a34d5fb1SAntonio Huete Jimenez 
291a34d5fb1SAntonio Huete Jimenez 	while (ch_isspace(*cmd))
292a34d5fb1SAntonio Huete Jimenez 		cmd++;
293a34d5fb1SAntonio Huete Jimenez 
294a34d5fb1SAntonio Huete Jimenez 	/*
295a34d5fb1SAntonio Huete Jimenez 	 * If we did not end up with a command, just skip it.
296a34d5fb1SAntonio Huete Jimenez 	 */
297a34d5fb1SAntonio Huete Jimenez 	if (cmd[0] == '\0')
298*6eef5f0cSAntonio Huete Jimenez 		return true;
299a34d5fb1SAntonio Huete Jimenez 
300a34d5fb1SAntonio Huete Jimenez 	useShell = UseShell(cmd);
301a34d5fb1SAntonio Huete Jimenez 	/*
302a34d5fb1SAntonio Huete Jimenez 	 * Print the command before echoing if we're not supposed to be quiet
303a34d5fb1SAntonio Huete Jimenez 	 * for this one. We also print the command if -n given.
304a34d5fb1SAntonio Huete Jimenez 	 */
305a34d5fb1SAntonio Huete Jimenez 	if (!silent || !GNode_ShouldExecute(gn)) {
30601e196c8SJohn Marino 		printf("%s\n", cmd);
30701e196c8SJohn Marino 		fflush(stdout);
30801e196c8SJohn Marino 	}
30901e196c8SJohn Marino 
31001e196c8SJohn Marino 	/*
31101e196c8SJohn Marino 	 * If we're not supposed to execute any commands, this is as far as
31201e196c8SJohn Marino 	 * we go...
31301e196c8SJohn Marino 	 */
314a34d5fb1SAntonio Huete Jimenez 	if (!doIt && !GNode_ShouldExecute(gn))
315*6eef5f0cSAntonio Huete Jimenez 		return true;
31601e196c8SJohn Marino 
317a34d5fb1SAntonio Huete Jimenez 	DEBUG1(JOB, "Execute: '%s'\n", cmd);
318a34d5fb1SAntonio Huete Jimenez 
31901e196c8SJohn Marino 	if (useShell) {
32001e196c8SJohn Marino 		/*
32101e196c8SJohn Marino 		 * We need to pass the command off to the shell, typically
32201e196c8SJohn Marino 		 * because the command contains a "meta" character.
32301e196c8SJohn Marino 		 */
3245f1e34d9SAlexandre Perrin 		static const char *shargv[5];
32501e196c8SJohn Marino 
326a34d5fb1SAntonio Huete Jimenez 		/* The following work for any of the builtin shell specs. */
327a34d5fb1SAntonio Huete Jimenez 		int shargc = 0;
3285f1e34d9SAlexandre Perrin 		shargv[shargc++] = shellPath;
329a34d5fb1SAntonio Huete Jimenez 		if (errCheck && shellErrFlag != NULL)
3305f1e34d9SAlexandre Perrin 			shargv[shargc++] = shellErrFlag;
331a34d5fb1SAntonio Huete Jimenez 		shargv[shargc++] = DEBUG(SHELL) ? "-xc" : "-c";
3325f1e34d9SAlexandre Perrin 		shargv[shargc++] = cmd;
333a34d5fb1SAntonio Huete Jimenez 		shargv[shargc] = NULL;
33401e196c8SJohn Marino 		av = shargv;
33501e196c8SJohn Marino 		bp = NULL;
33601e196c8SJohn Marino 		mav = NULL;
33701e196c8SJohn Marino 	} else {
33801e196c8SJohn Marino 		/*
339a34d5fb1SAntonio Huete Jimenez 		 * No meta-characters, so no need to exec a shell. Break the
340a34d5fb1SAntonio Huete Jimenez 		 * command into words to form an argument vector we can
341a34d5fb1SAntonio Huete Jimenez 		 * execute.
34201e196c8SJohn Marino 		 */
343*6eef5f0cSAntonio Huete Jimenez 		Words words = Str_Words(cmd, false);
344a34d5fb1SAntonio Huete Jimenez 		mav = words.words;
345a34d5fb1SAntonio Huete Jimenez 		bp = words.freeIt;
34601e196c8SJohn Marino 		av = (void *)mav;
34701e196c8SJohn Marino 	}
34801e196c8SJohn Marino 
34901e196c8SJohn Marino #ifdef USE_META
350*6eef5f0cSAntonio Huete Jimenez 	if (useMeta)
35101e196c8SJohn Marino 		meta_compat_start();
35201e196c8SJohn Marino #endif
35301e196c8SJohn Marino 
354a34d5fb1SAntonio Huete Jimenez 	Var_ReexportVars();
355a34d5fb1SAntonio Huete Jimenez 
356a34d5fb1SAntonio Huete Jimenez 	compatChild = cpid = vfork();
357*6eef5f0cSAntonio Huete Jimenez 	if (cpid < 0)
35801e196c8SJohn Marino 		Fatal("Could not fork");
359*6eef5f0cSAntonio Huete Jimenez 
36001e196c8SJohn Marino 	if (cpid == 0) {
36101e196c8SJohn Marino #ifdef USE_META
362*6eef5f0cSAntonio Huete Jimenez 		if (useMeta)
36301e196c8SJohn Marino 			meta_compat_child();
36401e196c8SJohn Marino #endif
36501e196c8SJohn Marino 		(void)execvp(av[0], (char *const *)UNCONST(av));
366a34d5fb1SAntonio Huete Jimenez 		execDie("exec", av[0]);
36701e196c8SJohn Marino 	}
368f445c897SJohn Marino 
36901e196c8SJohn Marino 	free(mav);
37001e196c8SJohn Marino 	free(bp);
371f445c897SJohn Marino 
372a34d5fb1SAntonio Huete Jimenez 	/* XXX: Memory management looks suspicious here. */
373a34d5fb1SAntonio Huete Jimenez 	/* XXX: Setting a list item to NULL is unexpected. */
374a34d5fb1SAntonio Huete Jimenez 	LstNode_SetNull(ln);
37501e196c8SJohn Marino 
37601e196c8SJohn Marino #ifdef USE_META
377*6eef5f0cSAntonio Huete Jimenez 	if (useMeta)
378ca58f742SDaniel Fojt 		meta_compat_parent(cpid);
37901e196c8SJohn Marino #endif
38001e196c8SJohn Marino 
38101e196c8SJohn Marino 	/*
38201e196c8SJohn Marino 	 * The child is off and running. Now all we can do is wait...
38301e196c8SJohn Marino 	 */
38401e196c8SJohn Marino 	while ((retstat = wait(&reason)) != cpid) {
38501e196c8SJohn Marino 		if (retstat > 0)
386*6eef5f0cSAntonio Huete Jimenez 			JobReapChild(retstat, reason, false); /* not ours? */
38701e196c8SJohn Marino 		if (retstat == -1 && errno != EINTR) {
38801e196c8SJohn Marino 			break;
38901e196c8SJohn Marino 		}
39001e196c8SJohn Marino 	}
39101e196c8SJohn Marino 
392a34d5fb1SAntonio Huete Jimenez 	if (retstat < 0)
393a34d5fb1SAntonio Huete Jimenez 		Fatal("error in wait: %d: %s", retstat, strerror(errno));
394a34d5fb1SAntonio Huete Jimenez 
39501e196c8SJohn Marino 	if (WIFSTOPPED(reason)) {
39601e196c8SJohn Marino 		status = WSTOPSIG(reason);	/* stopped */
39701e196c8SJohn Marino 	} else if (WIFEXITED(reason)) {
39801e196c8SJohn Marino 		status = WEXITSTATUS(reason);	/* exited */
39901e196c8SJohn Marino #if defined(USE_META) && defined(USE_FILEMON_ONCE)
400*6eef5f0cSAntonio Huete Jimenez 		if (useMeta)
40101e196c8SJohn Marino 			meta_cmd_finish(NULL);
40201e196c8SJohn Marino #endif
40301e196c8SJohn Marino 		if (status != 0) {
404a34d5fb1SAntonio Huete Jimenez 			if (DEBUG(ERROR))
405a34d5fb1SAntonio Huete Jimenez 				DebugFailedTarget(cmd, gn);
40601e196c8SJohn Marino 			printf("*** Error code %d", status);
40701e196c8SJohn Marino 		}
40801e196c8SJohn Marino 	} else {
40901e196c8SJohn Marino 		status = WTERMSIG(reason);	/* signaled */
41001e196c8SJohn Marino 		printf("*** Signal %d", status);
41101e196c8SJohn Marino 	}
41201e196c8SJohn Marino 
41301e196c8SJohn Marino 
414a34d5fb1SAntonio Huete Jimenez 	if (!WIFEXITED(reason) || status != 0) {
41501e196c8SJohn Marino 		if (errCheck) {
41601e196c8SJohn Marino #ifdef USE_META
417*6eef5f0cSAntonio Huete Jimenez 			if (useMeta)
418*6eef5f0cSAntonio Huete Jimenez 				meta_job_error(NULL, gn, false, status);
41901e196c8SJohn Marino #endif
42001e196c8SJohn Marino 			gn->made = ERROR;
421a34d5fb1SAntonio Huete Jimenez 			if (opts.keepgoing) {
42201e196c8SJohn Marino 				/*
423a34d5fb1SAntonio Huete Jimenez 				 * Abort the current target,
424a34d5fb1SAntonio Huete Jimenez 				 * but let others continue.
42501e196c8SJohn Marino 				 */
42601e196c8SJohn Marino 				printf(" (continuing)\n");
427ca58f742SDaniel Fojt 			} else {
428ca58f742SDaniel Fojt 				printf("\n");
429ca58f742SDaniel Fojt 			}
430a34d5fb1SAntonio Huete Jimenez 			if (deleteOnError)
431ca58f742SDaniel Fojt 				CompatDeleteTarget(gn);
43201e196c8SJohn Marino 		} else {
43301e196c8SJohn Marino 			/*
43401e196c8SJohn Marino 			 * Continue executing commands for this target.
43501e196c8SJohn Marino 			 * If we return 0, this will happen...
43601e196c8SJohn Marino 			 */
43701e196c8SJohn Marino 			printf(" (ignored)\n");
43801e196c8SJohn Marino 			status = 0;
43901e196c8SJohn Marino 		}
44001e196c8SJohn Marino 	}
441a34d5fb1SAntonio Huete Jimenez 
44201e196c8SJohn Marino 	free(cmdStart);
443ca58f742SDaniel Fojt 	compatChild = 0;
444a34d5fb1SAntonio Huete Jimenez 	if (compatSigno != 0) {
445ca58f742SDaniel Fojt 		bmake_signal(compatSigno, SIG_DFL);
446ca58f742SDaniel Fojt 		kill(myPid, compatSigno);
447ca58f742SDaniel Fojt 	}
44801e196c8SJohn Marino 
449*6eef5f0cSAntonio Huete Jimenez 	return status == 0;
45001e196c8SJohn Marino }
45101e196c8SJohn Marino 
452a34d5fb1SAntonio Huete Jimenez static void
RunCommands(GNode * gn)453a34d5fb1SAntonio Huete Jimenez RunCommands(GNode *gn)
454a34d5fb1SAntonio Huete Jimenez {
455a34d5fb1SAntonio Huete Jimenez 	StringListNode *ln;
456a34d5fb1SAntonio Huete Jimenez 
457a34d5fb1SAntonio Huete Jimenez 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
458a34d5fb1SAntonio Huete Jimenez 		const char *cmd = ln->datum;
459*6eef5f0cSAntonio Huete Jimenez 		if (!Compat_RunCommand(cmd, gn, ln))
460a34d5fb1SAntonio Huete Jimenez 			break;
461a34d5fb1SAntonio Huete Jimenez 	}
462a34d5fb1SAntonio Huete Jimenez }
463a34d5fb1SAntonio Huete Jimenez 
464a34d5fb1SAntonio Huete Jimenez static void
MakeInRandomOrder(GNode ** gnodes,GNode ** end,GNode * pgn)465*6eef5f0cSAntonio Huete Jimenez MakeInRandomOrder(GNode **gnodes, GNode **end, GNode *pgn)
466*6eef5f0cSAntonio Huete Jimenez {
467*6eef5f0cSAntonio Huete Jimenez 	GNode **it;
468*6eef5f0cSAntonio Huete Jimenez 	size_t r;
469*6eef5f0cSAntonio Huete Jimenez 
470*6eef5f0cSAntonio Huete Jimenez 	for (r = (size_t)(end - gnodes); r >= 2; r--) {
471*6eef5f0cSAntonio Huete Jimenez 		/* Biased, but irrelevant in practice. */
472*6eef5f0cSAntonio Huete Jimenez 		size_t i = (size_t)random() % r;
473*6eef5f0cSAntonio Huete Jimenez 		GNode *t = gnodes[r - 1];
474*6eef5f0cSAntonio Huete Jimenez 		gnodes[r - 1] = gnodes[i];
475*6eef5f0cSAntonio Huete Jimenez 		gnodes[i] = t;
476*6eef5f0cSAntonio Huete Jimenez 	}
477*6eef5f0cSAntonio Huete Jimenez 
478*6eef5f0cSAntonio Huete Jimenez 	for (it = gnodes; it != end; it++)
479*6eef5f0cSAntonio Huete Jimenez 		Compat_Make(*it, pgn);
480*6eef5f0cSAntonio Huete Jimenez }
481*6eef5f0cSAntonio Huete Jimenez 
482*6eef5f0cSAntonio Huete Jimenez static void
MakeWaitGroupsInRandomOrder(GNodeList * gnodes,GNode * pgn)483*6eef5f0cSAntonio Huete Jimenez MakeWaitGroupsInRandomOrder(GNodeList *gnodes, GNode *pgn)
484*6eef5f0cSAntonio Huete Jimenez {
485*6eef5f0cSAntonio Huete Jimenez 	Vector vec;
486*6eef5f0cSAntonio Huete Jimenez 	GNodeListNode *ln;
487*6eef5f0cSAntonio Huete Jimenez 	GNode **nodes;
488*6eef5f0cSAntonio Huete Jimenez 	size_t i, n, start;
489*6eef5f0cSAntonio Huete Jimenez 
490*6eef5f0cSAntonio Huete Jimenez 	Vector_Init(&vec, sizeof(GNode *));
491*6eef5f0cSAntonio Huete Jimenez 	for (ln = gnodes->first; ln != NULL; ln = ln->next)
492*6eef5f0cSAntonio Huete Jimenez 		*(GNode **)Vector_Push(&vec) = ln->datum;
493*6eef5f0cSAntonio Huete Jimenez 	nodes = vec.items;
494*6eef5f0cSAntonio Huete Jimenez 	n = vec.len;
495*6eef5f0cSAntonio Huete Jimenez 
496*6eef5f0cSAntonio Huete Jimenez 	start = 0;
497*6eef5f0cSAntonio Huete Jimenez 	for (i = 0; i < n; i++) {
498*6eef5f0cSAntonio Huete Jimenez 		if (nodes[i]->type & OP_WAIT) {
499*6eef5f0cSAntonio Huete Jimenez 			MakeInRandomOrder(nodes + start, nodes + i, pgn);
500*6eef5f0cSAntonio Huete Jimenez 			Compat_Make(nodes[i], pgn);
501*6eef5f0cSAntonio Huete Jimenez 			start = i + 1;
502*6eef5f0cSAntonio Huete Jimenez 		}
503*6eef5f0cSAntonio Huete Jimenez 	}
504*6eef5f0cSAntonio Huete Jimenez 	MakeInRandomOrder(nodes + start, nodes + i, pgn);
505*6eef5f0cSAntonio Huete Jimenez 
506*6eef5f0cSAntonio Huete Jimenez 	Vector_Done(&vec);
507*6eef5f0cSAntonio Huete Jimenez }
508*6eef5f0cSAntonio Huete Jimenez 
509*6eef5f0cSAntonio Huete Jimenez static void
MakeNodes(GNodeList * gnodes,GNode * pgn)510a34d5fb1SAntonio Huete Jimenez MakeNodes(GNodeList *gnodes, GNode *pgn)
511a34d5fb1SAntonio Huete Jimenez {
512a34d5fb1SAntonio Huete Jimenez 	GNodeListNode *ln;
513a34d5fb1SAntonio Huete Jimenez 
514*6eef5f0cSAntonio Huete Jimenez 	if (Lst_IsEmpty(gnodes))
515*6eef5f0cSAntonio Huete Jimenez 		return;
516*6eef5f0cSAntonio Huete Jimenez 	if (opts.randomizeTargets) {
517*6eef5f0cSAntonio Huete Jimenez 		MakeWaitGroupsInRandomOrder(gnodes, pgn);
518*6eef5f0cSAntonio Huete Jimenez 		return;
519*6eef5f0cSAntonio Huete Jimenez 	}
520*6eef5f0cSAntonio Huete Jimenez 
521a34d5fb1SAntonio Huete Jimenez 	for (ln = gnodes->first; ln != NULL; ln = ln->next) {
522*6eef5f0cSAntonio Huete Jimenez 		GNode *cgn = ln->datum;
523*6eef5f0cSAntonio Huete Jimenez 		Compat_Make(cgn, pgn);
524a34d5fb1SAntonio Huete Jimenez 	}
525a34d5fb1SAntonio Huete Jimenez }
526a34d5fb1SAntonio Huete Jimenez 
527*6eef5f0cSAntonio Huete Jimenez static bool
MakeUnmade(GNode * gn,GNode * pgn)528a34d5fb1SAntonio Huete Jimenez MakeUnmade(GNode *gn, GNode *pgn)
529a34d5fb1SAntonio Huete Jimenez {
530a34d5fb1SAntonio Huete Jimenez 
531a34d5fb1SAntonio Huete Jimenez 	assert(gn->made == UNMADE);
532a34d5fb1SAntonio Huete Jimenez 
53301e196c8SJohn Marino 	/*
53401e196c8SJohn Marino 	 * First mark ourselves to be made, then apply whatever transformations
53501e196c8SJohn Marino 	 * the suffix module thinks are necessary. Once that's done, we can
53601e196c8SJohn Marino 	 * descend and make all our children. If any of them has an error
537*6eef5f0cSAntonio Huete Jimenez 	 * but the -k flag was given, our 'make' field will be set to false
538a34d5fb1SAntonio Huete Jimenez 	 * again. This is our signal to not attempt to do anything but abort
539a34d5fb1SAntonio Huete Jimenez 	 * our parent as well.
54001e196c8SJohn Marino 	 */
541*6eef5f0cSAntonio Huete Jimenez 	gn->flags.remake = true;
54201e196c8SJohn Marino 	gn->made = BEINGMADE;
543a34d5fb1SAntonio Huete Jimenez 
544a34d5fb1SAntonio Huete Jimenez 	if (!(gn->type & OP_MADE))
54501e196c8SJohn Marino 		Suff_FindDeps(gn);
546a34d5fb1SAntonio Huete Jimenez 
547a34d5fb1SAntonio Huete Jimenez 	MakeNodes(&gn->children, gn);
548a34d5fb1SAntonio Huete Jimenez 
549*6eef5f0cSAntonio Huete Jimenez 	if (!gn->flags.remake) {
55001e196c8SJohn Marino 		gn->made = ABORTED;
551*6eef5f0cSAntonio Huete Jimenez 		pgn->flags.remake = false;
552*6eef5f0cSAntonio Huete Jimenez 		return false;
55301e196c8SJohn Marino 	}
55401e196c8SJohn Marino 
555a34d5fb1SAntonio Huete Jimenez 	if (Lst_FindDatum(&gn->implicitParents, pgn) != NULL)
556a34d5fb1SAntonio Huete Jimenez 		Var_Set(pgn, IMPSRC, GNode_VarTarget(gn));
55701e196c8SJohn Marino 
55801e196c8SJohn Marino 	/*
559a34d5fb1SAntonio Huete Jimenez 	 * All the children were made ok. Now youngestChild->mtime contains the
56001e196c8SJohn Marino 	 * modification time of the newest child, we need to find out if we
56101e196c8SJohn Marino 	 * exist and when we were modified last. The criteria for datedness
562a34d5fb1SAntonio Huete Jimenez 	 * are defined by GNode_IsOODate.
56301e196c8SJohn Marino 	 */
564a34d5fb1SAntonio Huete Jimenez 	DEBUG1(MAKE, "Examining %s...", gn->name);
565a34d5fb1SAntonio Huete Jimenez 	if (!GNode_IsOODate(gn)) {
56601e196c8SJohn Marino 		gn->made = UPTODATE;
567a34d5fb1SAntonio Huete Jimenez 		DEBUG0(MAKE, "up-to-date.\n");
568*6eef5f0cSAntonio Huete Jimenez 		return false;
56901e196c8SJohn Marino 	}
57001e196c8SJohn Marino 
57101e196c8SJohn Marino 	/*
57201e196c8SJohn Marino 	 * If the user is just seeing if something is out-of-date, exit now
57301e196c8SJohn Marino 	 * to tell him/her "yes".
57401e196c8SJohn Marino 	 */
575a34d5fb1SAntonio Huete Jimenez 	DEBUG0(MAKE, "out-of-date.\n");
576*6eef5f0cSAntonio Huete Jimenez 	if (opts.query && gn != Targ_GetEndNode())
57701e196c8SJohn Marino 		exit(1);
57801e196c8SJohn Marino 
57901e196c8SJohn Marino 	/*
580a34d5fb1SAntonio Huete Jimenez 	 * We need to be re-made.
581a34d5fb1SAntonio Huete Jimenez 	 * Ensure that $? (.OODATE) and $> (.ALLSRC) are both set.
58201e196c8SJohn Marino 	 */
583*6eef5f0cSAntonio Huete Jimenez 	GNode_SetLocalVars(gn);
58401e196c8SJohn Marino 
58501e196c8SJohn Marino 	/*
58601e196c8SJohn Marino 	 * Alter our type to tell if errors should be ignored or things
587a34d5fb1SAntonio Huete Jimenez 	 * should not be printed so Compat_RunCommand knows what to do.
58801e196c8SJohn Marino 	 */
589a34d5fb1SAntonio Huete Jimenez 	if (opts.ignoreErrors)
59001e196c8SJohn Marino 		gn->type |= OP_IGNORE;
591*6eef5f0cSAntonio Huete Jimenez 	if (opts.silent)
59201e196c8SJohn Marino 		gn->type |= OP_SILENT;
59301e196c8SJohn Marino 
59401e196c8SJohn Marino 	if (Job_CheckCommands(gn, Fatal)) {
59501e196c8SJohn Marino 		/*
596a34d5fb1SAntonio Huete Jimenez 		 * Our commands are ok, but we still have to worry about
597a34d5fb1SAntonio Huete Jimenez 		 * the -t flag.
59801e196c8SJohn Marino 		 */
599*6eef5f0cSAntonio Huete Jimenez 		if (!opts.touch || (gn->type & OP_MAKE)) {
60001e196c8SJohn Marino 			curTarg = gn;
60101e196c8SJohn Marino #ifdef USE_META
602*6eef5f0cSAntonio Huete Jimenez 			if (useMeta && GNode_ShouldExecute(gn))
60301e196c8SJohn Marino 				meta_job_start(NULL, gn);
60401e196c8SJohn Marino #endif
605a34d5fb1SAntonio Huete Jimenez 			RunCommands(gn);
60601e196c8SJohn Marino 			curTarg = NULL;
60701e196c8SJohn Marino 		} else {
608*6eef5f0cSAntonio Huete Jimenez 			Job_Touch(gn, (gn->type & OP_SILENT) != OP_NONE);
60901e196c8SJohn Marino 		}
61001e196c8SJohn Marino 	} else {
61101e196c8SJohn Marino 		gn->made = ERROR;
61201e196c8SJohn Marino 	}
61301e196c8SJohn Marino #ifdef USE_META
614a34d5fb1SAntonio Huete Jimenez 	if (useMeta && GNode_ShouldExecute(gn)) {
615f445c897SJohn Marino 		if (meta_job_finish(NULL) != 0)
616f445c897SJohn Marino 			gn->made = ERROR;
61701e196c8SJohn Marino 	}
61801e196c8SJohn Marino #endif
61901e196c8SJohn Marino 
62001e196c8SJohn Marino 	if (gn->made != ERROR) {
62101e196c8SJohn Marino 		/*
62201e196c8SJohn Marino 		 * If the node was made successfully, mark it so, update
623a34d5fb1SAntonio Huete Jimenez 		 * its modification time and timestamp all its parents.
62401e196c8SJohn Marino 		 * This is to keep its state from affecting that of its parent.
62501e196c8SJohn Marino 		 */
62601e196c8SJohn Marino 		gn->made = MADE;
627a34d5fb1SAntonio Huete Jimenez 		if (Make_Recheck(gn) == 0)
628*6eef5f0cSAntonio Huete Jimenez 			pgn->flags.force = true;
62901e196c8SJohn Marino 		if (!(gn->type & OP_EXEC)) {
630*6eef5f0cSAntonio Huete Jimenez 			pgn->flags.childMade = true;
631a34d5fb1SAntonio Huete Jimenez 			GNode_UpdateYoungestChild(pgn, gn);
63201e196c8SJohn Marino 		}
633a34d5fb1SAntonio Huete Jimenez 	} else if (opts.keepgoing) {
634*6eef5f0cSAntonio Huete Jimenez 		pgn->flags.remake = false;
63501e196c8SJohn Marino 	} else {
636*6eef5f0cSAntonio Huete Jimenez 		PrintOnError(gn, "\nStop.\n");
63701e196c8SJohn Marino 		exit(1);
63801e196c8SJohn Marino 	}
639*6eef5f0cSAntonio Huete Jimenez 	return true;
64001e196c8SJohn Marino }
641a34d5fb1SAntonio Huete Jimenez 
642a34d5fb1SAntonio Huete Jimenez static void
MakeOther(GNode * gn,GNode * pgn)643a34d5fb1SAntonio Huete Jimenez MakeOther(GNode *gn, GNode *pgn)
644a34d5fb1SAntonio Huete Jimenez {
645a34d5fb1SAntonio Huete Jimenez 
646a34d5fb1SAntonio Huete Jimenez 	if (Lst_FindDatum(&gn->implicitParents, pgn) != NULL) {
647a34d5fb1SAntonio Huete Jimenez 		const char *target = GNode_VarTarget(gn);
648a34d5fb1SAntonio Huete Jimenez 		Var_Set(pgn, IMPSRC, target != NULL ? target : "");
649a34d5fb1SAntonio Huete Jimenez 	}
650a34d5fb1SAntonio Huete Jimenez 
65101e196c8SJohn Marino 	switch (gn->made) {
65201e196c8SJohn Marino 	case BEINGMADE:
65301e196c8SJohn Marino 		Error("Graph cycles through %s", gn->name);
65401e196c8SJohn Marino 		gn->made = ERROR;
655*6eef5f0cSAntonio Huete Jimenez 		pgn->flags.remake = false;
65601e196c8SJohn Marino 		break;
65701e196c8SJohn Marino 	case MADE:
658a34d5fb1SAntonio Huete Jimenez 		if (!(gn->type & OP_EXEC)) {
659*6eef5f0cSAntonio Huete Jimenez 			pgn->flags.childMade = true;
660a34d5fb1SAntonio Huete Jimenez 			GNode_UpdateYoungestChild(pgn, gn);
66101e196c8SJohn Marino 		}
66201e196c8SJohn Marino 		break;
66301e196c8SJohn Marino 	case UPTODATE:
664a34d5fb1SAntonio Huete Jimenez 		if (!(gn->type & OP_EXEC))
665a34d5fb1SAntonio Huete Jimenez 			GNode_UpdateYoungestChild(pgn, gn);
66601e196c8SJohn Marino 		break;
66701e196c8SJohn Marino 	default:
66801e196c8SJohn Marino 		break;
66901e196c8SJohn Marino 	}
67001e196c8SJohn Marino }
67101e196c8SJohn Marino 
672a34d5fb1SAntonio Huete Jimenez /*
673a34d5fb1SAntonio Huete Jimenez  * Make a target.
674a34d5fb1SAntonio Huete Jimenez  *
675a34d5fb1SAntonio Huete Jimenez  * If an error is detected and not being ignored, the process exits.
67601e196c8SJohn Marino  *
67701e196c8SJohn Marino  * Input:
678a34d5fb1SAntonio Huete Jimenez  *	gn		The node to make
679a34d5fb1SAntonio Huete Jimenez  *	pgn		Parent to abort if necessary
68001e196c8SJohn Marino  *
681a34d5fb1SAntonio Huete Jimenez  * Output:
682a34d5fb1SAntonio Huete Jimenez  *	gn->made
683a34d5fb1SAntonio Huete Jimenez  *		UPTODATE	gn was already up-to-date.
684a34d5fb1SAntonio Huete Jimenez  *		MADE		gn was recreated successfully.
685a34d5fb1SAntonio Huete Jimenez  *		ERROR		An error occurred while gn was being created,
686a34d5fb1SAntonio Huete Jimenez  *				either due to missing commands or in -k mode.
687a34d5fb1SAntonio Huete Jimenez  *		ABORTED		gn was not remade because one of its
688a34d5fb1SAntonio Huete Jimenez  *				dependencies could not be made due to errors.
68901e196c8SJohn Marino  */
69001e196c8SJohn Marino void
Compat_Make(GNode * gn,GNode * pgn)691a34d5fb1SAntonio Huete Jimenez Compat_Make(GNode *gn, GNode *pgn)
69201e196c8SJohn Marino {
693a34d5fb1SAntonio Huete Jimenez 	if (shellName == NULL)	/* we came here from jobs */
694f445c897SJohn Marino 		Shell_Init();
69501e196c8SJohn Marino 
696a34d5fb1SAntonio Huete Jimenez 	if (gn->made == UNMADE && (gn == pgn || !(pgn->type & OP_MADE))) {
697a34d5fb1SAntonio Huete Jimenez 		if (!MakeUnmade(gn, pgn))
698a34d5fb1SAntonio Huete Jimenez 			goto cohorts;
699a34d5fb1SAntonio Huete Jimenez 
700a34d5fb1SAntonio Huete Jimenez 		/* XXX: Replace with GNode_IsError(gn) */
701a34d5fb1SAntonio Huete Jimenez 	} else if (gn->made == ERROR) {
702a34d5fb1SAntonio Huete Jimenez 		/*
703a34d5fb1SAntonio Huete Jimenez 		 * Already had an error when making this.
704a34d5fb1SAntonio Huete Jimenez 		 * Tell the parent to abort.
705a34d5fb1SAntonio Huete Jimenez 		 */
706*6eef5f0cSAntonio Huete Jimenez 		pgn->flags.remake = false;
707a34d5fb1SAntonio Huete Jimenez 	} else {
708a34d5fb1SAntonio Huete Jimenez 		MakeOther(gn, pgn);
70901e196c8SJohn Marino 	}
71001e196c8SJohn Marino 
711a34d5fb1SAntonio Huete Jimenez cohorts:
712a34d5fb1SAntonio Huete Jimenez 	MakeNodes(&gn->cohorts, pgn);
713a34d5fb1SAntonio Huete Jimenez }
714a34d5fb1SAntonio Huete Jimenez 
715a34d5fb1SAntonio Huete Jimenez static void
MakeBeginNode(void)716a34d5fb1SAntonio Huete Jimenez MakeBeginNode(void)
717a34d5fb1SAntonio Huete Jimenez {
718a34d5fb1SAntonio Huete Jimenez 	GNode *gn = Targ_FindNode(".BEGIN");
719a34d5fb1SAntonio Huete Jimenez 	if (gn == NULL)
720a34d5fb1SAntonio Huete Jimenez 		return;
721a34d5fb1SAntonio Huete Jimenez 
72201e196c8SJohn Marino 	Compat_Make(gn, gn);
723a34d5fb1SAntonio Huete Jimenez 	if (GNode_IsError(gn)) {
724*6eef5f0cSAntonio Huete Jimenez 		PrintOnError(gn, "\nStop.\n");
72501e196c8SJohn Marino 		exit(1);
72601e196c8SJohn Marino 	}
72701e196c8SJohn Marino }
728a34d5fb1SAntonio Huete Jimenez 
729a34d5fb1SAntonio Huete Jimenez static void
InitSignals(void)730a34d5fb1SAntonio Huete Jimenez InitSignals(void)
731a34d5fb1SAntonio Huete Jimenez {
732a34d5fb1SAntonio Huete Jimenez 	if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN)
733a34d5fb1SAntonio Huete Jimenez 		bmake_signal(SIGINT, CompatInterrupt);
734a34d5fb1SAntonio Huete Jimenez 	if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN)
735a34d5fb1SAntonio Huete Jimenez 		bmake_signal(SIGTERM, CompatInterrupt);
736a34d5fb1SAntonio Huete Jimenez 	if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN)
737a34d5fb1SAntonio Huete Jimenez 		bmake_signal(SIGHUP, CompatInterrupt);
738a34d5fb1SAntonio Huete Jimenez 	if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN)
739a34d5fb1SAntonio Huete Jimenez 		bmake_signal(SIGQUIT, CompatInterrupt);
74001e196c8SJohn Marino }
74101e196c8SJohn Marino 
742a34d5fb1SAntonio Huete Jimenez void
Compat_MakeAll(GNodeList * targs)743*6eef5f0cSAntonio Huete Jimenez Compat_MakeAll(GNodeList *targs)
744a34d5fb1SAntonio Huete Jimenez {
745a34d5fb1SAntonio Huete Jimenez 	GNode *errorNode = NULL;
746a34d5fb1SAntonio Huete Jimenez 
747a34d5fb1SAntonio Huete Jimenez 	if (shellName == NULL)
748a34d5fb1SAntonio Huete Jimenez 		Shell_Init();
749a34d5fb1SAntonio Huete Jimenez 
750a34d5fb1SAntonio Huete Jimenez 	InitSignals();
751a34d5fb1SAntonio Huete Jimenez 
752*6eef5f0cSAntonio Huete Jimenez 	/*
753*6eef5f0cSAntonio Huete Jimenez 	 * Create the .END node now, to keep the (debug) output of the
754*6eef5f0cSAntonio Huete Jimenez 	 * counter.mk test the same as before 2020-09-23.  This
755*6eef5f0cSAntonio Huete Jimenez 	 * implementation detail probably doesn't matter though.
756*6eef5f0cSAntonio Huete Jimenez 	 */
757a34d5fb1SAntonio Huete Jimenez 	(void)Targ_GetEndNode();
758a34d5fb1SAntonio Huete Jimenez 
759*6eef5f0cSAntonio Huete Jimenez 	if (!opts.query)
760a34d5fb1SAntonio Huete Jimenez 		MakeBeginNode();
761a34d5fb1SAntonio Huete Jimenez 
762a34d5fb1SAntonio Huete Jimenez 	/*
76301e196c8SJohn Marino 	 * Expand .USE nodes right now, because they can modify the structure
76401e196c8SJohn Marino 	 * of the tree.
76501e196c8SJohn Marino 	 */
76601e196c8SJohn Marino 	Make_ExpandUse(targs);
76701e196c8SJohn Marino 
76801e196c8SJohn Marino 	while (!Lst_IsEmpty(targs)) {
769a34d5fb1SAntonio Huete Jimenez 		GNode *gn = Lst_Dequeue(targs);
77001e196c8SJohn Marino 		Compat_Make(gn, gn);
77101e196c8SJohn Marino 
77201e196c8SJohn Marino 		if (gn->made == UPTODATE) {
77301e196c8SJohn Marino 			printf("`%s' is up to date.\n", gn->name);
77401e196c8SJohn Marino 		} else if (gn->made == ABORTED) {
775a34d5fb1SAntonio Huete Jimenez 			printf("`%s' not remade because of errors.\n",
776a34d5fb1SAntonio Huete Jimenez 			    gn->name);
77701e196c8SJohn Marino 		}
778a34d5fb1SAntonio Huete Jimenez 		if (GNode_IsError(gn) && errorNode == NULL)
779a34d5fb1SAntonio Huete Jimenez 			errorNode = gn;
78001e196c8SJohn Marino 	}
78101e196c8SJohn Marino 
782a34d5fb1SAntonio Huete Jimenez 	/* If the user has defined a .END target, run its commands. */
783a34d5fb1SAntonio Huete Jimenez 	if (errorNode == NULL) {
784a34d5fb1SAntonio Huete Jimenez 		GNode *endNode = Targ_GetEndNode();
785a34d5fb1SAntonio Huete Jimenez 		Compat_Make(endNode, endNode);
786a34d5fb1SAntonio Huete Jimenez 		if (GNode_IsError(endNode))
787a34d5fb1SAntonio Huete Jimenez 			errorNode = endNode;
78801e196c8SJohn Marino 	}
789a34d5fb1SAntonio Huete Jimenez 
790a34d5fb1SAntonio Huete Jimenez 	if (errorNode != NULL) {
791a34d5fb1SAntonio Huete Jimenez 		if (DEBUG(GRAPH2))
792a34d5fb1SAntonio Huete Jimenez 			Targ_PrintGraph(2);
793a34d5fb1SAntonio Huete Jimenez 		else if (DEBUG(GRAPH3))
794a34d5fb1SAntonio Huete Jimenez 			Targ_PrintGraph(3);
795*6eef5f0cSAntonio Huete Jimenez 		PrintOnError(errorNode, "\nStop.\n");
796a34d5fb1SAntonio Huete Jimenez 		exit(1);
79701e196c8SJohn Marino 	}
79801e196c8SJohn Marino }
799