xref: /freebsd/usr.sbin/sysconf/tests/sysconf_test.sh (revision c4fde87a3236b500246d4fce76dbca2a3d64f73a)
1#
2# Copyright (c) 2026 Devin Teske <dteske@FreeBSD.org>
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6
7#
8# Resolve the sysconf binary: honor SYSCONF if set, else the sibling
9# build product (objdir layout: .../sysconf/tests next to .../sysconf/sysconf),
10# else PATH.  Require a regular file: when installed under
11# /usr/tests/usr.sbin/sysconf, `../sysconf' is this directory itself and
12# `[ -x dir ]' is true for searchable directories.
13#
14find_sysconf()
15{
16	if [ -n "$SYSCONF" ] && [ -f "$SYSCONF" ] && [ -x "$SYSCONF" ]; then
17		return
18	fi
19	if [ -f "$( atf_get_srcdir )/../sysconf" ] &&
20	   [ -x "$( atf_get_srcdir )/../sysconf" ]
21	then
22		SYSCONF="$( atf_get_srcdir )/../sysconf"
23	elif [ -f "$( pwd )/../sysconf" ] && [ -x "$( pwd )/../sysconf" ]; then
24		SYSCONF="$( pwd )/../sysconf"
25	else
26		SYSCONF=$( command -v sysconf ) ||
27			atf_skip "sysconf binary not found"
28	fi
29}
30
31setup_root()
32{
33	find_sysconf
34	ROOT="$( pwd )/root"
35	mkdir -p "$ROOT/etc" "$ROOT/boot/defaults"
36}
37
38cleanup_root()
39{
40	rm -rf "$( pwd )/root"
41}
42
43atf_test_case make_append_accumulate cleanup
44make_append_accumulate_head()
45{
46	atf_set "descr" \
47		"make += accumulates on read and appends a line on write"
48}
49make_append_accumulate_body()
50{
51	setup_root
52	printf 'foo=1\n' > "$ROOT/etc/make.conf"
53	atf_check -o inline:'foo: 1\n' "$SYSCONF" make -R "$ROOT" foo
54	printf 'foo+=2\n' >> "$ROOT/etc/make.conf"
55	atf_check -o inline:'foo: 1 2\n' "$SYSCONF" make -R "$ROOT" foo
56	atf_check -o inline:'foo: 1 2 -> 1 2 -O2\n' \
57	    "$SYSCONF" make -R "$ROOT" 'foo+=-O2'
58	atf_check -o inline:'foo: 1 2 -O2\n' "$SYSCONF" make -R "$ROOT" foo
59	atf_check -o match:'foo\+=-O2' cat "$ROOT/etc/make.conf"
60	# -V on a new += statement reports (added), not `+= -> +=value'
61	atf_check -o match:'make.conf:[0-9]*: foo\+=-O3 \(added\)' \
62	    "$SYSCONF" make -R "$ROOT" -V 'foo+=-O3'
63	atf_check -o inline:'foo: 1 2 -O2 -O3\n' "$SYSCONF" make -R "$ROOT" foo
64	# Identical += is a no-op (append_present)
65	before=$( stat -f '%m' "$ROOT/etc/make.conf" )
66	atf_check "$SYSCONF" make -R "$ROOT" -c 'foo+=-O2'
67	after=$( stat -f '%m' "$ROOT/etc/make.conf" )
68	atf_check_equal "$before" "$after"
69}
70make_append_accumulate_cleanup()
71{
72	cleanup_root
73}
74
75atf_test_case src_triad_and_trail cleanup
76src_triad_and_trail_head()
77{
78	atf_set "descr" "src triad order, -V trail, writes prefer src.conf"
79}
80src_triad_and_trail_body()
81{
82	setup_root
83	printf 'CFLAGS=-O0\n' > "$ROOT/etc/src-env.conf"
84	printf 'CFLAGS+=-g\n' > "$ROOT/etc/make.conf"
85	printf 'CFLAGS+=-pipe\n' > "$ROOT/etc/src.conf"
86	atf_check -o inline:'CFLAGS: -O0 -g -pipe\n' \
87	    "$SYSCONF" src -R "$ROOT" CFLAGS
88	atf_check -o match:'src-env.conf:1: CFLAGS=-O0' \
89	    -o match:'make.conf:1: CFLAGS\+=-g -> -O0 -g' \
90	    -o match:'src.conf:1: CFLAGS\+=-pipe -> -O0 -g -pipe' \
91	    "$SYSCONF" src -R "$ROOT" -V CFLAGS
92	atf_check -o match:'src.conf' \
93	    "$SYSCONF" src -R "$ROOT" -v CFLAGS
94	# New directive lands in src.conf
95	atf_check "$SYSCONF" src -R "$ROOT" -q WITHOUT_FOO=
96	atf_check -o match:'WITHOUT_FOO=' cat "$ROOT/etc/src.conf"
97	atf_check -o not-match:'WITHOUT_FOO' cat "$ROOT/etc/make.conf"
98}
99src_triad_and_trail_cleanup()
100{
101	cleanup_root
102}
103
104atf_test_case src_env_rejected
105src_env_rejected_head()
106{
107	atf_set "descr" "src-env keyword is rejected with a hint toward src"
108}
109src_env_rejected_body()
110{
111	find_sysconf
112	atf_check -s not-exit:0 -e match:'src-env' -e match:'src' \
113	    "$SYSCONF" src-env foo
114}
115
116atf_test_case env_overrides cleanup
117env_overrides_head()
118{
119	atf_set "descr" "SRC_ENV_CONF / __MAKE_CONF / SRCCONF remap the triad"
120}
121env_overrides_body()
122{
123	setup_root
124	mkdir -p "$ROOT/alt"
125	printf 'X=from-env\n' > "$ROOT/alt/se.conf"
126	printf 'X+=from-make\n' > "$ROOT/alt/mk.conf"
127	printf 'X+=from-src\n' > "$ROOT/alt/sc.conf"
128	# Empty stock files so -R still resolves the triad slots
129	:> "$ROOT/etc/src-env.conf"
130	:> "$ROOT/etc/make.conf"
131	:> "$ROOT/etc/src.conf"
132	export SRC_ENV_CONF="$ROOT/alt/se.conf"
133	export __MAKE_CONF="$ROOT/alt/mk.conf"
134	export SRCCONF="$ROOT/alt/sc.conf"
135	atf_check -o inline:'X: from-env from-make from-src\n' \
136	    "$SYSCONF" src -R "$ROOT" X
137	unset SRC_ENV_CONF __MAKE_CONF SRCCONF
138}
139env_overrides_cleanup()
140{
141	cleanup_root
142}
143
144atf_test_case attached_f_passthrough cleanup
145attached_f_passthrough_head()
146{
147	atf_set "descr" \
148		"Attached -fPATH does not steal the next argv (rc as name)"
149}
150attached_f_passthrough_body()
151{
152	setup_root
153	mkdir -p "$ROOT/boot"
154	printf 'zfs_load="YES"\n' > "$ROOT/boot/loader.conf"
155	#
156	# If find_target consumed 'loader' as -f's argument, 'rc' would become
157	# the target and exec sysrc(8).  Correctly, target is loader and 'rc'
158	# is an unknown directive name.
159	#
160	atf_check -s not-exit:0 -e match:'unknown directive' \
161	    "$SYSCONF" -R "$ROOT" -f/boot/loader.conf loader rc
162}
163attached_f_passthrough_cleanup()
164{
165	cleanup_root
166}
167
168atf_test_case verbatim_backslash cleanup
169verbatim_backslash_head()
170{
171	atf_set "descr" \
172		"verbatim_ok re-examines the byte after an even \\\\ run"
173}
174verbatim_backslash_body()
175{
176	setup_root
177	printf 'foo=1\n' > "$ROOT/etc/make.conf"
178	# Even-length \\ before # must not skip #: put must reject (Faraz)
179	atf_check -s not-exit:0 -e match:'Invalid argument' \
180	    "$SYSCONF" make -R "$ROOT" 'foo=a\\#b'
181	# A value without a comment marker still writes.
182	atf_check -o match:'foo:' \
183	    "$SYSCONF" make -R "$ROOT" 'foo=a\\b'
184	atf_check -o match:'foo=a\\\\b' cat "$ROOT/etc/make.conf"
185}
186verbatim_backslash_cleanup()
187{
188	cleanup_root
189}
190
191atf_test_case make_strike_last_assign cleanup
192make_strike_last_assign_head()
193{
194	atf_set "descr" \
195		"make -= strikes the last assignment containing the word"
196}
197make_strike_last_assign_body()
198{
199	setup_root
200	printf 'bar+=1\nbar+=1 2\nbar+=1 2 3\n' > "$ROOT/etc/make.conf"
201	atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=3'
202	atf_check -o inline:'bar+=1\nbar+=1 2\nbar+=1 2\n' \
203	    cat "$ROOT/etc/make.conf"
204	atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=2'
205	atf_check -o inline:'bar+=1\nbar+=1 2\nbar+=1\n' \
206	    cat "$ROOT/etc/make.conf"
207	atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=1'
208	atf_check -o inline:'bar+=1\nbar+=1 2\n' cat "$ROOT/etc/make.conf"
209	atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=1'
210	atf_check -o inline:'bar+=1\nbar+=2\n' cat "$ROOT/etc/make.conf"
211	atf_check -o match:'->' "$SYSCONF" make -R "$ROOT" 'bar-=2'
212	atf_check -o inline:'bar+=1\n' cat "$ROOT/etc/make.conf"
213	atf_check -o inline:'bar: 1 (unchanged)\n' \
214	    "$SYSCONF" make -R "$ROOT" 'bar-=9'
215	# Emptying the last word deletes the statement: (removed), like (added)
216	printf 'z+=only\n' >>"$ROOT/etc/make.conf"
217	atf_check -o match:'make.conf:[0-9]*: z\+=only \(removed\)' \
218	    "$SYSCONF" make -R "$ROOT" -V 'z-=only'
219	atf_check -o not-match:'^z\+=' cat "$ROOT/etc/make.conf"
220}
221make_strike_last_assign_cleanup()
222{
223	cleanup_root
224}
225
226atf_test_case equal_value_nocheck_mtime cleanup
227equal_value_nocheck_mtime_head()
228{
229	atf_set "descr" "Equal-value write and -c leave mtime alone"
230}
231equal_value_nocheck_mtime_body()
232{
233	setup_root
234	printf 'bar=1\n' > "$ROOT/etc/make.conf"
235	sleep 1
236	before=$( stat -f '%m' "$ROOT/etc/make.conf" )
237	# Equal-value write: informational echo, file untouched
238	atf_check -o inline:'bar: 1 (unchanged)\n' \
239	    "$SYSCONF" make -R "$ROOT" bar=1
240	# -e uses `=' for write echoes the same as for reads
241	atf_check -o inline:'bar=1 (unchanged)\n' \
242	    "$SYSCONF" make -R "$ROOT" -e bar=1
243	after=$( stat -f '%m' "$ROOT/etc/make.conf" )
244	atf_check_equal "$before" "$after"
245	# -q suppresses the echo; -c is silent and does not write
246	atf_check -o empty "$SYSCONF" make -R "$ROOT" -q bar=1
247	atf_check -o empty "$SYSCONF" make -R "$ROOT" -c bar=1
248	after2=$( stat -f '%m' "$ROOT/etc/make.conf" )
249	atf_check_equal "$before" "$after2"
250	atf_check -o inline:'bar=1 # -> 2\n' \
251	    "$SYSCONF" make -R "$ROOT" -e bar=2
252	atf_check -o inline:'bar=2\n' \
253	    "$SYSCONF" make -R "$ROOT" -e bar
254}
255equal_value_nocheck_mtime_cleanup()
256{
257	cleanup_root
258}
259
260atf_test_case sysctl_oid_range cleanup
261sysctl_oid_range_head()
262{
263	atf_set "descr" \
264		"sysctl target rejects values that overflow the OID CTLTYPE"
265}
266sysctl_oid_range_body()
267{
268	find_sysconf
269	case "$( uname -s )" in
270	FreeBSD) ;;
271	*) atf_skip "requires FreeBSD sysctl OIDFMT" ;;
272	esac
273	# -f alone (no -R) still validates against the running kernel.
274	conf="$( pwd )/sysctl.conf"
275	:> "$conf"
276	atf_check -s exit:1 -e match:'out of range for integer' \
277	    "$SYSCONF" sysctl -f "$conf" \
278	    security.bsd.see_other_uids=99999999999
279	atf_check -o empty cat "$conf"
280	atf_check -s exit:1 -e match:'out of range for unsigned integer' \
281	    "$SYSCONF" sysctl -f "$conf" kern.ipc.somaxconn=-1
282	atf_check -s exit:1 -e match:'out of range for unsigned integer' \
283	    "$SYSCONF" sysctl -f "$conf" kern.ipc.somaxconn=abc
284	atf_check -o match:'see_other_uids' \
285	    "$SYSCONF" sysctl -f "$conf" security.bsd.see_other_uids=0
286	atf_check -o match:'see_other_uids=0' cat "$conf"
287}
288sysctl_oid_range_cleanup()
289{
290	rm -f "$( pwd )/sysctl.conf"
291}
292
293atf_test_case make_src_knobs cleanup
294make_src_knobs_head()
295{
296	atf_set "descr" \
297		"-s WITH_/WITHOUT_ presence, query display, unchanged, -x"
298}
299make_src_knobs_body()
300{
301	setup_root
302	:> "$ROOT/etc/make.conf"
303	:> "$ROOT/etc/sysctl.conf"
304	:> "$ROOT/etc/src-env.conf"
305	:> "$ROOT/etc/src.conf"
306
307	# -s only on make/src
308	atf_check -s exit:1 -e match:'only valid for make and src' \
309	    "$SYSCONF" sysctl -R "$ROOT" -s WITHOUT_FOO
310	# name must be WITH_/WITHOUT_
311	atf_check -s exit:1 -e match:'WITH_ or WITHOUT_' \
312	    "$SYSCONF" make -R "$ROOT" -s CFLAGS
313	# no value with -s
314	atf_check -s exit:1 -e match:'does not take a value' \
315	    "$SYSCONF" make -R "$ROOT" -s 'WITHOUT_FOO='
316
317	atf_check -o inline:'WITHOUT_FOO: (not present) -> (present)\n' \
318	    "$SYSCONF" make -R "$ROOT" -s WITHOUT_FOO
319	atf_check -o match:'^WITHOUT_FOO=$' cat "$ROOT/etc/make.conf"
320	atf_check -o inline:'WITHOUT_FOO (present)\n' \
321	    "$SYSCONF" make -R "$ROOT" WITHOUT_FOO
322	atf_check -o inline:'WITHOUT_FOO=\n' \
323	    "$SYSCONF" make -R "$ROOT" -e WITHOUT_FOO
324	atf_check -o inline:'\n' \
325	    "$SYSCONF" make -R "$ROOT" -n WITHOUT_FOO
326
327	before=$( stat -f '%m' "$ROOT/etc/make.conf" )
328	atf_check -o inline:'WITHOUT_FOO: (present) (unchanged)\n' \
329	    "$SYSCONF" make -R "$ROOT" -s WITHOUT_FOO
330	after=$( stat -f '%m' "$ROOT/etc/make.conf" )
331	atf_check_equal "$before" "$after"
332
333	# Non-empty placeholder (=t) still means present (defined())
334	atf_check -o inline:'WITHOUT_BAR: (not present) -> (present)\n' \
335	    "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAR=t'
336	atf_check -o match:'^WITHOUT_BAR=t$' cat "$ROOT/etc/make.conf"
337	atf_check -o inline:'WITHOUT_BAR (present)\n' \
338	    "$SYSCONF" make -R "$ROOT" WITHOUT_BAR
339	atf_check -o inline:'WITHOUT_BAR=t\n' \
340	    "$SYSCONF" make -R "$ROOT" -e WITHOUT_BAR
341	atf_check -o inline:'t\n' \
342	    "$SYSCONF" make -R "$ROOT" -n WITHOUT_BAR
343	before=$( stat -f '%m' "$ROOT/etc/make.conf" )
344	atf_check -o inline:'WITHOUT_BAR: (present) (unchanged)\n' \
345	    "$SYSCONF" make -R "$ROOT" -s WITHOUT_BAR
346	after=$( stat -f '%m' "$ROOT/etc/make.conf" )
347	atf_check_equal "$before" "$after"
348	atf_check -o match:'^WITHOUT_BAR=t$' cat "$ROOT/etc/make.conf"
349
350	# Explicit name= always writes (incl. empty); echo value changes
351	atf_check -o inline:'WITHOUT_BAR: t -> \n' \
352	    "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAR='
353	atf_check -o match:'^WITHOUT_BAR=$' cat "$ROOT/etc/make.conf"
354	atf_check -o inline:'WITHOUT_BAR:  -> 123\n' \
355	    "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAR=123'
356	atf_check -o match:'^WITHOUT_BAR=123$' cat "$ROOT/etc/make.conf"
357	atf_check -o inline:'WITHOUT_BAR: 123 -> 456\n' \
358	    "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAR=456'
359	atf_check -o match:'^WITHOUT_BAR=456$' cat "$ROOT/etc/make.conf"
360	# -s still no-op while present with a value
361	before=$( stat -f '%m' "$ROOT/etc/make.conf" )
362	atf_check -o inline:'WITHOUT_BAR: (present) (unchanged)\n' \
363	    "$SYSCONF" make -R "$ROOT" -s WITHOUT_BAR
364	after=$( stat -f '%m' "$ROOT/etc/make.conf" )
365	atf_check_equal "$before" "$after"
366	atf_check -o match:'^WITHOUT_BAR=456$' cat "$ROOT/etc/make.conf"
367
368	# src prefers src.conf
369	atf_check -o inline:'WITHOUT_LLDB: (not present) -> (present)\n' \
370	    "$SYSCONF" src -R "$ROOT" -s WITHOUT_LLDB
371	atf_check -o match:'^WITHOUT_LLDB=$' cat "$ROOT/etc/src.conf"
372	# -x is quiet unless -v/-V (same as non-knob removals)
373	atf_check -o empty \
374	    "$SYSCONF" src -R "$ROOT" -x WITHOUT_LLDB
375	atf_check -o empty cat "$ROOT/etc/src.conf"
376	atf_check -o inline:'WITHOUT_LLDB: (not present) -> (present)\n' \
377	    "$SYSCONF" src -R "$ROOT" -s WITHOUT_LLDB
378	atf_check -o match:'WITHOUT_LLDB \(removed\)' \
379	    "$SYSCONF" src -R "$ROOT" -vx WITHOUT_LLDB
380	atf_check -o empty cat "$ROOT/etc/src.conf"
381
382	# WITH_*=no (exact lowercase) warns like bsd.mkopt.mk; WITHOUT_*=no
383	# and WITH_*=NO do not
384	atf_check -e match:'Use WITHOUT_FOO=1 instead of WITH_FOO=no' \
385	    -o match:'WITH_FOO' \
386	    "$SYSCONF" make -R "$ROOT" 'WITH_FOO=no'
387	atf_check -o match:'^WITH_FOO=no$' cat "$ROOT/etc/make.conf"
388	atf_check -e empty -o match:'WITH_BAR' \
389	    "$SYSCONF" make -R "$ROOT" 'WITH_BAR=NO'
390	atf_check -e empty -o match:'WITHOUT_BAZ' \
391	    "$SYSCONF" make -R "$ROOT" 'WITHOUT_BAZ=no'
392
393	# Reads remind with file:line (presence display hides =no)
394	atf_check -e match:'make.conf:[0-9]+: Use WITHOUT_FOO=1 instead of WITH_FOO=no' \
395	    -o inline:'WITH_FOO (present)\n' \
396	    "$SYSCONF" make -R "$ROOT" WITH_FOO
397	atf_check -e match:'make.conf:[0-9]+: Use WITHOUT_FOO=1 instead of WITH_FOO=no' \
398	    -o match:'WITH_FOO \(present\)' \
399	    "$SYSCONF" make -R "$ROOT" -a
400	atf_check -e match:'make.conf:[0-9]+: Use WITHOUT_FOO=1 instead of WITH_FOO=no' \
401	    -o inline:'WITH_FOO=no\n' \
402	    "$SYSCONF" make -R "$ROOT" -e WITH_FOO
403	atf_check -e empty -o inline:'WITH_FOO (present)\n' \
404	    "$SYSCONF" make -R "$ROOT" -q WITH_FOO
405
406	# WITHOUT_MODULES is not a presence knob
407	atf_check -s exit:1 -e match:'WITHOUT_MODULES takes a module list' \
408	    "$SYSCONF" make -R "$ROOT" -s WITHOUT_MODULES
409	atf_check -o match:'WITHOUT_MODULES:  -> plip' \
410	    "$SYSCONF" make -R "$ROOT" 'WITHOUT_MODULES=plip'
411	atf_check -o inline:'WITHOUT_MODULES: plip\n' \
412	    "$SYSCONF" make -R "$ROOT" WITHOUT_MODULES
413}
414make_src_knobs_cleanup()
415{
416	cleanup_root
417}
418
419atf_test_case max_bytes_cap cleanup
420max_bytes_cap_head()
421{
422	atf_set "descr" "BSDCONF_MAX_BYTES bounds parse input"
423}
424max_bytes_cap_body()
425{
426	setup_root
427	printf 'foo=ok\n' > "$ROOT/etc/make.conf"
428	atf_check -o inline:'foo: ok\n' "$SYSCONF" make -R "$ROOT" foo
429	# A tight cap rejects an otherwise valid file
430	atf_check -s not-exit:0 -e match:'File too large' \
431	    env BSDCONF_MAX_BYTES=4 "$SYSCONF" make -R "$ROOT" foo
432	got=$( printf 'bar=piped\n' | "$SYSCONF" generic -f - bar ) ||
433		atf_fail "pipe parse failed"
434	atf_check_equal "bar: piped" "$got"
435}
436max_bytes_cap_cleanup()
437{
438	cleanup_root
439}
440
441atf_test_case target_prefix cleanup
442target_prefix_head()
443{
444	atf_set "descr" \
445		"Unique target prefixes resolve; ambiguous and unknown fail"
446}
447target_prefix_body()
448{
449	find_sysconf
450	setup_root
451	:> "$ROOT/etc/make.conf"
452	:> "$ROOT/etc/src-env.conf"
453	:> "$ROOT/etc/src.conf"
454	printf 'foo=1\n' > "$ROOT/etc/make.conf"
455
456	# Unique prefixes
457	atf_check -o inline:'foo: 1\n' "$SYSCONF" m -R "$ROOT" foo
458	atf_check -o inline:'foo: 1\n' "$SYSCONF" ma -R "$ROOT" foo
459	atf_check -o inline:'foo: 1\n' "$SYSCONF" make -R "$ROOT" foo
460	atf_check -o inline:'foo: 1\n' "$SYSCONF" sr -R "$ROOT" foo
461	printf 'kern.foo=1\n' > "$ROOT/etc/sysctl.conf"
462	atf_check -o inline:'kern.foo: 1\n' "$SYSCONF" sy -R "$ROOT" kern.foo
463	# generic requires -f
464	atf_check -s not-exit:0 -e match:'no default files' \
465	    "$SYSCONF" g -R "$ROOT" foo
466	atf_check -o inline:'foo: 1\n' \
467	    "$SYSCONF" g -R "$ROOT" -f /etc/make.conf foo
468
469	# Ambiguous: src and sysctl
470	atf_check -s not-exit:0 \
471	    -e match:'ambiguous target' \
472	    -e match:'src' \
473	    -e match:'sysctl' \
474	    "$SYSCONF" s foo
475	# Exact still wins
476	atf_check -o inline:'foo: 1\n' "$SYSCONF" src -R "$ROOT" foo
477	# Infix is not a prefix
478	atf_check -s not-exit:0 -e match:'unknown target' \
479	    "$SYSCONF" ctl foo
480	# src-env is not a prefix of src
481	atf_check -s not-exit:0 -e match:'src-env' -e match:'src' \
482	    "$SYSCONF" src-env foo
483}
484target_prefix_cleanup()
485{
486	cleanup_root
487}
488
489atf_test_case poudriere_sysrc cleanup
490poudriere_sysrc_head()
491{
492	atf_set "descr" \
493		"poudriere target feeds sysrc -f over the conf collection"
494}
495poudriere_sysrc_body()
496{
497	find_sysconf
498	command -v sysrc > /dev/null 2>&1 ||
499		atf_skip "sysrc not installed"
500	ETC="$( pwd )/petc"
501	mkdir -p "$ETC/poudriere.d"
502	printf 'ZPOOL=old\nFOO=global\n' > "$ETC/poudriere.conf"
503	printf 'FOO=jail\nJOBS=2\n' \
504	    > "$ETC/poudriere.d/131amd64-poudriere.conf"
505	export POUDRIERE_ETC="$ETC"
506
507	# -l / -L are printed here, one path per line (not sysrc -L)
508	atf_check -o inline:"$ETC/poudriere.conf\n" \
509	    "$SYSCONF" p -l
510	atf_check -o inline:"$ETC/poudriere.conf\n$ETC/poudriere.d/poudriere.conf\n" \
511	    "$SYSCONF" p -L
512	atf_check -o inline:"$ETC/poudriere.conf\n$ETC/poudriere.d/131amd64-poudriere.conf\n" \
513	    "$SYSCONF" p --jail 131amd64 -l
514	atf_check -o inline:"$ETC/poudriere.conf\n$ETC/poudriere.d/poudriere.conf\n$ETC/poudriere.d/131amd64-poudriere.conf\n" \
515	    "$SYSCONF" p --jail 131amd64 -L
516	atf_check -o inline:"$ETC/poudriere.conf\n" \
517	    "$SYSCONF" p --jail 99amd64 -l
518	atf_check -o match:'99amd64-poudriere.conf' \
519	    -o not-match:'rc\.conf' \
520	    "$SYSCONF" p --jail 99amd64 -L
521	atf_check -o inline:"$ETC/poudriere.conf\n" \
522	    "$SYSCONF" p -E -L
523	atf_check -o inline:"$ETC/poudriere.conf\n$ETC/poudriere.d/131amd64-poudriere.conf\n" \
524	    "$SYSCONF" p --jail 131amd64 -E -L
525	atf_check -s not-exit:0 -e match:'take no names' \
526	    "$SYSCONF" p -l ZPOOL
527
528	# Shorthand p; read from the global file
529	atf_check -o match:'ZPOOL: old' \
530	    "$SYSCONF" p ZPOOL
531	# Write a new name into the first file
532	atf_check -o match:'BASEFS' \
533	    "$SYSCONF" poudriere BASEFS=/poudriere
534	atf_check -o match:'BASEFS=' cat "$ETC/poudriere.conf"
535	atf_check -o not-match:'BASEFS' \
536	    cat "$ETC/poudriere.d/131amd64-poudriere.conf"
537
538	# Overlay collection: --jail appends the jail overlay last
539	atf_check -o match:'FOO: jail' \
540	    "$SYSCONF" poudriere --jail 131amd64 FOO
541	# Without --jail the overlay is not in the collection
542	atf_check -o match:'FOO: global' \
543	    "$SYSCONF" poudriere FOO
544	# --tree is an alias of --ports
545	printf 'FOO=tree\n' > "$ETC/poudriere.d/default-poudriere.conf"
546	atf_check -o match:'FOO: tree' \
547	    "$SYSCONF" poudriere --tree default FOO
548	atf_check -o match:'FOO: tree' \
549	    "$SYSCONF" poudriere --ports default FOO
550	# Rewrite the overlay's existing var
551	atf_check -o match:'JOBS' \
552	    "$SYSCONF" poudriere --jail 131amd64 JOBS=8
553	atf_check -o match:'JOBS: 8' \
554	    "$SYSCONF" poudriere --jail 131amd64 JOBS
555
556	# Attached --jail=
557	atf_check -o match:'FOO: jail' \
558	    "$SYSCONF" poudriere --jail=131amd64 FOO
559
560	# `--' ends the nested keyword; colliding names are variables
561	printf 'src=from-conf\nm=short\n' >> "$ETC/poudriere.conf"
562	printf 'src=from-overlay\n' > "$ETC/poudriere.d/src.conf"
563	atf_check -o match:'src: from-conf' \
564	    "$SYSCONF" p -- src
565	atf_check -o match:'m: short' \
566	    "$SYSCONF" p -- m
567	atf_check -s not-exit:0 -e match:"unknown variable 'make'" \
568	    "$SYSCONF" p -- make
569	atf_check -o match:'src: from-overlay' \
570	    "$SYSCONF" p src src
571
572	# -f replaces discovery
573	printf 'BAR=only\n' > "$ETC/other.conf"
574	atf_check -o match:'BAR: only' \
575	    "$SYSCONF" poudriere -f "$ETC/other.conf" BAR
576
577	# Missing globals
578	unset POUDRIERE_ETC
579	export POUDRIERE_ETC="$( pwd )/missing-etc"
580	mkdir -p "$POUDRIERE_ETC"
581	atf_check -s not-exit:0 -e match:'poudriere.conf' \
582	    "$SYSCONF" p ZPOOL
583}
584poudriere_sysrc_cleanup()
585{
586	rm -rf "$( pwd )/petc" "$( pwd )/missing-etc"
587}
588
589atf_test_case poudriere_overlays cleanup
590poudriere_overlays_head()
591{
592	atf_set "descr" \
593		"poudriere make/src/src-env overlays with --jail/--tree/--set"
594}
595poudriere_overlays_body()
596{
597	find_sysconf
598	ETC="$( pwd )/petc"
599	D="$ETC/poudriere.d"
600	mkdir -p "$D"
601	export POUDRIERE_ETC="$ETC"
602
603	printf 'CFLAGS=global\n' > "$D/make.conf"
604	printf 'CFLAGS=jail\n' > "$D/131amd64-make.conf"
605	printf 'CFLAGS=tree\n' > "$D/default-make.conf"
606	printf 'CFLAGS=set\n' > "$D/dev-make.conf"
607	printf 'CFLAGS=combo\n' > "$D/131amd64-default-make.conf"
608
609	# Shorthand p m
610	atf_check -o inline:'CFLAGS: global\n' \
611	    "$SYSCONF" p m CFLAGS
612	atf_check -o inline:'CFLAGS: jail\n' \
613	    "$SYSCONF" poudriere make --jail 131amd64 CFLAGS
614	atf_check -o inline:'CFLAGS: tree\n' \
615	    "$SYSCONF" p m --tree default CFLAGS
616	atf_check -o inline:'CFLAGS: tree\n' \
617	    "$SYSCONF" poudriere make --ports default CFLAGS
618	atf_check -o inline:'CFLAGS: set\n' \
619	    "$SYSCONF" poudriere make --set dev CFLAGS
620	# jail-tree combo is last of those two
621	atf_check -o inline:'CFLAGS: combo\n' \
622	    "$SYSCONF" poudriere make --jail 131amd64 --tree default CFLAGS
623
624	# Rewrite overlay's existing name; new name goes to global
625	atf_check -o match:'CFLAGS' \
626	    "$SYSCONF" poudriere make --jail 131amd64 CFLAGS=-O2
627	atf_check -o match:'CFLAGS=-O2' cat "$D/131amd64-make.conf"
628	atf_check -o match:'CFLAGS=global' cat "$D/make.conf"
629	atf_check -o match:'CXXFLAGS' \
630	    "$SYSCONF" poudriere make --jail 131amd64 CXXFLAGS=-pipe
631	atf_check -o match:'CXXFLAGS=-pipe' cat "$D/make.conf"
632	atf_check -o not-match:'CXXFLAGS' cat "$D/131amd64-make.conf"
633
634	# Create missing global
635	rm -f "$D/make.conf"
636	atf_check -o match:'LDFLAGS' \
637	    "$SYSCONF" p m LDFLAGS=-L/usr/local/lib
638	atf_check -o match:'LDFLAGS=-L/usr/local/lib' cat "$D/make.conf"
639
640	# src vs src-env; --tree ignored (no tree-src.conf in poudriere(8))
641	printf 'WITHOUT_FOO=\n' > "$D/src.conf"
642	printf 'WITHOUT_TREE=\n' > "$D/default-src.conf"
643	printf 'SRC_ENV_VAR=1\n' > "$D/src-env.conf"
644	printf 'SRC_ENV_VAR=tree\n' > "$D/default-src-env.conf"
645	atf_check -o inline:'WITHOUT_FOO (present)\n' \
646	    "$SYSCONF" poudriere src WITHOUT_FOO
647	atf_check -s not-exit:0 -e match:'unknown directive' \
648	    "$SYSCONF" poudriere src --tree default WITHOUT_TREE
649	atf_check -o inline:'SRC_ENV_VAR: 1\n' \
650	    "$SYSCONF" poudriere src-env SRC_ENV_VAR
651	atf_check -o inline:'SRC_ENV_VAR: 1\n' \
652	    "$SYSCONF" poudriere src-env --tree default SRC_ENV_VAR
653	atf_check -o inline:'SRC_ENV_VAR: 1\n' \
654	    "$SYSCONF" p src-e SRC_ENV_VAR
655
656	# Ambiguous nested prefix
657	atf_check -s not-exit:0 -e match:'ambiguous' -e match:'src' \
658	    -e match:'src-env' \
659	    "$SYSCONF" p s FOO
660
661	# -l lists the collection
662	atf_check -o match:'make.conf' -o match:'131amd64-make.conf' \
663	    "$SYSCONF" poudriere make --jail 131amd64 -l
664
665	# -L lists every poudriere(8) stem, including files not on disk
666	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" \
667	    "$SYSCONF" p m --jail 160 --set abc --tree xyz -L
668	atf_check -o inline:"$D/make.conf\n$D/xyz-make.conf\n$D/160-make.conf\n$D/160-xyz-make.conf\n" \
669	    "$SYSCONF" p m --jail 160 --tree xyz -L
670	atf_check -o inline:"$D/make.conf\n" \
671	    "$SYSCONF" p m --jail 160 --set abc --tree xyz -l
672	atf_check -o inline:"$D/make.conf\n" \
673	    "$SYSCONF" p m --jail 160 --set abc --tree xyz -E -L
674	atf_check -o inline:"$D/src.conf\n$D/abc-src.conf\n$D/160-src.conf\n" \
675	    "$SYSCONF" p src --jail 160 --set abc --tree xyz -L
676	atf_check -o inline:"$D/src.conf\n$D/160-src.conf\n" \
677	    "$SYSCONF" p src --jail 160 --tree xyz -L
678	atf_check -o inline:"$D/src-env.conf\n$D/abc-src-env.conf\n$D/160-src-env.conf\n" \
679	    "$SYSCONF" p src-env --jail 160 --set abc --tree xyz -L
680	atf_check -o inline:"$D/src-env.conf\n" \
681	    "$SYSCONF" p src-env --jail 160 --set abc --tree xyz -E -L
682}
683poudriere_overlays_cleanup()
684{
685	rm -rf "$( pwd )/petc"
686}
687
688atf_init_test_cases()
689{
690	atf_add_test_case make_src_knobs
691	atf_add_test_case make_append_accumulate
692	atf_add_test_case make_strike_last_assign
693	atf_add_test_case src_triad_and_trail
694	atf_add_test_case src_env_rejected
695	atf_add_test_case env_overrides
696	atf_add_test_case attached_f_passthrough
697	atf_add_test_case verbatim_backslash
698	atf_add_test_case equal_value_nocheck_mtime
699	atf_add_test_case sysctl_oid_range
700	atf_add_test_case max_bytes_cap
701	atf_add_test_case target_prefix
702	atf_add_test_case poudriere_sysrc
703	atf_add_test_case poudriere_overlays
704}
705