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
This commit is contained in:
Devin Teske committed 2026-10-08 09:26:43 -07:00
1 parent 439eb9c977
commit 398b29f07f
9 files changed
+1378 -28

No files matched your search

+2
View File
@@ -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 \
+364
View File
@@ -0,0 +1,364 @@
.\" Copyright (c) 2013-2026 Devin Teske <[email protected]>
.\" Copyright (c) 2021-2026 Faraz Vahedi <[email protected]>
.\"
.\" 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 [email protected]
.An Faraz Vahedi Aq Mt [email protected]
+3 -1
View File
@@ -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
+51 -19
View File
@@ -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);
}
+56 -1
View File
@@ -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 ,
+13 -5
View File
@@ -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,
+677
View File
@@ -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);
}
if (only_readable && *nfiles == 0)
errx(EXIT_FAILURE,
"Unable to find a readable poudriere.conf in %s or %s",
etc, d);
poudriere_add_overlays(files, nfiles, max, d, "poudriere.conf", 1,
only_readable);
}
/*
* make.conf / src.conf / src-env.conf under POUDRIERED. The global file
* is always listed (ENOENT is tolerated on read; a write creates it).
* Overlays are appended only when readable, unless `only_readable' is 0
* (`-L' lists every stem, including files that do not exist yet).
* Plugin hook make.conf is not collected.
*/
static void
poudriere_collect_make_files(char **files, unsigned int *nfiles,
unsigned int max, const char *suffix, int full, 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), d, suffix);
poudriere_add_path(files, nfiles, max, path);
poudriere_add_overlays(files, nfiles, max, d, suffix, full,
only_readable);
}
/*
* True when remaining argv (except the target at `skip') contains sysrc(8)
* `-f'. Clusters are scanned like getopt: `f' takes an argument, as do
* `j', `R', and `s' (so `-qf FILE' counts and `-F' does not).
*/
static int
argv_has_sysrc_f(int argc, char *argv[], int skip)
{
const char *p;
int n;
for (n = 1; n < argc; n++) {
if (n == skip)
continue;
if (strcmp(argv[n], "--") == 0)
return (0);
if (argv[n][0] != '-' || argv[n][1] == '\0' ||
argv[n][1] == '-')
continue;
for (p = argv[n] + 1; *p != '\0'; p++) {
if (*p == 'f')
return (1);
if (*p == 'j' || *p == 'R' || *p == 's') {
if (p[1] != '\0')
break;
if (n + 1 < argc)
n++;
break;
}
}
}
return (0);
}
/*
* If `arg' is `--name' or `--name=value', return the value. Separate-argv
* form consumes `next' (*consumed = 1). Missing or empty values are errors.
*/
static const char *
longopt_arg(const char *arg, const char *next, int *consumed,
const char *name)
{
size_t nlen;
*consumed = 0;
if (!longopt_eq(arg, name))
return (NULL);
nlen = strlen(name);
if (arg[2 + nlen] == '=') {
if (arg[3 + nlen] == '\0')
errx(EXIT_FAILURE,
"option `--%s' requires an argument", name);
return (arg + 3 + nlen);
}
if (next == NULL || *next == '\0')
errx(EXIT_FAILURE, "option `--%s' requires an argument",
name);
*consumed = 1;
return (next);
}
static void
poudriere_parse_longopts(int argc, char *argv[])
{
const char *next;
const char *val;
int consumed;
int n;
for (n = 1; n < argc; n++) {
if (strcmp(argv[n], "--") == 0)
break;
consumed = 0;
next = (n + 1 < argc) ? argv[n + 1] : NULL;
if ((val = longopt_arg(argv[n], next, &consumed,
"jail")) != NULL)
poudriere_jail = val;
else if ((val = longopt_arg(argv[n], next, &consumed,
"ports")) != NULL)
poudriere_tree = val;
else if ((val = longopt_arg(argv[n], next, &consumed,
"tree")) != NULL)
poudriere_tree = val;
else if ((val = longopt_arg(argv[n], next, &consumed,
"set")) != NULL)
poudriere_set = val;
if (consumed)
n++;
}
}
/*
* Drop the poudriere keyword, optional nested target, and context long
* options so the remainder can be parsed as a native sysconf command
* line (or, for the sysrc path, rebuilt without those tokens).
*/
static int
poudriere_compact(int argc, char *argv[], int tgt, int sub)
{
int dst;
int endopts;
int n;
dst = 1;
endopts = 0;
for (n = 1; n < argc; n++) {
if (n == tgt || n == sub)
continue;
if (!endopts && strcmp(argv[n], "--") == 0)
endopts = 1;
if (!endopts && poudriere_longopt_p(argv[n])) {
if (strchr(argv[n], '=') == NULL && n + 1 < argc)
n++;
continue;
}
argv[dst++] = argv[n];
}
argv[dst] = NULL;
return (dst);
}
/*
* `-l' / `-L' on this target. Returns 1 when either is present.
* `*all' is `-L' (every location for the named jail, tree, and set,
* including files that do not exist). `*exist' is `-E'. `*filep' is an
* explicit `-f'. `*names' is a non-option operand (listing takes none).
* `-R dir' is applied as the sysconf root for the paths printed.
*/
static int
argv_wants_list(int argc, char *argv[], int skip, int *all, int *exist,
const char **filep, int *names)
{
const char *arg;
const char *p;
int list;
int n;
*all = 0;
*exist = 0;
*filep = NULL;
*names = 0;
list = 0;
for (n = 1; n < argc; n++) {
if (n == skip)
continue;
if (strcmp(argv[n], "--") == 0) {
if (n + 1 < argc)
*names = 1;
break;
}
if (argv[n][0] == '-' && argv[n][1] == '-') {
if (poudriere_longopt_p(argv[n]) &&
strchr(argv[n], '=') == NULL && n + 1 < argc)
n++;
continue;
}
if (argv[n][0] != '-' || argv[n][1] == '\0') {
*names = 1;
continue;
}
for (p = argv[n] + 1; *p != '\0'; p++) {
if (*p == 'l')
list = 1;
else if (*p == 'L') {
list = 1;
*all = 1;
} else if (*p == 'E')
*exist = 1;
else if (*p == 'f' || *p == 'j' || *p == 'R' ||
*p == 's') {
if (p[1] != '\0')
arg = p + 1;
else if (n + 1 < argc)
arg = argv[++n];
else
arg = NULL;
if (*p == 'f')
*filep = arg;
else if (*p == 'R' && arg != NULL)
rootdir = arg;
break;
}
}
}
return (list);
}
static void
poudriere_puts_files(char **files, unsigned int nfiles, int exist_only)
{
unsigned int n;
for (n = 0; n < nfiles; n++) {
if (exist_only && access(files[n], F_OK) != 0)
continue;
puts(files[n]);
}
}
/*
* The `poudriere' target without a nested make/src/src-env keyword:
* resolve the shell-sourced poudriere.conf collection (same order as
* poudriere's include_poudriere_confs()) and hand it to sysrc(8) as
* `-f' files. `--jail'/`--ports'/`--tree'/`--set' select overlays;
* they are stripped so sysrc never sees them. An explicit sysrc `-f'
* replaces discovery. `-l' and `-L' are printed here, one path per
* line. Never returns.
*/
static void
exec_poudriere_sysrc(int argc, char *argv[], int skip)
{
char *files[POUDRIERE_MAXFILES];
char **nargv;
char path[PATH_MAX];
const char *list_file;
unsigned int nfiles;
int all;
int endopts;
int exist;
int n;
int names;
int nargc;
int user_f;
nfiles = 0;
nargc = 0;
if (argv_wants_list(argc, argv, skip, &all, &exist, &list_file,
&names)) {
if (names)
errx(EXIT_FAILURE, "-l/-L take no names");
if (list_file != NULL) {
if (snprintf(path, sizeof(path), "%s%s", rootdir,
list_file) >= (int)sizeof(path))
errx(EXIT_FAILURE, "%s%s: %s", rootdir,
list_file, strerror(ENAMETOOLONG));
if (!exist || access(path, F_OK) == 0)
puts(path);
exit(EXIT_SUCCESS);
}
poudriere_collect_files(files, &nfiles, POUDRIERE_MAXFILES,
all ? 0 : 1);
poudriere_puts_files(files, nfiles, exist);
exit(EXIT_SUCCESS);
}
user_f = argv_has_sysrc_f(argc, argv, skip);
if (!user_f)
poudriere_collect_files(files, &nfiles, POUDRIERE_MAXFILES,
1);
if ((nargv = calloc((size_t)argc + (size_t)nfiles * 2 + 2,
sizeof(*nargv))) == NULL)
err(EXIT_FAILURE, NULL);
nargv[nargc++] = (char *)(uintptr_t)"sysrc";
for (n = 0; n < (int)nfiles; n++) {
nargv[nargc++] = (char *)(uintptr_t)"-f";
nargv[nargc++] = files[n];
}
endopts = 0;
for (n = 1; n < argc; n++) {
if (n == skip)
continue;
if (!endopts && strcmp(argv[n], "--") == 0) {
endopts = 1;
nargv[nargc++] = argv[n];
continue;
}
if (!endopts && poudriere_longopt_p(argv[n])) {
if (strchr(argv[n], '=') == NULL && n + 1 < argc)
n++;
continue;
}
nargv[nargc++] = argv[n];
}
nargv[nargc] = NULL;
execvp("sysrc", nargv);
err(EXIT_FAILURE, "sysrc");
}
int
poudriere_native(void)
{
return (poudriere_sub != NULL);
}
/*
* Nested `poudriere make|src|src-env': native make(1) format over the
* matching poudriere.d overlay collection. `-f' replaces discovery.
*/
void
poudriere_setup(void)
{
char *files[POUDRIERE_MAXFILES];
char path[PATH_MAX];
const char *prefix;
const char *suffix;
int full;
unsigned int i;
unsigned int nfiles;
format = BSDCONF_FORMAT_MAKE;
if (file != NULL) {
prefix = file_stdin ? "" : rootdir;
if ((conf_files = calloc(1, sizeof(*conf_files))) == NULL)
err(EXIT_FAILURE, NULL);
if (snprintf(path, sizeof(path), "%s%s", prefix, file) >=
(int)sizeof(path))
errx(EXIT_FAILURE, "%s%s: %s", prefix, file,
strerror(ENAMETOOLONG));
if ((conf_files[0] = strdup(path)) == NULL)
err(EXIT_FAILURE, NULL);
nconf_files = 1;
write_idx = 0;
return;
}
if (strcmp(poudriere_sub, "make") == 0) {
suffix = "make.conf";
full = 1;
} else if (strcmp(poudriere_sub, "src") == 0) {
suffix = "src.conf";
full = 0;
} else {
suffix = "src-env.conf";
full = 0;
}
nfiles = 0;
/* `-L' lists missing overlays; reads and `-l' do not. */
poudriere_collect_make_files(files, &nfiles, POUDRIERE_MAXFILES,
suffix, full, list_all ? 0 : 1);
if ((conf_files = calloc(nfiles, sizeof(*conf_files))) == NULL)
err(EXIT_FAILURE, NULL);
for (i = 0; i < nfiles; i++)
conf_files[i] = files[i];
nconf_files = nfiles;
write_idx = 0;
}
/*
* On the sysrc path, exec and do not return. On the native
* make/src/src-env path, rewrite argv and return the new argc.
* A bare `--' before the next word ends the nested keyword, so that
* word is a poudriere.conf variable (`sysconf p -- src').
*/
int
poudriere_dispatch(int argc, char *argv[], int tgt)
{
int subn;
poudriere_parse_longopts(argc, argv);
subn = find_operand(argc, argv, tgt + 1, 0);
if (subn > 0 && strchr(argv[subn], '=') == NULL)
poudriere_sub = resolve_keyword(argv[subn], poudriere_subs,
"poudriere target");
if (poudriere_sub == NULL)
exec_poudriere_sysrc(argc, argv, tgt); /* never returns */
return (poudriere_compact(argc, argv, tgt, subn));
}
void
poudriere_usage(void)
{
fprintf(stderr,
" %s poudriere [--jail name] [--ports name] [--tree name]\n",
pgm);
fprintf(stderr,
" [--set name] [sysrc(8) argument ...]\n");
fprintf(stderr,
" %s poudriere {make|src|src-env} [-ceFinNqsvVx]\n", pgm);
fprintf(stderr,
" [--jail name] [--ports name] [--tree name]\n");
fprintf(stderr,
" [--set name] [-j jail | -R dir] [-f file]\n");
fprintf(stderr,
" name[[+|-]=value] ...\n");
fprintf(stderr,
" %s poudriere {make|src|src-env} [-eFnNqvV]\n", pgm);
fprintf(stderr,
" [--jail name] [--ports name] [--tree name]\n");
fprintf(stderr,
" [--set name] [-f file] -a\n");
fprintf(stderr,
" %s poudriere {make|src|src-env} [-E]\n", pgm);
fprintf(stderr,
" [--jail name] [--ports name] [--tree name]\n");
fprintf(stderr,
" [--set name] [-f file] -l | -L\n");
}
void
poudriere_help(void)
{
fprintf(stderr, "\t%-9s %s\n", "poudriere",
"poudriere.conf via sysrc(8); make/src/src-env overlays");
fprintf(stderr, "\t%-9s %s\n", "",
"(--jail/--ports/--tree/--set select poudriere.d files)");
}
+11 -2
View File
@@ -37,7 +37,7 @@
#define __unused /* not all compilers support attributes */
#endif
#define SYSCONF_VERSION "2.1 2026-09-22"
#define SYSCONF_VERSION "2.2 2026-09-22"
/* getopt(3) optstring; shared by parse_options() and find_target() */
#define OPTSTRING "AacdDEeFf:hij:k:lLnNqR:svVx"
@@ -197,12 +197,21 @@ int sysctl_writable(const char *_name, const char *_value,
#endif
/* sysconf-targets.c */
int find_operand(int _argc, char **_argv, int _from, int _past_dd);
const char *resolve_keyword(const char *_token,
const char *const *_keywords, const char *_what);
const char *target_resolve(int _argc, char **_argv);
const char *target_resolve(int *_argcp, char **_argv);
/* sysconf.c */
void usage(void);
void help(void);
/* sysconf_poudriere.c */
int poudriere_longopt_p(const char *_arg);
int poudriere_dispatch(int _argc, char **_argv, int _tgt);
int poudriere_native(void);
void poudriere_setup(void);
void poudriere_usage(void);
void poudriere_help(void);
#endif /* !_SYSCONF_PRIV_H_ */
+201
View File
@@ -486,6 +486,205 @@ target_prefix_cleanup()
cleanup_root
}
atf_test_case poudriere_sysrc cleanup
poudriere_sysrc_head()
{
atf_set "descr" \
"poudriere target feeds sysrc -f over the conf collection"
}
poudriere_sysrc_body()
{
find_sysconf
command -v sysrc > /dev/null 2>&1 ||
atf_skip "sysrc not installed"
ETC="$( pwd )/petc"
mkdir -p "$ETC/poudriere.d"
printf 'ZPOOL=old\nFOO=global\n' > "$ETC/poudriere.conf"
printf 'FOO=jail\nJOBS=2\n' \
> "$ETC/poudriere.d/131amd64-poudriere.conf"
export POUDRIERE_ETC="$ETC"
# -l / -L are printed here, one path per line (not sysrc -L)
atf_check -o inline:"$ETC/poudriere.conf\n" \
"$SYSCONF" p -l
atf_check -o inline:"$ETC/poudriere.conf\n$ETC/poudriere.d/poudriere.conf\n" \
"$SYSCONF" p -L
atf_check -o inline:"$ETC/poudriere.conf\n$ETC/poudriere.d/131amd64-poudriere.conf\n" \
"$SYSCONF" p --jail 131amd64 -l
atf_check -o inline:"$ETC/poudriere.conf\n$ETC/poudriere.d/poudriere.conf\n$ETC/poudriere.d/131amd64-poudriere.conf\n" \
"$SYSCONF" p --jail 131amd64 -L
atf_check -o inline:"$ETC/poudriere.conf\n" \
"$SYSCONF" p --jail 99amd64 -l
atf_check -o match:'99amd64-poudriere.conf' \
-o not-match:'rc\.conf' \
"$SYSCONF" p --jail 99amd64 -L
atf_check -o inline:"$ETC/poudriere.conf\n" \
"$SYSCONF" p -E -L
atf_check -o inline:"$ETC/poudriere.conf\n$ETC/poudriere.d/131amd64-poudriere.conf\n" \
"$SYSCONF" p --jail 131amd64 -E -L
atf_check -s not-exit:0 -e match:'take no names' \
"$SYSCONF" p -l ZPOOL
# Shorthand p; read from the global file
atf_check -o match:'ZPOOL: old' \
"$SYSCONF" p ZPOOL
# Write a new name into the first file
atf_check -o match:'BASEFS' \
"$SYSCONF" poudriere BASEFS=/poudriere
atf_check -o match:'BASEFS=' cat "$ETC/poudriere.conf"
atf_check -o not-match:'BASEFS' \
cat "$ETC/poudriere.d/131amd64-poudriere.conf"
# Overlay collection: --jail appends the jail overlay last
atf_check -o match:'FOO: jail' \
"$SYSCONF" poudriere --jail 131amd64 FOO
# Without --jail the overlay is not in the collection
atf_check -o match:'FOO: global' \
"$SYSCONF" poudriere FOO
# --tree is an alias of --ports
printf 'FOO=tree\n' > "$ETC/poudriere.d/default-poudriere.conf"
atf_check -o match:'FOO: tree' \
"$SYSCONF" poudriere --tree default FOO
atf_check -o match:'FOO: tree' \
"$SYSCONF" poudriere --ports default FOO
# Rewrite the overlay's existing var
atf_check -o match:'JOBS' \
"$SYSCONF" poudriere --jail 131amd64 JOBS=8
atf_check -o match:'JOBS: 8' \
"$SYSCONF" poudriere --jail 131amd64 JOBS
# Attached --jail=
atf_check -o match:'FOO: jail' \
"$SYSCONF" poudriere --jail=131amd64 FOO
# `--' ends the nested keyword; colliding names are variables
printf 'src=from-conf\nm=short\n' >> "$ETC/poudriere.conf"
printf 'src=from-overlay\n' > "$ETC/poudriere.d/src.conf"
atf_check -o match:'src: from-conf' \
"$SYSCONF" p -- src
atf_check -o match:'m: short' \
"$SYSCONF" p -- m
atf_check -s not-exit:0 -e match:"unknown variable 'make'" \
"$SYSCONF" p -- make
atf_check -o match:'src: from-overlay' \
"$SYSCONF" p src src
# -f replaces discovery
printf 'BAR=only\n' > "$ETC/other.conf"
atf_check -o match:'BAR: only' \
"$SYSCONF" poudriere -f "$ETC/other.conf" BAR
# Missing globals
unset POUDRIERE_ETC
export POUDRIERE_ETC="$( pwd )/missing-etc"
mkdir -p "$POUDRIERE_ETC"
atf_check -s not-exit:0 -e match:'poudriere.conf' \
"$SYSCONF" p ZPOOL
}
poudriere_sysrc_cleanup()
{
rm -rf "$( pwd )/petc" "$( pwd )/missing-etc"
}
atf_test_case poudriere_overlays cleanup
poudriere_overlays_head()
{
atf_set "descr" \
"poudriere make/src/src-env overlays with --jail/--tree/--set"
}
poudriere_overlays_body()
{
find_sysconf
ETC="$( pwd )/petc"
D="$ETC/poudriere.d"
mkdir -p "$D"
export POUDRIERE_ETC="$ETC"
printf 'CFLAGS=global\n' > "$D/make.conf"
printf 'CFLAGS=jail\n' > "$D/131amd64-make.conf"
printf 'CFLAGS=tree\n' > "$D/default-make.conf"
printf 'CFLAGS=set\n' > "$D/dev-make.conf"
printf 'CFLAGS=combo\n' > "$D/131amd64-default-make.conf"
# Shorthand p m
atf_check -o inline:'CFLAGS: global\n' \
"$SYSCONF" p m CFLAGS
atf_check -o inline:'CFLAGS: jail\n' \
"$SYSCONF" poudriere make --jail 131amd64 CFLAGS
atf_check -o inline:'CFLAGS: tree\n' \
"$SYSCONF" p m --tree default CFLAGS
atf_check -o inline:'CFLAGS: tree\n' \
"$SYSCONF" poudriere make --ports default CFLAGS
atf_check -o inline:'CFLAGS: set\n' \
"$SYSCONF" poudriere make --set dev CFLAGS
# jail-tree combo is last of those two
atf_check -o inline:'CFLAGS: combo\n' \
"$SYSCONF" poudriere make --jail 131amd64 --tree default CFLAGS
# Rewrite overlay's existing name; new name goes to global
atf_check -o match:'CFLAGS' \
"$SYSCONF" poudriere make --jail 131amd64 CFLAGS=-O2
atf_check -o match:'CFLAGS=-O2' cat "$D/131amd64-make.conf"
atf_check -o match:'CFLAGS=global' cat "$D/make.conf"
atf_check -o match:'CXXFLAGS' \
"$SYSCONF" poudriere make --jail 131amd64 CXXFLAGS=-pipe
atf_check -o match:'CXXFLAGS=-pipe' cat "$D/make.conf"
atf_check -o not-match:'CXXFLAGS' cat "$D/131amd64-make.conf"
# Create missing global
rm -f "$D/make.conf"
atf_check -o match:'LDFLAGS' \
"$SYSCONF" p m LDFLAGS=-L/usr/local/lib
atf_check -o match:'LDFLAGS=-L/usr/local/lib' cat "$D/make.conf"
# src vs src-env; --tree ignored (no tree-src.conf in poudriere(8))
printf 'WITHOUT_FOO=\n' > "$D/src.conf"
printf 'WITHOUT_TREE=\n' > "$D/default-src.conf"
printf 'SRC_ENV_VAR=1\n' > "$D/src-env.conf"
printf 'SRC_ENV_VAR=tree\n' > "$D/default-src-env.conf"
atf_check -o inline:'WITHOUT_FOO (present)\n' \
"$SYSCONF" poudriere src WITHOUT_FOO
atf_check -s not-exit:0 -e match:'unknown directive' \
"$SYSCONF" poudriere src --tree default WITHOUT_TREE
atf_check -o inline:'SRC_ENV_VAR: 1\n' \
"$SYSCONF" poudriere src-env SRC_ENV_VAR
atf_check -o inline:'SRC_ENV_VAR: 1\n' \
"$SYSCONF" poudriere src-env --tree default SRC_ENV_VAR
atf_check -o inline:'SRC_ENV_VAR: 1\n' \
"$SYSCONF" p src-e SRC_ENV_VAR
# Ambiguous nested prefix
atf_check -s not-exit:0 -e match:'ambiguous' -e match:'src' \
-e match:'src-env' \
"$SYSCONF" p s FOO
# -l lists the collection
atf_check -o match:'make.conf' -o match:'131amd64-make.conf' \
"$SYSCONF" poudriere make --jail 131amd64 -l
# -L lists every poudriere(8) stem, including files not on disk
atf_check -o inline:"$D/make.conf\n$D/abc-make.conf\n$D/xyz-make.conf\n$D/160-make.conf\n$D/xyz-abc-make.conf\n$D/160-xyz-make.conf\n$D/160-abc-make.conf\n$D/160-xyz-abc-make.conf\n" \
"$SYSCONF" p m --jail 160 --set abc --tree xyz -L
atf_check -o inline:"$D/make.conf\n$D/xyz-make.conf\n$D/160-make.conf\n$D/160-xyz-make.conf\n" \
"$SYSCONF" p m --jail 160 --tree xyz -L
atf_check -o inline:"$D/make.conf\n" \
"$SYSCONF" p m --jail 160 --set abc --tree xyz -l
atf_check -o inline:"$D/make.conf\n" \
"$SYSCONF" p m --jail 160 --set abc --tree xyz -E -L
atf_check -o inline:"$D/src.conf\n$D/abc-src.conf\n$D/160-src.conf\n" \
"$SYSCONF" p src --jail 160 --set abc --tree xyz -L
atf_check -o inline:"$D/src.conf\n$D/160-src.conf\n" \
"$SYSCONF" p src --jail 160 --tree xyz -L
atf_check -o inline:"$D/src-env.conf\n$D/abc-src-env.conf\n$D/160-src-env.conf\n" \
"$SYSCONF" p src-env --jail 160 --set abc --tree xyz -L
atf_check -o inline:"$D/src-env.conf\n" \
"$SYSCONF" p src-env --jail 160 --set abc --tree xyz -E -L
}
poudriere_overlays_cleanup()
{
rm -rf "$( pwd )/petc"
}
atf_init_test_cases()
{
atf_add_test_case make_src_knobs
@@ -500,4 +699,6 @@ atf_init_test_cases()
atf_add_test_case sysctl_oid_range
atf_add_test_case max_bytes_cap
atf_add_test_case target_prefix
atf_add_test_case poudriere_sysrc
atf_add_test_case poudriere_overlays
}