rcvar.subr revision 238438
1if [ ! "$_STARTUP_RCVAR_SUBR" ]; then _STARTUP_RCVAR_SUBR=1
2#
3# Copyright (c) 2006-2012 Devin Teske
4# All Rights Reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27# $FreeBSD: head/usr.sbin/bsdconfig/startup/include/rcvar.subr 238438 2012-07-14 03:16:57Z dteske $
28#
29############################################################ INCLUDES
30
31BSDCFG_LIBE="/usr/libexec/bsdconfig"
32. $BSDCFG_LIBE/include/common.subr || exit 1
33f_include $BSDCFG_LIBE/include/sysrc.subr
34
35############################################################ CONFIGURATION
36
37#
38# Default path to the `/etc/rc.d' directory where service(8) scripts are stored
39#
40: ${ETC_RC_D:=/etc/rc.d}
41
42#
43# Default path to `/etc/rc.subr' (for find_local_scripts_new())
44#
45: ${ETC_RC_SUBR:=/etc/rc.subr}
46
47############################################################ GLOBALS
48
49#
50# Initialize in-memory cache variables
51#
52STARTUP_RCVAR_MAP=
53_STARTUP_RCVAR_MAP=
54
55#
56# Define what an rcvar looks like
57#
58STARTUP_RCVAR_REGEX='[[:alpha:]_][[:alnum:]_]*="([Yy][Ee][Ss]|[Nn][Oo])"'
59
60#
61# Default path to on-disk cache file(s)
62#
63STARTUP_RCVAR_MAP_CACHEFILE="/var/run/bsdconfig/startup_rcvar_map.cache"
64
65############################################################ FUNCTIONS
66
67# f_startup_rcvar_map
68#
69# Produce a map (beit from in-memory cache or on-disk cache) of rc.d scripts
70# and their associated rcvar's. The map returned has the following format:
71#
72# 	rcvar default script description
73#
74# With each as follows:
75#
76# 	rcvar         the variable used to enable this rc.d script
77# 	default       default value for this variable
78# 	script        the rc.d script in-question
79# 	description   description of the variable from rc.conf(5) defaults
80#
81f_startup_rcvar_map()
82{
83	# If the in-memory cached value is available, return it immediately
84	if [ "$_STARTUP_RCVAR_MAP" ]; then
85		echo "$STARTUP_RCVAR_MAP"
86		return $SUCCESS
87	fi
88
89	#
90	# create the in-memory cache (potentially from validated on-disk cache)
91	#
92
93	# Get a list of /etc/rc.d scripts ...
94	local file rc_script_list=
95	for file in "$ETC_RC_D"/*; do
96		[ -f "$file" ] || continue
97		[ -x "$file" ] || continue
98		rc_script_list="$rc_script_list${rc_script_list:+ }$file"
99	done
100	# ... and /usr/local/etc/rc.d scripts
101	rc_script_list="$rc_script_list${rc_script_list:+ }$(
102		local_startup=$( f_sysrc_get local_startup )
103		f_include "$ETC_RC_SUBR"
104		find_local_scripts_new
105		echo $local_rc
106	)"
107
108	#
109	# Calculate a digest given the checksums of all dependencies (scripts and
110	# the defaults file). This digest will be used to determine if an on-disk
111	# global persistant cache file (containg this digest on the first line)
112	# is valid and can be used to quickly populate the cache value for
113	# immediate return.
114	#
115	local rc_script_list_digest
116	rc_script_list_digest=$( cd "$ETC_RC_D" &&
117		cksum "$RC_DEFAULTS" $rc_script_list | md5 )
118
119	#
120	# Check to see if the global persistant cache file exists
121	#
122	if [ -f "$STARTUP_RCVAR_MAP_CACHEFILE" ]; then
123		#
124		# Attempt to populate the in-memory cache with the (soon to be)
125		# be validated on-disk cache. If validation fails, fall-back to
126		# the current value and provide error exit status.
127		#
128		STARTUP_RCVAR_MAP=$(
129			(	# Get digest as the first word on the first line
130				read digest rest_ignored
131
132				#
133				# If the stored digest matches the calculated-one
134				# populate the in-memory cache from the on-disk
135				# cache and provide success exit status.
136				#
137				if [ "$digest" = "$rc_script_list_digest" ]; then
138					cat
139					exit $SUCCESS
140				else
141					# Otherwise, return the current value
142					echo "$STARTUP_RCVAR_MAP"
143					exit $FAILURE
144				fi
145			) < "$STARTUP_RCVAR_MAP_CACHEFILE"
146		)
147		export STARTUP_RCVAR_MAP
148		if [ $? -eq $SUCCESS ]; then
149			export _STARTUP_RCVAR_MAP=1
150			echo "$STARTUP_RCVAR_MAP"
151			return $SUCCESS
152		fi
153		# Otherwise, fall-through to create in-memory cache from scratch
154	fi
155
156	#
157	# If we reach this point, we need to generate the data from scratch
158	# (and after we do, we'll attempt to create the global persistant
159	# cache file to speed up future executions).
160	#
161
162	STARTUP_RCVAR_MAP=$(
163		for script in $rc_script_list; do
164			rcvar_list=$( $script rcvar | awk -F= \
165				-v script="$script" '
166		              	/^'"$STARTUP_RCVAR_REGEX"'/ {
167		              		if ( $2 ~ /^"[Yy][Ee][Ss]"$/ )
168		              			print $1 ",YES"
169		              		else
170		              			print $1 ",NO"
171		              	}' )
172			for entry in $rcvar_list; do
173				rcvar="${entry%%,*}"
174				rcvar_default=$( f_sysrc_get_default "$rcvar" )
175				[ "$rcvar_default" ] ||
176					rcvar_default="${entry#*,}"
177				rcvar_desc=$( f_sysrc_desc "$rcvar" )
178				echo $rcvar ${rcvar_default:-NO} \
179				     $script "$rcvar_desc"
180			done
181		done | sort -u
182	)
183	export STARTUP_RCVAR_MAP
184	export _STARTUP_RCVAR_MAP=1
185	echo "$STARTUP_RCVAR_MAP"
186
187	#
188	# Attempt to create the persistant global cache
189	#
190
191	# Create a new temporary file to write to
192	local tmpfile="$( mktemp -t "$pgm" )"
193	[ "$tmpfile" ] || return $FAILURE
194
195	# Write the temporary file contents
196	echo "$rc_script_list_digest" > "$tmpfile"
197	echo "$STARTUP_RCVAR_MAP" >> "$tmpfile"
198
199	# Finally, move the temporary file into place
200	case "$STARTUP_RCVAR_MAP_CACHEFILE" in
201	*/*) f_quietly mkdir -p "${STARTUP_RCVAR_MAP_CACHEFILE%/*}"
202	esac
203	mv "$tmpfile" "$STARTUP_RCVAR_MAP_CACHEFILE"
204}
205
206fi # ! $_STARTUP_RCVAR_SUBR
207