freebsd-skq/usr.sbin/bsdconfig/share/device.subr
Devin Teske 2cc6c69d05 Improve network device scanning in the netdev module. First, make it use the
`device.subr' framework (improving performane and reducing sub-shells). Next
improve the `device.subr' framework itself. Make use of the `flags' device
struct member for network interfaces to indicate if an interface is Active,
Wired Ethernet, or 802.11 Wireless. Functions have been added to make checks
against the `flags' bit-field quick and efficient. Last, add function for
rescanning the network to update the device registers. Remove an unnecessary
local (ifn) while we're here (use already provided local `if').
2013-11-22 00:32:32 +00:00

1025 lines
32 KiB
Plaintext

if [ ! "$_DEVICE_SUBR" ]; then _DEVICE_SUBR=1
#
# Copyright (c) 2012-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..." device.subr
f_include $BSDCFG_SHARE/dialog.subr
f_include $BSDCFG_SHARE/strings.subr
f_include $BSDCFG_SHARE/struct.subr
BSDCFG_LIBE="/usr/libexec/bsdconfig"
f_include_lang $BSDCFG_LIBE/include/messages.subr
############################################################ GLOBALS
DEVICES=
DEVICE_NAMES=
# A "device" from sysinstall's point of view
f_struct_define DEVICE \
name \
desc \
devname \
type \
capacity \
enabled \
init \
get \
shutdown \
flags \
private \
volume
# Network devices have their `private' property set to this
f_struct_define DEVICE_INFO \
use_rtsol use_dhcp ipaddr ipv6addr netmask extras
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
# 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.
#
# Returns success if the device path exists and is a cdev.
#
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
}
# f_device_register $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).
#
# If not already registered, the device is then appended to the DEVICES
# environment variable, a space-separated list of all registered devices.
#
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 capacity="${10}"
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"
device_$name set capacity "$capacity"
# 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"
return $SUCCESS
}
# f_device_reset
#
# Reset the registered device chain.
#
f_device_reset()
{
local dev
for dev in $DEVICES; do
f_device_shutdown $dev
#
# 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
#
f_struct_free device_$dev
done
DEVICES=
}
# f_device_reset_network
#
# Reset the registered network device chain.
#
f_device_reset_network()
{
local dev type private pruned_list=
for dev in $DEVICES; do
device_$dev get type type
if [ "$type" != "$DEVICE_TYPE_NETWORK" ]; then
pruned_list="$pruned_list $dev"
continue
fi
#
# Leave the device up (don't call shutdown routine)
#
# Network devices may have DEVICE_INFO private member
device_$dev get private private
[ "$private" ] && f_struct_free "$private"
f_struct_free device_$dev
done
DEVICES="${pruned_list# }"
}
# f_device_get_all
#
# Get all device information for devices we have attached.
#
f_device_get_all()
{
local devname desc
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, try to find all the types of devices one might use
# as a media source for content
#
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
# ASIDE: This would be equivalent to the following:
# debug= f_device_name_get $dev desc
# debug= f_device_name_get $dev type
# debug= f_device_name_get $dev max
debug= f_getvar _device_desc$n desc
debug= f_getvar _device_type$n type
debug= f_getvar _device_max$n max
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_device_capacity "$devname" )"
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_device_capacity "$devname" )"
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_device_capacity "$devname" )"
f_dprintf "Found a USB disk for %s" "$devname"
;;
esac
done
done
# 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 \
f_media_init_cdrom f_media_get_cdrom \
f_media_shutdown_cdrom "" \
"$( f_device_capacity "$devname" )"
f_dprintf "Found a CDROM device for %s" "$devname"
done
# 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
# 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 \
f_media_init_cdrom f_media_get_cdrom \
f_media_shutdown_cdrom "" \
"$( f_device_capacity "$devname" )"
f_dprintf "Found a CDROM device for %s" "$devname"
;;
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
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 ;;
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
# Try and find its description
f_device_desc "$diskname" $DEVICE_TYPE_DISK desc
f_device_register "$diskname" "$desc" \
"/dev/$diskname" $DEVICE_TYPE_DISK 0 \
"" "" "" "" \
"$( f_device_capacity "$diskname" )"
f_dprintf "Found a disk device named %s" "$diskname"
# 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_device_capacity "/dev/$slice" )"
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_device_capacity \
"$/dev/$part" )"
f_dprintf "Found a UFS partition %s" \
"$part"
done # parts
;;
esac
done # slices
done # disks
}
# f_device_get_all_network
#
# Get all network device information for attached network devices.
#
f_device_get_all_network()
{
local devname desc flags
for devname in $( ifconfig -l ); do
# Eliminate network devices that don't make sense
case "$devname" in
lo*) continue ;;
esac
# 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 "" -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_$devname set flags $flags
done
}
# f_device_name_get $type $name type|desc|max [$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.
# 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
# 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()
{
local __type="$1" __name="$2" __prop="$3" __var_to_set="$4"
local __dev __devtype __n=0
# Return failure if no $name or $prop is an unknown property
[ "$__name" ] || return $FAILURE
case "$__prop" in type|desc|max) : good ;;
*) return $FAILURE; esac
#
# 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]}" __dname=
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" -o "$__dev" = "$__dname" ] || continue
f_getvar _device_type$__n __devtype
[ "${__type:-$__devtype}" = "$__devtype" ] || continue
f_getvar _device_$__prop$__n $__var_to_set
return $?
done
return $FAILURE
}
# f_device_name_set $type $name $desc [$max]
#
# 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.
#
f_device_name_set()
{
local type="$1" name="$2" desc="$3" max="$4"
local dev devtype n=0 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 ))
fi
setvar _device_type$n "$type"
setvar _device_desc$n "$desc"
[ "${4+set}" ] && setvar _device_max$n "$max"
return $SUCCESS
}
# f_device_desc $device_name $device_type [$var_to_set]
#
# Print a description for a device name (eg., `fxp0') given a specific device
# type/class.
#
# If $var_to_set is missing or NULL, the device description 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_desc()
{
local __name="$1" __type="$2" __var_to_set="$3"
local __devname __devunit __cp
# Check variables
[ "$__name" ] || return $SUCCESS
[ "$__type" = "$DEVICE_TYPE_ANY" ] && type=
[ "$__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.
#
if f_have sysctl; then
__devname="${__name%%[0-9]*}"
__devunit="${__name#$__devname}"
__devunit="${__devunit%%[!0-9]*}"
if [ "$__var_to_set" ]; then
if __cp=$(
sysctl -n "dev.$__devname.$__devunit.%desc" \
2> /dev/null
); then
setvar "$__var_to_set" "$__cp" &&
return $SUCCESS
fi
else
sysctl -n "dev.$__devname.$__devunit.%desc" \
2> /dev/null && return $SUCCESS
fi
fi
#
# For disks, attempt to return camcontrol(8) descriptions.
# Otherwise fall through to below static list.
#
f_have camcontrol &&
[ "${__type:-$DEVICE_TYPE_DISK}" = "$DEVICE_TYPE_DISK" ] &&
__cp=$( camcontrol devlist 2> /dev/null | awk -v disk="$__name" '
$0~"(\\(|,)"disk"(,|\\))" {
if (!match($0, "<[^>]+>")) next
print substr($0, RSTART+1, RLENGTH-2)
found = 1
exit
}
END { exit ! found }
' ) && setvar "$__var_to_set" "$__cp" && return $SUCCESS
#
# 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]}" __dname=
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
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
[ "$__dev" = "$__name" -o "$__dev" = "$__dname" ] ||
continue
fi
debug= f_getvar _device_desc$__n $__var_to_set
return $?
done
#
# Sensible fall-backs for specific types
#
case "$__type" in
$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_NETWORK) __cp="<unknown network interface type>" ;;
*)
__cp="<unknown device type>"
esac
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" "$__cp"
else
echo "$__cp"
fi
return $FAILURE
}
# f_device_is_ethernet $device
#
# Returns true if $device is a wired Ethernet network interface. Otherwise
# returns false. Example wired interfaces include: fxp0 em0 bge0 rl0 etc.
#
f_device_is_ethernet()
{
local dev="$1" type flags
# Make sure we have an actual device by that name
f_struct "device_$dev" || return $FAILURE
# Make sure that the device is a network device
device_$dev get type type
[ "$type" = "$DEVICE_TYPE_NETWORK" ] || return $FAILURE
# Make sure that the media flags indicate that it is Ethernet
device_$dev get flags flags
[ $(( ${flags:-0} & $IF_ETHERNET )) -eq $IF_ETHERNET ]
}
# 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 "device_$dev" || return $FAILURE
# Make sure that the device is a network device
device_$dev get type type
[ "$type" = "$DEVICE_TYPE_NETWORK" ] || return $FAILURE
# Make sure that the media flags indicate that it is Ethernet
device_$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 "device_$dev" || return $FAILURE
device_$dev get type type
case "$type" in
$DEVICE_TYPE_NETWORK)
# Make sure that the media flags indicate that it is active
device_$dev get flags flags
[ $(( ${flags:-0} & $IF_ACTIVE )) -eq $IF_ACTIVE ]
;;
*)
return $FAILURE
esac
}
# f_device_rescan
#
# Rescan all devices, after closing previous set - convenience function.
#
f_device_rescan()
{
f_device_reset
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_find $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 $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 __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
if [ "$__name" = "$__devname" -o ! "$__name" ] &&
[ "$__type" = "$DEVICE_TYPE_ANY" -o \
"$__type" = "$__devtype" ]
then
__found="$__found $__dev"
fi
done
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" "${__found# }"
else
echo $__found
fi
[ "$__found" ] # Return status
}
# f_device_init $name
#
# Initialize a device by evaluating its `init' function.
#
f_device_init()
{
local name="$1" init_func
device_$name get init init_func || return $?
${init_func:-:} $name
}
# f_device_get $name $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).
#
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"}
}
# f_device_shutdown $name
#
# Shutdown a device by evaluating its `shutdown' function.
#
f_device_shutdown()
{
local name="$1" shutdown_func
device_$name get shutdown shutdown_func || return $?
${shutdown_func:-:} $name
}
# f_device_menu $title $prompt $hline $device_type [$helpfile]
#
# Display a menu listing all the devices of a certain type in the system.
#
f_device_menu()
{
f_dialog_title "$1"
local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
f_dialog_title_restore
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 desc menu_list=
for dev in $devs; do
device_$dev get desc desc
f_shell_escape "$desc" desc
menu_list="$menu_list '$dev' '$desc'"
done
local height width rows
eval f_dialog_menu_size height width rows \
\"\$title\" \
\"\$btitle\" \
\"\$prompt\" \
\"\$hline\" \
$menu_list
local errexit=
case $- in *e*) errexit=1; esac
set +e
local mtag
while :; do
mtag=$( eval $DIALOG \
--title \"\$title\" \
--backtitle \"\$btitle\" \
--ok-label \"\$msg_ok\" \
--cancel-label \"\$msg_cancel\" \
${helpfile:+ \
--help-button \
--help-label \"\$msg_help\" \
${USE_XDIALOG:+--help \"\"} \
} \
--menu \"\$prompt\" \
$height $width $rows \
$menu_list \
2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
)
local retval=$?
[ $retval -ne $DIALOG_HELP ] && break
# Otherwise, the Help button was pressed
f_show_help "$helpfile"
# ...then loop back to menu
done
f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
[ "$errexit" ] && set -e
if [ $retval -eq $DIALOG_OK ]; then
# Clean up the output of [X]dialog(1) and return it
f_dialog_data_sanitize mtag
echo "$mtag" >&2
fi
return $retval
}
# f_device_capacity $device [$var_to_set]
#
# Return the capacity of $device in bytes.
#
f_device_capacity()
{
local __dev="$1" __var_to_set="$2"
local __bytes
__bytes=$( diskinfo -v "$__dev" 2> /dev/null |
awk '/# mediasize in bytes/{print $1}' ) || __bytes=-1
if [ "$__var_to_set" ]; then
setvar "$__var_to_set" "$__bytes"
else
echo "$__bytes"
fi
}
#
# 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"; }
############################################################ 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_disk "vtbd%d" "VirtIO Block Device" 16
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
# 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_dprintf "%s: Initialized %u known device names/descriptions." device.subr \
"$( set -- $DEVICE_NAMES; echo $# )"
#
# Scan for the above devices unless requeted otherwise
#
f_dprintf "%s: DEVICE_SELF_SCAN_ALL=[%s]" device.subr "$DEVICE_SELF_SCAN_ALL"
case "$DEVICE_SELF_SCAN_ALL" in
""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
*) f_device_get_all
esac
f_dprintf "%s: Successfully loaded." device.subr
fi # ! $_DEVICE_SUBR