summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsdconfig/share
diff options
context:
space:
mode:
authordteske <dteske@FreeBSD.org>2012-09-18 22:28:42 +0000
committerdteske <dteske@FreeBSD.org>2012-09-18 22:28:42 +0000
commit282d6b7f2c0f1fb51d911f75ef9989f62e389985 (patch)
tree3ef909c692976c6a6b0854f8d722182e78ff8915 /usr.sbin/bsdconfig/share
parent969b25f00f504248a5c234274661472d753475ad (diff)
downloadFreeBSD-src-282d6b7f2c0f1fb51d911f75ef9989f62e389985.zip
FreeBSD-src-282d6b7f2c0f1fb51d911f75ef9989f62e389985.tar.gz
Move major includes into /usr/share/bsdconfig for easy external access.
Reviewed by: adrian (co-mentor) Approved by: adrian (co-mentor)
Diffstat (limited to 'usr.sbin/bsdconfig/share')
-rw-r--r--usr.sbin/bsdconfig/share/Makefile11
-rw-r--r--usr.sbin/bsdconfig/share/common.subr299
-rw-r--r--usr.sbin/bsdconfig/share/dialog.subr1443
-rw-r--r--usr.sbin/bsdconfig/share/mustberoot.subr362
-rw-r--r--usr.sbin/bsdconfig/share/strings.subr104
-rw-r--r--usr.sbin/bsdconfig/share/sysrc.subr618
6 files changed, 2837 insertions, 0 deletions
diff --git a/usr.sbin/bsdconfig/share/Makefile b/usr.sbin/bsdconfig/share/Makefile
new file mode 100644
index 0000000..7f299ec
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${SHAREDIR}/bsdconfig
+FILES= common.subr dialog.subr mustberoot.subr strings.subr sysrc.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/share/common.subr b/usr.sbin/bsdconfig/share/common.subr
new file mode 100644
index 0000000..c724c62
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/common.subr
@@ -0,0 +1,299 @@
+if [ ! "$_COMMON_SUBR" ]; then _COMMON_SUBR=1
+#
+# Copyright (c) 2012 Ron McDowell
+# Copyright (c) 2012 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.
+#
+# $FreeBSD$
+#
+############################################################ GLOBALS
+
+#
+# Program name
+#
+pgm="${0##*/}"
+
+#
+# Program arguments
+#
+ARGC="$#"
+ARGV="$@"
+
+#
+# Global exit status variables
+#
+SUCCESS=0
+FAILURE=1
+
+############################################################ FUNCTIONS
+
+#
+# This is an empty function by default, to use it, copy
+# /usr/share/examples/bsdconfig/bsdconfigrc to $HOME/.bsdconfigrc
+#
+f_dprintf()
+{
+ : this page intentionally left blank
+}
+
+# f_err $fmt [ $opts ... ]
+#
+# Print a message to stderr (fd=2).
+#
+f_err()
+{
+ printf "$@" >&2
+}
+
+# f_quietly $command [ $arguments ... ]
+#
+# run a command quietly (quell any output to stdout or stderr)
+#
+f_quietly()
+{
+ "$@" > /dev/null 2>&1
+}
+
+# f_have $anything ...
+#
+# A wrapper to the `type' built-in. Returns true if argument is a valid shell
+# built-in, keyword, or externally-tracked binary, otherwise false.
+#
+f_have()
+{
+ f_quietly type "$@"
+}
+
+# f_die [ $status [ $fmt [ $opts ... ]]]
+#
+# Abruptly terminate due to an error optionally displaying a message in a
+# dialog box using printf(1) syntax.
+#
+f_die()
+{
+ local status=$FAILURE
+
+ # If there is at least one argument, take it as the status
+ if [ $# -gt 0 ]; then
+ status=$1
+ shift 1 # status
+ fi
+
+ # If there are still arguments left, pass them to f_show_msg
+ [ $# -gt 0 ] && f_show_msg "$@"
+
+ # Optionally call f_clean_up() function if it exists
+ f_have f_clean_up && f_clean_up
+
+ exit $status
+}
+
+# f_interrupt
+#
+# Interrupt handler.
+#
+f_interrupt()
+{
+ exec 2>&1 # fix sh(1) bug where stderr gets lost within async-trap
+ f_die
+}
+
+# f_show_msg $fmt [ $opts ... ]
+#
+# Display a message in a dialog box using printf(1) syntax.
+#
+f_show_msg()
+{
+ local msg
+ msg=$( printf "$@" )
+
+ #
+ # Use f_dialog_msgbox from dialog.subr if possible, otherwise fall
+ # back to dialog(1) (without options, making it obvious when using
+ # un-aided system dialog).
+ #
+ if f_have f_dialog_msgbox; then
+ f_dialog_msgbox "$msg"
+ else
+ dialog --msgbox "$msg" 0 0
+ fi
+}
+
+# f_include $file
+#
+# Include a shell subroutine file.
+#
+# If the subroutine file exists but returns error status during loading, exit
+# is called and execution is prematurely terminated with the same error status.
+#
+f_include()
+{
+ local file="$1"
+ . "$file" || exit $?
+}
+
+# f_include_lang $file
+#
+# Include a language file. Automatically takes $LANG and $LC_ALL into
+# considerationg when including $file (suffix ".$LC_ALL" or ".$LANG" will
+# automatically by added prior to loading the language file).
+#
+# No error is produced if (a) a language has been requested (by setting either
+# $LANG or $LC_ALL in the environment) and (b) the language file does not
+# exist -- in which case we will fall back to loading $file without-suffix.
+#
+# If the language file exists but returns error status during loading, exit
+# is called and execution is prematurely terminated with the same error status.
+#
+f_include_lang()
+{
+ local file="$1"
+ local lang="${LANG:-$LC_ALL}"
+
+ f_dprintf "lang=[$lang]"
+ if [ -f "$file.$lang" ]; then
+ . "$file.$lang" || exit $?
+ else
+ . "$file" || exit $?
+ fi
+}
+
+# f_usage $file [ $key1 $value1 ... ]
+#
+# Display USAGE file with optional pre-processor macro definitions. The first
+# argument is the template file containing the usage text to be displayed. If
+# $LANG or $LC_ALL (in order of preference, respectively) is set, ".encoding"
+# will automatically be appended as a suffix to the provided $file pathname.
+#
+# When processing $file, output begins at the first line containing that is
+# (a) not a comment, (b) not empty, and (c) is not pure-whitespace. All lines
+# appearing after this first-line are output, including (a) comments (b) empty
+# lines, and (c) lines that are purely whitespace-only.
+#
+# If additional arguments appear after $file, substitutions are made while
+# printing the contents of the USAGE file. The pre-processor macro syntax is in
+# the style of autoconf(1), for example:
+#
+# f_usage $file "FOO" "BAR"
+#
+# Will cause instances of "@FOO@" appearing in $file to be replaced with the
+# text "BAR" before bering printed to the screen.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_usage_awk='
+BEGIN { found = 0 }
+{
+ if ( !found && $0 ~ /^[[:space:]]*($|#)/ ) next
+ found = 1
+ print
+}
+'
+f_usage()
+{
+ local file="$1"
+ local lang="${LANG:-$LC_ALL}"
+
+ f_dprintf "lang=[$lang]"
+
+ shift 1 # file
+
+ local usage
+ if [ -f "$file.$lang" ]; then
+ usage=$( awk "$f_usage_awk" "$file.$lang" ) || exit $FAILURE
+ else
+ usage=$( awk "$f_usage_awk" "$file" ) || exit $FAILURE
+ fi
+
+ while [ $# -gt 0 ]; do
+ local key="$1"
+ export value="$2"
+ usage=$( echo "$usage" | awk \
+ "{ gsub(/@$key@/, ENVIRON[\"value\"]); print }" )
+ shift 2
+ done
+
+ f_err "%s\n" "$usage"
+
+ exit $FAILURE
+}
+
+# f_index_menu_selection $file $pgm
+#
+# Process $file looking for $menu_selection values that correspond to $pgm.
+# This function is for internationalization (i18n) mapping of the on-disk
+# scriptname ($pgm) into the localized language (given language-specific
+# $file). If $LANG or $LC_ALL (in orderder of preference, respectively) is set,
+# ".encoding" will automatically be appended as a suffix to the provided $file
+# pathname.
+#
+# If, within $file, multiple $menu_selection values map to $pgm, only the first
+# one will be returned. If no mapping can be made, the NULL string is returned.
+#
+# If $file does not exist, error status is returned along with the NULL string.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_index_menusel_awk='
+# Variables that should be defined on the invocation line:
+# -v pgm="program_name"
+#
+( $0 ~ "^menu_selection=.*\\|" pgm "\"" ) {
+ sub(/\|.*/, "")
+ sub(/^menu_selection="/, "")
+ print
+ exit
+}
+'
+f_index_menu_selection()
+{
+ local file="$1" pgm="$2"
+ local lang="${LANG:-$LC_ALL}"
+
+ f_dprintf "lang=[$lang]"
+
+ if [ -f "$file.$lang" ]; then
+ awk -v pgm="$pgm" "$f_index_menusel_awk" "$file.$lang" ||
+ exit $FAILURE
+ elif [ -f "$file" ]; then
+ awk -v pgm="$pgm" "$f_index_menusel_awk" "$file" ||
+ exit $FAILURE
+ else
+ return $FAILURE
+ fi
+}
+
+############################################################ MAIN
+
+#
+# Trap signals so we can recover gracefully
+#
+trap 'f_interrupt' SIGINT
+trap 'f_die' SIGTERM SIGPIPE SIGXCPU SIGXFSZ \
+ SIGFPE SIGTRAP SIGABRT SIGSEGV
+trap '' SIGALRM SIGPROF SIGUSR1 SIGUSR2 SIGHUP SIGVTALRM
+
+fi # ! $_COMMON_SUBR
diff --git a/usr.sbin/bsdconfig/share/dialog.subr b/usr.sbin/bsdconfig/share/dialog.subr
new file mode 100644
index 0000000..cced388
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/dialog.subr
@@ -0,0 +1,1443 @@
+if [ ! "$_DIALOG_SUBR" ]; then _DIALOG_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_include $BSDCFG_SHARE/strings.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# Default directory to store dialog(1) temporary files
+#
+: ${DIALOG_TMPDIR:="/tmp"}
+
+############################################################ GLOBALS
+
+#
+# Default name of dialog(1) utility
+# NOTE: This is changed to "Xdialog" by the optional `-X' argument
+#
+DIALOG="dialog"
+
+#
+# Default dialog(1) title and backtitle text
+#
+DIALOG_TITLE="$pgm"
+DIALOG_BACKTITLE="bsdconfig"
+
+#
+# Settings used while interacting with dialog(1)
+#
+DIALOG_MENU_TAGS="123456789ABCDEFGHIJKLMNOPQRSTUVWYZabcdefghijklmnopqrstuvwxyz"
+
+#
+# Declare that we are fully-compliant with Xdialog(1) by unset'ing all
+# compatibility settings.
+#
+unset XDIALOG_HIGH_DIALOG_COMPAT
+unset XDIALOG_FORCE_AUTOSIZE
+unset XDIALOG_INFOBOX_TIMEOUT
+
+#
+# Default behavior is to call f_dialog_init() automatically if not already
+# called manually by the time the first f_dialog_*() function is used.
+#
+: ${DIALOG_SELF_INITIALIZE=1}
+
+############################################################ GENERIC FUNCTIONS
+
+# f_dialog_title [$new_title]
+#
+# Set the title of future dialog(1) ($DIALOG_TITLE) or backtitle of Xdialog(1)
+# ($DIALOG_BACKTITLE) invocations. If no arguments are given or the first
+# argument is NULL, the current title is returned.
+#
+# Each time this function is called, a backup of the current values is made
+# allowing a one-time (single-level) restoration of the previous title using the
+# f_dialog_title_restore() function (below).
+#
+f_dialog_title()
+{
+ local new_title="$1"
+
+ if [ "$new_title" ]; then
+ if [ "$USE_XDIALOG" ]; then
+ _DIALOG_BACKTITLE="$DIALOG_BACKTITLE"
+ DIALOG_BACKTITLE="$new_title"
+ else
+ _DIALOG_TITLE="$DIALOG_TITLE"
+ DIALOG_TITLE="$new_title"
+ fi
+ else
+ if [ "$USE_XDIALOG" ]; then
+ echo "$DIALOG_BACKTITLE"
+ else
+ echo "$DIALOG_TITLE"
+ fi
+ fi
+}
+
+# f_dialog_title_restore
+#
+# Restore the previous title set by the last call to f_dialog_title().
+# Restoration is non-recursive and only works to restore the most-recent title.
+#
+f_dialog_title_restore()
+{
+ if [ "$USE_XDIALOG" ]; then
+ DIALOG_BACKTITLE="$_DIALOG_BACKTITLE"
+ else
+ DIALOG_TITLE="$_DIALOG_TITLE"
+ fi
+}
+
+# f_dialog_backtitle [$new_backtitle]
+#
+# Set the backtitle of future dialog(1) ($DIALOG_BACKTITLE) or title of
+# Xdialog(1) ($DIALOG_TITLE) invocations. If no arguments are given or the
+# first argument is NULL, the current backtitle is returned.
+#
+f_dialog_backtitle()
+{
+ local new_backtitle="$1"
+
+ if [ "$new_backtitle" ]; then
+ if [ "$USE_XDIALOG" ]; then
+ _DIALOG_TITLE="$DIALOG_TITLE"
+ DIALOG_TITLE="$new_backtitle"
+ else
+ _DIALOG_BACKTITLE="$DIALOG_BACKTITLE"
+ DIALOG_BACKTITLE="$new_backtitle"
+ fi
+ else
+ if [ "$USE_XDIALOG" ]; then
+ echo "$DIALOG_TITLE"
+ else
+ echo "$DIALOG_BACKTITLE"
+ fi
+ fi
+}
+
+# f_dialog_backtitle_restore
+#
+# Restore the previous backtitle set by the last call to f_dialog_backtitle().
+# Restoration is non-recursive and only works to restore the most-recent
+# backtitle.
+#
+f_dialog_backtitle_restore()
+{
+ if [ "$USE_XDIALOG" ]; then
+ DIALOG_TITLE="$_DIALOG_TITLE"
+ else
+ DIALOG_BACKTITLE="$_DIALOG_BACKTITLE"
+ fi
+}
+
+############################################################ SIZE FUNCTIONS
+
+# f_dialog_infobox_size $title $backtitle $prompt [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--infobox' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, and [optionally] hline returning
+# the optimal width and height for the box (not exceeding the actual terminal
+# width or height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_infobox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
+ local min_width max_size
+
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ max_size=$( stty size ) # usually "24 80"
+ fi
+
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+ local height width=$min_width
+
+ #
+ # Bump width for long titles (but don't exceed terminal width).
+ #
+ n=$(( ${#title} + 4 ))
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ # Add 16.6% width for Xdialog(1)
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 ))
+
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+
+ #
+ # For Xdialog(1), bump width for long backtitles (which appear within
+ # the window; don't exceed maximum width).
+ #
+ if [ "$USE_XDIALOG" ]; then
+ n=$(( ${#btitle} + 4 ))
+ n=$(( $n + $n / 6 ))
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ #
+ # Bump width for long prompts (if not already at maximum width).
+ #
+ if [ $width -lt $max_width ]; then
+ n=$( echo "$prompt" | f_longest_line_length )
+ n=$(( $n + 4 ))
+
+ # Add 16.6% width for Xdialog(1)
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ #
+ # Bump width for long hlines (if not already at maximum width).
+ # NOTE: Though Xdialog(1) supports `--hline', it's not currently used.
+ #
+ if [ ! "$USE_XDIALOG" ]; then
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#hline} + 10 ))
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+ fi
+
+ #
+ # Set height based on number of rows in prompt
+ #
+ height=$( echo "$prompt" | f_number_of_lines )
+ height=$(( $height + 2 ))
+
+ #
+ # For Xdialog(1) bump height if backtitle is enabled (displayed in the
+ # X11 window with a separator line between the backtitle and msg text)
+ #
+ if [ "$USE_XDIALOG" -a "$btitle" ]; then
+ n=$( echo "$btitle" | f_number_of_lines )
+ height=$(( $height + $n + 2 ))
+ fi
+
+ # Make sure height is less than maximum screen size
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_dialog_buttonbox_size $title $backtitle $prompt [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--msgbox' and `--yesno' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, and [optionally] hline returning
+# the optimal width and height for the box (not exceeding the actual terminal
+# width or height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_buttonbox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4"
+ local size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ # Add height to accomodate the buttons
+ height=$(( $height + 2 ))
+
+ # Adjust for clipping with Xdialog(1) on Linux/GTK2
+ [ "$USE_XDIALOG" ] && height=$(( $height + 3 ))
+
+ #
+ # Enforce maximum height regardless
+ #
+ local max_size
+ if [ "$USE_XDIALOG" ]; then
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ max_size=$( stty size ) # usually "24 80"
+ fi
+ local max_height="${max_size%%[$IFS]*}"
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_dialog_inputbox_size $title $backtitle $prompt $init [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--inputbox' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, initial text, and [optionally]
+# hline returning the optimal width and height for the box (not exceeding the
+# actual terminal width and height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_inputbox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" init="$4" hline="$5" n
+ local size="$( f_dialog_buttonbox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ local min_width max_size
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ max_size=$( stty size ) # usually "24 80"
+ fi
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+
+ #
+ # Add height to accomodate the input box
+ #
+ [ ! "$USE_XDIALOG" ] && height=$(( $height + 3 ))
+ [ $height -le $max_height ] || height=$max_height
+
+ #
+ # Bump width for initial text (if not already at maximum width).
+ # NOTE: Something neither dialog(1)/Xdialog(1) do, but worth it!
+ #
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#init} + 7 ))
+
+ # Add 16.6% width for Xdialog(1)
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_xdialog_2inputsbox_size $title $backtitle $prompt \
+# $label1 $init1 $label2 $init2
+#
+# Xdialog(1) does not perform auto-sizing of the width and height of
+# `--2inputsbox' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, label for the first field, initial
+# text for said field, label for the second field, and initial text for said
+# field returning the optimal width and height for the box (not exceeding the
+# actual terminal width and height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# Xdialog(1).
+#
+# Output is in the format of "height width".
+#
+f_xdialog_2inputsbox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3"
+ local label1="$4" init1="$5" label2="$6" init2="$7" n
+ local size="$( f_dialog_inputbox_size \
+ "$title" "$btitle" "$prompt" "$init1" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ local min_width=35
+ local max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+
+ # Add height for first label
+ height=$(( $height + 2 ))
+
+ #
+ # Bump width for first label text (if not already at maximum width).
+ #
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#label1} + 7 ))
+
+ # Add 16.6% width for Xdialog(1)
+ n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Add height for second label
+ height=$(( $height + 2 ))
+
+ #
+ # Bump width for second label text (if not already at maximum width).
+ #
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#label2} + 7 ))
+
+ # Add 16.6% width for Xdialog(1)
+ n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Add height for a second inputbox
+ height=$(( $height + 2 ))
+
+ #
+ # Bump width for second initial text (if not already at maximum width).
+ # NOTE: Something neither dialog(1)/Xdialog(1) do, but worth it!
+ #
+ if [ $width -lt $max_width ]; then
+ n=$(( ${#init2} + 7 ))
+
+ # Add 16.6% width for Xdialog(1)
+ n=$(( $n + $n / 6 ))
+
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_dialog_menu_size $title $backtitle $prompt $hline \
+# $tag1 $item1 $tag2 $item2 ...
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--menu' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, hline and list of tag/item pairs,
+# returning the optimal width and height for the menu (not exceeding the actual
+# terminal width or height).
+#
+# Output is in the format of "height width rows".
+#
+f_dialog_menu_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
+ local min_width min_rows max_size
+
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ min_rows=1
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ min_rows=0
+ max_size=$( stty size ) # usually "24 80"
+ fi
+
+ local max_width="${max_size##*[$IFS]}"
+ local max_height="${max_size%%[$IFS]*}"
+ local box_size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local box_height="${box_size%%[$IFS]*}"
+ local box_width="${box_size##*[$IFS]}"
+ local max_rows=$(( $max_height - 8 ))
+ local height width=$box_width rows=$min_rows
+
+ shift 4 # title/btitle/prompt/hline
+
+ # If there's no prompt, bump the max-rows by 1
+ [ "$prompt" ] || max_rows=$(( $max_rows + 1 ))
+
+ #
+ # The sum total between the longest tag-length and longest item-length
+ # should be used for the menu width (not to exceed terminal width).
+ #
+ # Also, calculate the number of rows (not to exceed terminal height).
+ #
+ local longest_tag=0 longest_item=0
+ while [ $# -ge 2 ]; do
+ local tag="$1" item="$2"
+ shift 2 # tag/item
+
+ [ ${#tag} -gt $longest_tag ] && longest_tag=${#tag}
+ [ ${#item} -gt $longest_item ] && longest_item=${#item}
+ [ $rows -lt $max_rows ] && rows=$(( $rows + 1 ))
+ done
+
+ # Update width
+ n=$(( $longest_tag + $longest_item + 10 ))
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1)
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+
+ # Fix rows and set height
+ [ $rows -gt 0 ] || rows=1
+ if [ "$USE_XDIALOG" ]; then
+ height=$(( $rows + $box_height + 7 ))
+ else
+ height=$(( $rows + $box_height + 4 ))
+ fi
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return all three
+ echo "$height $width $rows"
+}
+
+# f_dialog_menu_with_help_size $title $backtitle $prompt $hline \
+# $tag1 $item1 $help1 $tag2 $item2 $help2 ...
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--menu' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, hline and list of tag/item/help
+# triplets, returning the optimal width and height for the menu (not exceeding
+# the actual terminal width or height).
+#
+# Output is in the format of "height width rows".
+#
+f_dialog_menu_with_help_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
+ local min_width min_rows max_size
+
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ min_rows=1
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ min_rows=0
+ max_size=$( stty size ) # usually "24 80"
+ fi
+
+ local max_width="${max_size##*[$IFS]}"
+ local max_height="${max_size%%[$IFS]*}"
+ local box_size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local box_height="${box_size%%[$IFS]*}"
+ local box_width="${box_size##*[$IFS]}"
+ local max_rows=$(( $max_height - 8 ))
+ local height width=$box_width rows=$min_rows
+
+ shift 4 # title/btitle/prompt/hline
+
+ # If there's no prompt, bump the max-rows by 1
+ [ "$prompt" ] || max_rows=$(( $max_rows + 1 ))
+
+ #
+ # The sum total between the longest tag-length and longest item-length
+ # should be used for the menu width (not to exceed terminal width).
+ #
+ # Also, calculate the number of rows (not to exceed terminal height).
+ #
+ # Also, calculate the longest help while we're here. This will be used
+ # to influence the width of the menu if (and only-if) using Xdialog(1).
+ #
+ local longest_tag=0 longest_item=0 longest_help=0
+ while [ $# -ge 3 ]; do
+ local tag="$1" item="$2" help="$3"
+ shift 3 # tag/item/help
+
+ [ ${#tag} -gt $longest_tag ] && longest_tag=${#tag}
+ [ ${#item} -gt $longest_item ] && longest_item=${#item}
+ [ ${#help} -gt $longest_help ] && longest_help=${#help}
+ [ $rows -lt $max_rows ] && rows=$(( $rows + 1 ))
+ done
+
+ # Update width
+ n=$(( $longest_tag + $longest_item + 10 ))
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1)
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+
+ # Update width for help text if using Xdialog(1)
+ if [ "$USE_XDIALOG" ]; then
+ n=$(( $longest_help + 10 ))
+ n=$(( $n + $n / 6 )) # +16.6%
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+ fi
+
+ # Fix rows and set height
+ [ $rows -gt 0 ] || rows=1
+ if [ "$USE_XDIALOG" ]; then
+ height=$(( $rows + $box_height + 8 ))
+ else
+ height=$(( $rows + $box_height + 4 ))
+ fi
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return all three
+ echo "$height $width $rows"
+}
+
+# f_dialog_radiolist_size $title $backtitle $prompt $hline \
+# $tag1 $item1 $status1 $tag2 $item2 $status2 ...
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--radiolist' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, hline and list of tag/item/status
+# triplets, returning the optimal width and height for the radiolist (not
+# exceeding the actual terminal width or height).
+#
+# Output is in the format of "height width rows".
+#
+f_dialog_radiolist_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n=0
+ local min_width min_rows max_size
+
+ if [ "$USE_XDIALOG" ]; then
+ min_width=35
+ min_rows=1
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_width=24
+ min_rows=0
+ max_size=$( stty size ) # usually "24 80"
+ fi
+
+ local max_width="${max_size##*[$IFS]}"
+ local max_height="${max_size%%[$IFS]*}"
+ local box_size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local box_height="${box_size%%[$IFS]*}"
+ local box_width="${box_size##*[$IFS]}"
+ local max_rows=$(( $max_height - 8 ))
+ local height width=$box_width rows=$min_rows
+
+ shift 4 # title/btitle/prompt/hline
+
+ #
+ # The sum total between the longest tag-length, longest item-length,
+ # and radio-button width should be used for the menu width (not to
+ # exceed terminal width).
+ #
+ # Also, calculate the number of rows (not to exceed terminal height).
+ #
+ local longest_tag=0 longest_item=0
+ while [ $# -ge 2 ]; do
+ local tag="$1" item="$2" help="$3"
+ shift 3 # tag/item/status
+
+ [ ${#tag} -gt $longest_tag ] && longest_tag=${#tag}
+ [ ${#item} -gt $longest_item ] && longest_item=${#item}
+ [ $rows -lt $max_rows ] && rows=$(( $rows + 1 ))
+ done
+
+ # Update width
+ n=$(( $longest_tag + $longest_item + 13 ))
+ [ "$USE_XDIALOG" ] && n=$(( $n + $n / 6 )) # Add 16.6% for Xdialog(1)
+ if [ $n -gt $width -a $n -gt $min_width ]; then
+ if [ $n -lt $max_width ]; then
+ width=$n
+ else
+ width=$max_width
+ fi
+ fi
+
+ # Fix rows and set height
+ [ $rows -gt 0 ] || rows=1
+ if [ "$USE_XDIALOG" ]; then
+ height=$(( $rows + $box_height + 7 ))
+ else
+ height=$(( $rows + $box_height + 4 ))
+ fi
+ [ $height -le $max_height ] || height=$max_height
+
+ # Return all three
+ echo "$height $width $rows"
+}
+
+# f_dialog_calendar_size $title $backtitle $prompt [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--calendar' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, and [optionally] hline returning
+# the optimal width and height for the box (not exceeding the actual terminal
+# width and height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_calendar_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n
+ local size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ local min_width min_height max_size
+ if [ "$USE_XDIALOG" ]; then
+ min_height=15
+ min_width=55
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_height=0
+ min_width=40
+ max_size=$( stty size ) # usually "24 80"
+ fi
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+
+ #
+ # Enforce the minimum width for displaying the calendar
+ #
+ [ $width -ge $min_width ] || width=$min_width
+
+ #
+ # When using dialog(1), the calendar box is unique from other dialog(1)
+ # boxes in-that the height passed should not accomodate the 15-lines
+ # required to display the calendar. This does not apply to Xdialog(1).
+ #
+ # When using Xdialog(1), the height must accomodate the 15-lines
+ # required to display the calendar.
+ #
+ # NOTE: Also under dialog(1), because we can't predict whether the user
+ # has disabled shadow's in their `$HOME/.dialogrc' file, we'll subtract
+ # 16 rather than 15. This does not apply to Xdialog(1).
+ #
+ max_height=$(( $max_height - 16 ))
+ height=$( echo "$prompt" | f_number_of_lines )
+ if [ "$USE_XDIALOG" ]; then
+ # Add height to accomodate for the embedded calendar widget
+ height=$(( $height + $min_height - 1 ))
+
+ # Also, bump height if backtitle is enabled
+ if [ "$btitle" ]; then
+ local n="$( echo "$btitle" | f_number_of_lines )"
+ height=$(( $height + $n + 2 ))
+ fi
+ else
+ [ "$prompt" ] && height=$(( $height + 1 ))
+ fi
+ [ $height -le $max_height ] || height=$max_height
+
+ #
+ # The calendar box refuses to display if too large.
+ #
+ max_width=$(( $max_width - 2 ))
+ [ $width -le $max_width ] || width=$max_width
+
+ # Return both
+ echo "$height $width"
+}
+
+# f_dialog_timebox_size $title $backtitle $prompt [$hline]
+#
+# Not all versions of dialog(1) perform auto-sizing of the width and height of
+# `--timebox' boxes sensibly.
+#
+# This function helps solve this issue by taking as arguments (in order of
+# appearance) the title, backtitle, prompt, and [optionally] hline returning
+# the optimal width and height for the box (not exceeding the actual terminal
+# width and height).
+#
+# Newline character sequences (``\n'') in $prompt are expanded as-is done by
+# dialog(1).
+#
+# Output is in the format of "height width".
+#
+f_dialog_timebox_size()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local title="$1" btitle="$2" prompt="$3" hline="$4" n
+ local size="$( f_dialog_infobox_size \
+ "$title" "$btitle" "$prompt" "$hline" )"
+ local height="${size%%[$IFS]*}"
+ local width="${size##*[$IFS]}"
+
+ local min_width min_height max_size
+ if [ "$USE_XDIALOG" ]; then
+ min_width=40
+ max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
+ else
+ min_height=0
+ min_width=20
+ max_size=$( stty size ) # usually "24 80"
+ fi
+ local max_height="${max_size%%[$IFS]*}"
+ local max_width="${max_size##*[$IFS]}"
+
+ #
+ # Enforce the minimum width for displaying the timebox
+ #
+ [ $width -ge $min_width ] || width=$min_width
+
+ #
+ # When using dialog(1), the timebox box is unique from other dialog(1)
+ # boxes in-that the height passed should not accomodate the 6-lines
+ # required to display the timebox. This does not apply to Xdialog(1).
+ #
+ # When using Xdialog(1), the height seems to have no effect. All values
+ # provide the same results.
+ #
+ # NOTE: Also under dialog(1), because we can't predict whether the user
+ # has disabled shadow's in their `$HOME/.dialogrc' file, we'll subtract
+ # 7 rather than 6. This does not apply to Xdialog(1).
+ #
+ if [ "$USE_XDIALOG" ]; then
+ height=0 # Autosize; all values produce same results
+ else
+ max_height=$(( $max_height - 7 ))
+ height=$( echo "$prompt" | f_number_of_lines )
+ height=$(( $height + 1 ))
+ [ $height -le $max_height ] || height=$max_height
+ [ "$prompt" ] && height=$(( $height + 1 ))
+ fi
+
+ #
+ # The timebox box refuses to display if too large.
+ #
+ max_width=$(( $max_width - 2 ))
+ [ $width -le $max_width ] || width=$max_width
+
+ # Return both
+ echo "$height $width"
+}
+
+############################################################ CLEAR FUNCTIONS
+
+# f_dialog_clear
+#
+# Clears any/all previous dialog(1) displays.
+#
+f_dialog_clear()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ $DIALOG --clear
+}
+
+############################################################ INFO FUNCTIONS
+
+# f_dialog_info $info_text ...
+#
+# Throw up a dialog(1) infobox. The infobox remains until another dialog is
+# displayed or `dialog --clear' (or dialog_clear) is called.
+#
+f_dialog_info()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local info_text="$*"
+ local size="$( f_dialog_infobox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$info_text" )"
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ ${USE_XDIALOG:+--ignore-eof} \
+ ${USE_XDIALOG:+--no-buttons} \
+ --infobox \"\$info_text\" $size
+}
+
+# f_xdialog_info $info_text ...
+#
+# Throw up an Xdialog(1) infobox and do not dismiss it until stdin produces
+# EOF. This implies that you must execute this either as an rvalue to a pipe,
+# lvalue to indirection or in a sub-shell that provides data on stdin.
+#
+f_xdialog_info()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local info_text="$*"
+ local size="$( f_dialog_infobox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$info_text" )"
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --no-close --no-buttons \
+ --infobox \"\$info_text\" $size \
+ -1 # timeout of -1 means abort when EOF on stdin
+}
+
+############################################################ MSGBOX FUNCTIONS
+
+# f_dialog_msgbox $msg_text ...
+#
+# Throw up a dialog(1) msgbox. The msgbox remains until the user presses ENTER
+# or ESC, acknowledging the modal dialog.
+#
+# If the user presses ENTER, the exit status is zero (success), otherwise if
+# the user presses ESC the exit status is 255.
+#
+f_dialog_msgbox()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local msg_text="$*"
+ local size="$( f_dialog_buttonbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg_text" )"
+
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$msg_text\" $size
+}
+
+############################################################ YESNO FUNCTIONS
+
+# f_dialog_yesno $msg_text ...
+#
+# Display a dialog(1) Yes/No prompt to allow the user to make some decision.
+# The yesno prompt remains until the user presses ENTER or ESC, acknowledging
+# the modal dialog.
+#
+# If the user chooses YES the exit status is zero, or chooses NO the exit
+# status is one, or presses ESC the exit status is 255.
+#
+f_dialog_yesno()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local msg_text="$*"
+ local hline="$hline_arrows_tab_enter"
+ local size="$( f_dialog_buttonbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg_text" \
+ "$hline" )"
+
+ if [ "$USE_XDIALOG" ]; then
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_yes\" \
+ --cancel-label \"\$msg_no\" \
+ --yesno \"\$msg_text\" $size
+ else
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --yes-label \"\$msg_yes\" \
+ --no-label \"\$msg_no\" \
+ --yesno \"\$msg_text\" $size
+ fi
+}
+
+# f_dialog_noyes $msg_text ...
+#
+# Display a dialog(1) No/Yes prompt to allow the user to make some decision.
+# The noyes prompt remains until the user presses ENTER or ESC, acknowledging
+# the modal dialog.
+#
+# If the user chooses YES the exit status is zero, or chooses NO the exit
+# status is one, or presses ESC the exit status is 255.
+#
+# NOTE: This is just like the f_dialog_yesno function except "No" is default.
+#
+f_dialog_noyes()
+{
+ [ "$DIALOG_SELF_INITIALIZE" ] && f_dialog_init
+
+ local msg_text="$*"
+ local hline="$hline_arrows_tab_enter"
+ local size="$( f_dialog_buttonbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg_text" \
+ "$hline" )"
+
+ if [ "$USE_XDIALOG" ]; then
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --default-no \
+ --ok-label \"\$msg_yes\" \
+ --cancel-label \"\$msg_no\" \
+ --yesno \"\$msg_text\" $size
+ else
+ eval $DIALOG \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --hline \"\$hline\" \
+ --defaultno \
+ --yes-label \"\$msg_yes\" \
+ --no-label \"\$msg_no\" \
+ --yesno \"\$msg_text\" $size
+ fi
+}
+
+############################################################ INPUT FUNCTIONS
+
+# f_dialog_inputstr
+#
+# Obtain the inputstr entered by the user from the most recently displayed
+# dialog(1) inputbox and clean up any temporary files.
+#
+f_dialog_inputstr()
+{
+ local tmpfile="$DIALOG_TMPDIR/dialog.inputbox.$$"
+
+ [ -f "$tmpfile" ] || return $FAILURE
+
+ # Skip warnings and trim leading/trailing whitespace from user input
+ awk '
+ BEGIN { found = 0 }
+ {
+ if ( ! found )
+ {
+ if ( $0 ~ /^$/ ) next
+ if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next
+ found = 1
+ }
+ sub(/^[[:space:]]*/, "")
+ sub(/[[:space:]]*$/, "")
+ print
+ }
+ ' "$tmpfile" 2> /dev/null
+ f_quietly rm -f "$tmpfile"
+
+ return $SUCCESS
+}
+
+############################################################ MENU FUNCTIONS
+
+# f_dialog_menutag
+#
+# Obtain the menutag chosen by the user from the most recently displayed
+# dialog(1) menu and clean up any temporary files.
+#
+f_dialog_menutag()
+{
+ local tmpfile="$DIALOG_TMPDIR/dialog.menu.$$"
+
+ [ -f "$tmpfile" ] || return $FAILURE
+
+ awk '
+ BEGIN { found = 0 }
+ {
+ if ( found ) # ... just spew
+ {
+ print
+ next
+ }
+ if ( $0 ~ /^$/ ) next
+ if ( $0 ~ /^Gdk-WARNING \*\*:/ ) next
+ found = 1
+ print
+ }
+ ' "$tmpfile" 2> /dev/null
+ f_quietly rm -f "$tmpfile"
+
+ return $SUCCESS
+}
+
+# f_dialog_menutag2item $tag_chosen $tag1 $item1 $tag2 $item2 ...
+#
+# To use the `--menu' option of dialog(1) you must pass an ordered list of
+# tag/item pairs on the command-line. When the user selects a menu option the
+# tag for that item is printed to stderr.
+#
+# This function allows you to dereference the tag chosen by the user back into
+# the item associated with said tag.
+#
+# Pass the tag chosen by the user as the first argument, followed by the
+# ordered list of tag/item pairs (HINT: use the same tag/item list as was
+# passed to dialog(1) for consistency).
+#
+# If the tag cannot be found, NULL is returned.
+#
+f_dialog_menutag2item()
+{
+ local tag="$1" tagn item
+ shift 1 # tag
+
+ while [ $# -gt 0 ]; do
+ tagn="$1"
+ item="$2"
+ shift 2 # tagn/item
+
+ if [ "$tag" = "$tagn" ]; then
+ echo "$item"
+ return $SUCCESS
+ fi
+ done
+ return $FAILURE
+}
+
+# f_dialog_menutag2item_with_help $tag_chosen $tag1 $item1 $help1 \
+# $tag2 $item2 $help2 ...
+#
+# To use the `--menu' option of dialog(1) with the `--item-help' option, you
+# must pass an ordered list of tag/item/help triplets on the command-line. When
+# the user selects a menu option the tag for that item is printed to stderr.
+#
+# This function allows you to dereference the tag chosen by the user back into
+# the item associated with said tag (help is discarded/ignored).
+#
+# Pass the tag chosen by the user as the first argument, followed by the
+# ordered list of tag/item/help triplets (HINT: use the same tag/item/help list
+# as was passed to dialog(1) for consistency).
+#
+# If the tag cannot be found, NULL is returned.
+#
+f_dialog_menutag2item_with_help()
+{
+ local tag="$1" tagn item
+ shift 1 # tag
+
+ while [ $# -gt 0 ]; do
+ tagn="$1"
+ item="$2"
+ shift 3 # tagn/item/help
+
+ if [ "$tag" = "$tagn" ]; then
+ echo "$item"
+ return $SUCCESS
+ fi
+ done
+ return $FAILURE
+}
+
+# f_dialog_menutag2index $tag_chosen $tag1 $item1 $tag2 $item2 ...
+#
+# To use the `--menu' option of dialog(1) you must pass an ordered list of
+# tag/item pairs on the command-line. When the user selects a menu option the
+# tag for that item is printed to stderr.
+#
+# This function allows you to dereference the tag chosen by the user back into
+# the index associated with said tag. The index is the one-based tag/item pair
+# array position within the ordered list of tag/item pairs passed to dialog(1).
+#
+# Pass the tag chosen by the user as the first argument, followed by the
+# ordered list of tag/item pairs (HINT: use the same tag/item list as was
+# passed to dialog(1) for consistency).
+#
+# If the tag cannot be found, NULL is returned.
+#
+f_dialog_menutag2index()
+{
+ local tag="$1" tagn n=1
+ shift 1 # tag
+
+ while [ $# -gt 0 ]; do
+ tagn="$1"
+ shift 2 # tagn/item
+
+ if [ "$tag" = "$tagn" ]; then
+ echo $n
+ return $SUCCESS
+ fi
+ n=$(( $n + 1 ))
+ done
+ return $FAILURE
+}
+
+# f_dialog_menutag2index_with_help $tag_chosen $tag1 $item1 $help1 \
+# $tag2 $item2 $help2 ...
+#
+# To use the `--menu' option of dialog(1) with the `--item-help' option, you
+# must pass an ordered list of tag/item/help triplets on the command-line. When
+# the user selects a menu option the tag for that item is printed to stderr.
+#
+# This function allows you to dereference the tag chosen by the user back into
+# the index associated with said tag. The index is the one-based tag/item/help
+# triplet array position within the ordered list of tag/item/help triplets
+# passed to dialog(1).
+#
+# Pass the tag chosen by the user as the first argument, followed by the
+# ordered list of tag/item/help triplets (HINT: use the same tag/item/help list
+# as was passed to dialog(1) for consistency).
+#
+# If the tag cannot be found, NULL is returned.
+#
+f_dialog_menutag2index_with_help()
+{
+ local tag="$1" tagn n=1
+ shift 1 # tag
+
+ while [ $# -gt 0 ]; do
+ tagn="$1"
+ shift 3 # tagn/item/help
+
+ if [ "$tag" = "$tagn" ]; then
+ echo $n
+ return $SUCCESS
+ fi
+ n=$(( $n + 1 ))
+ done
+ return $FAILURE
+}
+
+############################################################ INIT FUNCTIONS
+
+# f_dialog_init
+#
+# Initialize (or re-initialize) the dialog module after setting/changing any
+# of the following environment variables:
+#
+# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate
+# that Xdialog(1) should be used instead of dialog(1).
+#
+# SECURE Either NULL or Non-NULL. If given a value will indicate
+# that (while running as root) sudo(8) authentication is
+# required to proceed.
+#
+f_dialog_init()
+{
+ DIALOG_SELF_INITIALIZE=
+
+ #
+ # Process stored command-line arguments
+ #
+ SECURE=$( set -- "$ARGV"
+ while getopts S flag > /dev/null; do
+ case "$flag" in
+ S) echo 1;;
+ \?) continue;;
+ esac
+ done
+ )
+ USE_XDIALOG=$( set -- "$ARGV"
+ while getopts SX flag > /dev/null; do
+ case "$flag" in
+ S|X) echo 1;;
+ \?) continue;;
+ esac
+ done
+ )
+
+ #
+ # Process `-X' command-line option
+ #
+ [ "$USE_XDIALOG" ] && DIALOG=Xdialog
+
+ #
+ # Sanity check, or die gracefully
+ #
+ if ! f_have $DIALOG; then
+ unset USE_XDIALOG
+ failed_dialog="$DIALOG"
+ DIALOG=dialog
+ f_die 1 "$msg_no_such_file_or_directory" "$pgm" "$failed_dialog"
+ fi
+
+ #
+ # If we're already running as root but we got there by way of sudo(8)
+ # and we have X11, we should merge the xauth(1) credentials from our
+ # original user.
+ #
+ if [ "$USE_XDIALOG" ] &&
+ [ "$( id -u )" = "0" ] &&
+ [ "$SUDO_USER" -a "$DISPLAY" ]
+ then
+ if ! f_have xauth; then
+ # Die gracefully, as we [likely] can't use Xdialog(1)
+ unset USE_XDIALOG
+ DIALOG=dialog
+ f_die 1 "$msg_no_such_file_or_directory" "$pgm" "xauth"
+ fi
+ HOSTNAME=$(hostname)
+ displaynum="${DISPLAY#*:}"
+ eval xauth -if \~$SUDO_USER/.Xauthority extract - \
+ \"\$HOSTNAME/unix:\$displaynum\" \
+ \"\$HOSTNAME:\$displaynum\" | sudo sh -c 'xauth -ivf \
+ ~root/.Xauthority merge - > /dev/null 2>&1'
+ fi
+
+ #
+ # Probe Xdialog(1) for maximum height/width constraints, or die
+ # gracefully
+ #
+ if [ "$USE_XDIALOG" ]; then
+ if ! maxsize=$( LANG= LC_ALL= $DIALOG --print-maxsize 2>&1 )
+ then
+ # Xdialog(1) failed, fall back to dialog(1)
+ unset USE_XDIALOG
+ size=$( f_dialog_buttonbox_size "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$maxsize" "" )
+ eval dialog \
+ --title \"\$DIALOG_TITLE\" \
+ --backtitle \"\$DIALOG_BACKTITLE\" \
+ --ok-label \"\$msg_ok\" \
+ --msgbox \"\$maxsize\" $size
+ exit $FAILURE
+ fi
+
+ XDIALOG_MAXSIZE=$(
+ set -- ${maxsize##*:}
+
+ height=${1%,}
+ width=$2
+
+ echo $height $width
+ )
+ unset maxsize
+ fi
+
+ #
+ # If using Xdialog(1), swap DIALOG_TITLE with DIALOG_BACKTITLE.
+ # The reason for this is because many dialog(1) applications use
+ # --backtitle for the program name (which is better suited as
+ # --title with Xdialog(1)).
+ #
+ if [ "$USE_XDIALOG" ]; then
+ _DIALOG_TITLE="$DIALOG_TITLE"
+ DIALOG_TITLE="$DIALOG_BACKTITLE"
+ DIALOG_BACKTITLE="$_DIALOG_TITLE"
+ unset _DIALOG_TITLE
+ fi
+}
+
+############################################################ CLEAN-UP FUNCTIONS
+
+# f_clean_up
+#
+# Clean-up routines (run when script exits or is killed).
+#
+f_clean_up()
+{
+ f_quietly rm -f "$DIALOG_TMPDIR"/dialog.*.$$
+}
+
+############################################################ MAIN
+
+#
+# Trap signals so we can recover gracefully
+#
+trap 'f_clean_up' EXIT
+
+fi # ! $_DIALOG_SUBR
diff --git a/usr.sbin/bsdconfig/share/mustberoot.subr b/usr.sbin/bsdconfig/share/mustberoot.subr
new file mode 100644
index 0000000..ec3e16a
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/mustberoot.subr
@@ -0,0 +1,362 @@
+if [ ! "$_MUSTBEROOT_SUBR" ]; then _MUSTBEROOT_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_include $BSDCFG_SHARE/dialog.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ CONFIGURATION
+# NOTE: These are not able to be overridden/inherited for security purposes.
+
+#
+# Number of tries a user gets to enter his/her password before we log the
+# sudo(8) failure and exit.
+#
+PASSWD_TRIES=3
+
+#
+# While in SECURE mode, should authentication as `root' be allowed? Set to
+# non-NULL to enable authentication as `root', otherwise disabled.
+#
+# WARNING:
+# Unless using a custom sudo(8) configuration, user `root' should not be
+# allowed because no password is required to become `root' when already `root'
+# and therefore, any value entered as password will work.
+#
+SECURE_ALLOW_ROOT=
+
+#
+# While in SECURE mode, should we divulge (through error message) when the
+# requested authentication user does not exist? Set to non-NULL to enable,
+# otherwise a non-existent user is treated like an invalid password.
+#
+SECURE_DIVULGE_UNKNOWN_USER=
+
+############################################################ FUNCTIONS
+
+# f_become_root_via_sudo
+#
+# If not running as root, prompt for sudo(8) credentials to become root.
+# Re-execution of the current program via sudo is automatically handled.
+#
+# The following environment variables effect functionality:
+#
+# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate
+# that Xdialog(1) should be used instead of dialog(1).
+#
+f_become_root_via_sudo()
+{
+ local msg hline size
+
+ [ "$( id -u )" = "0" ] && return $SUCCESS
+
+ f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm"
+
+ #
+ # Check sudo(8) access before prompting for password.
+ #
+ :| sudo -S -v 2> /dev/null
+ if [ $? -ne $SUCCESS ]; then
+ #
+ # sudo(8) access denied. Prompt for their password.
+ #
+ msg="$msg_please_enter_password"
+ hline="$hline_alnum_punc_tab_enter"
+ size=$( f_dialog_inputbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$hline" )
+
+ #
+ # Continue prompting until they either Cancel, succeed
+ # or exceed the number of allowed failures.
+ #
+ local password nfailures=0 retval
+ while [ $nfailures -lt $PASSWD_TRIES ]; do
+ if [ "$USE_XDIALOG" ]; then
+ password=$( $DIALOG \
+ --title "$DIALOG_TITLE" \
+ --backtitle "$DIALOG_BACKTITLE" \
+ --hline "$hline" \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --password --inputbox "$msg" $size \
+ 2>&1 > /dev/null )
+ retval=$?
+
+ # Catch X11-related errors
+ [ $retval -eq 255 ] &&
+ f_die $retval "$password"
+ else
+ $DIALOG \
+ --title "$DIALOG_TITLE" \
+ --backtitle "$DIALOG_BACKTITLE" \
+ --hline "$hline" \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --insecure \
+ --passwordbox "$msg" $size \
+ 2> "$DIALOG_TMPDIR/dialog.inputbox.$$"
+ retval=$?
+ password=$( f_dialog_inputstr )
+ fi
+
+ # Exit if the user cancelled.
+ [ $retval -eq $SUCCESS ] || exit $retval
+
+ #
+ # Validate sudo(8) credentials
+ #
+ sudo -S -v 2> /dev/null <<-EOF
+ $password
+ EOF
+ retval=$?
+ unset password # scrub memory
+ if [ $retval -eq $SUCCESS ]; then
+ # Access granted...
+ break
+ else
+ # Access denied...
+ nfailures=$(( $nfailures + 1 ))
+
+ # introduce a short delay
+ if [ $nfailures -lt $PASSWD_TRIES ]; then
+ f_dialog_info "$msg_sorry_try_again"
+ sleep 1
+ fi
+ fi
+ done
+
+ #
+ # If user exhausted number of allowed password tries, log
+ # the security event and exit immediately.
+ #
+ if [ $nfailures -ge $PASSWD_TRIES ]; then
+ msg=$( printf "$msg_nfailed_attempts" "$nfailures" )
+ logger -p auth.notice -t sudo " " \
+ "$USER : $msg" \
+ "; TTY=$(tty)" \
+ "; PWD=$PWD" \
+ "; USER=root" \
+ "; COMMAND=$0"
+ f_die 1 "sudo: $msg"
+ fi
+ fi
+
+ # Use xauth(1) to grant root the ability to use this X11/SSH session
+ if [ "$USE_XDIALOG" -a "$SSH_CONNECTION" -a "$DISPLAY" ]; then
+ f_have xauth || f_die 1 \
+ "$msg_no_such_file_or_directory" "$pgm" "xauth"
+ local HOSTNAME displaynum
+ HOSTNAME=$(hostname)
+ displaynum="${DISPLAY#*:}"
+ xauth -f ~/.Xauthority extract - $HOSTNAME/unix:$displaynum \
+ $HOSTNAME:$displaynum | sudo sh -c 'xauth -ivf \
+ ~root/.Xauthority merge - > /dev/null 2>&1'
+ fi
+
+ # Re-execute ourselves with sudo(8)
+ if [ $ARGC -gt 0 ]; then
+ exec sudo "$0" $ARGV
+ else
+ exec sudo "$0"
+ fi
+ exit $? # Never reached unless error
+}
+
+# f_authenticate_some_user
+#
+# Only used if running as root and requires X11 (see USE_XDIALOG below).
+# Prompts the user to enter a username and password to be authenticated via
+# sudo(8) to proceed.
+#
+# The following environment variables effect functionality:
+#
+# USE_XDIALOG Either NULL or Non-NULL. If given a value will indicate
+# that Xdialog(1) should be used instead of dialog(1).
+#
+f_authenticate_some_user()
+{
+ local msg hline size width height
+
+ f_have sudo || f_die 1 "$msg_must_be_root_to_execute" "$pgm"
+
+ #
+ # Secure-mode has been requested.
+ #
+
+ [ "$USE_XDIALOG" ] || f_die 1 "$msg_secure_mode_requires_x11"
+ [ "$(id -u)" = "0" ] || f_die 1 "$msg_secure_mode_requires_root"
+
+ #
+ # Prompt for sudo(8) credentials.
+ #
+
+ msg="$msg_please_enter_username_password"
+ hline="$hline_alnum_punc_tab_enter"
+ size=$( f_xdialog_2inputsbox_size \
+ "$DIALOG_TITLE" \
+ "$DIALOG_BACKTITLE" \
+ "$msg" \
+ "$field_username" "" \
+ "$field_password" "" )
+ width="${size##*[$IFS]}"
+ height="${size%%[$IFS]*}"
+ height=$(( $height + 2 )) # Add height for --password
+
+ #
+ # Continue prompting until they either Cancel, succeed or exceed the
+ # number of allowed failures.
+ #
+ local user_pass nfailures=0 retval
+ while [ $nfailures -lt $PASSWD_TRIES ]; do
+ user_pass=$( $DIALOG \
+ --title "$DIALOG_TITLE" \
+ --backtitle "$DIALOG_BACKTITLE" \
+ --hline "$hline" \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --password --2inputsbox "$msg" \
+ $height $width \
+ "$field_username" "" \
+ "$field_password" "" \
+ 2>&1 > /dev/null )
+ retval=$?
+
+ # Catch X11-related errors
+ [ $retval -eq 255 ] && f_die $retval "$user_pass"
+
+ # Exit if the user cancelled.
+ [ $retval -eq $SUCCESS ] || exit $retval
+
+ #
+ # Make sure the user exists and is non-root
+ #
+ local user password
+ user="${user_pass%%/*}"
+ password="${user_pass#*/}"
+ unset user_pass # scrub memory
+ if [ ! "$user" ]; then
+ nfailures=$(( $nfailures + 1 ))
+ f_dialog_msgbox "$msg_no_username"
+ continue
+ fi
+ if [ ! "$SECURE_ALLOW_ROOT" ]; then
+ case "$user" in
+ root|toor)
+ nfailures=$(( $nfailures + 1 ))
+ f_dialog_msgbox "$( printf \
+ "$msg_user_disallowed" "$user" )"
+ continue
+ esac
+ fi
+ if ! f_quietly id "$user"; then
+ nfailures=$(( $nfailures + 1 ))
+ if [ "$SECURE_DIVULGE_UNKNOWN_USER" ]; then
+ f_dialog_msgbox "$( printf \
+ "$msg_unknown_user" "$user" )"
+ elif [ $nfailures -lt $PASSWD_TRIES ]; then
+ f_dialog_info "$msg_sorry_try_again"
+ sleep 1
+ fi
+ continue
+ fi
+
+ #
+ # Validate sudo(8) credentials for given user
+ #
+ su -m "$user" <<-EOF
+ sh <<EOS
+ sudo -k
+ sudo -S -v 2> /dev/null <<EOP
+ $password
+ EOP
+ EOS
+ EOF
+ retval=$?
+ unset user
+ unset password # scrub memory
+
+ if [ $retval -eq $SUCCESS ]; then
+ # Access granted...
+ break
+ else
+ # Access denied...
+ nfailures=$(( $nfailures + 1 ))
+
+ # introduce a short delay
+ if [ $nfailures -lt $PASSWD_TRIES ]; then
+ f_dialog_info "$msg_sorry_try_again"
+ sleep 1
+ fi
+ fi
+ done
+
+ #
+ # If user exhausted number of allowed password tries, log
+ # the security event and exit immediately.
+ #
+ if [ $nfailures -ge $PASSWD_TRIES ]; then
+ msg=$( printf "$msg_nfailed_attempts" "$nfailures" )
+ logger -p auth.notice -t sudo " " \
+ "${SUDO_USER:-$USER} : $msg" \
+ "; TTY=$(tty)" \
+ "; PWD=$PWD" \
+ "; USER=root" \
+ "; COMMAND=$0"
+ f_die 1 "sudo: $message"
+ fi
+}
+
+# f_mustberoot_init
+#
+# If not already root, make the switch to root by re-executing ourselves via
+# sudo(8) using user-supplied credentials.
+#
+# The following environment variables effect functionality:
+#
+# SECURE Either NULL or Non-NULL. If given a value will indicate
+# that (while running as root) sudo(8) authentication is
+# required to proceed.
+#
+f_mustberoot_init()
+{
+ if [ "$(id -u)" != "0" -a ! "$SECURE" ]; then
+ f_become_root_via_sudo
+ elif [ "$SECURE" ]; then
+ f_authenticate_some_user
+ fi
+}
+
+fi # ! $_MUSTBEROOT_SUBR
diff --git a/usr.sbin/bsdconfig/share/strings.subr b/usr.sbin/bsdconfig/share/strings.subr
new file mode 100644
index 0000000..1a330ad
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/strings.subr
@@ -0,0 +1,104 @@
+if [ ! "$_STRINGS_SUBR" ]; then _STRINGS_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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.
+#
+# $FreeBSD$
+
+# f_substr "$string" $start [ $length ]
+#
+# Simple wrapper to awk(1)'s `substr' function.
+#
+f_substr()
+{
+ local string="$1" start="${2:-0}" len="${3:-0}"
+ echo "$string" | awk "{ print substr(\$0, $start, $len) }"
+}
+
+# f_longest_line_length
+#
+# Simple wrapper to an awk(1) script to print the length of the longest line of
+# input (read from stdin). Supports the newline escape-sequence `\n' for
+# splitting a single line into multiple lines.
+#
+f_longest_line_length_awk='
+BEGIN { longest = 0 }
+{
+ if (split($0, lines, /\\n/) > 1)
+ {
+ for (n in lines)
+ {
+ len = length(lines[n])
+ longest = ( len > longest ? len : longest )
+ }
+ }
+ else
+ {
+ len = length($0)
+ longest = ( len > longest ? len : longest )
+ }
+}
+END { print longest }
+'
+f_longest_line_length()
+{
+ awk "$f_longest_line_length_awk"
+}
+
+# f_number_of_lines
+#
+# Simple wrapper to an awk(1) script to print the number of lines read from
+# stdin. Supports newline escape-sequence `\n' for splitting a single line into
+# multiple lines.
+#
+f_number_of_lines_awk='
+BEGIN { num_lines = 0 }
+{
+ num_lines += split($0, unused, /\\n/)
+}
+END { print num_lines }
+'
+f_number_of_lines()
+{
+ awk "$f_number_of_lines_awk"
+}
+
+# f_isinteger $arg
+#
+# Returns true if argument is a positive/negative whole integer.
+#
+f_isinteger()
+{
+ local arg="$1"
+
+ # Prevent division-by-zero
+ [ "$arg" = "0" ] && return $SUCCESS
+
+ # Attempt to perform arithmetic divison (an operation which will exit
+ # with error unless arg is a valid positive/negative whole integer).
+ #
+ ( : $((0/$arg)) ) > /dev/null 2>&1
+}
+
+fi # ! $_STRINGS_SUBR
diff --git a/usr.sbin/bsdconfig/share/sysrc.subr b/usr.sbin/bsdconfig/share/sysrc.subr
new file mode 100644
index 0000000..014ab46
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/sysrc.subr
@@ -0,0 +1,618 @@
+if [ ! "$_SYSRC_SUBR" ]; then _SYSRC_SUBR=1
+#
+# Copyright (c) 2006-2012 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 (INLUDING, 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.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ CONFIGURATION
+
+#
+# Standard pathnames (inherit values from shell if available)
+#
+: ${RC_DEFAULTS:="/etc/defaults/rc.conf"}
+
+############################################################ GLOBALS
+
+#
+# Global exit status variables
+#
+SUCCESS=0
+FAILURE=1
+
+############################################################ FUNCTIONS
+
+# f_clean_env [ --except $varname ... ]
+#
+# Unset all environment variables in the current scope. An optional list of
+# arguments can be passed, indicating which variables to avoid unsetting; the
+# `--except' is required to enable the exclusion-list as the remainder of
+# positional arguments.
+#
+# Be careful not to call this in a shell that you still expect to perform
+# $PATH expansion in, because this will blow $PATH away. This is best used
+# within a sub-shell block "(...)" or "$(...)" or "`...`".
+#
+f_clean_env()
+{
+ local var arg except=
+
+ #
+ # Should we process an exclusion-list?
+ #
+ if [ "$1" = "--except" ]; then
+ except=1
+ shift 1
+ fi
+
+ #
+ # Loop over a list of variable names from set(1) built-in.
+ #
+ for var in $( set | awk -F= \
+ '/^[[:alpha:]_][[:alnum:]_]*=/ {print $1}' \
+ | grep -v '^except$'
+ ); do
+ #
+ # In POSIX bourne-shell, attempting to unset(1) OPTIND results
+ # in "unset: Illegal number:" and causes abrupt termination.
+ #
+ [ "$var" = OPTIND ] && continue
+
+ #
+ # Process the exclusion-list?
+ #
+ if [ "$except" ]; then
+ for arg in "$@" ""; do
+ [ "$var" = "$arg" ] && break
+ done
+ [ "$arg" ] && continue
+ fi
+
+ unset "$var"
+ done
+}
+
+# f_sysrc_get $varname
+#
+# Get a system configuration setting from the collection of system-
+# configuration files (in order: /etc/defaults/rc.conf /etc/rc.conf
+# and /etc/rc.conf).
+#
+# NOTE: Additional shell parameter-expansion formats are supported. For
+# example, passing an argument of "hostname%%.*" (properly quoted) will
+# return the hostname up to (but not including) the first `.' (see sh(1),
+# "Parameter Expansion" for more information on additional formats).
+#
+f_sysrc_get()
+{
+ # Sanity check
+ [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE
+
+ # Taint-check variable name
+ case "$1" in
+ [0-9]*)
+ # Don't expand possible positional parameters
+ return $FAILURE;;
+ *)
+ [ "$1" ] || return $FAILURE
+ esac
+
+ ( # Execute within sub-shell to protect parent environment
+
+ #
+ # Clear the environment of all variables, preventing the
+ # expansion of normals such as `PS1', `TERM', etc.
+ #
+ f_clean_env --except RC_CONFS RC_DEFAULTS SUCCESS
+
+ . "$RC_DEFAULTS" > /dev/null 2>&1
+
+ unset RC_DEFAULTS
+ # no longer needed
+
+ #
+ # If the query is for `rc_conf_files' then store the value that
+ # we inherited from sourcing RC_DEFAULTS (above) so that we may
+ # conditionally restore this value after source_rc_confs in the
+ # event that RC_CONFS does not customize the value.
+ #
+ if [ "$1" = "rc_conf_files" ]; then
+ _rc_conf_files="$rc_conf_files"
+ fi
+
+ #
+ # If RC_CONFS is defined, set $rc_conf_files to an explicit
+ # value, modifying the default behavior of source_rc_confs().
+ #
+ ( : ${RC_CONFS?} ) > /dev/null 2>&1
+ if [ $? -eq ${SUCCESS:-0} ]; then
+ rc_conf_files="$RC_CONFS"
+ _rc_confs_set=1
+ fi
+
+ unset SUCCESS
+ # no longer needed
+
+ source_rc_confs > /dev/null 2>&1
+
+ #
+ # If the query was for `rc_conf_files' AND after calling
+ # source_rc_confs the vaue has not changed, then we should
+ # restore the value to the one inherited from RC_DEFAULTS
+ # before performing the final query (preventing us from
+ # returning what was set via RC_CONFS when the intent was
+ # instead to query the value from the file(s) specified).
+ #
+ if [ "$1" = "rc_conf_files" -a \
+ "$_rc_confs_set" -a \
+ "$rc_conf_files" = "$RC_CONFS" \
+ ]; then
+ rc_conf_files="$_rc_conf_files"
+ unset _rc_conf_files
+ unset _rc_confs_set
+ fi
+
+ unset RC_CONFS
+ # no longer needed
+
+ #
+ # This must be the last functional line for both the sub-shell
+ # and the function to preserve the return status from formats
+ # such as "${varname?}" and "${varname:?}" (see "Parameter
+ # Expansion" in sh(1) for more information).
+ #
+ eval echo '"${'"$1"'}"' 2> /dev/null
+ )
+}
+
+# f_sysrc_get_default $varname
+#
+# Get a system configuration default setting from the default rc.conf(5) file
+# (or whatever RC_DEFAULTS points at).
+#
+f_sysrc_get_default()
+{
+ # Sanity check
+ [ -f "$RC_DEFAULTS" -a -r "$RC_DEFAULTS" ] || return $FAILURE
+
+ # Taint-check variable name
+ case "$1" in
+ [0-9]*)
+ # Don't expand possible positional parameters
+ return $FAILURE;;
+ *)
+ [ "$1" ] || return $FAILURE
+ esac
+
+ ( # Execute within sub-shell to protect parent environment
+
+ #
+ # Clear the environment of all variables, preventing the
+ # expansion of normals such as `PS1', `TERM', etc.
+ #
+ f_clean_env --except RC_DEFAULTS
+
+ . "$RC_DEFAULTS" > /dev/null 2>&1
+
+ unset RC_DEFAULTS
+ # no longer needed
+
+ #
+ # This must be the last functional line for both the sub-shell
+ # and the function to preserve the return status from formats
+ # such as "${varname?}" and "${varname:?}" (see "Parameter
+ # Expansion" in sh(1) for more information).
+ #
+ eval echo '"${'"$1"'}"' 2> /dev/null
+ )
+}
+
+# f_sysrc_find $varname
+#
+# Find which file holds the effective last-assignment to a given variable
+# within the rc.conf(5) file(s).
+#
+# If the variable is found in any of the rc.conf(5) files, the function prints
+# the filename it was found in and then returns success. Otherwise output is
+# NULL and the function returns with error status.
+#
+f_sysrc_find()
+{
+ local varname="$1"
+ local regex="^[[:space:]]*$varname="
+ local rc_conf_files="$( f_sysrc_get rc_conf_files )"
+ local conf_files=
+ local file
+
+ # Check parameters
+ [ "$varname" ] || return $FAILURE
+
+ #
+ # If RC_CONFS is defined, set $rc_conf_files to an explicit
+ # value, modifying the default behavior of source_rc_confs().
+ #
+ [ "$RC_CONFS" ] && rc_conf_files="$RC_CONFS"
+
+ #
+ # Reverse the order of files in rc_conf_files (the boot process sources
+ # these in order, so we will search them in reverse-order to find the
+ # last-assignment -- the one that ultimately effects the environment).
+ #
+ for file in $rc_conf_files; do
+ conf_files="$file${conf_files:+ }$conf_files"
+ done
+
+ #
+ # Append the defaults file (since directives in the defaults file
+ # indeed affect the boot process, we'll want to know when a directive
+ # is found there).
+ #
+ conf_files="$conf_files${conf_files:+ }$RC_DEFAULTS"
+
+ #
+ # Find which file matches assignment to the given variable name.
+ #
+ for file in $conf_files; do
+ [ -f "$file" -a -r "$file" ] || continue
+ if grep -Eq "$regex" $file; then
+ echo $file
+ return $SUCCESS
+ fi
+ done
+
+ return $FAILURE # Not found
+}
+
+# f_sysrc_desc $varname
+#
+# Attempts to return the comments associated with varname from the rc.conf(5)
+# defaults file `/etc/defaults/rc.conf' (or whatever RC_DEFAULTS points to).
+#
+# Multi-line comments are joined together. Results are NULL if no description
+# could be found.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_sysrc_desc_awk='
+# Variables that should be defined on the invocation line:
+# -v varname="varname"
+#
+BEGIN {
+ regex = "^[[:space:]]*"varname"="
+ found = 0
+ buffer = ""
+}
+{
+ if ( ! found )
+ {
+ if ( ! match($0, regex) ) next
+
+ found = 1
+ sub(/^[^#]*(#[[:space:]]*)?/, "")
+ buffer = $0
+ next
+ }
+
+ if ( !/^[[:space:]]*#/ ||
+ /^[[:space:]]*[[:alpha:]_][[:alnum:]_]*=/ ||
+ /^[[:space:]]*#[[:alpha:]_][[:alnum:]_]*=/ ||
+ /^[[:space:]]*$/ ) exit
+
+ sub(/(.*#)*[[:space:]]*/, "")
+ buffer = buffer" "$0
+}
+END {
+ # Clean up the buffer
+ sub(/^[[:space:]]*/, "", buffer)
+ sub(/[[:space:]]*$/, "", buffer)
+
+ print buffer
+ exit ! found
+}
+'
+f_sysrc_desc()
+{
+ awk -v varname="$1" "$f_sysrc_desc_awk" < "$RC_DEFAULTS"
+}
+
+# f_sysrc_set $varname $new_value
+#
+# Change a setting in the system configuration files (edits the files in-place
+# to change the value in the last assignment to the variable). If the variable
+# does not appear in the source file, it is appended to the end of the primary
+# system configuration file `/etc/rc.conf'.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_sysrc_set_awk='
+# Variables that should be defined on the invocation line:
+# -v varname="varname"
+# -v new_value="new_value"
+#
+BEGIN {
+ regex = "^[[:space:]]*"varname"="
+ found = retval = 0
+}
+{
+ # If already found... just spew
+ if ( found ) { print; next }
+
+ # Does this line match an assignment to our variable?
+ if ( ! match($0, regex) ) { print; next }
+
+ # Save important match information
+ found = 1
+ matchlen = RSTART + RLENGTH - 1
+
+ # Store the value text for later munging
+ value = substr($0, matchlen + 1, length($0) - matchlen)
+
+ # Store the first character of the value
+ t1 = t2 = substr(value, 0, 1)
+
+ # Assignment w/ back-ticks, expression, or misc.
+ # We ignore these since we did not generate them
+ #
+ if ( t1 ~ /[`$\\]/ ) { retval = 1; print; next }
+
+ # Assignment w/ single-quoted value
+ else if ( t1 == "'\''" ) {
+ sub(/^'\''[^'\'']*/, "", value)
+ if ( length(value) == 0 ) t2 = ""
+ sub(/^'\''/, "", value)
+ }
+
+ # Assignment w/ double-quoted value
+ else if ( t1 == "\"" ) {
+ sub(/^"(.*\\\\+")*[^"]*/, "", value)
+ if ( length(value) == 0 ) t2 = ""
+ sub(/^"/, "", value)
+ }
+
+ # Assignment w/ non-quoted value
+ else if ( t1 ~ /[^[:space:];]/ ) {
+ t1 = t2 = "\""
+ sub(/^[^[:space:]]*/, "", value)
+ }
+
+ # Null-assignment
+ else if ( t1 ~ /[[:space:];]/ ) { t1 = t2 = "\"" }
+
+ printf "%s%c%s%c%s\n", substr($0, 0, matchlen), \
+ t1, new_value, t2, value
+}
+END { exit retval }
+'
+f_sysrc_set()
+{
+ local varname="$1" new_value="$2"
+
+ # Check arguments
+ [ "$varname" ] || return $FAILURE
+
+ #
+ # Find which rc.conf(5) file contains the last-assignment
+ #
+ local not_found=
+ local file="$( f_sysrc_find "$varname" )"
+ if [ "$file" = "$RC_DEFAULTS" -o ! "$file" ]; then
+ #
+ # We either got a null response (not found) or the variable
+ # was only found in the rc.conf(5) defaults. In either case,
+ # let's instead modify the first file from $rc_conf_files.
+ #
+
+ not_found=1
+
+ #
+ # If RC_CONFS is defined, use $RC_CONFS
+ # rather than $rc_conf_files.
+ #
+ if [ "$RC_CONFS" ]; then
+ file="${RC_CONFS%%[$IFS]*}"
+ else
+ file=$( f_sysrc_get rc_conf_files )
+ file="${file%%[$IFS]*}"
+ fi
+ fi
+
+ #
+ # If not found, append new value to last file and return.
+ #
+ if [ "$not_found" ]; then
+ echo "$varname=\"$new_value\"" >> "$file"
+ return $?
+ fi
+
+ #
+ # Perform sanity checks.
+ #
+ if [ ! -w "$file" ]; then
+ f_err "$msg_cannot_create_permission_denied\n" \
+ "$pgm" "$file"
+ return $FAILURE
+ fi
+
+ #
+ # Create a new temporary file to write to.
+ #
+ local tmpfile="$( mktemp -t "$pgm" )"
+ [ "$tmpfile" ] || return $FAILURE
+
+ #
+ # Fixup permissions (else we're in for a surprise, as mktemp(1) creates
+ # the temporary file with 0600 permissions, and if we simply mv(1) the
+ # temporary file over the destination, the destination will inherit the
+ # permissions from the temporary file).
+ #
+ local mode
+ mode=$( stat -f '%#Lp' "$file" 2> /dev/null )
+ f_quietly chmod "${mode:-0644}" "$tmpfile"
+
+ #
+ # Fixup ownership. The destination file _is_ writable (we tested
+ # earlier above). However, this will fail if we don't have sufficient
+ # permissions (so we throw stderr into the bit-bucket).
+ #
+ local owner
+ owner=$( stat -f '%u:%g' "$file" 2> /dev/null )
+ f_quietly chown "${owner:-root:wheel}" "$tmpfile"
+
+ #
+ # Operate on the matching file, replacing only the last occurrence.
+ #
+ local new_contents retval
+ new_contents=$( tail -r $file 2> /dev/null )
+ new_contents=$( echo "$new_contents" | awk -v varname="$varname" \
+ -v new_value="$new_value" "$f_sysrc_set_awk" )
+ retval=$?
+
+ #
+ # Write the temporary file contents.
+ #
+ echo "$new_contents" | tail -r > "$tmpfile" || return $FAILURE
+ if [ $retval -ne $SUCCESS ]; then
+ echo "$varname=\"$new_value\"" >> "$tmpfile"
+ fi
+
+ #
+ # Taint-check our results.
+ #
+ if ! /bin/sh -n "$tmpfile"; then
+ f_err "$msg_previous_syntax_errors\n" "$pgm" "$file"
+ rm -f "$tmpfile"
+ return $FAILURE
+ fi
+
+ #
+ # Finally, move the temporary file into place.
+ #
+ mv "$tmpfile" "$file"
+}
+
+# f_sysrc_delete $varname
+#
+# Remove a setting from the system configuration files (edits files in-place).
+# Deletes all assignments to the given variable in all config files. If the
+# `-f file' option is passed, the removal is restricted to only those files
+# specified, otherwise the system collection of rc_conf_files is used.
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_sysrc_delete_awk='
+# Variables that should be defined on the invocation line:
+# -v varname="varname"
+#
+BEGIN {
+ regex = "^[[:space:]]*"varname"="
+ found = 0
+}
+{
+ if ( $0 ~ regex )
+ found = 1
+ else
+ print
+}
+END { exit ! found }
+'
+f_sysrc_delete()
+{
+ local varname="$1"
+ local file
+
+ # Check arguments
+ [ "$varname" ] || return $FAILURE
+
+ #
+ # Operate on each of the specified files
+ #
+ for file in ${RC_CONFS:-$( f_sysrc_get rc_conf_files )}; do
+ [ -e "$file" ] || continue
+
+ #
+ # Create a new temporary file to write to.
+ #
+ local tmpfile="$( mktemp -t "$pgm" )"
+ [ "$tmpfile" ] || return $FAILURE
+
+ #
+ # Fixup permissions and ownership (mktemp(1) defaults to 0600
+ # permissions) to instead match the destination file.
+ #
+ local mode owner
+ mode=$( stat -f '%#Lp' "$file" 2> /dev/null )
+ owner=$( stat -f '%u:%g' "$file" 2> /dev/null )
+ f_quietly chmod "${mode:-0644}" "$tmpfile"
+ f_quietly chown "${owner:-root:wheel}" "$tmpfile"
+
+ #
+ # Operate on the file, removing all occurrences, saving the
+ # output in our temporary file.
+ #
+ awk -v varname="$varname" "$f_sysrc_delete_awk" "$file" \
+ > "$tmpfile"
+ if [ $? -ne $SUCCESS ]; then
+ # The file didn't contain any assignments
+ rm -f "$tmpfile"
+ continue
+ fi
+
+ #
+ # Taint-check our results.
+ #
+ if ! /bin/sh -n "$tmpfile"; then
+ f_err "$msg_previous_syntax_errors\n" \
+ "$pgm" "$file"
+ rm -f "$tmpfile"
+ return $FAILURE
+ fi
+
+ #
+ # Perform sanity checks
+ #
+ if [ ! -w "$file" ]; then
+ f_err "$msg_permission_denied\n" "$pgm" "$file"
+ rm -f "$tmpfile"
+ return $FAILURE
+ fi
+
+ #
+ # Finally, move the temporary file into place.
+ #
+ mv "$tmpfile" "$file"
+ done
+}
+
+fi # ! $_SYSRC_SUBR
OpenPOWER on IntegriCloud