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