2cc6c69d05
`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').
1025 lines
32 KiB
Plaintext
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
|