From nobody Sat Feb 05 20:29:17 2022 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 7758B19A123E; Sat, 5 Feb 2022 20:29:17 +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 4JrkXF2sV0z4WL4; Sat, 5 Feb 2022 20:29:17 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1644092957; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=YXjRlYP6ZmZlV1ItM9Oi189UOQS/r3NJUoq+OBbcd8Y=; b=ZLMMH5gJ+q6IPJWzYIxEZottus/FGkglyRDaneI24EyoSr8l77LwCgc9Va5VyZEqFvWytE WSk92Kp3H93yqqVKCByD73ZhQIwRVswvFzJA+at8AeS2/HfEU7Sb5ezbkQ95ssy2JtDY/R Wo/c60ys3wH89k+4DGeDcT2F8QDykONavRewBCPBBJS3FdjL4dT1YufzZRJ0rPuk5FNwgr c0WhM8kS8Z4OxRx81n4NacEFob6WN4rFrPJVHoiIZTu07Q+GD+fZPVIcnTw6cKTRYbq30I QeKBdajdJm9JFwApkAQJtI5QVlBeqcG0jCbv3p8eOGqUlD7/uNPwEhuGWuoGOA== 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 41D2D25AD9; Sat, 5 Feb 2022 20:29:17 +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 215KTH7E061836; Sat, 5 Feb 2022 20:29:17 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 215KTHTN061834; Sat, 5 Feb 2022 20:29:17 GMT (envelope-from git) Date: Sat, 5 Feb 2022 20:29:17 GMT Message-Id: <202202052029.215KTHTN061834@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: 9f45a3c8c82f - main - Merge bmake-20220204 List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org 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: 9f45a3c8c82ffead7044ae836d9257113c630d3b Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1644092957; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=YXjRlYP6ZmZlV1ItM9Oi189UOQS/r3NJUoq+OBbcd8Y=; b=A6V2sd4uLletDdc5rkkT5pSQVEkGuwy3d39CenEqirIbVaJoAiIuK0Yk4Qb0LXYk+H/REo eJ0diMjdS1LxmSAsNsR6RZiTkLF4Fx+DP5tC8gUTTQ4r3ji+6km04ewkhr+sWzenrq0H08 AtMrEKy1ipyXoTtCI+zowrC465f0yaqL/A+qJAsTURWY7Ab0cMP4t5429krN9v3mIvN2KT 6EMo2pRSGc8GGAE6ZkyDaEPfs7f9Yw+sgrBeY6SBML4FKnOo3a11UW3yoFO8craM1nsEQ/ A1F5VwLEM+wp2KoPTE8lDeFojVVheD0bNhDiWtm3ONJisq0/PG9TxKQmrwu3Kw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1644092957; a=rsa-sha256; cv=none; b=i1p6qDwjC3sJYFVnZopxZDYp02GF9oeKty1SV9wcTLHPvKaSPJI3HNZtTQpC/4gBjljbww XbWW3JVi5owQj0aLUCWZv5Pp9pW/xTFd8BvmXM6UDnmRGn77gFzYnX+HG1bnx5dMEXPFbS aikLMoCJ3Wpcmb9rpr4FLGFfPJuLq2zjYTJAOlVg6Nzk1KCPqTdVFoL/Af71FrzcXe7rqa QlLHxjxS1PfSK1sS+iKuVhbVIhT9EDNMTZLJ3C7u6/EG6+V16O347iiNYNpN4oTibALt+N El+wIYXMa/EE1SEpgZc1LAqPDPZx9VyQx+t4CKpjKIRC63l0WrfOuD+usFEmgQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by sjg: URL: https://cgit.FreeBSD.org/src/commit/?id=9f45a3c8c82ffead7044ae836d9257113c630d3b commit 9f45a3c8c82ffead7044ae836d9257113c630d3b Merge: e515b9b44c20 cdde9e894dee Author: Simon J. Gerraty AuthorDate: 2022-02-05 20:26:16 +0000 Commit: Simon J. Gerraty CommitDate: 2022-02-05 20:26:16 +0000 Merge bmake-20220204 contrib/bmake/ChangeLog | 155 ++ contrib/bmake/FILES | 41 +- contrib/bmake/VERSION | 2 +- contrib/bmake/arch.c | 90 +- contrib/bmake/bmake.1 | 51 +- contrib/bmake/bmake.cat1 | 39 +- contrib/bmake/buf.c | 15 +- contrib/bmake/buf.h | 19 +- contrib/bmake/compat.c | 93 +- contrib/bmake/cond.c | 429 +++--- contrib/bmake/dir.c | 21 +- contrib/bmake/dir.h | 14 +- contrib/bmake/filemon/filemon.h | 4 +- contrib/bmake/for.c | 228 ++- contrib/bmake/hash.c | 80 +- contrib/bmake/hash.h | 24 +- contrib/bmake/job.c | 99 +- contrib/bmake/job.h | 34 +- contrib/bmake/lst.h | 20 +- contrib/bmake/main.c | 548 +++---- contrib/bmake/make.1 | 51 +- contrib/bmake/make.c | 32 +- contrib/bmake/make.h | 672 ++++++-- contrib/bmake/make_malloc.c | 12 +- contrib/bmake/make_malloc.h | 26 +- contrib/bmake/meta.c | 172 ++- contrib/bmake/meta.h | 8 +- contrib/bmake/metachar.h | 12 +- contrib/bmake/mk/ChangeLog | 57 + contrib/bmake/mk/FILES | 1 + contrib/bmake/mk/cc-wrap.mk | 61 + contrib/bmake/mk/dirdeps.mk | 101 +- contrib/bmake/mk/host-target.mk | 7 +- contrib/bmake/mk/init.mk | 8 +- contrib/bmake/mk/install-mk | 4 +- contrib/bmake/mk/meta2deps.py | 38 +- contrib/bmake/mk/meta2deps.sh | 29 +- contrib/bmake/mk/mk-files.txt | 93 +- contrib/bmake/mk/sys.clean-env.mk | 6 +- contrib/bmake/nonints.h | 348 ----- contrib/bmake/parse.c | 1608 ++++++++------------ contrib/bmake/str.c | 29 +- contrib/bmake/str.h | 46 +- contrib/bmake/suff.c | 66 +- contrib/bmake/targ.c | 40 +- contrib/bmake/trace.c | 17 +- contrib/bmake/unit-tests/Makefile | 30 +- contrib/bmake/unit-tests/comment.mk | 6 +- contrib/bmake/unit-tests/cond-func-empty.mk | 17 +- contrib/bmake/unit-tests/cond-func.exp | 10 +- contrib/bmake/unit-tests/cond-func.mk | 20 +- contrib/bmake/unit-tests/cond-op-parentheses.exp | 7 +- contrib/bmake/unit-tests/cond-op-parentheses.mk | 36 +- contrib/bmake/unit-tests/cond-short.mk | 12 +- contrib/bmake/unit-tests/cond-token-number.exp | 2 +- contrib/bmake/unit-tests/cond-token-number.mk | 15 +- contrib/bmake/unit-tests/cond-token-plain.exp | 3 +- contrib/bmake/unit-tests/cond-token-plain.mk | 49 +- contrib/bmake/unit-tests/cond-token-string.exp | 4 +- contrib/bmake/unit-tests/dep-duplicate.exp | 4 + contrib/bmake/unit-tests/dep-duplicate.mk | 27 + contrib/bmake/unit-tests/dep-op-missing.exp | 4 + contrib/bmake/unit-tests/dep-op-missing.mk | 13 + contrib/bmake/unit-tests/dep-wildcards.exp | 2 + contrib/bmake/unit-tests/dep.exp | 6 +- contrib/bmake/unit-tests/dep.mk | 16 +- contrib/bmake/unit-tests/depsrc-meta.exp | 2 + contrib/bmake/unit-tests/depsrc-meta.mk | 19 +- contrib/bmake/unit-tests/depsrc-use.mk | 7 +- contrib/bmake/unit-tests/depsrc-usebefore.mk | 7 +- contrib/bmake/unit-tests/depsrc.exp | 1 + contrib/bmake/unit-tests/depsrc.mk | 14 +- contrib/bmake/unit-tests/deptgt-error.exp | 10 +- contrib/bmake/unit-tests/deptgt-error.mk | 22 +- contrib/bmake/unit-tests/deptgt-ignore.exp | 12 +- contrib/bmake/unit-tests/deptgt-ignore.mk | 30 +- contrib/bmake/unit-tests/deptgt-interrupt.exp | 3 +- contrib/bmake/unit-tests/deptgt-interrupt.mk | 9 +- contrib/bmake/unit-tests/deptgt-main.exp | 1 + contrib/bmake/unit-tests/deptgt-main.mk | 27 +- contrib/bmake/unit-tests/deptgt-notparallel.exp | 8 + contrib/bmake/unit-tests/deptgt-notparallel.mk | 18 +- contrib/bmake/unit-tests/deptgt-order.exp | 7 + contrib/bmake/unit-tests/deptgt-order.mk | 4 +- contrib/bmake/unit-tests/deptgt-path-suffix.exp | 5 +- contrib/bmake/unit-tests/deptgt-path-suffix.mk | 10 +- contrib/bmake/unit-tests/deptgt.exp | 13 +- contrib/bmake/unit-tests/deptgt.mk | 11 +- contrib/bmake/unit-tests/directive-dinclude.exp | 5 +- contrib/bmake/unit-tests/directive-dinclude.mk | 25 +- contrib/bmake/unit-tests/directive-elifdef.mk | 21 +- contrib/bmake/unit-tests/directive-elifndef.mk | 23 +- contrib/bmake/unit-tests/directive-export-impl.exp | 16 +- contrib/bmake/unit-tests/directive-for-escape.exp | 102 +- contrib/bmake/unit-tests/directive-for-escape.mk | 62 +- .../unit-tests/directive-for-generating-endif.exp | 2 +- contrib/bmake/unit-tests/directive-for.exp | 18 + contrib/bmake/unit-tests/directive-for.mk | 81 +- .../bmake/unit-tests/directive-hyphen-include.exp | 5 +- .../bmake/unit-tests/directive-hyphen-include.mk | 22 +- contrib/bmake/unit-tests/directive-if.exp | 23 +- contrib/bmake/unit-tests/directive-if.mk | 15 +- contrib/bmake/unit-tests/directive-ifdef.exp | 3 - contrib/bmake/unit-tests/directive-ifdef.mk | 44 +- contrib/bmake/unit-tests/directive-ifmake.exp | 6 +- contrib/bmake/unit-tests/directive-ifmake.mk | 39 +- contrib/bmake/unit-tests/directive-include.exp | 2 + contrib/bmake/unit-tests/directive-include.mk | 33 +- contrib/bmake/unit-tests/directive-info.exp | 2 +- contrib/bmake/unit-tests/directive-info.mk | 13 +- contrib/bmake/unit-tests/directive-sinclude.exp | 5 +- contrib/bmake/unit-tests/directive-sinclude.mk | 18 +- contrib/bmake/unit-tests/directive-undef.exp | 2 +- contrib/bmake/unit-tests/directive-unexport-env.mk | 5 +- contrib/bmake/unit-tests/directive-warning.exp | 16 +- contrib/bmake/unit-tests/directive-warning.mk | 9 +- contrib/bmake/unit-tests/directive.exp | 10 +- contrib/bmake/unit-tests/directive.mk | 22 +- contrib/bmake/unit-tests/envfirst.mk | 44 - contrib/bmake/unit-tests/hanoi-include.mk | 6 +- contrib/bmake/unit-tests/include-main.exp | 12 +- contrib/bmake/unit-tests/include-main.mk | 4 +- contrib/bmake/unit-tests/include-sub.mk | 10 +- contrib/bmake/unit-tests/meta-cmd-cmp.exp | 16 + contrib/bmake/unit-tests/meta-cmd-cmp.mk | 36 +- contrib/bmake/unit-tests/modts.exp | 14 - contrib/bmake/unit-tests/modts.mk | 47 - contrib/bmake/unit-tests/modword.exp | 126 -- contrib/bmake/unit-tests/modword.mk | 161 -- contrib/bmake/unit-tests/opt-debug-cond.exp | 5 + contrib/bmake/unit-tests/opt-debug-cond.mk | 22 +- contrib/bmake/unit-tests/opt-debug-curdir.mk | 10 +- contrib/bmake/unit-tests/opt-debug-file.exp | 13 +- contrib/bmake/unit-tests/opt-debug-file.mk | 48 +- contrib/bmake/unit-tests/opt-debug-hash.exp | 7 +- contrib/bmake/unit-tests/opt-debug-hash.mk | 9 +- contrib/bmake/unit-tests/opt-debug-parse.exp | 25 + contrib/bmake/unit-tests/opt-debug-parse.mk | 34 +- contrib/bmake/unit-tests/opt-debug-var.exp | 6 + contrib/bmake/unit-tests/opt-debug-var.mk | 30 +- contrib/bmake/unit-tests/opt-debug-x-trace.exp | 2 + contrib/bmake/unit-tests/opt-debug-x-trace.mk | 10 +- contrib/bmake/unit-tests/opt-define.mk | 30 +- contrib/bmake/unit-tests/opt-env.exp | 6 +- contrib/bmake/unit-tests/opt-env.mk | 45 +- contrib/bmake/unit-tests/opt-jobs-internal.exp | 7 +- contrib/bmake/unit-tests/opt-jobs-internal.mk | 11 +- contrib/bmake/unit-tests/opt-raw.mk | 16 +- contrib/bmake/unit-tests/opt-silent.exp | 2 + contrib/bmake/unit-tests/opt-silent.mk | 8 +- .../unit-tests/{var-class.exp => opt-version.exp} | 1 + contrib/bmake/unit-tests/opt-version.mk | 12 + contrib/bmake/unit-tests/opt-where-am-i.exp | 3 + contrib/bmake/unit-tests/opt-where-am-i.mk | 14 +- contrib/bmake/unit-tests/parse.exp | 5 + contrib/bmake/unit-tests/parse.mk | 14 + contrib/bmake/unit-tests/posix.mk | 7 +- contrib/bmake/unit-tests/sh.mk | 5 +- contrib/bmake/unit-tests/suff-incomplete.exp | 12 +- contrib/bmake/unit-tests/suff-main-several.exp | 30 +- contrib/bmake/unit-tests/suff-rebuild.exp | 22 +- contrib/bmake/unit-tests/var-class-cmdline.exp | 4 - contrib/bmake/unit-tests/var-class-global.mk | 8 - contrib/bmake/unit-tests/var-class-local.exp | 5 - contrib/bmake/unit-tests/var-class-local.mk | 45 - contrib/bmake/unit-tests/var-class.mk | 9 - contrib/bmake/unit-tests/var-eval-short.exp | 16 +- contrib/bmake/unit-tests/var-eval-short.mk | 11 +- contrib/bmake/unit-tests/var-op-expand.mk | 4 +- contrib/bmake/unit-tests/var-op-shell.exp | 12 +- contrib/bmake/unit-tests/var-op-shell.mk | 15 +- contrib/bmake/unit-tests/var-op-sunsh.mk | 49 +- contrib/bmake/unit-tests/var-recursive.exp | 7 + contrib/bmake/unit-tests/var-recursive.mk | 16 +- contrib/bmake/unit-tests/var-scope-cmdline.exp | 4 + .../{var-class-cmdline.mk => var-scope-cmdline.mk} | 2 +- .../unit-tests/{envfirst.exp => var-scope-env.exp} | 0 .../{var-class-env.mk => var-scope-env.mk} | 2 +- .../{var-class-env.exp => var-scope-global.exp} | 0 contrib/bmake/unit-tests/var-scope-global.mk | 18 + ...class-global.exp => var-scope-local-legacy.exp} | 0 ...s-local-legacy.mk => var-scope-local-legacy.mk} | 2 +- contrib/bmake/unit-tests/var-scope-local.exp | 21 + contrib/bmake/unit-tests/var-scope-local.mk | 200 +++ .../{var-class-local-legacy.exp => var-scope.exp} | 0 contrib/bmake/unit-tests/var-scope.mk | 9 + contrib/bmake/unit-tests/varmod-assign-shell.exp | 14 + contrib/bmake/unit-tests/varmod-assign-shell.mk | 36 + contrib/bmake/unit-tests/varmod-ifelse.mk | 6 +- contrib/bmake/unit-tests/varmod-indirect.exp | 12 +- contrib/bmake/unit-tests/varmod-indirect.mk | 6 +- contrib/bmake/unit-tests/varmod-loop.exp | 6 +- contrib/bmake/unit-tests/varmod-order-numeric.mk | 7 +- contrib/bmake/unit-tests/varmod-order.mk | 16 +- contrib/bmake/unit-tests/varmod-quote-dollar.exp | 1 + contrib/bmake/unit-tests/varmod-quote-dollar.mk | 6 +- contrib/bmake/unit-tests/varmod-select-words.exp | 125 ++ contrib/bmake/unit-tests/varmod-select-words.mk | 162 +- contrib/bmake/unit-tests/varmod-shell.exp | 10 + contrib/bmake/unit-tests/varmod-shell.mk | 10 +- contrib/bmake/unit-tests/varmod-sun-shell.exp | 11 + contrib/bmake/unit-tests/varmod-sun-shell.mk | 7 +- contrib/bmake/unit-tests/varmod-to-separator.exp | 26 +- contrib/bmake/unit-tests/varmod-to-separator.mk | 93 +- contrib/bmake/unit-tests/varname-dot-make-jobs.exp | 7 + contrib/bmake/unit-tests/varname-dot-make-jobs.mk | 24 +- contrib/bmake/unit-tests/varname-dot-make-pid.mk | 18 +- contrib/bmake/unit-tests/varname-dot-make-ppid.mk | 25 +- contrib/bmake/unit-tests/varname-dot-shell.exp | 12 +- contrib/bmake/unit-tests/varname-dot-suffixes.mk | 6 +- contrib/bmake/unit-tests/varname-empty.exp | 1 + contrib/bmake/unit-tests/varname-makeflags.mk | 20 +- contrib/bmake/unit-tests/varname.mk | 44 +- contrib/bmake/unit-tests/varparse-errors.exp | 6 + contrib/bmake/unit-tests/varparse-errors.mk | 22 +- contrib/bmake/unit-tests/varquote.mk | 6 +- contrib/bmake/util.c | 43 +- contrib/bmake/var.c | 692 ++++----- 218 files changed, 5441 insertions(+), 4167 deletions(-) diff --cc contrib/bmake/job.c index f90c35bb6d49,000000000000..0dd202394e4d mode 100644,000000..100644 --- a/contrib/bmake/job.c +++ b/contrib/bmake/job.c @@@ -1,3067 -1,0 +1,3068 @@@ - /* $NetBSD: job.c,v 1.440 2021/11/28 19:51:06 rillig Exp $ */ ++/* $NetBSD: job.c,v 1.451 2022/02/04 23:22:19 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.440 2021/11/28 19:51:06 rillig Exp $"); ++MAKE_RCSID("$NetBSD: job.c,v 1.451 2022/02/04 23:22:19 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 + * 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; + + 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 */ + + 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 */ ++ 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 */ ++ /* ++ * A string literal that results in a newline character when it ++ * occurs 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. */ + bool echo; + + /* Run the command even in -n or -N mode. */ + bool always; + + /* + * true if we turned error checking off before writing the command to + * the commands file and need to turn it back on + */ + 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' */ + 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:U}" +static bool 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:U}" +static bool Job_error_token = true; + +/* + * error handling variables + */ +static int job_errors = 0; /* number of errors reported */ +static enum { /* Why is the make aborting? */ + ABORT_NONE, + ABORT_ERROR, /* Aborted because of an error */ + ABORT_INTERRUPT, /* Aborted because it was interrupted */ + ABORT_WAIT /* Waiting for jobs to finish */ +} 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 */ + "", /* .echoOff */ + "", /* .echoOn */ + "", /* .noPrint */ + 0, /* .noPrintLen */ + 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 */ + "", /* .echoOff */ + "", /* .echoOn */ + "", /* .noPrint */ + 0, /* .noPrintLen */ + 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 */ + "set +v", /* .echoOff */ + "set -v", /* .echoOn */ + "set +v", /* .noPrint */ + 6, /* .noPrintLen */ + 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 */ + "unset verbose", /* .echoOff */ + "set verbose", /* .echoOn */ + "unset verbose", /* .noPrint */ + 13, /* .noPrintLen */ + 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 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 bool readyfd(Job *); + - static char *targPrefix = NULL; /* To identify a job change in the output. */ ++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 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 +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)) ++ if (GNode_IsPrecious(gn)) + return; + if (opts.noExecute) + return; + + file = GNode_Path(gn); - if (eunlink(file) != -1) ++ if (unlink_file(file)) + 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); +} + +/* + * 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); +} + +static void +JobPassSig_suspend(int signo) +{ + sigset_t nmask, omask; + struct sigaction act; + + /* Suppress job started/continued messages */ + 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, bool isJobs) +{ + Job *job; *** 2892 LINES SKIPPED ***