sysrc.subr revision 240798
1214501Srpauloif [ ! "$_SYSRC_SUBR" ]; then _SYSRC_SUBR=1 2214501Srpaulo# 3214501Srpaulo# Copyright (c) 2006-2012 Devin Teske 4214501Srpaulo# All Rights Reserved. 5252726Srpaulo# 6252726Srpaulo# Redistribution and use in source and binary forms, with or without 7214501Srpaulo# modification, are permitted provided that the following conditions 8214501Srpaulo# are met: 9214501Srpaulo# 1. Redistributions of source code must retain the above copyright 10214501Srpaulo# notice, this list of conditions and the following disclaimer. 11214501Srpaulo# 2. Redistributions in binary form must reproduce the above copyright 12214501Srpaulo# notice, this list of conditions and the following disclaimer in the 13214501Srpaulo# documentation and/or other materials provided with the distribution. 14214501Srpaulo# 15214501Srpaulo# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16214501Srpaulo# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE 17214501Srpaulo# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18214501Srpaulo# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19214501Srpaulo# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20214501Srpaulo# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21214501Srpaulo# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22252726Srpaulo# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23252726Srpaulo# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24252726Srpaulo# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25252726Srpaulo# SUCH DAMAGE. 26252726Srpaulo# 27214501Srpaulo# $FreeBSD: head/usr.sbin/bsdconfig/share/sysrc.subr 240798 2012-09-22 04:04:02Z dteske $ 28214501Srpaulo# 29214501Srpaulo############################################################ INCLUDES 30214501Srpaulo 31214501SrpauloBSDCFG_SHARE="/usr/share/bsdconfig" 32252726Srpaulo. $BSDCFG_SHARE/common.subr || exit 1 33214501Srpaulo 34214501SrpauloBSDCFG_LIBE="/usr/libexec/bsdconfig" 35214501Srpaulof_include_lang $BSDCFG_LIBE/include/messages.subr 36214501Srpaulo 37214501Srpaulo############################################################ CONFIGURATION 38214501Srpaulo 39214501Srpaulo# 40252726Srpaulo# Standard pathnames (inherit values from shell if available) 41252726Srpaulo# 42214501Srpaulo: ${RC_DEFAULTS:="/etc/defaults/rc.conf"} 43214501Srpaulo 44214501Srpaulo############################################################ GLOBALS 45214501Srpaulo 46252726Srpaulo# 47214501Srpaulo# Global exit status variables 48214501Srpaulo# 49214501SrpauloSUCCESS=0 50214501SrpauloFAILURE=1 51214501Srpaulo 52252726Srpaulo############################################################ FUNCTIONS 53214501Srpaulo 54214501Srpaulo# f_clean_env [ --except $varname ... ] 55214501Srpaulo# 56214501Srpaulo# Unset all environment variables in the current scope. An optional list of 57214501Srpaulo# arguments can be passed, indicating which variables to avoid unsetting; the 58252726Srpaulo# `--except' is required to enable the exclusion-list as the remainder of 59214501Srpaulo# positional arguments. 60214501Srpaulo# 61214501Srpaulo# Be careful not to call this in a shell that you still expect to perform 62214501Srpaulo# $PATH expansion in, because this will blow $PATH away. This is best used 63214501Srpaulo# within a sub-shell block "(...)" or "$(...)" or "`...`". 64214501Srpaulo# 65214501Srpaulof_clean_env() 66214501Srpaulo{ 67214501Srpaulo local var arg except= 68214501Srpaulo 69214501Srpaulo # 70214501Srpaulo # Should we process an exclusion-list? 71214501Srpaulo # 72214501Srpaulo if [ "$1" = "--except" ]; then 73214501Srpaulo except=1 74214501Srpaulo shift 1 75214501Srpaulo fi 76214501Srpaulo 77214501Srpaulo # 78214501Srpaulo # Loop over a list of variable names from set(1) built-in. 79214501Srpaulo # 80214501Srpaulo for var in $( set | awk -F= \ 81214501Srpaulo '/^[[:alpha:]_][[:alnum:]_]*=/ {print $1}' \ 82214501Srpaulo | grep -v '^except$' 83214501Srpaulo ); do 84214501Srpaulo # 85214501Srpaulo # In POSIX bourne-shell, attempting to unset(1) OPTIND results 86214501Srpaulo # in "unset: Illegal number:" and causes abrupt termination. 87214501Srpaulo # 88214501Srpaulo [ "$var" = OPTIND ] && continue 89214501Srpaulo 90214501Srpaulo # 91214501Srpaulo # Process the exclusion-list? 92214501Srpaulo # 93214501Srpaulo if [ "$except" ]; then 94214501Srpaulo for arg in "$@" ""; do 95252726Srpaulo [ "$var" = "$arg" ] && break 96214501Srpaulo done 97214501Srpaulo [ "$arg" ] && continue 98252726Srpaulo fi 99214501Srpaulo 100214501Srpaulo unset "$var" 101214501Srpaulo done 102214501Srpaulo} 103214501Srpaulo 104214501Srpaulo# f_sysrc_get $varname 105252726Srpaulo# 106252726Srpaulo# Get a system configuration setting from the collection of system- 107214501Srpaulo# configuration files (in order: /etc/defaults/rc.conf /etc/rc.conf 108214501Srpaulo# and /etc/rc.conf). 109214501Srpaulo# 110214501Srpaulo# NOTE: Additional shell parameter-expansion formats are supported. For 111252726Srpaulo# example, passing an argument of "hostname%%.*" (properly quoted) will 112214501Srpaulo# return the hostname up to (but not including) the first `.' (see sh(1), 113214501Srpaulo# "Parameter Expansion" for more information on additional formats). 114214501Srpaulo# 115214501Srpaulof_sysrc_get() 116214501Srpaulo{ 117214501Srpaulo # Sanity check 118252726Srpaulo [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE 119252726Srpaulo 120252726Srpaulo # Taint-check variable name 121214501Srpaulo case "$1" in 122214501Srpaulo [0-9]*) 123214501Srpaulo # Don't expand possible positional parameters 124252726Srpaulo return $FAILURE;; 125252726Srpaulo *) 126252726Srpaulo [ "$1" ] || return $FAILURE 127252726Srpaulo esac 128252726Srpaulo 129252726Srpaulo ( # Execute within sub-shell to protect parent environment 130252726Srpaulo 131252726Srpaulo # 132252726Srpaulo # Clear the environment of all variables, preventing the 133214501Srpaulo # expansion of normals such as `PS1', `TERM', etc. 134214501Srpaulo # 135214501Srpaulo f_clean_env --except RC_CONFS RC_DEFAULTS 136252726Srpaulo 137214501Srpaulo . "$RC_DEFAULTS" > /dev/null 2>&1 138214501Srpaulo 139214501Srpaulo unset RC_DEFAULTS 140214501Srpaulo # no longer needed 141214501Srpaulo 142214501Srpaulo # 143214501Srpaulo # If the query is for `rc_conf_files' then store the value that 144214501Srpaulo # we inherited from sourcing RC_DEFAULTS (above) so that we may 145214501Srpaulo # conditionally restore this value after source_rc_confs in the 146214501Srpaulo # event that RC_CONFS does not customize the value. 147214501Srpaulo # 148214501Srpaulo if [ "$1" = "rc_conf_files" ]; then 149252726Srpaulo _rc_conf_files="$rc_conf_files" 150252726Srpaulo fi 151252726Srpaulo 152252726Srpaulo # 153252726Srpaulo # If RC_CONFS is defined, set $rc_conf_files to an explicit 154252726Srpaulo # value, modifying the default behavior of source_rc_confs(). 155252726Srpaulo # 156252726Srpaulo if [ "${RC_CONFS+set}" ]; then 157214501Srpaulo rc_conf_files="$RC_CONFS" 158214501Srpaulo _rc_confs_set=1 159214501Srpaulo fi 160214501Srpaulo 161214501Srpaulo source_rc_confs > /dev/null 2>&1 162214501Srpaulo 163214501Srpaulo # 164214501Srpaulo # If the query was for `rc_conf_files' AND after calling 165214501Srpaulo # source_rc_confs the value has not changed, then we should 166214501Srpaulo # restore the value to the one inherited from RC_DEFAULTS 167214501Srpaulo # before performing the final query (preventing us from 168214501Srpaulo # returning what was set via RC_CONFS when the intent was 169214501Srpaulo # instead to query the value from the file(s) specified). 170214501Srpaulo # 171214501Srpaulo if [ "$1" = "rc_conf_files" -a \ 172214501Srpaulo "$_rc_confs_set" -a \ 173214501Srpaulo "$rc_conf_files" = "$RC_CONFS" \ 174214501Srpaulo ]; then 175214501Srpaulo rc_conf_files="$_rc_conf_files" 176214501Srpaulo unset _rc_conf_files 177214501Srpaulo unset _rc_confs_set 178214501Srpaulo fi 179214501Srpaulo 180214501Srpaulo unset RC_CONFS 181214501Srpaulo # no longer needed 182214501Srpaulo 183214501Srpaulo # 184214501Srpaulo # This must be the last functional line for both the sub-shell 185214501Srpaulo # and the function to preserve the return status from formats 186214501Srpaulo # such as "${varname?}" and "${varname:?}" (see "Parameter 187214501Srpaulo # Expansion" in sh(1) for more information). 188214501Srpaulo # 189214501Srpaulo eval echo '"${'"$1"'}"' 2> /dev/null 190214501Srpaulo ) 191252726Srpaulo} 192252726Srpaulo 193252726Srpaulo# f_sysrc_get_default $varname 194252726Srpaulo# 195252726Srpaulo# Get a system configuration default setting from the default rc.conf(5) file 196252726Srpaulo# (or whatever RC_DEFAULTS points at). 197252726Srpaulo# 198252726Srpaulof_sysrc_get_default() 199252726Srpaulo{ 200252726Srpaulo # Sanity check 201252726Srpaulo [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE 202252726Srpaulo 203214501Srpaulo # Taint-check variable name 204252726Srpaulo case "$1" in 205252726Srpaulo [0-9]*) 206252726Srpaulo # Don't expand possible positional parameters 207252726Srpaulo return $FAILURE;; 208252726Srpaulo *) 209252726Srpaulo [ "$1" ] || return $FAILURE 210252726Srpaulo esac 211252726Srpaulo 212214501Srpaulo ( # Execute within sub-shell to protect parent environment 213214501Srpaulo 214214501Srpaulo # 215214501Srpaulo # Clear the environment of all variables, preventing the 216214501Srpaulo # expansion of normals such as `PS1', `TERM', etc. 217214501Srpaulo # 218214501Srpaulo f_clean_env --except RC_DEFAULTS 219214501Srpaulo 220214501Srpaulo . "$RC_DEFAULTS" > /dev/null 2>&1 221214501Srpaulo 222214501Srpaulo unset RC_DEFAULTS 223214501Srpaulo # no longer needed 224214501Srpaulo 225214501Srpaulo # 226214501Srpaulo # This must be the last functional line for both the sub-shell 227214501Srpaulo # and the function to preserve the return status from formats 228214501Srpaulo # such as "${varname?}" and "${varname:?}" (see "Parameter 229214501Srpaulo # Expansion" in sh(1) for more information). 230214501Srpaulo # 231214501Srpaulo eval echo '"${'"$1"'}"' 2> /dev/null 232214501Srpaulo ) 233214501Srpaulo} 234214501Srpaulo 235214501Srpaulo# f_sysrc_find $varname 236252726Srpaulo# 237252726Srpaulo# Find which file holds the effective last-assignment to a given variable 238252726Srpaulo# within the rc.conf(5) file(s). 239252726Srpaulo# 240214501Srpaulo# If the variable is found in any of the rc.conf(5) files, the function prints 241214501Srpaulo# the filename it was found in and then returns success. Otherwise output is 242214501Srpaulo# NULL and the function returns with error status. 243214501Srpaulo# 244214501Srpaulof_sysrc_find() 245214501Srpaulo{ 246214501Srpaulo local varname="$1" 247214501Srpaulo local regex="^[[:space:]]*$varname=" 248214501Srpaulo local rc_conf_files="$( f_sysrc_get rc_conf_files )" 249214501Srpaulo local conf_files= 250214501Srpaulo local file 251214501Srpaulo 252214501Srpaulo # Check parameters 253214501Srpaulo [ "$varname" ] || return $FAILURE 254214501Srpaulo 255214501Srpaulo # 256214501Srpaulo # If RC_CONFS is defined, set $rc_conf_files to an explicit 257214501Srpaulo # value, modifying the default behavior of source_rc_confs(). 258214501Srpaulo # 259214501Srpaulo [ "$RC_CONFS" ] && rc_conf_files="$RC_CONFS" 260214501Srpaulo 261214501Srpaulo # 262214501Srpaulo # Reverse the order of files in rc_conf_files (the boot process sources 263214501Srpaulo # these in order, so we will search them in reverse-order to find the 264214501Srpaulo # last-assignment -- the one that ultimately effects the environment). 265214501Srpaulo # 266214501Srpaulo for file in $rc_conf_files; do 267214501Srpaulo conf_files="$file${conf_files:+ }$conf_files" 268214501Srpaulo done 269252726Srpaulo 270252726Srpaulo # 271252726Srpaulo # Append the defaults file (since directives in the defaults file 272252726Srpaulo # indeed affect the boot process, we'll want to know when a directive 273252726Srpaulo # is found there). 274252726Srpaulo # 275252726Srpaulo conf_files="$conf_files${conf_files:+ }$RC_DEFAULTS" 276252726Srpaulo 277252726Srpaulo # 278252726Srpaulo # Find which file matches assignment to the given variable name. 279252726Srpaulo # 280252726Srpaulo for file in $conf_files; do 281252726Srpaulo [ -f "$file" -a -r "$file" ] || continue 282252726Srpaulo if grep -Eq "$regex" $file; then 283252726Srpaulo echo $file 284252726Srpaulo return $SUCCESS 285252726Srpaulo fi 286252726Srpaulo done 287252726Srpaulo 288252726Srpaulo return $FAILURE # Not found 289252726Srpaulo} 290252726Srpaulo 291252726Srpaulo# f_sysrc_desc $varname 292214501Srpaulo# 293214501Srpaulo# Attempts to return the comments associated with varname from the rc.conf(5) 294214501Srpaulo# defaults file `/etc/defaults/rc.conf' (or whatever RC_DEFAULTS points to). 295214501Srpaulo# 296214501Srpaulo# Multi-line comments are joined together. Results are NULL if no description 297214501Srpaulo# could be found. 298214501Srpaulo# 299214501Srpaulo# This function is a two-parter. Below is the awk(1) portion of the function, 300214501Srpaulo# afterward is the sh(1) function which utilizes the below awk script. 301214501Srpaulo# 302214501Srpaulof_sysrc_desc_awk=' 303214501Srpaulo# Variables that should be defined on the invocation line: 304214501Srpaulo# -v varname="varname" 305214501Srpaulo# 306214501SrpauloBEGIN { 307214501Srpaulo regex = "^[[:space:]]*"varname"=" 308214501Srpaulo found = 0 309214501Srpaulo buffer = "" 310214501Srpaulo} 311214501Srpaulo{ 312214501Srpaulo if ( ! found ) 313252726Srpaulo { 314214501Srpaulo if ( ! match($0, regex) ) next 315214501Srpaulo 316214501Srpaulo found = 1 317214501Srpaulo sub(/^[^#]*(#[[:space:]]*)?/, "") 318214501Srpaulo buffer = $0 319214501Srpaulo next 320214501Srpaulo } 321214501Srpaulo 322214501Srpaulo if ( !/^[[:space:]]*#/ || 323214501Srpaulo /^[[:space:]]*[[:alpha:]_][[:alnum:]_]*=/ || 324214501Srpaulo /^[[:space:]]*#[[:alpha:]_][[:alnum:]_]*=/ || 325214501Srpaulo /^[[:space:]]*$/ ) exit 326214501Srpaulo 327214501Srpaulo sub(/(.*#)*[[:space:]]*/, "") 328214501Srpaulo buffer = buffer" "$0 329214501Srpaulo} 330214501SrpauloEND { 331214501Srpaulo # Clean up the buffer 332214501Srpaulo sub(/^[[:space:]]*/, "", buffer) 333214501Srpaulo sub(/[[:space:]]*$/, "", buffer) 334214501Srpaulo 335214501Srpaulo print buffer 336214501Srpaulo exit ! found 337214501Srpaulo} 338214501Srpaulo' 339214501Srpaulof_sysrc_desc() 340214501Srpaulo{ 341214501Srpaulo awk -v varname="$1" "$f_sysrc_desc_awk" < "$RC_DEFAULTS" 342214501Srpaulo} 343214501Srpaulo 344214501Srpaulo# f_sysrc_set $varname $new_value 345214501Srpaulo# 346214501Srpaulo# Change a setting in the system configuration files (edits the files in-place 347214501Srpaulo# to change the value in the last assignment to the variable). If the variable 348214501Srpaulo# does not appear in the source file, it is appended to the end of the primary 349214501Srpaulo# system configuration file `/etc/rc.conf'. 350214501Srpaulo# 351214501Srpaulo# This function is a two-parter. Below is the awk(1) portion of the function, 352214501Srpaulo# afterward is the sh(1) function which utilizes the below awk script. 353214501Srpaulo# 354214501Srpaulof_sysrc_set_awk=' 355214501Srpaulo# Variables that should be defined on the invocation line: 356214501Srpaulo# -v varname="varname" 357214501Srpaulo# -v new_value="new_value" 358214501Srpaulo# 359214501SrpauloBEGIN { 360214501Srpaulo regex = "^[[:space:]]*"varname"=" 361214501Srpaulo found = retval = 0 362214501Srpaulo} 363214501Srpaulo{ 364214501Srpaulo # If already found... just spew 365214501Srpaulo if ( found ) { print; next } 366214501Srpaulo 367214501Srpaulo # Does this line match an assignment to our variable? 368214501Srpaulo if ( ! match($0, regex) ) { print; next } 369214501Srpaulo 370214501Srpaulo # Save important match information 371214501Srpaulo found = 1 372214501Srpaulo matchlen = RSTART + RLENGTH - 1 373214501Srpaulo 374214501Srpaulo # Store the value text for later munging 375214501Srpaulo value = substr($0, matchlen + 1, length($0) - matchlen) 376214501Srpaulo 377214501Srpaulo # Store the first character of the value 378214501Srpaulo t1 = t2 = substr(value, 0, 1) 379214501Srpaulo 380214501Srpaulo # Assignment w/ back-ticks, expression, or misc. 381214501Srpaulo # We ignore these since we did not generate them 382214501Srpaulo # 383214501Srpaulo if ( t1 ~ /[`$\\]/ ) { retval = 1; print; next } 384214501Srpaulo 385214501Srpaulo # Assignment w/ single-quoted value 386214501Srpaulo else if ( t1 == "'\''" ) { 387214501Srpaulo sub(/^'\''[^'\'']*/, "", value) 388214501Srpaulo if ( length(value) == 0 ) t2 = "" 389214501Srpaulo sub(/^'\''/, "", value) 390214501Srpaulo } 391214501Srpaulo 392214501Srpaulo # Assignment w/ double-quoted value 393214501Srpaulo else if ( t1 == "\"" ) { 394214501Srpaulo sub(/^"(.*\\\\+")*[^"]*/, "", value) 395214501Srpaulo if ( length(value) == 0 ) t2 = "" 396214501Srpaulo sub(/^"/, "", value) 397214501Srpaulo } 398214501Srpaulo 399214501Srpaulo # Assignment w/ non-quoted value 400214501Srpaulo else if ( t1 ~ /[^[:space:];]/ ) { 401214501Srpaulo t1 = t2 = "\"" 402214501Srpaulo sub(/^[^[:space:]]*/, "", value) 403214501Srpaulo } 404214501Srpaulo 405214501Srpaulo # Null-assignment 406214501Srpaulo else if ( t1 ~ /[[:space:];]/ ) { t1 = t2 = "\"" } 407214501Srpaulo 408214501Srpaulo printf "%s%c%s%c%s\n", substr($0, 0, matchlen), \ 409214501Srpaulo t1, new_value, t2, value 410214501Srpaulo} 411214501SrpauloEND { exit retval } 412214501Srpaulo' 413214501Srpaulof_sysrc_set() 414214501Srpaulo{ 415214501Srpaulo local varname="$1" new_value="$2" 416214501Srpaulo 417214501Srpaulo # Check arguments 418214501Srpaulo [ "$varname" ] || return $FAILURE 419214501Srpaulo 420214501Srpaulo # 421214501Srpaulo # Find which rc.conf(5) file contains the last-assignment 422252726Srpaulo # 423252726Srpaulo local not_found= 424252726Srpaulo local file="$( f_sysrc_find "$varname" )" 425252726Srpaulo if [ "$file" = "$RC_DEFAULTS" -o ! "$file" ]; then 426252726Srpaulo # 427252726Srpaulo # We either got a null response (not found) or the variable 428214501Srpaulo # was only found in the rc.conf(5) defaults. In either case, 429214501Srpaulo # let's instead modify the first file from $rc_conf_files. 430214501Srpaulo # 431214501Srpaulo 432214501Srpaulo not_found=1 433214501Srpaulo 434252726Srpaulo # 435252726Srpaulo # If RC_CONFS is defined, use $RC_CONFS 436252726Srpaulo # rather than $rc_conf_files. 437214501Srpaulo # 438214501Srpaulo if [ "$RC_CONFS" ]; then 439214501Srpaulo file="${RC_CONFS%%[$IFS]*}" 440252726Srpaulo else 441252726Srpaulo file=$( f_sysrc_get rc_conf_files ) 442252726Srpaulo file="${file%%[$IFS]*}" 443214501Srpaulo fi 444214501Srpaulo fi 445214501Srpaulo 446214501Srpaulo # 447214501Srpaulo # If not found, append new value to last file and return. 448214501Srpaulo # 449214501Srpaulo if [ "$not_found" ]; then 450214501Srpaulo echo "$varname=\"$new_value\"" >> "$file" 451214501Srpaulo return $? 452214501Srpaulo fi 453214501Srpaulo 454214501Srpaulo # 455252726Srpaulo # Perform sanity checks. 456252726Srpaulo # 457252726Srpaulo if [ ! -w "$file" ]; then 458252726Srpaulo f_err "$msg_cannot_create_permission_denied\n" \ 459214501Srpaulo "$pgm" "$file" 460214501Srpaulo return $FAILURE 461252726Srpaulo fi 462252726Srpaulo 463252726Srpaulo # 464214501Srpaulo # Create a new temporary file to write to. 465214501Srpaulo # 466214501Srpaulo local tmpfile="$( mktemp -t "$pgm" )" 467214501Srpaulo [ "$tmpfile" ] || return $FAILURE 468214501Srpaulo 469214501Srpaulo # 470214501Srpaulo # Fixup permissions (else we're in for a surprise, as mktemp(1) creates 471214501Srpaulo # the temporary file with 0600 permissions, and if we simply mv(1) the 472214501Srpaulo # temporary file over the destination, the destination will inherit the 473214501Srpaulo # permissions from the temporary file). 474214501Srpaulo # 475214501Srpaulo local mode 476214501Srpaulo mode=$( stat -f '%#Lp' "$file" 2> /dev/null ) 477214501Srpaulo f_quietly chmod "${mode:-0644}" "$tmpfile" 478214501Srpaulo 479214501Srpaulo # 480214501Srpaulo # Fixup ownership. The destination file _is_ writable (we tested 481214501Srpaulo # earlier above). However, this will fail if we don't have sufficient 482214501Srpaulo # permissions (so we throw stderr into the bit-bucket). 483214501Srpaulo # 484214501Srpaulo local owner 485214501Srpaulo owner=$( stat -f '%u:%g' "$file" 2> /dev/null ) 486214501Srpaulo f_quietly chown "${owner:-root:wheel}" "$tmpfile" 487214501Srpaulo 488214501Srpaulo # 489214501Srpaulo # Operate on the matching file, replacing only the last occurrence. 490214501Srpaulo # 491214501Srpaulo local new_contents retval 492214501Srpaulo new_contents=$( tail -r $file 2> /dev/null ) 493214501Srpaulo new_contents=$( echo "$new_contents" | awk -v varname="$varname" \ 494214501Srpaulo -v new_value="$new_value" "$f_sysrc_set_awk" ) 495214501Srpaulo retval=$? 496214501Srpaulo 497214501Srpaulo # 498214501Srpaulo # Write the temporary file contents. 499214501Srpaulo # 500252726Srpaulo echo "$new_contents" | tail -r > "$tmpfile" || return $FAILURE 501252726Srpaulo if [ $retval -ne $SUCCESS ]; then 502252726Srpaulo echo "$varname=\"$new_value\"" >> "$tmpfile" 503252726Srpaulo fi 504252726Srpaulo 505252726Srpaulo # 506214501Srpaulo # Taint-check our results. 507214501Srpaulo # 508214501Srpaulo if ! /bin/sh -n "$tmpfile"; then 509214501Srpaulo f_err "$msg_previous_syntax_errors\n" "$pgm" "$file" 510214501Srpaulo rm -f "$tmpfile" 511214501Srpaulo return $FAILURE 512214501Srpaulo fi 513214501Srpaulo 514214501Srpaulo # 515214501Srpaulo # Finally, move the temporary file into place. 516214501Srpaulo # 517214501Srpaulo mv "$tmpfile" "$file" 518214501Srpaulo} 519214501Srpaulo 520214501Srpaulo# f_sysrc_delete $varname 521214501Srpaulo# 522214501Srpaulo# Remove a setting from the system configuration files (edits files in-place). 523214501Srpaulo# Deletes all assignments to the given variable in all config files. If the 524214501Srpaulo# `-f file' option is passed, the removal is restricted to only those files 525214501Srpaulo# specified, otherwise the system collection of rc_conf_files is used. 526214501Srpaulo# 527214501Srpaulo# This function is a two-parter. Below is the awk(1) portion of the function, 528214501Srpaulo# afterward is the sh(1) function which utilizes the below awk script. 529214501Srpaulo# 530214501Srpaulof_sysrc_delete_awk=' 531214501Srpaulo# Variables that should be defined on the invocation line: 532214501Srpaulo# -v varname="varname" 533214501Srpaulo# 534214501SrpauloBEGIN { 535214501Srpaulo regex = "^[[:space:]]*"varname"=" 536214501Srpaulo found = 0 537214501Srpaulo} 538214501Srpaulo{ 539214501Srpaulo if ( $0 ~ regex ) 540214501Srpaulo found = 1 541214501Srpaulo else 542214501Srpaulo print 543214501Srpaulo} 544214501SrpauloEND { exit ! found } 545214501Srpaulo' 546214501Srpaulof_sysrc_delete() 547214501Srpaulo{ 548214501Srpaulo local varname="$1" 549214501Srpaulo local file 550214501Srpaulo 551214501Srpaulo # Check arguments 552214501Srpaulo [ "$varname" ] || return $FAILURE 553214501Srpaulo 554214501Srpaulo # 555214501Srpaulo # Operate on each of the specified files 556214501Srpaulo # 557214501Srpaulo for file in ${RC_CONFS:-$( f_sysrc_get rc_conf_files )}; do 558214501Srpaulo [ -e "$file" ] || continue 559214501Srpaulo 560214501Srpaulo # 561214501Srpaulo # Create a new temporary file to write to. 562214501Srpaulo # 563214501Srpaulo local tmpfile="$( mktemp -t "$pgm" )" 564214501Srpaulo [ "$tmpfile" ] || return $FAILURE 565214501Srpaulo 566214501Srpaulo # 567214501Srpaulo # Fixup permissions and ownership (mktemp(1) defaults to 0600 568214501Srpaulo # permissions) to instead match the destination file. 569252726Srpaulo # 570252726Srpaulo local mode owner 571214501Srpaulo mode=$( stat -f '%#Lp' "$file" 2> /dev/null ) 572214501Srpaulo owner=$( stat -f '%u:%g' "$file" 2> /dev/null ) 573214501Srpaulo f_quietly chmod "${mode:-0644}" "$tmpfile" 574214501Srpaulo f_quietly chown "${owner:-root:wheel}" "$tmpfile" 575214501Srpaulo 576214501Srpaulo # 577214501Srpaulo # Operate on the file, removing all occurrences, saving the 578214501Srpaulo # output in our temporary file. 579214501Srpaulo # 580214501Srpaulo awk -v varname="$varname" "$f_sysrc_delete_awk" "$file" \ 581214501Srpaulo > "$tmpfile" 582214501Srpaulo if [ $? -ne $SUCCESS ]; then 583214501Srpaulo # The file didn't contain any assignments 584214501Srpaulo rm -f "$tmpfile" 585214501Srpaulo continue 586214501Srpaulo fi 587214501Srpaulo 588214501Srpaulo # 589214501Srpaulo # Taint-check our results. 590214501Srpaulo # 591214501Srpaulo if ! /bin/sh -n "$tmpfile"; then 592214501Srpaulo f_err "$msg_previous_syntax_errors\n" \ 593214501Srpaulo "$pgm" "$file" 594214501Srpaulo rm -f "$tmpfile" 595214501Srpaulo return $FAILURE 596214501Srpaulo fi 597214501Srpaulo 598214501Srpaulo # 599214501Srpaulo # Perform sanity checks 600214501Srpaulo # 601214501Srpaulo if [ ! -w "$file" ]; then 602214501Srpaulo f_err "$msg_permission_denied\n" "$pgm" "$file" 603214501Srpaulo rm -f "$tmpfile" 604214501Srpaulo return $FAILURE 605214501Srpaulo fi 606214501Srpaulo 607214501Srpaulo # 608214501Srpaulo # Finally, move the temporary file into place. 609214501Srpaulo # 610214501Srpaulo mv "$tmpfile" "$file" 611214501Srpaulo done 612214501Srpaulo} 613214501Srpaulo 614214501Srpaulofi # ! $_SYSRC_SUBR 615214501Srpaulo