Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 5 Jan 2013 02:08:48 +0000 (UTC)
From:      Devin Teske <dteske@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r245052 - in head/usr.sbin/bsdconfig: . include share
Message-ID:  <201301050208.r0528m5x023476@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dteske
Date: Sat Jan  5 02:08:47 2013
New Revision: 245052
URL: http://svnweb.freebsd.org/changeset/base/245052

Log:
  Add support for scripting (sysinstall style).
  
  Reviewed by:	jilles

Added:
  head/usr.sbin/bsdconfig/share/script.subr   (contents, props changed)
  head/usr.sbin/bsdconfig/share/variable.subr   (contents, props changed)
Modified:
  head/usr.sbin/bsdconfig/USAGE
  head/usr.sbin/bsdconfig/bsdconfig
  head/usr.sbin/bsdconfig/bsdconfig.8
  head/usr.sbin/bsdconfig/include/messages.subr
  head/usr.sbin/bsdconfig/share/Makefile
  head/usr.sbin/bsdconfig/share/common.subr

Modified: head/usr.sbin/bsdconfig/USAGE
==============================================================================
--- head/usr.sbin/bsdconfig/USAGE	Sat Jan  5 00:27:08 2013	(r245051)
+++ head/usr.sbin/bsdconfig/USAGE	Sat Jan  5 02:08:47 2013	(r245052)
@@ -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.

Modified: head/usr.sbin/bsdconfig/bsdconfig
==============================================================================
--- head/usr.sbin/bsdconfig/bsdconfig	Sat Jan  5 00:27:08 2013	(r245051)
+++ head/usr.sbin/bsdconfig/bsdconfig	Sat Jan  5 02:08:47 2013	(r245052)
@@ -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
 #

Modified: head/usr.sbin/bsdconfig/bsdconfig.8
==============================================================================
--- head/usr.sbin/bsdconfig/bsdconfig.8	Sat Jan  5 00:27:08 2013	(r245051)
+++ head/usr.sbin/bsdconfig/bsdconfig.8	Sat Jan  5 02:08:47 2013	(r245052)
@@ -85,6 +85,17 @@ a master menu listing the available comm
 .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

Modified: head/usr.sbin/bsdconfig/include/messages.subr
==============================================================================
--- head/usr.sbin/bsdconfig/include/messages.subr	Sat Jan  5 00:27:08 2013	(r245051)
+++ head/usr.sbin/bsdconfig/include/messages.subr	Sat Jan  5 02:08:47 2013	(r245052)
@@ -34,6 +34,7 @@ msg_becoming_root_via_sudo="Becoming roo
 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-mod
 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"

Modified: head/usr.sbin/bsdconfig/share/Makefile
==============================================================================
--- head/usr.sbin/bsdconfig/share/Makefile	Sat Jan  5 00:27:08 2013	(r245051)
+++ head/usr.sbin/bsdconfig/share/Makefile	Sat Jan  5 02:08:47 2013	(r245052)
@@ -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}

Modified: head/usr.sbin/bsdconfig/share/common.subr
==============================================================================
--- head/usr.sbin/bsdconfig/share/common.subr	Sat Jan  5 00:27:08 2013	(r245051)
+++ head/usr.sbin/bsdconfig/share/common.subr	Sat Jan  5 02:08:47 2013	(r245052)
@@ -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

Added: head/usr.sbin/bsdconfig/share/script.subr
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bsdconfig/share/script.subr	Sat Jan  5 02:08:47 2013	(r245052)
@@ -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

Added: head/usr.sbin/bsdconfig/share/variable.subr
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bsdconfig/share/variable.subr	Sat Jan  5 02:08:47 2013	(r245052)
@@ -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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201301050208.r0528m5x023476>