git: 398b29f07f7d - main - sysconf: add a poudriere target
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 08 Oct 2026 16:29:56 UTC
The branch main has been updated by dteske:
URL: https://cgit.FreeBSD.org/src/commit/?id=398b29f07f7d1fa6a045b3ccf242a55cb61207c0
commit 398b29f07f7d1fa6a045b3ccf242a55cb61207c0
Author: Devin Teske <dteske@FreeBSD.org>
AuthorDate: 2026-10-08 16:26:43 +0000
Commit: Devin Teske <dteske@FreeBSD.org>
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 <dteske@FreeBSD.org>
+.\" Copyright (c) 2021-2026 Faraz Vahedi <kfv@FreeBSD.org>
+.\"
+.\" 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/<setname>-poudriere.conf
+.Pa POUDRIERED/<tree>-poudriere.conf
+.Pa POUDRIERED/<jailname>-poudriere.conf
+.Pa POUDRIERED/<tree>-<setname>-poudriere.conf
+.Pa POUDRIERED/<jailname>-<tree>-poudriere.conf
+.Pa POUDRIERED/<jailname>-<setname>-poudriere.conf
+.Pa POUDRIERED/<jailname>-<tree>-<setname>-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/<setname>-make.conf
+.Pa POUDRIERED/<tree>-make.conf
+.Pa POUDRIERED/<jailname>-make.conf
+.Pa POUDRIERED/<tree>-<setname>-make.conf
+.Pa POUDRIERED/<jailname>-<tree>-make.conf
+.Pa POUDRIERED/<jailname>-<setname>-make.conf
+.Pa POUDRIERED/<jailname>-<tree>-<setname>-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/<setname>-src.conf
+.Pa POUDRIERED/<jailname>-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/<setname>-src-env.conf
+.Pa POUDRIERED/<jailname>-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 <jailname>-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 <dteske@FreeBSD.org>
+ * Copyright (c) 2021-2026 Faraz Vahedi <kfv@FreeBSD.org>
+ *
+ * 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 ***