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