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