Add support for scripting (sysinstall style).
Reviewed by: jilles
This commit is contained in:
parent
e77a012915
commit
57018d79b2
@ -31,6 +31,9 @@ Usage:
|
||||
@PROGRAM_NAME@ [OPTIONS] [command [OPTIONS]]
|
||||
|
||||
OPTIONS:
|
||||
-f file Load file as script and then exit. If multiple occurrences,
|
||||
program will only exit after last occurrence. If file is a
|
||||
single dash (`-'), @PROGRAM_NAME@ reads from standard input.
|
||||
-h Print usage statement and exit.
|
||||
-S Secure X11 mode (implies `-X'). As root, always prompt-for
|
||||
and validate sudo(8) username/password before starting.
|
||||
|
@ -204,25 +204,45 @@ dialog_menu_main()
|
||||
############################################################ MAIN
|
||||
|
||||
#
|
||||
# If $0 is not "bsdconfig", interpret it as a keyword to a menuitem
|
||||
# If $0 is not "bsdconfig", interpret it either as a keyword to a menuitem or
|
||||
# as a valid resword (see script.subr for additional details about reswords).
|
||||
#
|
||||
if [ "$pgm" != "bsdconfig" ] &&
|
||||
indexfile=$( f_index_file "$pgm" ) &&
|
||||
cmd=$( f_index_menusel_command "$indexfile" "$pgm" )
|
||||
then
|
||||
exec "$cmd" "$@" || exit 1
|
||||
if [ "$pgm" != "bsdconfig" ]; then
|
||||
if indexfile=$( f_index_file "$pgm" ) &&
|
||||
cmd=$( f_index_menusel_command "$indexfile" "$pgm" )
|
||||
then
|
||||
f_dprintf "pgm=[%s] indexfile=[%s] cmd=[%s]" \
|
||||
"$pgm" "$indexfile" "$cmd"
|
||||
exec "$cmd" "$@" || exit 1
|
||||
else
|
||||
f_include $BSDCFG_SHARE/script.subr
|
||||
for resword in $RESWORDS; do
|
||||
[ "$pgm" = "$resword" ] || continue
|
||||
# Found a match
|
||||
f_dprintf "pgm=[%s] A valid resWord!" "$pgm"
|
||||
f_dispatch $resword
|
||||
exit $?
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Process command-line arguments
|
||||
#
|
||||
while getopts hSX flag; do
|
||||
scripts_loaded=0
|
||||
while getopts f:hSX flag; do
|
||||
case "$flag" in
|
||||
f) [ $scripts_loaded -eq 0 ] && f_include $BSDCFG_SHARE/script.subr
|
||||
f_script_load "$OPTARG"
|
||||
scripts_loaded=$(( $scripts_loaded + 1 ));;
|
||||
h|\?) usage;;
|
||||
esac
|
||||
done
|
||||
shift $(( $OPTIND -1 ))
|
||||
|
||||
# If we've loaded any scripts, do not continue any further
|
||||
[ $scripts_loaded -gt 0 ] && exit
|
||||
|
||||
#
|
||||
# Initialize
|
||||
#
|
||||
|
@ -85,6 +85,17 @@ a master menu listing the available commands.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width indent+
|
||||
.It Fl f Ar file
|
||||
Load
|
||||
.Ar file
|
||||
as script and then exit.
|
||||
If multiple occurrences, program will only exit after last occurrence.
|
||||
If
|
||||
.Ar file
|
||||
is a single dash
|
||||
.Pq Sq Fl ,
|
||||
.Nm
|
||||
reads from standard input.
|
||||
.It Fl h
|
||||
Print usage statement and exit.
|
||||
.It Fl S
|
||||
|
@ -34,6 +34,7 @@ msg_becoming_root_via_sudo="Becoming root via sudo(8)..."
|
||||
msg_cancel="Cancel"
|
||||
msg_cancel_exit="Cancel/Exit"
|
||||
msg_cannot_create_permission_denied="%s: cannot create %s: Permission denied"
|
||||
msg_command_failed_rest_of_script_aborted="Command \`%s' failed - rest of script aborted."
|
||||
msg_created_path="Created %s"
|
||||
msg_directory_not_found="%s: Directory not found."
|
||||
msg_exit="Exit"
|
||||
@ -56,6 +57,7 @@ msg_secure_mode_requires_x11="Secure-mode requires X11 (use \`-X')!"
|
||||
msg_secure_mode_requires_root="Secure-mode requires root-access!"
|
||||
msg_sorry_try_again="Sorry, try again."
|
||||
msg_try_sudo_only_this_once="Try sudo(8) only this once"
|
||||
msg_unable_to_open="Unable to open %s"
|
||||
msg_unknown_user="Unknown user: %s"
|
||||
msg_usage="Usage"
|
||||
msg_user_disallowed="User disallowed: %s"
|
||||
|
@ -3,7 +3,8 @@
|
||||
NO_OBJ=
|
||||
|
||||
FILESDIR= ${SHAREDIR}/bsdconfig
|
||||
FILES= common.subr dialog.subr mustberoot.subr strings.subr sysrc.subr
|
||||
FILES= common.subr dialog.subr mustberoot.subr script.subr \
|
||||
strings.subr sysrc.subr variable.subr
|
||||
|
||||
beforeinstall:
|
||||
mkdir -p ${DESTDIR}${FILESDIR}
|
||||
|
@ -114,6 +114,30 @@ f_have()
|
||||
f_quietly type "$@"
|
||||
}
|
||||
|
||||
# f_getvar $var_to_get [$var_to_set]
|
||||
#
|
||||
# Utility function designed to go along with the already-builtin setvar.
|
||||
# Allows clean variable name indirection without forking or sub-shells.
|
||||
#
|
||||
# Returns error status if the requested variable ($var_to_get) is not set.
|
||||
#
|
||||
# If $var_to_set is missing or NULL, the value of $var_to_get 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_getvar()
|
||||
{
|
||||
local var_to_get="$1" var_to_set="$2"
|
||||
[ "$var_to_set" ] || local value
|
||||
eval ${var_to_set:-value}=\"\${$var_to_get}\"
|
||||
eval [ \"\${$var_to_get+set}\" ]
|
||||
local retval=$?
|
||||
eval f_dprintf '"f_getvar: var=[%s] value=[%s] r=%u"' \
|
||||
\"\$var_to_get\" \"\$${var_to_set:-value}\" \$retval
|
||||
[ "$var_to_set" ] || { [ "$value" ] && echo "$value"; }
|
||||
return $retval
|
||||
}
|
||||
|
||||
# f_die [ $status [ $fmt [ $opts ... ]]]
|
||||
#
|
||||
# Abruptly terminate due to an error optionally displaying a message in a
|
||||
|
139
usr.sbin/bsdconfig/share/script.subr
Normal file
139
usr.sbin/bsdconfig/share/script.subr
Normal file
@ -0,0 +1,139 @@
|
||||
if [ ! "$_SCRIPT_SUBR" ]; then _SCRIPT_SUBR=1
|
||||
#
|
||||
# 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 (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_dprintf "%s: loading includes..." script.subr
|
||||
f_include $BSDCFG_SHARE/variable.subr
|
||||
|
||||
############################################################ GLOBALS
|
||||
|
||||
RESWORDS=
|
||||
|
||||
############################################################ FUNCTIONS
|
||||
|
||||
# f_resword_new $resword $function
|
||||
#
|
||||
# Create a new `reserved' word for scripting purposes. Reswords call pre-
|
||||
# defined functions but differ from those functions in the following ways:
|
||||
#
|
||||
# + Reswords do not take arguments but instead get all their data from
|
||||
# the environment variable namespace.
|
||||
# + Unless noError is set (must be non-NULL), if calling the resword
|
||||
# results in failure, the application will terminate prematurely.
|
||||
# + noError is unset after each/every resword is called.
|
||||
#
|
||||
# Reswords should not be used in bsdconfig itself (hence the name `reserved
|
||||
# word') but instead only in scripts loaded through f_script_load()).
|
||||
#
|
||||
f_resword_new()
|
||||
{
|
||||
local resword="$1" func="$2"
|
||||
[ "$resword" ] || return $FAILURE
|
||||
f_dprintf "script.subr: New resWord %s -> %s" "$resword" "$func"
|
||||
eval $resword\(\){ f_dispatch $func $resword\; }
|
||||
RESWORDS="$RESWORDS${RESWORDS:+ }$resword"
|
||||
}
|
||||
|
||||
# f_dispatch $func [$resword]
|
||||
#
|
||||
# Wrapper function used by `reserved words' (reswords) to call other functions.
|
||||
# If $noError is set and non-NULL, a failure result from $func is ignored,
|
||||
# otherwise the application is prematurely terminated using f_die().
|
||||
#
|
||||
# NOTE: $noError is unset after every call.
|
||||
#
|
||||
f_dispatch()
|
||||
{
|
||||
local func="$1" resword="${2:-$1}"
|
||||
f_dprintf "f_dispatch: calling resword \`%s'" "$resword"
|
||||
eval $func
|
||||
local retval=$? _ignore_this_error
|
||||
f_getvar $VAR_NO_ERROR _ignore_this_error
|
||||
[ $retval -eq $SUCCESS ] ||
|
||||
[ "$_ignore_this_error" ] || f_die $retval \
|
||||
"$msg_command_failed_rest_of_script_aborted" "$resword"
|
||||
unset $VAR_NO_ERROR
|
||||
}
|
||||
|
||||
# f_script_load [$file]
|
||||
#
|
||||
# Load a script (usually filled with reswords). If $file is missing or NULL,
|
||||
# use one of the following instead (in order):
|
||||
#
|
||||
# $configFile
|
||||
# install.cfg
|
||||
# /stand/install.fg
|
||||
# /tmp/install.cfg
|
||||
#
|
||||
# Unknown/unregistered reswords will generate sh(1) syntax errors but not cause
|
||||
# premature termination.
|
||||
#
|
||||
# Returns success if a script was loaded and itself returned success.
|
||||
#
|
||||
f_script_load()
|
||||
{
|
||||
local script="$1" config_file
|
||||
|
||||
f_dprintf "f_script_load: script=[%s]" "$script"
|
||||
if [ ! "$script" ]; then
|
||||
f_getvar $VAR_CONFIG_FILE config_file
|
||||
for script in \
|
||||
$config_file \
|
||||
install.cfg \
|
||||
/stand/install.cfg \
|
||||
/tmp/install.cfg \
|
||||
; do
|
||||
[ -e "$script" ] && break
|
||||
done
|
||||
elif [ "$script" = "-" ]; then
|
||||
f_dprintf "f_script_load: Loading script from stdin"
|
||||
eval "$( cat )"
|
||||
else
|
||||
f_dprintf "f_script_load: Loading script \`%s'" "$script"
|
||||
if [ ! -e "$script" ]; then
|
||||
f_show_msg "$msg_unable_to_open" "$script"
|
||||
return $FAILURE
|
||||
fi
|
||||
. "$script"
|
||||
fi
|
||||
}
|
||||
|
||||
############################################################ MAIN
|
||||
|
||||
#
|
||||
# Reserved words meant for scripting
|
||||
#
|
||||
f_resword_new dumpVariables f_dump_variables
|
||||
f_resword_new loadConfig f_script_load
|
||||
|
||||
f_dprintf "%s: Successfully loaded." script.subr
|
||||
|
||||
fi # ! $_SCRIPT_SUBR
|
185
usr.sbin/bsdconfig/share/variable.subr
Normal file
185
usr.sbin/bsdconfig/share/variable.subr
Normal file
@ -0,0 +1,185 @@
|
||||
if [ ! "$_VARIABLE_SUBR" ]; then _VARIABLE_SUBR=1
|
||||
#
|
||||
# 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 (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_dprintf "%s: loading includes..." variable.subr
|
||||
f_include $BSDCFG_SHARE/dialog.subr
|
||||
|
||||
############################################################ GLOBALS
|
||||
|
||||
VARIABLES=
|
||||
|
||||
#
|
||||
# Default behavior is to call f_variable_set_defaults() when loaded.
|
||||
#
|
||||
: ${VARIABLE_SELF_INITIALIZE=1}
|
||||
|
||||
#
|
||||
# File to write when f_dump_variables() is called.
|
||||
#
|
||||
: ${VARIABLE_DUMPFILE:=/etc/bsdconfig.vars}
|
||||
|
||||
############################################################ FUNCTIONS
|
||||
|
||||
# f_variable_new $handle $variable
|
||||
#
|
||||
# Register a new variable named $variable with the given reference-handle
|
||||
# $handle. The environment variable $handle is set to $variable allowing you to
|
||||
# use the f_getvar() function (from common.subr) with $handle to get the value
|
||||
# of environment variable $variable. For example:
|
||||
#
|
||||
# f_variable_new VAR_ABC abc
|
||||
#
|
||||
# allows the later indirection:
|
||||
#
|
||||
# f_getvar $VAR_ABC
|
||||
#
|
||||
# to return the value of environment variable `abc'. Variables registered in
|
||||
# this manner are recorded in the $VARIABLES environment variable for later
|
||||
# allowing dynamic enumeration of so-called `registered/advertised' variables.
|
||||
#
|
||||
f_variable_new()
|
||||
{
|
||||
local handle="$1" variable="$2"
|
||||
[ "$handle" ] || return $FAILURE
|
||||
f_dprintf "variable.subr: New variable %s -> %s" "$handle" "$variable"
|
||||
setvar $handle $variable
|
||||
VARIABLES="$VARIABLES${VARIABLES:+ }$handle"
|
||||
}
|
||||
|
||||
# f_variable_get_value $var [ $fmt [ $opts ... ] ]
|
||||
#
|
||||
# Unless nonInteractive is set, prompt the user with a given value (pre-filled
|
||||
# with the value of $var) and give them the chance to change the value.
|
||||
#
|
||||
# Unlike f_getvar() (from common.subr) which can return a variable to the
|
||||
# caller on standard output, this function has no [meaningful] output.
|
||||
#
|
||||
# Returns success unless $var is either NULL or missing.
|
||||
#
|
||||
f_variable_get_value()
|
||||
{
|
||||
local var="$1" cp
|
||||
|
||||
[ "$var" ] || return $FAILURE
|
||||
|
||||
if ! { f_getvar $var cp && ! f_interactive; }; then
|
||||
shift 1 # var
|
||||
cp=$( f_dialog_input "$( printf "$@" )" "$cp" ) &&
|
||||
setvar $var "$cp"
|
||||
fi
|
||||
|
||||
return $SUCCESS
|
||||
}
|
||||
|
||||
# f_variable_set_defaults
|
||||
#
|
||||
# Installs sensible defaults for registered/advertised variables.
|
||||
#
|
||||
f_variable_set_defaults()
|
||||
{
|
||||
#
|
||||
# Initialize various user-edittable values to their defaults
|
||||
#
|
||||
setvar $VAR_RELNAME "$UNAME_R"
|
||||
|
||||
f_dprintf "f_variable_set_defaults: Defaults initialized."
|
||||
}
|
||||
|
||||
# f_dump_variables
|
||||
#
|
||||
# Dump a list of registered/advertised variables and their respective values to
|
||||
# $VARIABLE_DUMPFILE. Returns success unless the file couldn't be written. If
|
||||
# an error occurs, it is displayed using f_show_msg() (from common.subr).
|
||||
#
|
||||
f_dump_variables()
|
||||
{
|
||||
local err sanitize_awk="{ gsub(/'/, \"'\\\\''\"); print }"
|
||||
if ! err=$(
|
||||
( for handle in $VARIABLES; do
|
||||
f_getvar $handle var || continue
|
||||
f_getvar $var value || continue
|
||||
value=$( echo "$value" | awk "$sanitize_awk" )
|
||||
printf "%s='%s'\n" "$var" "$value"
|
||||
done > "$VARIABLE_DUMPFILE" ) 2>&1
|
||||
); then
|
||||
f_show_msg "%s" "$err"
|
||||
return $FAILURE
|
||||
fi
|
||||
}
|
||||
|
||||
# f_debugging
|
||||
#
|
||||
# Are we in debug mode? Returns success if extra DEBUG information has been
|
||||
# requested (by setting $debug to non-NULL), otherwise false.
|
||||
#
|
||||
f_debugging()
|
||||
{
|
||||
local value
|
||||
f_getvar $VAR_DEBUG value && [ "$value" ]
|
||||
}
|
||||
|
||||
# f_interactive()
|
||||
#
|
||||
# Are we running interactively? Return error if $nonInteractive is set and non-
|
||||
# NULL, otherwise return success.
|
||||
#
|
||||
f_interactive()
|
||||
{
|
||||
local value
|
||||
! f_getvar $VAR_NONINTERACTIVE value || [ ! "$value" ]
|
||||
}
|
||||
|
||||
############################################################ MAIN
|
||||
|
||||
#
|
||||
# Variables that can be tweaked from config files
|
||||
#
|
||||
f_variable_new VAR_CONFIG_FILE configFile
|
||||
f_variable_new VAR_DEBUG debug
|
||||
f_variable_new VAR_DEBUG_FILE debugFile
|
||||
f_variable_new VAR_NO_ERROR noError
|
||||
f_variable_new VAR_NONINTERACTIVE nonInteractive
|
||||
f_variable_new VAR_RELNAME releaseName
|
||||
|
||||
#
|
||||
# Self-initialize unless requested otherwise
|
||||
#
|
||||
f_dprintf "%s: VARIABLE_SELF_INITIALIZE=[%s]" \
|
||||
variable.subr "$VARIABLE_SELF_INITIALIZE"
|
||||
case "$VARIABLE_SELF_INITIALIZE" in
|
||||
""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
|
||||
*) f_variable_set_defaults
|
||||
esac
|
||||
|
||||
f_dprintf "%s: Successfully loaded." variable.subr
|
||||
|
||||
fi # ! $_VARIABLE_SUBR
|
Loading…
Reference in New Issue
Block a user