# # Copyright (c) 2026 Devin Teske # # SPDX-License-Identifier: BSD-2-Clause # # # Resolve the sysconf binary: honor SYSCONF if set, else the sibling # build product (objdir layout: .../sysconf/tests next to .../sysconf/sysconf), # else PATH. Require a regular file: when installed under # /usr/tests/usr.sbin/sysconf, `../sysconf' is this directory itself and # `[ -x dir ]' is true for searchable directories. # find_sysconf() { if [ -n "$SYSCONF" ] && [ -f "$SYSCONF" ] && [ -x "$SYSCONF" ]; then return fi if [ -f "$( atf_get_srcdir )/../sysconf" ] && [ -x "$( atf_get_srcdir )/../sysconf" ] then SYSCONF="$( atf_get_srcdir )/../sysconf" elif [ -f "$( pwd )/../sysconf" ] && [ -x "$( pwd )/../sysconf" ]; then SYSCONF="$( pwd )/../sysconf" else SYSCONF=$( command -v sysconf ) || atf_skip "sysconf binary not found" fi } setup_root() { find_sysconf ROOT="$( pwd )/root" mkdir -p "$ROOT/etc" "$ROOT/boot/defaults" } cleanup_root() { rm -rf "$( pwd )/root" } atf_test_case make_append_accumulate cleanup make_append_accumulate_head() { atf_set "descr" \ "make += accumulates on read and appends a line on write" } make_append_accumulate_body() { setup_root printf 'foo=1\n' > "$ROOT/etc/make.conf" atf_check -o inline:'foo: 1\n' "$SYSCONF" make -R "$ROOT" foo printf 'foo+=2\n' >> "$ROOT/etc/make.conf" atf_check -o inline:'foo: 1 2\n' "$SYSCONF" make -R "$ROOT" foo atf_check -o inline:'foo: 1 2 -> 1 2 -O2\n' \ "$SYSCONF" make -R "$ROOT" 'foo+=-O2' atf_check -o inline:'foo: 1 2 -O2\n' "$SYSCONF" make -R "$ROOT" foo atf_check -o match:'foo\+=-O2' cat "$ROOT/etc/make.conf" # -V on a new += statement reports (added), not `+= -> +=value' atf_check -o match:'make.conf:[0-9]*: foo\+=-O3 \(added\)' \ "$SYSCONF" make -R "$ROOT" -V 'foo+=-O3' atf_check -o inline:'foo: 1 2 -O2 -O3\n' "$SYSCONF" make -R "$ROOT" foo # Identical += is a no-op (append_present) before=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check "$SYSCONF" make -R "$ROOT" -c 'foo+=-O2' after=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check_equal "$before" "$after" } make_append_accumulate_cleanup() { cleanup_root } atf_test_case src_triad_and_trail cleanup src_triad_and_trail_head() { atf_set "descr" "src triad order, -V trail, writes prefer src.conf" } src_triad_and_trail_body() { setup_root printf 'CFLAGS=-O0\n' > "$ROOT/etc/src-env.conf" printf 'CFLAGS+=-g\n' > "$ROOT/etc/make.conf" printf 'CFLAGS+=-pipe\n' > "$ROOT/etc/src.conf" atf_check -o inline:'CFLAGS: -O0 -g -pipe\n' \ "$SYSCONF" src -R "$ROOT" CFLAGS atf_check -o match:'src-env.conf:1: CFLAGS=-O0' \ -o match:'make.conf:1: CFLAGS\+=-g -> -O0 -g' \ -o match:'src.conf:1: CFLAGS\+=-pipe -> -O0 -g -pipe' \ "$SYSCONF" src -R "$ROOT" -V CFLAGS atf_check -o match:'src.conf' \ "$SYSCONF" src -R "$ROOT" -v CFLAGS # New directive lands in src.conf atf_check "$SYSCONF" src -R "$ROOT" -q WITHOUT_FOO= atf_check -o match:'WITHOUT_FOO=' cat "$ROOT/etc/src.conf" atf_check -o not-match:'WITHOUT_FOO' cat "$ROOT/etc/make.conf" } src_triad_and_trail_cleanup() { cleanup_root } atf_test_case src_env_rejected src_env_rejected_head() { atf_set "descr" "src-env keyword is rejected with a hint toward src" } src_env_rejected_body() { find_sysconf atf_check -s not-exit:0 -e match:'src-env' -e match:'src' \ "$SYSCONF" src-env foo } atf_test_case env_overrides cleanup env_overrides_head() { atf_set "descr" "SRC_ENV_CONF / __MAKE_CONF / SRCCONF remap the triad" } env_overrides_body() { setup_root mkdir -p "$ROOT/alt" printf 'X=from-env\n' > "$ROOT/alt/se.conf" printf 'X+=from-make\n' > "$ROOT/alt/mk.conf" printf 'X+=from-src\n' > "$ROOT/alt/sc.conf" # Empty stock files so -R still resolves the triad slots :> "$ROOT/etc/src-env.conf" :> "$ROOT/etc/make.conf" :> "$ROOT/etc/src.conf" export SRC_ENV_CONF="$ROOT/alt/se.conf" export __MAKE_CONF="$ROOT/alt/mk.conf" export SRCCONF="$ROOT/alt/sc.conf" atf_check -o inline:'X: from-env from-make from-src\n' \ "$SYSCONF" src -R "$ROOT" X unset SRC_ENV_CONF __MAKE_CONF SRCCONF } env_overrides_cleanup() { cleanup_root } atf_test_case attached_f_passthrough cleanup attached_f_passthrough_head() { atf_set "descr" \ "Attached -fPATH does not steal the next argv (rc as name)" } attached_f_passthrough_body() { setup_root mkdir -p "$ROOT/boot" printf 'zfs_load="YES"\n' > "$ROOT/boot/loader.conf" # # If find_target consumed 'loader' as -f's argument, 'rc' would become # the target and exec sysrc(8). Correctly, target is loader and 'rc' # is an unknown directive name. # atf_check -s not-exit:0 -e match:'unknown directive' \ "$SYSCONF" -R "$ROOT" -f/boot/loader.conf loader rc } attached_f_passthrough_cleanup() { cleanup_root } atf_test_case verbatim_backslash cleanup verbatim_backslash_head() { atf_set "descr" \ "verbatim_ok re-examines the byte after an even \\\\ run" } verbatim_backslash_body() { setup_root printf 'foo=1\n' > "$ROOT/etc/make.conf" # Even-length \\ before # must not skip #: put must reject (Faraz) atf_check -s not-exit:0 -e match:'Invalid argument' \ "$SYSCONF" make -R "$ROOT" 'foo=a\\#b' # A value without a comment marker still writes. atf_check -o match:'foo:' \ "$SYSCONF" make -R "$ROOT" 'foo=a\\b' atf_check -o match:'foo=a\\\\b' cat "$ROOT/etc/make.conf" } verbatim_backslash_cleanup() { cleanup_root } atf_test_case make_strike_last_assign cleanup make_strike_last_assign_head() { atf_set "descr" \ "make -= strikes the last assignment containing the word" } make_strike_last_assign_body() { setup_root printf 'bar+=1\nbar+=1 2\nbar+=1 2 3\n' > "$ROOT/etc/make.conf" atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=3' atf_check -o inline:'bar+=1\nbar+=1 2\nbar+=1 2\n' \ cat "$ROOT/etc/make.conf" atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=2' atf_check -o inline:'bar+=1\nbar+=1 2\nbar+=1\n' \ cat "$ROOT/etc/make.conf" atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=1' atf_check -o inline:'bar+=1\nbar+=1 2\n' cat "$ROOT/etc/make.conf" atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=1' atf_check -o inline:'bar+=1\nbar+=2\n' cat "$ROOT/etc/make.conf" atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=2' atf_check -o inline:'bar+=1\n' cat "$ROOT/etc/make.conf" atf_check -o inline:'bar: 1 (unchanged)\n' \ "$SYSCONF" make -R "$ROOT" 'bar-=9' # Emptying the last word deletes the statement: (removed), like (added) printf 'z+=only\n' >>"$ROOT/etc/make.conf" atf_check -o match:'make.conf:[0-9]*: z\+=only \(removed\)' \ "$SYSCONF" make -R "$ROOT" -V 'z-=only' atf_check -o not-match:'^z\+=' cat "$ROOT/etc/make.conf" } make_strike_last_assign_cleanup() { cleanup_root } atf_test_case equal_value_nocheck_mtime cleanup equal_value_nocheck_mtime_head() { atf_set "descr" "Equal-value write and -c leave mtime alone" } equal_value_nocheck_mtime_body() { setup_root printf 'bar=1\n' > "$ROOT/etc/make.conf" sleep 1 before=$( stat -f '%m' "$ROOT/etc/make.conf" ) # Equal-value write: informational echo, file untouched atf_check -o inline:'bar: 1 (unchanged)\n' \ "$SYSCONF" make -R "$ROOT" bar=1 # -e uses `=' for write echoes the same as for reads atf_check -o inline:'bar=1 (unchanged)\n' \ "$SYSCONF" make -R "$ROOT" -e bar=1 after=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check_equal "$before" "$after" # -q suppresses the echo; -c is silent and does not write atf_check -o empty "$SYSCONF" make -R "$ROOT" -q bar=1 atf_check -o empty "$SYSCONF" make -R "$ROOT" -c bar=1 after2=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check_equal "$before" "$after2" atf_check -o inline:'bar=1 # -> 2\n' \ "$SYSCONF" make -R "$ROOT" -e bar=2 atf_check -o inline:'bar=2\n' \ "$SYSCONF" make -R "$ROOT" -e bar } equal_value_nocheck_mtime_cleanup() { cleanup_root } atf_test_case sysctl_oid_range cleanup sysctl_oid_range_head() { atf_set "descr" \ "sysctl target rejects values that overflow the OID CTLTYPE" } sysctl_oid_range_body() { find_sysconf case "$( uname -s )" in FreeBSD) ;; *) atf_skip "requires FreeBSD sysctl OIDFMT" ;; esac # -f alone (no -R) still validates against the running kernel. conf="$( pwd )/sysctl.conf" :> "$conf" atf_check -s exit:1 -e match:'out of range for integer' \ "$SYSCONF" sysctl -f "$conf" \ security.bsd.see_other_uids=99999999999 atf_check -o empty cat "$conf" atf_check -s exit:1 -e match:'out of range for unsigned integer' \ "$SYSCONF" sysctl -f "$conf" kern.ipc.somaxconn=-1 atf_check -s exit:1 -e match:'out of range for unsigned integer' \ "$SYSCONF" sysctl -f "$conf" kern.ipc.somaxconn=abc atf_check -o match:'see_other_uids' \ "$SYSCONF" sysctl -f "$conf" security.bsd.see_other_uids=0 atf_check -o match:'see_other_uids=0' cat "$conf" } sysctl_oid_range_cleanup() { rm -f "$( pwd )/sysctl.conf" } atf_test_case make_src_knobs cleanup make_src_knobs_head() { atf_set "descr" \ "-s WITH_/WITHOUT_ presence, query display, unchanged, -x" } make_src_knobs_body() { setup_root :> "$ROOT/etc/make.conf" :> "$ROOT/etc/sysctl.conf" :> "$ROOT/etc/src-env.conf" :> "$ROOT/etc/src.conf" # -s only on make/src atf_check -s exit:1 -e match:'only valid for make and src' \ "$SYSCONF" sysctl -R "$ROOT" -s WITHOUT_FOO # name must be WITH_/WITHOUT_ atf_check -s exit:1 -e match:'WITH_ or WITHOUT_' \ "$SYSCONF" make -R "$ROOT" -s CFLAGS # no value with -s atf_check -s exit:1 -e match:'does not take a value' \ "$SYSCONF" make -R "$ROOT" -s 'WITHOUT_FOO=' atf_check -o inline:'WITHOUT_FOO: (not present) -> (present)\n' \ "$SYSCONF" make -R "$ROOT" -s WITHOUT_FOO atf_check -o match:'^WITHOUT_FOO=$' cat "$ROOT/etc/make.conf" atf_check -o inline:'WITHOUT_FOO (present)\n' \ "$SYSCONF" make -R "$ROOT" WITHOUT_FOO atf_check -o inline:'WITHOUT_FOO=\n' \ "$SYSCONF" make -R "$ROOT" -e WITHOUT_FOO atf_check -o inline:'\n' \ "$SYSCONF" make -R "$ROOT" -n WITHOUT_FOO before=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check -o inline:'WITHOUT_FOO: (present) (unchanged)\n' \ "$SYSCONF" make -R "$ROOT" -s WITHOUT_FOO after=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check_equal "$before" "$after" # Non-empty placeholder (=t) still means present (defined()) atf_check -o inline:'WITHOUT_BAR: (not present) -> (present)\n' \ "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAR=t' atf_check -o match:'^WITHOUT_BAR=t$' cat "$ROOT/etc/make.conf" atf_check -o inline:'WITHOUT_BAR (present)\n' \ "$SYSCONF" make -R "$ROOT" WITHOUT_BAR atf_check -o inline:'WITHOUT_BAR=t\n' \ "$SYSCONF" make -R "$ROOT" -e WITHOUT_BAR atf_check -o inline:'t\n' \ "$SYSCONF" make -R "$ROOT" -n WITHOUT_BAR before=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check -o inline:'WITHOUT_BAR: (present) (unchanged)\n' \ "$SYSCONF" make -R "$ROOT" -s WITHOUT_BAR after=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check_equal "$before" "$after" atf_check -o match:'^WITHOUT_BAR=t$' cat "$ROOT/etc/make.conf" # Explicit name= always writes (incl. empty); echo value changes atf_check -o inline:'WITHOUT_BAR: t -> \n' \ "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAR=' atf_check -o match:'^WITHOUT_BAR=$' cat "$ROOT/etc/make.conf" atf_check -o inline:'WITHOUT_BAR: -> 123\n' \ "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAR=123' atf_check -o match:'^WITHOUT_BAR=123$' cat "$ROOT/etc/make.conf" atf_check -o inline:'WITHOUT_BAR: 123 -> 456\n' \ "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAR=456' atf_check -o match:'^WITHOUT_BAR=456$' cat "$ROOT/etc/make.conf" # -s still no-op while present with a value before=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check -o inline:'WITHOUT_BAR: (present) (unchanged)\n' \ "$SYSCONF" make -R "$ROOT" -s WITHOUT_BAR after=$( stat -f '%m' "$ROOT/etc/make.conf" ) atf_check_equal "$before" "$after" atf_check -o match:'^WITHOUT_BAR=456$' cat "$ROOT/etc/make.conf" # src prefers src.conf atf_check -o inline:'WITHOUT_LLDB: (not present) -> (present)\n' \ "$SYSCONF" src -R "$ROOT" -s WITHOUT_LLDB atf_check -o match:'^WITHOUT_LLDB=$' cat "$ROOT/etc/src.conf" # -x is quiet unless -v/-V (same as non-knob removals) atf_check -o empty \ "$SYSCONF" src -R "$ROOT" -x WITHOUT_LLDB atf_check -o empty cat "$ROOT/etc/src.conf" atf_check -o inline:'WITHOUT_LLDB: (not present) -> (present)\n' \ "$SYSCONF" src -R "$ROOT" -s WITHOUT_LLDB atf_check -o match:'WITHOUT_LLDB \(removed\)' \ "$SYSCONF" src -R "$ROOT" -vx WITHOUT_LLDB atf_check -o empty cat "$ROOT/etc/src.conf" # WITH_*=no (exact lowercase) warns like bsd.mkopt.mk; WITHOUT_*=no # and WITH_*=NO do not atf_check -e match:'Use WITHOUT_FOO=1 instead of WITH_FOO=no' \ -o match:'WITH_FOO' \ "$SYSCONF" make -R "$ROOT" 'WITH_FOO=no' atf_check -o match:'^WITH_FOO=no$' cat "$ROOT/etc/make.conf" atf_check -e empty -o match:'WITH_BAR' \ "$SYSCONF" make -R "$ROOT" 'WITH_BAR=NO' atf_check -e empty -o match:'WITHOUT_BAZ' \ "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAZ=no' # Reads remind with file:line (presence display hides =no) atf_check -e match:'make.conf:[0-9]+: Use WITHOUT_FOO=1 instead of WITH_FOO=no' \ -o inline:'WITH_FOO (present)\n' \ "$SYSCONF" make -R "$ROOT" WITH_FOO atf_check -e match:'make.conf:[0-9]+: Use WITHOUT_FOO=1 instead of WITH_FOO=no' \ -o match:'WITH_FOO \(present\)' \ "$SYSCONF" make -R "$ROOT" -a atf_check -e match:'make.conf:[0-9]+: Use WITHOUT_FOO=1 instead of WITH_FOO=no' \ -o inline:'WITH_FOO=no\n' \ "$SYSCONF" make -R "$ROOT" -e WITH_FOO atf_check -e empty -o inline:'WITH_FOO (present)\n' \ "$SYSCONF" make -R "$ROOT" -q WITH_FOO # WITHOUT_MODULES is not a presence knob atf_check -s exit:1 -e match:'WITHOUT_MODULES takes a module list' \ "$SYSCONF" make -R "$ROOT" -s WITHOUT_MODULES atf_check -o match:'WITHOUT_MODULES: -> plip' \ "$SYSCONF" make -R "$ROOT" 'WITHOUT_MODULES=plip' atf_check -o inline:'WITHOUT_MODULES: plip\n' \ "$SYSCONF" make -R "$ROOT" WITHOUT_MODULES } make_src_knobs_cleanup() { cleanup_root } atf_init_test_cases() { atf_add_test_case make_src_knobs atf_add_test_case make_append_accumulate atf_add_test_case make_strike_last_assign atf_add_test_case src_triad_and_trail atf_add_test_case src_env_rejected atf_add_test_case env_overrides atf_add_test_case attached_f_passthrough atf_add_test_case verbatim_backslash atf_add_test_case equal_value_nocheck_mtime atf_add_test_case sysctl_oid_range }