From nobody Thu Oct 08 16:29:56 2026 X-Original-To: dev-commits-src-main@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 4j0wSj0ydFz6vtj4 for ; Thu, 08 Oct 2026 16:29:57 +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 "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4j0wSj0ZNCz3JZX for ; Thu, 08 Oct 2026 16:29:57 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791476997; 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=Y4O23lQ+ein1qiHfsTKNtcJm1290jmV2DSdZAu1MNr4=; b=egh7YAUls79WBS9XdIcAC8FobN+Hg7F3NePppd9mzoHwYmj3sfQG4wYH/7fpYQ/5gYgxVa Niwkwv7OqewdKwbcH+CBDY0EpP4u+Mx9thvRf2u4pVbEBOWr8DLyAVHOTCGVwZ/92B05aU NE0dqXPIKDiDlmtjI3W57++UGtWWXPFmPDx43o0G7md50FqmGW/7sXXUFIuS9XiZVvUFfU x1iUhLZXY1+14T5NRWYwoGSvy/1UGBvBIamMyCU+XLB0iPWGJ8Bxt9yspY/Q5gMNxagoKU rq8tUZLqli6VRbhuksjNyeBV7C097ftcZKiZeFUETY6pKubcfIWwNb5FfaV1Sg== ARC-Seal: i=1; a=rsa-sha256; d=freebsd.org; s=dkim; cv=none; t=1791476997; b=ZTCn/A9TWHh9yIWf6Uohgh9bgQ9psEX/MSVobjBERCwKU4g322pwMhm8qcItp+8vJrkWFO UW/0Oq9TaDVRQk6CmNq/UCz5M/+7rcXcLEZ42R62JFyz5oxSWWM7rkbGH7EuG3EsQxRnIX XlCFno3f4An3hpErsJ1+Bp74Xm/d0gwFhtDHyoOQU80iH0TQ9h8MNajNsVASZA8DhKNgrX NQ+D7zGpo1B2xH2OGZKfcRMgdm6g+qiIoIKrEh3cNs88JpvvbyESX5aM03wL918c8vvweU Zc4gihXOOf0Z81NEucKmTBff1H4e1FMDakl+73CZ6uov+zJXrqes+GpjytDOow== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1791476997; 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=Y4O23lQ+ein1qiHfsTKNtcJm1290jmV2DSdZAu1MNr4=; b=dAIXoTuBWEflIvHrwV60MqnzPI2Hwtcr3uIuHz9kOs2xnYhL9czI8tJlrzJo5juuU3oWLq S0fe/vjsfzJys+D/Au2Npgy5wSlSIn/WuWEiYqT8+KYIWS2iU5bUZSdQLzg64yaj8nLPNg kLMSrk2E1M4YVZn0Di7yDVl28UeOFCvfmE0Htl5JbeQsY41OWM5aOM9vSJicutFSnXnLOR MoLSDGFd2Cv4AtddX3m8p5zRuM80T2CzFvCaCEVGC2KzCs9bGn3z6qeOKdyVYPDgk1+/A5 cGnkbTFCS/YLelydJsd6mj3YSjOWFPSO+YYkKTt3QNlo1V/IMeFxXxlKO/fc3g== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4j0wSh6kywzp2q for ; Thu, 08 Oct 2026 16:29:56 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3f55d by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Thu, 08 Oct 2026 16:29:56 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Devin Teske Subject: git: 398b29f07f7d - main - sysconf: add a poudriere target List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: dteske X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 398b29f07f7d1fa6a045b3ccf242a55cb61207c0 Auto-Submitted: auto-generated Date: Thu, 08 Oct 2026 16:29:56 +0000 Message-Id: <6ac7c504.3f55d.36e19ae6@gitrepo.freebsd.org> The branch main has been updated by dteske: URL: https://cgit.FreeBSD.org/src/commit/?id=398b29f07f7d1fa6a045b3ccf242a55cb61207c0 commit 398b29f07f7d1fa6a045b3ccf242a55cb61207c0 Author: Devin Teske AuthorDate: 2026-10-08 16:26:43 +0000 Commit: Devin Teske CommitDate: 2026-10-08 16:26:43 +0000 sysconf: add a poudriere target poudriere.conf is handed to sysrc(8), including the jail, tree, and set overlays poudriere(8) consults. make, src, and src-env are sub-targets over the matching make(1) files under poudriere.d. -l and -L list one path per line; -L includes overlays that do not exist yet. A bare -- ends the sub-target so the next word is a variable. Bump sysconf(8) to 2.2. Reviewed by: fuz, kfv, bcr Differential Revision: https://reviews.freebsd.org/D59943 --- usr.sbin/sysconf/Makefile | 2 + usr.sbin/sysconf/sysconf-poudriere.8 | 364 ++++++++++++++++++ usr.sbin/sysconf/sysconf-targets.8 | 4 +- usr.sbin/sysconf/sysconf-targets.c | 70 +++- usr.sbin/sysconf/sysconf.8 | 57 ++- usr.sbin/sysconf/sysconf.c | 18 +- usr.sbin/sysconf/sysconf_poudriere.c | 677 +++++++++++++++++++++++++++++++++ usr.sbin/sysconf/sysconf_priv.h | 13 +- usr.sbin/sysconf/tests/sysconf_test.sh | 201 ++++++++++ 9 files changed, 1378 insertions(+), 28 deletions(-) diff --git a/usr.sbin/sysconf/Makefile b/usr.sbin/sysconf/Makefile index 2c96997ff787..cbe5440d6da7 100644 --- a/usr.sbin/sysconf/Makefile +++ b/usr.sbin/sysconf/Makefile @@ -6,6 +6,7 @@ MAN= sysconf.8 \ sysconf-generic.8 \ sysconf-loader.8 \ sysconf-make.8 \ + sysconf-poudriere.8 \ sysconf-rc.8 \ sysconf-src.8 \ sysconf-sysctl.8 \ @@ -16,6 +17,7 @@ SRCS= sysconf.c \ sysconf_edit_assign.c \ sysconf_edit_make.c \ sysconf_edit_write.c \ + sysconf_poudriere.c \ sysconf_print.c \ sysconf_query_desc.c \ sysconf_query_sysctl.c \ diff --git a/usr.sbin/sysconf/sysconf-poudriere.8 b/usr.sbin/sysconf/sysconf-poudriere.8 new file mode 100644 index 000000000000..a5a61fea4421 --- /dev/null +++ b/usr.sbin/sysconf/sysconf-poudriere.8 @@ -0,0 +1,364 @@ +.\" Copyright (c) 2013-2026 Devin Teske +.\" Copyright (c) 2021-2026 Faraz Vahedi +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd September 23, 2026 +.Dt SYSCONF-POUDRIERE 8 +.Os +.Sh NAME +.Nm "sysconf poudriere" +.Nd configure poudriere.conf and poudriere.d overlay files +.Sh SYNOPSIS +.Nm sysconf +.Cm poudriere +.Op Fl Fl jail Ar name +.Op Fl Fl ports Ar name +.Op Fl Fl tree Ar name +.Op Fl Fl set Ar name +.Op Ar sysrc_argument ... +.Nm sysconf +.Cm poudriere +.Bro Cm make Ns | Ns Cm src Ns | Ns Cm src-env Brc +.Op Fl ceFinNqsvVx +.Op Fl Fl jail Ar name +.Op Fl Fl ports Ar name +.Op Fl Fl tree Ar name +.Op Fl Fl set Ar name +.Op Fl j Ar jail | Fl R Ar dir +.Op Fl f Ar file +.Ar name Ns Op Ns Oo +|- Oc Ns = Ns Ar value +.Ar ... +.Nm sysconf +.Cm poudriere +.Bro Cm make Ns | Ns Cm src Ns | Ns Cm src-env Brc +.Op Fl eFnNqvV +.Op Fl Fl jail Ar name +.Op Fl Fl ports Ar name +.Op Fl Fl tree Ar name +.Op Fl Fl set Ar name +.Op Fl f Ar file +.Fl a +.Nm sysconf +.Cm poudriere +.Bro Cm make Ns | Ns Cm src Ns | Ns Cm src-env Brc +.Op Fl E +.Op Fl Fl jail Ar name +.Op Fl Fl ports Ar name +.Op Fl Fl tree Ar name +.Op Fl Fl set Ar name +.Op Fl f Ar file +.Fl l | L +.Sh DESCRIPTION +The +.Cm poudriere +target of +.Xr sysconf 8 +reaches the same files +.Xr poudriere 8 +sources. +With no sub-target, it is the +.Pa poudriere.conf +collection, handed to +.Xr sysrc 8 +as +.Fl f +files. +The sub-targets are +.Cm make , +.Cm src , +and +.Cm src-env . +Each is the matching +.Xr make 1 +collection under +.Pa poudriere.d , +handled by the same engine as +.Xr sysconf-make 8 . +.Pp +A unique prefix of the +.Cm poudriere +keyword is accepted +.Pq Ql p . +A unique prefix of a sub-target is accepted the same way +.Po +.Ql m +selects +.Cm make ; +.Ql s +and +.Ql sr +are ambiguous between +.Cm src +and +.Cm src-env +.Pc . +.Ss poudriere.conf +.Pa poudriere.conf +is +.Xr rc.conf 5 Ns -style +shell written by the administrator; +poudriere never writes it. +The default collection, sourced by every poudriere command, is in order: +.Pa POUDRIERE_ETC/poudriere.conf +if readable +.Pq default Pa /usr/local/etc/poudriere.conf , +then +.Pa POUDRIERED/poudriere.conf +if readable and not the same file as the first +.Pq default Pa POUDRIERE_ETC/poudriere.d/poudriere.conf . +At least one of those two files must exist. +Honor +.Ev POUDRIERE_ETC +and +.Ev POUDRIERED +when set. +.Pp +When a jail, ports tree, or set is given, the matching files are +appended, in the order +.Xr poudriere 8 +uses: +.Bd -unfilled -offset indent +.Pa POUDRIERED/-poudriere.conf +.Pa POUDRIERED/-poudriere.conf +.Pa POUDRIERED/-poudriere.conf +.Pa POUDRIERED/--poudriere.conf +.Pa POUDRIERED/--poudriere.conf +.Pa POUDRIERED/--poudriere.conf +.Pa POUDRIERED/---poudriere.conf +.Ed +.Pp +An explicit +.Xr sysrc 8 +.Fl f +replaces discovery. +.Fl l +and +.Fl L +are handled here and printed one path per line. +For this +.Pa poudriere.conf +collection, +.Fl l +lists each readable file. +.Fl L +lists every location the given jail, tree, and set would consult, +including overlays that do not exist yet. +If no jail, tree, or set is given, the list is the two global +.Pa poudriere.conf +paths. +.Fl E +limits either list to files that exist. +.Fl l +and +.Fl L +take no variable names. +Other arguments except the +.Cm poudriere +keyword itself are handed to +.Xr sysrc 8 +verbatim. +A bare +.Ql -- +means the next word is a variable in this collection, even when that +word is +.Cm make , +.Cm src , +.Cm src-env , +or a unique prefix of one of those sub-targets. +.Ss make.conf, src.conf, and src-env.conf +These live only under +.Pa POUDRIERED +and use +.Xr make 1 +syntax, so they are not mixed into the +.Pa poudriere.conf +sysrc collection. +.Pp +.Cm poudriere make +consults, in the order shown by +.Xr poudriere 8 : +.Bd -unfilled -offset indent +.Pa POUDRIERED/make.conf +.Pa POUDRIERED/-make.conf +.Pa POUDRIERED/-make.conf +.Pa POUDRIERED/-make.conf +.Pa POUDRIERED/--make.conf +.Pa POUDRIERED/--make.conf +.Pa POUDRIERED/--make.conf +.Pa POUDRIERED/---make.conf +.Ed +.Pp +.Fl l +always prints the global path, even when that file does not exist: +.Pa POUDRIERED/make.conf +for +.Cm make , +.Pa POUDRIERED/src.conf +for +.Cm src , +and +.Pa POUDRIERED/src-env.conf +for +.Cm src-env . +An overlay is printed only when the file exists. +.Fl L +lists every location the given jail, tree, and set would consult, +including files that do not exist yet. +.Cm src +and +.Cm src-env +have no per-tree file, so +.Fl Fl tree +does not add a path to those lists. +.Fl E +limits either list to files that exist, so a missing global is omitted. +On a read, a missing global is skipped and an +overlay is consulted only when the file exists. +Hook-plugin +.Pa make.conf +files are not collected. +.Pp +.Cm poudriere src +follows the shorter list +.Xr poudriere 8 +uses when building jails +.Pq global, then set, then jail; no tree : +.Bd -unfilled -offset indent +.Pa POUDRIERED/src.conf +.Pa POUDRIERED/-src.conf +.Pa POUDRIERED/-src.conf +.Ed +.Pp +.Cm poudriere src-env +uses that same order, with +.Pa src-env.conf +in place of +.Pa src.conf : +.Bd -unfilled -offset indent +.Pa POUDRIERED/src-env.conf +.Pa POUDRIERED/-src-env.conf +.Pa POUDRIERED/-src-env.conf +.Ed +.Pp +An explicit +.Fl f +replaces discovery, as on other +.Nm sysconf +targets. +A name already defined is rewritten in the last file in the +collection that defines it, so the change is not placed where a later +overlay would mask it. +A name defined nowhere is appended to the global file, and that write +creates the global file when it is missing. +A bare +.Ar name +reads, and +.Ar name Ns = Ns Ar value +writes, including +.Ql += +and +.Ql -= . +Those rules are the +.Dq Assignment syntax +section of +.Xr sysconf 8 . +.Ss Context long options +.Bl -tag -width indent +.It Fl Fl jail Ar name +Poudriere jail name, as in +.Pa -make.conf +and the other jail files. +.It Fl Fl ports Ar name , Fl Fl tree Ar name +Poudriere ports tree. +.Fl Fl tree +is an alias of +.Fl Fl ports ; +when both are given, the last wins. +A tree applies to +.Pa poudriere.conf +and the +.Cm make +sub-target. +.Cm src +and +.Cm src-env +ignore it; poudriere does not read a per-tree src file. +.It Fl Fl set Ar name +Poudriere set name. +.El +.Pp +.Fl Fl jail Ns = Ns Ar name +(and the same attached form for the others) is accepted. +These long options are consumed here and never passed to +.Xr sysrc 8 +or mistaken for +.Nm sysconf +operands. +They are distinct from +.Fl j +on +.Xr sysconf 8 +and +.Xr sysrc 8 , +which name a running jail. +.Ss Out of scope +Poudriere maintains the following itself, or they are a different format: +.Pp +.Bl -tag -width indent -compact +.It Pa poudriere.d/jails/ , poudriere.d/ports/ +One file per property; the whole file is the value. +.It Pa poudriere.d/*-options/ +A +.Ev PORT_DBDIR +tree of per-port +.Ql OPTIONS +files, written by +.Ql poudriere options +.Pq Ql make config . +.It Pa poudriere.d/*-blacklist +Port origins, one per line +.Pq with optional Ql @flavor ; +.Ql # +comments. +Not +.Ql name=value . +.It Pa poudriere.d/hooks/ +Shell scripts, including plugin +.Pa make.conf +files under +.Pa hooks/plugins/ . +.El +.Sh ENVIRONMENT +.Bl -tag -width POUDRIERE_ETC +.It Ev POUDRIERE_ETC +Directory containing +.Pa poudriere.conf +.Pq default Pa /usr/local/etc . +.It Ev POUDRIERED +Overlay directory +.Pq default Pa POUDRIERE_ETC/poudriere.d . +.El +.Sh EXAMPLES +.Dl sysconf poudriere ZPOOL=zroot +.Dl sysconf poudriere --jail 131amd64 PARALLEL_JOBS=8 +.Dl sysconf p ZPOOL +.Dl sysconf p -- src +.Dl sysconf poudriere make --jail 131amd64 CFLAGS +.Dl sysconf p m --jail 131amd64 CFLAGS+=-O2 +.Dl sysconf poudriere src --set dev WITHOUT_LLVM_BINUTILS= +.Dl sysconf p src-env --jail 131amd64 SRC_ENV_VAR +.Sh SEE ALSO +.Xr poudriere 8 , +.Xr sysconf 8 , +.Xr sysconf-make 8 , +.Xr sysconf-rc 8 , +.Xr sysrc 8 +.Sh HISTORY +The +.Nm sysconf +utility first appeared in +.Fx 16.0 . +.Sh AUTHORS +.An Devin Teske Aq Mt dteske@FreeBSD.org +.An Faraz Vahedi Aq Mt kfv@FreeBSD.org diff --git a/usr.sbin/sysconf/sysconf-targets.8 b/usr.sbin/sysconf/sysconf-targets.8 index 0b611bc5e0a7..e87992852677 100644 --- a/usr.sbin/sysconf/sysconf-targets.8 +++ b/usr.sbin/sysconf/sysconf-targets.8 @@ -3,7 +3,7 @@ .\" .\" SPDX-License-Identifier: BSD-2-Clause .\" -.Dd August 2, 2026 +.Dd September 22, 2026 .Dt SYSCONF-TARGETS 8 .Os .Sh NAME @@ -24,6 +24,7 @@ Per-target file lists and syntax quirks are in .Xr sysconf-make 8 , .Xr sysconf-src 8 , .Xr sysconf-rc 8 , +.Xr sysconf-poudriere 8 , and .Xr sysconf-generic 8 . Shared options remain in @@ -160,6 +161,7 @@ but may differ when the value depends on conditionals or mk defaults. .Xr sysconf-generic 8 , .Xr sysconf-loader 8 , .Xr sysconf-make 8 , +.Xr sysconf-poudriere 8 , .Xr sysconf-rc 8 , .Xr sysconf-src 8 , .Xr sysconf-sysctl 8 diff --git a/usr.sbin/sysconf/sysconf-targets.c b/usr.sbin/sysconf/sysconf-targets.c index 940502d4ad02..9031b6c06748 100644 --- a/usr.sbin/sysconf/sysconf-targets.c +++ b/usr.sbin/sysconf/sysconf-targets.c @@ -6,7 +6,8 @@ */ /* - * Target keyword selection: unique-prefix match, and the rc pass-through. + * Target keyword selection: unique-prefix match, the rc pass-through, + * and the poudriere target (sysrc collection or native make overlays). */ #include "sysconf_priv.h" @@ -20,6 +21,7 @@ static const char *const target_keywords[] = { "generic", "loader", "make", + "poudriere", "rc", "src", "sysctl", @@ -82,31 +84,47 @@ resolve_target_keyword(const char *token) } /* - * Locate the target keyword in `argv' without consuming or validating - * anything: the first argument that is neither an option cluster nor the - * argument of one (per OPTSTRING; an unknown option letter is assumed to - * take no argument). A `--' ends option scanning as usual. Returns the - * argv index of the target, or -1 when there is none. Used before any - * getopt(3) processing so that the `rc' pass-through target (see - * exec_sysrc() below) can be detected while the command line is still - * pristine. + * Locate an operand in `argv' without consuming or validating anything: + * the first argument that is neither an option cluster nor the argument + * of one (per OPTSTRING; an unknown option letter is assumed to take no + * argument). Used before any getopt(3) processing so that pass-through + * targets (`rc', `poudriere'; see exec_sysrc() / poudriere_dispatch()) + * can be detected while the command line is still pristine. * * Attached arguments (`-fPATH', `-R/altroot') are self-contained: the rest * of the cluster is the option's argument, so the following argv element is * not consumed. Only a trailing option letter that takes an argument and * has nothing after it in the cluster (`-f PATH') skips the next element. + * + * Poudriere context long options (`--jail'/`--ports'/`--tree'/`--set') + * take an argument and must not be mistaken for a keyword. + * + * `past_dd' is for the top-level target: `--' ends options and the next + * word is the keyword (`sysconf -- loader'). The poudriere nested keyword + * passes zero: `--' ends the stem, and the following word is a name + * (`sysconf p -- src' reads the variable src from poudriere.conf). */ -static int -find_target(int argc, char *argv[]) +int +find_operand(int argc, char *argv[], int from, int past_dd) { int n; const char *o; const char *p; - for (n = 1; n < argc; n++) { - if (strcmp(argv[n], "--") == 0) + for (n = from; n < argc; n++) { + if (strcmp(argv[n], "--") == 0) { + if (!past_dd) + return (-1); return (n + 1 < argc ? n + 1 : -1); + } if (argv[n][0] == '-' && argv[n][1] != '\0') { + if (argv[n][1] == '-') { + if (poudriere_longopt_p(argv[n]) && + strchr(argv[n], '=') == NULL && + n + 1 < argc) + n++; + continue; + } for (p = argv[n] + 1; *p != '\0'; p++) { o = strchr(OPTSTRING, *p); if (o != NULL && o[1] == ':') { @@ -129,6 +147,13 @@ find_target(int argc, char *argv[]) return (-1); } +static int +find_target(int argc, char *argv[]) +{ + + return (find_operand(argc, argv, 1, 1)); +} + /* * The `rc' pass-through: rc.conf(5) is sysrc(8)'s domain, and its feature * set is a superset of ours, so no option or argument is validated, @@ -159,21 +184,28 @@ exec_sysrc(int argc, char *argv[], int skip) /* * Resolve the target keyword. The `rc' target execs sysrc(8) and does - * not return, so `--help' and `--version' are not intercepted on that - * path. Unique-prefix shorthands are expanded (`r', `m'). Returns the - * canonical keyword, or NULL when the token is unknown or absent. + * not return. The `poudriere' target either execs sysrc(8) or compacts + * argv for a native make/src/src-env overlay (`*argcp' is updated) and + * returns NULL so main does not treat it as a libbsdconf keyword. + * Unique-prefix shorthands are expanded (`r', `m', `p'). Returns the + * canonical keyword, or NULL when the token is unknown, absent, or + * handled as a poudriere overlay. */ const char * -target_resolve(int argc, char *argv[]) +target_resolve(int *argcp, char *argv[]) { const char *resolved; int n; - n = find_target(argc, argv); + n = find_target(*argcp, argv); if (n < 0) return (NULL); resolved = resolve_target_keyword(argv[n]); if (resolved != NULL && strcmp(resolved, "rc") == 0) - exec_sysrc(argc, argv, n); /* never returns */ + exec_sysrc(*argcp, argv, n); /* never returns */ + if (resolved != NULL && strcmp(resolved, "poudriere") == 0) { + *argcp = poudriere_dispatch(*argcp, argv, n); + return (NULL); + } return (resolved); } diff --git a/usr.sbin/sysconf/sysconf.8 b/usr.sbin/sysconf/sysconf.8 index b6147bd39088..6d8428b5f72a 100644 --- a/usr.sbin/sysconf/sysconf.8 +++ b/usr.sbin/sysconf/sysconf.8 @@ -3,7 +3,7 @@ .\" .\" SPDX-License-Identifier: BSD-2-Clause .\" -.Dd September 22, 2026 +.Dd September 23, 2026 .Dt SYSCONF 8 .Os .Sh NAME @@ -38,6 +38,45 @@ .Nm .Cm rc .Op Ar sysrc_argument ... +.Nm +.Cm poudriere +.Op Fl Fl jail Ar name +.Op Fl Fl ports Ar name +.Op Fl Fl tree Ar name +.Op Fl Fl set Ar name +.Op Ar sysrc_argument ... +.Nm +.Cm poudriere +.Bro Cm make Ns | Ns Cm src Ns | Ns Cm src-env Brc +.Op Fl ceFinNqsvVx +.Op Fl Fl jail Ar name +.Op Fl Fl ports Ar name +.Op Fl Fl tree Ar name +.Op Fl Fl set Ar name +.Op Fl j Ar jail | Fl R Ar dir +.Op Fl f Ar file +.Ar name Ns Op Ns Oo +|- Oc Ns = Ns Ar value +.Ar ... +.Nm +.Cm poudriere +.Bro Cm make Ns | Ns Cm src Ns | Ns Cm src-env Brc +.Op Fl eFnNqvV +.Op Fl Fl jail Ar name +.Op Fl Fl ports Ar name +.Op Fl Fl tree Ar name +.Op Fl Fl set Ar name +.Op Fl f Ar file +.Fl a +.Nm +.Cm poudriere +.Bro Cm make Ns | Ns Cm src Ns | Ns Cm src-env Brc +.Op Fl E +.Op Fl Fl jail Ar name +.Op Fl Fl ports Ar name +.Op Fl Fl tree Ar name +.Op Fl Fl set Ar name +.Op Fl f Ar file +.Fl l | L .Sh DESCRIPTION The .Nm @@ -259,6 +298,20 @@ Pass-through to .Xr sysrc 8 . See .Xr sysconf-rc 8 . +.It Cm poudriere +.Pa poudriere.conf +collection via +.Xr sysrc 8 ; +.Cm poudriere make , +.Cm poudriere src , +and +.Cm poudriere src-env +for the +.Xr make 1 +overlays under +.Pa poudriere.d . +See +.Xr sysconf-poudriere 8 . .It Cm generic Foreign or unknown format; requires @@ -682,6 +735,7 @@ Further examples for each target appear in .Xr sysconf-make 8 , .Xr sysconf-src 8 , .Xr sysconf-rc 8 , +.Xr sysconf-poudriere 8 , and .Xr sysconf-generic 8 . .Sh SEE ALSO @@ -695,6 +749,7 @@ and .Xr sysconf-generic 8 , .Xr sysconf-loader 8 , .Xr sysconf-make 8 , +.Xr sysconf-poudriere 8 , .Xr sysconf-rc 8 , .Xr sysconf-src 8 , .Xr sysconf-sysctl 8 , diff --git a/usr.sbin/sysconf/sysconf.c b/usr.sbin/sysconf/sysconf.c index 8e23dc7a8278..41091aa2ed58 100644 --- a/usr.sbin/sysconf/sysconf.c +++ b/usr.sbin/sysconf/sysconf.c @@ -171,10 +171,10 @@ main(int argc, char *argv[]) pgm = getprogname(); /* - * Target selection, including the rc pass-through, runs while - * argv is still pristine (see target_resolve()). + * Target selection, including the rc and poudriere pass-throughs, + * runs while argv is still pristine (see target_resolve()). */ - resolved = target_resolve(argc, argv); + resolved = target_resolve(&argc, argv); /* * Honor `--help' and `--version' wherever they appear (getopt(3) @@ -206,8 +206,11 @@ main(int argc, char *argv[]) * sysctl(8) (e.g., `sysconf sysctl -L'). getopt(3) skips over its * first argument, so hand it the target keyword's slot as the * program name. + * + * Nested `poudriere make|src|src-env' already stripped both keywords; + * remaining argv is options plus names. */ - if (argc > 0) { + if (argc > 0 && !poudriere_native()) { target = resolved != NULL ? resolved : argv[0]; argc--; argv++; @@ -254,7 +257,10 @@ main(int argc, char *argv[]) #endif /* Resolve the target format and its backing files */ - resolve_target(target); + if (poudriere_native()) + poudriere_setup(); + else + resolve_target(target); /* `-k' requires a target with a module drop-in directory */ if (module != NULL) { @@ -564,6 +570,7 @@ usage(void) " -l | -L\n", pgm); fprintf(stderr, " %s rc [sysrc(8) argument ...]\n", pgm); + poudriere_usage(); fprintf(stderr, "Try `%s --help' for more information.\n", pgm); exit(EXIT_FAILURE); } @@ -598,6 +605,7 @@ help(void) "__MAKE_CONF, SRCCONF)"); fprintf(stderr, TGTFMT, "rc", "pass-through: all other arguments go to sysrc(8) verbatim"); + poudriere_help(); fprintf(stderr, TGTFMT, "generic", "no default files; requires -f file"); fprintf(stderr, diff --git a/usr.sbin/sysconf/sysconf_poudriere.c b/usr.sbin/sysconf/sysconf_poudriere.c new file mode 100644 index 000000000000..6e8b1e0e0295 --- /dev/null +++ b/usr.sbin/sysconf/sysconf_poudriere.c @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2013-2026 Devin Teske + * Copyright (c) 2021-2026 Faraz Vahedi + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +/* + * poudriere(8) target: poudriere.conf via sysrc(8), and the make(1) + * overlays (make.conf, src.conf, src-env.conf) under poudriere.d. + */ + +#include "sysconf_priv.h" + +#define POUDRIERE_ETC_DEF "/usr/local/etc" +#define POUDRIERE_MAXFILES 16 + +/* + * Nested poudriere targets (make(1) overlay files under poudriere.d). + * Exact match wins; otherwise a unique prefix. `s' and `sr' are + * ambiguous (src vs src-env); `m' uniquely selects make. + */ +static const char *const poudriere_subs[] = { + "make", + "src", + "src-env", + NULL +}; + +/* Poudriere context; filled when the poudriere target is selected. */ +static const char *poudriere_sub = NULL; /* make, src, src-env */ +static const char *poudriere_jail = NULL; +static const char *poudriere_tree = NULL; /* --ports or --tree */ +static const char *poudriere_set = NULL; + +/* + * True when `arg' is `--name' or `--name=value'. + */ +static int +longopt_eq(const char *arg, const char *name) +{ + size_t nlen; + + if (arg[0] != '-' || arg[1] != '-') + return (0); + nlen = strlen(name); + if (strncmp(arg + 2, name, nlen) != 0) + return (0); + return (arg[2 + nlen] == '\0' || arg[2 + nlen] == '='); +} + +int +poudriere_longopt_p(const char *arg) +{ + + return (longopt_eq(arg, "jail") || longopt_eq(arg, "ports") || + longopt_eq(arg, "tree") || longopt_eq(arg, "set")); +} + +static void +poudriere_add_path(char **files, unsigned int *nfiles, unsigned int max, + const char *path) +{ + + if (*nfiles >= max) + errx(EXIT_FAILURE, "too many poudriere files"); + if ((files[*nfiles] = strdup(path)) == NULL) + err(EXIT_FAILURE, NULL); + (*nfiles)++; +} + +static void +poudriere_add_if_readable(char **files, unsigned int *nfiles, + unsigned int max, const char *path) +{ + + if (access(path, R_OK) != 0) + return; + poudriere_add_path(files, nfiles, max, path); +} + +static int +same_realpath(const char *a, const char *b) +{ + char ra[PATH_MAX]; + char rb[PATH_MAX]; + + if (realpath(a, ra) == NULL || realpath(b, rb) == NULL) + return (0); + return (strcmp(ra, rb) == 0); +} + +/* + * Join `dir'/`name', then prefix `-R dir' when set. `rootdir' is empty + * until parse_options(), so the sysrc pass-through is unprefixed. + */ +static void +poudriere_join(char *dst, size_t dstsz, const char *dir, const char *name) +{ + char raw[PATH_MAX]; + int n; + + n = snprintf(raw, sizeof(raw), "%s/%s", dir, name); + if (n < 0 || (size_t)n >= sizeof(raw)) + errx(EXIT_FAILURE, "%s/%s: %s", dir, name, + strerror(ENAMETOOLONG)); + n = snprintf(dst, dstsz, "%s%s", rootdir, raw); + if (n < 0 || (size_t)n >= dstsz) + errx(EXIT_FAILURE, "%s%s: %s", rootdir, raw, + strerror(ENAMETOOLONG)); +} + +static void +poudriere_etc_d(const char **etc, const char **d, char *dbuf, size_t dbufsz) +{ + + *etc = getenv("POUDRIERE_ETC"); + if (*etc == NULL || **etc == '\0') + *etc = POUDRIERE_ETC_DEF; + *d = getenv("POUDRIERED"); + if (*d == NULL || **d == '\0') { + if (snprintf(dbuf, dbufsz, "%s/poudriere.d", *etc) >= + (int)dbufsz) + errx(EXIT_FAILURE, "%s/poudriere.d: %s", *etc, + strerror(ENAMETOOLONG)); + *d = dbuf; + } +} + +static void +poudriere_try_named(char **files, unsigned int *nfiles, unsigned int max, + const char *dir, const char *stem, const char *suffix, int only_readable) +{ + char name[PATH_MAX]; + char path[PATH_MAX]; + int n; + + if (stem == NULL || *stem == '\0') + return; + n = snprintf(name, sizeof(name), "%s-%s", stem, suffix); + if (n < 0 || (size_t)n >= sizeof(name)) + errx(EXIT_FAILURE, "poudriere overlay name: %s", + strerror(ENAMETOOLONG)); + poudriere_join(path, sizeof(path), dir, name); + if (only_readable) + poudriere_add_if_readable(files, nfiles, max, path); + else + poudriere_add_path(files, nfiles, max, path); +} + +/* + * Overlay stems in poudriere(8) construction order. `full' is the + * make.conf / poudriere.conf set (set, tree, jail, and the four combos). + * src.conf and src-env.conf are global plus set and jail only. + */ +static void +poudriere_add_overlays(char **files, unsigned int *nfiles, unsigned int max, + const char *dir, const char *suffix, int full, int only_readable) +{ + char stem[PATH_MAX]; + int n; + + poudriere_try_named(files, nfiles, max, dir, poudriere_set, suffix, + only_readable); + if (full) + poudriere_try_named(files, nfiles, max, dir, poudriere_tree, + suffix, only_readable); + poudriere_try_named(files, nfiles, max, dir, poudriere_jail, suffix, + only_readable); + if (!full) + return; + if (poudriere_tree != NULL && *poudriere_tree != '\0' && + poudriere_set != NULL && *poudriere_set != '\0') { + n = snprintf(stem, sizeof(stem), "%s-%s", poudriere_tree, + poudriere_set); + if (n < 0 || (size_t)n >= sizeof(stem)) + errx(EXIT_FAILURE, "poudriere overlay name: %s", + strerror(ENAMETOOLONG)); + poudriere_try_named(files, nfiles, max, dir, stem, suffix, + only_readable); + } + if (poudriere_jail != NULL && *poudriere_jail != '\0' && + poudriere_tree != NULL && *poudriere_tree != '\0') { + n = snprintf(stem, sizeof(stem), "%s-%s", poudriere_jail, + poudriere_tree); + if (n < 0 || (size_t)n >= sizeof(stem)) + errx(EXIT_FAILURE, "poudriere overlay name: %s", + strerror(ENAMETOOLONG)); + poudriere_try_named(files, nfiles, max, dir, stem, suffix, + only_readable); + } + if (poudriere_jail != NULL && *poudriere_jail != '\0' && + poudriere_set != NULL && *poudriere_set != '\0') { + n = snprintf(stem, sizeof(stem), "%s-%s", poudriere_jail, + poudriere_set); + if (n < 0 || (size_t)n >= sizeof(stem)) + errx(EXIT_FAILURE, "poudriere overlay name: %s", + strerror(ENAMETOOLONG)); + poudriere_try_named(files, nfiles, max, dir, stem, suffix, + only_readable); + } + if (poudriere_jail != NULL && *poudriere_jail != '\0' && + poudriere_tree != NULL && *poudriere_tree != '\0' && + poudriere_set != NULL && *poudriere_set != '\0') { + n = snprintf(stem, sizeof(stem), "%s-%s-%s", poudriere_jail, + poudriere_tree, poudriere_set); + if (n < 0 || (size_t)n >= sizeof(stem)) + errx(EXIT_FAILURE, "poudriere overlay name: %s", + strerror(ENAMETOOLONG)); + poudriere_try_named(files, nfiles, max, dir, stem, suffix, + only_readable); + } +} + +/* + * Build the poudriere.conf collection in include_poudriere_confs() order: + * POUDRIERE_ETC/poudriere.conf, then POUDRIERED/poudriere.conf if distinct, + * then optional set/tree/jail overlays. At least one global file must exist. + */ +static void +poudriere_collect_files(char **files, unsigned int *nfiles, unsigned int max, + int only_readable) +{ + char dbuf[PATH_MAX]; + char path[PATH_MAX]; + const char *d; + const char *etc; + + poudriere_etc_d(&etc, &d, dbuf, sizeof(dbuf)); + + poudriere_join(path, sizeof(path), etc, "poudriere.conf"); + if (only_readable) + poudriere_add_if_readable(files, nfiles, max, path); + else + poudriere_add_path(files, nfiles, max, path); + + poudriere_join(path, sizeof(path), d, "poudriere.conf"); + if (*nfiles == 0 || !same_realpath(files[0], path)) { + if (only_readable) + poudriere_add_if_readable(files, nfiles, max, path); + else + poudriere_add_path(files, nfiles, max, path); + } *** 687 LINES SKIPPED ***