xref: /freebsd/usr.sbin/bsdconfig/share/sysrc.subr (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1if [ ! "$_SYSRC_SUBR" ]; then _SYSRC_SUBR=1
2#
3# Copyright (c) 2006-2015 Devin Teske
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27#
28############################################################ INCLUDES
29
30BSDCFG_SHARE="/usr/share/bsdconfig"
31[ "$_COMMON_SUBR" ] || . $BSDCFG_SHARE/common.subr || exit 1
32
33BSDCFG_LIBE="/usr/libexec/bsdconfig"
34if [ ! "$_SYSRC_JAILED" ]; then
35	f_dprintf "%s: loading includes..." sysrc.subr
36	f_include_lang $BSDCFG_LIBE/include/messages.subr
37fi
38
39############################################################ CONFIGURATION
40
41#
42# Standard pathnames (inherit values from shell if available)
43#
44: ${RC_DEFAULTS:="/etc/defaults/rc.conf"}
45
46############################################################ GLOBALS
47
48#
49# Global exit status variables
50#
51SUCCESS=0
52FAILURE=1
53
54#
55# Valid characters that can appear in an sh(1) variable name
56#
57# Please note that the character ranges A-Z and a-z should be avoided because
58# these can include accent characters (which are not valid in a variable name).
59# For example, A-Z matches any character that sorts after A but before Z,
60# including A and Z. Although ASCII order would make more sense, that is not
61# how it works.
62#
63VALID_VARNAME_CHARS="0-9ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"
64
65############################################################ FUNCTIONS
66
67# f_clean_env [ --except $varname ... ]
68#
69# Unset all environment variables in the current scope. An optional list of
70# arguments can be passed, indicating which variables to avoid unsetting; the
71# `--except' is required to enable the exclusion-list as the remainder of
72# positional arguments.
73#
74# Be careful not to call this in a shell that you still expect to perform
75# $PATH expansion in, because this will blow $PATH away. This is best used
76# within a sub-shell block "(...)" or "$(...)" or "`...`".
77#
78f_clean_env()
79{
80	local var arg except=
81
82	#
83	# Should we process an exclusion-list?
84	#
85	if [ "$1" = "--except" ]; then
86		except=1
87		shift 1
88	fi
89
90	#
91	# Loop over a list of variable names from set(1) built-in.
92	#
93	for var in $( set | awk -F= \
94		'/^[[:alpha:]_][[:alnum:]_]*=/ {print $1}' \
95		| grep -v '^except$'
96	); do
97		#
98		# In POSIX bourne-shell, attempting to unset(1) OPTIND results
99		# in "unset: Illegal number:" and causes abrupt termination.
100		#
101		[ "$var" = OPTIND ] && continue
102
103		#
104		# Process the exclusion-list?
105		#
106		if [ "$except" ]; then
107			for arg in "$@" ""; do
108				[ "$var" = "$arg" ] && break
109			done
110			[ "$arg" ] && continue
111		fi
112
113		unset "$var"
114	done
115}
116
117# f_sysrc_get $varname
118#
119# Get a system configuration setting from the collection of system-
120# configuration files (in order: /etc/defaults/rc.conf /etc/rc.conf and
121# /etc/rc.conf.local)
122#
123# NOTE: Additional shell parameter-expansion formats are supported. For
124# example, passing an argument of "hostname%%.*" (properly quoted) will
125# return the hostname up to (but not including) the first `.' (see sh(1),
126# "Parameter Expansion" for more information on additional formats).
127#
128f_sysrc_get()
129{
130	# Sanity check
131	[ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE
132
133	# Taint-check variable name
134	case "$1" in
135	[0-9]*)
136		# Don't expand possible positional parameters
137		return $FAILURE ;;
138	*)
139		[ "$1" ] || return $FAILURE
140	esac
141
142	( # Execute within sub-shell to protect parent environment
143
144		#
145		# Clear the environment of all variables, preventing the
146		# expansion of normals such as `PS1', `TERM', etc.
147		#
148		f_clean_env --except IFS RC_CONFS RC_DEFAULTS
149
150		. "$RC_DEFAULTS" > /dev/null 2>&1
151
152		unset RC_DEFAULTS
153			# no longer needed
154
155		#
156		# If the query is for `rc_conf_files' then store the value that
157		# we inherited from sourcing RC_DEFAULTS (above) so that we may
158		# conditionally restore this value after source_rc_confs in the
159		# event that RC_CONFS does not customize the value.
160		#
161		if [ "$1" = "rc_conf_files" ]; then
162			_rc_conf_files="$rc_conf_files"
163		fi
164
165		#
166		# If RC_CONFS is defined, set $rc_conf_files to an explicit
167		# value, modifying the default behavior of source_rc_confs().
168		#
169		if [ "${RC_CONFS+set}" ]; then
170			rc_conf_files="$RC_CONFS"
171			_rc_confs_set=1
172		fi
173
174		source_rc_confs > /dev/null 2>&1
175
176		#
177		# If the query was for `rc_conf_files' AND after calling
178		# source_rc_confs the value has not changed, then we should
179		# restore the value to the one inherited from RC_DEFAULTS
180		# before performing the final query (preventing us from
181		# returning what was set via RC_CONFS when the intent was
182		# instead to query the value from the file(s) specified).
183		#
184		if [ "$1" = "rc_conf_files" -a \
185		     "$_rc_confs_set" -a \
186		     "$rc_conf_files" = "$RC_CONFS" \
187		]; then
188			rc_conf_files="$_rc_conf_files"
189			unset _rc_conf_files
190			unset _rc_confs_set
191		fi
192
193		unset RC_CONFS
194			# no longer needed
195
196		#
197		# This must be the last functional line for both the sub-shell
198		# and the function to preserve the return status from formats
199		# such as "${varname?}" and "${varname:?}" (see "Parameter
200		# Expansion" in sh(1) for more information).
201		#
202		eval printf "'%s\\n'" '"${'"$1"'}"' 2> /dev/null
203	)
204}
205
206# f_sysrc_service_configs [-a|-p] $name [$var_to_set]
207#
208# Get a list of optional `rc.conf.d' entries sourced by system `rc.d' script
209# $name (see rc.subr(8) for additional information on `rc.conf.d'). If $name
210# exists in `/etc/rc.d' or $local_startup directories and is an rc(8) script
211# the result is a space separated list of `rc.conf.d' entries sourced by the
212# $name `rc.d' script. Otherwise, if $name exists as a binary `rc.d' script,
213# the result is ``/etc/rc.conf.d/$name /usr/local/etc/rc.conf.d/$name''. The
214# result is NULL if $name does not exist.
215#
216# If $var_to_set is missing or NULL, output is to standard out. Returns success
217# if $name was found, failure otherwise.
218#
219# If `-a' flag is given and $var_to_set is non-NULL, append result to value of
220# $var_to_set rather than overwriting current contents.
221#
222# If `-p' flag is given and $var_to_set is non-NULL, prepend result to value of
223# $var_to_set rather than overwriting current contents.
224#
225# NB: The `-a' and `-p' option flags are mutually exclusive.
226#
227f_sysrc_service_configs()
228{
229	local OPTIND=1 OPTARG __flag __append= __prepend=
230	local __local_startup __dir __spath __stype __names=
231
232	while getopts ap __flag; do
233		case "$__flag" in
234		a) __append=1 __prepend= ;;
235		p) __prepend=1 __append= ;;
236		esac
237	done
238	shift $(( $OPTIND - 1 ))
239
240	[ $# -gt 0 ] || return $FAILURE
241	local __sname="$1" __var_to_set="$2"
242
243	__local_startup=$( f_sysrc_get local_startup )
244	for __dir in /etc/rc.d $__local_startup; do
245		__spath="$__dir/$__sname"
246		[ -f "$__spath" -a -x "$__spath" ] || __spath= continue
247		break
248	done
249	[ "$__spath" ] || return $FAILURE
250
251	__stype=$( file -b "$__spath" 2> /dev/null )
252	case "$__stype" in
253	*"shell script"*)
254		__names=$( exec 9<&1 1>&- 2>&-
255			last_name=
256			print_name() {
257				local name="$1"
258				case "$name" in
259				""|.|..|*/*|"$last_name") return ;;
260				esac
261				echo "$name" >&9
262				last_name="$name"
263			}
264			eval "$( awk '{
265				gsub(/load_rc_config /, "print_name ")
266				gsub(/run_rc_command /, ": ")
267				print
268			}' "$__spath" )"
269		) ;;
270	*)
271		__names="$__sname"
272	esac
273
274	local __name __test_path __configs=
275	for __name in $__names; do
276		for __dir in /etc/rc.d $__local_startup; do
277			__test_path="${__dir%/rc.d}/rc.conf.d/$__name"
278			[ -d "$__test_path" ] ||
279				__configs="$__configs $__test_path" continue
280			for __test_path in "$__test_path"/*; do
281				[ -f "$__test_path" ] || continue
282				__configs="$__configs $__test_path"
283			done
284		done
285	done
286	__configs="${__configs# }"
287
288	if [ "$__var_to_set" ]; then
289		local __cur=
290		[ "$__append" -o "$__prepend" ] &&
291			f_getvar "$__var_to_set" __cur
292		[ "$__append"  ] && __configs="$__cur{$__cur:+ }$__configs"
293		[ "$__prepend" ] && __configs="$__configs${__cur:+ }$__cur"
294		setvar "$__var_to_set" "$__configs"
295	else
296		echo "$__configs"
297	fi
298
299	return $SUCCESS
300}
301
302# f_sysrc_get_default $varname
303#
304# Get a system configuration default setting from the default rc.conf(5) file
305# (or whatever RC_DEFAULTS points at).
306#
307f_sysrc_get_default()
308{
309	# Sanity check
310	[ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE
311
312	# Taint-check variable name
313	case "$1" in
314	[0-9]*)
315		# Don't expand possible positional parameters
316		return $FAILURE ;;
317	*)
318		[ "$1" ] || return $FAILURE
319	esac
320
321	( # Execute within sub-shell to protect parent environment
322
323		#
324		# Clear the environment of all variables, preventing the
325		# expansion of normals such as `PS1', `TERM', etc.
326		#
327		f_clean_env --except RC_DEFAULTS
328
329		. "$RC_DEFAULTS" > /dev/null 2>&1
330
331		unset RC_DEFAULTS
332			# no longer needed
333
334		#
335		# This must be the last functional line for both the sub-shell
336		# and the function to preserve the return status from formats
337		# such as "${varname?}" and "${varname:?}" (see "Parameter
338		# Expansion" in sh(1) for more information).
339		#
340		eval printf "'%s\\n'" '"${'"$1"'}"' 2> /dev/null
341	)
342}
343
344# f_sysrc_find $varname
345#
346# Find which file holds the effective last-assignment to a given variable
347# within the rc.conf(5) file(s).
348#
349# If the variable is found in any of the rc.conf(5) files, the function prints
350# the filename it was found in and then returns success. Otherwise output is
351# NULL and the function returns with error status.
352#
353f_sysrc_find()
354{
355	local varname="${1%%[!$VALID_VARNAME_CHARS]*}"
356	local regex="^[[:space:]]*$varname="
357	local rc_conf_files="$( f_sysrc_get rc_conf_files )"
358	local conf_files=
359	local file
360
361	# Check parameters
362	case "$varname" in
363	""|[0-9]*) return $FAILURE
364	esac
365
366	#
367	# If RC_CONFS is defined, set $rc_conf_files to an explicit
368	# value, modifying the default behavior of source_rc_confs().
369	#
370	[ "${RC_CONFS+set}" ] && rc_conf_files="$RC_CONFS"
371
372	#
373	# Reverse the order of files in rc_conf_files (the boot process sources
374	# these in order, so we will search them in reverse-order to find the
375	# last-assignment -- the one that ultimately effects the environment).
376	#
377	for file in $rc_conf_files; do
378		conf_files="$file${conf_files:+ }$conf_files"
379	done
380
381	#
382	# Append the defaults file (since directives in the defaults file
383	# indeed affect the boot process, we'll want to know when a directive
384	# is found there).
385	#
386	conf_files="$conf_files${conf_files:+ }$RC_DEFAULTS"
387
388	#
389	# Find which file matches assignment to the given variable name.
390	#
391	for file in $conf_files; do
392		[ -f "$file" -a -r "$file" ] || continue
393		if grep -Eq "$regex" $file; then
394			echo $file
395			return $SUCCESS
396		fi
397	done
398
399	return $FAILURE # Not found
400}
401
402# f_sysrc_desc $varname
403#
404# Attempts to return the comments associated with varname from the rc.conf(5)
405# defaults file `/etc/defaults/rc.conf' (or whatever RC_DEFAULTS points to).
406#
407# Multi-line comments are joined together. Results are NULL if no description
408# could be found.
409#
410# This function is a two-parter. Below is the awk(1) portion of the function,
411# afterward is the sh(1) function which utilizes the below awk script.
412#
413f_sysrc_desc_awk='
414# Variables that should be defined on the invocation line:
415# 	-v varname="varname"
416#
417BEGIN {
418	regex = "^[[:space:]]*"varname"="
419	found = 0
420	buffer = ""
421}
422{
423	if ( ! found )
424	{
425		if ( ! match($0, regex) ) next
426
427		found = 1
428		sub(/^[^#]*(#[[:space:]]*)?/, "")
429		buffer = $0
430		next
431	}
432
433	if ( !/^[[:space:]]*#/ ||
434	      /^[[:space:]]*[[:alpha:]_][[:alnum:]_]*=/ ||
435	      /^[[:space:]]*#[[:alpha:]_][[:alnum:]_]*=/ ||
436	      /^[[:space:]]*$/ ) exit
437
438	sub(/(.*#)*[[:space:]]*/, "")
439	buffer = buffer" "$0
440}
441END {
442	# Clean up the buffer
443	sub(/^[[:space:]]*/, "", buffer)
444	sub(/[[:space:]]*$/, "", buffer)
445
446	print buffer
447	exit ! found
448}
449'
450f_sysrc_desc()
451{
452	awk -v varname="$1" "$f_sysrc_desc_awk" < "$RC_DEFAULTS"
453}
454
455# f_sysrc_set $varname $new_value
456#
457# Change a setting in the system configuration files (edits the files in-place
458# to change the value in the last assignment to the variable). If the variable
459# does not appear in the source file, it is appended to the end of the primary
460# system configuration file `/etc/rc.conf'.
461#
462# This function is a two-parter. Below is the awk(1) portion of the function,
463# afterward is the sh(1) function which utilizes the below awk script.
464#
465f_sysrc_set_awk='
466# Variables that should be defined on the invocation line:
467# 	-v varname="varname"
468# 	-v new_value="new_value"
469#
470BEGIN {
471	regex = "^[[:space:]]*"varname"="
472	found = retval = 0
473}
474{
475	# If already found... just spew
476	if ( found ) { print; next }
477
478	# Does this line match an assignment to our variable?
479	if ( ! match($0, regex) ) { print; next }
480
481	# Save important match information
482	found = 1
483	matchlen = RSTART + RLENGTH - 1
484
485	# Store the value text for later munging
486	value = substr($0, matchlen + 1, length($0) - matchlen)
487
488	# Store the first character of the value
489	t1 = t2 = substr(value, 0, 1)
490
491	# Assignment w/ back-ticks, expression, or misc.
492	# We ignore these since we did not generate them
493	#
494	if ( t1 ~ /[`$\\]/ ) { retval = 1; print; next }
495
496	# Assignment w/ single-quoted value
497	else if ( t1 == "'\''" ) {
498		sub(/^'\''[^'\'']*/, "", value)
499		if ( length(value) == 0 ) t2 = ""
500		sub(/^'\''/, "", value)
501	}
502
503	# Assignment w/ double-quoted value
504	else if ( t1 == "\"" ) {
505		sub(/^"(.*\\\\+")*[^"]*/, "", value)
506		if ( length(value) == 0 ) t2 = ""
507		sub(/^"/, "", value)
508	}
509
510	# Assignment w/ non-quoted value
511	else if ( t1 ~ /[^[:space:];]/ ) {
512		t1 = t2 = "\""
513		sub(/^[^[:space:]]*/, "", value)
514	}
515
516	# Null-assignment
517	else if ( t1 ~ /[[:space:];]/ ) { t1 = t2 = "\"" }
518
519	printf "%s%c%s%c%s\n", substr($0, 0, matchlen), \
520		t1, new_value, t2, value
521}
522END { exit retval }
523'
524f_sysrc_set()
525{
526	local funcname=f_sysrc_set
527	local varname="$1" new_value="$2"
528
529	# Check arguments
530	[ "$varname" ] || return $FAILURE
531
532	#
533	# Find which rc.conf(5) file contains the last-assignment
534	#
535	local not_found=
536	local file="$( f_sysrc_find "$varname" )"
537	if [ "$file" = "$RC_DEFAULTS" -o ! "$file" ]; then
538		#
539		# We either got a null response (not found) or the variable
540		# was only found in the rc.conf(5) defaults. In either case,
541		# let's instead modify the first file from $rc_conf_files.
542		#
543
544		not_found=1
545
546		#
547		# If RC_CONFS is defined, use $RC_CONFS
548		# rather than $rc_conf_files.
549		#
550		if [ "${RC_CONFS+set}" ]; then
551			file="${RC_CONFS%%[$IFS]*}"
552		else
553			file=$( f_sysrc_get 'rc_conf_files%%[$IFS]*' )
554		fi
555	fi
556
557	#
558	# If not found, append new value to first file and return.
559	#
560	if [ "$not_found" ]; then
561		# Add a newline if missing before appending to the file
562		[ ! -e "$file" ] || awk 'BEGIN { wc = 0 } NR == 1 {
563			(cmd = "wc -l " FILENAME) | getline
564			close(cmd)
565			wc = $1
566		} END { exit wc != NR }' "$file" ||
567			echo >> "$file" || return $?
568		echo "$varname=\"$new_value\"" >> "$file"
569		return $?
570	fi
571
572	#
573	# Perform sanity checks.
574	#
575	if [ ! -w "$file" ]; then
576		f_err "$msg_cannot_create_permission_denied\n" \
577		      "$pgm" "$file"
578		return $FAILURE
579	fi
580
581	#
582	# Create a new temporary file to write to.
583	#
584	local tmpfile
585	if ! f_eval_catch -dk tmpfile $funcname mktemp 'mktemp -t "%s"' "$pgm"
586	then
587		echo "$tmpfile" >&2
588		return $FAILURE
589	fi
590
591	#
592	# Fixup permissions (else we're in for a surprise, as mktemp(1) creates
593	# the temporary file with 0600 permissions, and if we simply mv(1) the
594	# temporary file over the destination, the destination will inherit the
595	# permissions from the temporary file).
596	#
597	local mode
598	f_eval_catch -dk mode $funcname stat 'stat -f "%%#Lp" "%s"' "$file" ||
599		mode=0644
600	f_eval_catch -d $funcname chmod 'chmod "%s" "%s"' "$mode" "$tmpfile"
601
602	#
603	# Fixup ownership. The destination file _is_ writable (we tested
604	# earlier above). However, this will fail if we don't have sufficient
605	# permissions (so we throw stderr into the bit-bucket).
606	#
607	local owner
608	f_eval_catch -dk owner $funcname stat \
609		'stat -f "%%u:%%g" "%s"' "$file" || owner="root:wheel"
610	f_eval_catch -d $funcname chown 'chown "%s" "%s"' "$owner" "$tmpfile"
611
612	#
613	# Operate on the matching file, replacing only the last occurrence.
614	#
615	# Use awk to ensure LF at end of each line, else files without ending
616	# LF will trigger a bug in `tail -r' where last two lines are joined.
617	#
618	local new_contents retval
619	new_contents=$( awk 1 "$file" 2> /dev/null | tail -r )
620	new_contents=$( echo "$new_contents" | awk -v varname="$varname" \
621		-v new_value="$new_value" "$f_sysrc_set_awk" )
622	retval=$?
623
624	#
625	# Write the temporary file contents.
626	#
627	echo "$new_contents" | tail -r > "$tmpfile" || return $FAILURE
628	if [ $retval -ne $SUCCESS ]; then
629		echo "$varname=\"$new_value\"" >> "$tmpfile"
630	fi
631
632	#
633	# Taint-check our results.
634	#
635	if ! f_eval_catch -d $funcname sh '/bin/sh -n "%s"' "$tmpfile"; then
636		f_err "$msg_previous_syntax_errors\n" "$pgm" "$file"
637		rm -f "$tmpfile"
638		return $FAILURE
639	fi
640
641	#
642	# Finally, move the temporary file into place.
643	#
644	f_eval_catch -de $funcname mv 'mv "%s" "%s"' "$tmpfile" "$file"
645}
646
647# f_sysrc_delete $varname
648#
649# Remove a setting from the system configuration files (edits files in-place).
650# Deletes all assignments to the given variable in all config files. If the
651# `-f file' option is passed, the removal is restricted to only those files
652# specified, otherwise the system collection of rc_conf_files is used.
653#
654# This function is a two-parter. Below is the awk(1) portion of the function,
655# afterward is the sh(1) function which utilizes the below awk script.
656#
657f_sysrc_delete_awk='
658# Variables that should be defined on the invocation line:
659# 	-v varname="varname"
660#
661BEGIN {
662	regex = "^[[:space:]]*"varname"="
663	found = 0
664}
665{
666	if ( $0 ~ regex )
667		found = 1
668	else
669		print
670}
671END { exit ! found }
672'
673f_sysrc_delete()
674{
675	local funcname=f_sysrc_delete
676	local varname="$1"
677	local file
678
679	# Check arguments
680	[ "$varname" ] || return $FAILURE
681
682	#
683	# Operate on each of the specified files
684	#
685	local tmpfile
686	for file in ${RC_CONFS-$( f_sysrc_get rc_conf_files )}; do
687		[ -e "$file" ] || continue
688
689		#
690		# Create a new temporary file to write to.
691		#
692		if ! f_eval_catch -dk tmpfile $funcname mktemp \
693			'mktemp -t "%s"' "$pgm"
694		then
695			echo "$tmpfile" >&2
696			return $FAILURE
697		fi
698
699		#
700		# Fixup permissions and ownership (mktemp(1) defaults to 0600
701		# permissions) to instead match the destination file.
702		#
703		local mode owner
704		f_eval_catch -dk mode $funcname stat \
705			'stat -f "%%#Lp" "%s"' "$file" || mode=0644
706		f_eval_catch -dk owner $funcname stat \
707			'stat -f "%%u:%%g" "%s"' "$file" || owner="root:wheel"
708		f_eval_catch -d $funcname chmod \
709			'chmod "%s" "%s"' "$mode" "$tmpfile"
710		f_eval_catch -d $funcname chown \
711			'chown "%s" "%s"' "$owner" "$tmpfile"
712
713		#
714		# Operate on the file, removing all occurrences, saving the
715		# output in our temporary file.
716		#
717		awk -v varname="$varname" "$f_sysrc_delete_awk" "$file" \
718			> "$tmpfile"
719		if [ $? -ne $SUCCESS ]; then
720			# The file didn't contain any assignments
721			rm -f "$tmpfile"
722			continue
723		fi
724
725		#
726		# Taint-check our results.
727		#
728		if ! f_eval_catch -d $funcname sh '/bin/sh -n "%s"' "$tmpfile"
729		then
730			f_err "$msg_previous_syntax_errors\n" \
731			      "$pgm" "$file"
732			rm -f "$tmpfile"
733			return $FAILURE
734		fi
735
736		#
737		# Perform sanity checks
738		#
739		if [ ! -w "$file" ]; then
740			f_err "$msg_permission_denied\n" "$pgm" "$file"
741			rm -f "$tmpfile"
742			return $FAILURE
743		fi
744
745		#
746		# Finally, move the temporary file into place.
747		#
748		f_eval_catch -de $funcname mv \
749			'mv "%s" "%s"' "$tmpfile" "$file" || return $FAILURE
750	done
751}
752
753############################################################ MAIN
754
755f_dprintf "%s: Successfully loaded." sysrc.subr
756
757fi # ! $_SYSRC_SUBR
758