1ab2043b8SDevin Teskeif [ ! "$_STARTUP_RCVAR_SUBR" ]; then _STARTUP_RCVAR_SUBR=1
2ab2043b8SDevin Teske#
3d3a0f918SDevin Teske# Copyright (c) 2006-2013 Devin Teske
4f8ea072aSDevin 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
208e37a7c8SDevin 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"
31ab2043b8SDevin Teske. $BSDCFG_SHARE/common.subr || exit 1
3256961fd7SDevin Teskef_dprintf "%s: loading includes..." startup/rcvar.subr
33ab2043b8SDevin Teskef_include $BSDCFG_SHARE/sysrc.subr
34ab2043b8SDevin Teske
35ab2043b8SDevin Teske############################################################ CONFIGURATION
36ab2043b8SDevin Teske
37ab2043b8SDevin Teske#
38ab2043b8SDevin Teske# Default path to the `/etc/rc.d' directory where service(8) scripts are stored
39ab2043b8SDevin Teske#
40ab2043b8SDevin Teske: ${ETC_RC_D:=/etc/rc.d}
41ab2043b8SDevin Teske
42ab2043b8SDevin Teske#
43ab2043b8SDevin Teske# Default path to `/etc/rc.subr' (for find_local_scripts_new())
44ab2043b8SDevin Teske#
45ab2043b8SDevin Teske: ${ETC_RC_SUBR:=/etc/rc.subr}
46ab2043b8SDevin Teske
47ab2043b8SDevin Teske############################################################ GLOBALS
48ab2043b8SDevin Teske
49ab2043b8SDevin Teske#
50ab2043b8SDevin Teske# Initialize in-memory cache variables
51ab2043b8SDevin Teske#
52ab2043b8SDevin TeskeSTARTUP_RCVAR_MAP=
53ab2043b8SDevin Teske_STARTUP_RCVAR_MAP=
54ab2043b8SDevin Teske
55ab2043b8SDevin Teske#
56ab2043b8SDevin Teske# Define what an rcvar looks like
57ab2043b8SDevin Teske#
58ab2043b8SDevin TeskeSTARTUP_RCVAR_REGEX='[[:alpha:]_][[:alnum:]_]*="([Yy][Ee][Ss]|[Nn][Oo])"'
59ab2043b8SDevin Teske
60ab2043b8SDevin Teske#
61ab2043b8SDevin Teske# Default path to on-disk cache file(s)
62ab2043b8SDevin Teske#
63ab2043b8SDevin TeskeSTARTUP_RCVAR_MAP_CACHEFILE="/var/run/bsdconfig/startup_rcvar_map.cache"
64ab2043b8SDevin Teske
65ab2043b8SDevin Teske############################################################ FUNCTIONS
66ab2043b8SDevin Teske
67d3a0f918SDevin Teske# f_startup_rcvar_map [$var_to_set]
68ab2043b8SDevin Teske#
69ab2043b8SDevin Teske# Produce a map (beit from in-memory cache or on-disk cache) of rc.d scripts
70ab2043b8SDevin Teske# and their associated rcvar's. The map returned has the following format:
71ab2043b8SDevin Teske#
72ab2043b8SDevin Teske# 	rcvar default script description
73ab2043b8SDevin Teske#
74ab2043b8SDevin Teske# With each as follows:
75ab2043b8SDevin Teske#
76ab2043b8SDevin Teske# 	rcvar         the variable used to enable this rc.d script
77ab2043b8SDevin Teske# 	default       default value for this variable
78ab2043b8SDevin Teske# 	script        the rc.d script in-question
79ab2043b8SDevin Teske# 	description   description of the variable from rc.conf(5) defaults
80ab2043b8SDevin Teske#
81d3a0f918SDevin Teske# If $var_to_set is missing or NULL, the map is printed to standard output for
82d3a0f918SDevin Teske# capturing in a sub-shell (which is less-recommended because of performance
83d3a0f918SDevin Teske# degredation; for example, when called in a loop).
84d3a0f918SDevin Teske#
85ab2043b8SDevin Teskef_startup_rcvar_map()
86ab2043b8SDevin Teske{
87d4ae33f0SDevin Teske	local __funcname=f_startup_rcvar_map
88d3a0f918SDevin Teske	local __var_to_set="$1"
89d3a0f918SDevin Teske
90ab2043b8SDevin Teske	# If the in-memory cached value is available, return it immediately
91ab2043b8SDevin Teske	if [ "$_STARTUP_RCVAR_MAP" ]; then
92d3a0f918SDevin Teske		if [ "$__var_to_set" ]; then
93d3a0f918SDevin Teske			setvar "$__var_to_set" "$STARTUP_RCVAR_MAP"
94d3a0f918SDevin Teske		else
95ab2043b8SDevin Teske			echo "$STARTUP_RCVAR_MAP"
96d3a0f918SDevin Teske		fi
97ab2043b8SDevin Teske		return $SUCCESS
98ab2043b8SDevin Teske	fi
99ab2043b8SDevin Teske
100ab2043b8SDevin Teske	#
101ab2043b8SDevin Teske	# create the in-memory cache (potentially from validated on-disk cache)
102ab2043b8SDevin Teske	#
103ab2043b8SDevin Teske
104ab2043b8SDevin Teske	# Get a list of /etc/rc.d scripts ...
105d3a0f918SDevin Teske	local __file __rc_script_list=
106d3a0f918SDevin Teske	for __file in "$ETC_RC_D"/*; do
107d3a0f918SDevin Teske		[ -f "$__file" ] || continue
108d3a0f918SDevin Teske		[ -x "$__file" ] || continue
109d3a0f918SDevin Teske		__rc_script_list="$__rc_script_list $__file"
110ab2043b8SDevin Teske	done
111ab2043b8SDevin Teske	# ... and /usr/local/etc/rc.d scripts
112d3a0f918SDevin Teske	__rc_script_list="$__rc_script_list $(
113ab2043b8SDevin Teske		local_startup=$( f_sysrc_get local_startup )
114ab2043b8SDevin Teske		f_include "$ETC_RC_SUBR"
115ab2043b8SDevin Teske		find_local_scripts_new
116ab2043b8SDevin Teske		echo $local_rc
117ab2043b8SDevin Teske	)"
118d3a0f918SDevin Teske	__rc_script_list="${__rc_script_list# }" # Trim leading space
119ab2043b8SDevin Teske
120ab2043b8SDevin Teske	#
121d1bb7ccaSDevin Teske	# Calculate a digest given the checksums of all dependencies (scripts
122d1bb7ccaSDevin Teske	# and the defaults file). This digest will be used to determine if an
123ec65e4f8SPedro F. Giffuni	# on-disk global persistent cache file (containg this digest on the
124d1bb7ccaSDevin Teske	# first line) is valid and can be used to quickly populate the cache
125d1bb7ccaSDevin Teske	# value for immediate return.
126ab2043b8SDevin Teske	#
127d3a0f918SDevin Teske	local __rc_script_list_digest
128d4ae33f0SDevin Teske	__rc_script_list_digest=$( cd "$ETC_RC_D" 2> /dev/null &&
129d4ae33f0SDevin Teske		cksum "$RC_DEFAULTS" $__rc_script_list 2> /dev/null | md5 )
130ab2043b8SDevin Teske
131ab2043b8SDevin Teske	#
132ec65e4f8SPedro F. Giffuni	# Check to see if the global persistent cache file exists
133ab2043b8SDevin Teske	#
134ab2043b8SDevin Teske	if [ -f "$STARTUP_RCVAR_MAP_CACHEFILE" ]; then
135ab2043b8SDevin Teske		#
136ab2043b8SDevin Teske		# Attempt to populate the in-memory cache with the (soon to be)
137d3a0f918SDevin Teske		# validated on-disk cache. If validation fails, fall-back to
138d3a0f918SDevin Teske		# the current value and return error.
139ab2043b8SDevin Teske		#
140ab2043b8SDevin Teske		STARTUP_RCVAR_MAP=$(
141d3a0f918SDevin Teske			(	# Get digest as first word on first line
142ab2043b8SDevin Teske				read digest rest_ignored
143ab2043b8SDevin Teske
144ab2043b8SDevin Teske				#
145d1bb7ccaSDevin Teske				# If the stored digest matches the calculated-
146d1bb7ccaSDevin Teske				# one populate the in-memory cache from the on-
147d3a0f918SDevin Teske				# disk cache and return success.
148ab2043b8SDevin Teske				#
149d3a0f918SDevin Teske				if [ "$digest" = "$__rc_script_list_digest" ]
150d1bb7ccaSDevin Teske				then
151ab2043b8SDevin Teske					cat
152ab2043b8SDevin Teske					exit $SUCCESS
153ab2043b8SDevin Teske				else
154ab2043b8SDevin Teske					# Otherwise, return the current value
155ab2043b8SDevin Teske					echo "$STARTUP_RCVAR_MAP"
156ab2043b8SDevin Teske					exit $FAILURE
157ab2043b8SDevin Teske				fi
158ab2043b8SDevin Teske			) < "$STARTUP_RCVAR_MAP_CACHEFILE"
159ab2043b8SDevin Teske		)
160d3a0f918SDevin Teske		local __retval=$?
161d3a0f918SDevin Teske		export STARTUP_RCVAR_MAP # Make children faster (export cache)
162d3a0f918SDevin Teske		if [ $__retval -eq $SUCCESS ]; then
163ab2043b8SDevin Teske			export _STARTUP_RCVAR_MAP=1
164d3a0f918SDevin Teske			if [ "$__var_to_set" ]; then
165d3a0f918SDevin Teske				setvar "$__var_to_set" "$STARTUP_RCVAR_MAP"
166d3a0f918SDevin Teske			else
167ab2043b8SDevin Teske				echo "$STARTUP_RCVAR_MAP"
168d3a0f918SDevin Teske			fi
169ab2043b8SDevin Teske			return $SUCCESS
170ab2043b8SDevin Teske		fi
171d1bb7ccaSDevin Teske		# Otherwise, fall-thru to create in-memory cache from scratch
172ab2043b8SDevin Teske	fi
173ab2043b8SDevin Teske
174ab2043b8SDevin Teske	#
175ab2043b8SDevin Teske	# If we reach this point, we need to generate the data from scratch
176ec65e4f8SPedro F. Giffuni	# (and after we do, we'll attempt to create the global persistent
177ab2043b8SDevin Teske	# cache file to speed up future executions).
178ab2043b8SDevin Teske	#
179ab2043b8SDevin Teske
180ab2043b8SDevin Teske	STARTUP_RCVAR_MAP=$(
181d3a0f918SDevin Teske		for script in $__rc_script_list; do
182d4ae33f0SDevin Teske			rcvar_list=$( $script rcvar 2> /dev/null | awk -F= \
183ab2043b8SDevin Teske				-v script="$script" '
184ab2043b8SDevin Teske		              	/^'"$STARTUP_RCVAR_REGEX"'/ {
185ab2043b8SDevin Teske		              		if ( $2 ~ /^"[Yy][Ee][Ss]"$/ )
186ab2043b8SDevin Teske		              			print $1 ",YES"
187ab2043b8SDevin Teske		              		else
188ab2043b8SDevin Teske		              			print $1 ",NO"
189ab2043b8SDevin Teske		              	}' )
190ab2043b8SDevin Teske			for entry in $rcvar_list; do
191ab2043b8SDevin Teske				rcvar="${entry%%,*}"
192ab2043b8SDevin Teske				rcvar_default=$( f_sysrc_get_default "$rcvar" )
193ab2043b8SDevin Teske				[ "$rcvar_default" ] ||
194ab2043b8SDevin Teske					rcvar_default="${entry#*,}"
195ab2043b8SDevin Teske				rcvar_desc=$( f_sysrc_desc "$rcvar" )
196ab2043b8SDevin Teske				echo $rcvar ${rcvar_default:-NO} \
197ab2043b8SDevin Teske				     $script "$rcvar_desc"
198ab2043b8SDevin Teske			done
199ab2043b8SDevin Teske		done | sort -u
200ab2043b8SDevin Teske	)
201ab2043b8SDevin Teske	export STARTUP_RCVAR_MAP
202ab2043b8SDevin Teske	export _STARTUP_RCVAR_MAP=1
203d3a0f918SDevin Teske	if [ "$__var_to_set" ]; then
204d3a0f918SDevin Teske		setvar "$__var_to_set" "$STARTUP_RCVAR_MAP"
205d3a0f918SDevin Teske	else
206ab2043b8SDevin Teske		echo "$STARTUP_RCVAR_MAP"
207d3a0f918SDevin Teske	fi
208ab2043b8SDevin Teske
209ab2043b8SDevin Teske	#
210ec65e4f8SPedro F. Giffuni	# Attempt to create/update the persistent global cache
211ab2043b8SDevin Teske	#
212ab2043b8SDevin Teske
213ab2043b8SDevin Teske	# Create a new temporary file to write to
214d4ae33f0SDevin Teske	local __tmpfile
215d4ae33f0SDevin Teske	f_eval_catch -dk __tmpfile $__funcname mktemp \
216d4ae33f0SDevin Teske		'mktemp -t "%s"' "$__tmpfile" || return $FAILURE
217ab2043b8SDevin Teske
218ab2043b8SDevin Teske	# Write the temporary file contents
219d3a0f918SDevin Teske	echo "$__rc_script_list_digest" > "$__tmpfile"
220d3a0f918SDevin Teske	echo "$STARTUP_RCVAR_MAP" >> "$__tmpfile"
221ab2043b8SDevin Teske
222ab2043b8SDevin Teske	# Finally, move the temporary file into place
223ab2043b8SDevin Teske	case "$STARTUP_RCVAR_MAP_CACHEFILE" in
224d4ae33f0SDevin Teske	*/*) f_eval_catch -d $__funcname mkdir \
225d4ae33f0SDevin Teske		'mkdir -p "%s"' "${STARTUP_RCVAR_MAP_CACHEFILE%/*}"
226ab2043b8SDevin Teske	esac
227d4ae33f0SDevin Teske	f_eval_catch -d $__funcname mv \
228d4ae33f0SDevin Teske		'mv "%s" "%s"' "$__tmpfile" "$STARTUP_RCVAR_MAP_CACHEFILE"
229ab2043b8SDevin Teske}
230ab2043b8SDevin Teske
23156961fd7SDevin Teske############################################################ MAIN
23256961fd7SDevin Teske
23356961fd7SDevin Teskef_dprintf "%s: Successfully loaded." startup/rcvar.subr
23456961fd7SDevin Teske
235ab2043b8SDevin Teskefi # ! $_STARTUP_RCVAR_SUBR
236