aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/bsdconfig/startup/share/rcconf.subr
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bsdconfig/startup/share/rcconf.subr')
-rw-r--r--usr.sbin/bsdconfig/startup/share/rcconf.subr499
1 files changed, 499 insertions, 0 deletions
diff --git a/usr.sbin/bsdconfig/startup/share/rcconf.subr b/usr.sbin/bsdconfig/startup/share/rcconf.subr
new file mode 100644
index 000000000000..71ca6f2fbf71
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/share/rcconf.subr
@@ -0,0 +1,499 @@
+if [ ! "$_STARTUP_RCCONF_SUBR" ]; then _STARTUP_RCCONF_SUBR=1
+#
+# Copyright (c) 2006-2013 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." startup/rcconf.subr
+f_include $BSDCFG_SHARE/sysrc.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig" APP_DIR="140.startup"
+f_include_lang $BSDCFG_LIBE/$APP_DIR/include/messages.subr
+
+############################################################ GLOBALS
+
+#
+# Initialize in-memory cache variables
+#
+STARTUP_RCCONF_MAP=
+_STARTUP_RCCONF_MAP=
+
+#
+# Define what a variable looks like
+#
+STARTUP_RCCONF_REGEX="^[[:alpha:]_][[:alnum:]_]*="
+
+#
+# Default path to on-disk cache file(s)
+#
+STARTUP_RCCONF_MAP_CACHEFILE="/var/run/bsdconfig/startup_rcconf_map.cache"
+
+############################################################ FUNCTIONS
+
+# f_startup_rcconf_list
+#
+# Produce a list of non-default configuration variables configured in the
+# rc.conf(5) collection of files.
+#
+f_startup_rcconf_list()
+{
+ ( # Operate within a sub-shell to protect the parent environment
+ . "$RC_DEFAULTS" > /dev/null
+ f_clean_env --except PATH STARTUP_RCCONF_REGEX rc_conf_files
+ source_rc_confs > /dev/null
+ export _rc_conf_files_file="$( f_sysrc_find rc_conf_files )"
+ export RC_DEFAULTS
+ set | awk -F= "
+ function test_print(var)
+ {
+ if ( var == \"OPTIND\" ) return
+ if ( var == \"PATH\" ) return
+ if ( var == \"RC_DEFAULTS\" ) return
+ if ( var == \"STARTUP_RCCONF_REGEX\" ) return
+ if ( var == \"_rc_conf_files_file\" ) return
+ if ( var == \"rc_conf_files\" )
+ {
+ if ( ENVIRON[\"_rc_conf_files_file\"] == \
+ ENVIRON[\"RC_DEFAULTS\"] ) return
+ }
+ print var
+ }
+ /$STARTUP_RCCONF_REGEX/ { test_print(\$1) }"
+ )
+}
+
+# f_startup_rcconf_map [$var_to_set]
+#
+# Produce a map (beit from in-memory cache or on-disk cache) of rc.conf(5)
+# variables and their descriptions. The map returned has the following format:
+#
+# var description
+#
+# With each as follows:
+#
+# var the rc.conf(5) variable
+# description description of the variable
+#
+# If $var_to_set is missing or NULL, the map is printed to standard output for
+# capturing in a sub-shell (which is less-recommended because of performance
+# degredation; for example, when called in a loop).
+#
+f_startup_rcconf_map()
+{
+ local __funcname=f_startup_rcconf_map
+ local __var_to_set="$1"
+
+ # If the in-memory cached value is available, return it immediately
+ if [ "$_STARTUP_RCCONF_MAP" ]; then
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$STARTUP_RCCONF_MAP"
+ else
+ echo "$STARTUP_RCCONF_MAP"
+ fi
+ return $SUCCESS
+ fi
+
+ #
+ # Create the in-memory cache (potentially from validated on-disk cache)
+ #
+
+ #
+ # Calculate digest used to determine if the on-disk global persistent
+ # cache file (containing this digest on the first line) is valid and
+ # can be used to quickly populate the cache value for immediate return.
+ #
+ local __rc_defaults_digest
+ __rc_defaults_digest=$( exec 2> /dev/null; md5 < "$RC_DEFAULTS" )
+
+ #
+ # Check to see if the global persistent cache file exists
+ #
+ if [ -f "$STARTUP_RCCONF_MAP_CACHEFILE" ]; then
+ #
+ # Attempt to populate the in-memory cache with the (soon to be)
+ # validated on-disk cache. If validation fails, fall-back to
+ # the current value and provide error exit status.
+ #
+ STARTUP_RCCONF_MAP=$(
+ ( # Get digest as the first word on first line
+ read digest rest_ignored
+
+ #
+ # If the stored digest matches the calculated-
+ # one populate the in-memory cache from the on-
+ # disk cache and provide success exit status.
+ #
+ if [ "$digest" = "$__rc_defaults_digest" ]
+ then
+ cat
+ exit $SUCCESS
+ else
+ # Otherwise, return the current value
+ echo "$STARTUP_RCCONF_MAP"
+ exit $FAILURE
+ fi
+ ) < "$STARTUP_RCCONF_MAP_CACHEFILE"
+ )
+ local __retval=$?
+ export STARTUP_RCCONF_MAP # Make children faster (export cache)
+ if [ $__retval -eq $SUCCESS ]; then
+ export _STARTUP_RCCONF_MAP=1
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$STARTUP_RCCONF_MAP"
+ else
+ echo "$STARTUP_RCCONF_MAP"
+ fi
+ return $SUCCESS
+ fi
+ # Otherwise, fall-thru to create in-memory cache from scratch
+ fi
+
+ #
+ # If we reach this point, we need to generate the data from scratch
+ # (and after we do, we'll attempt to create the global persistent
+ # cache file to speed up future executions).
+ #
+
+ STARTUP_RCCONF_MAP=$(
+ f_clean_env --except \
+ PATH \
+ RC_DEFAULTS \
+ STARTUP_RCCONF_REGEX \
+ f_sysrc_desc_awk
+ . "$RC_DEFAULTS"
+
+ # Unset variables we don't want reported
+ unset source_rc_confs_defined
+
+ for var in $( set | awk -F= "
+ function test_print(var)
+ {
+ if ( var == \"OPTIND\" ) return
+ if ( var == \"PATH\" ) return
+ if ( var == \"RC_DEFAULTS\" ) return
+ if ( var == \"STARTUP_RCCONF_REGEX\" ) return
+ if ( var == \"f_sysrc_desc_awk\" ) return
+ print var
+ }
+ /$STARTUP_RCCONF_REGEX/ { test_print(\$1) }
+ " ); do
+ echo $var "$( f_sysrc_desc $var )"
+ done
+ )
+ export STARTUP_RCCONF_MAP
+ export _STARTUP_RCCONF_MAP=1
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$STARTUP_RCCONF_MAP"
+ else
+ echo "$STARTUP_RCCONF_MAP"
+ fi
+
+ #
+ # Attempt to create the persistent global cache
+ #
+
+ # Create a new temporary file to write to
+ local __tmpfile
+ f_eval_catch -dk __tmpfile $__funcname mktemp \
+ 'mktemp -t "%s"' "$pgm" || return $FAILURE
+
+ # Write the temporary file contents
+ echo "$__rc_defaults_digest" > "$__tmpfile"
+ echo "$STARTUP_RCCONF_MAP" >> "$__tmpfile"
+
+ # Finally, move the temporary file into place
+ case "$STARTUP_RCCONF_MAP_CACHEFILE" in
+ */*) f_eval_catch -d $__funcname mkdir \
+ 'mkdir -p "%s"' "${STARTUP_RCCONF_MAP_CACHEFILE%/*}"
+ esac
+ f_eval_catch -d $__funcname mv \
+ 'mv "%s" "%s"' "$__tmpfile" "$STARTUP_RCCONF_MAP_CACHEFILE"
+}
+
+# f_startup_rcconf_map_expand $var_to_get
+#
+# Expands the map ($var_to_get) into the shell environment namespace by
+# creating _${var}_desc variables containing the description of each variable
+# encountered.
+#
+# NOTE: Variables are exported for later-required awk(1) ENVIRON visibility.
+#
+f_startup_rcconf_map_expand()
+{
+ local var_to_get="$1"
+ eval "$( debug= f_getvar "$var_to_get" | awk '
+ BEGIN {
+ rword = "^[[:space:]]*[^[:space:]]*[[:space:]]*"
+ }
+ {
+ var = $1
+ desc = $0
+ sub(rword, "", desc)
+ gsub(/'\''/, "'\''\\'\'\''", desc)
+ printf "_%s_desc='\''%s'\''\n", var, desc
+ printf "export _%s_desc\n", var
+ }' )"
+}
+
+# f_dialog_input_view_details
+#
+# Display a menu for selecting which details are to be displayed. The following
+# variables are tracked/modified by the menu/user's selection:
+#
+# SHOW_DESC Show or hide descriptions
+#
+# Mutually exclusive options:
+#
+# SHOW_VALUE Show the value (default; override only)
+# SHOW_DEFAULT_VALUE Show both value and default
+# SHOW_CONFIGURED Show rc.conf(5) file variable is configured in
+#
+# Each variable is treated as a boolean (NULL for false, non-NULL for true).
+#
+# Variables are exported for later-required awk(1) ENVIRON visibility. Returns
+# success unless the user chose `Cancel' or pressed Escape.
+#
+f_dialog_input_view_details()
+{
+ local prompt=
+ local menu_list # calculated below
+ local defaultitem= # calculated below
+ local hline="$hline_arrows_tab_enter"
+
+ # Calculate marks for checkboxes and radio buttons
+ local md=" "
+ if [ "$SHOW_DESC" ]; then
+ md="X"
+ fi
+ local m1=" " m2=" " m3=" "
+ if [ "$SHOW_VALUE" ]; then
+ m1="*"
+ defaultitem="1 ($m1) $msg_show_value"
+ elif [ "$SHOW_DEFAULT_VALUE" ]; then
+ m2="*"
+ defaultitem="2 ($m2) $msg_show_default_value"
+ elif [ "$SHOW_CONFIGURED" ]; then
+ m3="*"
+ defaultitem="3 ($m3) $msg_show_configured"
+ fi
+
+ # Create the menu list with the above-calculated marks
+ menu_list="
+ 'R $msg_reset' '$msg_reset_desc'
+ 'D [$md] $msg_desc' '$msg_desc_desc'
+ '1 ($m1) $msg_show_value' '$msg_show_value_desc'
+ '2 ($m2) $msg_show_default_value' '$msg_show_default_value_desc'
+ '3 ($m3) $msg_show_configured' '$msg_show_configured_desc'
+ " # END-QUOTE
+
+ local height width rows
+ eval f_dialog_menu_size height width rows \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list
+
+ f_dialog_title "$msg_choose_view_details"
+
+ local mtag
+ mtag=$( eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --default-item \"\$defaultitem\" \
+ --menu \"\$prompt\" \
+ $height $width $rows \
+ $menu_list \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+ )
+ local retval=$?
+ f_dialog_data_sanitize mtag
+
+ f_dialog_title_restore
+
+ [ $retval -eq $DIALOG_OK ] || return $DIALOG_CANCEL
+
+ case "$mtag" in
+ "R $msg_reset")
+ SHOW_VALUE=1
+ SHOW_DESC=1
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=
+ ;;
+ "D [X] $msg_desc") SHOW_DESC= ;;
+ "D [ ] $msg_desc") SHOW_DESC=1 ;;
+ "1 ("?") $msg_show_value")
+ SHOW_VALUE=1
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=
+ ;;
+ "2 ("?") $msg_show_default_value")
+ SHOW_VALUE=
+ SHOW_DEFAULT_VALUE=1
+ SHOW_CONFIGURED=
+ ;;
+ "3 ("?") $msg_show_configured")
+ SHOW_VALUE=
+ SHOW_DEFAULT_VALUE=
+ SHOW_CONFIGURED=1
+ ;;
+ esac
+}
+
+# f_dialog_input_rclist [$default]
+#
+# Presents a menu of rc.conf(5) defaults (with, or without descriptions). This
+# function should be treated like a call to dialog(1) (the exit status should
+# be captured and f_dialog_menutag_fetch() should be used to get the user's
+# response). Optionally if present and non-null, highlight $default rcvar.
+#
+f_dialog_input_rclist()
+{
+ local prompt="$msg_please_select_an_rcconf_directive"
+ local menu_list="
+ 'X $msg_exit' '' ${SHOW_DESC:+'$msg_exit_this_menu'}
+ " # END-QUOTE
+ local defaultitem="$1"
+ local hline="$hline_arrows_tab_enter"
+
+ if [ ! "$_RCCONF_MAP" ]; then
+ # Generate RCCONF_MAP of `var desc ...' per-line
+ f_dialog_info "$msg_creating_rcconf_map"
+ RCCONF_MAP=$( f_startup_rcconf_map )
+ export RCCONF_MAP
+ # Generate _${var}_desc variables from $RCCONF_MAP
+ f_startup_rcconf_map_expand
+ export _RCCONF_MAP=1
+ fi
+
+ menu_list="$menu_list $(
+ export SHOW_DESC
+ echo "$RCCONF_MAP" | awk '
+ BEGIN {
+ prefix = ""
+ rword = "^[[:space:]]*[^[:space:]]*[[:space:]]*"
+ }
+ {
+ cur_prefix = tolower(substr($1, 1, 1))
+ printf "'\''"
+ if ( prefix != cur_prefix )
+ prefix = cur_prefix
+ else
+ printf " "
+ rcvar = $1
+ printf "%s'\'' '\'\''", rcvar
+ if ( ENVIRON["SHOW_DESC"] ) {
+ desc = $0
+ sub(rword, "", desc)
+ gsub(/'\''/, "'\''\\'\'\''", desc)
+ printf " '\''%s'\''", desc
+ }
+ printf "\n"
+ }'
+ )"
+
+ set -f # set noglob because descriptions in the $menu_list may contain
+ # `*' and get expanded by dialog(1) (doesn't affect Xdialog(1)).
+ # This prevents dialog(1) from expanding wildcards in help line.
+
+ local height width rows
+ eval f_dialog_menu${SHOW_DESC:+_with_help}_size \
+ height width rows \
+ \"\$DIALOG_TITLE\" \
+ \"\$DIALOG_BACKTITLE\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list
+
+ local menu_choice
+ menu_choice=$( eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --default-item \"\$defaultitem\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ ${SHOW_DESC:+--item-help} \
+ --menu \"\$prompt\" \
+ $height $width $rows \
+ $menu_list \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+ )
+ local retval=$?
+ f_dialog_menutag_store -s "$menu_choice"
+ return $retval
+}
+
+# f_dialog_input_rcvar [$init]
+#
+# Allows the user to enter the name for a new rc.conf(5) variable. If the user
+# does not cancel or press ESC, the $rcvar variable will hold the newly-
+# configured value upon return.
+#
+f_dialog_input_rcvar()
+{
+ #
+ # Loop until the user provides taint-free/valid input
+ #
+ local _input="$1"
+ while :; do
+
+ # Return if user either pressed ESC or chosen Cancel/No
+ f_dialog_input _input "$msg_please_enter_rcvar_name" \
+ "$_input" "$hline_alnum_tab_enter" || return $?
+
+ # Check for invalid entry (1of2)
+ if ! echo "$_input" | grep -q "^[[:alpha:]_]"; then
+ f_show_msg "$msg_rcvar_must_start_with"
+ continue
+ fi
+
+ # Check for invalid entry (2of2)
+ if ! echo "$_input" | grep -q "^[[:alpha:]_][[:alnum:]_]*$"
+ then
+ f_show_msg "$msg_rcvar_contains_invalid_chars"
+ continue
+ fi
+
+ rcvar="$_input"
+ break
+ done
+
+ f_dprintf "f_dialog_input_rcvar: rcvar->[%s]" "$rcvar"
+
+ return $DIALOG_OK
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." startup/rcconf.subr
+
+fi # ! $_STARTUP_RCCONF_SUBR