sysrc.subr revision 240783
1238438Sdteskeif [ ! "$_SYSRC_SUBR" ]; then _SYSRC_SUBR=1
2238438Sdteske#
3238438Sdteske# Copyright (c) 2006-2012 Devin Teske
4238438Sdteske# All Rights Reserved.
5238438Sdteske#
6238438Sdteske# Redistribution and use in source and binary forms, with or without
7238438Sdteske# modification, are permitted provided that the following conditions
8238438Sdteske# are met:
9238438Sdteske# 1. Redistributions of source code must retain the above copyright
10238438Sdteske#    notice, this list of conditions and the following disclaimer.
11238438Sdteske# 2. Redistributions in binary form must reproduce the above copyright
12238438Sdteske#    notice, this list of conditions and the following disclaimer in the
13238438Sdteske#    documentation and/or other materials provided with the distribution.
14238438Sdteske#
15238438Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16238438Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
17238438Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18238438Sdteske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19238438Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20238438Sdteske# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21238438Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22238438Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23238438Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24238438Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25238438Sdteske# SUCH DAMAGE.
26238438Sdteske#
27238438Sdteske# $FreeBSD: head/usr.sbin/bsdconfig/share/sysrc.subr 240783 2012-09-21 19:03:25Z dteske $
28238438Sdteske#
29238438Sdteske############################################################ INCLUDES
30238438Sdteske
31240684SdteskeBSDCFG_SHARE="/usr/share/bsdconfig"
32240684Sdteske. $BSDCFG_SHARE/common.subr || exit 1
33240684Sdteske
34238438SdteskeBSDCFG_LIBE="/usr/libexec/bsdconfig"
35238438Sdteskef_include_lang $BSDCFG_LIBE/include/messages.subr
36238438Sdteske
37238438Sdteske############################################################ CONFIGURATION
38238438Sdteske
39238438Sdteske#
40238438Sdteske# Standard pathnames (inherit values from shell if available)
41238438Sdteske#
42238438Sdteske: ${RC_DEFAULTS:="/etc/defaults/rc.conf"}
43238438Sdteske
44238438Sdteske############################################################ GLOBALS
45238438Sdteske
46238438Sdteske#
47238438Sdteske# Global exit status variables
48238438Sdteske#
49238438SdteskeSUCCESS=0
50238438SdteskeFAILURE=1
51238438Sdteske
52238438Sdteske############################################################ FUNCTIONS
53238438Sdteske
54238438Sdteske# f_clean_env [ --except $varname ... ]
55238438Sdteske#
56238438Sdteske# Unset all environment variables in the current scope. An optional list of
57238438Sdteske# arguments can be passed, indicating which variables to avoid unsetting; the
58238438Sdteske# `--except' is required to enable the exclusion-list as the remainder of
59238438Sdteske# positional arguments.
60238438Sdteske#
61238438Sdteske# Be careful not to call this in a shell that you still expect to perform
62238438Sdteske# $PATH expansion in, because this will blow $PATH away. This is best used
63238438Sdteske# within a sub-shell block "(...)" or "$(...)" or "`...`".
64238438Sdteske#
65238438Sdteskef_clean_env()
66238438Sdteske{
67238438Sdteske	local var arg except=
68238438Sdteske
69238438Sdteske	#
70238438Sdteske	# Should we process an exclusion-list?
71238438Sdteske	#
72238438Sdteske	if [ "$1" = "--except" ]; then
73238438Sdteske		except=1
74238438Sdteske		shift 1
75238438Sdteske	fi
76238438Sdteske
77238438Sdteske	#
78238438Sdteske	# Loop over a list of variable names from set(1) built-in.
79238438Sdteske	#
80238438Sdteske	for var in $( set | awk -F= \
81238438Sdteske		'/^[[:alpha:]_][[:alnum:]_]*=/ {print $1}' \
82238438Sdteske		| grep -v '^except$'
83238438Sdteske	); do
84238438Sdteske		#
85238438Sdteske		# In POSIX bourne-shell, attempting to unset(1) OPTIND results
86238438Sdteske		# in "unset: Illegal number:" and causes abrupt termination.
87238438Sdteske		#
88238438Sdteske		[ "$var" = OPTIND ] && continue
89238438Sdteske
90238438Sdteske		#
91238438Sdteske		# Process the exclusion-list?
92238438Sdteske		#
93238438Sdteske		if [ "$except" ]; then
94238438Sdteske			for arg in "$@" ""; do
95238438Sdteske				[ "$var" = "$arg" ] && break
96238438Sdteske			done
97238438Sdteske			[ "$arg" ] && continue
98238438Sdteske		fi
99238438Sdteske
100238438Sdteske		unset "$var"
101238438Sdteske	done
102238438Sdteske}
103238438Sdteske
104238438Sdteske# f_sysrc_get $varname
105238438Sdteske#
106238438Sdteske# Get a system configuration setting from the collection of system-
107238438Sdteske# configuration files (in order: /etc/defaults/rc.conf /etc/rc.conf
108238438Sdteske# and /etc/rc.conf).
109238438Sdteske#
110238438Sdteske# NOTE: Additional shell parameter-expansion formats are supported. For
111238438Sdteske# example, passing an argument of "hostname%%.*" (properly quoted) will
112238438Sdteske# return the hostname up to (but not including) the first `.' (see sh(1),
113238438Sdteske# "Parameter Expansion" for more information on additional formats).
114238438Sdteske#
115238438Sdteskef_sysrc_get()
116238438Sdteske{
117238438Sdteske	# Sanity check
118238438Sdteske	[ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE
119238438Sdteske
120238438Sdteske	# Taint-check variable name
121238438Sdteske	case "$1" in
122238438Sdteske	[0-9]*)
123238438Sdteske		# Don't expand possible positional parameters
124238438Sdteske		return $FAILURE;;
125238438Sdteske	*)
126238438Sdteske		[ "$1" ] || return $FAILURE
127238438Sdteske	esac
128238438Sdteske
129238438Sdteske	( # Execute within sub-shell to protect parent environment
130238438Sdteske
131238438Sdteske		#
132238438Sdteske		# Clear the environment of all variables, preventing the
133238438Sdteske		# expansion of normals such as `PS1', `TERM', etc.
134238438Sdteske		#
135238438Sdteske		f_clean_env --except RC_CONFS RC_DEFAULTS SUCCESS
136238438Sdteske
137240783Sdteske		. "$RC_DEFAULTS" > /dev/null 2>&1
138238438Sdteske
139238438Sdteske		unset RC_DEFAULTS
140238438Sdteske			# no longer needed
141238438Sdteske
142238438Sdteske		#
143238438Sdteske		# If the query is for `rc_conf_files' then store the value that
144238438Sdteske		# we inherited from sourcing RC_DEFAULTS (above) so that we may
145238438Sdteske		# conditionally restore this value after source_rc_confs in the
146238438Sdteske		# event that RC_CONFS does not customize the value.
147238438Sdteske		#
148238438Sdteske		if [ "$1" = "rc_conf_files" ]; then
149238438Sdteske			_rc_conf_files="$rc_conf_files"
150238438Sdteske		fi
151238438Sdteske
152238438Sdteske		#
153238438Sdteske		# If RC_CONFS is defined, set $rc_conf_files to an explicit
154238438Sdteske		# value, modifying the default behavior of source_rc_confs().
155238438Sdteske		#
156240783Sdteske		( : ${RC_CONFS?} ) > /dev/null 2>&1
157238438Sdteske		if [ $? -eq ${SUCCESS:-0} ]; then
158238438Sdteske			rc_conf_files="$RC_CONFS"
159238438Sdteske			_rc_confs_set=1
160238438Sdteske		fi
161238438Sdteske
162238438Sdteske		unset SUCCESS
163238438Sdteske			# no longer needed
164238438Sdteske
165240783Sdteske		source_rc_confs > /dev/null 2>&1
166238438Sdteske
167238438Sdteske		#
168238438Sdteske		# If the query was for `rc_conf_files' AND after calling
169238438Sdteske		# source_rc_confs the vaue has not changed, then we should
170238438Sdteske		# restore the value to the one inherited from RC_DEFAULTS
171238438Sdteske		# before performing the final query (preventing us from
172238438Sdteske		# returning what was set via RC_CONFS when the intent was
173238438Sdteske		# instead to query the value from the file(s) specified).
174238438Sdteske		#
175238438Sdteske		if [ "$1" = "rc_conf_files" -a \
176238438Sdteske		     "$_rc_confs_set" -a \
177238438Sdteske		     "$rc_conf_files" = "$RC_CONFS" \
178238438Sdteske		]; then
179238438Sdteske			rc_conf_files="$_rc_conf_files"
180238438Sdteske			unset _rc_conf_files
181238438Sdteske			unset _rc_confs_set
182238438Sdteske		fi
183238438Sdteske
184238438Sdteske		unset RC_CONFS
185238438Sdteske			# no longer needed
186238438Sdteske
187238438Sdteske		#
188238438Sdteske		# This must be the last functional line for both the sub-shell
189238438Sdteske		# and the function to preserve the return status from formats
190238438Sdteske		# such as "${varname?}" and "${varname:?}" (see "Parameter
191238438Sdteske		# Expansion" in sh(1) for more information).
192238438Sdteske		#
193240783Sdteske		eval echo '"${'"$1"'}"' 2> /dev/null
194238438Sdteske	)
195238438Sdteske}
196238438Sdteske
197238438Sdteske# f_sysrc_get_default $varname
198238438Sdteske#
199238438Sdteske# Get a system configuration default setting from the default rc.conf(5) file
200238438Sdteske# (or whatever RC_DEFAULTS points at).
201238438Sdteske#
202238438Sdteskef_sysrc_get_default()
203238438Sdteske{
204238438Sdteske	# Sanity check
205238438Sdteske	[ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE
206238438Sdteske
207238438Sdteske	# Taint-check variable name
208238438Sdteske	case "$1" in
209238438Sdteske	[0-9]*)
210238438Sdteske		# Don't expand possible positional parameters
211238438Sdteske		return $FAILURE;;
212238438Sdteske	*)
213238438Sdteske		[ "$1" ] || return $FAILURE
214238438Sdteske	esac
215238438Sdteske
216238438Sdteske	( # Execute within sub-shell to protect parent environment
217238438Sdteske
218238438Sdteske		#
219238438Sdteske		# Clear the environment of all variables, preventing the
220238438Sdteske		# expansion of normals such as `PS1', `TERM', etc.
221238438Sdteske		#
222238438Sdteske		f_clean_env --except RC_DEFAULTS
223238438Sdteske
224240783Sdteske		. "$RC_DEFAULTS" > /dev/null 2>&1
225238438Sdteske
226238438Sdteske		unset RC_DEFAULTS
227238438Sdteske			# no longer needed
228238438Sdteske
229238438Sdteske		#
230238438Sdteske		# This must be the last functional line for both the sub-shell
231238438Sdteske		# and the function to preserve the return status from formats
232238438Sdteske		# such as "${varname?}" and "${varname:?}" (see "Parameter
233238438Sdteske		# Expansion" in sh(1) for more information).
234238438Sdteske		#
235240783Sdteske		eval echo '"${'"$1"'}"' 2> /dev/null
236238438Sdteske	)
237238438Sdteske}
238238438Sdteske
239238438Sdteske# f_sysrc_find $varname
240238438Sdteske#
241238438Sdteske# Find which file holds the effective last-assignment to a given variable
242238438Sdteske# within the rc.conf(5) file(s).
243238438Sdteske#
244238438Sdteske# If the variable is found in any of the rc.conf(5) files, the function prints
245238438Sdteske# the filename it was found in and then returns success. Otherwise output is
246238438Sdteske# NULL and the function returns with error status.
247238438Sdteske#
248238438Sdteskef_sysrc_find()
249238438Sdteske{
250238438Sdteske	local varname="$1"
251238438Sdteske	local regex="^[[:space:]]*$varname="
252238438Sdteske	local rc_conf_files="$( f_sysrc_get rc_conf_files )"
253238438Sdteske	local conf_files=
254238438Sdteske	local file
255238438Sdteske
256238438Sdteske	# Check parameters
257238438Sdteske	[ "$varname" ] || return $FAILURE
258238438Sdteske
259238438Sdteske	#
260238438Sdteske	# If RC_CONFS is defined, set $rc_conf_files to an explicit
261238438Sdteske	# value, modifying the default behavior of source_rc_confs().
262238438Sdteske	#
263238438Sdteske	[ "$RC_CONFS" ] && rc_conf_files="$RC_CONFS"
264238438Sdteske
265238438Sdteske	#
266238438Sdteske	# Reverse the order of files in rc_conf_files (the boot process sources
267238438Sdteske	# these in order, so we will search them in reverse-order to find the
268238438Sdteske	# last-assignment -- the one that ultimately effects the environment).
269238438Sdteske	#
270238438Sdteske	for file in $rc_conf_files; do
271238438Sdteske		conf_files="$file${conf_files:+ }$conf_files"
272238438Sdteske	done
273238438Sdteske
274238438Sdteske	#
275238438Sdteske	# Append the defaults file (since directives in the defaults file
276238438Sdteske	# indeed affect the boot process, we'll want to know when a directive
277238438Sdteske	# is found there).
278238438Sdteske	#
279238438Sdteske	conf_files="$conf_files${conf_files:+ }$RC_DEFAULTS"
280238438Sdteske
281238438Sdteske	#
282238438Sdteske	# Find which file matches assignment to the given variable name.
283238438Sdteske	#
284238438Sdteske	for file in $conf_files; do
285238438Sdteske		[ -f "$file" -a -r "$file" ] || continue
286238438Sdteske		if grep -Eq "$regex" $file; then
287238438Sdteske			echo $file
288238438Sdteske			return $SUCCESS
289238438Sdteske		fi
290238438Sdteske	done
291238438Sdteske
292238438Sdteske	return $FAILURE # Not found
293238438Sdteske}
294238438Sdteske
295238438Sdteske# f_sysrc_desc $varname
296238438Sdteske#
297238438Sdteske# Attempts to return the comments associated with varname from the rc.conf(5)
298238438Sdteske# defaults file `/etc/defaults/rc.conf' (or whatever RC_DEFAULTS points to).
299238438Sdteske#
300238438Sdteske# Multi-line comments are joined together. Results are NULL if no description
301238438Sdteske# could be found.
302238438Sdteske#
303238438Sdteske# This function is a two-parter. Below is the awk(1) portion of the function,
304238438Sdteske# afterward is the sh(1) function which utilizes the below awk script.
305238438Sdteske#
306238438Sdteskef_sysrc_desc_awk='
307238438Sdteske# Variables that should be defined on the invocation line:
308238438Sdteske# 	-v varname="varname"
309238438Sdteske#
310238438SdteskeBEGIN {
311238438Sdteske	regex = "^[[:space:]]*"varname"="
312238438Sdteske	found = 0
313238438Sdteske	buffer = ""
314238438Sdteske}
315238438Sdteske{
316238438Sdteske	if ( ! found )
317238438Sdteske	{
318238438Sdteske		if ( ! match($0, regex) ) next
319238438Sdteske
320238438Sdteske		found = 1
321238438Sdteske		sub(/^[^#]*(#[[:space:]]*)?/, "")
322238438Sdteske		buffer = $0
323238438Sdteske		next
324238438Sdteske	}
325238438Sdteske
326238438Sdteske	if ( !/^[[:space:]]*#/ ||
327238438Sdteske	      /^[[:space:]]*[[:alpha:]_][[:alnum:]_]*=/ ||
328238438Sdteske	      /^[[:space:]]*#[[:alpha:]_][[:alnum:]_]*=/ ||
329238438Sdteske	      /^[[:space:]]*$/ ) exit
330238438Sdteske
331238438Sdteske	sub(/(.*#)*[[:space:]]*/, "")
332238438Sdteske	buffer = buffer" "$0
333238438Sdteske}
334238438SdteskeEND {
335238438Sdteske	# Clean up the buffer
336238438Sdteske	sub(/^[[:space:]]*/, "", buffer)
337238438Sdteske	sub(/[[:space:]]*$/, "", buffer)
338238438Sdteske
339238438Sdteske	print buffer
340238438Sdteske	exit ! found
341238438Sdteske}
342238438Sdteske'
343238438Sdteskef_sysrc_desc()
344238438Sdteske{
345238438Sdteske	awk -v varname="$1" "$f_sysrc_desc_awk" < "$RC_DEFAULTS"
346238438Sdteske}
347238438Sdteske
348238438Sdteske# f_sysrc_set $varname $new_value
349238438Sdteske#
350238438Sdteske# Change a setting in the system configuration files (edits the files in-place
351238438Sdteske# to change the value in the last assignment to the variable). If the variable
352238438Sdteske# does not appear in the source file, it is appended to the end of the primary
353238438Sdteske# system configuration file `/etc/rc.conf'.
354238438Sdteske#
355238438Sdteske# This function is a two-parter. Below is the awk(1) portion of the function,
356238438Sdteske# afterward is the sh(1) function which utilizes the below awk script.
357238438Sdteske#
358238438Sdteskef_sysrc_set_awk='
359238438Sdteske# Variables that should be defined on the invocation line:
360238438Sdteske# 	-v varname="varname"
361238438Sdteske# 	-v new_value="new_value"
362238438Sdteske#
363238438SdteskeBEGIN {
364238438Sdteske	regex = "^[[:space:]]*"varname"="
365238438Sdteske	found = retval = 0
366238438Sdteske}
367238438Sdteske{
368238438Sdteske	# If already found... just spew
369238438Sdteske	if ( found ) { print; next }
370238438Sdteske
371238438Sdteske	# Does this line match an assignment to our variable?
372238438Sdteske	if ( ! match($0, regex) ) { print; next }
373238438Sdteske
374238438Sdteske	# Save important match information
375238438Sdteske	found = 1
376238438Sdteske	matchlen = RSTART + RLENGTH - 1
377238438Sdteske
378238438Sdteske	# Store the value text for later munging
379238438Sdteske	value = substr($0, matchlen + 1, length($0) - matchlen)
380238438Sdteske
381238438Sdteske	# Store the first character of the value
382238438Sdteske	t1 = t2 = substr(value, 0, 1)
383238438Sdteske
384238438Sdteske	# Assignment w/ back-ticks, expression, or misc.
385238438Sdteske	# We ignore these since we did not generate them
386238438Sdteske	#
387238438Sdteske	if ( t1 ~ /[`$\\]/ ) { retval = 1; print; next }
388238438Sdteske
389238438Sdteske	# Assignment w/ single-quoted value
390238438Sdteske	else if ( t1 == "'\''" ) {
391238438Sdteske		sub(/^'\''[^'\'']*/, "", value)
392238438Sdteske		if ( length(value) == 0 ) t2 = ""
393238438Sdteske		sub(/^'\''/, "", value)
394238438Sdteske	}
395238438Sdteske
396238438Sdteske	# Assignment w/ double-quoted value
397238438Sdteske	else if ( t1 == "\"" ) {
398238438Sdteske		sub(/^"(.*\\\\+")*[^"]*/, "", value)
399238438Sdteske		if ( length(value) == 0 ) t2 = ""
400238438Sdteske		sub(/^"/, "", value)
401238438Sdteske	}
402238438Sdteske
403238438Sdteske	# Assignment w/ non-quoted value
404238438Sdteske	else if ( t1 ~ /[^[:space:];]/ ) {
405238438Sdteske		t1 = t2 = "\""
406238438Sdteske		sub(/^[^[:space:]]*/, "", value)
407238438Sdteske	}
408238438Sdteske
409238438Sdteske	# Null-assignment
410238438Sdteske	else if ( t1 ~ /[[:space:];]/ ) { t1 = t2 = "\"" }
411238438Sdteske
412238438Sdteske	printf "%s%c%s%c%s\n", substr($0, 0, matchlen), \
413238438Sdteske		t1, new_value, t2, value
414238438Sdteske}
415238438SdteskeEND { exit retval }
416238438Sdteske'
417238438Sdteskef_sysrc_set()
418238438Sdteske{
419238438Sdteske	local varname="$1" new_value="$2"
420238438Sdteske
421238438Sdteske	# Check arguments
422238438Sdteske	[ "$varname" ] || return $FAILURE
423238438Sdteske
424238438Sdteske	#
425238438Sdteske	# Find which rc.conf(5) file contains the last-assignment
426238438Sdteske	#
427238438Sdteske	local not_found=
428238438Sdteske	local file="$( f_sysrc_find "$varname" )"
429238438Sdteske	if [ "$file" = "$RC_DEFAULTS" -o ! "$file" ]; then
430238438Sdteske		#
431238438Sdteske		# We either got a null response (not found) or the variable
432238438Sdteske		# was only found in the rc.conf(5) defaults. In either case,
433238438Sdteske		# let's instead modify the first file from $rc_conf_files.
434238438Sdteske		#
435238438Sdteske
436238438Sdteske		not_found=1
437238438Sdteske
438238438Sdteske		#
439238438Sdteske		# If RC_CONFS is defined, use $RC_CONFS
440238438Sdteske		# rather than $rc_conf_files.
441238438Sdteske		#
442238438Sdteske		if [ "$RC_CONFS" ]; then
443238438Sdteske			file="${RC_CONFS%%[$IFS]*}"
444238438Sdteske		else
445238438Sdteske			file=$( f_sysrc_get rc_conf_files )
446238438Sdteske			file="${file%%[$IFS]*}"
447238438Sdteske		fi
448238438Sdteske	fi
449238438Sdteske
450238438Sdteske	#
451238438Sdteske	# If not found, append new value to last file and return.
452238438Sdteske	#
453238438Sdteske	if [ "$not_found" ]; then
454238438Sdteske		echo "$varname=\"$new_value\"" >> "$file"
455238438Sdteske		return $?
456238438Sdteske	fi
457238438Sdteske
458238438Sdteske	#
459238438Sdteske	# Perform sanity checks.
460238438Sdteske	#
461238438Sdteske	if [ ! -w "$file" ]; then
462238438Sdteske		f_err "$msg_cannot_create_permission_denied\n" \
463238438Sdteske		      "$pgm" "$file"
464238438Sdteske		return $FAILURE
465238438Sdteske	fi
466238438Sdteske
467238438Sdteske	#
468238438Sdteske	# Create a new temporary file to write to.
469238438Sdteske	#
470238438Sdteske	local tmpfile="$( mktemp -t "$pgm" )"
471238438Sdteske	[ "$tmpfile" ] || return $FAILURE
472238438Sdteske
473238438Sdteske	#
474238438Sdteske	# Fixup permissions (else we're in for a surprise, as mktemp(1) creates
475238438Sdteske	# the temporary file with 0600 permissions, and if we simply mv(1) the
476238438Sdteske	# temporary file over the destination, the destination will inherit the
477238438Sdteske	# permissions from the temporary file).
478238438Sdteske	#
479238438Sdteske	local mode
480240783Sdteske	mode=$( stat -f '%#Lp' "$file" 2> /dev/null )
481238438Sdteske	f_quietly chmod "${mode:-0644}" "$tmpfile"
482238438Sdteske
483238438Sdteske	#
484238438Sdteske	# Fixup ownership. The destination file _is_ writable (we tested
485238438Sdteske	# earlier above). However, this will fail if we don't have sufficient
486238438Sdteske	# permissions (so we throw stderr into the bit-bucket).
487238438Sdteske	#
488238438Sdteske	local owner
489240783Sdteske	owner=$( stat -f '%u:%g' "$file" 2> /dev/null )
490238438Sdteske	f_quietly chown "${owner:-root:wheel}" "$tmpfile"
491238438Sdteske
492238438Sdteske	#
493238438Sdteske	# Operate on the matching file, replacing only the last occurrence.
494238438Sdteske	#
495238438Sdteske	local new_contents retval
496240783Sdteske	new_contents=$( tail -r $file 2> /dev/null )
497238438Sdteske	new_contents=$( echo "$new_contents" | awk -v varname="$varname" \
498238438Sdteske		-v new_value="$new_value" "$f_sysrc_set_awk" )
499238438Sdteske	retval=$?
500238438Sdteske
501238438Sdteske	#
502238438Sdteske	# Write the temporary file contents.
503238438Sdteske	#
504238438Sdteske	echo "$new_contents" | tail -r > "$tmpfile" || return $FAILURE
505238438Sdteske	if [ $retval -ne $SUCCESS ]; then
506238438Sdteske		echo "$varname=\"$new_value\"" >> "$tmpfile"
507238438Sdteske	fi
508238438Sdteske
509238438Sdteske	#
510238438Sdteske	# Taint-check our results.
511238438Sdteske	#
512238438Sdteske	if ! /bin/sh -n "$tmpfile"; then
513238438Sdteske		f_err "$msg_previous_syntax_errors\n" "$pgm" "$file"
514238438Sdteske		rm -f "$tmpfile"
515238438Sdteske		return $FAILURE
516238438Sdteske	fi
517238438Sdteske
518238438Sdteske	#
519238438Sdteske	# Finally, move the temporary file into place.
520238438Sdteske	#
521238438Sdteske	mv "$tmpfile" "$file"
522238438Sdteske}
523238438Sdteske
524238438Sdteske# f_sysrc_delete $varname
525238438Sdteske#
526238438Sdteske# Remove a setting from the system configuration files (edits files in-place).
527238438Sdteske# Deletes all assignments to the given variable in all config files. If the
528238438Sdteske# `-f file' option is passed, the removal is restricted to only those files
529238438Sdteske# specified, otherwise the system collection of rc_conf_files is used.
530238438Sdteske#
531238438Sdteske# This function is a two-parter. Below is the awk(1) portion of the function,
532238438Sdteske# afterward is the sh(1) function which utilizes the below awk script.
533238438Sdteske#
534238438Sdteskef_sysrc_delete_awk='
535238438Sdteske# Variables that should be defined on the invocation line:
536238438Sdteske# 	-v varname="varname"
537238438Sdteske#
538238438SdteskeBEGIN {
539238438Sdteske	regex = "^[[:space:]]*"varname"="
540238438Sdteske	found = 0
541238438Sdteske}
542238438Sdteske{
543238438Sdteske	if ( $0 ~ regex )
544238438Sdteske		found = 1
545238438Sdteske	else
546238438Sdteske		print
547238438Sdteske}
548238438SdteskeEND { exit ! found }
549238438Sdteske'
550238438Sdteskef_sysrc_delete()
551238438Sdteske{
552238438Sdteske	local varname="$1"
553238438Sdteske	local file
554238438Sdteske
555238438Sdteske	# Check arguments
556238438Sdteske	[ "$varname" ] || return $FAILURE
557238438Sdteske
558238438Sdteske	#
559238438Sdteske	# Operate on each of the specified files
560238438Sdteske	#
561238438Sdteske	for file in ${RC_CONFS:-$( f_sysrc_get rc_conf_files )}; do
562238438Sdteske		[ -e "$file" ] || continue
563238438Sdteske
564238438Sdteske		#
565238438Sdteske		# Create a new temporary file to write to.
566238438Sdteske		#
567238438Sdteske		local tmpfile="$( mktemp -t "$pgm" )"
568238438Sdteske		[ "$tmpfile" ] || return $FAILURE
569238438Sdteske
570238438Sdteske		#
571238438Sdteske		# Fixup permissions and ownership (mktemp(1) defaults to 0600
572238438Sdteske		# permissions) to instead match the destination file.
573238438Sdteske		#
574238438Sdteske		local mode owner
575240783Sdteske		mode=$( stat -f '%#Lp' "$file" 2> /dev/null )
576240783Sdteske		owner=$( stat -f '%u:%g' "$file" 2> /dev/null )
577238438Sdteske		f_quietly chmod "${mode:-0644}" "$tmpfile"
578238438Sdteske		f_quietly chown "${owner:-root:wheel}" "$tmpfile"
579238438Sdteske
580238438Sdteske		#
581238438Sdteske		# Operate on the file, removing all occurrences, saving the
582238438Sdteske		# output in our temporary file.
583238438Sdteske		#
584238438Sdteske		awk -v varname="$varname" "$f_sysrc_delete_awk" "$file" \
585238438Sdteske			> "$tmpfile"
586238438Sdteske		if [ $? -ne $SUCCESS ]; then
587238438Sdteske			# The file didn't contain any assignments
588238438Sdteske			rm -f "$tmpfile"
589238438Sdteske			continue
590238438Sdteske		fi
591238438Sdteske
592238438Sdteske		#
593238438Sdteske		# Taint-check our results.
594238438Sdteske		#
595238438Sdteske		if ! /bin/sh -n "$tmpfile"; then
596238438Sdteske			f_err "$msg_previous_syntax_errors\n" \
597238438Sdteske			      "$pgm" "$file"
598238438Sdteske			rm -f "$tmpfile"
599238438Sdteske			return $FAILURE
600238438Sdteske		fi
601238438Sdteske
602238438Sdteske		#
603238438Sdteske		# Perform sanity checks
604238438Sdteske		#
605238438Sdteske		if [ ! -w "$file" ]; then
606238438Sdteske			f_err "$msg_permission_denied\n" "$pgm" "$file"
607238438Sdteske			rm -f "$tmpfile"
608238438Sdteske			return $FAILURE
609238438Sdteske		fi
610238438Sdteske
611238438Sdteske		#
612238438Sdteske		# Finally, move the temporary file into place.
613238438Sdteske		#
614238438Sdteske		mv "$tmpfile" "$file"
615238438Sdteske	done
616238438Sdteske}
617238438Sdteske
618238438Sdteskefi # ! $_SYSRC_SUBR
619