1if [ ! "$_SYSRC_SUBR" ]; then _SYSRC_SUBR=1 2# 3# SPDX-License-Identifier: BSD-2-Clause 4# 5# Copyright (c) 2006-2026 Devin Teske 6# 7############################################################ INFORMATION 8# 9# This file was split-out of bsdconfig(8) and is now self-contained, and is 10# no longer dependent on bsdconfig(8) or any of its libraries. 11# 12############################################################ CONFIGURATION 13 14# 15# Standard pathnames (inherit values from shell if available) 16# 17: "${RC_DEFAULTS:=/etc/defaults/rc.conf}" 18 19############################################################ GLOBALS 20 21# 22# Global exit status variables 23# 24SUCCESS=0 25FAILURE=1 26 27# 28# Error messages 29# 30msg_cannot_create_permission_denied="%s: cannot create %s: Permission denied" 31msg_permission_denied="%s: %s: Permission denied" 32msg_previous_syntax_errors="%s: Not overwriting \`%s' due to previous syntax errors" 33 34# 35# Valid characters that can appear in an sh(1) variable name 36# 37# Please note that the character ranges A-Z and a-z should be avoided because 38# these can include accent characters (which are not valid in a variable name). 39# For example, A-Z matches any character that sorts after A but before Z, 40# including A and Z. Although ASCII order would make more sense, that is not 41# how it works. 42# 43VALID_VARNAME_CHARS="0-9ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_" 44 45############################################################ FUNCTIONS 46 47# f_have $anything ... 48# 49# A wrapper to the `type' built-in. Returns true if argument is a valid shell 50# built-in, keyword, or externally-tracked binary, otherwise false. 51# 52if ! type f_have > /dev/null 2>&1; then 53f_have() 54{ 55 type "$@" > /dev/null 2>&1 56} 57fi 58 59# f_err $format [$arguments ...] 60# 61# Print a message to stderr (fd=2). 62# 63if ! f_have f_err; then 64f_err() 65{ 66 printf "$@" >&2 67} 68fi 69 70# setvar $var_to_set [$value] 71# 72# Implement setvar for shells unlike FreeBSD sh(1). 73# 74if ! f_have setvar; then 75setvar() 76{ 77 [ $# -gt 0 ] || return $SUCCESS 78 local __setvar_var_to_set="$1" __setvar_right="$2" __setvar_left= 79 case $# in 80 1) unset "$__setvar_var_to_set" 81 return $? ;; 82 2) : fall through ;; 83 *) f_err "setvar: too many arguments\n" 84 return $FAILURE 85 esac 86 case "$__setvar_var_to_set" in *[!0-9A-Za-z_]*) 87 f_err "setvar: %s: bad variable name\n" "$__setvar_var_to_set" 88 return 2 89 esac 90 while case "$__setvar_r" in *\'*) : ;; *) false ; esac 91 do 92 __setvar_left="$__setvar_left${__setvar_right%%\'*}'\\''" 93 __setvar_right="${__setvar_right#*\'}" 94 done 95 __setvar_left="$__setvar_left${__setvar_right#*\'}" 96 eval "$__setvar_var_to_set='$__setvar_left'" 97} 98fi 99 100# f_getvar $var_to_get [$var_to_set] 101# 102# Utility function designed to go along with the already-builtin setvar. 103# Allows clean variable name indirection without forking or sub-shells. 104# 105# Returns error status if the requested variable ($var_to_get) is not set. 106# 107# If $var_to_set is missing or NULL, the value of $var_to_get is printed to 108# standard output for capturing in a sub-shell (which is less-recommended 109# because of performance degredation; for example, when called in a loop). 110# 111if ! f_have f_getvar; then 112f_getvar() 113{ 114 local __var_to_get="$1" __var_to_set="$2" 115 [ "$__var_to_set" ] || local value 116 eval [ \"\${$__var_to_get+set}\" ] 117 local __retval=$? 118 eval ${__var_to_set:-value}=\"\${$__var_to_get}\" 119 [ "$__var_to_set" ] || { [ "$value" ] && echo "$value"; } 120 return $__retval 121} 122fi 123 124# f_eval_catch [-de] [-k $var_to_set] $funcname $utility \ 125# $printf_format [$printf_args ...] 126# 127# Evaluate the printf-rendered command line and capture its output. The return 128# status of the command is preserved. If `-k' is given, output is stored in 129# $var_to_set. If `-e' is given, output is echoed to stderr on failure. 130# 131if ! f_have f_eval_catch; then 132f_eval_catch() 133{ 134 local OPTIND OPTARG __flag __show_err= __var_to_set= 135 while getopts "dek:" __flag > /dev/null; do 136 case "$__flag" in 137 d) : ;; # no-op: always non-interactive here 138 e) __show_err=1 ;; 139 k) __var_to_set="$OPTARG" ;; 140 esac 141 done 142 shift $(( $OPTIND - 1 )) 143 144 local __funcname="$1" __utility="$2"; shift 2 145 local __cmd __output __retval 146 147 __cmd=$( printf -- "$@" ) 148 __output=$( exec 2>&1; eval "$__cmd" ) 149 __retval=$? 150 if [ "$__output" -a "$__show_err" ]; then 151 echo "$__output" >&2 152 fi 153 [ "$__var_to_set" ] && setvar "$__var_to_set" "$__output" 154 return $__retval 155} 156fi 157 158# f_clean_env [--except $varname ...] 159# 160# Unset all environment variables in the current scope. An optional list of 161# arguments can be passed, indicating which variables to avoid unsetting; the 162# `--except' is required to enable the exclusion-list as the remainder of 163# positional arguments. 164# 165# Be careful not to call this in a shell that you still expect to perform 166# $PATH expansion in, because this will blow $PATH away. This is best used 167# within a sub-shell block "(...)" or "$(...)" or "`...`". 168# 169f_clean_env() 170{ 171 local var arg except= 172 173 # 174 # Should we process an exclusion-list? 175 # 176 if [ "$1" = "--except" ]; then 177 except=1 178 shift 1 179 fi 180 181 # 182 # Loop over a list of variable names from set(1) built-in. 183 # 184 for var in $( set | awk -F= \ 185 '/^[[:alpha:]_][[:alnum:]_]*=/ {print $1}' \ 186 | grep -v '^except$' 187 ); do 188 # 189 # In POSIX bourne-shell, attempting to unset(1) OPTIND results 190 # in "unset: Illegal number:" and causes abrupt termination. 191 # 192 [ "$var" = OPTIND ] && continue 193 194 # 195 # Process the exclusion-list? 196 # 197 if [ "$except" ]; then 198 for arg in "$@" ""; do 199 [ "$var" = "$arg" ] && break 200 done 201 [ "$arg" ] && continue 202 fi 203 204 unset "$var" 205 done 206} 207 208# f_sysrc_get $varname 209# 210# Get a system configuration setting from the collection of system- 211# configuration files (in order: /etc/defaults/rc.conf /etc/rc.conf and 212# /etc/rc.conf.local) 213# 214# NOTE: Additional shell parameter-expansion formats are supported. For 215# example, passing an argument of "hostname%%.*" (properly quoted) will 216# return the hostname up to (but not including) the first `.' (see sh(1), 217# "Parameter Expansion" for more information on additional formats). 218# 219f_sysrc_get() 220{ 221 # Sanity check 222 [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE 223 224 # Taint-check variable name 225 case "$1" in 226 [0-9]*) 227 # Don't expand possible positional parameters 228 return $FAILURE ;; 229 *) 230 [ "$1" ] || return $FAILURE 231 esac 232 233 ( # Execute within sub-shell to protect parent environment 234 235 # 236 # Clear the environment of all variables, preventing the 237 # expansion of normals such as `PS1', `TERM', etc. 238 # 239 f_clean_env --except IFS RC_CONFS RC_DEFAULTS 240 241 . "$RC_DEFAULTS" > /dev/null 2>&1 242 243 unset RC_DEFAULTS 244 # no longer needed 245 246 # 247 # If the query is for `rc_conf_files' then store the value that 248 # we inherited from sourcing RC_DEFAULTS (above) so that we may 249 # conditionally restore this value after source_rc_confs in the 250 # event that RC_CONFS does not customize the value. 251 # 252 if [ "$1" = "rc_conf_files" ]; then 253 _rc_conf_files="$rc_conf_files" 254 fi 255 256 # 257 # If RC_CONFS is defined, set $rc_conf_files to an explicit 258 # value, modifying the default behavior of source_rc_confs(). 259 # 260 if [ "${RC_CONFS+set}" ]; then 261 rc_conf_files="$RC_CONFS" 262 _rc_confs_set=1 263 fi 264 265 source_rc_confs > /dev/null 2>&1 266 267 # 268 # If the query was for `rc_conf_files' AND after calling 269 # source_rc_confs the value has not changed, then we should 270 # restore the value to the one inherited from RC_DEFAULTS 271 # before performing the final query (preventing us from 272 # returning what was set via RC_CONFS when the intent was 273 # instead to query the value from the file(s) specified). 274 # 275 if [ "$1" = "rc_conf_files" -a \ 276 "$_rc_confs_set" -a \ 277 "$rc_conf_files" = "$RC_CONFS" \ 278 ]; then 279 rc_conf_files="$_rc_conf_files" 280 unset _rc_conf_files 281 unset _rc_confs_set 282 fi 283 284 unset RC_CONFS 285 # no longer needed 286 287 # 288 # This must be the last functional line for both the sub-shell 289 # and the function to preserve the return status from formats 290 # such as "${varname?}" and "${varname:?}" (see "Parameter 291 # Expansion" in sh(1) for more information). 292 # 293 eval printf "'%s\\n'" '"${'"$1"'}"' 2> /dev/null 294 ) 295} 296 297# f_sysrc_service_configs [-a|-p] $name [$var_to_set] 298# 299# Get a list of optional `rc.conf.d' entries sourced by system `rc.d' script 300# $name (see rc.subr(8) for additional information on `rc.conf.d'). If $name 301# exists in `/etc/rc.d' or $local_startup directories and is an rc(8) script 302# the result is a space separated list of `rc.conf.d' entries sourced by the 303# $name `rc.d' script. Otherwise, if $name exists as a binary `rc.d' script, 304# the result is ``/etc/rc.conf.d/$name /usr/local/etc/rc.conf.d/$name''. The 305# result is NULL if $name does not exist. 306# 307# If $var_to_set is missing or NULL, output is to standard out. Returns success 308# if $name was found, failure otherwise. 309# 310# If `-a' flag is given and $var_to_set is non-NULL, append result to value of 311# $var_to_set rather than overwriting current contents. 312# 313# If `-p' flag is given and $var_to_set is non-NULL, prepend result to value of 314# $var_to_set rather than overwriting current contents. 315# 316# NB: The `-a' and `-p' option flags are mutually exclusive. 317# 318f_sysrc_service_configs() 319{ 320 local OPTIND=1 OPTARG __flag __append= __prepend= 321 local __local_startup __dir __spath __stype __names= 322 323 while getopts ap __flag; do 324 case "$__flag" in 325 a) __append=1 __prepend= ;; 326 p) __prepend=1 __append= ;; 327 esac 328 done 329 shift $(( $OPTIND - 1 )) 330 331 [ $# -gt 0 ] || return $FAILURE 332 local __sname="$1" __var_to_set="$2" 333 334 __local_startup=$( f_sysrc_get local_startup ) 335 for __dir in /etc/rc.d $__local_startup; do 336 __spath="$__dir/$__sname" 337 [ -f "$__spath" -a -x "$__spath" ] || __spath= continue 338 break 339 done 340 [ "$__spath" ] || return $FAILURE 341 342 __stype=$( file -b "$__spath" 2> /dev/null ) 343 case "$__stype" in 344 *"shell script"*) 345 __names=$( exec 9<&1 1>&- 2>&- 346 last_name= 347 print_name() { 348 local name="$1" 349 case "$name" in 350 ""|.|..|*/*|"$last_name") return ;; 351 esac 352 echo "$name" >&9 353 last_name="$name" 354 } 355 eval "$( awk '{ 356 gsub(/load_rc_config /, "print_name ") 357 gsub(/run_rc_command /, ": ") 358 print 359 }' "$__spath" )" 360 ) ;; 361 *) 362 __names="$__sname" 363 esac 364 365 local __name __test_path __configs= 366 for __name in $__names; do 367 for __dir in /etc/rc.d $__local_startup; do 368 __test_path="${__dir%/rc.d}/rc.conf.d/$__name" 369 [ -d "$__test_path" ] || 370 __configs="$__configs $__test_path" continue 371 for __test_path in "$__test_path"/*; do 372 [ -f "$__test_path" ] || continue 373 __configs="$__configs $__test_path" 374 done 375 done 376 done 377 __configs="${__configs# }" 378 379 if [ "$__var_to_set" ]; then 380 local __cur= 381 [ "$__append" -o "$__prepend" ] && 382 f_getvar "$__var_to_set" __cur 383 [ "$__append" ] && __configs="$__cur{$__cur:+ }$__configs" 384 [ "$__prepend" ] && __configs="$__configs${__cur:+ }$__cur" 385 setvar "$__var_to_set" "$__configs" 386 else 387 echo "$__configs" 388 fi 389 390 return $SUCCESS 391} 392 393# f_sysrc_get_default $varname 394# 395# Get a system configuration default setting from the default rc.conf(5) file 396# (or whatever RC_DEFAULTS points at). 397# 398f_sysrc_get_default() 399{ 400 # Sanity check 401 [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE 402 403 # Taint-check variable name 404 case "$1" in 405 [0-9]*) 406 # Don't expand possible positional parameters 407 return $FAILURE ;; 408 *) 409 [ "$1" ] || return $FAILURE 410 esac 411 412 ( # Execute within sub-shell to protect parent environment 413 414 # 415 # Clear the environment of all variables, preventing the 416 # expansion of normals such as `PS1', `TERM', etc. 417 # 418 f_clean_env --except RC_DEFAULTS 419 420 . "$RC_DEFAULTS" > /dev/null 2>&1 421 422 unset RC_DEFAULTS 423 # no longer needed 424 425 # 426 # This must be the last functional line for both the sub-shell 427 # and the function to preserve the return status from formats 428 # such as "${varname?}" and "${varname:?}" (see "Parameter 429 # Expansion" in sh(1) for more information). 430 # 431 eval printf "'%s\\n'" '"${'"$1"'}"' 2> /dev/null 432 ) 433} 434 435# f_sysrc_find $varname 436# 437# Find which file holds the effective last-assignment to a given variable 438# within the rc.conf(5) file(s). 439# 440# If the variable is found in any of the rc.conf(5) files, the function prints 441# the filename it was found in and then returns success. Otherwise output is 442# NULL and the function returns with error status. 443# 444f_sysrc_find() 445{ 446 local varname="${1%%[!$VALID_VARNAME_CHARS]*}" 447 local regex="^[[:space:]]*$varname=" 448 local rc_conf_files="$( f_sysrc_get rc_conf_files )" 449 local conf_files= 450 local file 451 452 # Check parameters 453 case "$varname" in 454 ""|[0-9]*) return $FAILURE 455 esac 456 457 # 458 # If RC_CONFS is defined, set $rc_conf_files to an explicit 459 # value, modifying the default behavior of source_rc_confs(). 460 # 461 [ "${RC_CONFS+set}" ] && rc_conf_files="$RC_CONFS" 462 463 # 464 # Reverse the order of files in rc_conf_files (the boot process sources 465 # these in order, so we will search them in reverse-order to find the 466 # last-assignment -- the one that ultimately effects the environment). 467 # 468 for file in $rc_conf_files; do 469 conf_files="$file${conf_files:+ }$conf_files" 470 done 471 472 # 473 # Append the defaults file (since directives in the defaults file 474 # indeed affect the boot process, we'll want to know when a directive 475 # is found there). 476 # 477 conf_files="$conf_files${conf_files:+ }$RC_DEFAULTS" 478 479 # 480 # Find which file matches assignment to the given variable name. 481 # 482 for file in $conf_files; do 483 [ -f "$file" -a -r "$file" ] || continue 484 if grep -Eq "$regex" $file; then 485 echo $file 486 return $SUCCESS 487 fi 488 done 489 490 return $FAILURE # Not found 491} 492 493# f_sysrc_desc $varname 494# 495# Attempts to return the comments associated with varname from the rc.conf(5) 496# defaults file `/etc/defaults/rc.conf' (or whatever RC_DEFAULTS points to). 497# 498# Multi-line comments are joined together. Results are NULL if no description 499# could be found. 500# 501# This function is a two-parter. Below is the awk(1) portion of the function, 502# afterward is the sh(1) function which utilizes the below awk script. 503# 504f_sysrc_desc_awk=' 505# Variables that should be defined on the invocation line: 506# -v varname="varname" 507# 508BEGIN { 509 regex = "^[[:space:]]*"varname"=" 510 found = 0 511 buffer = "" 512} 513{ 514 if ( ! found ) 515 { 516 if ( ! match($0, regex) ) next 517 518 found = 1 519 sub(/^[^#]*(#[[:space:]]*)?/, "") 520 buffer = $0 521 next 522 } 523 524 if ( !/^[[:space:]]*#/ || 525 /^[[:space:]]*[[:alpha:]_][[:alnum:]_]*=/ || 526 /^[[:space:]]*#[[:alpha:]_][[:alnum:]_]*=/ || 527 /^[[:space:]]*$/ ) exit 528 529 sub(/(.*#)*[[:space:]]*/, "") 530 buffer = buffer" "$0 531} 532END { 533 # Clean up the buffer 534 sub(/^[[:space:]]*/, "", buffer) 535 sub(/[[:space:]]*$/, "", buffer) 536 537 print buffer 538 exit ! found 539} 540' 541f_sysrc_desc() 542{ 543 awk -v varname="$1" "$f_sysrc_desc_awk" < "$RC_DEFAULTS" 544} 545 546# f_sysrc_set $varname $new_value 547# 548# Change a setting in the system configuration files (edits the files in-place 549# to change the value in the last assignment to the variable). If the variable 550# does not appear in the source file, it is appended to the end of the primary 551# system configuration file `/etc/rc.conf'. 552# 553# This function is a two-parter. Below is the awk(1) portion of the function, 554# afterward is the sh(1) function which utilizes the below awk script. 555# 556f_sysrc_set_awk=' 557# Variables that should be defined on the invocation line: 558# -v varname="varname" 559# -v new_value="new_value" 560# 561BEGIN { 562 regex = "^[[:space:]]*"varname"=" 563 found = retval = 0 564} 565{ 566 # If already found... just spew 567 if ( found ) { print; next } 568 569 # Does this line match an assignment to our variable? 570 if ( ! match($0, regex) ) { print; next } 571 572 # Save important match information 573 found = 1 574 matchlen = RSTART + RLENGTH - 1 575 576 # Store the value text for later munging 577 value = substr($0, matchlen + 1, length($0) - matchlen) 578 579 # Store the first character of the value 580 t1 = t2 = substr(value, 0, 1) 581 582 # Assignment w/ back-ticks, expression, or misc. 583 # We ignore these since we did not generate them 584 # 585 if ( t1 ~ /[`$\\]/ ) { retval = 1; print; next } 586 587 # Assignment w/ single-quoted value 588 else if ( t1 == "'\''" ) { 589 sub(/^'\''[^'\'']*/, "", value) 590 if ( length(value) == 0 ) t2 = "" 591 sub(/^'\''/, "", value) 592 } 593 594 # Assignment w/ double-quoted value 595 else if ( t1 == "\"" ) { 596 sub(/^"(.*\\\\+")*[^"]*/, "", value) 597 if ( length(value) == 0 ) t2 = "" 598 sub(/^"/, "", value) 599 } 600 601 # Assignment w/ non-quoted value 602 else if ( t1 ~ /[^[:space:];]/ ) { 603 t1 = t2 = "\"" 604 sub(/^[^[:space:]]*/, "", value) 605 } 606 607 # Null-assignment 608 else if ( t1 ~ /[[:space:];]/ ) { t1 = t2 = "\"" } 609 610 printf "%s%c%s%c%s\n", substr($0, 0, matchlen), \ 611 t1, new_value, t2, value 612} 613END { exit retval } 614' 615f_sysrc_set() 616{ 617 local funcname=f_sysrc_set 618 local varname="$1" new_value="$2" 619 620 # Check arguments 621 [ "$varname" ] || return $FAILURE 622 623 # 624 # Find which rc.conf(5) file contains the last-assignment 625 # 626 local not_found= 627 local file="$( f_sysrc_find "$varname" )" 628 if [ "$file" = "$RC_DEFAULTS" -o ! "$file" ]; then 629 # 630 # We either got a null response (not found) or the variable 631 # was only found in the rc.conf(5) defaults. In either case, 632 # let's instead modify the first file from $rc_conf_files. 633 # 634 635 not_found=1 636 637 # 638 # If RC_CONFS is defined, use $RC_CONFS 639 # rather than $rc_conf_files. 640 # 641 if [ "${RC_CONFS+set}" ]; then 642 file="${RC_CONFS%%[$IFS]*}" 643 else 644 file=$( f_sysrc_get 'rc_conf_files%%[$IFS]*' ) 645 fi 646 fi 647 648 # 649 # If not found, append new value to first file and return. 650 # 651 if [ "$not_found" ]; then 652 # Add a newline if missing before appending to the file 653 [ ! -e "$file" ] || awk 'BEGIN { wc = 0 } NR == 1 { 654 (cmd = "wc -l " FILENAME) | getline 655 close(cmd) 656 wc = $1 657 } END { exit wc != NR }' "$file" || 658 echo >> "$file" || return $? 659 echo "$varname=\"$new_value\"" >> "$file" 660 return $? 661 fi 662 663 # 664 # Perform sanity checks. 665 # 666 if [ ! -w "$file" ]; then 667 f_err "$msg_cannot_create_permission_denied\n" \ 668 "$pgm" "$file" 669 return $FAILURE 670 fi 671 672 # 673 # Create a new temporary file to write to. 674 # 675 local tmpfile 676 if ! f_eval_catch -dk tmpfile $funcname mktemp 'mktemp -t "%s"' "$pgm" 677 then 678 echo "$tmpfile" >&2 679 return $FAILURE 680 fi 681 682 # 683 # Fixup permissions (else we're in for a surprise, as mktemp(1) creates 684 # the temporary file with 0600 permissions, and if we simply mv(1) the 685 # temporary file over the destination, the destination will inherit the 686 # permissions from the temporary file). 687 # 688 local mode 689 f_eval_catch -dk mode $funcname stat 'stat -f "%%#Lp" "%s"' "$file" || 690 mode=0644 691 f_eval_catch -d $funcname chmod 'chmod "%s" "%s"' "$mode" "$tmpfile" 692 693 # 694 # Fixup ownership. The destination file _is_ writable (we tested 695 # earlier above). However, this will fail if we don't have sufficient 696 # permissions (so we throw stderr into the bit-bucket). 697 # 698 local owner 699 f_eval_catch -dk owner $funcname stat \ 700 'stat -f "%%u:%%g" "%s"' "$file" || owner="root:wheel" 701 f_eval_catch -d $funcname chown 'chown "%s" "%s"' "$owner" "$tmpfile" 702 703 # 704 # Operate on the matching file, replacing only the last occurrence. 705 # 706 # Use awk to ensure LF at end of each line, else files without ending 707 # LF will trigger a bug in `tail -r' where last two lines are joined. 708 # 709 local new_contents retval 710 new_contents=$( awk 1 "$file" 2> /dev/null | tail -r ) 711 new_contents=$( echo "$new_contents" | awk -v varname="$varname" \ 712 -v new_value="$new_value" "$f_sysrc_set_awk" ) 713 retval=$? 714 715 # 716 # Write the temporary file contents. 717 # 718 echo "$new_contents" | tail -r > "$tmpfile" || return $FAILURE 719 if [ $retval -ne $SUCCESS ]; then 720 echo "$varname=\"$new_value\"" >> "$tmpfile" 721 fi 722 723 # 724 # Taint-check our results. 725 # 726 if ! f_eval_catch -d $funcname sh '/bin/sh -n "%s"' "$tmpfile"; then 727 f_err "$msg_previous_syntax_errors\n" "$pgm" "$file" 728 rm -f "$tmpfile" 729 return $FAILURE 730 fi 731 732 # 733 # Finally, move the temporary file into place. 734 # 735 f_eval_catch -de $funcname mv 'mv "%s" "%s"' "$tmpfile" "$file" 736} 737 738# f_sysrc_delete $varname 739# 740# Remove a setting from the system configuration files (edits files in-place). 741# Deletes all assignments to the given variable in all config files. If the 742# `-f file' option is passed, the removal is restricted to only those files 743# specified, otherwise the system collection of rc_conf_files is used. 744# 745# This function is a two-parter. Below is the awk(1) portion of the function, 746# afterward is the sh(1) function which utilizes the below awk script. 747# 748f_sysrc_delete_awk=' 749# Variables that should be defined on the invocation line: 750# -v varname="varname" 751# 752BEGIN { 753 regex = "^[[:space:]]*"varname"=" 754 found = 0 755} 756{ 757 if ( $0 ~ regex ) 758 found = 1 759 else 760 print 761} 762END { exit ! found } 763' 764f_sysrc_delete() 765{ 766 local funcname=f_sysrc_delete 767 local varname="$1" 768 local file 769 770 # Check arguments 771 [ "$varname" ] || return $FAILURE 772 773 # 774 # Operate on each of the specified files 775 # 776 local tmpfile 777 for file in ${RC_CONFS-$( f_sysrc_get rc_conf_files )}; do 778 [ -e "$file" ] || continue 779 780 # 781 # Create a new temporary file to write to. 782 # 783 if ! f_eval_catch -dk tmpfile $funcname mktemp \ 784 'mktemp -t "%s"' "$pgm" 785 then 786 echo "$tmpfile" >&2 787 return $FAILURE 788 fi 789 790 # 791 # Fixup permissions and ownership (mktemp(1) defaults to 0600 792 # permissions) to instead match the destination file. 793 # 794 local mode owner 795 f_eval_catch -dk mode $funcname stat \ 796 'stat -f "%%#Lp" "%s"' "$file" || mode=0644 797 f_eval_catch -dk owner $funcname stat \ 798 'stat -f "%%u:%%g" "%s"' "$file" || owner="root:wheel" 799 f_eval_catch -d $funcname chmod \ 800 'chmod "%s" "%s"' "$mode" "$tmpfile" 801 f_eval_catch -d $funcname chown \ 802 'chown "%s" "%s"' "$owner" "$tmpfile" 803 804 # 805 # Operate on the file, removing all occurrences, saving the 806 # output in our temporary file. 807 # 808 awk -v varname="$varname" "$f_sysrc_delete_awk" "$file" \ 809 > "$tmpfile" 810 if [ $? -ne $SUCCESS ]; then 811 # The file didn't contain any assignments 812 rm -f "$tmpfile" 813 continue 814 fi 815 816 # 817 # Taint-check our results. 818 # 819 if ! f_eval_catch -d $funcname sh '/bin/sh -n "%s"' "$tmpfile" 820 then 821 f_err "$msg_previous_syntax_errors\n" \ 822 "$pgm" "$file" 823 rm -f "$tmpfile" 824 return $FAILURE 825 fi 826 827 # 828 # Perform sanity checks 829 # 830 if [ ! -w "$file" ]; then 831 f_err "$msg_permission_denied\n" "$pgm" "$file" 832 rm -f "$tmpfile" 833 return $FAILURE 834 fi 835 836 # 837 # Finally, move the temporary file into place. 838 # 839 f_eval_catch -de $funcname mv \ 840 'mv "%s" "%s"' "$tmpfile" "$file" || return $FAILURE 841 done 842} 843 844############################################################ MAIN 845 846fi # ! $_SYSRC_SUBR 847