aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/bsdconfig/share
diff options
context:
space:
mode:
authorSimon J. Gerraty <sjg@FreeBSD.org>2014-04-28 07:50:45 +0000
committerSimon J. Gerraty <sjg@FreeBSD.org>2014-04-28 07:50:45 +0000
commit3b8f08459569bf0faa21473e5cec2491e95c9349 (patch)
tree80f45dd81ca716bcd7ca9674581e1fc40b93cd34 /usr.sbin/bsdconfig/share
parent9d2ab4a62d6733c45958627ac113bdbd818d1e2a (diff)
parentb2ba55951383498f252746f618d513139da06e8e (diff)
Notes
Diffstat (limited to 'usr.sbin/bsdconfig/share')
-rw-r--r--usr.sbin/bsdconfig/share/Makefile5
-rw-r--r--usr.sbin/bsdconfig/share/common.subr390
-rw-r--r--usr.sbin/bsdconfig/share/device.subr1495
-rw-r--r--usr.sbin/bsdconfig/share/dialog.subr111
-rw-r--r--usr.sbin/bsdconfig/share/geom.subr430
-rw-r--r--usr.sbin/bsdconfig/share/keymap.subr263
-rw-r--r--usr.sbin/bsdconfig/share/media/cdrom.subr69
-rw-r--r--usr.sbin/bsdconfig/share/media/common.subr27
-rw-r--r--usr.sbin/bsdconfig/share/media/directory.subr8
-rw-r--r--usr.sbin/bsdconfig/share/media/dos.subr47
-rw-r--r--usr.sbin/bsdconfig/share/media/floppy.subr61
-rw-r--r--usr.sbin/bsdconfig/share/media/ftp.subr35
-rw-r--r--usr.sbin/bsdconfig/share/media/http.subr74
-rw-r--r--usr.sbin/bsdconfig/share/media/nfs.subr42
-rw-r--r--usr.sbin/bsdconfig/share/media/tcpip.subr141
-rw-r--r--usr.sbin/bsdconfig/share/media/ufs.subr41
-rw-r--r--usr.sbin/bsdconfig/share/media/usb.subr48
-rw-r--r--usr.sbin/bsdconfig/share/mustberoot.subr17
-rwxr-xr-xusr.sbin/bsdconfig/share/packages/categories.subr4
-rwxr-xr-xusr.sbin/bsdconfig/share/packages/index.subr220
-rwxr-xr-xusr.sbin/bsdconfig/share/packages/packages.subr125
-rw-r--r--usr.sbin/bsdconfig/share/script.subr36
-rw-r--r--usr.sbin/bsdconfig/share/strings.subr158
-rw-r--r--usr.sbin/bsdconfig/share/struct.subr2
-rw-r--r--usr.sbin/bsdconfig/share/sysrc.subr55
-rw-r--r--usr.sbin/bsdconfig/share/variable.subr42
26 files changed, 2981 insertions, 965 deletions
diff --git a/usr.sbin/bsdconfig/share/Makefile b/usr.sbin/bsdconfig/share/Makefile
index 3392e2ac53e70..5b81af4312126 100644
--- a/usr.sbin/bsdconfig/share/Makefile
+++ b/usr.sbin/bsdconfig/share/Makefile
@@ -5,8 +5,9 @@ NO_OBJ=
SUBDIR= media packages
FILESDIR= ${SHAREDIR}/bsdconfig
-FILES= common.subr device.subr dialog.subr mustberoot.subr \
- script.subr strings.subr struct.subr sysrc.subr variable.subr
+FILES= common.subr device.subr dialog.subr geom.subr keymap.subr \
+ mustberoot.subr script.subr strings.subr struct.subr \
+ sysrc.subr variable.subr
beforeinstall:
mkdir -p ${DESTDIR}${FILESDIR}
diff --git a/usr.sbin/bsdconfig/share/common.subr b/usr.sbin/bsdconfig/share/common.subr
index d087ccacb1dbc..762fd39e0342c 100644
--- a/usr.sbin/bsdconfig/share/common.subr
+++ b/usr.sbin/bsdconfig/share/common.subr
@@ -1,7 +1,7 @@
if [ ! "$_COMMON_SUBR" ]; then _COMMON_SUBR=1
#
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -58,9 +58,16 @@ FAILURE=1
#
# Operating environment details
#
-export UNAME_S="$(uname -s)" # Operating System (i.e. FreeBSD)
-export UNAME_P="$(uname -p)" # Processor Architecture (i.e. i386)
-export UNAME_R="$(uname -r)" # Release Level (i.e. X.Y-RELEASE)
+export UNAME_S="$( uname -s )" # Operating System (i.e. FreeBSD)
+export UNAME_P="$( uname -p )" # Processor Architecture (i.e. i386)
+export UNAME_M="$( uname -m )" # Machine platform (i.e. i386)
+export UNAME_R="$( uname -r )" # Release Level (i.e. X.Y-RELEASE)
+if [ ! "${PKG_ABI+set}" ]; then
+ export PKG_ABI="$(
+ ASSUME_ALWAYS_YES=1 pkg -vv 2> /dev/null |
+ awk '$1=="ABI"{print $3;exit}'
+ )"
+fi
#
# Default behavior is to call f_debug_init() automatically when loaded.
@@ -68,6 +75,14 @@ export UNAME_R="$(uname -r)" # Release Level (i.e. X.Y-RELEASE)
: ${DEBUG_SELF_INITIALIZE=1}
#
+# Default behavior of f_debug_init() is to truncate $debugFile (set to NULL to
+# disable truncating the debug file when initializing). To get child processes
+# to append to the same log file, export this variarable (with a NULL value)
+# and also export debugFile with the desired value.
+#
+: ${DEBUG_INITIALIZE_FILE=1}
+
+#
# Define standard optstring arguments that should be supported by all programs
# using this include (unless DEBUG_SELF_INITIALIZE is set to NULL to prevent
# f_debug_init() from autamatically processing "$@" for the below arguments):
@@ -106,7 +121,7 @@ GETOPTS_ALLFLAGS="${GETOPTS_ALLFLAGS}0123456789"
############################################################ FUNCTIONS
-# f_dprintf $fmt [ $opts ... ]
+# f_dprintf $format [$arguments ...]
#
# Sensible debug function. Override in ~/.bsdconfigrc if desired.
# See /usr/share/examples/bsdconfig/bsdconfigrc for example.
@@ -138,7 +153,7 @@ f_debug_init()
# Process stored command-line arguments
#
set -- $ARGV
- local OPTIND
+ local OPTIND OPTARG flag
f_dprintf "f_debug_init: ARGV=[%s] GETOPTS_STDARGS=[%s]" \
"$ARGV" "$GETOPTS_STDARGS"
while getopts "$GETOPTS_STDARGS$GETOPTS_EXTRA$GETOPTS_ALLFLAGS" flag \
@@ -164,18 +179,17 @@ f_debug_init()
[ "$debugFile" ] && export debugFile
#
- # Truncate the debug file upon. Note that we will trim a leading plus
- # (`+') from the value of debugFile to support persistant meaning that
- # f_dprintf() should print both to standard output and $debugFile
- # (minus the leading plus, of course).
+ # Truncate debug file unless requested otherwise. Note that we will
+ # trim a leading plus (`+') from the value of debugFile to support
+ # persistant meaning that f_dprintf() should print both to standard
+ # output and $debugFile (minus the leading plus, of course).
#
local _debug_file="${debugFile#+}"
- if [ "$_debug_file" ]; then
+ if [ "$_debug_file" -a "$DEBUG_INITIALIZE_FILE" ]; then
if ( umask 022 && :> "$_debug_file" ); then
f_dprintf "Successfully initialized debugFile \`%s'" \
"$_debug_file"
- [ "${debug+set}" ] ||
- debug=1 # turn debugging on if not set
+ f_isset debug || debug=1 # turn debugging on if not set
else
unset debugFile
f_dprintf "Unable to initialize debugFile \`%s'" \
@@ -184,16 +198,16 @@ f_debug_init()
fi
}
-# f_err $fmt [ $opts ... ]
+# f_err $format [$arguments ...]
#
# Print a message to stderr (fd=2).
#
f_err()
{
- printf "$@" >&${TERMINAL_STDERR_PASSTHRU:-2}
+ printf "$@" >&2
}
-# f_quietly $command [ $arguments ... ]
+# f_quietly $command [$arguments ...]
#
# Run a command quietly (quell any output to stdout or stderr)
#
@@ -256,9 +270,9 @@ 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 ${__var_to_set:-value}=\"\${$__var_to_get}\"
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"; }
@@ -275,7 +289,7 @@ f_isset()
eval [ \"\${${1%%[$IFS]*}+set}\" ]
}
-# f_die [ $status [ $fmt [ $opts ... ]]]
+# f_die [$status [$format [$arguments ...]]]
#
# Abruptly terminate due to an error optionally displaying a message in a
# dialog box using printf(1) syntax.
@@ -309,7 +323,7 @@ f_interrupt()
f_die
}
-# f_show_info $fmt [ $opts ... ]
+# f_show_info $format [$arguments ...]
#
# Display a message in a dialog infobox using printf(1) syntax.
#
@@ -330,7 +344,7 @@ f_show_info()
fi
}
-# f_show_msg $fmt [ $opts ... ]
+# f_show_msg $format [$arguments ...]
#
# Display a message in a dialog box using printf(1) syntax.
#
@@ -351,8 +365,29 @@ f_show_msg()
fi
}
+# f_show_err $format [$arguments ...]
+#
+# Display a message in a dialog box with ``Error'' i18n title (overridden by
+# setting msg_error) using printf(1) syntax.
+#
+f_show_err()
+{
+ local msg
+ msg=$( printf "$@" )
+
+ : ${msg:=${msg_an_unknown_error_occurred:-An unknown error occurred}}
-# f_yesno $fmt [ $opts ... ]
+ if [ "$_DIALOG_SUBR" ]; then
+ f_dialog_title "${msg_error:-Error}"
+ f_dialog_msgbox "$msg"
+ f_dialog_title_restore
+ else
+ dialog --title "${msg_error:-Error}" --msgbox "$msg" 0 0
+ fi
+ return $SUCCESS
+}
+
+# f_yesno $format [$arguments ...]
#
# Display a message in a dialog yes/no box using printf(1) syntax.
#
@@ -373,7 +408,7 @@ f_yesno()
fi
}
-# f_noyes $fmt [ $opts ... ]
+# f_noyes $format [$arguments ...]
#
# Display a message in a dialog yes/no box using printf(1) syntax.
# NOTE: THis is just like the f_yesno function except "No" is default.
@@ -466,7 +501,7 @@ f_include_lang()
fi
}
-# f_usage $file [ $key1 $value1 ... ]
+# 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
@@ -485,7 +520,7 @@ f_include_lang()
# 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.
+# text "BAR" before being 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.
@@ -527,7 +562,7 @@ f_usage()
exit $FAILURE
}
-# f_index_file $keyword
+# f_index_file $keyword [$var_to_set]
#
# Process all INDEX files known to bsdconfig and return the path to first file
# containing a menu_selection line with a keyword portion matching $keyword.
@@ -537,6 +572,9 @@ f_usage()
#
# If no file is found, error status is returned along with the NULL string.
#
+# If $var_to_set is NULL or missing, output is printed to stdout (which is less
+# recommended due to performance degradation; in a loop for example).
+#
# 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.
#
@@ -553,33 +591,55 @@ END { exit ! found }
'
f_index_file()
{
- local keyword="$1"
- local lang="${LANG:-$LC_ALL}"
+ local __keyword="$1" __var_to_set="$2"
+ local __lang="${LANG:-$LC_ALL}"
+ local __indexes="$BSDCFG_LIBE${BSDCFG_LIBE:+/}*/INDEX"
- f_dprintf "f_index_file: keyword=[%s] lang=[%s]" "$keyword" "$lang"
+ f_dprintf "f_index_file: keyword=[%s] lang=[%s]" "$__keyword" "$__lang"
- if [ "$lang" ]; then
- awk -v keyword="$keyword" "$f_index_file_awk" \
- $BSDCFG_LIBE${BSDCFG_LIBE:+/}*/INDEX.$lang &&
- return $SUCCESS
+ if [ "$__lang" ]; then
+ if [ "$__var_to_set" ]; then
+ eval "$__var_to_set"='"$( awk -v keyword="$__keyword" \
+ "$f_index_file_awk" $__indexes.$__lang
+ )"' && return $SUCCESS
+ else
+ awk -v keyword="$__keyword" "$f_index_file_awk" \
+ $__indexes.$__lang && return $SUCCESS
+ fi
# No match, fall-thru to non-i18n sources
fi
- awk -v keyword="$keyword" "$f_index_file_awk" \
- $BSDCFG_LIBE${BSDCFG_LIBE:+/}*/INDEX && return $SUCCESS
+ if [ "$__var_to_set" ]; then
+ eval "$__var_to_set"='"$( awk -v keyword="$__keyword" \
+ "$f_index_file_awk" $__indexes )"' && return $SUCCESS
+ else
+ awk -v keyword="$__keyword" "$f_index_file_awk" $__indexes &&
+ return $SUCCESS
+ fi
# No match? Fall-thru to `local' libexec sources (add-on modules)
[ "$BSDCFG_LOCAL_LIBE" ] || return $FAILURE
- if [ "$lang" ]; then
- awk -v keyword="$keyword" "$f_index_file_awk" \
- $BSDCFG_LOCAL_LIBE/*/INDEX.$lang && return $SUCCESS
+ __indexes="$BSDCFG_LOCAL_LIBE/*/INDEX"
+ if [ "$__lang" ]; then
+ if [ "$__var_to_set" ]; then
+ eval "$__var_to_set"='"$( awk -v keyword="$__keyword" \
+ "$f_index_file_awk" $__indexes.$__lang
+ )"' && return $SUCCESS
+ else
+ awk -v keyword="$__keyword" "$f_index_file_awk" \
+ $__indexes.$__lang && return $SUCCESS
+ fi
# No match, fall-thru to non-i18n sources
fi
- awk -v keyword="$keyword" "$f_index_file_awk" \
- $BSDCFG_LOCAL_LIBE/*/INDEX
+ if [ "$__var_to_set" ]; then
+ eval "$__var_to_set"='$( awk -v keyword="$__keyword" \
+ "$f_index_file_awk" $__indexes )"'
+ else
+ awk -v keyword="$__keyword" "$f_index_file_awk" $__indexes
+ fi
}
-# f_index_menusel_keyword $indexfile $pgm
+# f_index_menusel_keyword $indexfile $pgm [$var_to_set]
#
# Process $indexfile and return only the keyword portion of the menu_selection
# line with a command portion matching $pgm.
@@ -596,6 +656,9 @@ f_index_file()
#
# If $indexfile does not exist, error status is returned with NULL.
#
+# If $var_to_set is NULL or missing, output is printed to stdout (which is less
+# recommended due to performance degradation; in a loop for example).
+#
# 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.
#
@@ -626,24 +689,23 @@ END { exit ! found }
'
f_index_menusel_keyword()
{
- local indexfile="$1" pgm="$2"
- local lang="${LANG:-$LC_ALL}"
+ local __indexfile="$1" __pgm="$2" __var_to_set="$3"
+ local __lang="${LANG:-$LC_ALL}" __file="$__indexfile"
+ [ -f "$__indexfile.$__lang" ] && __file="$__indexfile.$__lang"
f_dprintf "f_index_menusel_keyword: index=[%s] pgm=[%s] lang=[%s]" \
- "$indexfile" "$pgm" "$lang"
+ "$__file" "$__pgm" "$__lang"
- if [ -f "$indexfile.$lang" ]; then
- awk -v pgm="$pgm" \
- "$f_index_menusel_keyword_awk" \
- "$indexfile.$lang"
- elif [ -f "$indexfile" ]; then
- awk -v pgm="$pgm" \
- "$f_index_menusel_keyword_awk" \
- "$indexfile"
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$( awk \
+ -v pgm="$__pgm" "$f_index_menusel_keyword_awk" "$__file"
+ )"
+ else
+ awk -v pgm="$__pgm" "$f_index_menusel_keyword_awk" "$__file"
fi
}
-# f_index_menusel_command $indexfile $keyword
+# f_index_menusel_command $indexfile $keyword [$var_to_set]
#
# Process $indexfile and return only the command portion of the menu_selection
# line with a keyword portion matching $keyword.
@@ -659,6 +721,9 @@ f_index_menusel_keyword()
#
# If $indexfile doesn't exist, error status is returned with NULL.
#
+# If $var_to_set is NULL or missing, output is printed to stdout (which is less
+# recommended due to performance degradation; in a loop for example).
+#
# 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.
#
@@ -689,37 +754,34 @@ END { exit ! found }
'
f_index_menusel_command()
{
- local indexfile="$1" keyword="$2" command
- local lang="${LANG:-$LC_ALL}"
+ local __indexfile="$1" __keyword="$2" __var_to_set="$3" __command
+ local __lang="${LANG:-$LC_ALL}" __file="$__indexfile"
+ [ -f "$__indexfile.$__lang" ] && __file="$__indexfile.$__lang"
f_dprintf "f_index_menusel_command: index=[%s] key=[%s] lang=[%s]" \
- "$indexfile" "$keyword" "$lang"
+ "$__file" "$__keyword" "$__lang"
- if [ -f "$indexfile.$lang" ]; then
- command=$( awk -v key="$keyword" \
- "$f_index_menusel_command_awk" \
- "$indexfile.$lang" ) || return $FAILURE
- elif [ -f "$indexfile" ]; then
- command=$( awk -v key="$keyword" \
- "$f_index_menusel_command_awk" \
- "$indexfile" ) || return $FAILURE
- else
- return $FAILURE
- fi
+ [ -f "$__file" ] || return $FAILURE
+ __command=$( awk -v key="$__keyword" \
+ "$f_index_menusel_command_awk" "$__file" ) || return $FAILURE
#
# If the command pathname is not fully qualified fix-up/force to be
# relative to the $indexfile directory.
#
- case "$command" in
+ case "$__command" in
/*) : already fully qualified ;;
*)
- local indexdir="${indexfile%/*}"
- [ "$indexdir" != "$indexfile" ] || indexdir="."
- command="$indexdir/$command"
+ local __indexdir="${__indexfile%/*}"
+ [ "$__indexdir" != "$__indexfile" ] || __indexdir="."
+ __command="$__indexdir/$__command"
esac
- echo "$command"
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$__command"
+ else
+ echo "$__command"
+ fi
}
# f_running_as_init
@@ -736,14 +798,192 @@ f_running_as_init()
}
# f_mounted $local_directory
+# f_mounted -b $device
#
-# Return success if a filesystem is mounted on a particular directory.
+# Return success if a filesystem is mounted on a particular directory. If `-b'
+# is present, instead check that the block device (or a partition thereof) is
+# mounted.
#
f_mounted()
{
- local dir="$1"
- [ -d "$dir" ] || return $FAILURE
- mount | grep -Eq " on $dir \([^)]+\)$"
+ local OPTIND OPTARG flag use_device=
+ while getopts b flag; do
+ case "$flag" in
+ b) use_device=1 ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+ if [ "$use_device" ]; then
+ local device="$1"
+ mount | grep -Eq \
+ "^$device([[:space:]]|p[0-9]|s[0-9]|\.nop|\.eli)"
+ else
+ [ -d "$dir" ] || return $FAILURE
+ mount | grep -Eq " on $dir \([^)]+\)$"
+ fi
+ # Return status is that of last grep(1)
+}
+
+# f_eval_catch [-de] [-k $var_to_set] $funcname $utility \
+# $format [$arguments ...]
+#
+# Silently evaluate a command in a sub-shell and test for error. If debugging
+# is enabled a copy of the command and its output is sent to debug (either
+# stdout or file depending on environment). If an error occurs, output of the
+# command is displayed in a dialog(1) msgbox using the [above] f_show_err()
+# function (unless optional `-d' flag is given, then no dialog).
+#
+# The $funcname argument is sent to debugging while the $utility argument is
+# used in the title of the dialog box. The command that is executed as well as
+# sent to debugging with $funcname is the product of the printf(1) syntax
+# produced by $format with optional $arguments.
+#
+# The following options are supported:
+#
+# -d Do not use dialog(1).
+# -e Produce error text from failed command on stderr.
+# -k var Save output from the command in var.
+#
+# Example 1:
+#
+# debug=1
+# f_eval_catch myfunc echo 'echo "%s"' "Hello, World!"
+#
+# Produces the following debug output:
+#
+# DEBUG: myfunc: echo "Hello, World!"
+# DEBUG: myfunc: retval=0 <output below>
+# Hello, World!
+#
+# Example 2:
+#
+# debug=1
+# f_eval_catch -k contents myfunc cat 'cat "%s"' /some/file
+# # dialog(1) Error ``cat: /some/file: No such file or directory''
+# # contents=[cat: /some/file: No such file or directory]
+#
+# Produces the following debug output:
+#
+# DEBUG: myfunc: cat "/some/file"
+# DEBUG: myfunc: retval=1 <output below>
+# cat: /some/file: No such file or directory
+#
+# Example 3:
+#
+# debug=1
+# echo 123 | f_eval_catch myfunc rev rev
+#
+# Produces the following debug output:
+#
+# DEBUG: myfunc: rev
+# DEBUG: myfunc: retval=0 <output below>
+# 321
+#
+# Example 4:
+#
+# debug=1
+# f_eval_catch myfunc true true
+#
+# Produces the following debug output:
+#
+# DEBUG: myfunc: true
+# DEBUG: myfunc: retval=0 <no output>
+#
+# Example 5:
+#
+# f_eval_catch -de myfunc ls 'ls "%s"' /some/dir
+# # Output on stderr ``ls: /some/dir: No such file or directory''
+#
+# Example 6:
+#
+# f_eval_catch -dek contents myfunc ls 'ls "%s"' /etc
+# # Output from `ls' sent to stderr and also saved in $contents
+#
+f_eval_catch()
+{
+ local __no_dialog= __show_err= __var_to_set=
+
+ #
+ # Process local function arguments
+ #
+ local OPTIND OPTARG __flag
+ while getopts "dek:" __flag > /dev/null; do
+ case "$__flag" in
+ d) __no_dialog=1 ;;
+ e) __show_err=1 ;;
+ k) __var_to_set="$OPTARG" ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ local __funcname="$1" __utility="$2"; shift 2
+ local __cmd __output __retval
+
+ __cmd=$( printf -- "$@" )
+ f_dprintf "%s: %s" "$__funcname" "$__cmd" # Log command *before* eval
+ __output=$( exec 2>&1; eval "$__cmd" )
+ __retval=$?
+ if [ "$__output" ]; then
+ [ "$__show_err" ] && echo "$__output" >&2
+ f_dprintf "%s: retval=%i <output below>\n%s" "$__funcname" \
+ $__retval "$__output"
+ else
+ f_dprintf "%s: retval=%i <no output>" "$__funcname" $__retval
+ fi
+
+ ! [ "$__no_dialog" -o "$nonInteractive" -o $__retval -eq $SUCCESS ] &&
+ msg_error="${msg_error:-Error}${__utility:+: $__utility}" \
+ f_show_err "%s" "$__output"
+ # NB: f_show_err will handle NULL output appropriately
+
+ [ "$__var_to_set" ] && setvar "$__var_to_set" "$__output"
+
+ return $__retval
+}
+
+# f_count $var_to_set arguments ...
+#
+# Sets $var_to_set to the number of arguments minus one (the effective number
+# of arguments following $var_to_set).
+#
+# Example:
+# f_count count dog house # count=[2]
+#
+f_count()
+{
+ setvar "$1" $(( $# - 1 ))
+}
+
+# f_count_ifs $var_to_set string ...
+#
+# Sets $var_to_set to the number of words (split by the internal field
+# separator, IFS) following $var_to_set.
+#
+# Example 1:
+#
+# string="word1 word2 word3"
+# f_count_ifs count "$string" # count=[3]
+# f_count_ifs count $string # count=[3]
+#
+# Example 2:
+#
+# IFS=. f_count_ifs count www.freebsd.org # count=[3]
+#
+# NB: Make sure to use double-quotes if you are using a custom value for IFS
+# and you don't want the current value to effect the result. See example 3.
+#
+# Example 3:
+#
+# string="a-b c-d"
+# IFS=- f_count_ifs count "$string" # count=[3]
+# IFS=- f_count_ifs count $string # count=[4]
+#
+f_count_ifs()
+{
+ local __var_to_set="$1"
+ shift 1
+ set -- $*
+ setvar "$__var_to_set" $#
}
############################################################ MAIN
diff --git a/usr.sbin/bsdconfig/share/device.subr b/usr.sbin/bsdconfig/share/device.subr
index b92080934c19c..d93cd9b60251f 100644
--- a/usr.sbin/bsdconfig/share/device.subr
+++ b/usr.sbin/bsdconfig/share/device.subr
@@ -1,6 +1,6 @@
if [ ! "$_DEVICE_SUBR" ]; then _DEVICE_SUBR=1
#
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
. $BSDCFG_SHARE/common.subr || exit 1
f_dprintf "%s: loading includes..." device.subr
f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/geom.subr
f_include $BSDCFG_SHARE/strings.subr
f_include $BSDCFG_SHARE/struct.subr
@@ -40,114 +41,128 @@ f_include_lang $BSDCFG_LIBE/include/messages.subr
############################################################ GLOBALS
-DEVICES=
-DEVICE_NAMES=
+NDEVICES=0 # Set by f_device_register(), used by f_device_*()
-# A "device" from sysinstall's point of view
+#
+# A "device" from legacy sysinstall's point of view (mostly)
+#
+# NB: Disk devices have their `private' property set to GEOM ident
+# NB: USB devices have their `private' property set to USB disk device name
+#
f_struct_define DEVICE \
- name \
+ capacity \
desc \
devname \
- type \
enabled \
- init \
- get \
- shutdown \
flags \
+ get \
+ init \
+ name \
private \
+ shutdown \
+ type \
volume
# Network devices have their `private' property set to this
f_struct_define DEVICE_INFO \
- use_rtsol use_dhcp ipaddr ipv6addr netmask extras
+ extras \
+ ipaddr \
+ ipv6addr \
+ netmask \
+ use_dhcp \
+ use_rtsol
-setvar DEVICE_TYPE_NONE 1
-setvar DEVICE_TYPE_DISK 2
-setvar DEVICE_TYPE_FLOPPY 3
-setvar DEVICE_TYPE_FTP 4
-setvar DEVICE_TYPE_NETWORK 5
-setvar DEVICE_TYPE_CDROM 6
-setvar DEVICE_TYPE_USB 7
-setvar DEVICE_TYPE_DOS 8
-setvar DEVICE_TYPE_UFS 9
-setvar DEVICE_TYPE_NFS 10
-setvar DEVICE_TYPE_ANY 11
-setvar DEVICE_TYPE_HTTP_PROXY 12
-setvar DEVICE_TYPE_HTTP 13
+#
+# Device types for f_device_register(), f_device_find(), et al.
+#
+setvar DEVICE_TYPE_ANY "any" # Any
+setvar DEVICE_TYPE_NONE "NONE" # Unknown
+setvar DEVICE_TYPE_DISK "DISK" # GEOM `DISK'
+setvar DEVICE_TYPE_FLOPPY "FD" # GEOM `FD'
+setvar DEVICE_TYPE_FTP "FTP" # Dynamic network device
+setvar DEVICE_TYPE_NETWORK "NETWORK" # See f_device_get_all_network
+setvar DEVICE_TYPE_CDROM "CDROM" # GEOM `DISK'
+setvar DEVICE_TYPE_USB "USB" # GEOM `PART'
+setvar DEVICE_TYPE_DOS "DOS" # GEOM `DISK' `PART' or `LABEL'
+setvar DEVICE_TYPE_UFS "UFS" # GEOM `DISK' `PART' or `LABEL'
+setvar DEVICE_TYPE_NFS "NFS" # Dynamic network device
+setvar DEVICE_TYPE_HTTP_PROXY "HTTP_PROXY" # Dynamic network device
+setvar DEVICE_TYPE_HTTP "HTTP" # Dynamic network device
+
+# Network devices have the following flags available
+setvar IF_ETHERNET 1
+setvar IF_WIRELESS 2
+setvar IF_ACTIVE 4
#
# Default behavior is to call f_device_get_all() automatically when loaded.
#
: ${DEVICE_SELF_SCAN_ALL=1}
-############################################################ FUNCTIONS
-
-# f_device_try $name [$i [$var_path]]
#
-# Test a particular device. If $i is given, then $name is expected to contain a
-# single "%d" where $i will be inserted using printf. If $var_path is given,
-# it is used as a variable name to provide the caller the device pathname.
+# Device Catalog variables
#
-# Returns success if the device path exists and is a cdev.
+DEVICE_CATALOG_APPEND_ONLY= # Used by f_device_catalog_set()
+NCATALOG_DEVICES=0 # Used by f_device_catalog_*() and MAIN
+
#
-f_device_try()
-{
- local name="$1" i="$2" var_path="$3" unit
- if [ "$i" ]; then
- unit=$( printf "$name" "$i" )
- else
- unit="$name"
- fi
- case "$unit" in
- /dev/*) : good ;; # already qualified
- *) unit="/dev/$unit" ;;
- esac
- [ "$var_path" ] && setvar "$var_path" "$unit"
- f_dprintf "f_device_try: making sure %s is a device node" "$unit"
- if [ -c "$unit" ]; then
- f_dprintf "f_device_try: %s is a cdev [good]" "$unit"
- return $SUCCESS
- else
- f_dprintf "f_device_try: %s is not a cdev [skip]" "$unit"
- return $FAILURE
- fi
-}
+# A ``catalog'' device is for mapping GEOM devices to media devices (for
+# example, determining if a $GEOM_CLASS_DISK geom is $DEVICE_TYPE_CDROM or
+# $DEVICE_TYPE_DISK) and also getting default descriptions for devices that
+# either lack a GEOM provided description or lack a presence in GEOM)
+#
+f_struct_define CATALOG_DEVICE \
+ desc \
+ name \
+ type
+
+############################################################ FUNCTIONS
-# f_device_register $name $desc $devname $type $enabled $init_function \
-# $get_function $shutdown_function $private
+# f_device_register $var_to_set $name $desc $devname $type $enabled
+# $init_function $get_function $shutdown_function
+# $private $capacity
#
-# Register a device. A `structure' (see struct.subr) is created with the name
-# device_$name (so make sure $name contains only alpha-numeric characters or
-# the underscore, `_'). The remaining arguments after $name correspond to the
-# properties of the `DEVICE' structure-type (defined above).
+# Register a device. A `structure' (see struct.subr) is created and if
+# $var_to_set is non-NULL, upon success holds the name of the struct created.
+# The remaining positional arguments correspond to the properties of the
+# `DEVICE' structure-type to be assigned (defined above).
#
-# If not already registered, the device is then appended to the DEVICES
-# environment variable, a space-separated list of all registered devices.
+# If not already registered (based on $name and $type), a new device is created
+# and $NDEVICES is incremented.
#
f_device_register()
{
- local name="$1" desc="$2" devname="$3" type="$4" enabled="$5"
- local init_func="$6" get_func="$7" shutdown_func="$8" private="$9"
+ local __var_to_set="$1" __name="$2" __desc="$3" __devname="$4"
+ local __type="$5" __enabled="$6" __init_func="$7" __get_func="$8"
+ local __shutdown_func="$9" __private="${10}" __capacity="${11}"
- f_struct_new DEVICE "device_$name" || return $FAILURE
- device_$name set name "$name"
- device_$name set desc "$desc"
- device_$name set devname "$devname"
- device_$name set type "$type"
- device_$name set enabled "$enabled"
- device_$name set init "$init_func"
- device_$name set get "$get_func"
- device_$name set shutdown "$shutdown_func"
- device_$name set private "$private"
+ # Required parameter(s)
+ [ "$__name" ] || return $FAILURE
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "" || return $FAILURE
+ fi
- # Scan our global register to see if it needs ammending
- local dev found=
- for dev in $DEVICES; do
- [ "$dev" = "$name" ] || continue
- found=1 && break
- done
- [ "$found" ] || DEVICES="$DEVICES $name"
+ local __device
+ if f_device_find -1 "$__name" "$__type" __device; then
+ f_struct_free "$__device"
+ f_struct_new DEVICE "$__device" || return $FAILURE
+ else
+ __device=device_$(( NDEVICES + 1 ))
+ f_struct_new DEVICE "$__device" || return $FAILURE
+ NDEVICES=$(( $NDEVICES + 1 ))
+ fi
+ $__device set name "$__name"
+ $__device set desc "$__desc"
+ $__device set devname "$__devname"
+ $__device set type "$__type"
+ $__device set enabled "$__enabled"
+ $__device set init "$__init_func"
+ $__device set get "$__get_func"
+ $__device set shutdown "$__shutdown_func"
+ $__device set private "$__private"
+ $__device set capacity "$__capacity"
+ [ "$__var_to_set" ] && setvar "$__var_to_set" "$__device"
return $SUCCESS
}
@@ -157,33 +172,94 @@ f_device_register()
#
f_device_reset()
{
- local dev
- for dev in $DEVICES; do
- f_device_shutdown $dev
+ local n=1
+ while [ $n -le $NDEVICES ]; do
+ f_device_shutdown device_$n
#
- # XXX this potentially leaks $dev->private if it's being
+ # XXX This potentially leaks $dev->private if it's being
# used to point to something dynamic, but you're not supposed
# to call this routine at such times that some open instance
- # has its private member pointing somewhere anyway. XXX
+ # has its private member pointing somewhere anyway.
#
- f_struct_free device_$dev
+ f_struct_free device_$n
+
+ n=$(( $n + 1 ))
+ done
+ NDEVICES=0
+}
+
+# f_device_reset_network
+#
+# Reset the registered network device chain.
+#
+f_device_reset_network()
+{
+ local n=1 device type private i
+ while [ $n -le $NDEVICES ]; do
+ device=device_$n
+ f_struct $device || continue
+ $device get type type
+ [ "$type" = "$DEVICE_TYPE_NETWORK" ] || continue
+
+ #
+ # Leave the device up (don't call shutdown routine)
+ #
+
+ # Network devices may have DEVICE_INFO private member
+ $device get private private
+ [ "$private" ] && f_struct_free "$private"
+
+ # Free the network device
+ f_struct_free $device
+
+ # Fill the gap we just created
+ i=$n
+ while [ $i -lt $NDEVICES ]; do
+ f_struct_copy device_$(( $i + 1 )) device_$i
+ done
+ f_struct_free device_$NDEVICES
+
+ # Finally decrement the number of devices
+ NDEVICES=$(( $NDEVICES - 1 ))
+
+ n=$(( $n + 1 ))
done
- DEVICES=
}
# f_device_get_all
#
-# Get all device information for devices we have attached.
+# Get all device information for all devices.
#
f_device_get_all()
{
- local devname desc
+ local devname type desc capacity
f_dprintf "f_device_get_all: Probing devices..."
f_dialog_info "$msg_probing_devices_please_wait_this_can_take_a_while"
# First go for the network interfaces
+ f_device_get_all_network
+
+ # Next, go for the GEOM devices we might want to use as media
+ local geom geoms geom_name
+ debug= f_geom_find "" $GEOM_CLASS_DEV geoms
+ for geom in $geoms; do
+ if ! f_device_probe_geom $geom; then
+ debug= $geom get name geom_name
+ f_dprintf "WARNING! Unable to classify %s as %s" \
+ "GEOM device $geom_name" "media source"
+ fi
+ done
+}
+
+# f_device_get_all_network
+#
+# Get all network device information for attached network devices.
+#
+f_device_get_all_network()
+{
+ local devname desc device flags
for devname in $( ifconfig -l ); do
# Eliminate network devices that don't make sense
case "$devname" in
@@ -193,232 +269,618 @@ f_device_get_all()
# Try and find its description
f_device_desc "$devname" $DEVICE_TYPE_NETWORK desc
- f_dprintf "Found a network device named %s" "$devname"
- f_device_register $devname \
- "$desc" "$devname" $DEVICE_TYPE_NETWORK 1 \
- f_media_init_network "" f_media_shutdown_network ""
+ f_dprintf "Found network device named %s" "$devname"
+ debug= f_device_register device $devname "$desc" \
+ "$devname" $DEVICE_TYPE_NETWORK 1 \
+ f_media_init_network "" f_media_shutdown_network "" -1
+
+ # Set flags based on media and status
+ flags=0
+ eval "$( ifconfig $devname 2> /dev/null | awk -v var=flags '
+ function _or(var, mask) {
+ printf "%s=$(( $%s | $%s ))\n", var, var, mask
+ }
+ BEGIN { S = "[[:space:]]+" }
+ {
+ if (!match($0, "^" S "(media|status):" S)) next
+ value = substr($0, RLENGTH + 1)
+ if ($1 == "media:") {
+ if (value ~ /Ethernet/) _or(var, "IF_ETHERNET")
+ if (value ~ /802\.11/) _or(var, "IF_WIRELESS")
+ } else if ($1 == "status:") {
+ if (value ~ /^active/) _or(var, "IF_ACTIVE")
+ }
+ }' )"
+ $device set flags $flags
done
+}
+
+# f_device_rescan
+#
+# Rescan all devices, after closing previous set - convenience function.
+#
+f_device_rescan()
+{
+ f_device_reset
+ f_geom_rescan
+ f_device_get_all
+}
+
+# f_device_rescan_network
+#
+# Rescan all network devices, after closing previous set - for convenience.
+#
+f_device_rescan_network()
+{
+ f_device_reset_network
+ f_device_get_all_network
+}
+
+# f_device_probe_geom $geom
+#
+# Probe a single GEOM device and if it can be classified as a media source,
+# register it using f_device_register() with known type-specific arguments.
+#
+f_device_probe_geom()
+{
+ local geom="$1"
+
+ f_struct "$geom" || return $FAILURE
+
+ # geom associated variables
+ local geom_name geom_consumer provider_ref geom_provider=
+ local provider_geom provider_config provider_class=
+ local provider_config_type catalog_struct catalog_type
+ local disk_ident
+
+ # gnop(8)/geli(8) associated variables (p for `parent device')
+ local p_devname p_geom p_consumer p_provider_ref p_provider
+ local p_provider_config p_provider_geom p_provider_class
+
+ # md(4) associated variables
+ local config config_type config_file magic=
+
+ # Temporarily disable debugging to keep debug output light
+ local old_debug="$debug" debug=
- # Next, try to find all the types of devices one might use
- # as a media source for content
#
+ # Get the GEOM name (for use below in device registration)
+ #
+ $geom get name devname || continue
- local dev desc type max n=0
- for dev in $DEVICE_NAMES; do
- n=$(( $n + 1 ))
- # Get the desc, type, and max (with debugging disabled)
- # NOTE: Bypassing f_device_name_get() for efficiency
- debug= f_getvar _device_desc$n desc
- debug= f_getvar _device_type$n type
- debug= f_getvar _device_max$n max
+ #
+ # Attempt to get the consumer, provider, provider config, and
+ # provider class for this geom (errors ignored).
+ #
+ # NB: Each GEOM in the `DEV' class should have one consumer.
+ # That consumer should have a reference to its provider.
+ #
+ $geom get consumer1 geom_consumer
+ f_struct "$geom_consumer" get provider_ref provider_ref &&
+ f_geom_find_by id "$provider_ref" provider geom_provider
+ if f_struct "$geom_provider"; then
+ $geom_provider get config provider_config
+ f_geom_parent $geom_provider provider_geom &&
+ f_geom_parent $provider_geom provider_class
+ fi
- local k=0
- while [ $k -lt ${max:-0} ]; do
- i=$k k=$(( $k + 1 ))
- devname=""
- case "$type" in
- $DEVICE_TYPE_CDROM)
- f_device_try "$dev" "$i" devname || continue
- f_device_register "${devname##*/}" "$desc" \
- "$devname" $DEVICE_TYPE_CDROM 1 \
- f_media_init_cdrom f_media_get_cdrom \
- f_media_shutdown_cdrom ""
- f_dprintf "Found a CDROM device for %s" \
- "$devname"
- ;;
- $DEVICE_TYPE_FLOPPY)
- f_device_try "$dev" "$i" devname || continue
- f_device_register "${devname##*/}" "$desc" \
- "$devname" $DEVICE_TYPE_FLOPPY 1 \
- f_media_init_floppy \
- f_media_get_floppy \
- f_media_shutdown_floppy ""
- f_dprintf "Found a floppy device for %s" \
- "$devname"
- ;;
- $DEVICE_TYPE_USB)
- f_device_try "$dev" "$i" devname || continue
- f_device_register "${devname##*/}" "$desc" \
- "$devname" $DEVICE_TYPE_USB 1 \
- f_media_init_usb f_media_get_usb \
- f_media_shutdown_usb ""
- f_dprintf "Found a USB disk for %s" "$devname"
- ;;
+ #
+ # Get values for device registration (errors ignored)
+ #
+ f_struct "$provider_class" get name type
+ f_struct "$geom_provider" get mediasize capacity
+ f_struct "$provider_config" get descr desc
+
+ #
+ # For gnop(8), geli(8), or combination thereof, change device type to
+ # that of the consumer
+ #
+ p_devname= p_geom= p_provider= p_provider_config=
+ case "$devname" in
+ *.nop.eli) p_devname="${devname%.nop.eli}" ;;
+ *.eli.nop) p_devname="${devname%.eli.nop}" ;;
+ *.eli) p_devname="${devname%.eli}" ;;
+ *.nop) p_devname="${devname%.nop}" ;;
+ esac
+ [ "$p_devname" ] && f_geom_find "$p_devname" $GEOM_CLASS_DEV p_geom
+ if [ "${p_geom:-$geom}" != "$geom" ]; then
+ f_struct "$p_geom" get consumer1 p_consumer
+ f_struct "$p_consumer" get provider_ref p_provider_ref &&
+ f_geom_find_by id "$p_provider_ref" provider p_provider
+ if f_struct "$p_provider"; then
+ $p_provider get config p_provider_config
+ f_geom_parent $p_provider p_provider_geom &&
+ f_geom_parent $p_provider_geom p_provider_class
+ fi
+ f_struct "$p_provider_class" get name type
+ fi
+
+ # Look up geom device in device catalog for default description
+ f_device_catalog_get \
+ $DEVICE_TYPE_ANY "${p_devname:-$devname}" catalog_struct
+ [ "$desc" ] || f_struct "catalog_device_$catalog_struct" get desc desc
+
+ # Use device catalog entry for potential re-classification(s)
+ f_struct "catalog_device_$catalog_struct" get type catalog_type
+
+ # Restore debugging for this next part (device registration)
+ debug="$old_debug"
+
+ #
+ # Register the device
+ #
+ local retval device
+ case "$type" in
+ $GEOM_CLASS_DISK)
+ # First attempt to classify by device catalog (see MAIN)
+ case "$catalog_type" in
+ $DEVICE_TYPE_CDROM)
+ f_dprintf "Found CDROM device for disk %s" "$devname"
+ debug= f_device_register device "$devname" "$desc" \
+ "/dev/$devname" $DEVICE_TYPE_CDROM 1 \
+ f_media_init_cdrom f_media_get_cdrom \
+ f_media_shutdown_cdrom "" "$capacity" &&
+ return $SUCCESS
+ ;;
+ esac
+
+ # Fall back to register label device as a disk and taste it
+ f_dprintf "Found disk device named %s" "$devname"
+ debug= f_struct "$p_provider_config" get \
+ ident disk_ident ||
+ debug= f_struct "$provider_config" get \
+ ident disk_ident
+ debug= f_device_register device "$devname" "$desc" \
+ "/dev/$devname" $DEVICE_TYPE_DISK 1 \
+ "" "" "" "$disk_ident" "$capacity"
+ retval=$?
+
+ # Detect ``dangerously dedicated'' filesystems (errors ignored)
+ f_device_probe_disk_fs device "$devname" "$capacity" &&
+ retval=$SUCCESS
+
+ return $retval
+ ;;
+ $GEOM_CLASS_FD)
+ f_dprintf "Found floppy device named %s" "$devname"
+ debug= f_device_register device "$devname" "$desc" \
+ "/dev/$devname" $DEVICE_TYPE_FLOPPY 1 \
+ f_media_init_floppy f_media_get_floppy \
+ f_media_shutdown_floppy "" "$capacity"
+ return $?
+ ;;
+ $GEOM_CLASS_LABEL)
+ : fall through to below section # reduces indentation level
+ ;;
+ $GEOM_CLASS_MD)
+ f_dprintf "Found disk device named %s" "$devname"
+ debug= f_device_register device "$devname" "$desc" \
+ "/dev/$devname" $DEVICE_TYPE_DISK 1 \
+ "" "" "" "" "$capacity"
+ retval=$?
+
+ #
+ # Attempt to get file(1) magic to potentially classify as
+ # alternate media type. If unable to get magic, fall back to
+ # md(4) characteristics (such as vnode filename).
+ #
+ [ -r "/dev/$devname" ] &&
+ magic=$( file -bs "/dev/$devname" 2> /dev/null )
+ if [ ! "$magic" ]; then
+ # Fall back to md(4) characteristics
+ if f_struct "$p_provider_config"; then
+ config="$p_provider_config"
+ else
+ config="$provider_config"
+ fi
+ debug= f_struct "$config" get type config_type
+ debug= f_struct "$config" get file config_file
+
+ # Substitute magic for below based on type and file
+ case "$config_type=$config_file" in
+ vnode=*.iso) magic="ISO 9660" ;;
esac
- done
- done
+ fi
+ f_device_probe_disk_fs device \
+ "$devname" "$capacity" "$magic" &&
+ retval=$SUCCESS # Errors ignored
+
+ return $retval
+ ;;
+ $GEOM_CLASS_PART)
+ if f_struct "$p_provider_config"; then
+ config="$p_provider_config"
+ else
+ config="$provider_config"
+ fi
+ debug= f_struct "$config" get type provider_config_type
+ f_device_probe_geom_part device \
+ "$provider_config_type" "$devname" "$capacity"
+ retval=$?
+ device_type=$DEVICE_TYPE_NONE
+ [ $retval -eq $SUCCESS ] &&
+ debug= f_struct "$device" get type device_type
+
+ # Potentially re-classify as USB device
+ if [ "$device_type" = "$DEVICE_TYPE_UFS" -a \
+ "$catalog_type" = "$DEVICE_TYPE_USB" ]
+ then
+ f_dprintf "Found USB device for partition %s" \
+ "$devname"
+ debug= f_struct "$p_provider_geom" get \
+ name disk_name ||
+ debug= f_struct "$provider_geom" get \
+ name disk_name
+ debug= f_device_register device "$devname" "$desc" \
+ "/dev/$devname" $DEVICE_TYPE_USB 1 \
+ f_media_init_usb f_media_get_usb \
+ f_media_shutdown_usb "$disk_name" "$capacity"
+ retval=$?
+ fi
+
+ return $retval
+ ;;
+ $GEOM_CLASS_RAID)
+ # Use the provider geom name as the description
+ if [ ! "$desc" ]; then
+ f_struct "$p_provider_geom" get name desc ||
+ f_struct "$provider_geom" get name desc
+ fi
+
+ f_dprintf "Found disk device named %s" "$devname"
+ debug= f_device_register device \
+ "$devname" "${desc:-GEOM RAID device}" \
+ "/dev/$devname" $DEVICE_TYPE_DISK 1 \
+ "" "" "" "" "$capacity"
+ retval=$?
+
+ # Detect ``dangerously dedicated'' filesystems
+ f_device_probe_disk_fs device "$devname" "$capacity" &&
+ retval=$SUCCESS # Errors ignored
+
+ return $retval
+ ;;
+ $GEOM_CLASS_ZFS_ZVOL)
+ f_dprintf "Found disk device named %s" "$devname"
+ debug= f_device_register device \
+ "$devname" "${desc:-GEOM ZFS::ZVOL device}" \
+ "/dev/$devname" $DEVICE_TYPE_DISK 1 \
+ "" "" "" "" "$capacity"
+ retval=$?
+
+ # Detect ``dangerously dedicated'' filesystems
+ f_device_probe_disk_fs device "$devname" "$capacity" &&
+ retval=$SUCCESS # Errors ignored
+
+ return $retval
+ ;;
+ *)
+ return $FAILURE # Unknown GEOM class
+ esac
+
+ #
+ # Still here? Must be $GEOM_CLASS_LABEL
+ #
+
+ local label_geom label_devname label_devgeom= label_devconsumer
+ local label_devprovider= label_devprovider_ref label_devprovider_config
+ local label_gpart_type
- # Register ISO9660 providers as CDROM devices
- for devname in /dev/iso9660/*; do
- f_device_try "$devname" || continue
- f_device_register "${devname##*/}" "ISO9660 file system" \
- "$devname" $DEVICE_TYPE_CDROM 1 \
+ if f_struct "$p_provider"; then
+ label_geom="$p_provider_geom"
+ else
+ label_geom="$provider_geom"
+ fi
+
+ case "$devname" in
+ gpt/*|gptid/*)
+ #
+ # Attempt to get the partition type by getting the `config'
+ # member of the provider for our device (which is named in the
+ # parent geom of our current provider).
+ #
+ debug= f_struct "$label_geom" get name label_devname &&
+ debug= f_geom_find "$label_devname" $GEOM_CLASS_DEV \
+ label_devgeom
+ debug= f_struct "$label_devgeom" get \
+ consumer1 label_devconsumer
+ debug= f_struct "$label_devconsumer" get \
+ provider_ref label_devprovider_ref &&
+ debug= f_geom_find_by id "$label_devprovider_ref" \
+ provider label_devprovider
+ debug= f_struct "$label_devprovider" get \
+ config label_devprovider_config
+ debug= f_struct "$label_devprovider_config" get \
+ type label_gpart_type
+
+ #
+ # Register device label based on partition type
+ #
+ f_device_probe_geom_part device \
+ "$label_gpart_type" "$devname" "$capacity"
+ return $?
+ ;;
+ iso9660/*)
+ f_dprintf "Found CDROM device labeled %s" "$devname"
+ debug= f_device_register device \
+ "$devname" "ISO9660 file system" \
+ "/dev/$devname" $DEVICE_TYPE_CDROM 1 \
f_media_init_cdrom f_media_get_cdrom \
- f_media_shutdown_cdrom ""
- f_dprintf "Found a CDROM device for %s" "$devname"
- done
+ f_media_shutdown_cdrom "" "$capacity"
+ return $?
+ ;;
+ label/*)
+ # For generic labels, use provider geom name as real device
+ debug= f_struct "$label_geom" get name label_devname
+
+ # Look up label geom device in device catalog for default desc
+ debug= f_device_catalog_get \
+ $DEVICE_TYPE_ANY "$label_devname" catalog_struct
+ [ "$desc" ] || debug= f_struct \
+ "catalog_device_$catalog_struct" get desc desc
- # Scan for mdconfig(8)-created md(4) devices
- local filename
- for devname in /dev/md[0-9] /dev/md[0-9][0-9]; do
- f_device_try "$devname" || continue
+ # Use device catalog entry for potential re-classification(s)
+ debug= f_struct "catalog_device_$catalog_struct" get \
+ type catalog_type
- # See if the md(4) device is a vnode type backed by a file
- filename=$( sysctl kern.geom.conftxt |
- awk -v devname="${devname##*/}" \
- '
- ( $2 == "MD" ) && \
- ( $3 == devname ) && \
- ( $(NF-2) == "vnode" ) && \
- ( $(NF-1) == "file" ) \
- {
- print $NF
- }
- ' )
- case "$filename" in
- *.iso) # Register the device as an ISO9660 provider
- f_device_register "${devname##*/}" \
- "md(4) vnode file system" \
- "$devname" $DEVICE_TYPE_CDROM 1 \
+ # First attempt to classify by device catalog (see MAIN)
+ case "$catalog_type" in
+ $DEVICE_TYPE_CDROM)
+ f_dprintf "Found CDROM device for disk %s" "$devname"
+ debug= f_device_register device "$devname" "$desc" \
+ "/dev/$devname" $DEVICE_TYPE_CDROM 1 \
f_media_init_cdrom f_media_get_cdrom \
- f_media_shutdown_cdrom ""
- f_dprintf "Found a CDROM device for %s" "$devname"
+ f_media_shutdown_cdrom "" "$capacity" &&
+ return $SUCCESS
;;
esac
- done
- # Finally go get the disks and look for partitions to register
- local diskname slices index type rest slice part
- for diskname in $( sysctl -n kern.disks ); do
+ # Fall back to register label device as a disk and taste it
+ f_dprintf "Found disk device labeled %s" "$devname"
+ debug= f_device_register device \
+ "$devname" "GEOM LABEL device" \
+ "/dev/$devname" $DEVICE_TYPE_DISK 1 \
+ "" "" "" "" "$capacity"
+ retval=$?
+
+ # Detect ``dangerously dedicated'' filesystems (errors ignored)
+ f_device_probe_disk_fs device "$devname" "$capacity" &&
+ retval=$SUCCESS
+
+ return $retval
+ ;;
+ msdosfs/*)
+ f_dprintf "Found DOS partition labeled %s" "$devname"
+ debug= f_device_register device "$devname" "DOS file system" \
+ "/dev/$devname" $DEVICE_TYPE_DOS 1 \
+ f_media_init_dos f_media_get_dos \
+ f_media_shutdown_dos "" "$capacity"
+ return $?
+ ;;
+ ufs/*|ufsid/*)
+ f_dprintf "Found UFS partition labeled %s" "$devname"
+ debug= f_device_register device "$devname" "UFS file system" \
+ "/dev/$devname" $DEVICE_TYPE_UFS 1 \
+ f_media_init_ufs f_media_get_ufs \
+ f_media_shutdown_ufs "" "$capacity"
+ return $?
+ ;;
+ ext2fs/*|ntfs/*|reiserfs/*)
+ return $FAILURE # No media device handlers for these labels
+ ;;
+ esac
+
+ # Unable to classify GEOM label
+ return $FAILURE
+}
- case "$diskname" in
- cd*)
- # XXX
- # Due to unknown reasons, kern.disks returns SCSI
- # CDROM as a valid disk. This will prevent bsdconfig
- # from presenting SCSI CDROMs as available disks in
- # various menus. Why GEOM treats SCSI CDROM as a disk
- # is beyond me and that should be investigated.
- # For temporary workaround, ignore SCSI CDROM device.
- #
- continue ;;
+# f_device_probe_geom_part $var_to_set $gpart_type $devname $capacity [$magic]
+#
+# Given a gpart(8) partition type and a device name, register the device if it
+# is a known partition type that we can handle. If $var_to_set is non-NULL,
+# upon success holds the DEVICE struct name of the registered device.
+#
+# Returns success if the device was successfully registered, failure otherwise.
+#
+f_device_probe_geom_part()
+{
+ local __var_to_set="$1" __gpart_type="$2" __devname="$3"
+ local __capacity="${4:--1}" __magic="$5"
+
+ #
+ # Register device based on partition type
+ # NB: !0 equates to `unused' bsdlabel
+ #
+ case "$__gpart_type" in
+ fat16|fat32)
+ f_dprintf "Found DOS partition named %s" "$__devname"
+ debug= f_device_register "$__var_to_set" \
+ "$__devname" "DOS file system" \
+ "/dev/$__devname" $DEVICE_TYPE_DOS 1 \
+ f_media_init_dos f_media_get_dos \
+ f_media_shutdown_dos "" "$__capacity"
+ return $?
+ ;;
+ freebsd|!0) # Commonly used inappropriately, taste for FreeBSD
+ [ -r "/dev/$__devname" -a ! "$__magic" ] &&
+ __magic=$( file -bs "/dev/$__devname" 2> /dev/null )
+ case "$__magic" in
+ *"Unix Fast File system"*)
+ f_dprintf "Found UFS partition named %s" "$__devname"
+ debug= f_device_register "$__var_to_set" \
+ "$__devname" "UFS file system" \
+ "/dev/$__devname" $DEVICE_TYPE_UFS 1 \
+ f_media_init_ufs f_media_get_ufs \
+ f_media_shutdown_ufs "" "$__capacity"
+ return $?
esac
+ return $FAILURE
+ ;;
+ freebsd-ufs)
+ f_dprintf "Found UFS partition named %s" "$__devname"
+ debug= f_device_register "$__var_to_set" \
+ "$__devname" "UFS file system" \
+ "/dev/$__devname" $DEVICE_TYPE_UFS 1 \
+ f_media_init_ufs f_media_get_ufs \
+ f_media_shutdown_ufs "" "$__capacity"
+ return $?
+ ;;
+ apple-*|linux-*|ms-*|netbsd-*|ntfs|vmware-*)
+ return $FAILURE # No device types for these
+ ;;
+ bios-*|ebr|efi|mbr|freebsd-boot|freebsd-swap)
+ return $FAILURE # Not a source for media
+ ;;
+ freebsd-nandfs|freebsd-vinum|freebsd-zfs)
+ return $FAILURE # Unsupported as media source
+ ;;
+ esac
- # Try to create a list of partitions and their types,
- # consisting of "N,typeN ..." (e.g., "1,0xa5 2,0x06").
- if ! slices=$( fdisk -p "$diskname" 2> /dev/null |
- awk '( $1 == "p" ) { print $2","$3 }' )
- then
- f_dprintf "Unable to open disk %s" "$diskname"
- continue
- fi
+ return $FAILURE # Unknown partition type
+}
- f_device_register "$diskname" "" \
- "/dev/$diskname" $DEVICE_TYPE_DISK 0
- f_dprintf "Found a disk device named %s" "$diskname"
+# f_device_probe_disk_fs $var_to_set $devname [$capacity [$magic]]
+#
+# Given a device name, taste it and register the device if it is a so-called
+# ``dangerously dedicated'' file system written without a partition table.
+# Tasting is done using file(1) (specifically `file -bs') but if $magic is
+# present and non-NULL it is used instead. If $var_to_set is non-NULL, upon
+# success holds the DEVICE struct name of the registered device.
+#
+# Returns success if the device was successfully registered, failure otherwise.
+#
+f_device_probe_disk_fs()
+{
+ local __var_to_set="$1" __devname="$2" __capacity="${3:--1}"
+ local __magic="$4"
- # Look for existing partitions to register
- for slice in $slices; do
- index="${slice%%,*}" type="${slice#*,}"
- slice=${diskname}s$index
- case "$type" in
- 0x01|0x04|0x06|0x0b|0x0c|0x0e|0xef)
- # DOS partitions to add as "DOS media devices"
- f_device_register "$slice" "" \
- "/dev/$slice" $DEVICE_TYPE_DOS 1 \
- f_media_init_dos f_media_get_dos \
- f_media_shutdown_dos ""
- f_dprintf "Found a DOS partition %s" "$slice"
- ;;
- 0xa5) # FreeBSD partition
- for part in $(
- bsdlabel -r $slice 2> /dev/null |
- awk -v slice="$slice" '
- ( $1 ~ /[abdefgh]:/ ) {
- printf "%s%s\n",
- slice,
- substr($1,1,1)
- }'
- ); do
- f_quietly dumpfs -m /dev/$part ||
- continue
- f_device_register \
- "$part" "" "/dev/$part" \
- $DEVICE_TYPE_UFS 1 \
- f_media_init_ufs \
- f_media_get_ufs \
- f_media_shutdown_ufs ""
- f_dprintf "Found a UFS partition %s" \
- "$part"
- done # parts
- ;;
- esac
- done # slices
+ [ -r "/dev/${__devname#/dev/}" -a ! "$__magic" ] &&
+ __magic=$( file -bs "/dev/$__devname" 2> /dev/null )
+
+ case "$__magic" in
+ *"ISO 9660"*)
+ f_dprintf "Found CDROM device for disk %s" "$__devname"
+ debug= f_device_register "$__var_to_set" \
+ "$__devname" "ISO9660 file system" \
+ "/dev/$__devname" $DEVICE_TYPE_CDROM 1 \
+ f_media_init_cdrom f_media_get_cdrom \
+ f_media_shutdown_cdrom "" "$__capacity"
+ return $?
+ ;;
+ *"Unix Fast File system"*)
+ f_dprintf "Found UFS device for disk %s" "$__devname"
+ debug= f_device_register "$__var_to_set" \
+ "$__devname" "UFS file system" \
+ "/dev/$__devname" $DEVICE_TYPE_UFS 1 \
+ f_media_init_ufs f_media_get_ufs \
+ f_media_shutdown_ufs "" "$__capacity"
+ return $?
+ ;;
+ *"FAT (12 bit)"*|*"FAT (16 bit)"*|*"FAT (32 bit)"*)
+ f_dprintf "Found DOS device for disk %s" "$__devname"
+ debug= f_device_register "$__var_to_set" \
+ "$__devname" "DOS file system" \
+ "/dev/$__devname" $DEVICE_TYPE_DOS 1 \
+ f_media_init_dos f_media_get_dos \
+ f_media_shutdown_dos "" "$__capacity"
+ return $?
+ ;;
+ esac
- done # disks
+ return $FAILURE # Unknown file system type
}
-# f_device_name_get $type $name type|desc|max [$var_to_set]
+# f_device_catalog_get $type $name [$var_to_set]
#
-# Fetch the device type (type), description (desc), or maximum number of
-# devices to scan for (max) associated with device $name and $type. If $type is
-# either NULL, missing, or set to $DEVICE_TYPE_ANY then only $name is used.
+# Fetch the struct name of the catalog device matching device $name. If $type
+# is either NULL, missing, or set to $DEVICE_TYPE_ANY then only $name is used.
# Returns success if a match was found, otherwise failure.
#
-# If $var_to_set is missing or NULL, the device name is printed to standard out
+# If $var_to_set is missing or NULL, the struct name is printed to standard out
# for capturing in a sub-shell (which is less-recommended because of
# performance degredation; for example, when called in a loop).
#
-f_device_name_get()
+f_device_catalog_get()
{
- local __type="$1" __name="$2" __prop="$3" __var_to_set="$4"
- local __dev __devtype __n=0
+ local __type="$1" __name="$2" __var_to_set="$3"
+ local __dname=
- # Return failure if no $name or $prop is an unknown property
+ # Return failure if no $name
[ "$__name" ] || return $FAILURE
- case "$__prop" in type|desc|max) : good ;;
- *) return $FAILURE; esac
+
+ # Disable debugging to keep debug output light
+ local debug=
+
+ #
+ # Attempt to create an alternate-form of $__name that contains the
+ # first contiguous string of numbers replaced with `%d' for comparison
+ # against stored pattern names (see MAIN).
+ #
+ local __left="${__name%%[0-9]*}" __right="${__name#*[0-9]}"
+ if [ "$__left" != "$__name" ]; then
+ # Chop leading digits from right 'til we hit first non-digit
+ while :; do
+ case "$__right" in
+ [0-9]*) __right="${__right#[0-9]}" ;;
+ *) break
+ esac
+ done
+ __dname="${__left}%d$__right"
+ fi
[ "$__type" = "$DEVICE_TYPE_ANY" ] && __type=
- for __dev in $DEVICE_NAMES; do
- __n=$(( $__n + 1 ))
- [ "$__dev" = "$__name" ] || continue
- f_getvar _device_type$__n __devtype
- [ "${__type:-$__devtype}" = "$__devtype" ] || continue
- f_getvar _device_$__prop$__n $__var_to_set
+ local __dev __dev_name __dev_type
+ for __dev in $DEVICE_CATALOG; do
+ catalog_device_$__dev get name __dev_name
+ [ "$__dev_name" = "$__name" -o "$__dev_name" = "$__dname" ] ||
+ continue
+ catalog_device_$__dev get type __dev_type
+ [ "${__type:-$__dev_type}" = "$__dev_type" ] || continue
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" $__dev
+ else
+ echo $__dev
+ fi
return $?
done
+
+ [ "$__var_to_set" ] && setvar "$__var_to_set" ""
return $FAILURE
}
-# f_device_name_set $type $name $desc [$max]
+# f_device_catalog_set $type $name $desc
#
-# Store a description (desc) and [optionally] maximum number of devices to scan
-# for (max) in-association with device $type and $name. Returns success unless
-# $name is NULL or missing. Use the f_device_name_get() routine with the same
-# $name and optionally $type to retrieve one of type, desc, or max properties.
+# Store a description (desc) in-association with device $type and $name.
+# Returns success unless $name is NULL or missing. Use f_device_catalog_get()
+# routine with the same $name and optionally $type to retrieve catalog device
+# structure (see CATALOG_DEVICE struct definition in GLOBALS section).
#
-f_device_name_set()
+f_device_catalog_set()
{
- local type="$1" name="$2" desc="$3" max="$4"
- local dev devtype n=0 found=
+ local type="$1" name="$2" desc="$3"
+ local struct dev dev_type found=
+
[ "$name" ] || return $FAILURE
- for dev in $DEVICE_NAMES; do
- n=$(( $n + 1 ))
- [ "$dev" = "$name" ] || continue
- if f_getvar _device_type$n devtype; then
- # Allow multiple entries with same name but diff type
- [ "$devtype" = "$type" ] || continue
- fi
- found=1 && break
- done
- if [ ! "$found" ]; then
- DEVICE_NAMES="$DEVICE_NAMES $name"
- n=$(( $n + 1 ))
+
+ # Disable debugging to keep debug output light
+ local debug=
+
+ f_str2varname "$name" struct
+ if [ ! "$DEVICE_CATALOG_APPEND_ONLY" ]; then
+ for dev in $DEVICE_CATALOG; do
+ [ "$dev" = "$struct" ] || continue
+ found=1 break
+ done
fi
- setvar _device_type$n "$type"
- setvar _device_desc$n "$desc"
- [ "${4+set}" ] && setvar _device_max$n "$max"
+ if [ "$found" ]; then
+ f_struct_free "catalog_device_$struct"
+ else
+ DEVICE_CATALOG="$DEVICE_CATALOG $struct"
+ fi
+ f_struct_new CATALOG_DEVICE "catalog_device_$struct" || return $FAILURE
+ catalog_device_$struct set type "$type"
+ catalog_device_$struct set name "$name"
+ catalog_device_$struct set desc "$desc"
return $SUCCESS
}
@@ -442,8 +904,8 @@ f_device_desc()
[ "$__var_to_set" ] && { setvar "$__var_to_set" "" || return; }
#
- # Return sysctl MIB dev.NAME.UNIT.%desc if it exists,
- # otherwise fall through to below static list.
+ # Return sysctl MIB dev.NAME.UNIT.%desc if it exists, otherwise fall
+ # through to further alternate methods.
#
if f_have sysctl; then
__devname="${__name%%[0-9]*}"
@@ -463,24 +925,11 @@ f_device_desc()
fi
fi
- local __dev __devtype __n=0
- for __dev in $DEVICE_NAMES; do
- __n=$(( $__n + 1 ))
- debug= f_getvar _device_type$__n __devtype
- [ "${__type:-$__devtype}" = "$__devtype" ] || continue
- if [ "$__devtype" = "$DEVICE_TYPE_NETWORK" ]; then
- __devname=$( f_substr "$__name" 0 ${#__dev} )
- [ "$__devname" = "$__dev" ] || continue
- else
- __devname="${__name%%[0-9]*}"
- __devunit="${__name#$__devname}"
- __devunit="${__devunit%%[!0-9]*}"
- __devname=$( printf "$__dev" $__devunit )
- [ "$__devname" = "$__name" ] || continue
- fi
- debug= f_getvar _device_desc$__n $__var_to_set
- return $?
- done
+ # Look up device in catalog for default description
+ local __catalog_struct
+ debug= f_device_catalog_get "$__type" "$__name" __catalog_struct
+ debug= f_struct "catalog_device_$__catalog_struct" get \
+ desc "$__var_to_set" && return $SUCCESS
#
# Sensible fall-backs for specific types
@@ -489,7 +938,7 @@ f_device_desc()
$DEVICE_TYPE_CDROM) __cp="<unknown cdrom device type>" ;;
$DEVICE_TYPE_DISK) __cp="<unknown disk device type>" ;;
$DEVICE_TYPE_FLOPPY) __cp="<unknown floppy device type>" ;;
- $DEVICE_TYPE_USB) __cp="<unknown usb storage device type>" ;;
+ $DEVICE_TYPE_USB) __cp="<unknown USB storage device type>" ;;
$DEVICE_TYPE_NETWORK) __cp="<unknown network interface type>" ;;
*)
__cp="<unknown device type>"
@@ -504,39 +953,108 @@ f_device_desc()
return $FAILURE
}
-# f_device_rescan
+# f_device_is_ethernet $device
#
-# Rescan all devices, after closing previous set - convenience function.
+# Returns true if $device is a wired Ethernet network interface. Otherwise
+# returns false. Example wired interfaces include: fxp0 em0 bge0 rl0 etc.
#
-f_device_rescan()
+f_device_is_ethernet()
{
- f_device_reset
- f_device_get_all
+ local dev="$1" type flags
+
+ # Make sure we have an actual device by that name
+ f_struct "$dev" || return $FAILURE
+
+ # Make sure that the device is a network device
+ $dev get type type
+ [ "$type" = "$DEVICE_TYPE_NETWORK" ] || return $FAILURE
+
+ # Make sure that the media flags indicate that it is Ethernet
+ $dev get flags flags
+ [ $(( ${flags:-0} & $IF_ETHERNET )) -eq $IF_ETHERNET ]
}
-# f_device_find $name [$type [$var_to_set]]
+# f_device_is_wireless $device
+#
+# Returns true if $device is a Wireless network interface. Otherwise returns
+# false. Examples of wireless interfaces include: iwn0
+#
+f_device_is_wireless()
+{
+ local dev="$1" type flags
+
+ # Make sure we have an actual device by that name
+ f_struct "$dev" || return $FAILURE
+
+ # Make sure that the device is a network device
+ $dev get type type
+ [ "$type" = "$DEVICE_TYPE_NETWORK" ] || return $FAILURE
+
+ # Make sure that the media flags indicate that it is 802.11 wireless
+ $dev get flags flags
+ [ $(( ${flags:-0} & $IF_WIRELESS )) -eq $IF_WIRELESS ]
+}
+
+# f_device_is_active $device
+#
+# Returns true if $device is active. Otherwise returns false. Currently this
+# only works for network interfaces.
+#
+f_device_is_active()
+{
+ local dev="$1" type flags=0
+
+ # Make sure we have an actual device by that name
+ f_struct "$dev" || return $FAILURE
+
+ $dev get type type
+ case "$type" in
+ $DEVICE_TYPE_NETWORK)
+ # Make sure that the media flags indicate that it is active
+ $dev get flags flags
+ [ $(( ${flags:-0} & $IF_ACTIVE )) -eq $IF_ACTIVE ]
+ ;;
+ *)
+ return $FAILURE
+ esac
+}
+
+# f_device_find [-1] $name [$type [$var_to_set]]
#
# Find one or more registered devices by name, type, or both. Returns a space-
# separated list of devices matching the search criterion.
#
+# If `-1' option flag is given, only the first matching device is returned.
+#
# If $var_to_set is missing or NULL, the device name(s) are printed to standard
# out for capturing in a sub-shell (which is less-recommended because of
# performance degredation; for example, when called in a loop).
#
f_device_find()
{
+ local OPTIND OPTARG flag only_one=
+ while getopts 1 flag; do
+ case "$flag" in
+ 1) only_one=1 ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
local __name="$1" __type="${2:-$DEVICE_TYPE_ANY}" __var_to_set="$3"
- local __dev __devname __devtype __found=
- for __dev in $DEVICES; do
- device_$__dev get name __devname
- device_$__dev get type __devtype
+ local __n=1 __devname __devtype __found=
+ while [ $__n -le $NDEVICES ]; do
+ device_$__n get name __devname
+ device_$__n get type __devtype
if [ "$__name" = "$__devname" -o ! "$__name" ] &&
[ "$__type" = "$DEVICE_TYPE_ANY" -o \
"$__type" = "$__devtype" ]
then
- __found="$__found $__dev"
+ __found="$__found device_$__n"
+ [ "$only_one" ] && break
fi
+ __n=$(( $__n + 1 ))
done
+
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" "${__found# }"
else
@@ -545,38 +1063,100 @@ f_device_find()
[ "$__found" ] # Return status
}
-# f_device_init $name
+# f_device_init $device
#
-# Initialize a device by evaluating its `init' function.
+# Initialize a device by evaluating its `init' function. The $device argument
+# is a DEVICE struct name.
#
f_device_init()
{
- local name="$1" init_func
- device_$name get init init_func || return $?
- ${init_func:-:} $name
+ local device="$1" init_func
+ f_struct "$device" || return $?
+ $device get init init_func
+ ${init_func:-:} "$device"
}
-# f_device_get $name $file [$probe]
+# f_device_get $device $file [$probe]
#
# Read $file by evaluating the device's `get' function. The file is commonly
# produced on standard output (but it truly depends on the function called).
+# The $device argument is a DEVICE struct name.
#
f_device_get()
{
- local name="$1" file="$2" probe="$3" get_func
- device_$name get get get_func || return $?
- ${get_func:-:} $name "$file" ${3+"$probe"}
+ local device="$1" file="$2" probe="$3" get_func
+ f_struct "$device" || return $?
+ $device get get get_func
+ ${get_func:-:} "$device" "$file" ${3+"$probe"}
}
-# f_device_shutdown $name
+# f_device_shutdown $device
#
-# Shutdown a device by evaluating its `shutdown' function.
+# Shutdown a device by evaluating its `shutdown' function. The $device argument
+# is a DEVICE struct name.
#
f_device_shutdown()
{
- local name="$1" shutdown_func
- device_$name get shutdown shutdown_func || return $?
- ${shutdown_func:-:} $name
+ local device="$1" shutdown_func
+ f_struct "$device" || return $?
+ $device get shutdown shutdown_func
+ ${shutdown_func:-:} "$device"
+}
+
+# f_devices_sort_by $property $var_to_get [$var_to_set]
+#
+# Take list of devices from $var_to_get (separated by whitespace, newline
+# included) and sort them by $property (e.g., `name'). The sorted list of
+# DEVICE struct names is returned on standard output separated by whitespace
+# (newline to be specific) unless $var_to_set is present and non-NULL.
+#
+# 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_device_sort_by_awk='
+# Variables that should be defined on the invocation line:
+# -v prop="property"
+function asorti(src, dest)
+{
+ for (i in src) dest[++nitems] = i
+ for (i = 1; i <= nitems; k = i++) {
+ idx = dest[i]
+ while ((k > 0) && (dest[k] > idx)) {
+ dest[k+1] = dest[k]; k--
+ }
+ dest[k+1] = idx
+ }
+ return nitems
+}
+{
+ split($0, devs, FS)
+ for (d in devs) {
+ name = ENVIRON["_struct_value_" devs[d] "_" prop]
+ devices[name] = devs[d]
+ }
+}
+END {
+ nitems = asorti(devices, devices_sorted)
+ for (i = 1; i <= nitems; i++) print devices[devices_sorted[i]]
+}
+'
+f_device_sort_by()
+{
+ local __property="${1:-name}" __var_to_get="$2" __var_to_set="$3"
+
+ f_isset "$__var_to_get" || return $FAILURE
+
+ local __dev
+ for __dev in $( f_getvar "$__var_to_get" ); do
+ export _struct_value_${__dev}_$__property
+ done
+
+ local __cp
+ setvar "${__var_to_set:-__cp}" "$(
+ f_getvar "$__var_to_get" |
+ awk -v prop="$__property" "$f_device_sort_by_awk"
+ )"
+ [ "$__var_to_set" ] || echo "$__cp"
}
# f_device_menu $title $prompt $hline $device_type [$helpfile]
@@ -591,20 +1171,20 @@ f_device_menu()
local prompt="$2" hline="$3" type="$4" helpfile="$5"
- local dev devtype devs=
- for dev in $DEVICES; do
- device_$dev get type devtype || continue
- [ "$devtype" = "$type" ] || continue
- devs="$devs $dev"
- done
- [ "$devs" ] || return $DIALOG_CANCEL
+ local devs
+ f_device_find "" "$type" devs || return $DIALOG_CANCEL
- local desc menu_list=
+ local name desc menu_list=
+ f_device_sort_by name devs devs
for dev in $devs; do
- device_$dev get desc desc
+ $dev get name name
+ $dev get desc desc
+ f_shell_escape "$name" name
f_shell_escape "$desc" desc
- menu_list="$menu_list '$dev' '$desc'"
+ menu_list="$menu_list
+ '$name' '$desc'" # END-QUOTE
done
+ menu_list="${menu_list#$NL}"
local height width rows
eval f_dialog_menu_size height width rows \
@@ -623,6 +1203,7 @@ f_device_menu()
mtag=$( eval $DIALOG \
--title \"\$title\" \
--backtitle \"\$btitle\" \
+ --hline \"\$hline\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
${helpfile:+ \
@@ -647,9 +1228,15 @@ f_device_menu()
[ "$errexit" ] && set -e
if [ $retval -eq $DIALOG_OK ]; then
- # Clean up the output of [X]dialog(1) and return it
+ # Clean up the output of [X]dialog(1)
f_dialog_data_sanitize mtag
- echo "$mtag" >&2
+
+ # Map the user's choice back to a struct name
+ local index device
+ index=$( eval f_dialog_menutag2index \"\$mtag\" $menu_list )
+ device=$( set -- $devs; eval echo \${$index} )
+
+ echo "$device" >&2
fi
return $retval
@@ -658,133 +1245,141 @@ f_device_menu()
#
# Short-hand
#
-f_cdrom() { f_device_name_set $DEVICE_TYPE_CDROM "$1" "$2" "$3"; }
-f_disk() { f_device_name_set $DEVICE_TYPE_DISK "$1" "$2" "$3"; }
-f_floppy() { f_device_name_set $DEVICE_TYPE_FLOPPY "$1" "$2" "$3"; }
-f_serial() { f_device_name_set $DEVICE_TYPE_NETWORK "$1" "$2" "$3"; }
-f_usb() { f_device_name_set $DEVICE_TYPE_USB "$1" "$2" "$3"; }
-f_network() { f_device_name_set $DEVICE_TYPE_NETWORK "$1" "$2"; }
+f_cdrom() { f_device_catalog_set $DEVICE_TYPE_CDROM "$1" "$2"; }
+f_disk() { f_device_catalog_set $DEVICE_TYPE_DISK "$1" "$2"; }
+f_floppy() { f_device_catalog_set $DEVICE_TYPE_FLOPPY "$1" "$2"; }
+f_usb() { f_device_catalog_set $DEVICE_TYPE_USB "$1" "$2"; }
+f_network() { f_device_catalog_set $DEVICE_TYPE_NETWORK "$1" "$2"; }
############################################################ MAIN
-# CDROM, Disk, Floppy, Serial, and USB devices/names
-f_cdrom "cd%d" "SCSI CDROM drive" 4
-f_cdrom "mcd%d" "Mitsumi (old model) CDROM drive" 4
-f_cdrom "scd%d" "Sony CDROM drive - CDU31/33A type" 4
-f_disk "aacd%d" "Adaptec FSA RAID array" 4
-f_disk "ada%d" "ATA/SATA disk device" 16
-f_disk "amrd%d" "AMI MegaRAID drive" 4
-f_disk "da%d" "SCSI disk device" 16
-f_disk "idad%d" "Compaq RAID array" 4
-f_disk "ipsd%d" "IBM ServeRAID RAID array" 4
-f_disk "mfid%d" "LSI MegaRAID SAS array" 4
-f_disk "mlxd%d" "Mylex RAID disk" 4
-f_disk "twed%d" "3ware ATA RAID array" 4
-f_floppy "fd%d" "Floppy Drive unit A" 4
-f_serial "cuau%d" "%s on device %s (COM%d)" 16
-f_usb "da%da" "USB Mass Storage Device" 16
+#
+# The below classifications allow us to re-group the GEOM devices from the
+# `DEV' GEOM class appropriately while providing fall-back descriptions both
+# for making the below code more maintainable and handling the rare case the
+# GEOM device lacks a description.
+#
+
+DEVICE_CATALOG_APPEND_ONLY=1 # Make initial loading faster
+
+# CDROM, Disk, Floppy, and USB devices/names
+f_cdrom "cd%d" "SCSI CDROM drive"
+f_cdrom "mcd%d" "Mitsumi (old model) CDROM drive"
+f_cdrom "scd%d" "Sony CDROM drive - CDU31/33A type"
+f_disk "aacd%d" "Adaptec FSA RAID array"
+f_disk "ada%d" "ATA/SATA disk device"
+f_disk "amrd%d" "AMI MegaRAID drive"
+f_disk "da%d" "SCSI disk device"
+f_disk "idad%d" "Compaq RAID array"
+f_disk "ipsd%d" "IBM ServeRAID RAID array"
+f_disk "md%d" "md(4) disk device"
+f_disk "mfid%d" "LSI MegaRAID SAS array"
+f_disk "mlxd%d" "Mylex RAID disk"
+f_disk "twed%d" "3ware ATA RAID array"
+f_disk "vtbd%d" "VirtIO Block Device"
+f_floppy "fd%d" "Floppy Drive unit A"
+f_usb "da%da" "USB Mass Storage Device"
# Network interfaces/names
-f_network "ae" "Attansic/Atheros L2 Fast Ethernet"
-f_network "age" "Attansic/Atheros L1 Gigabit Ethernet"
-f_network "alc" "Atheros AR8131/AR8132 PCIe Ethernet"
-f_network "ale" "Atheros AR8121/AR8113/AR8114 PCIe Ethernet"
-f_network "an" "Aironet 4500/4800 802.11 wireless adapter"
-f_network "ath" "Atheros IEEE 802.11 wireless adapter"
-f_network "aue" "ADMtek USB Ethernet adapter"
-f_network "axe" "ASIX Electronics USB Ethernet adapter"
-f_network "bce" "Broadcom NetXtreme II Gigabit Ethernet card"
-f_network "bfe" "Broadcom BCM440x PCI Ethernet card"
-f_network "bge" "Broadcom BCM570x PCI Gigabit Ethernet card"
-f_network "bm" "Apple BMAC Built-in Ethernet"
-f_network "bwn" "Broadcom BCM43xx IEEE 802.11 wireless adapter"
-f_network "cas" "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"
-f_network "cc3i" "SDL HSSI sync serial PCI card"
-f_network "cue" "CATC USB Ethernet adapter"
-f_network "cxgb" "Chelsio T3 10Gb Ethernet card"
-f_network "dc" "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"
-f_network "de" "DEC DE435 PCI NIC or other DC21040-AA based card"
-f_network "disc" "Software discard network interface"
-f_network "ed" "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"
-f_network "el" "3Com 3C501 Ethernet card"
-f_network "em" "Intel(R) PRO/1000 Ethernet card"
-f_network "en" "Efficient Networks ATM PCI card"
-f_network "ep" "3Com 3C509 Ethernet card/3C589 PCMCIA"
-f_network "et" "Agere ET1310 based PCI Express Gigabit Ethernet card"
-f_network "ex" "Intel EtherExpress Pro/10 Ethernet card"
-f_network "fe" "Fujitsu MB86960A/MB86965A Ethernet card"
-f_network "fpa" "DEC DEFPA PCI FDDI card"
-f_network "fwe" "FireWire Ethernet emulation"
-f_network "fwip" "IP over FireWire"
-f_network "fxp" "Intel EtherExpress Pro/100B PCI Fast Ethernet card"
-f_network "gem" "Apple GMAC or Sun ERI/GEM Ethernet adapter"
-f_network "hme" "Sun HME (Happy Meal Ethernet) Ethernet adapter"
-f_network "ie" "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"
-f_network "igb" "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"
-f_network "ipw" "Intel PRO/Wireless 2100 IEEE 802.11 adapter"
-f_network "iwi" "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"
-f_network "iwn" "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"
-f_network "ixgbe" "Intel(R) PRO/10Gb Ethernet card"
-f_network "ixgb" "Intel(R) PRO/10Gb Ethernet card"
-f_network "ix" "Intel Etherexpress Ethernet card"
- # Maintain sequential order of above(3): ixgbe ixgb ix
-f_network "jme" "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"
-f_network "kue" "Kawasaki LSI USB Ethernet adapter"
-f_network "le" "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"
-f_network "lge" "Level 1 LXT1001 Gigabit Ethernet card"
-f_network "lnc" "Lance/PCnet (Isolan/Novell NE2100/NE32-VL) Ethernet"
-f_network "lo" "Loop-back (local) network interface"
-f_network "lp" "Parallel Port IP (PLIP) peer connection"
-f_network "malo" "Marvell Libertas 88W8335 802.11 wireless adapter"
-f_network "msk" "Marvell/SysKonnect Yukon II Gigabit Ethernet"
-f_network "mxge" "Myricom Myri10GE 10Gb Ethernet card"
-f_network "nfe" "NVIDIA nForce MCP Ethernet"
-f_network "nge" "NatSemi PCI Gigabit Ethernet card"
-f_network "ng" "Vimage netgraph(4) bridged Ethernet device"
- # Maintain sequential order of above(2): nge ng
-f_network "nve" "NVIDIA nForce MCP Ethernet"
-f_network "nxge" "Neterion Xframe 10GbE Server/Storage adapter"
-f_network "pcn" "AMD Am79c79x PCI Ethernet card"
-f_network "plip" "Parallel Port IP (PLIP) peer connection"
-f_network "ral" "Ralink Technology IEEE 802.11 wireless adapter"
-f_network "ray" "Raytheon Raylink 802.11 wireless adapter"
-f_network "re" "RealTek 8139C+/8169/8169S/8110S PCI Ethernet adapter"
-f_network "rl" "RealTek 8129/8139 PCI Ethernet card"
-f_network "rue" "RealTek USB Ethernet card"
-f_network "rum" "Ralink Technology USB IEEE 802.11 wireless adapter"
-f_network "sf" "Adaptec AIC-6915 PCI Ethernet card"
-f_network "sge" "Silicon Integrated Systems SiS190/191 Ethernet"
-f_network "sis" "SiS 900/SiS 7016 PCI Ethernet card"
-f_network "sk" "SysKonnect PCI Gigabit Ethernet card"
-f_network "snc" "SONIC Ethernet card"
-f_network "sn" "SMC/Megahertz Ethernet card"
- # Maintain sequential order of above(2): snc sn
-f_network "sr" "SDL T1/E1 sync serial PCI card"
-f_network "ste" "Sundance ST201 PCI Ethernet card"
-f_network "stge" "Sundance/Tamarack TC9021 Gigabit Ethernet"
-f_network "ti" "Alteon Networks PCI Gigabit Ethernet card"
-f_network "tl" "Texas Instruments ThunderLAN PCI Ethernet card"
-f_network "txp" "3Com 3cR990 Ethernet card"
-f_network "tx" "SMC 9432TX Ethernet card"
- # Maintain sequential order of above(2): txp tx
-f_network "uath" "Atheros AR5005UG and AR5005UX USB wireless adapter"
-f_network "upgt" "Conexant/Intersil PrismGT USB wireless adapter"
-f_network "ural" "Ralink Technology RT2500USB 802.11 wireless adapter"
-f_network "urtw" "Realtek 8187L USB wireless adapter"
-f_network "vge" "VIA VT612x PCI Gigabit Ethernet card"
-f_network "vlan" "IEEE 802.1Q VLAN network interface"
-f_network "vr" "VIA VT3043/VT86C100A Rhine PCI Ethernet card"
-f_network "vx" "3COM 3c590 / 3c595 Ethernet card"
-f_network "wb" "Winbond W89C840F PCI Ethernet card"
-f_network "wi" "Lucent WaveLAN/IEEE 802.11 wireless adapter"
-f_network "wpi" "Intel 3945ABG IEEE 802.11 wireless adapter"
-f_network "wx" "Intel Gigabit Ethernet (82452) card"
-f_network "xe" "Xircom/Intel EtherExpress Pro100/16 Ethernet card"
-f_network "xl" "3COM 3c90x / 3c90xB PCI Ethernet card"
-f_network "zyd" "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"
+f_network "ae%d" "Attansic/Atheros L2 Fast Ethernet"
+f_network "age%d" "Attansic/Atheros L1 Gigabit Ethernet"
+f_network "alc%d" "Atheros AR8131/AR8132 PCIe Ethernet"
+f_network "ale%d" "Atheros AR8121/AR8113/AR8114 PCIe Ethernet"
+f_network "an%d" "Aironet 4500/4800 802.11 wireless adapter"
+f_network "ath%d" "Atheros IEEE 802.11 wireless adapter"
+f_network "aue%d" "ADMtek USB Ethernet adapter"
+f_network "axe%d" "ASIX Electronics USB Ethernet adapter"
+f_network "bce%d" "Broadcom NetXtreme II Gigabit Ethernet card"
+f_network "bfe%d" "Broadcom BCM440x PCI Ethernet card"
+f_network "bge%d" "Broadcom BCM570x PCI Gigabit Ethernet card"
+f_network "bm%d" "Apple BMAC Built-in Ethernet"
+f_network "bwn%d" "Broadcom BCM43xx IEEE 802.11 wireless adapter"
+f_network "cas%d" "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"
+f_network "cc3i%d" "SDL HSSI sync serial PCI card"
+f_network "cue%d" "CATC USB Ethernet adapter"
+f_network "cxgb%d" "Chelsio T3 10Gb Ethernet card"
+f_network "dc%d" "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"
+f_network "de%d" "DEC DE435 PCI NIC or other DC21040-AA based card"
+f_network "disc%d" "Software discard network interface"
+f_network "ed%d" "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"
+f_network "el%d" "3Com 3C501 Ethernet card"
+f_network "em%d" "Intel(R) PRO/1000 Ethernet card"
+f_network "en%d" "Efficient Networks ATM PCI card"
+f_network "ep%d" "3Com 3C509 Ethernet card/3C589 PCMCIA"
+f_network "et%d" "Agere ET1310 based PCI Express Gigabit Ethernet card"
+f_network "ex%d" "Intel EtherExpress Pro/10 Ethernet card"
+f_network "fe%d" "Fujitsu MB86960A/MB86965A Ethernet card"
+f_network "fpa%d" "DEC DEFPA PCI FDDI card"
+f_network "fwe%d" "FireWire Ethernet emulation"
+f_network "fwip%d" "IP over FireWire"
+f_network "fxp%d" "Intel EtherExpress Pro/100B PCI Fast Ethernet card"
+f_network "gem%d" "Apple GMAC or Sun ERI/GEM Ethernet adapter"
+f_network "hme%d" "Sun HME (Happy Meal Ethernet) Ethernet adapter"
+f_network "ie%d" "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"
+f_network "igb%d" "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"
+f_network "ipw%d" "Intel PRO/Wireless 2100 IEEE 802.11 adapter"
+f_network "iwi%d" "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"
+f_network "iwn%d" "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"
+f_network "ix%d" "Intel Etherexpress Ethernet card"
+f_network "ixgb%d" "Intel(R) PRO/10Gb Ethernet card"
+f_network "ixgbe%d" "Intel(R) PRO/10Gb Ethernet card"
+f_network "jme%d" "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"
+f_network "kue%d" "Kawasaki LSI USB Ethernet adapter"
+f_network "le%d" "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"
+f_network "lge%d" "Level 1 LXT1001 Gigabit Ethernet card"
+f_network "lnc%d" "Lance/PCnet (Isolan/Novell NE2100/NE32-VL) Ethernet"
+f_network "lo%d" "Loop-back (local) network interface"
+f_network "lp%d" "Parallel Port IP (PLIP) peer connection"
+f_network "malo%d" "Marvell Libertas 88W8335 802.11 wireless adapter"
+f_network "msk%d" "Marvell/SysKonnect Yukon II Gigabit Ethernet"
+f_network "mxge%d" "Myricom Myri10GE 10Gb Ethernet card"
+f_network "nfe%d" "NVIDIA nForce MCP Ethernet"
+f_network "ng%d" "Vimage netgraph(4) bridged Ethernet device"
+f_network "nge%d" "NatSemi PCI Gigabit Ethernet card"
+f_network "nve%d" "NVIDIA nForce MCP Ethernet"
+f_network "nxge%d" "Neterion Xframe 10GbE Server/Storage adapter"
+f_network "pcn%d" "AMD Am79c79x PCI Ethernet card"
+f_network "plip%d" "Parallel Port IP (PLIP) peer connection"
+f_network "ral%d" "Ralink Technology IEEE 802.11 wireless adapter"
+f_network "ray%d" "Raytheon Raylink 802.11 wireless adapter"
+f_network "re%d" "RealTek 8139C+/8169/8169S/8110S PCI Ethernet adapter"
+f_network "rl%d" "RealTek 8129/8139 PCI Ethernet card"
+f_network "rue%d" "RealTek USB Ethernet card"
+f_network "rum%d" "Ralink Technology USB IEEE 802.11 wireless adapter"
+f_network "sf%d" "Adaptec AIC-6915 PCI Ethernet card"
+f_network "sge%d" "Silicon Integrated Systems SiS190/191 Ethernet"
+f_network "sis%d" "SiS 900/SiS 7016 PCI Ethernet card"
+f_network "sk%d" "SysKonnect PCI Gigabit Ethernet card"
+f_network "sn%d" "SMC/Megahertz Ethernet card"
+f_network "snc%d" "SONIC Ethernet card"
+f_network "sr%d" "SDL T1/E1 sync serial PCI card"
+f_network "ste%d" "Sundance ST201 PCI Ethernet card"
+f_network "stge%d" "Sundance/Tamarack TC9021 Gigabit Ethernet"
+f_network "ti%d" "Alteon Networks PCI Gigabit Ethernet card"
+f_network "tl%d" "Texas Instruments ThunderLAN PCI Ethernet card"
+f_network "tx%d" "SMC 9432TX Ethernet card"
+f_network "txp%d" "3Com 3cR990 Ethernet card"
+f_network "uath%d" "Atheros AR5005UG and AR5005UX USB wireless adapter"
+f_network "upgt%d" "Conexant/Intersil PrismGT USB wireless adapter"
+f_network "ural%d" "Ralink Technology RT2500USB 802.11 wireless adapter"
+f_network "urtw%d" "Realtek 8187L USB wireless adapter"
+f_network "vge%d" "VIA VT612x PCI Gigabit Ethernet card"
+f_network "vlan%d" "IEEE 802.1Q VLAN network interface"
+f_network "vr%d" "VIA VT3043/VT86C100A Rhine PCI Ethernet card"
+f_network "vx%d" "3COM 3c590 / 3c595 Ethernet card"
+f_network "wb%d" "Winbond W89C840F PCI Ethernet card"
+f_network "wi%d" "Lucent WaveLAN/IEEE 802.11 wireless adapter"
+f_network "wpi%d" "Intel 3945ABG IEEE 802.11 wireless adapter"
+f_network "wx%d" "Intel Gigabit Ethernet (82452) card"
+f_network "xe%d" "Xircom/Intel EtherExpress Pro100/16 Ethernet card"
+f_network "xl%d" "3COM 3c90x / 3c90xB PCI Ethernet card"
+f_network "zyd%d" "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"
+
+DEVICE_CATALOG_APPEND_ONLY= # Additional loading modifies existing devices
-f_dprintf "%s: Initialized %u known device names/descriptions." device.subr \
- "$( set -- $DEVICE_NAMES; echo $# )"
+f_count NCATALOG_DEVICES $DEVICE_CATALOG
+f_dprintf "%s: Initialized device catalog with %u names/descriptions." \
+ device.subr $NCATALOG_DEVICES
#
# Scan for the above devices unless requeted otherwise
diff --git a/usr.sbin/bsdconfig/share/dialog.subr b/usr.sbin/bsdconfig/share/dialog.subr
index ff7fc86358216..e0dfe80636338 100644
--- a/usr.sbin/bsdconfig/share/dialog.subr
+++ b/usr.sbin/bsdconfig/share/dialog.subr
@@ -1,6 +1,6 @@
if [ ! "$_DIALOG_SUBR" ]; then _DIALOG_SUBR=1
#
-# Copyright (c) 2006-2013 Devin Teske
+# Copyright (c) 2006-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -296,12 +296,25 @@ f_dialog_backtitle_restore()
#
f_dialog_max_size()
{
+ local funcname=f_dialog_max_size
local __var_height="$1" __var_width="$2" __max_size
[ "$__var_height" -o "$__var_width" ] || return $FAILURE
if [ "$USE_XDIALOG" ]; then
__max_size="$XDIALOG_MAXSIZE" # see CONFIGURATION
else
- __max_size=$( stty size 2> /dev/null ) # usually "24 80"
+ if __max_size=$( $DIALOG --print-maxsize \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
+ then
+ f_dprintf "$funcname: %s --print-maxsize = [%s]" \
+ "$DIALOG" "$__max_size"
+ # usually "MaxSize: 24, 80"
+ __max_size="${__max_size#*: }"
+ f_replaceall "$__max_size" "," "" __max_size
+ else
+ f_eval_catch -dk __max_size $funcname stty \
+ 'stty size' || __max_size=
+ # usually "24 80"
+ fi
: ${__max_size:=$DEFAULT_TERMINAL_SIZE}
fi
if [ "$__var_height" ]; then
@@ -415,8 +428,8 @@ f_dialog_size_constrain()
if [ "$debug" ]; then
# Print final constrained values to debugging
- f_quietly f_getvar "$__var_height"
- f_quietly f_getvar "$__var_width"
+ [ "$__var_height" ] && f_quietly f_getvar "$__var_height"
+ [ "$__var_width" ] && f_quietly f_getvar "$__var_width"
fi
return $__retval # success if no debug warnings were printed
@@ -456,16 +469,17 @@ f_dialog_menu_constrain()
# Print debug warnings if any given (non-NULL) argument are invalid
# NOTE: Don't change the name of $__{var,min,}{height,width,rows}
#
- local __height __width __rows
+ local __height_menu_constrain __width_menu_constrain
+ local __rows_menu_constrain
local __arg __cp __fname=f_dialog_menu_constrain
for __arg in height width rows; do
debug= f_getvar __var_$__arg __cp
[ "$__cp" ] || continue
- if ! debug= f_getvar "$__cp" __$__arg; then
+ if ! debug= f_getvar "$__cp" __${__arg}_menu_constrain; then
f_dprintf "%s: var_%s variable \`%s' not set" \
$__fname $__arg "$__cp"
__retval=$FAILURE
- elif ! eval f_isinteger \$__$__arg; then
+ elif ! eval f_isinteger \$__${__arg}_menu_constrain; then
f_dprintf "%s: var_%s variable value not a number" \
$__fname $__arg
__retval=$FAILURE
@@ -489,9 +503,11 @@ f_dialog_menu_constrain()
# Adjust height if desired
if [ "$__var_height" ]; then
- if [ $__height -lt ${__min_height:-0} ]; then
+ if [ $__height_menu_constrain -lt ${__min_height:-0} ]; then
setvar "$__var_height" $__min_height
- elif [ $__height -gt $__max_height_menu_constrain ]; then
+ elif [ $__height_menu_constrain -gt \
+ $__max_height_menu_constrain ]
+ then
setvar "$__var_height" $__max_height_menu_constrain
fi
fi
@@ -503,9 +519,11 @@ f_dialog_menu_constrain()
else
: ${__min_width:=${DIALOG_MIN_WIDTH:-24}}
fi
- if [ $__width -lt $__min_width ]; then
+ if [ $__width_menu_constrain -lt $__min_width ]; then
setvar "$__var_width" $__min_width
- elif [ $__width -gt $__max_width_menu_constrain ]; then
+ elif [ $__width_menu_constrain -gt \
+ $__max_width_menu_constrain ]
+ then
setvar "$__var_width" $__max_width_menu_constrain
fi
fi
@@ -518,24 +536,28 @@ f_dialog_menu_constrain()
: ${__min_rows:=0}
fi
- local __max_rows=$(( $__max_height_menu_constrain - 8 ))
+ local __max_rows_menu_constrain=$((
+ $__max_height_menu_constrain - 7
+ ))
# If prompt_len is zero (no prompt), bump the max-rows by 1
# Default assumption is (if no argument) that there's no prompt
- [ ${__prompt_len:-0} -gt 0 ] ||
- __max_rows=$(( $__max_rows + 1 ))
+ [ ${__prompt_len:-0} -gt 0 ] || __max_rows_menu_constrain=$((
+ $__max_rows_menu_constrain + 1
+ ))
- if [ $__rows -lt $__min_rows ]; then
+ if [ $__rows_menu_constrain -lt $__min_rows ]; then
setvar "$__var_rows" $__min_rows
- elif [ $__rows -gt $__max_rows ]; then
- setvar "$__var_rows" $__max_rows
+ elif [ $__rows_menu_constrain -gt $__max_rows_menu_constrain ]
+ then
+ setvar "$__var_rows" $__max_rows_menu_constrain
fi
fi
if [ "$debug" ]; then
- # Print final constrained values to debuggin
- f_quietly f_getvar "$__var_height"
- f_quietly f_getvar "$__var_width"
- f_quietly f_getvar "$__var_rows"
+ # Print final constrained values to debugging
+ [ "$__var_height" ] && f_quietly f_getvar "$__var_height"
+ [ "$__var_width" ] && f_quietly f_getvar "$__var_width"
+ [ "$__var_rows" ] && f_quietly f_getvar "$__var_rows"
fi
return $__retval # success if no debug warnings were printed
@@ -1087,19 +1109,20 @@ f_dialog_radiolist_size()
# longest item-length (both used to bump the width), and the number of
# rows (used to bump the height).
#
- local __longest_tag=0 __longest_item=0 __rows=0
+ local __longest_tag=0 __longest_item=0 __rows_rlist_size=0
while [ $# -ge 3 ]; do
local __tag="$1" __item="$2"
shift 3 # tag/item/status
[ ${#__tag} -gt $__longest_tag ] && __longest_tag=${#__tag}
[ ${#__item} -gt $__longest_item ] && __longest_item=${#__item}
- __rows=$(( $__rows + 1 ))
+ __rows_rlist_size=$(( $__rows_rlist_size + 1 ))
done
# Adjust rows early (for up-coming height calculation)
if [ "$__var_height" -o "$__var_rows" ]; then
# Add a row for visual aid if using Xdialog(1)
- [ "$USE_XDIALOG" ] && __rows=$(( $__rows + 1 ))
+ [ "$USE_XDIALOG" ] &&
+ __rows_rlist_size=$(( $__rows_rlist_size + 1 ))
fi
# Adjust height if desired
@@ -1107,10 +1130,12 @@ f_dialog_radiolist_size()
# Add rows to height
if [ "$USE_XDIALOG" ]; then
__height_rlist_size=$((
- $__height_rlist_size + $__rows + 7 ))
+ $__height_rlist_size + $__rows_rlist_size + 7
+ ))
else
__height_rlist_size=$((
- $__height_rlist_size + $__rows + 4 ))
+ $__height_rlist_size + $__rows_rlist_size + 4
+ ))
fi
setvar "$__var_height" $__height_rlist_size
fi
@@ -1127,7 +1152,7 @@ f_dialog_radiolist_size()
fi
# Store adjusted rows if desired
- [ "$__var_rows" ] && setvar "$__var_rows" $__rows
+ [ "$__var_rows" ] && setvar "$__var_rows" $__rows_rlist_size
# Constrain height, width, and rows to sensible minimum/maximum values
# Return success if no-constrain, else return status from constrain
@@ -1207,20 +1232,26 @@ f_dialog_radiolist_with_help_size()
# all used to bump the width -- and the number of rows (used to bump
# the height).
#
- local __longest_tag=0 __longest_item=0 __longest_help=0 __rows=0
+ local __longest_tag=0 __longest_item=0 __longest_help=0
+ local __rows_rlist_with_help_size=0
while [ $# -ge 4 ]; do
local __tag="$1" __item="$2" __status="$3" __help="$4"
shift 4 # tag/item/status/help
[ ${#__tag} -gt $__longest_tag ] && __longest_tag=${#__tag}
[ ${#__item} -gt $__longest_item ] && __longest_item=${#__item}
[ ${#__help} -gt $__longest_help ] && __longest_help=${#__help}
- __rows=$(( $__rows + 1 ))
+ __rows_rlist_with_help_size=$((
+ $__rows_rlist_with_help_size + 1
+ ))
done
# Adjust rows early (for up-coming height calculation)
if [ "$__var_height" -o "$__var_rows" ]; then
# Add a row for visual aid if using Xdialog(1)
- [ "$USE_XDIALOG" ] && __rows=$(( $__rows + 1 ))
+ [ "$USE_XDIALOG" ] &&
+ __rows_rlist_with_help_size=$((
+ $__rows_rlist_with_help_size + 1
+ ))
fi
# Adjust height if desired
@@ -1228,10 +1259,14 @@ f_dialog_radiolist_with_help_size()
# Add rows to height
if [ "$USE_XDIALOG" ]; then
__height_rlist_with_help_size=$((
- $__height_rlist_with_help_size + $__rows + 7 ))
+ $__height_rlist_with_help_size +
+ $__rows_rlist_with_help_size + 7
+ ))
else
__height_rlist_with_help_size=$((
- $__height_rlist_with_help_size + $__rows + 4 ))
+ $__height_rlist_with_help_size +
+ $__rows_rlist_with_help_size + 4
+ ))
fi
setvar "$__var_height" $__height
fi
@@ -1257,7 +1292,7 @@ f_dialog_radiolist_with_help_size()
fi
# Store adjusted rows if desired
- [ "$__var_rows" ] && setvar "$__var_rows" $__rows
+ [ "$__var_rows" ] && setvar "$__var_rows" $__rows_rlist_with_help_size
# Constrain height, width, and rows to sensible minimum/maximum values
# Return success if no-constrain, else return status from constrain
@@ -2043,7 +2078,10 @@ f_dialog_menutag2index_with_help()
#
f_dialog_init()
{
+ local funcname=f_dialog_init
+
DIALOG_SELF_INITIALIZE=
+ USE_DIALOG=1
#
# Clone terminal stdout so we can redirect to it from within sub-shells
@@ -2087,7 +2125,7 @@ f_dialog_init()
#
# Process `-X' command-line option
#
- [ "$USE_XDIALOG" ] && DIALOG=Xdialog
+ [ "$USE_XDIALOG" ] && DIALOG=Xdialog USE_DIALOG=
#
# Sanity check, or die gracefully
@@ -2130,7 +2168,7 @@ f_dialog_init()
DIALOG=dialog
f_die 1 "$msg_no_such_file_or_directory" "$pgm" "xauth"
fi
- HOSTNAME=$(hostname)
+ HOSTNAME=$( hostname )
local displaynum="${DISPLAY#*:}"
eval xauth -if \~$SUDO_USER/.Xauthority extract - \
\"\$HOSTNAME/unix:\$displaynum\" \
@@ -2144,7 +2182,8 @@ f_dialog_init()
#
if [ "$USE_XDIALOG" ]; then
local maxsize
- if ! maxsize=$( LANG= LC_ALL= $DIALOG --print-maxsize 2>&1 )
+ if ! f_eval_catch -dk maxsize $funcname "$DIALOG" \
+ 'LANG= LC_ALL= %s --print-maxsize' "$DIALOG"
then
# Xdialog(1) failed, fall back to dialog(1)
unset USE_XDIALOG
diff --git a/usr.sbin/bsdconfig/share/geom.subr b/usr.sbin/bsdconfig/share/geom.subr
new file mode 100644
index 0000000000000..19ed7840be17f
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/geom.subr
@@ -0,0 +1,430 @@
+if [ ! "$_GEOM_SUBR" ]; then _GEOM_SUBR=1
+#
+# Copyright (c) 2012-2014 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$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." geom.subr
+f_include $BSDCFG_SHARE/strings.subr
+f_include $BSDCFG_SHARE/struct.subr
+
+############################################################ GLOBALS
+
+NGEOM_CLASSES=0 # Set by f_geom_get_all()/f_geom_reset()
+
+#
+# GEOM classes for use with f_geom_find()
+#
+# NB: Since $GEOM_CLASS_ANY is the NULL string, make sure you quote it whenever
+# you put arguments after it.
+#
+setvar GEOM_CLASS_ANY "any"
+setvar GEOM_CLASS_DEV "DEV"
+setvar GEOM_CLASS_DISK "DISK"
+setvar GEOM_CLASS_ELI "ELI"
+setvar GEOM_CLASS_FD "FD"
+setvar GEOM_CLASS_LABEL "LABEL"
+setvar GEOM_CLASS_MD "MD"
+setvar GEOM_CLASS_NOP "NOP"
+setvar GEOM_CLASS_PART "PART"
+setvar GEOM_CLASS_RAID "RAID"
+setvar GEOM_CLASS_SWAP "SWAP"
+setvar GEOM_CLASS_VFS "VFS"
+setvar GEOM_CLASS_ZFS_VDEV "ZFS::VDEV"
+setvar GEOM_CLASS_ZFS_ZVOL "ZFS::ZVOL"
+
+#
+# GEOM structure definitions
+#
+f_struct_define GEOM_CLASS \
+ id name ngeoms
+f_struct_define GEOM_GEOM \
+ id class_ref config name nconsumers nproviders rank
+ # Also consumerN where N is 1 through nconsumers
+ # Also providerN where N is 1 through nproviders
+f_struct_define GEOM_CONSUMER \
+ id geom_ref config mode provider_ref
+f_struct_define GEOM_PROVIDER \
+ id geom_ref config mode name mediasize
+
+# The config property of GEOM_GEOM struct is defined as this
+f_struct_define GEOM_GEOM_CONFIG \
+ entries first fwheads fwsectors last modified scheme state
+
+# The config property of GEOM_PROVIDER struct is defined as this
+f_struct_define GEOM_PROVIDER_CONFIG \
+ descr file fwheads fwsectors ident length type unit
+
+#
+# Default behavior is to call f_geom_get_all() automatically when loaded.
+#
+: ${GEOM_SELF_SCAN_ALL=1}
+
+############################################################ FUNCTIONS
+
+# f_geom_get_all
+#
+# Parse sysctl(8) `kern.geom.confxml' data into a series of structs. GEOM
+# classes are at the top of the heirarchy and are stored as numbered structs
+# from 1 to $NGEOM_CLASSES (set by this function) named `geom_class_C'. GEOM
+# objects within each class are stored as numbered structs from 1 to `ngeoms'
+# (a property of the GEOM class struct) named `geom_class_C_geom_N' (where C
+# is the class number and N is the geom number).
+#
+# Use the function f_geom_find() to get a list of geoms (execute without
+# arguments) or find specific geoms by class or name.
+#
+f_geom_get_all()
+{
+ eval "$( sysctl -n kern.geom.confxml | awk '
+ BEGIN {
+ struct_count["class"] = 0
+ struct_count["geom"] = 0
+ struct_count["consumer"] = 0
+ struct_count["provider"] = 0
+ }
+ ############################################### FUNCTIONS
+ function set_value(prop, value)
+ {
+ if (!struct_stack[cur_struct]) return
+ printf "%s set %s \"%s\"\n",
+ struct_stack[cur_struct], prop, value
+ }
+ function create(type, id)
+ {
+ if (struct = created[type "_" id])
+ print "f_struct_free", struct
+ else {
+ struct = struct_stack[cur_struct]
+ struct = struct ( struct ? "" : "geom" )
+ struct = struct "_" type "_" ++struct_count[type]
+ created[type "_" id] = struct
+ }
+ print "debug= f_struct_new GEOM_" toupper(type), struct
+ cur_struct++
+ struct_stack[cur_struct] = struct
+ type_stack[cur_struct] = type
+ set_value("id", id)
+ }
+ function create_config()
+ {
+ struct = struct_stack[cur_struct]
+ struct = struct ( struct ? "" : "geom" )
+ struct = struct "_config"
+ set_value("config", struct)
+ type = type_stack[cur_struct]
+ print "debug= f_struct_new GEOM_" toupper(type) "_CONFIG", \
+ struct
+ cur_struct++
+ struct_stack[cur_struct] = struct
+ type_stack[cur_struct] = type "_config"
+ }
+ function extract_attr(field, attr)
+ {
+ if (match(field, attr "=\"0x[[:xdigit:]]+\"")) {
+ len = length(attr)
+ return substr($2, len + 3, RLENGTH - len - 3)
+ }
+ }
+ function extract_data(type)
+ {
+ data = $0
+ sub("^[[:space:]]*<" type ">", "", data)
+ sub("</" type ">.*$", "", data)
+ return data
+ }
+ ############################################### OPENING PATTERNS
+ $1 == "<mesh>" { mesh = 1 }
+ $1 ~ /^<(class|geom)$/ && mesh {
+ prop = substr($1, 2)
+ if ((ref = extract_attr($2, "ref")) != "")
+ set_value(prop "_ref", ref)
+ else if ((id = extract_attr($2, "id")) != "")
+ create(prop, id)
+ }
+ $1 ~ /^<(consumer|provider)$/ && mesh {
+ prop = substr($1, 2)
+ if ((ref = extract_attr($2, "ref")) != "")
+ set_value(prop "_ref", ref)
+ else if ((id = extract_attr($2, "id")) != "") {
+ create(prop, id)
+ cur_struct--
+ propn = struct_count[prop]
+ set_value(prop propn, struct_stack[cur_struct+1])
+ cur_struct++
+ }
+ }
+ $1 == "<config>" && mesh { create_config() }
+ ############################################### PROPERTIES
+ $1 ~ /^<[[:alnum:]]+>/ {
+ prop = $1
+ sub(/^</, "", prop); sub(/>.*/, "", prop)
+ set_value(prop, extract_data(prop))
+ }
+ ############################################### CLOSING PATTERNS
+ $1 ~ "^</(consumer|provider|config)>$" { cur_struct-- }
+ $1 == "</geom>" {
+ set_value("nconsumers", struct_count["consumer"])
+ set_value("nproviders", struct_count["provider"])
+ cur_struct--
+ struct_count["consumer"] = 0
+ struct_count["provider"] = 0
+ }
+ $1 == "</class>" {
+ set_value("ngeoms", struct_count["geom"])
+ cur_struct--
+ struct_count["consumer"] = 0
+ struct_count["provider"] = 0
+ struct_count["geom"] = 0
+ }
+ $1 == "</mesh>" {
+ printf "NGEOM_CLASSES=%u\n", struct_count["class"]
+ delete struct_count
+ mesh = 0
+ }' )"
+}
+
+# f_geom_reset
+#
+# Reset the registered GEOM chain.
+#
+f_geom_reset()
+{
+ local classn=1 class ngeoms geomn geom
+ while [ $classn -le ${NGEOM_CLASSES:-0} ]; do
+ class=geom_class_$classn
+ $class get ngeoms ngeoms
+ geomn=1
+ while [ $geomn -le $ngeoms ]; do
+ f_struct_free ${class}_geom_$geomn
+ geomn=$(( $geomn + 1 ))
+ done
+ classn=$(( $classn + 1 ))
+ done
+ NGEOM_CLASSES=0
+}
+
+# f_geom_rescan
+#
+# Rescan all GEOMs - convenience function.
+#
+f_geom_rescan()
+{
+ f_geom_reset
+ f_geom_get_all
+}
+
+# f_geom_find $name [$type [$var_to_set]]
+#
+# Find one or more registered GEOMs by name, type, or both. Returns a space-
+# separated list of GEOMs matching the search criterion. The $type argument
+# should be the GEOM class (see $GEOM_CLASS_* variables in GLOBALS above).
+#
+# If $var_to_set is missing or NULL, the GEOM name(s) are printed to standard
+# out for capturing in a sub-shell (which is less-recommended because of
+# performance degredation; for example, when called in a loop).
+#
+f_geom_find()
+{
+ local __name="$1" __type="${2:-$GEOM_CLASS_ANY}" __var_to_set="$3"
+ local __classn=1 __class __class_name __ngeoms
+ local __geomn __geom __geom_name __found=
+ while [ $__classn -le ${NGEOM_CLASSES:-0} ]; do
+ __class=geom_class_$__classn
+ $__class get name __class_name
+ if [ "$__type" != "$GEOM_CLASS_ANY" -a \
+ "$__type" != "$__class_name" ]
+ then
+ __classn=$(( $__classn + 1 ))
+ continue
+ fi
+
+ __geomn=1
+ $__class get ngeoms __ngeoms || __ngeoms=0
+ while [ $__geomn -le $__ngeoms ]; do
+ __geom=${__class}_geom_$__geomn
+ $__geom get name __geom_name
+ [ "$__name" = "$__geom_name" -o ! "$__name" ] &&
+ __found="$__found $__geom"
+ __geomn=$(( $__geomn + 1 ))
+ done
+ __classn=$(( $__classn + 1 ))
+ done
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "${__found# }"
+ else
+ echo $__found
+ fi
+ [ "$__found" ] # Return status
+}
+
+# f_geom_find_by $prop $find [$type [$var_to_set]]
+#
+# Find GEOM-related struct where $prop of the struct is equal to $find. Returns
+# NULL or the name of the first GEOM struct to match. The $type argument should
+# be one of the following:
+#
+# NULL Find any of the below
+# class Find GEOM_CLASS struct
+# geom Find GEOM_GEOM struct
+# consumer Find GEOM_CONSUMER struct
+# provider Find GEOM_PROVIDER struct
+#
+# The $prop argument can be any property of the given type of struct. Some
+# properties are common to all types (such as id) so the $type argument is
+# optional (allowing you to return any struct whose property matches $find).
+#
+# If $var_to_set is missing or NULL, the GEOM struct name is printed to
+# standard out for capturing in a sub-shell (which is less-recommended because
+# of performance degredation; for example when called in a loop).
+#
+f_geom_find_by()
+{
+ local __prop="$1" __find="$2" __type="$3" __var_to_set="$4"
+ local __classn=1 __class __ngeoms
+ local __geomn __geom __nitems
+ local __itype __itemn __item
+ local __value __found=
+
+ if [ ! "$__prop" ]; then
+ [ "$__var_to_set" ] && setvar "$__var_to_set" ""
+ return $FAILURE
+ fi
+
+ case "$__type" in
+ "") : OK ;;
+ class|GEOM_CLASS) __type=class ;;
+ geom|GEOM_GEOM) __type=geom ;;
+ consumer|GEOM_CONSUMER) __type=consumer ;;
+ provider|GEOM_PROVIDER) __type=provider ;;
+ *)
+ [ "$__var_to_set" ] && setvar "$__var_to_set" ""
+ return $FAILURE
+ esac
+
+ while [ $__classn -le ${NGEOM_CLASSES:-0} ]; do
+ __class=geom_class_$__classn
+
+ if [ "${__type:-class}" = "class" ]; then
+ $__class get "$__prop" __value || __value=
+ [ "$__value" = "$__find" ] && __found="$__class" break
+ [ "$__type" ] && __classn=$(( $__classn + 1 )) continue
+ fi
+
+ __geomn=1
+ $__class get ngeoms __ngeoms || __ngeoms=0
+ while [ $__geomn -le $__ngeoms ]; do
+ __geom=${__class}_geom_$__geomn
+
+ if [ "${__type:-geom}" = "geom" ]; then
+ $__geom get "$__prop" __value || __value=
+ [ "$__value" = "$__find" ] &&
+ __found="$__geom" break
+ [ "$__type" ] &&
+ __geomn=$(( $__geomn + 1 )) continue
+ fi
+
+ for __itype in ${__type:-consumer provider}; do
+ $__geom get n${__itype}s __nitems || continue
+ __itemn=1
+ while [ $__itemn -le $__nitems ]; do
+ __item=${__geom}_${__itype}_$__itemn
+
+ $__item get "$__prop" __value ||
+ __value=
+ [ "$__value" = "$__find" ] &&
+ __found="$__item" break
+ __itemn=$(( $__itemn + 1 ))
+ done
+ [ "$__found" ] && break
+ done
+ [ "$__found" ] && break
+ __geomn=$(( $__geomn + 1 ))
+ done
+ [ "$__found" ] && break
+ __classn=$(( $__classn + 1 ))
+ done
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$__found"
+ else
+ [ "$__found" ] && echo "$__found"
+ fi
+ [ "$__found" ] # Return status
+}
+
+# f_geom_parent $geom|$consumer|$provider|$config [$var_to_set]
+#
+# Get the GEOM class associated with one of $geom, $consumer, $provider or
+# $config.
+#
+# If $var_to_set is missing or NULL, the GEOM class name is printed to standard
+# out for capturing in a sub-shell (which is less-recommended because of
+# performance degredation; for example when called in a loop).
+#
+f_geom_parent()
+{
+ local __struct="$1" __var_to_set="$2"
+ # NB: Order of pattern matches below is important
+ case "$__struct" in
+ *_config*) __struct="${__struct%_config*}" ;;
+ *_consumer_*) __struct="${__struct%_consumer_[0-9]*}" ;;
+ *_provider_*) __struct="${__struct%_provider_[0-9]*}" ;;
+ *_geom_*) __struct="${__struct%_geom_[0-9]*}" ;;
+ *) __struct=
+ esac
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$__struct"
+ else
+ echo "$__struct"
+ fi
+ f_struct "$__struct" # Return status
+}
+
+############################################################ MAIN
+
+#
+# Parse GEOM configuration unless requeted otherwise
+#
+f_dprintf "%s: GEOM_SELF_SCAN_ALL=[%s]" geom.subr "$GEOM_SELF_SCAN_ALL"
+case "$GEOM_SELF_SCAN_ALL" in
+""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
+*)
+ f_geom_get_all
+ if [ "$debug" ]; then
+ debug= f_geom_find "" "$GEOM_CLASS_ANY" geoms
+ f_count ngeoms $geoms
+ f_dprintf "%s: Initialized %u geom devices in %u classes." \
+ geom.subr "$ngeoms" "$NGEOM_CLASSES"
+ unset geoms ngeoms
+ fi
+esac
+
+f_dprintf "%s: Successfully loaded." geom.subr
+
+fi # ! $_GEOM_SUBR
diff --git a/usr.sbin/bsdconfig/share/keymap.subr b/usr.sbin/bsdconfig/share/keymap.subr
new file mode 100644
index 0000000000000..d4f391c8c8b87
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/keymap.subr
@@ -0,0 +1,263 @@
+if [ ! "$_KEYMAP_SUBR" ]; then _KEYMAP_SUBR=1
+#
+# Copyright (c) 2013 Devin Teske
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." keymap.subr
+f_include $BSDCFG_SHARE/struct.subr
+
+############################################################ CONFIGURATION
+
+#
+# Defaults taken from usr.sbin/kbdmap/kbdmap.h
+#
+: ${DEFAULT_LANG:=en}
+: ${DEFAULT_KEYMAP_DIR:=/usr/share/syscons/keymaps}
+
+############################################################ GLOBALS
+
+KEYMAPS=
+NKEYMAPS=0
+
+# A "keymap" from kbdmap's point of view
+f_struct_define KEYMAP \
+ desc \
+ keym \
+ mark
+
+#
+# Default behavior is to call f_keymap_get_all() automatically when loaded.
+#
+: ${KEYMAP_SELF_SCAN_ALL=1}
+
+############################################################ FUNCTIONS
+
+# f_keymap_register $name $desc $keym $mark
+#
+# Register a keymap. A `structure' (see struct.subr) is created with the name
+# keymap_$name (so make sure $name contains only alpha-numeric characters or
+# the underscore, `_'). The remaining arguments after $name correspond to the
+# propertise of the `KEYMAP' structure-type (defined above).
+#
+# If not already registered, the keymap is then appended to the KEYMAPS
+# environment variable, a space-separated list of all registered keymaps.
+#
+f_keymap_register()
+{
+ local name="$1" desc="$2" keym="$3" mark="$4"
+
+ f_struct_new KEYMAP "keymap_$name" || return $FAILURE
+ keymap_$name set desc "$desc"
+ keymap_$name set keym "$keym"
+ keymap_$name set mark "$mark"
+
+ # Scan our global register to see if needs ammending
+ local k found=
+ for k in $KEYMAPS; do
+ [ "$k" = "$name" ] || continue
+ found=1 && break
+ done
+ [ "$found" ] || KEYMAPS="$KEYMAPS $name"
+
+ return $SUCCESS
+}
+
+# f_keymap_checkfile $keymap
+#
+# Check that $keymap is a readable kbdmap(5) file. Returns success if $keymap
+# is a file, is readable, and exists in $DEFAULT_KEYMAP_DIR; otherwise failure.
+# If debugging is enabled, an appropriate debug error message is printed if
+# $keymap is not available.
+#
+f_keymap_checkfile()
+{
+ local keym="$1"
+
+ # Fixup keymap if it doesn't already contain at least one `/'
+ [ "${keym#*/}" = "$keym" ] && keym="$DEFAULT_KEYMAP_DIR/$keym"
+
+ # Short-cuts
+ [ -f "$keym" -a -r "$keym" ] && return $SUCCESS
+ f_debugging || return $FAILURE
+
+ # Print an appropriate debug error message
+ if [ ! -e "$keym" ]; then
+ f_dprintf "%s: No such file or directory" "$keym"
+ elif [ ! -f "$keym" ]; then
+ f_dprintf "%s: Not a file!" "$keym"
+ elif [ ! -r "$keym" ]; then
+ f_dprintf "%s: Permission denied" "$keym"
+ fi
+
+ return $FAILURE
+}
+
+# f_keymap_get_all
+#
+# Get all keymap information for kbdmap(5) entries both in the database and
+# loosely existing in $DEFAULT_KEYMAP_DIR.
+#
+f_keymap_get_all()
+{
+ local fname=f_keymap_get_all
+ local lang="${LC_ALL:-${LC_CTYPE:-${LANG:-$DEFAULT_LANG}}}"
+ [ "$lang" = "C" ] && lang="$DEFAULT_LANG"
+
+ f_dprintf "%s: Looking for keymap files..." $fname
+ f_dialog_info "$msg_looking_for_keymap_files"
+ f_dprintf "DEFAULT_LANG=[%s]" "$DEFAULT_LANG"
+
+ eval "$( awk -F: -v lang="$lang" -v lang_default="$DEFAULT_LANG" '
+ BEGIN {
+ # en_US.ISO8859-1 -> en_..\.ISO8859-1
+ dialect = lang
+ if (length(dialect) >= 6 &&
+ substr(dialect, 3, 1) == "_")
+ dialect = substr(dialect, 1, 3) ".." \
+ substr(dialect, 6)
+ printf "f_dprintf \"dialect=[%%s]\" \"%s\";\n", dialect
+
+ # en_US.ISO8859-1 -> en
+ lang_abk = lang
+ if (length(lang_abk) >= 3 &&
+ substr(lang_abk, 3, 1) == "_")
+ lang_abk = substr(lang_abk, 1, 2)
+ printf "f_dprintf \"lang_abk=[%%s]\" \"%s\";\n",
+ lang_abk
+ }
+ function find_token(buffer, token)
+ {
+ if (split(buffer, tokens, /,/) == 0) return 0
+ found = 0
+ for (t in tokens)
+ if (token == tokens[t]) { found = 1; break }
+ return found
+ }
+ function add_keymap(desc,mark,keym)
+ {
+ marks[keym] = mark
+ name = keym
+ gsub(/[^[:alnum:]_]/, "_", name)
+ gsub(/'\''/, "'\''\\'\'\''", desc);
+ printf "f_keymap_checkfile %s && " \
+ "f_keymap_register %s '\'%s\'' %s %u\n",
+ keym, name, desc, keym, mark
+ }
+ !/^[[:space:]]*(#|$)/ {
+ sub(/^[[:space:]]*/, "", $0)
+ keym = $1
+ if (keym ~ /^(MENU|FONT)$/) next
+ lg = ($2 == "" ? lang_default : $2)
+
+ # Match the entry and store the type of match we made
+ # as the mark value (so that if we make a better match
+ # later on with a higher mark, it overwrites previous)
+
+ mark = marks[keym];
+ if (find_token(lg, lang))
+ add_keymap($3, 4, keym) # Best match
+ else if (mark <= 3 && find_token(lg, dialect))
+ add_keymap($3, 3, keym)
+ else if (mark <= 2 && find_token(lg, lang_abk))
+ add_keymap($3, 2, keym)
+ else if (mark <= 1 && find_token(lg, lang_default))
+ add_keymap($3, 1, keym)
+ else if (mark <= 0)
+ add_keymap($3, 0, keym)
+ }
+ ' "$DEFAULT_KEYMAP_DIR/INDEX.${DEFAULT_KEYMAP_DIR##*/}" )"
+
+
+ #
+ # Look for keymaps not in database
+ #
+ local direntry keym name
+ set +f # glob
+ for direntry in "$DEFAULT_KEYMAP_DIR"/*; do
+ [ "${direntry##*.}" = ".kbd" ] || continue
+ keym="${direntry##*/}"
+ f_str2varname "$keym" name
+ f_struct keymap_$name && continue
+ f_keymap_checkfile "$keym" &&
+ f_keymap_register $name "${keym%.*}" "$keym" 0
+ f_dprintf "%s: not in kbdmap(5) database" "$keym"
+ done
+
+ #
+ # Sort the items by their descriptions
+ #
+ f_dprintf "%s: Sorting keymap entries by description..." $fname
+ KEYMAPS=$(
+ for k in $KEYMAPS; do
+ echo -n "$k "
+ # NOTE: Translate '8x8' to '8x08' before sending to
+ # sort(1) so that things work out as we might expect.
+ debug= keymap_$k get desc | sed -e 's/8x8/8x08/g'
+ done | sort -k2 | awk '{
+ printf "%s%s", (started ? " " : ""), $1; started = 1
+ }'
+ )
+
+ return $SUCCESS
+}
+
+# f_keymap_kbdcontrol $keymap
+#
+# Install keyboard map file from $keymap.
+#
+f_keymap_kbdcontrol()
+{
+ local keymap="$1"
+
+ [ "$keymap" ] || return $SUCCESS
+
+ # Fixup keymap if it doesn't already contain at least one `/'
+ [ "${keymap#*/}" = "$keymap" ] && keymap="$DEFAULT_KEYMAP_DIR/$keymap"
+
+ [ "$USE_XDIALOG" ] || kbdcontrol -l "$keymap"
+}
+
+############################################################ MAIN
+
+#
+# Scan for keymaps unless requeted otherwise
+#
+f_dprintf "%s: KEYMAP_SELF_SCAN_ALL=[%s]" keymap.subr "$KEYMAP_SELF_SCAN_ALL"
+case "$KEYMAP_SELF_SCAN_ALL" in
+""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
+*) f_keymap_get_all
+esac
+
+f_count NKEYMAPS $KEYMAPS
+f_dprintf "%s: Found %u keymap file(s)." keymap.subr $NKEYMAPS
+
+f_dprintf "%s: Successfully loaded." keymap.subr
+
+fi # ! $_KEYMAP_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/cdrom.subr b/usr.sbin/bsdconfig/share/media/cdrom.subr
index c59f88aa58503..bbbd638fec6ea 100644
--- a/usr.sbin/bsdconfig/share/media/cdrom.subr
+++ b/usr.sbin/bsdconfig/share/media/cdrom.subr
@@ -58,31 +58,25 @@ f_media_set_cdrom()
local devs ndevs
f_device_find "" $DEVICE_TYPE_CDROM devs
- ndevs=$( set -- $devs; echo $# )
+ f_count ndevs $devs
if [ ${ndevs:=0} -eq 0 ]; then
f_interactive && f_show_msg "$msg_no_cd_dvd_devices_found"
return $FAILURE
- elif [ $ndevs -gt 1 ]; then
+ elif [ $ndevs -eq 1 ]; then
+ f_struct_copy $devs device_media
+ else
+ local dev
local title="$msg_choose_a_cd_dvd_type"
local prompt="$msg_please_select_a_cd_dvd_drive"
- local hline=""
+ local hline=
- local dev retval
dev=$( f_device_menu \
"$title" "$prompt" "$hline" $DEVICE_TYPE_CDROM \
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
- retval=$?
- [ "$dev" ] || return $FAILURE
-
- f_device_find "$dev" $DEVICE_TYPE_CDROM devs
- [ "$devs" ] || return $FAILURE
- dev="${devs%%[$IFS]*}"
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) ||
+ return $FAILURE
- f_struct_copy device_$dev device_media
- [ $retval -eq $SUCCESS ] || return $FAILURE
- else
- f_struct_copy device_$devs device_media
+ f_struct_copy "$dev" device_media
fi
f_struct device_media || return $FAILURE
@@ -95,9 +89,10 @@ f_media_set_cdrom()
#
f_media_init_cdrom()
{
+ local funcname=f_media_init_cdrom
local dev="$1" devname err
- device_$dev get devname devname || return $FAILURE
+ f_struct "$dev" get devname devname || return $FAILURE
f_dprintf "Init routine called for CDROM device. devname=[%s]" \
"$devname"
@@ -106,14 +101,13 @@ f_media_init_cdrom()
return $SUCCESS
fi
- if [ ! -e "$MOUNTPOINT" ] &&
- ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
- then
- f_dialog_msgbox "$err"
- return $FAILURE
+ if [ ! -e "$MOUNTPOINT" ]; then
+ f_eval_catch $funcname mkdir 'mkdir -p "%s"' "$MOUNTPOINT" ||
+ return $FAILURE
fi
- if ! err=$( mount_cd9660 "$devname" "$MOUNTPOINT" 2>&1 )
+ if ! f_eval_catch -dk err $funcname mount_cd9660 \
+ 'mount_cd9660 "%s" "%s"' "$devname" "$MOUNTPOINT"
then
err="${err#mount_cd9660: }"; err="${err#$devname: }"
case "$err" in
@@ -154,20 +148,22 @@ f_media_init_cdrom()
f_media_get_cdrom()
{
local dev="$1" file="$2" probe_type="$3"
+ local name
+ $dev get name name
f_dprintf "f_media_get_cdrom: dev=[%s] file=[%s] probe_type=%s" \
- "$dev" "$file" "$probe_type"
+ "$name" "$file" "$probe_type"
f_media_generic_get "$MOUNTPOINT" "$file" "$probe_type"
}
# f_media_shutdown_cdrom $device
#
-# Shuts down the CDROM device and ejects the media using f_media_eject_cdrom(),
-# below. Return status should be ignored.
+# Shuts down the CDROM device. Return status should be ignored.
#
f_media_shutdown_cdrom()
{
+ local funcname=f_media_shutdown_cdrom
local dev="$1" err
[ "$CDROM_MOUNTED" ] || return $FAILURE
@@ -177,15 +173,15 @@ f_media_shutdown_cdrom()
return $SUCCESS
fi
- if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ if ! f_eval_catch -dk err $funcname umount \
+ 'umount -f "%s"' "$MOUNTPOINT"
+ then
err="${err#umount: }"; err="${err#*: }"
f_show_msg "$msg_could_not_unmount_the_cdrom_dvd" \
"$MOUNTPOINT" "$err"
else
CDROM_MOUNTED=
fi
-
- f_media_eject_cdrom "$dev"
}
# f_media_eject_cdrom $device
@@ -194,11 +190,20 @@ f_media_shutdown_cdrom()
#
f_media_eject_cdrom()
{
- local dev="$1" devname err
- device_$dev get name devname || return $SUCCESS
- case "$devname" in /dev/iso9660/*) return $SUCCESS; esac
+ local funcname=f_media_eject_cdrom
+ local dev="$1" name devname err
+
+ f_struct "$dev" || return $SUCCESS
+ $dev get name name || return $SUCCESS
+ $dev get devname devname || return $SUCCESS
+
+ # Don't eject labels
+ case "$name" in */*) return $SUCCESS; esac
+
f_dprintf "Ejecting CDROM/DVD at %s" "$devname"
- if ! err=$( cdcontrol -f "$devname" eject 2>&1 ); then
+ if ! f_eval_catch -dk err $funcname cdcontrol \
+ 'cdcontrol -f "%s" eject' "$devname"
+ then
f_dprintf "Could not eject the CDROM/DVD from %s: %s" \
"$devname" "${err#cdcontrol: }"
fi
diff --git a/usr.sbin/bsdconfig/share/media/common.subr b/usr.sbin/bsdconfig/share/media/common.subr
index 01d50a19e7568..7a6ddaa9388f5 100644
--- a/usr.sbin/bsdconfig/share/media/common.subr
+++ b/usr.sbin/bsdconfig/share/media/common.subr
@@ -61,7 +61,7 @@ f_media_open()
{ # Verify and initialize device media if-defined
f_struct device_media &&
f_media_verify &&
- f_device_init media
+ f_device_init device_media
} || return $FAILURE
}
@@ -74,7 +74,7 @@ f_media_close()
{
f_dprintf "f_media_close: Shutting down media device"
f_struct device_media &&
- f_device_shutdown media
+ f_device_shutdown device_media
f_struct_free device_media
}
@@ -99,6 +99,7 @@ f_media_verify()
#
f_media_generic_get()
{
+ local funcname=f_media_generic_get
local base="$1" file="$2" probe_type="$3"
local fname=f_media_generic_get
@@ -117,13 +118,10 @@ f_media_generic_get()
f_dprintf "%s: file exists path=[%s]" $fname "$path"
if [ "$probe_type" = "$PROBE_SIZE" ]; then
local size
- if ! size=$( stat -f %z "$path" 2>&1 ); then
- f_dprintf "stat: %s" "$size"
- echo "-1"
- else
- f_isinteger "$size" || size=-1
- echo $size
- fi
+ f_eval_catch -dk size $funcname stat \
+ 'stat -f %%z "%s"' "$path" || size=-1
+ f_isinteger "$size" || size=-1
+ echo $size
fi
[ "$probe_type" ] && return $SUCCESS
cat "$path"
@@ -136,13 +134,10 @@ f_media_generic_get()
f_dprintf "%s: file exists path=[%s]" $fname "$path"
if [ "$probe_type" = "$PROBE_SIZE" ]; then
local size
- if ! size=$( stat -f %z "$path" 2>&1 ); then
- f_dprintf "stat: %s" "$size"
- echo "-1"
- else
- f_isinteger "$size" || size=-1
- echo $size
- fi
+ f_eval_catch -dk size $funcname stat \
+ 'stat -f %%z "%s"' "$path" || size=-1
+ f_isinteger "$size" || size=-1
+ echo $size
fi
[ "$probe_type" ] && return $SUCCESS
elif [ "$probe_type" ]; then
diff --git a/usr.sbin/bsdconfig/share/media/directory.subr b/usr.sbin/bsdconfig/share/media/directory.subr
index 3f462938af554..004cb74bb07ef 100644
--- a/usr.sbin/bsdconfig/share/media/directory.subr
+++ b/usr.sbin/bsdconfig/share/media/directory.subr
@@ -90,7 +90,7 @@ f_media_init_directory()
{
local dev="$1" path
- device_$dev get private path || return $FAILURE
+ $dev get private path || return $FAILURE
f_dprintf "Init routine called for Directory device. path=[%s]" \
"$path"
@@ -125,11 +125,13 @@ f_media_init_directory()
f_media_get_directory()
{
local dev="$1" file="$2" probe_type="$3" path
+ local name
+ $dev get name name
f_dprintf "f_media_get_directory: dev=[%s] file=[%s] probe_type=%s" \
- "$dev" "$file" "$probe_type"
+ "$name" "$file" "$probe_type"
- device_$dev get private path
+ $dev get private path
f_media_generic_get "$path" "$file" "$probe_type"
}
diff --git a/usr.sbin/bsdconfig/share/media/dos.subr b/usr.sbin/bsdconfig/share/media/dos.subr
index be4cfc7d9a602..df91aebcd8149 100644
--- a/usr.sbin/bsdconfig/share/media/dos.subr
+++ b/usr.sbin/bsdconfig/share/media/dos.subr
@@ -56,31 +56,25 @@ f_media_set_dos()
local devs ndevs
f_device_find "" $DEVICE_TYPE_DOS devs
- ndevs=$( set -- $devs; echo $# )
+ f_count ndevs $devs
if [ ${ndevs:=0} -eq 0 ]; then
f_show_msg "$msg_no_dos_primary_partitions_found"
return $FAILURE
- elif [ $ndevs -gt 1 ]; then
+ elif [ $ndevs -eq 1 ]; then
+ f_struct_copy $devs device_media
+ else
+ local dev
local title="$msg_choose_a_dos_partition"
local prompt="$msg_please_select_dos_partition"
- local hline=""
+ local hline=
- local dev retval
dev=$( f_device_menu \
"$title" "$prompt" "$hline" $DEVICE_TYPE_DOS \
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
- retval=$?
- [ "$dev" ] || return $FAILURE
-
- f_device_find "$dev" $DEVICE_TYPE_DOS devs
- [ "$devs" ] || return $FAILURE
- dev="${devs%%[$IFS]*}"
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) ||
+ return $FAILURE
- f_struct_copy device_$dev device_media
- [ $retval -eq $SUCCESS ] || return $FAILURE
- else
- f_struct_copy device_$devs device_media
+ f_struct_copy "$dev" device_media
fi
f_struct device_media || return $FAILURE
@@ -93,9 +87,10 @@ f_media_set_dos()
#
f_media_init_dos()
{
+ local funcname=f_media_init_dos
local dev="$1" devname err
- device_$dev get devname devname || return $FAILURE
+ $dev get devname devname || return $FAILURE
f_dprintf "Init routine called for DOS device. devname=[%s]" \
"$devname"
@@ -104,14 +99,13 @@ f_media_init_dos()
return $SUCCESS
fi
- if [ ! -e "$MOUNTPOINT" ] &&
- ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
- then
- f_dialog_msgbox "$err"
- return $FAILURE
+ if [ ! -e "$MOUNTPOINT" ]; then
+ f_eval_catch $funcname mkdir 'mkdir -p "%s"' "$MOUNTPOINT" ||
+ return $FAILURE
fi
- if ! err=$( mount_msdosfs "$devname" "$MOUNTPOINT" 2>&1 )
+ if ! f_eval_catch -dk err $funcname mount_msdosfs \
+ 'mount_msdosfs "%s" "%s"' "$devname" "$MOUNTPOINT"
then
err="${err#mount_msdosfs: }"; err="${err#$devname: }"
f_show_msg "$msg_error_mounting_device" \
@@ -132,9 +126,11 @@ f_media_init_dos()
f_media_get_dos()
{
local dev="$1" file="$2" probe_type="$3"
+ local name
+ $dev get name name
f_dprintf "f_media_get_dos: dev=[%s] file=[%s] probe_type=%s" \
- "$dev" "$file" "$probe_type"
+ "$name" "$file" "$probe_type"
f_media_generic_get "$MOUNTPOINT" "$file" "$probe_type"
}
@@ -146,11 +142,14 @@ f_media_get_dos()
#
f_media_shutdown_dos()
{
+ local funcname=f_media_shutdown_dos
local dev="$1" err
[ "$DOS_MOUNTED" ] || return $FAILURE
- if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ if ! f_eval_catch -dk err $funcname umount \
+ 'umount -f "%s"' "$MOUNTPOINT"
+ then
err="${err#umount: }"; err="${err#*: }"
f_show_msg "$msg_could_not_unmount_the_dos_partition" \
"$MOUNTPOINT" "$err"
diff --git a/usr.sbin/bsdconfig/share/media/floppy.subr b/usr.sbin/bsdconfig/share/media/floppy.subr
index 62fe64b68d35c..bf402e533d33a 100644
--- a/usr.sbin/bsdconfig/share/media/floppy.subr
+++ b/usr.sbin/bsdconfig/share/media/floppy.subr
@@ -57,31 +57,25 @@ f_media_set_floppy()
local devs ndevs
f_device_find "" $DEVICE_TYPE_FLOPPY devs
- ndevs=$( set -- $devs; echo $# )
+ f_count ndevs $devs
if [ ${ndevs:=0} -eq 0 ]; then
f_interactive && f_show_msg "$msg_no_floppy_devices_found"
return $FAILURE
- elif [ $ndevs -gt 1 ]; then
+ elif [ $ndevs -eq 1 ]; then
+ f_struct_copy $devs device_media
+ else
+ local dev
local title="$msg_choose_a_floppy_drive"
local prompt="$msg_please_select_a_floppy_drive"
- local hline=""
+ local hline=
- local dev retval
dev=$( f_device_menu \
"$title" "$prompt" "$hline" $DEVICE_TYPE_FLOPPY \
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
- retval=$?
- [ "$dev" ] || return $FAILURE
-
- f_device_find "$dev" $DEVICE_TYPE_FLOPPY devs
- [ "$devs" ] || return $FAILURE
- dev="${devs%%[$IFS]*}"
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) ||
+ return $FAILURE
- f_struct_copy device_$dev device_media
- [ $retval -eq $SUCCESS ] || return $FAILURE
- else
- f_struct_copy device_$devs device_media
+ f_struct_copy "$dev" device_media
fi
f_struct device_media &&
@@ -98,9 +92,10 @@ f_media_set_floppy()
#
f_media_init_floppy()
{
+ local funcname=f_media_init_floppy
local dev="$1" devname err
- device_$dev get devname devname || return $FAILURE
+ $dev get devname devname || return $FAILURE
f_dprintf "Init floppy called for %s distribution. devname=[%s]" \
"${FLOPPY_DISTWANTED:-some}" "$devname"
@@ -110,7 +105,7 @@ f_media_init_floppy()
fi
local mp
- device_$dev get private mp
+ $dev get private mp
if [ ! -e "${mp:=$MOUNTPOINT}" ] && ! f_quietly mkdir -p "$mp"; then
f_show_msg "$msg_unable_to_make_directory_mountpoint" \
"$mp" "$devname"
@@ -119,7 +114,7 @@ f_media_init_floppy()
if f_interactive; then
local desc
- device_$dev get desc desc
+ $dev get desc desc
if [ "$FLOPPY_DISTWANTED" ]; then
f_show_msg "$msg_please_insert_floppy_in_drive" "$desc"
else
@@ -129,12 +124,15 @@ f_media_init_floppy()
fi
if ! {
- f_quietly mount_msdosfs -o ro -m 0777 -u 0 -g 0 "$devname" "$mp" ||
- err=$( mount -o ro "$devname" "$mp" 2>&1 )
+ f_eval_catch -dk err $funcname mount_msdosfs \
+ 'mount_msdosfs -o ro -m 0777 -u 0 -g 0 "%s" "%s"' \
+ "$devname" "$mp" ||
+ f_eval_catch -dk err $funcname mount \
+ 'mount -o ro "%s" "%s"' "$devname" "$mp"
}; then
err="${err#mount: }"; err="${err#*: }"
local name
- device_$dev get name name
+ $dev get name name
f_show_msg "$msg_error_mounting_floppy_device" \
"$name" "$devname" "$mp" "$err"
return $FAILURE
@@ -153,10 +151,13 @@ f_media_init_floppy()
#
f_media_get_floppy()
{
+ local funcname=f_media_get_floppy
local dev="$1" file="$2" probe_type="$3"
+ local name
+ $dev get name name
f_dprintf "f_media_get_floppy: dev=[%s] file=[%s] probe_type=%s" \
- "$dev" "$file" "$probe_type"
+ "$name" "$file" "$probe_type"
#
# floppies don't use f_media_generic_get() because it's too expensive
@@ -164,7 +165,7 @@ f_media_get_floppy()
# right or give up with floppies.
#
local mp
- device_$dev get private mp
+ $dev get private mp
local fp="${mp:=$MOUNTPOINT}/$file"
if ! [ -f "$fp" -a -r "$fp" ]; then
local nretries=4
@@ -188,7 +189,7 @@ f_media_get_floppy()
#
if [ "$probe_type" = "$PROBE_SIZE" ]; then
local size
- size=$( stat -f %z "$fp" 2>&1 ) || f_dprintf "stat: %s" "$size"
+ f_eval_catch -dk size $funcname stat 'stat -f %%z "%s"' "$fp"
f_isinteger "$size" || size=-1
echo "$size"
fi
@@ -203,19 +204,19 @@ f_media_get_floppy()
#
f_media_shutdown_floppy()
{
+ local funcname=f_media_shutdown_floppy
local dev="$1" err mp
[ "$FLOPPY_MOUNTED" ] || return $FAILURE
- device_$dev get private mp
- if ! err=$( umount -f "${mp:=$MOUNTPOINT}" 2>&1 ); then
- err="${err#umount: }"; err="${err#*:}"
- f_dprintf "Umount of floppy on %s failed: %s" "$mp" "$err"
- else
+ $dev get private mp
+ if f_eval_catch -d $funcname umount \
+ 'umount -f "%s"' "${mp:=$MOUNTPOINT}"
+ then
FLOPPY_MOUNTED=
if f_interactive && [ "$_systemState" != "fixit" ]; then
local desc
- device_$dev get desc desc
+ $dev get desc desc
f_show_msg "$msg_you_may_remove_the_floppy" "$desc"
fi
fi
diff --git a/usr.sbin/bsdconfig/share/media/ftp.subr b/usr.sbin/bsdconfig/share/media/ftp.subr
index d7f33bbb1c295..a249a01382bd2 100644
--- a/usr.sbin/bsdconfig/share/media/ftp.subr
+++ b/usr.sbin/bsdconfig/share/media/ftp.subr
@@ -328,16 +328,17 @@ f_media_set_ftp()
! f_dialog_yesno "$msg_youve_already_done_the_network_configuration"
then
f_struct device_network &&
- f_device_shutdown network
+ f_device_shutdown device_network
if ! f_device_select_tcp; then
unset $VAR_FTP_PATH
return $FAILURE
fi
- local dev
- f_getvar $VAR_NETWORK_DEVICE dev
- f_struct_copy "device_$dev" device_network
+ local dev if
+ f_getvar $VAR_NETWORK_DEVICE if
+ f_device_find -1 "$if" $DEVICE_TYPE_NETWORK dev
+ f_struct_copy "$dev" device_network
fi
- if ! f_device_init network; then
+ if ! f_device_init device_network; then
f_dprintf "f_media_set_ftp: %s" "$msg_net_device_init_failed"
unset $VAR_FTP_PATH
return $FAILURE
@@ -420,7 +421,7 @@ f_media_set_ftp()
if ! f_quietly f_host_lookup "$hostname"; then
f_show_msg "$msg_cannot_resolve_hostname" "$hostname"
f_struct device_network &&
- f_device_shutdown network
+ f_device_shutdown device_network
f_struct_free device_network
unset $VAR_FTP_PATH
return $FAILURE
@@ -436,7 +437,7 @@ f_media_set_ftp()
device_ftp set init f_media_init_ftp
device_ftp set get f_media_get_ftp
device_ftp set shutdown f_media_shutdown_ftp
- device_ftp set private network
+ device_ftp set private device_network
f_struct_copy device_ftp device_media
f_struct_free device_ftp
@@ -503,8 +504,9 @@ f_media_set_ftp_userpass()
f_device_network_up()
{
local dev="$1" netDev
- f_struct device_$dev || return $FAILURE
- device_$dev get private netDev || return $SUCCESS # No net == happy net
+ f_struct "$dev" || return $FAILURE
+ $dev get private netDev || return $SUCCESS # No net == happy net
+debug=1 f_dprintf "netDev=[$netDev]"
f_device_init $netDev
}
@@ -515,8 +517,8 @@ f_device_network_up()
f_device_network_down()
{
local dev="$1" netDev
- f_struct device_$dev || return $FAILURE
- device_$dev get private netDev || return $SUCCESS
+ f_struct "$dev" || return $FAILURE
+ $dev get private netDev || return $SUCCESS
f_device_shutdown $netDev
}
@@ -576,9 +578,9 @@ f_device_network_down()
f_media_init_ftp()
{
local dev="$1"
-
local url
- device_$dev get name url
+
+ $dev get name url
f_dprintf "Init routine called for FTP device. url=[%s]" "$url"
if [ "$FTP_INITIALIZED" ]; then
@@ -724,7 +726,6 @@ f_media_init_ftp()
local fdir
if fdir=$( echo "$rx" | awk '
- BEGIN { found = 0 }
/^Remote directory: / {
sub(/^[^:]*:[[:space:]]*/, "")
if ($0 == "/") next
@@ -794,6 +795,7 @@ f_media_init_ftp()
#
f_media_get_ftp()
{
+ local funcname=f_media_get_ftp
local dev="$1" file="$2" probe_type="$3" hosts=
f_dprintf "f_media_get_ftp: dev=[%s] file=[%s] probe_type=%s" \
@@ -870,9 +872,10 @@ f_media_get_ftp()
if [ "$probe_type" ]; then
local url="ftp://$userpass$host$port/$dir/$file" size
[ "$use_anon" ] && url="ftp://$host$port/$dir/$file"
- if ! size=$( fetch -s "$url" 2>&1 ) || ! f_isinteger "$size"
+ if ! f_eval_catch -dk size $funcname fetch \
+ 'fetch -s "%s"' "$url" || ! f_isinteger "$size"
then
- f_dprintf "request failed! size response=[%s]" "$size"
+ f_dprintf "size request failed!"
[ "$probe_type" = "$PROBE_SIZE" ] && echo "-1"
return $FAILURE
fi
diff --git a/usr.sbin/bsdconfig/share/media/http.subr b/usr.sbin/bsdconfig/share/media/http.subr
index 97c4ed02f2d20..6d6aa10433b40 100644
--- a/usr.sbin/bsdconfig/share/media/http.subr
+++ b/usr.sbin/bsdconfig/share/media/http.subr
@@ -77,7 +77,8 @@ f_dialog_menu_media_http()
f_dialog_title_restore
local prompt="$msg_please_select_the_site_closest_to_you_or_other"
local menu_list="
- '$msg_main_site' 'ftp.freebsd.org'
+ 'dist $msg_main_site' 'ftp.freebsd.org'
+ 'pkg $msg_main_site' 'pkg.freebsd.org'
'URL' '$msg_specify_some_other_http_site'
" # END-QUOTE
local hline="$msg_select_a_site_thats_close"
@@ -214,16 +215,17 @@ f_media_set_http()
! f_dialog_yesno "$msg_youve_already_done_the_network_configuration"
then
f_struct device_network &&
- f_device_shutdown network
+ f_device_shutdown device_network
if ! f_device_select_tcp; then
unset $VAR_HTTP_PATH
return $FAILURE
fi
- local dev
- f_getvar $VAR_NETWORK_DEVICE dev
- f_struct_copy "device_$dev" device_network
+ local dev if
+ f_getvar $VAR_NETWORK_DEVICE if
+ f_device_find -1 "$if" $DEVICE_TYPE_NETWORK dev
+ f_struct_copy "$dev" device_network
fi
- if ! f_device_init network; then
+ if ! f_device_init device_network; then
f_dprintf "f_media_set_http: %s" "$msg_net_device_init_failed"
unset $VAR_HTTP_PATH
return $FAILURE
@@ -306,7 +308,7 @@ f_media_set_http()
if ! f_quietly f_host_lookup "$hostname"; then
f_show_msg "$msg_cannot_resolve_hostname" "$hostname"
f_struct device_network &&
- f_device_shutdown network
+ f_device_shutdown device_network
f_struct_free device_network
unset $VAR_HTTP_PATH
return $FAILURE
@@ -322,7 +324,7 @@ f_media_set_http()
device_http set init f_media_init_http
device_http set get f_media_get_http
device_http set shutdown f_media_shutdown_http
- device_http set private network
+ device_http set private device_network
f_struct_copy device_http device_media
f_struct_free device_http
@@ -452,6 +454,11 @@ f_media_init_http()
local dev="$1"
f_dprintf "Init routine called for HTTP device. dev=[%s]" "$dev"
+ if [ "$HTTP_INITIALIZED" ]; then
+ f_dprintf "HTTP device already initialized."
+ return $SUCCESS
+ fi
+
#
# First verify access
#
@@ -481,7 +488,7 @@ f_media_init_http()
case "$rel" in
__RELEASE|any)
- setvar $VAR_HTTP_PATH "$VAR_HTTP_DIR"
+ f_getvar $VAR_HTTP_DIR $VAR_HTTP_PATH
f_http_check_access
http_found=$?
;;
@@ -493,22 +500,31 @@ f_media_init_http()
#
local fdir hp
f_getvar $VAR_HTTP_PATH%/ hp
- for fdir in $HTTP_DIRS; do
- setvar $VAR_HTTP_PATH "$hp/$fdir/$rel"
- if f_http_check_access; then
- http_found=$SUCCESS
- break
- fi
- done
+ setvar $VAR_HTTP_PATH "$hp/$PKG_ABI/latest"
+ if [ "$PKG_ABI" ] && f_http_check_access; then
+ http_found=$SUCCESS
+ setvar $VAR_HTTP_PATH "$hp"
+ else
+ for fdir in $HTTP_DIRS; do
+ setvar $VAR_HTTP_PATH "$hp/$fdir/$rel"
+ if f_http_check_access; then
+ http_found=$SUCCESS
+ break
+ fi
+ done
+ fi
esac
- [ $http_found -eq $SUCCESS ] && break
+ if [ $http_found -eq $SUCCESS ]; then
+ HTTP_INITIALIZED=YES
+ break
+ fi
f_getvar $VAR_HTTP_PATH http_path
f_show_msg "$msg_please_check_the_url_and_try_again" \
"$http_path"
- unset $VAR_HTTP_PATH
+ unset HTTP_INITIALIZED $VAR_HTTP_PATH
f_media_set_http || break
done
@@ -550,14 +566,21 @@ f_media_init_http()
f_media_get_http()
{
local dev="$1" file="$2" probe_type="$3" hosts=
+ local name
+ $dev get name name
f_dprintf "f_media_get_http: dev=[%s] file=[%s] probe_type=%s" \
- "$dev" "$file" "$probe_type"
+ "$name" "$file" "$probe_type"
local http_host http_port
f_getvar $VAR_HTTP_HOST http_host
f_getvar $VAR_HTTP_PORT http_port
+ if [ ! "$HTTP_INITIALIZED" ]; then
+ f_dprintf "No HTTP connection open, can't get file %s" "$file"
+ return $FAILURE
+ fi
+
if ! {
f_validate_ipaddr "$http_host" ||
f_validate_ipaddr6 "$http_host" ||
@@ -595,6 +618,7 @@ f_media_get_http()
local url="$http_path/$file" rx
f_dprintf "sending http request for: %s" "$url"
+ f_dprintf "using nc to connect to: %s:%s" "$host" "$http_port"
printf "GET %s HTTP/1.0\r\n\r\n" "$url" | nc -n "$host" "$http_port" |
(
#
@@ -648,6 +672,18 @@ f_media_get_http()
return $FAILURE
}
+# f_media_shutdown_http $device
+#
+# Shuts down the HTTP device. Return status should be ignored. Note that since
+# we don't maintain an open connection to the HTTP server, nothing to do.
+#
+f_media_shutdown_http()
+{
+ [ "$HTTP_INITIALIZED" ] || return $SUCCESS
+
+ unset HTTP_INITIALIZED
+}
+
############################################################ MAIN
f_dprintf "%s: Successfully loaded." media/http.subr
diff --git a/usr.sbin/bsdconfig/share/media/nfs.subr b/usr.sbin/bsdconfig/share/media/nfs.subr
index 8db5a069aa342..d83661f46b696 100644
--- a/usr.sbin/bsdconfig/share/media/nfs.subr
+++ b/usr.sbin/bsdconfig/share/media/nfs.subr
@@ -93,13 +93,14 @@ f_media_set_nfs()
! f_dialog_yesno "$msg_youve_already_done_the_network_configuration"
then
f_struct device_network &&
- f_device_shutdown network
+ f_device_shutdown device_network
f_device_select_tcp || return $FAILURE
- local dev
- f_getvar $VAR_NETWORK_DEVICE dev
- f_struct_copy "device_$dev" device_network
+ local dev if
+ f_getvar $VAR_NETWORK_DEVICE if
+ f_device_find -1 "$if" $DEVICE_TYPE_NETWORK dev
+ f_struct_copy "$dev" device_network
fi
- f_device_init network ||
+ f_device_init device_network ||
f_dprintf "%s: $msg_net_device_init_failed\n" f_media_set_nfs
local hostname="${nfs%%:*}"
@@ -112,7 +113,7 @@ f_media_set_nfs()
if ! f_quietly f_host_lookup "$hostname"; then
f_show_msg "$msg_cannot_resolve_hostname" "$hostname"
f_struct device_network &&
- f_device_shutdown network
+ f_device_shutdown device_network
f_struct_free device_network
unset $VAR_NFS_PATH
return $FAILURE
@@ -154,9 +155,10 @@ f_media_set_nfs()
#
f_media_init_nfs()
{
+ local funcname=f_media_init_nfs
local dev="$1" name err
- device_$dev get name name || return $FAILURE
+ $dev get name name || return $FAILURE
f_dprintf "Init routine called for NFS device. name=[%s]" \
"$name"
@@ -165,16 +167,14 @@ f_media_init_nfs()
return $SUCCESS
fi
- if ! f_device_init network; then
+ if ! f_device_init device_network; then
f_dprintf "f_media_init_nfs: %s" "$msg_net_device_init_failed"
return $FAILURE
fi
- if [ ! -e "$MOUNTPOINT" ] &&
- ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
- then
- f_dialog_msgbox "$err"
- return $FAILURE
+ if [ ! -e "$MOUNTPOINT" ]; then
+ f_eval_catch $funcname mkdir 'mkdir -p "%s"' "$MOUNTPOINT" ||
+ return $FAILURE
fi
local cp tcp="" use3="" secure="" readsize=4096 writesize=4096
@@ -191,14 +191,15 @@ f_media_init_nfs()
[ "$use3" ] && options="$options,nfsv3"
[ "$tcp" ] && options="$options,tcp"
- if ! err=$( mount_nfs \
- ${secure:+-P} -o "$options" "$name" "$MOUNTPOINT" 2>&1 )
+ if ! f_eval_catch -dk err $funcname mount_nfs \
+ 'mount_nfs %s -o "%s" "%s" "%s"' \
+ "${secure:+-P}" "$options" "$name" "$MOUNTPOINT"
then
err="${err#mount_nfs: }"
f_show_msg "$msg_error_mounting_device" \
"$name" "$MOUNTPOINT" "$err"
f_struct device_network &&
- f_device_shutdown network
+ f_device_shutdown device_network
return $FAILURE
fi
NFS_MOUNTED=1
@@ -218,9 +219,11 @@ f_media_init_nfs()
f_media_get_nfs()
{
local dev="$1" file="$2" probe_type="$3"
+ local name
+ $dev get name name
f_dprintf "f_media_get_nfs: dev=[%s] file=[%s] probe_type=%s" \
- "$dev" "$file" "$probe_type"
+ "$name" "$file" "$probe_type"
f_media_generic_get "$MOUNTPOINT" "$file" "$probe_type"
}
@@ -231,12 +234,15 @@ f_media_get_nfs()
#
f_media_shutdown_nfs()
{
+ local funcname=f_media_shutdown_nfs
local dev="$1" err
[ "$NFS_MOUNTED" ] || return $FAILURE
f_dprintf "Unmounting NFS partition on %s" "$MOUNTPOINT"
- if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ if ! f_eval_catch -dk err $funcname umount \
+ 'umount -f "%s"' "$MOUNTPOINT"
+ then
err="${err#umount: }"; err="${err#*: }"
f_show_msg "$msg_could_not_unmount_the_nfs_partition" \
"$MOUNTPOINT" "$err"
diff --git a/usr.sbin/bsdconfig/share/media/tcpip.subr b/usr.sbin/bsdconfig/share/media/tcpip.subr
index 5957b90728bb0..42c6e205da302 100644
--- a/usr.sbin/bsdconfig/share/media/tcpip.subr
+++ b/usr.sbin/bsdconfig/share/media/tcpip.subr
@@ -33,6 +33,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
f_dprintf "%s: loading includes..." media/tcpip.subr
f_include $BSDCFG_SHARE/device.subr
f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/strings.subr
f_include $BSDCFG_SHARE/struct.subr
f_include $BSDCFG_SHARE/variable.subr
@@ -110,10 +111,11 @@ f_struct_define DHCP_LEASE \
# begin or end with a hyphen).
# 3 One or more individual labels within the hostname are null.
#
-# f_dialog_validate_hostname $hostname
+# To call this function and display an appropriate error message to the user
+# based on the above error codes, use the following function defined in
+# dialog.subr:
#
-# If the hostname is determined to be invalid, the appropriate error will be
-# displayed using the f_show_msg function.
+# f_dialog_validate_hostname $hostname
#
f_validate_hostname()
{
@@ -167,8 +169,9 @@ f_inet_atoi()
{
local __addr="$1" __var_to_set="$2" __num=0
if f_validate_ipaddr "$__addr"; then
- __num=$( IFS=.; set -- $__addr; \
- echo $(( ($1 << 24) + ($2 << 16) + ($3 << 8) + $4 )) )
+ local IFS=.
+ set -- $__addr
+ __num=$(( ($1 << 24) + ($2 << 16) + ($3 << 8) + $4 ))
fi
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" $__num
@@ -201,8 +204,7 @@ f_validate_ipaddr()
# Track number of octets for error checking
local noctets=0
- local oldIFS="$IFS"
- local IFS="." # Split on `dot'
+ local oldIFS="$IFS" IFS="." # Split on `dot'
for octet in $ip; do
# Return error if the octet is null
[ "$octet" ] || return 2
@@ -573,7 +575,7 @@ f_ifconfig_netmask()
local __octet __netmask=
for __octet in $__octets; do
- __netmask="$__netmask.$( printf "%u" "0x$__octet" )"
+ f_sprintf __netmask "%s.%u" "$__netmask" "0x$__octet"
done
__netmask="${__netmask#.}"
if [ "$__var_to_set" ]; then
@@ -1020,10 +1022,42 @@ f_host_lookup()
# Fall back to host(1) -- which is further governed by nsswitch.conf(5)
#
- local __output __ip6 __addrs="" __wait=""
- f_getvar $VAR_MEDIA_TIMEOUT __wait
- [ "$__wait" ] && __wait="-W $(( $__wait / 2 ))"
+ local __output __ip6 __addrs=
f_getvar $VAR_IPV6_ENABLE __ip6
+
+ # If we have a TCP media type configured, check for an SRV record
+ local __srvtypes=
+ { f_quietly f_getvar $VAR_HTTP_PATH ||
+ f_quietly f_getvar $VAR_HTTP_PROXY_PATH
+ } && __srvtypes="$__srvtypes _http._tcp"
+ f_quietly f_getvar $VAR_FTP_PATH && __srvtypes="$__srvtypes _ftp._tcp"
+ f_quietly f_getvar $VAR_NFS_PATH &&
+ __srvtypes="$__srvtypes _nfs._tcp _nfs._udp"
+
+ # Calculate wait time as dividend of total time and host(1) invocations
+ local __host_runs __wait
+ f_count __host_runs $__srvtypes
+ if [ "$__ip6" = "YES" ]; then
+ __host_runs=$(( $__host_runs + 2 ))
+ else
+ __host_runs=$(( $__host_runs + 1 ))
+ fi
+ f_getvar $VAR_MEDIA_TIMEOUT __wait
+ [ "$__wait" ] && __wait="-W $(( $__wait / $__host_runs ))"
+
+ # Query SRV types first (1st host response taken as new host to query)
+ for __type in $__srvtypes; do
+ if __output=$(
+ host -t SRV $__wait -- "$__type.$__host" \
+ 2> /dev/null
+ ); then
+ __host=$( echo "$__output" |
+ awk '/ SRV /{print $NF;exit}' )
+ break
+ fi
+ done
+
+ # Try IPv6 first (if enabled)
if [ "$__ip6" = "YES" ]; then
if ! __output=$( host -t AAAA $__wait -- "$__host" 2>&1 ); then
# An error occurred, display in-full and return error
@@ -1031,13 +1065,17 @@ f_host_lookup()
setvar "$__var_to_set" "$__output"
return $FAILURE
fi
+ # Add the IPv6 addresses and fall-through to collect IPv4 too
__addrs=$( echo "$__output" | awk '/ address /{print $NF}' )
fi
+
+ # Good ol' IPv4
if ! __output=$( host -t A $__wait -- "$__host" 2>&1 ); then
# An error occurred, display it in-full and return error
[ "$__var_to_set" ] && setvar "$__var_to_set" "$__output"
return $FAILURE
fi
+
__addrs="$__addrs${__addrs:+ }$(
echo "$__output" | awk '/ address /{print $NF}' )"
if [ "$__var_to_set" ]; then
@@ -1098,15 +1136,16 @@ f_host_lookup()
#
f_device_dialog_tcp()
{
- local dev="$1" cp n
+ local dev="$1" devname cp n
local use_dhcp="" use_rtsol=""
local _ipaddr _netmask _extras
[ "$dev" ] || return $DIALOG_CANCEL
+ f_struct "$dev" get name devname || return $DIALOG_CANCEL
# Initialize vars from previous device values
local private
- device_$dev get private private
+ $dev get private private
if [ "$private" ] && f_struct "$private"; then
$private get ipaddr _ipaddr
$private get netmask _netmask
@@ -1144,17 +1183,17 @@ f_device_dialog_tcp()
f_quietly sysctl net.inet6.ip6.forwarding=0
f_quietly sysctl net.inet6.ip6.accept_rtadv=1
- f_quietly ifconfig $dev up
+ f_quietly ifconfig $devname up
i=$( sysctl -n net.inet6.ip6.dad_count )
sleep $(( $i + 1 ))
f_quietly mkdir -p /var/run
f_dialog_info "$msg_scanning_for_ra_servers"
- if f_quietly rtsol $dev; then
+ if f_quietly rtsol $devname; then
i=$( sysctl -n net.inet6.ip6.dad_count )
sleep $(( $i + 1 ))
- f_rtsol_get_info $dev
+ f_rtsol_get_info $devname
use_rtsol=1
else
use_rtsol=
@@ -1173,7 +1212,7 @@ f_device_dialog_tcp()
! f_isset $VAR_TRY_DHCP &&
f_dialog_noyes "$msg_try_dhcp_configuration"
}; then
- f_quietly ifconfig $dev delete
+ f_quietly ifconfig $devname delete
f_quietly mkdir -p /var/db
f_quietly mkdir -p /var/run
f_quietly mkdir -p /tmp
@@ -1183,17 +1222,17 @@ f_device_dialog_tcp()
( # Execute in sub-shell to allow/catch Ctrl-C
trap 'exit $FAILURE' SIGINT
if [ "$USE_XDIALOG" ]; then
- f_quietly dhclient $dev |
+ f_quietly dhclient $devname |
f_xdialog_info "$msg"
else
f_dialog_info "$msg"
- f_quietly dhclient $dev
+ f_quietly dhclient $devname
fi
)
local retval=$?
trap 'f_interrupt' SIGINT
if [ $retval -eq $SUCCESS ]; then
- f_dhcp_get_info $dev
+ f_dhcp_get_info $devname
use_dhcp=1
else
use_dhcp=
@@ -1214,7 +1253,7 @@ f_device_dialog_tcp()
if [ ! "$_ipaddr" ]; then
if f_getvar $VAR_IPADDR cp; then
_ipaddr="$cp"
- elif f_getvar ${dev}_$VAR_IPADDR cp; then
+ elif f_getvar ${devname}_$VAR_IPADDR cp; then
_ipaddr="$cp"
fi
fi
@@ -1223,7 +1262,7 @@ f_device_dialog_tcp()
if [ ! "$_netmask" ]; then
if f_getvar $VAR_NETMASK cp; then
_netmask="$cp"
- elif f_getvar ${dev}_$VAR_NETMASK cp; then
+ elif f_getvar ${devname}_$VAR_NETMASK cp; then
_netmask="$cp"
fi
fi
@@ -1232,7 +1271,7 @@ f_device_dialog_tcp()
if [ ! "$_extras" ]; then
if f_getvar $VAR_EXTRAS cp; then
_extras="$cp"
- elif f_getvar ${dev}_$VAR_EXTRAS cp; then
+ elif f_getvar ${devname}_$VAR_EXTRAS cp; then
_extras="$cp"
fi
fi
@@ -1256,8 +1295,8 @@ f_device_dialog_tcp()
[ "$_gateway" ] || f_route_get_default _gateway
[ ! "$_nameserver" ] &&
f_resolv_conf_nameservers cp && _nameserver=${cp%%[$IFS]*}
- [ "$_ipaddr" ] || f_ifconfig_inet $dev _ipaddr
- [ "$_netmask" ] || f_ifconfig_netmask $dev _netmask
+ [ "$_ipaddr" ] || f_ifconfig_inet $devname _ipaddr
+ [ "$_netmask" ] || f_ifconfig_netmask $devname _netmask
# If non-interactive, jump over dialog section and into config section
if f_netinteractive || f_interactive || [ ! "$_hostname" ]
@@ -1270,7 +1309,7 @@ f_device_dialog_tcp()
local extras_help="$tcplayout_extras_help"
# Modify the help line for PLIP config
- [ "${dev#plip}" != "$dev" ] &&
+ [ "${devname#plip}" != "$devname" ] &&
extras_help="$tcplayout_extras_help_for_plip"
f_getvar $VAR_IPV6ADDR cp && [ "$cp" ] &&
@@ -1279,7 +1318,8 @@ f_device_dialog_tcp()
if [ ! "$USE_XDIALOG" ]; then
local prompt="$msg_dialog_mixedform_navigation_help"
# Calculate center position for displaying device label
- local devlabel="$msg_configuration_for_interface $dev"
+ local devlabel="$msg_configuration_for_interface"
+ devlabel="$devlabel $devname"
local width=54
local n=$(( $width/2 - (${#devlabel} + 4)/2 - 2 ))
@@ -1465,7 +1505,7 @@ f_device_dialog_tcp()
f_dprintf "Creating struct DEVICE_INFO devinfo_%s" "$dev"
f_struct_new DEVICE_INFO devinfo_$dev
- device_$dev set private devinfo_$dev
+ $dev set private devinfo_$dev
devinfo_$dev set ipaddr $_ipaddr
devinfo_$dev set netmask $_netmask
@@ -1479,7 +1519,7 @@ f_device_dialog_tcp()
else
cp="inet $_ipaddr netmask $_netmask${extras:+ $extras}"
fi
- setvar $VAR_IFCONFIG$dev "$cp"
+ setvar $VAR_IFCONFIG$devname "$cp"
fi
[ "$use_rtsol" ] &&
setvar $VAR_IPV6_ENABLE "YES"
@@ -1552,7 +1592,7 @@ f_device_scan_tcp()
#
f_device_select_tcp()
{
- local devs dev cnt network_dev
+ local devs dev cnt if network_dev
f_getvar $VAR_NETWORK_DEVICE network_dev
f_dprintf "f_device_select_tcp: %s=[%s]" \
@@ -1570,23 +1610,18 @@ f_device_select_tcp()
while [ "$network_dev" ]; do
case "$network_dev" in
- *,*) dev="${network_dev%%,*}"
+ *,*) if="${network_dev%%,*}"
network_dev="${network_dev#*,}"
;;
- *) dev="$network_dev"
+ *) if="$network_dev"
network_dev=
esac
- f_device_find "$dev" $DEVICE_TYPE_NETWORK devs
- cnt=$( set -- $devs; echo $# )
-
- if [ ${cnt:=0} -gt 0 ]; then
- dev="${devs%%[$IFS]*}"
- f_device_dialog_tcp $dev
- if [ $? -eq $DIALOG_OK ]; then
- setvar $VAR_NETWORK_DEVICE $dev
- return $DIALOG_OK
- fi
+ f_device_find -1 "$if" $DEVICE_TYPE_NETWORK dev
+ f_device_dialog_tcp $dev
+ if [ $? -eq $DIALOG_OK ]; then
+ setvar $VAR_NETWORK_DEVICE $if
+ return $DIALOG_OK
fi
done
@@ -1596,8 +1631,9 @@ f_device_select_tcp()
fi # $network_dev
f_device_find "" $DEVICE_TYPE_NETWORK devs
- cnt=$( set -- $devs; echo $# )
+ f_count cnt $devs
dev="${devs%%[$IFS]*}"
+ $dev get name if
f_quietly f_getvar NETWORK_CONFIGURED # for debugging info
if ! f_running_as_init &&
@@ -1606,7 +1642,7 @@ f_device_select_tcp()
trap 'f_interrupt' SIGINT
if f_dialog_yesno "$msg_assume_network_is_already_configured"
then
- setvar $VAR_NETWORK_DEVICE $dev
+ setvar $VAR_NETWORK_DEVICE $if
return $DIALOG_OK
fi
fi
@@ -1618,7 +1654,7 @@ f_device_select_tcp()
elif [ $cnt -eq 1 ]; then
f_device_dialog_tcp $dev
retval=$?
- [ $retval -eq $DIALOG_OK ] && setvar $VAR_NETWORK_DEVICE $dev
+ [ $retval -eq $DIALOG_OK ] && setvar $VAR_NETWORK_DEVICE $if
else
local title="$msg_network_interface_information_required"
local prompt="$msg_please_select_ethernet_device_to_configure"
@@ -1627,19 +1663,14 @@ f_device_select_tcp()
dev=$( f_device_menu \
"$title" "$prompt" "$hline" $DEVICE_TYPE_NETWORK \
"$NETWORK_DEVICE_HELPFILE" \
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
- retval=$?
- [ "$dev" ] || return $DIALOG_CANCEL
-
- f_device_find "$dev" $DEVICE_TYPE_NETWORK devs
- [ "$devs" ] || return $DIALOG_CANCEL
- dev="${devs%%[$IFS]*}"
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) ||
+ return $DIALOG_CANCEL
f_device_dialog_tcp $dev
retval=$?
if [ $retval -eq $DIALOG_OK ]; then
- f_struct_copy device_$dev device_network
- setvar $VAR_NETWORK_DEVICE network
+ f_struct_copy "$dev" device_network
+ setvar $VAR_NETWORK_DEVICE device_network
else
f_struct_free device_network
fi
@@ -1667,7 +1698,7 @@ f_dialog_menu_select_tcp()
device_network get name name &&
f_yesno "$msg_would_you_like_to_bring_interface_up" "$name"
then
- if ! f_device_init network; then
+ if ! f_device_init device_network; then
f_show_msg "$msg_initialization_of_device_failed" \
"$name"
fi
diff --git a/usr.sbin/bsdconfig/share/media/ufs.subr b/usr.sbin/bsdconfig/share/media/ufs.subr
index 2de29b3f454ad..27e2f275b1823 100644
--- a/usr.sbin/bsdconfig/share/media/ufs.subr
+++ b/usr.sbin/bsdconfig/share/media/ufs.subr
@@ -67,7 +67,7 @@ f_media_set_ufs()
local devs ndevs
f_device_find "" $DEVICE_TYPE_UFS devs
- ndevs=$( set -- $devs; echo $# )
+ f_count ndevs $devs
if [ ${ndevs:=0} -eq 0 ]; then
f_variable_get_value $VAR_UFS_PATH \
@@ -89,22 +89,20 @@ f_media_set_ufs()
f_struct_copy device_ufs device_media
f_struct_free device_ufs
- elif [ $ndevs -gt 1 ]; then
+ elif [ $ndevs -eq 1 ]; then
+ f_struct_copy $devs device_media
+ else
+ local dev
local title="$msg_choose_a_ufs_partition"
local prompt="$msg_please_select_ufs_partition"
local hline=""
- local dev retval
dev=$( f_device_menu \
"$title" "$prompt" "$hline" $DEVICE_TYPE_UFS \
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
- retval=$?
- [ "$dev" ] || return $FAILURE
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) ||
+ return $FAILURE
- f_struct_copy device_$dev device_media
- [ $retval -eq $SUCCESS ] || return $FAILURE
- else
- f_struct_copy device_$devs device_media
+ f_struct_copy "$dev" device_media
fi
f_struct device_media || return $FAILURE
@@ -117,9 +115,10 @@ f_media_set_ufs()
#
f_media_init_ufs()
{
+ local funcname=f_media_init_ufs
local dev="$1" devname err
- device_$dev get devname devname || return $FAILURE
+ $dev get devname devname || return $FAILURE
f_dprintf "Init routine called for UFS device. devname=[%s]" \
"$devname"
@@ -134,14 +133,13 @@ f_media_init_ufs()
return $FAILURE
fi
- if [ ! -e "$MOUNTPOINT" ] &&
- ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
- then
- f_dialog_msgbox "$err"
- return $FAILURE
+ if [ ! -e "$MOUNTPOINT" ]; then
+ f_eval_catch $funcname mkdir 'mkdir -p "%s"' "$MOUNTPOINT" ||
+ return $FAILURE
fi
- if ! err=$( mount "$devname" "$MOUNTPOINT" 2>&1 )
+ if ! f_eval_catch -dk err $funcname mount \
+ 'mount "%s" "%s"' "$devname" "$MOUNTPOINT"
then
err="${err#mount: }"; err="${err#$devname : }"
f_show_msg "$msg_error_mounting_device" \
@@ -162,9 +160,11 @@ f_media_init_ufs()
f_media_get_ufs()
{
local dev="$1" file="$2" probe_type="$3"
+ local name
+ $dev get name name
f_dprintf "f_media_get_ufs: dev=[%s] file=[%s] probe_type=%s" \
- "$dev" "$file" "$probe_type"
+ "$name" "$file" "$probe_type"
f_media_generic_get "$MOUNTPOINT" "$file" "$probe_type"
}
@@ -175,11 +175,14 @@ f_media_get_ufs()
#
f_media_shutdown_ufs()
{
+ local funcname=f_media_shutdown_ufs
local dev="$1" err
[ "$UFS_MOUNTED" ] || return $FAILURE
- if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ if ! f_eval_catch -dk err $funcname umount \
+ 'umount -f "%s"' "$MOUNTPOINT"
+ then
err="${err#umount: }"; err="${err#*: }"
f_show_msg "$msg_could_not_unmount_the_ufs_partition" \
"$MOUNTPOINT" "$err"
diff --git a/usr.sbin/bsdconfig/share/media/usb.subr b/usr.sbin/bsdconfig/share/media/usb.subr
index f7afc296067e2..5ee9bc0438001 100644
--- a/usr.sbin/bsdconfig/share/media/usb.subr
+++ b/usr.sbin/bsdconfig/share/media/usb.subr
@@ -57,31 +57,25 @@ f_media_set_usb()
local devs ndevs
f_device_find "" $DEVICE_TYPE_USB devs
- ndevs=$( set -- $devs; echo $# )
+ f_count ndevs $devs
if [ ${ndevs:=0} -eq 0 ]; then
f_show_msg "$msg_no_usb_devices_found"
return $FAILURE
- elif [ $ndevs -gt 1 ]; then
+ elif [ $ndevs -eq 1 ]; then
+ f_struct_copy $devs device_media
+ else
+ local dev
local title="$msg_choose_a_usb_drive"
local prompt="$msg_please_select_a_usb_drive"
- local hline=""
+ local hline=
- local dev retval
dev=$( f_device_menu \
"$title" "$prompt" "$hline" $DEVICE_TYPE_USB \
- 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
- retval=$?
- [ "$dev" ] || return $FAILURE
-
- f_device_find "$dev" $DEVICE_TYPE_USB devs
- [ "$devs" ] || return $FAILURE
- dev="${devs%%[$IFS]*}"
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) ||
+ return $FAILURE
- f_struct_copy device_$dev device_media
- [ $retval -eq $SUCCESS ] || return $FAILURE
- else
- f_struct_copy device_$devs device_media
+ f_struct_copy "$dev" device_media
fi
f_struct device_media &&
@@ -103,9 +97,10 @@ f_media_set_usb()
#
f_media_init_usb()
{
+ local funcname=f_media_init_usb
local dev="$1" devname err
- device_$dev get devname devname || return $FAILURE
+ $dev get devname devname || return $FAILURE
f_dprintf "Init routine called for USB device. devname=[%s]" \
"$devname"
@@ -114,14 +109,14 @@ f_media_init_usb()
return $SUCCESS
fi
- if [ ! -e "$MOUNTPOINT" ] &&
- ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
- then
- f_dialog_msgbox "$err"
- return $FAILURE
+ if [ ! -e "$MOUNTPOINT" ]; then
+ f_eval_catch $funcname mkdir 'mkdir -p "%s"' "$MOUNTPOINT" ||
+ return $FAILURE
fi
- if err=$( mount "$devname" "$MOUNTPOINT" 2>&1 ); then
+ if f_eval_catch -dk err $funcname mount \
+ 'mount "%s" "%s"' "$devname" "$MOUNTPOINT"
+ then
USB_MOUNTED=1
return $SUCCESS
fi
@@ -142,9 +137,11 @@ f_media_init_usb()
f_media_get_usb()
{
local dev="$1" file="$2" probe_type="$3"
+ local name
+ $dev get name name
f_dprintf "f_media_get_usb: dev=[%s] file=[%s] probe_type=%s" \
- "$dev" "$file" "$probe_type"
+ "$name" "$file" "$probe_type"
f_media_generic_get "$MOUNTPOINT" "$file" "$probe_type"
}
@@ -156,11 +153,14 @@ f_media_get_usb()
#
f_media_shutdown_usb()
{
+ local funcname=f_media_shutdown_usb
local dev="$1" err
[ "$USB_MOUNTED" ] || return $FAILURE
- if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ if ! f_eval_catch -dk err $funcname umount \
+ 'umount -f "%s"' "$MOUNTPOINT"
+ then
err="${err#umount: }"; err="${err#*: }"
f_show_msg "$msg_could_not_unmount_the_ufs_partition" \
"$MOUNTPOINT" "$err"
diff --git a/usr.sbin/bsdconfig/share/mustberoot.subr b/usr.sbin/bsdconfig/share/mustberoot.subr
index 67b4c3ee3b82a..88ff81868d454 100644
--- a/usr.sbin/bsdconfig/share/mustberoot.subr
+++ b/usr.sbin/bsdconfig/share/mustberoot.subr
@@ -32,6 +32,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
. $BSDCFG_SHARE/common.subr || exit 1
f_dprintf "%s: loading includes..." mustberoot.subr
f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/strings.subr
BSDCFG_LIBE="/usr/libexec/bsdconfig"
f_include_lang $BSDCFG_LIBE/include/messages.subr
@@ -77,6 +78,7 @@ SECURE_DIVULGE_UNKNOWN_USER=
#
f_become_root_via_sudo()
{
+ local funcname=f_become_root_via_sudo
local prompt hline height width rows msg
[ "$( id -u )" = "0" ] && return $SUCCESS
@@ -90,8 +92,8 @@ f_become_root_via_sudo()
#
local checkpath="${HOME%/}/.bsdconfig_uses_sudo"
if [ ! -e "$checkpath" ]; then
- prompt=$( printf "$msg_you_are_not_root_but" bsdconfig )
- msg=$( printf "$msg_always_try_sudo_when_run_as" "$USER" )
+ f_sprintf prompt "$msg_you_are_not_root_but" bsdconfig
+ f_sprintf msg "$msg_always_try_sudo_when_run_as" "$USER"
local menu_list="
'X' '$msg_cancel_exit'
'1' '$msg'
@@ -124,12 +126,9 @@ f_become_root_via_sudo()
X) # Cancel/Exit
f_die ;;
1) # Always try sudo(8) when run as $user
- local err
- if ! err=$( touch "$checkpath" 2>&1 ); then
- f_dialog_msgbox "$err"
- else
+ f_eval_catch $funcname touch \
+ 'touch "%s"' "$checkpath" &&
f_show_msg "$msg_created_path" "$checkpath"
- fi
esac
else
#
@@ -225,7 +224,7 @@ f_become_root_via_sudo()
# the security event and exit immediately.
#
if [ $nfailures -ge $PASSWD_TRIES ]; then
- msg=$( printf "$msg_nfailed_attempts" "$nfailures" )
+ f_sprintf msg "$msg_nfailed_attempts" "$nfailures"
logger -p auth.notice -t sudo " " \
"$USER : $msg" \
"; TTY=$(tty)" \
@@ -387,7 +386,7 @@ f_authenticate_some_user()
# the security event and exit immediately.
#
if [ $nfailures -ge $PASSWD_TRIES ]; then
- msg=$( printf "$msg_nfailed_attempts" "$nfailures" )
+ f_sprintf msg "$msg_nfailed_attempts" "$nfailures"
logger -p auth.notice -t sudo " " \
"${SUDO_USER:-$USER} : $msg" \
"; TTY=$(tty)" \
diff --git a/usr.sbin/bsdconfig/share/packages/categories.subr b/usr.sbin/bsdconfig/share/packages/categories.subr
index dd2fa8f4428f8..474c41d948edd 100755
--- a/usr.sbin/bsdconfig/share/packages/categories.subr
+++ b/usr.sbin/bsdconfig/share/packages/categories.subr
@@ -39,6 +39,7 @@ f_include_lang $BSDCFG_LIBE/include/messages.subr
############################################################ GLOBALS
CATEGORIES=
+NCATEGORIES=0
############################################################ FUNCTIONS
@@ -199,8 +200,9 @@ f_category x11-wm "$msg_x11_wm_desc"
f_category xfce "$msg_xfce_desc"
f_category zope "$msg_zope_desc"
+f_count NCATEGORIES $CATEGORIES
f_dprintf "%s: Initialized %u package category descriptions." \
- packages/categories.subr "$( set -- $CATEGORIES; echo $# )"
+ packages/categories.subr $NCATEGORIES
f_dprintf "%s: Successfully loaded." packages/categories.subr
diff --git a/usr.sbin/bsdconfig/share/packages/index.subr b/usr.sbin/bsdconfig/share/packages/index.subr
index 863249c217881..9586501228ba0 100755
--- a/usr.sbin/bsdconfig/share/packages/index.subr
+++ b/usr.sbin/bsdconfig/share/packages/index.subr
@@ -43,45 +43,231 @@ f_include_lang $BSDCFG_LIBE/include/messages.subr
PACKAGE_INDEX=
_INDEX_INITTED=
+#
+# Default path to pkg(8) repo-packagesite.sqlite database
+#
+SQLITE_REPO="/var/db/pkg/repo-packagesite.sqlite"
+
+#
+# Default path to on-disk cache INDEX file
+#
+PACKAGES_INDEX_CACHEFILE="/var/run/bsdconfig/packages_INDEX.cache"
+
+#
+# INDEX format for FreeBSD-6.0 or higher:
+#
+# package|port-origin|install-prefix|comment|port-desc-file|maintainer|
+# categories|build-deps|run-deps|www-site|reserve|reserve|reserve|disc
+#
+INDEX_FORMAT="%n-%v" # package
+INDEX_FORMAT="$INDEX_FORMAT|/usr/ports/%o" # port-origin
+INDEX_FORMAT="$INDEX_FORMAT|%p" # install-prefix
+INDEX_FORMAT="$INDEX_FORMAT|%c" # comment
+INDEX_FORMAT="$INDEX_FORMAT|/usr/ports/%o/pkg-descr" # port-desc-file
+INDEX_FORMAT="$INDEX_FORMAT|%m" # maintainer
+INDEX_FORMAT="$INDEX_FORMAT|@CATEGORIES@" # place-holder
+INDEX_FORMAT="$INDEX_FORMAT|" # build-deps
+INDEX_FORMAT="$INDEX_FORMAT|@RUNDEPS@" # place-holder
+INDEX_FORMAT="$INDEX_FORMAT|%w" # www-site
+INDEX_FORMAT="$INDEX_FORMAT|" # reserved
+INDEX_FORMAT="$INDEX_FORMAT|" # reserved
+INDEX_FORMAT="$INDEX_FORMAT|" # reserved
+INDEX_FORMAT="$INDEX_FORMAT|" # disc
+
############################################################ FUNCTIONS
-# f_index_initialize $path [$var_to_set]
+# f_index_initialize [$var_to_set]
#
-# Read and initialize the global index. $path is to be relative to the chosen
-# media (not necessarily the filesystem; e.g. FTP) -- this is usually going to
-# be `packages/INDEX'. Returns success unless media cannot be initialized for
-# any reason (e.g. user cancels media selection dialog) or an error occurs. The
-# index is sorted before being loaded into $var_to_set.
+# Read and initialize the global index. Returns success unless media cannot be
+# initialized for any reason (e.g. user cancels media selection dialog or an
+# error occurs). The index is sorted before being loaded into $var_to_set.
#
# NOTE: The index is processed with f_index_read() [below] after being loaded.
#
f_index_initialize()
{
- local __path="$1" __var_to_set="${2:-PACKAGE_INDEX}"
+ local __funcname=f_index_initialize
+ local __var_to_set="${2:-PACKAGE_INDEX}"
[ "$_INDEX_INITTED" ] && return $SUCCESS
- [ "$__path" ] || return $FAILURE
# Got any media?
f_media_verify || return $FAILURE
# Does it move when you kick it?
- f_device_init media || return $FAILURE
+ f_device_init device_media || return $FAILURE
- f_show_info "$msg_attempting_to_fetch_file_from_selected_media" \
- "$__path"
- eval "$__var_to_set"='$( f_device_get media "$__path" )'
- if [ $? -ne $SUCCESS ]; then
- f_show_msg "$msg_unable_to_get_file_from_selected_media" \
- "$__path"
- f_device_shutdown media
+ f_show_info "$msg_attempting_to_update_repository_catalogue"
+
+ #
+ # Generate $PACKAGESITE variable for pkg(8) based on media type
+ #
+ local __type __data __site
+ device_media get type __type
+ device_media get private __data
+ case "$__type" in
+ $DEVICE_TYPE_DIRECTORY)
+ __site="file://$__data/packages/$PKG_ABI" ;;
+ $DEVICE_TYPE_FLOPPY)
+ __site="file://${__data:-$MOUNTPOINT}/packages/$PKG_ABI" ;;
+ $DEVICE_TYPE_FTP)
+ f_getvar $VAR_FTP_PATH __site
+ __site="$__site/packages/$PKG_ABI" ;;
+ $DEVICE_TYPE_HTTP)
+ f_getvar $VAR_HTTP_PATH __site
+ __site="$__site/$PKG_ABI/latest" ;;
+ $DEVICE_TYPE_HTTP_PROXY)
+ f_getvar $VAR_HTTP_PROXY_PATH __site
+ __site="$__site/packages/$PKG_ABI" ;;
+ $DEVICE_TYPE_CDROM)
+ __site="file://$MOUNTPOINT/packages/$PKG_ABI"
+ export REPOS_DIR="$MOUNTPOINT/packages/repos" ;;
+ *) # UFS, DISK, CDROM, USB, DOS, NFS, etc.
+ __site="file://$MOUNTPOINT/packages/$PKG_ABI"
+ esac
+
+ export PACKAGESITE="$__site"
+ f_dprintf "PACKAGESITE=[%s]" "$PACKAGESITE"
+ if ! f_eval_catch $__funcname pkg "pkg update"; then
+ f_show_err "$msg_unable_to_update_pkg_from_selected_media"
+ f_device_shutdown device_media
return $FAILURE
fi
+
+ #
+ # Try to get contents from validated on-disk cache
+ #
+
+ #
+ # Calculate digest used to determine if the on-disk persistant cache
+ # INDEX (containing this digest on the first line) is valid and can be
+ # used to quickly populate the environment.
+ #
+ local __sqlite_digest
+ if ! __sqlite_digest=$( md5 < "$SQLITE_REPO" 2> /dev/null ); then
+ f_show_err "$msg_no_pkg_database_found"
+ f_device_shutdown device_media
+ return $FAILURE
+ fi
+
+ #
+ # Check to see if the persistant cache INDEX file exists
+ #
+ if [ -f "$PACKAGES_INDEX_CACHEFILE" ]; then
+ #
+ # Attempt to populate the environment with the (soon to be)
+ # validated on-disk cache. If validation fails, fall-back to
+ # generating a fresh cache.
+ #
+ if eval $__var_to_set='$(
+ ( # Get digest as the first word on first line
+ read digest rest_ignored
+
+ #
+ # If the stored digest matches the calculated-
+ # one populate the environment from the on-disk
+ # cache and provide success exit status.
+ #
+ if [ "$digest" = "$__sqlite_digest" ]; then
+ cat
+ exit $SUCCESS
+ else
+ # Otherwise, return the current value
+ eval echo \"\$__var_to_set\"
+ exit $FAILURE
+ fi
+ ) < "$PACKAGES_INDEX_CACHEFILE" 2> /dev/null
+ )'; then
+ f_show_info \
+ "$msg_located_index_now_reading_package_data_from_it"
+ if ! f_index_read "$__var_to_set"; then
+ f_show_err \
+ "$msg_io_or_format_error_on_index_file"
+ return $FAILURE
+ fi
+ _INDEX_INITTED=1
+ return $SUCCESS
+ fi
+ # Otherwise, fall-thru to create a fresh cache from scratch
+ fi
+
+ #
+ # If we reach this point, we need to generate the data from scratch
+ #
+
+ f_show_info "$msg_getting_package_categories_via_pkg_rquery"
+ if ! eval "$( pkg rquery "%n-%v %C" | awk '
+ { categories[$1] = categories[$1] " " $2 }
+ END {
+ for (package in categories)
+ {
+ cats = categories[package]
+ sub(/^ /, "", cats)
+ gsub(/[^[:alnum:]_]/, "_", package)
+ printf "local _%s_categories=\"%s\";\n", package, cats
+ }
+ }' )"; then
+ f_show_err "$msg_unable_to_pkg_rquery_package_dependencies"
+ f_device_shutdown device_media
+ return $FAILURE
+ fi
+
+ f_show_info "$msg_getting_package_dependencies_via_pkg_rquery"
+ if ! eval "$( pkg rquery "%n-%v %dn-%dv" | awk '
+ { rundeps[$1] = rundeps[$1] " " $2 }
+ END {
+ for (package in rundeps)
+ {
+ deps = rundeps[package]
+ sub(/^ /, "", deps)
+ gsub(/[^[:alnum:]_]/, "_", package)
+ printf "local _%s_rundeps=\"%s\";\n", package, deps
+ }
+ }' )"; then
+ f_show_err "$msg_unable_to_pkg_rquery_package_dependencies"
+ f_device_shutdown device_media
+ return $FAILURE
+ fi
+
+ f_show_info "$msg_generating_index_from_pkg_database"
+ eval "$__var_to_set"='$( pkg rquery "$INDEX_FORMAT" |
+ while read LINE; do
+ package="${LINE%%|*}";
+ f_str2varname "$package" varpkg;
+ eval f_replaceall \"\$LINE\" \"\|@CATEGORIES@\|\" \
+ \"\|\$_${varpkg}_categories\|\" LINE
+ eval f_replaceall \"\$LINE\" \"\|@RUNDEPS@\|\" \
+ \"\|\$_${varpkg}_rundeps\|\" LINE
+ echo "$LINE"
+ done
+ )' # always returns true (status of last item in pipe-chain)
eval "$__var_to_set"='$( debug= f_getvar "$__var_to_set" | sort )'
+ #
+ # Attempt to create the persistant on-disk cache
+ #
+
+ # Create a new temporary file to write to
+ local __tmpfile
+ if f_eval_catch -dk __tmpfile $__funcname mktemp \
+ 'mktemp -t "%s"' "$pgm"
+ then
+ # Write the temporary file contents
+ echo "$__sqlite_digest" > "$__tmpfile"
+ debug= f_getvar "$__var_to_set" >> "$__tmpfile"
+
+ # Finally, move the temporary file into place
+ case "$PACKAGES_INDEX_CACHEFILE" in
+ */*) f_eval_catch -d $funcname mkdir \
+ 'mkdir -p "%s"' "${PACKAGES_INDEX_CACHEFILE%/*}"
+ esac
+ f_eval_catch -d $__funcname mv 'mv -f "%s" "%s"' \
+ "$__tmpfile" "$PACKAGES_INDEX_CACHEFILE"
+ fi
+
f_show_info "$msg_located_index_now_reading_package_data_from_it"
if ! f_index_read "$__var_to_set"; then
- f_show_msg "$msg_io_or_format_error_on_index_file" "$__path"
+ f_show_err "$msg_io_or_format_error_on_index_file"
return $FAILURE
fi
diff --git a/usr.sbin/bsdconfig/share/packages/packages.subr b/usr.sbin/bsdconfig/share/packages/packages.subr
index 85aebc80cf1aa..6fc936fe9e9d4 100755
--- a/usr.sbin/bsdconfig/share/packages/packages.subr
+++ b/usr.sbin/bsdconfig/share/packages/packages.subr
@@ -53,7 +53,7 @@ f_include_lang $BSDCFG_LIBE/include/messages.subr
#
# Package extensions to try
#
-PACKAGE_EXTENSIONS=".tbz .tbz2 .tgz"
+PACKAGE_EXTENSIONS=".txz .tbz .tbz2 .tgz"
#
# Variables used to track runtime states
@@ -164,24 +164,13 @@ f_package_deselect()
# f_package_detect_installed
#
-# Detect installed packages. Currently this searches /var/db/pkg for directory
+# Detect installed packages. Currently this uses pkg-query(8) for querying
# entries and marks each entry as an installed/selected package.
#
f_package_detect_installed()
{
- local installed package varpkg
- #
- # XXX KLUDGE ALERT! This makes evil assumptions about how XXX
- # packages register themselves and should *really* be done with
- # `pkg_info -e <name>' except that this is too slow for an
- # item check routine.. :-(
- #
- # NOTE: When transitioning to pkgng, make a single fork to `pkg' to
- # produce a list of all installed packages and parse _that_
- #
- installed=$( find -s /var/db/pkg -mindepth 1 -maxdepth 1 -type d |
- sed -e 's:/var/db/pkg/::' )
- for package in $installed; do
+ local package varpkg
+ for package in $( pkg query "%n-%v" ); do
f_str2varname $package varpkg
export _mark_$varpkg=X # exported for awk(1) ENVIRON[]
f_package_select $package
@@ -483,8 +472,7 @@ f_package_menu_select()
"$msg_all"|"") f_category_desc_get "All" prompt ;;
*) f_category_desc_get "$category" prompt ;;
esac
- prompt="$prompt $( printf "$msg_page_of_npages" \
- "$page" "$npages" )"
+ f_sprintf prompt "%s $msg_page_of_npages" "$prompt" "$page" "$npages"
local mheight mwidth mrows
eval f_dialog_menu${SHOW_DESC:+_with_help}_size mheight mwidth mrows \
@@ -547,7 +535,7 @@ f_package_menu_deselect()
" # End-Quote
local hline="$hline_alnum_arrows_punc_tab_enter"
- prompt=$( printf "$msg_what_would_you_like_to_do_with" "$package" )
+ f_sprintf prompt "$msg_what_would_you_like_to_do_with" "$package"
local height width rows
eval f_dialog_menu_size height width rows \
@@ -582,14 +570,14 @@ f_package_menu_deselect()
#
f_package_review()
{
+ local funcname=f_package_review
local prompt # Calculated below
local menu_list # Calculated below
local hline="$hline_alnum_arrows_punc_tab_enter"
- local fname=f_package_review
- f_dprintf "%s: SELECTED_PACKAGES=[%s]" $fname "$SELECTED_PACKAGES"
+ f_dprintf "$funcname: SELECTED_PACKAGES=[%s]" "$SELECTED_PACKAGES"
- prompt=$( printf "$msg_reviewing_selected_packages" "$_All_nselected" )
+ f_sprintf prompt "$msg_reviewing_selected_packages" "$_All_nselected"
local package varpkg mark
for package in $SELECTED_PACKAGES; do
@@ -639,7 +627,7 @@ f_package_review()
f_str2varname "$package" varpkg
debug= f_getvar _mark_$varpkg mark
[ "$mark" = "I" ] || continue
- f_dprintf "%s: Installing %s package" $fname "$package"
+ f_dprintf "$funcname: Installing %s package" "$package"
f_package_add "$package"
done
for package in $SELECTED_PACKAGES; do
@@ -647,7 +635,7 @@ f_package_review()
f_str2varname "$package" varpkg
debug= f_getvar _mark_$varpkg mark
[ "$mark" = "R" ] || continue
- f_dprintf "%s: Reinstalling %s package" $fname "$package"
+ f_dprintf "$funcname: Reinstalling %s package" "$package"
f_package_reinstall "$package"
done
for package in $SELECTED_PACKAGES; do
@@ -655,7 +643,7 @@ f_package_review()
f_str2varname "$package" varpkg
debug= f_getvar _mark_$varpkg mark
[ "$mark" = "U" ] || continue
- f_dprintf "%s: Uninstalling %s package" $fname "$package"
+ f_dprintf "$funcname: Uninstalling %s package" "$package"
f_package_delete "$package" || continue
f_package_deselect "$package"
done
@@ -850,7 +838,7 @@ f_package_add()
{ # Verify and initialize device media if-defined
f_media_verify &&
- f_device_init media &&
+ f_device_init device_media &&
f_index_initialize packages/INDEX
} || return $FAILURE
@@ -935,7 +923,7 @@ f_package_add()
# Done with the deps? Try to load the real m'coy.
#
- f_package_extract media "$name" "$depended"
+ f_package_extract device_media "$name" "$depended"
retval=$?
if [ $retval -ne $SUCCESS ]; then
status=$(( $status | $retval ))
@@ -954,11 +942,13 @@ f_package_add()
#
f_package_extract()
{
+ local funcname=f_package_extract
local device="$1" name="$2" depended="$3"
+ local devname=
- local fname=f_package_extract
- f_dprintf "%s: device=[%s] name=[%s] depended=[%s]" \
- $fname "$device" "$name" "$depended"
+ $device get name devname
+ f_dprintf "$funcname: device=[%s] name=[%s] depended=[%s]" \
+ "$devname" "$name" "$depended"
# Check to make sure it's not already there
local varpkg mark=
@@ -982,43 +972,51 @@ f_package_extract()
f_getvar $VAR_PKG_TMPDIR:-/var/tmp tmpdir
f_quietly mkdir -p -m 1777 "$tmpdir"
- local path
+ local path device_type
+ $device get type device_type
case "$name" in
*/*) path="$name" ;;
*)
- case "$name" in
- *-*|*_*) path="packages/All/$name" ;;
- *) path="packages/Latest/$name"
- esac
+ if [ "$device_type" = "$DEVICE_TYPE_HTTP" ]; then
+ path="$PKG_ABI/latest/All/$name"
+ else
+ path="packages/$PKG_ABI/All/$name"
+ fi
esac
- # We have a path, call the device strategy routine to get the file
+ # We have a path, call the device strategy routine to check the file
local pkg_ext found=
for pkg_ext in "" $PACKAGE_EXTENSIONS; do
if f_device_get $device "$path$pkg_ext" $PROBE_EXIST; then
path="$path$pkg_ext"
- f_dprintf "%s: found path=[%s] dev=[%s]" \
- $fname "$path" "$device"
+ found=1
+ break
+ elif [ "$device_type" = "$DEVICE_TYPE_HTTP" ] &&
+ f_device_get $device \
+ "packages/$PKG_ABI/All/$name$pkg_ext" $PROBE_EXIST
+ then
+ # Mirroring physical media over HTTP
+ path="packages/$PKG_ABI/All/$name$pkg_ext"
found=1
break
fi
done
+ [ "$found" ] && f_dprintf "$funcname: found path=[%s] dev=[%s]" \
+ "$path" "$devname"
local alert=f_show_msg no_confirm=
f_getvar $VAR_NO_CONFIRM no_confirm
[ "$no_confirm" ] && alert=f_show_info
if [ ! "$found" ]; then
- f_dprintf "%s: No such %s file on %s device" \
- $fname "$path" "$device"
+ f_dprintf "$funcname: No such %s file on %s device" \
+ "$path" "$devname"
$alert "$msg_unable_to_fetch_package_from_selected_media" \
"$name"
[ "$no_confirm" ] && sleep 2
return $FAILURE
fi
- local devname=
- f_struct device_$device get name devname
if [ "$depended" ]; then
f_show_info "$msg_adding_package_as_a_dependency_from_media" \
"$name" "$devname"
@@ -1026,27 +1024,14 @@ f_package_extract()
f_show_info "$msg_adding_package_from_media" "$name" "$devname"
fi
- # Get package data and pipe into pkg_add(1) while providing feedback
- {
- if ! f_device_get $device "$path"; then
- $alert "$msg_io_error_while_reading_in_the_package" \
- "$name" \
- >&$DIALOG_TERMINAL_PASSTHRU_FD 2> /dev/null
- [ "$no_confirm" ] && sleep 2
- else
- f_show_info \
- "$msg_package_read_successfully_waiting_for_pkg_add" \
- "$name" >&$DIALOG_TERMINAL_PASSTHRU_FD 2> /dev/null
- fi
- } | {
- if f_debugging; then
- /usr/sbin/pkg_add -v -
- else
- f_quietly /usr/sbin/pkg_add -
- fi
- }
+ # Request the package be added via pkg-install(8)
+ if f_debugging; then
+ f_eval_catch $funcname pkg 'pkg -d install -y "%s"' "$name"
+ else
+ f_eval_catch $funcname pkg 'pkg install -y "%s"' "$name"
+ fi
if [ $? -ne $SUCCESS ]; then
- $alert "$msg_pkg_add_apparently_did_not_like_the_package" \
+ $alert "$msg_pkg_install_apparently_did_not_like_the_package" \
"$name"
[ "$no_confirm" ] && sleep 2
else
@@ -1063,8 +1048,8 @@ f_package_extract()
#
f_package_delete()
{
+ local funcname=f_package_delete
local name="$1"
- local fname=f_package_delete
if ! { [ "$name" ] || { f_getvar $VAR_PACKAGE name && [ "$name" ]; }; }
then
@@ -1073,13 +1058,13 @@ f_package_delete()
return $FAILURE
fi
- f_dprintf "%s: name=[%s]" $fname "$name"
+ f_dprintf "$funcname: name=[%s]" "$name"
[ "$name" ] || return $FAILURE
{ # Verify and initialize device media if-defined
f_media_verify &&
- f_device_init media &&
+ f_device_init device_media &&
f_index_initialize packages/INDEX
} || return $FAILURE
@@ -1110,7 +1095,7 @@ f_package_delete()
# detected the installed packages -- something we should do only once.
#
if [ ! "$PACKAGES_DETECTED" ]; then
- f_dprintf "%s: Detecting installed packages" $fname
+ f_dprintf "$funcname: Detecting installed packages"
f_package_detect_installed
export PACKAGES_DETECTED=1 # exported for awk(1) ENVIRON[]
fi
@@ -1162,8 +1147,8 @@ f_package_delete()
# Chase dependencies that are marked for uninstallation
#
for pkgsel in $udeps; do
- f_dprintf "%s: Uninstalling dependecy %s (marked for delete)" \
- $fname "$pkgsel"
+ f_dprintf "$funcname: Uninstalling dependency %s (%s)" \
+ "$pkgsel" "marked for delete"
f_package_delete "$pkgsel"
done
@@ -1172,15 +1157,15 @@ f_package_delete()
#
f_show_info "$msg_uninstalling_package_waiting_for_pkg_delete" "$name"
if f_debugging; then
- pkg_delete -v "$name"
+ f_eval_catch $funcname pkg 'pkg -d delete -y "%s"' "$name"
else
- f_quietly pkg_delete "$name"
+ f_eval_catch $funcname pkg 'pkg delete -y "%s"' "$name"
fi
if [ $? -ne $SUCCESS ]; then
f_show_msg "$msg_pkg_delete_failed" "$name"
return $FAILURE
else
- f_dprintf "%s: pkg_delete(1) of %s successful" $fname "$name"
+ f_dprintf "$funcname: pkg-delete(8) of %s successful" "$name"
f_str2varname "$name" varpkg
setvar _mark_$varpkg ""
fi
diff --git a/usr.sbin/bsdconfig/share/script.subr b/usr.sbin/bsdconfig/share/script.subr
index a227419936e5b..b562e99b7303d 100644
--- a/usr.sbin/bsdconfig/share/script.subr
+++ b/usr.sbin/bsdconfig/share/script.subr
@@ -1,6 +1,6 @@
if [ ! "$_SCRIPT_SUBR" ]; then _SCRIPT_SUBR=1
#
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,8 @@ f_include $BSDCFG_SHARE/media/tcpip.subr
f_include $BSDCFG_SHARE/mustberoot.subr
f_include $BSDCFG_SHARE/networking/services.subr
f_include $BSDCFG_SHARE/packages/packages.subr
+f_include $BSDCFG_SHARE/usermgmt/group.subr
+f_include $BSDCFG_SHARE/usermgmt/user.subr
f_include $BSDCFG_SHARE/variable.subr
############################################################ GLOBALS
@@ -50,25 +52,23 @@ RESWORDS=
# 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()).
+# 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\; }
+ eval $resword\(\){ f_dispatch $func $resword \"\$@\"\; }
RESWORDS="$RESWORDS${RESWORDS:+ }$resword"
}
-# f_dispatch $func [$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,
@@ -78,9 +78,10 @@ f_resword_new()
#
f_dispatch()
{
- local func="$1" resword="${2:-$1}"
+ local func="$1" resword="$2"
+ shift 2 # func resword
f_dprintf "f_dispatch: calling resword \`%s'" "$resword"
- eval $func
+ eval $func "$@"
local retval=$?
if [ $retval -ne $SUCCESS ]; then
local _ignore_this_error
@@ -96,7 +97,7 @@ f_dispatch()
# Load a script (usually filled with reswords). If $file is missing or NULL,
# use one of the following instead (in order):
#
-# $configFile
+# $configFile (global)
# install.cfg
# /stand/install.fg
# /tmp/install.cfg
@@ -108,9 +109,10 @@ f_dispatch()
#
f_script_load()
{
+ local funcname=f_script_load
local script="$1" config_file retval=$SUCCESS
- f_dprintf "f_script_load: script=[%s]" "$script"
+ f_dprintf "$funcname: script=[%s]" "$script"
if [ ! "$script" ]; then
f_getvar $VAR_CONFIG_FILE config_file
for script in \
@@ -130,11 +132,11 @@ f_script_load()
setvar $VAR_NONINTERACTIVE yes
if [ "$script" = "-" ]; then
- f_dprintf "f_script_load: Loading script from stdin"
+ f_dprintf "$funcname: Loading script from stdin"
eval "$( cat )"
retval=$?
else
- f_dprintf "f_script_load: Loading script \`%s'" "$script"
+ f_dprintf "$funcname: Loading script \`%s'" "$script"
if [ ! -e "$script" ]; then
f_show_msg "$msg_unable_to_open" "$script"
return $FAILURE
@@ -198,6 +200,16 @@ f_resword_new packageAdd f_package_add
f_resword_new packageDelete f_package_delete
f_resword_new packageReinstall f_package_reinstall
+# usermgmt/group.subr
+f_resword_new addGroup f_group_add
+f_resword_new deleteGroup f_group_delete
+f_resword_new editGroup f_group_edit
+
+# usermgmt/user.subr
+f_resword_new addUser f_user_add
+f_resword_new deleteUser f_user_delete
+f_resword_new editUser f_user_edit
+
# variable.subr
f_resword_new installVarDefaults f_variable_set_defaults
f_resword_new dumpVariables f_dump_variables
diff --git a/usr.sbin/bsdconfig/share/strings.subr b/usr.sbin/bsdconfig/share/strings.subr
index 0a77048c2a642..487e061745327 100644
--- a/usr.sbin/bsdconfig/share/strings.subr
+++ b/usr.sbin/bsdconfig/share/strings.subr
@@ -26,9 +26,20 @@ if [ ! "$_STRINGS_SUBR" ]; then _STRINGS_SUBR=1
#
# $FreeBSD$
#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+
############################################################ GLOBALS
#
+# A Literal newline (for use with f_replace_all(), or IFS, or whatever)
+#
+NL="
+" # END-QUOTE
+
+#
# Valid characters that can appear in an sh(1) variable name
#
# Please note that the character ranges A-Z and a-z should be avoided because
@@ -41,7 +52,7 @@ VALID_VARNAME_CHARS="0-9ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"
############################################################ FUNCTIONS
-# f_substr "$string" $start [ $length ]
+# f_substr "$string" $start [$length]
#
# Simple wrapper to awk(1)'s `substr' function.
#
@@ -51,17 +62,18 @@ f_substr()
echo "$string" | awk "{ print substr(\$0, $start, $len) }"
}
-# f_snprintf $var_to_set $size $format ...
+# f_snprintf $var_to_set $size $format [$arguments ...]
#
# Similar to snprintf(3), write at most $size number of bytes into $var_to_set
-# using printf(1) syntax (`$format ...'). The value of $var_to_set is NULL
-# unless at-least one byte is stored from the output.
+# using printf(1) syntax (`$format [$arguments ...]'). The value of $var_to_set
+# is NULL unless at-least one byte is stored from the output.
#
f_snprintf()
{
local __var_to_set="$1" __size="$2"
- shift 2 # var_to_set/size
- eval "$__var_to_set"=\$\( printf \"\$@\" \| awk -v max=\"\$__size\" \''
+ shift 2 # var_to_set size
+ eval "$__var_to_set"=\$\( printf -- \"\$@\" \| \
+ awk -v max=\"\$__size\" \''
{
len = length($0)
max -= len
@@ -71,6 +83,18 @@ f_snprintf()
}'\' \)
}
+# f_sprintf $var_to_set $format [$arguments ...]
+#
+# Similar to sprintf(3), write a string into $var_to_set using printf(1) syntax
+# (`$format [$arguments ...]').
+#
+f_sprintf()
+{
+ local __var_to_set="$1"
+ shift 1 # var_to_set
+ eval "$__var_to_set"=\$\( printf -- \"\$@\" \)
+}
+
# f_vsnprintf $var_to_set $size $format $format_args
#
# Similar to vsnprintf(3), write at most $size number of bytes into $var_to_set
@@ -106,6 +130,16 @@ f_vsnprintf()
eval f_snprintf \"\$1\" \"\$2\" \"\$3\" $4
}
+# f_vsprintf $var_to_set $format $format_args
+#
+# Similar to vsprintf(3), write a string into $var_to_set using printf(1)
+# syntax (`$format $format_args').
+#
+f_vsprintf()
+{
+ eval f_sprintf \"\$1\" \"\$2\" $3
+}
+
# f_longest_line_length
#
# Simple wrapper to an awk(1) script to print the length of the longest line of
@@ -160,15 +194,8 @@ f_number_of_lines()
#
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
+ local arg="${1#-}"
+ [ "${arg:-x}" = "${arg%[!0-9]*}" ]
}
# f_uriencode [$text]
@@ -244,6 +271,9 @@ f_uridecode()
# capturing in a sub-shell (which is less recommended due to performance
# degradation).
#
+# To replace newlines or a sequence containing the newline character, use $NL
+# as `\n' is not supported.
+#
f_replaceall()
{
local __left="" __right="$1"
@@ -319,6 +349,104 @@ f_shell_unescape()
f_replaceall "$__string" "'\\''" "'" "$__var_to_set"
}
+# f_expand_number $string [$var_to_set]
+#
+# Unformat $string into a number, optionally to be stored in $var_to_set. This
+# function follows the SI power of two convention.
+#
+# The prefixes are:
+#
+# Prefix Description Multiplier
+# k kilo 1024
+# M mega 1048576
+# G giga 1073741824
+# T tera 1099511627776
+# P peta 1125899906842624
+# E exa 1152921504606846976
+#
+# NOTE: Prefixes are case-insensitive.
+#
+# Upon successful completion, success status is returned; otherwise the number
+# -1 is produced ($var_to_set set to -1 or if $var_to_set is NULL or missing)
+# on standard output. In the case of failure, the error status will be one of:
+#
+# Status Reason
+# 1 Given $string contains no digits
+# 2 An unrecognized prefix was given
+# 3 Result too large to calculate
+#
+f_expand_number()
+{
+ local __string="$1" __var_to_set="$2"
+ local __cp __num __bshift __maxinput
+
+ # Remove any leading non-digits
+ __string="${__string#${__string%%[0-9]*}}"
+
+ # Store the numbers (no trailing suffix)
+ __num="${__string%%[!0-9]*}"
+
+ # Produce `-1' if string didn't contain any digits
+ if [ ! "$__num" ]; then
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" -1
+ else
+ echo -1
+ fi
+ return 1 # 1 = "Given $string contains no digits"
+ fi
+
+ # Remove all the leading numbers from the string to get at the prefix
+ __string="${__string#"$__num"}"
+
+ #
+ # Test for invalid prefix (and determine bitshift length)
+ #
+ case "$__string" in
+ ""|[[:space:]]*) # Shortcut
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" $__num
+ else
+ echo $__num
+ fi
+ return $SUCCESS ;;
+ [Kk]*) __bshift=10 ;;
+ [Mm]*) __bshift=20 ;;
+ [Gg]*) __bshift=30 ;;
+ [Tt]*) __bshift=40 ;;
+ [Pp]*) __bshift=50 ;;
+ [Ee]*) __bshift=60 ;;
+ *)
+ # Unknown prefix
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" -1
+ else
+ echo -1
+ fi
+ return 2 # 2 = "An unrecognized prefix was given"
+ esac
+
+ # Determine if the wheels fall off
+ __maxinput=$(( 0x7fffffffffffffff >> $__bshift ))
+ if [ $__num -gt $__maxinput ]; then
+ # Input (before expanding) would exceed 64-bit signed int
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" -1
+ else
+ echo -1
+ fi
+ return 3 # 3 = "Result too large to calculate"
+ fi
+
+ # Shift the number out and produce it
+ __num=$(( $__num << $__bshift ))
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" $__num
+ else
+ echo $__num
+ fi
+}
+
############################################################ MAIN
f_dprintf "%s: Successfully loaded." strings.subr
diff --git a/usr.sbin/bsdconfig/share/struct.subr b/usr.sbin/bsdconfig/share/struct.subr
index fc4f7114e5dd6..78c785fc2b515 100644
--- a/usr.sbin/bsdconfig/share/struct.subr
+++ b/usr.sbin/bsdconfig/share/struct.subr
@@ -132,7 +132,7 @@ f_struct()
local __name="$1" __action="$2" __property="$3"
case $# in
0) return $FAILURE ;;
- 1) f_have $__name ;;
+ 1) f_have "$__name" ;;
*) case "$__action" in
get) local __var_to_set="$4"
f_getvar "_struct_value_${__name}_$__property" "$__var_to_set"
diff --git a/usr.sbin/bsdconfig/share/sysrc.subr b/usr.sbin/bsdconfig/share/sysrc.subr
index 66a4cf34e94a6..d863ba05907f8 100644
--- a/usr.sbin/bsdconfig/share/sysrc.subr
+++ b/usr.sbin/bsdconfig/share/sysrc.subr
@@ -118,8 +118,8 @@ f_clean_env()
# 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).
+# configuration files (in order: /etc/defaults/rc.conf /etc/rc.conf and
+# /etc/rc.conf.local)
#
# NOTE: Additional shell parameter-expansion formats are supported. For
# example, passing an argument of "hostname%%.*" (properly quoted) will
@@ -428,6 +428,7 @@ END { exit retval }
'
f_sysrc_set()
{
+ local funcname=f_sysrc_set
local varname="$1" new_value="$2"
# Check arguments
@@ -478,8 +479,12 @@ f_sysrc_set()
#
# Create a new temporary file to write to.
#
- local tmpfile="$( mktemp -t "$pgm" )"
- [ "$tmpfile" ] || return $FAILURE
+ local tmpfile
+ if ! f_eval_catch -dk tmpfile $funcname mktemp 'mktemp -t "%s"' "$pgm"
+ then
+ echo "$tmpfile" >&2
+ return $FAILURE
+ fi
#
# Fixup permissions (else we're in for a surprise, as mktemp(1) creates
@@ -488,8 +493,9 @@ f_sysrc_set()
# permissions from the temporary file).
#
local mode
- mode=$( stat -f '%#Lp' "$file" 2> /dev/null )
- f_quietly chmod "${mode:-0644}" "$tmpfile"
+ f_eval_catch -dk mode $funcname stat 'stat -f "%%#Lp" "%s"' "$file" ||
+ mode=0644
+ f_eval_catch -d $funcname chmod 'chmod "%s" "%s"' "$mode" "$tmpfile"
#
# Fixup ownership. The destination file _is_ writable (we tested
@@ -497,8 +503,9 @@ f_sysrc_set()
# 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"
+ f_eval_catch -dk owner $funcname stat \
+ 'stat -f "%%u:%%g" "%s"' "$file" || owner="root:wheel"
+ f_eval_catch -d $funcname chown 'chown "%s" "%s"' "$owner" "$tmpfile"
#
# Operate on the matching file, replacing only the last occurrence.
@@ -520,7 +527,7 @@ f_sysrc_set()
#
# Taint-check our results.
#
- if ! /bin/sh -n "$tmpfile"; then
+ if ! f_eval_catch -d $funcname sh '/bin/sh -n "%s"' "$tmpfile"; then
f_err "$msg_previous_syntax_errors\n" "$pgm" "$file"
rm -f "$tmpfile"
return $FAILURE
@@ -529,7 +536,7 @@ f_sysrc_set()
#
# Finally, move the temporary file into place.
#
- mv "$tmpfile" "$file"
+ f_eval_catch -de $funcname mv 'mv "%s" "%s"' "$tmpfile" "$file"
}
# f_sysrc_delete $varname
@@ -560,6 +567,7 @@ END { exit ! found }
'
f_sysrc_delete()
{
+ local funcname=f_sysrc_delete
local varname="$1"
local file
@@ -569,24 +577,33 @@ f_sysrc_delete()
#
# Operate on each of the specified files
#
+ local tmpfile
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
+ if ! f_eval_catch -dk tmpfile $funcname mktemp \
+ 'mktemp -t "%s"' "$pgm"
+ then
+ echo "$tmpfile" >&2
+ return $FAILURE
+ fi
#
# 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"
+ f_eval_catch -dk mode $funcname stat \
+ 'stat -f "%%#Lp" "%s"' "$file" || mode=0644
+ f_eval_catch -dk owner $funcname stat \
+ 'stat -f "%%u:%%g" "%s"' "$file" || owner="root:wheel"
+ f_eval_catch -d $funcname chmod \
+ 'chmod "%s" "%s"' "$mode" "$tmpfile"
+ f_eval_catch -d $funcname chown \
+ 'chown "%s" "%s"' "$owner" "$tmpfile"
#
# Operate on the file, removing all occurrences, saving the
@@ -603,7 +620,8 @@ f_sysrc_delete()
#
# Taint-check our results.
#
- if ! /bin/sh -n "$tmpfile"; then
+ if ! f_eval_catch -d $funcname sh '/bin/sh -n "%s"' "$tmpfile"
+ then
f_err "$msg_previous_syntax_errors\n" \
"$pgm" "$file"
rm -f "$tmpfile"
@@ -622,7 +640,8 @@ f_sysrc_delete()
#
# Finally, move the temporary file into place.
#
- mv "$tmpfile" "$file"
+ f_eval_catch -de $funcname mv \
+ 'mv "%s" "%s"' "$tmpfile" "$file" || return $FAILURE
done
}
diff --git a/usr.sbin/bsdconfig/share/variable.subr b/usr.sbin/bsdconfig/share/variable.subr
index 86523d6b38e45..c453f674ee57a 100644
--- a/usr.sbin/bsdconfig/share/variable.subr
+++ b/usr.sbin/bsdconfig/share/variable.subr
@@ -1,6 +1,6 @@
if [ ! "$_VARIABLE_SUBR" ]; then _VARIABLE_SUBR=1
#
-# Copyright (c) 2012-2013 Devin Teske
+# Copyright (c) 2012-2014 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -179,7 +179,7 @@ f_debugging()
f_getvar $VAR_DEBUG value && [ "$value" ]
}
-# f_interactive()
+# f_interactive
#
# Are we running interactively? Return error if $nonInteractive is set and non-
# NULL, otherwise return success.
@@ -190,7 +190,7 @@ f_interactive()
! f_getvar $VAR_NONINTERACTIVE value || [ ! "$value" ]
}
-# f_netinteractive()
+# f_netinteractive
#
# Has the user specifically requested the network-portion of configuration and
# setup to be performed interactively? Returns success if the user has asked
@@ -205,6 +205,21 @@ f_netinteractive()
f_getvar $VAR_NETINTERACTIVE value && [ "$value" ]
}
+# f_zfsinteractive
+#
+# Has the user specifically requested the ZFS-portion of configuration and
+# setup to be performed interactively? Returns success if the user has asked
+# for the ZFS configuration to be done interactively even if perhaps overall
+# non-interactive mode has been requested (by setting nonInteractive).
+#
+# Returns success if $zfsInteractive is set and non-NULL.
+#
+f_zfsinteractive()
+{
+ local value
+ f_getvar $VAR_ZFSINTERACTIVE value && [ "$value" ]
+}
+
############################################################ MAIN
#
@@ -226,6 +241,10 @@ f_variable_new VAR_FTP_PORT ftpPort
f_variable_new VAR_FTP_STATE ftpState
f_variable_new VAR_FTP_USER ftpUser
f_variable_new VAR_GATEWAY defaultrouter
+f_variable_new VAR_GROUP group
+f_variable_new VAR_GROUP_GID groupGid
+f_variable_new VAR_GROUP_MEMBERS groupMembers
+f_variable_new VAR_GROUP_PASSWORD groupPassword
f_variable_new VAR_HOSTNAME hostname
f_variable_new VAR_HTTP_DIR httpDirectory
f_variable_new VAR_HTTP_FTP_MODE httpFtpMode
@@ -240,6 +259,7 @@ f_variable_new VAR_IFCONFIG ifconfig_
f_variable_new VAR_IPADDR ipaddr
f_variable_new VAR_IPV6ADDR ipv6addr
f_variable_new VAR_IPV6_ENABLE ipv6_activate_all_interfaces
+f_variable_new VAR_KEYMAP keymap
f_variable_new VAR_MEDIA_TIMEOUT MEDIA_TIMEOUT
f_variable_new VAR_MEDIA_TYPE mediaType
f_variable_new VAR_NAMESERVER nameserver
@@ -263,6 +283,22 @@ f_variable_new VAR_SLOW_ETHER slowEthernetCard
f_variable_new VAR_TRY_DHCP tryDHCP
f_variable_new VAR_TRY_RTSOL tryRTSOL
f_variable_new VAR_UFS_PATH ufs
+f_variable_new VAR_USER user
+f_variable_new VAR_USER_ACCOUNT_EXPIRE userAccountExpire
+f_variable_new VAR_USER_DOTFILES_CREATE userDotfilesCreate
+f_variable_new VAR_USER_GECOS userGecos
+f_variable_new VAR_USER_GID userGid
+f_variable_new VAR_USER_GROUPS userGroups
+f_variable_new VAR_USER_GROUP_DELETE userGroupDelete
+f_variable_new VAR_USER_HOME userHome
+f_variable_new VAR_USER_HOME_CREATE userHomeCreate
+f_variable_new VAR_USER_HOME_DELETE userHomeDelete
+f_variable_new VAR_USER_LOGIN_CLASS userLoginClass
+f_variable_new VAR_USER_PASSWORD userPassword
+f_variable_new VAR_USER_PASSWORD_EXPIRE userPasswordExpire
+f_variable_new VAR_USER_SHELL userShell
+f_variable_new VAR_USER_UID userUid
+f_variable_new VAR_ZFSINTERACTIVE zfsInteractive
#
# Self-initialize unless requested otherwise