From owner-dev-commits-src-all@freebsd.org Fri Jun 25 23:01:54 2021 Return-Path: Delivered-To: dev-commits-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 9B82E6451B6; Fri, 25 Jun 2021 23:01:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4GBXZB3kWSz3jYN; Fri, 25 Jun 2021 23:01:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 6835613F12; Fri, 25 Jun 2021 23:01:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 15PN1s31041012; Fri, 25 Jun 2021 23:01:54 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 15PN1sla041011; Fri, 25 Jun 2021 23:01:54 GMT (envelope-from git) Date: Fri, 25 Jun 2021 23:01:54 GMT Message-Id: <202106252301.15PN1sla041011@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Simon J. Gerraty" Subject: git: b0c40a00a67f - main - Merge commit 'ee914ef902ae018bd4f67192832120f9bf05651f' into new_merge MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: sjg X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: b0c40a00a67f611868fc0f10bde6b28eb75931be Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 25 Jun 2021 23:01:54 -0000 The branch main has been updated by sjg: URL: https://cgit.FreeBSD.org/src/commit/?id=b0c40a00a67f611868fc0f10bde6b28eb75931be commit b0c40a00a67f611868fc0f10bde6b28eb75931be Merge: cab31e0e216c ee914ef902ae Author: Simon J. Gerraty AuthorDate: 2021-06-25 21:31:14 +0000 Commit: Simon J. Gerraty CommitDate: 2021-06-25 21:31:14 +0000 Merge commit 'ee914ef902ae018bd4f67192832120f9bf05651f' into new_merge contrib/bmake/ChangeLog | 113 + contrib/bmake/FILES | 13 + contrib/bmake/VERSION | 2 +- contrib/bmake/arch.c | 104 +- contrib/bmake/buf.h | 4 +- contrib/bmake/compat.c | 42 +- contrib/bmake/cond.c | 279 +- contrib/bmake/dir.c | 62 +- contrib/bmake/dir.h | 6 +- contrib/bmake/enum.h | 62 +- contrib/bmake/for.c | 46 +- contrib/bmake/hash.c | 68 +- contrib/bmake/hash.h | 14 +- contrib/bmake/import.sh | 17 +- contrib/bmake/job.c | 423 +-- contrib/bmake/job.h | 20 +- contrib/bmake/lst.c | 10 +- contrib/bmake/lst.h | 12 +- contrib/bmake/main.c | 250 +- contrib/bmake/make.c | 91 +- contrib/bmake/make.h | 129 +- contrib/bmake/meta.c | 194 +- contrib/bmake/meta.h | 8 +- contrib/bmake/metachar.h | 4 +- contrib/bmake/mk/ChangeLog | 35 + contrib/bmake/mk/dirdeps.mk | 76 +- contrib/bmake/mk/dpadd.mk | 7 +- contrib/bmake/mk/install-mk | 4 +- contrib/bmake/mk/meta.autodep.mk | 6 +- contrib/bmake/mk/meta2deps.py | 54 +- contrib/bmake/mk/rst2htm.mk | 6 +- contrib/bmake/nonints.h | 153 +- contrib/bmake/parse.c | 512 ++-- contrib/bmake/str.c | 101 +- contrib/bmake/str.h | 366 +++ contrib/bmake/suff.c | 71 +- contrib/bmake/targ.c | 14 +- contrib/bmake/unit-tests/Makefile | 28 +- contrib/bmake/unit-tests/archive.mk | 6 +- contrib/bmake/unit-tests/cmd-errors-jobs.exp | 2 +- contrib/bmake/unit-tests/cmd-errors-lint.exp | 2 +- contrib/bmake/unit-tests/cmd-errors.exp | 2 +- contrib/bmake/unit-tests/cond-func-empty.mk | 10 +- contrib/bmake/unit-tests/cond-func-make-main.mk | 6 +- contrib/bmake/unit-tests/cond-late.exp | 2 +- contrib/bmake/unit-tests/cond-short.mk | 14 +- contrib/bmake/unit-tests/cond-token-string.exp | 2 +- contrib/bmake/unit-tests/cond-token-var.mk | 23 +- contrib/bmake/unit-tests/cond1.exp | 2 +- contrib/bmake/unit-tests/counter-append.mk | 4 +- contrib/bmake/unit-tests/counter.mk | 4 +- contrib/bmake/unit-tests/dep-var.mk | 4 +- contrib/bmake/unit-tests/deptgt-makeflags.exp | 10 +- contrib/bmake/unit-tests/deptgt-order.exp | 3 + contrib/bmake/unit-tests/deptgt-order.mk | 18 +- contrib/bmake/unit-tests/deptgt.exp | 8 +- contrib/bmake/unit-tests/deptgt.mk | 4 +- contrib/bmake/unit-tests/directive-export-impl.exp | 88 +- contrib/bmake/unit-tests/directive-export-impl.mk | 23 +- contrib/bmake/unit-tests/directive-export.mk | 15 +- contrib/bmake/unit-tests/directive-for-errors.exp | 2 +- contrib/bmake/unit-tests/directive-for-errors.mk | 6 +- contrib/bmake/unit-tests/directive-for-escape.exp | 32 +- contrib/bmake/unit-tests/directive-for-escape.mk | 21 +- contrib/bmake/unit-tests/directive-for.exp | 2 +- contrib/bmake/unit-tests/directive-undef.exp | 3 +- contrib/bmake/unit-tests/directive-undef.mk | 21 +- .../bmake/unit-tests/directive-unexport-env.exp | 20 +- contrib/bmake/unit-tests/directive.exp | 8 +- contrib/bmake/unit-tests/include-main.exp | 2 +- contrib/bmake/unit-tests/job-output-null.exp | 4 + contrib/bmake/unit-tests/job-output-null.mk | 32 + .../bmake/unit-tests/jobs-empty-commands-error.exp | 5 + .../bmake/unit-tests/jobs-empty-commands-error.mk | 19 + contrib/bmake/unit-tests/moderrs.exp | 97 +- contrib/bmake/unit-tests/moderrs.mk | 25 +- contrib/bmake/unit-tests/modts.exp | 4 +- contrib/bmake/unit-tests/modword.exp | 24 +- contrib/bmake/unit-tests/modword.mk | 3 +- contrib/bmake/unit-tests/opt-chdir.mk | 6 +- contrib/bmake/unit-tests/opt-debug-errors-jobs.exp | 48 + contrib/bmake/unit-tests/opt-debug-errors-jobs.mk | 36 + contrib/bmake/unit-tests/opt-debug-lint.exp | 2 +- contrib/bmake/unit-tests/opt-debug-lint.mk | 20 +- contrib/bmake/unit-tests/opt-debug.exp | 6 +- contrib/bmake/unit-tests/opt-file.mk | 6 +- contrib/bmake/unit-tests/opt-jobs-no-action.mk | 4 +- contrib/bmake/unit-tests/recursive.mk | 7 +- contrib/bmake/unit-tests/sh-jobs.mk | 8 +- contrib/bmake/unit-tests/shell-csh.mk | 4 +- contrib/bmake/unit-tests/suff-incomplete.exp | 10 +- contrib/bmake/unit-tests/suff-main-several.exp | 24 +- contrib/bmake/unit-tests/suff-rebuild.exp | 14 +- contrib/bmake/unit-tests/var-class-cmdline.exp | 3 + contrib/bmake/unit-tests/var-class-cmdline.mk | 80 +- contrib/bmake/unit-tests/var-eval-short.exp | 29 + contrib/bmake/unit-tests/var-eval-short.mk | 163 ++ contrib/bmake/unit-tests/var-op-append.exp | 12 +- contrib/bmake/unit-tests/var-op-append.mk | 4 +- contrib/bmake/unit-tests/var-op-assign.mk | 4 +- contrib/bmake/unit-tests/var-op-sunsh.mk | 12 +- contrib/bmake/unit-tests/varcmd.mk | 14 +- contrib/bmake/unit-tests/vardebug.exp | 119 +- contrib/bmake/unit-tests/varmisc.exp | 2 +- contrib/bmake/unit-tests/varmod-assign.exp | 22 +- contrib/bmake/unit-tests/varmod-assign.mk | 39 +- contrib/bmake/unit-tests/varmod-defined.exp | 34 +- contrib/bmake/unit-tests/varmod-defined.mk | 6 +- contrib/bmake/unit-tests/varmod-edge.exp | 12 +- contrib/bmake/unit-tests/varmod-edge.mk | 26 +- contrib/bmake/unit-tests/varmod-hash.exp | 6 +- contrib/bmake/unit-tests/varmod-ifelse.exp | 22 +- contrib/bmake/unit-tests/varmod-ifelse.mk | 64 +- contrib/bmake/unit-tests/varmod-indirect.exp | 84 +- contrib/bmake/unit-tests/varmod-indirect.mk | 100 +- contrib/bmake/unit-tests/varmod-loop-varname.exp | 11 + contrib/bmake/unit-tests/varmod-loop-varname.mk | 127 + contrib/bmake/unit-tests/varmod-loop.exp | 19 +- contrib/bmake/unit-tests/varmod-loop.mk | 156 +- contrib/bmake/unit-tests/varmod-match-escape.exp | 74 +- contrib/bmake/unit-tests/varmod-match-escape.mk | 8 +- contrib/bmake/unit-tests/varmod-order.exp | 4 +- contrib/bmake/unit-tests/varmod-range.exp | 10 +- contrib/bmake/unit-tests/varmod-remember.exp | 2 - contrib/bmake/unit-tests/varmod-remember.mk | 29 +- contrib/bmake/unit-tests/varmod-shell.mk | 9 +- contrib/bmake/unit-tests/varmod-subst-regex.exp | 25 +- contrib/bmake/unit-tests/varmod-subst-regex.mk | 54 +- contrib/bmake/unit-tests/varmod-subst.exp | 2 +- contrib/bmake/unit-tests/varmod-subst.mk | 10 +- contrib/bmake/unit-tests/varmod-sun-shell.exp | 2 + contrib/bmake/unit-tests/varmod-sun-shell.mk | 21 + contrib/bmake/unit-tests/varmod-sysv.exp | 147 +- contrib/bmake/unit-tests/varmod-sysv.mk | 57 +- contrib/bmake/unit-tests/varmod-to-separator.exp | 12 +- contrib/bmake/unit-tests/varmod-unique.mk | 12 +- contrib/bmake/unit-tests/varname-dot-shell.exp | 32 +- contrib/bmake/unit-tests/varname-empty.exp | 60 +- contrib/bmake/unit-tests/varname-empty.mk | 4 +- contrib/bmake/unit-tests/varname.exp | 33 +- contrib/bmake/unit-tests/varparse-dynamic.mk | 6 +- contrib/bmake/unit-tests/varparse-errors.exp | 4 +- contrib/bmake/unit-tests/varparse-errors.mk | 4 +- contrib/bmake/var.c | 3073 +++++++++++--------- 144 files changed, 5499 insertions(+), 3548 deletions(-) diff --cc contrib/bmake/job.c index eb5454cde574,000000000000..c27c47d0b054 mode 100644,000000..100644 --- a/contrib/bmake/job.c +++ b/contrib/bmake/job.c @@@ -1,3012 -1,0 +1,3049 @@@ - /* $NetBSD: job.c,v 1.420 2021/02/05 22:15:44 sjg Exp $ */ ++/* $NetBSD: job.c,v 1.435 2021/06/16 09:47:51 rillig Exp $ */ + +/* + * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1988, 1989 by Adam de Boor + * Copyright (c) 1989 by Berkeley Softworks + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * job.c -- + * handle the creation etc. of our child processes. + * + * Interface: + * Job_Init Called to initialize this module. In addition, + * the .BEGIN target is made including all of its + * dependencies before this function returns. + * Hence, the makefiles must have been parsed + * before this function is called. + * + * Job_End Clean up any memory used. + * + * Job_Make Start the creation of the given target. + * + * Job_CatchChildren + * Check for and handle the termination of any + * children. This must be called reasonably + * frequently to keep the whole make going at + * a decent clip, since job table entries aren't + * removed until their process is caught this way. + * + * Job_CatchOutput + * Print any output our children have produced. + * Should also be called fairly frequently to + * keep the user informed of what's going on. + * If no output is waiting, it will block for + * a time given by the SEL_* constants, below, + * or until output is ready. + * + * Job_ParseShell Given a special dependency line with target '.SHELL', + * define the shell that is used for the creation + * commands in jobs mode. + * + * Job_Finish Perform any final processing which needs doing. + * This includes the execution of any commands + * which have been/were attached to the .END + * target. It should only be called when the + * job table is empty. + * + * Job_AbortAll Abort all currently running jobs. Do not handle + * output or do anything for the jobs, just kill them. + * Should only be called in an emergency. + * + * Job_CheckCommands + * Verify that the commands for a target are + * ok. Provide them if necessary and possible. + * + * Job_Touch Update a target without really updating it. + * + * Job_Wait Wait for all currently-running jobs to finish. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include +#include "wait.h" + +#include +#if !defined(USE_SELECT) && defined(HAVE_POLL_H) +#include +#else +#ifndef USE_SELECT /* no poll.h */ +# define USE_SELECT +#endif +#if defined(HAVE_SYS_SELECT_H) +# include +#endif +#endif +#include +#include +#if defined(HAVE_SYS_SOCKET_H) +# include +#endif + +#include "make.h" +#include "dir.h" +#include "job.h" +#include "pathnames.h" +#include "trace.h" + +/* "@(#)job.c 8.2 (Berkeley) 3/19/94" */ - MAKE_RCSID("$NetBSD: job.c,v 1.420 2021/02/05 22:15:44 sjg Exp $"); ++MAKE_RCSID("$NetBSD: job.c,v 1.435 2021/06/16 09:47:51 rillig Exp $"); + +/* + * A shell defines how the commands are run. All commands for a target are + * written into a single file, which is then given to the shell to execute + * the commands from it. The commands are written to the file using a few + * templates for echo control and error control. + * + * The name of the shell is the basename for the predefined shells, such as + * "sh", "csh", "bash". For custom shells, it is the full pathname, and its + * basename is used to select the type of shell; the longest match wins. + * So /usr/pkg/bin/bash has type sh, /usr/local/bin/tcsh has type csh. + * + * The echoing of command lines is controlled using hasEchoCtl, echoOff, + * echoOn, noPrint and noPrintLen. When echoOff is executed by the shell, it + * still outputs something, but this something is not interesting, therefore + * it is filtered out using noPrint and noPrintLen. + * + * The error checking for individual commands is controlled using hasErrCtl, + * errOn, errOff and runChkTmpl. + * + * In case a shell doesn't have error control, echoTmpl is a printf template + * for echoing the command, should echoing be on; runIgnTmpl is another + * printf template for executing the command while ignoring the return + * status. Finally runChkTmpl is a printf template for running the command and + * causing the shell to exit on error. If any of these strings are empty when - * hasErrCtl is FALSE, the command will be executed anyway as is, and if it ++ * hasErrCtl is false, the command will be executed anyway as is, and if it + * causes an error, so be it. Any templates set up to echo the command will + * escape any '$ ` \ "' characters in the command string to avoid unwanted + * shell code injection, the escaped command is safe to use in double quotes. + * + * The command-line flags "echo" and "exit" also control the behavior. The + * "echo" flag causes the shell to start echoing commands right away. The + * "exit" flag causes the shell to exit when an error is detected in one of + * the commands. + */ +typedef struct Shell { + + /* + * The name of the shell. For Bourne and C shells, this is used only + * to find the shell description when used as the single source of a + * .SHELL target. For user-defined shells, this is the full path of + * the shell. + */ + const char *name; + - Boolean hasEchoCtl; /* whether both echoOff and echoOn are there */ ++ bool hasEchoCtl; /* whether both echoOff and echoOn are there */ + const char *echoOff; /* command to turn echoing off */ + const char *echoOn; /* command to turn echoing back on */ + const char *noPrint; /* text to skip when printing output from the + * shell. This is usually the same as echoOff */ + size_t noPrintLen; /* length of noPrint command */ + - Boolean hasErrCtl; /* whether error checking can be controlled ++ bool hasErrCtl; /* whether error checking can be controlled + * for individual commands */ + const char *errOn; /* command to turn on error checking */ + const char *errOff; /* command to turn off error checking */ + + const char *echoTmpl; /* template to echo a command */ + const char *runIgnTmpl; /* template to run a command + * without error checking */ + const char *runChkTmpl; /* template to run a command + * with error checking */ + + /* string literal that results in a newline character when it appears + * outside of any 'quote' or "quote" characters */ + const char *newline; + char commentChar; /* character used by shell for comment lines */ + + const char *echoFlag; /* shell flag to echo commands */ + const char *errFlag; /* shell flag to exit on error */ +} Shell; + +typedef struct CommandFlags { + /* Whether to echo the command before or instead of running it. */ - Boolean echo; ++ bool echo; + + /* Run the command even in -n or -N mode. */ - Boolean always; ++ bool always; + + /* - * true if we turned error checking off before printing the command - * and need to turn it back on ++ * true if we turned error checking off before writing the command to ++ * the commands file and need to turn it back on + */ - Boolean ignerr; ++ bool ignerr; +} CommandFlags; + +/* + * Write shell commands to a file. + * + * TODO: keep track of whether commands are echoed. + * TODO: keep track of whether error checking is active. + */ +typedef struct ShellWriter { + FILE *f; + + /* we've sent 'set -x' */ - Boolean xtraced; ++ bool xtraced; + +} ShellWriter; + +/* + * FreeBSD: traditionally .MAKE is not required to + * pass jobs queue to sub-makes. + * Use .MAKE.ALWAYS_PASS_JOB_QUEUE=no to disable. + */ +#define MAKE_ALWAYS_PASS_JOB_QUEUE ".MAKE.ALWAYS_PASS_JOB_QUEUE" +static int Always_pass_job_queue = TRUE; +/* + * FreeBSD: aborting entire parallel make isn't always + * desired. When doing tinderbox for example, failure of + * one architecture should not stop all. + * We still want to bail on interrupt though. + */ +#define MAKE_JOB_ERROR_TOKEN "MAKE_JOB_ERROR_TOKEN" +static int Job_error_token = TRUE; + +/* + * error handling variables + */ +static int job_errors = 0; /* number of errors reported */ - typedef enum AbortReason { /* why is the make aborting? */ ++static enum { /* Why is the make aborting? */ + ABORT_NONE, - ABORT_ERROR, /* Because of an error */ - ABORT_INTERRUPT, /* Because it was interrupted */ ++ ABORT_ERROR, /* Aborted because of an error */ ++ ABORT_INTERRUPT, /* Aborted because it was interrupted */ + ABORT_WAIT /* Waiting for jobs to finish */ - /* XXX: "WAIT" is not a _reason_ for aborting, it's rather a status. */ - } AbortReason; - static AbortReason aborting = ABORT_NONE; ++} aborting = ABORT_NONE; +#define JOB_TOKENS "+EI+" /* Token to requeue for each abort state */ + +/* + * this tracks the number of tokens currently "out" to build jobs. + */ +int jobTokensRunning = 0; + +typedef enum JobStartResult { + JOB_RUNNING, /* Job is running */ + JOB_ERROR, /* Error in starting the job */ + JOB_FINISHED /* The job is already finished */ +} JobStartResult; + +/* + * Descriptions for various shells. + * + * The build environment may set DEFSHELL_INDEX to one of + * DEFSHELL_INDEX_SH, DEFSHELL_INDEX_KSH, or DEFSHELL_INDEX_CSH, to + * select one of the predefined shells as the default shell. + * + * Alternatively, the build environment may set DEFSHELL_CUSTOM to the + * name or the full path of a sh-compatible shell, which will be used as + * the default shell. + * + * ".SHELL" lines in Makefiles can choose the default shell from the + * set defined here, or add additional shells. + */ + +#ifdef DEFSHELL_CUSTOM +#define DEFSHELL_INDEX_CUSTOM 0 +#define DEFSHELL_INDEX_SH 1 +#define DEFSHELL_INDEX_KSH 2 +#define DEFSHELL_INDEX_CSH 3 +#else /* !DEFSHELL_CUSTOM */ +#define DEFSHELL_INDEX_SH 0 +#define DEFSHELL_INDEX_KSH 1 +#define DEFSHELL_INDEX_CSH 2 +#endif /* !DEFSHELL_CUSTOM */ + +#ifndef DEFSHELL_INDEX +#define DEFSHELL_INDEX 0 /* DEFSHELL_INDEX_CUSTOM or DEFSHELL_INDEX_SH */ +#endif /* !DEFSHELL_INDEX */ + +static Shell shells[] = { +#ifdef DEFSHELL_CUSTOM + /* + * An sh-compatible shell with a non-standard name. + * + * Keep this in sync with the "sh" description below, but avoid + * non-portable features that might not be supplied by all + * sh-compatible shells. + */ + { + DEFSHELL_CUSTOM, /* .name */ - FALSE, /* .hasEchoCtl */ ++ false, /* .hasEchoCtl */ + "", /* .echoOff */ + "", /* .echoOn */ + "", /* .noPrint */ + 0, /* .noPrintLen */ - FALSE, /* .hasErrCtl */ ++ false, /* .hasErrCtl */ + "", /* .errOn */ + "", /* .errOff */ + "echo \"%s\"\n", /* .echoTmpl */ + "%s\n", /* .runIgnTmpl */ + "{ %s \n} || exit $?\n", /* .runChkTmpl */ + "'\n'", /* .newline */ + '#', /* .commentChar */ + "", /* .echoFlag */ + "", /* .errFlag */ + }, +#endif /* DEFSHELL_CUSTOM */ + /* + * SH description. Echo control is also possible and, under + * sun UNIX anyway, one can even control error checking. + */ + { + "sh", /* .name */ - FALSE, /* .hasEchoCtl */ ++ false, /* .hasEchoCtl */ + "", /* .echoOff */ + "", /* .echoOn */ + "", /* .noPrint */ + 0, /* .noPrintLen */ - FALSE, /* .hasErrCtl */ ++ false, /* .hasErrCtl */ + "", /* .errOn */ + "", /* .errOff */ + "echo \"%s\"\n", /* .echoTmpl */ + "%s\n", /* .runIgnTmpl */ + "{ %s \n} || exit $?\n", /* .runChkTmpl */ + "'\n'", /* .newline */ + '#', /* .commentChar*/ +#if defined(MAKE_NATIVE) && defined(__NetBSD__) + /* XXX: -q is not really echoFlag, it's more like noEchoInSysFlag. */ + "q", /* .echoFlag */ +#else + "", /* .echoFlag */ +#endif + "", /* .errFlag */ + }, + /* + * KSH description. + */ + { + "ksh", /* .name */ - TRUE, /* .hasEchoCtl */ ++ true, /* .hasEchoCtl */ + "set +v", /* .echoOff */ + "set -v", /* .echoOn */ + "set +v", /* .noPrint */ + 6, /* .noPrintLen */ - FALSE, /* .hasErrCtl */ ++ false, /* .hasErrCtl */ + "", /* .errOn */ + "", /* .errOff */ + "echo \"%s\"\n", /* .echoTmpl */ + "%s\n", /* .runIgnTmpl */ + "{ %s \n} || exit $?\n", /* .runChkTmpl */ + "'\n'", /* .newline */ + '#', /* .commentChar */ + "v", /* .echoFlag */ + "", /* .errFlag */ + }, + /* + * CSH description. The csh can do echo control by playing + * with the setting of the 'echo' shell variable. Sadly, + * however, it is unable to do error control nicely. + */ + { + "csh", /* .name */ - TRUE, /* .hasEchoCtl */ ++ true, /* .hasEchoCtl */ + "unset verbose", /* .echoOff */ + "set verbose", /* .echoOn */ + "unset verbose", /* .noPrint */ + 13, /* .noPrintLen */ - FALSE, /* .hasErrCtl */ ++ false, /* .hasErrCtl */ + "", /* .errOn */ + "", /* .errOff */ + "echo \"%s\"\n", /* .echoTmpl */ + "csh -c \"%s || exit 0\"\n", /* .runIgnTmpl */ + "", /* .runChkTmpl */ + "'\\\n'", /* .newline */ + '#', /* .commentChar */ + "v", /* .echoFlag */ + "e", /* .errFlag */ + } +}; + +/* + * This is the shell to which we pass all commands in the Makefile. + * It is set by the Job_ParseShell function. + */ +static Shell *shell = &shells[DEFSHELL_INDEX]; +const char *shellPath = NULL; /* full pathname of executable image */ +const char *shellName = NULL; /* last component of shellPath */ +char *shellErrFlag = NULL; +static char *shell_freeIt = NULL; /* Allocated memory for custom .SHELL */ + + +static Job *job_table; /* The structures that describe them */ +static Job *job_table_end; /* job_table + maxJobs */ +static unsigned int wantToken; /* we want a token */ - static Boolean lurking_children = FALSE; - static Boolean make_suspended = FALSE; /* Whether we've seen a SIGTSTP (etc) */ ++static bool lurking_children = false; ++static bool make_suspended = false; /* Whether we've seen a SIGTSTP (etc) */ + +/* + * Set of descriptors of pipes connected to + * the output channels of children + */ +static struct pollfd *fds = NULL; +static Job **jobByFdIndex = NULL; +static nfds_t fdsLen = 0; +static void watchfd(Job *); +static void clearfd(Job *); - static Boolean readyfd(Job *); ++static bool readyfd(Job *); + +static char *targPrefix = NULL; /* To identify a job change in the output. */ +static Job tokenWaitJob; /* token wait pseudo-job */ + +static Job childExitJob; /* child exit pseudo-job */ +#define CHILD_EXIT "." +#define DO_JOB_RESUME "R" + +enum { + npseudojobs = 2 /* number of pseudo-jobs */ +}; + +static sigset_t caught_signals; /* Set of signals we handle */ +static volatile sig_atomic_t caught_sigchld; + - static void JobDoOutput(Job *, Boolean); - static void JobInterrupt(Boolean, int) MAKE_ATTR_DEAD; ++static void CollectOutput(Job *, bool); ++static void JobInterrupt(bool, int) MAKE_ATTR_DEAD; +static void JobRestartJobs(void); +static void JobSigReset(void); + +static void +SwitchOutputTo(GNode *gn) +{ + /* The node for which output was most recently produced. */ + static GNode *lastNode = NULL; + + if (gn == lastNode) + return; + lastNode = gn; + + if (opts.maxJobs != 1 && targPrefix != NULL && targPrefix[0] != '\0') + (void)fprintf(stdout, "%s %s ---\n", targPrefix, gn->name); +} + +static unsigned +nfds_per_job(void) +{ +#if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) + if (useMeta) + return 2; +#endif + return 1; +} + +void +Job_FlagsToString(const Job *job, char *buf, size_t bufsize) +{ + snprintf(buf, bufsize, "%c%c%c", + job->ignerr ? 'i' : '-', + !job->echo ? 's' : '-', + job->special ? 'S' : '-'); +} + +static void - job_table_dump(const char *where) ++DumpJobs(const char *where) +{ + Job *job; + char flags[4]; + + debug_printf("job table @ %s\n", where); + for (job = job_table; job < job_table_end; job++) { + Job_FlagsToString(job, flags, sizeof flags); + debug_printf("job %d, status %d, flags %s, pid %d\n", + (int)(job - job_table), job->status, flags, job->pid); + } +} + +/* + * Delete the target of a failed, interrupted, or otherwise + * unsuccessful job unless inhibited by .PRECIOUS. + */ +static void +JobDeleteTarget(GNode *gn) +{ + const char *file; + + if (gn->type & OP_JOIN) + return; + if (gn->type & OP_PHONY) + return; + if (Targ_Precious(gn)) + return; + if (opts.noExecute) + return; + + file = GNode_Path(gn); + if (eunlink(file) != -1) + Error("*** %s removed", file); +} + +/* + * JobSigLock/JobSigUnlock + * + * Signal lock routines to get exclusive access. Currently used to + * protect `jobs' and `stoppedJobs' list manipulations. + */ +static void +JobSigLock(sigset_t *omaskp) +{ + if (sigprocmask(SIG_BLOCK, &caught_signals, omaskp) != 0) { + Punt("JobSigLock: sigprocmask: %s", strerror(errno)); + sigemptyset(omaskp); + } +} + +static void +JobSigUnlock(sigset_t *omaskp) +{ + (void)sigprocmask(SIG_SETMASK, omaskp, NULL); +} + +static void +JobCreatePipe(Job *job, int minfd) +{ + int i, fd, flags; + int pipe_fds[2]; + + if (pipe(pipe_fds) == -1) + Punt("Cannot create pipe: %s", strerror(errno)); + + for (i = 0; i < 2; i++) { + /* Avoid using low numbered fds */ + fd = fcntl(pipe_fds[i], F_DUPFD, minfd); + if (fd != -1) { + close(pipe_fds[i]); + pipe_fds[i] = fd; + } + } + + job->inPipe = pipe_fds[0]; + job->outPipe = pipe_fds[1]; + + /* Set close-on-exec flag for both */ + if (fcntl(job->inPipe, F_SETFD, FD_CLOEXEC) == -1) + Punt("Cannot set close-on-exec: %s", strerror(errno)); + if (fcntl(job->outPipe, F_SETFD, FD_CLOEXEC) == -1) + Punt("Cannot set close-on-exec: %s", strerror(errno)); + + /* + * We mark the input side of the pipe non-blocking; we poll(2) the + * pipe when we're waiting for a job token, but we might lose the + * race for the token when a new one becomes available, so the read + * from the pipe should not block. + */ + flags = fcntl(job->inPipe, F_GETFL, 0); + if (flags == -1) + Punt("Cannot get flags: %s", strerror(errno)); + flags |= O_NONBLOCK; + if (fcntl(job->inPipe, F_SETFL, flags) == -1) + Punt("Cannot set flags: %s", strerror(errno)); +} + +/* Pass the signal to each running job. */ +static void +JobCondPassSig(int signo) +{ + Job *job; + + DEBUG1(JOB, "JobCondPassSig(%d) called.\n", signo); + + for (job = job_table; job < job_table_end; job++) { + if (job->status != JOB_ST_RUNNING) + continue; + DEBUG2(JOB, "JobCondPassSig passing signal %d to child %d.\n", + signo, job->pid); + KILLPG(job->pid, signo); + } +} + +/* + * SIGCHLD handler. + * + * Sends a token on the child exit pipe to wake us up from select()/poll(). + */ +/*ARGSUSED*/ +static void +JobChildSig(int signo MAKE_ATTR_UNUSED) +{ + caught_sigchld = 1; + while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 && + errno == EAGAIN) + continue; +} + + +/* Resume all stopped jobs. */ +/*ARGSUSED*/ +static void +JobContinueSig(int signo MAKE_ATTR_UNUSED) +{ + /* + * Defer sending SIGCONT to our stopped children until we return + * from the signal handler. + */ + while (write(childExitJob.outPipe, DO_JOB_RESUME, 1) == -1 && + errno == EAGAIN) + continue; +} + +/* + * Pass a signal on to all jobs, then resend to ourselves. + * We die by the same signal. + */ +MAKE_ATTR_DEAD static void +JobPassSig_int(int signo) +{ + /* Run .INTERRUPT target then exit */ - JobInterrupt(TRUE, signo); ++ JobInterrupt(true, signo); +} + +/* + * Pass a signal on to all jobs, then resend to ourselves. + * We die by the same signal. + */ +MAKE_ATTR_DEAD static void +JobPassSig_term(int signo) +{ + /* Dont run .INTERRUPT target then exit */ - JobInterrupt(FALSE, signo); ++ JobInterrupt(false, signo); +} + +static void +JobPassSig_suspend(int signo) +{ + sigset_t nmask, omask; + struct sigaction act; + + /* Suppress job started/continued messages */ - make_suspended = TRUE; ++ make_suspended = true; + + /* Pass the signal onto every job */ + JobCondPassSig(signo); + + /* + * Send ourselves the signal now we've given the message to everyone + * else. Note we block everything else possible while we're getting + * the signal. This ensures that all our jobs get continued when we + * wake up before we take any other signal. + */ + sigfillset(&nmask); + sigdelset(&nmask, signo); + (void)sigprocmask(SIG_SETMASK, &nmask, &omask); + + act.sa_handler = SIG_DFL; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + (void)sigaction(signo, &act, NULL); + + DEBUG1(JOB, "JobPassSig passing signal %d to self.\n", signo); + + (void)kill(getpid(), signo); + + /* + * We've been continued. + * + * A whole host of signals continue to happen! + * SIGCHLD for any processes that actually suspended themselves. + * SIGCHLD for any processes that exited while we were alseep. + * The SIGCONT that actually caused us to wakeup. + * + * Since we defer passing the SIGCONT on to our children until + * the main processing loop, we can be sure that all the SIGCHLD + * events will have happened by then - and that the waitpid() will + * collect the child 'suspended' events. + * For correct sequencing we just need to ensure we process the + * waitpid() before passing on the SIGCONT. + * + * In any case nothing else is needed here. + */ + + /* Restore handler and signal mask */ + act.sa_handler = JobPassSig_suspend; + (void)sigaction(signo, &act, NULL); + (void)sigprocmask(SIG_SETMASK, &omask, NULL); +} + +static Job * - JobFindPid(int pid, JobStatus status, Boolean isJobs) ++JobFindPid(int pid, JobStatus status, bool isJobs) +{ + Job *job; + + for (job = job_table; job < job_table_end; job++) { + if (job->status == status && job->pid == pid) + return job; + } + if (DEBUG(JOB) && isJobs) - job_table_dump("no pid"); ++ DumpJobs("no pid"); + return NULL; +} + +/* Parse leading '@', '-' and '+', which control the exact execution mode. */ +static void +ParseCommandFlags(char **pp, CommandFlags *out_cmdFlags) +{ + char *p = *pp; - out_cmdFlags->echo = TRUE; - out_cmdFlags->ignerr = FALSE; - out_cmdFlags->always = FALSE; ++ out_cmdFlags->echo = true; ++ out_cmdFlags->ignerr = false; ++ out_cmdFlags->always = false; + + for (;;) { + if (*p == '@') + out_cmdFlags->echo = DEBUG(LOUD); + else if (*p == '-') - out_cmdFlags->ignerr = TRUE; ++ out_cmdFlags->ignerr = true; + else if (*p == '+') - out_cmdFlags->always = TRUE; ++ out_cmdFlags->always = true; + else + break; + p++; + } + + pp_skip_whitespace(&p); + + *pp = p; +} + +/* Escape a string for a double-quoted string literal in sh, csh and ksh. */ +static char * +EscapeShellDblQuot(const char *cmd) +{ + size_t i, j; + + /* Worst that could happen is every char needs escaping. */ + char *esc = bmake_malloc(strlen(cmd) * 2 + 1); + for (i = 0, j = 0; cmd[i] != '\0'; i++, j++) { + if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' || *** 2485 LINES SKIPPED ***