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