xref: /freebsd/usr.sbin/bsdconfig/share/device.subr (revision 77e93191b92eed7842f56154eed1d1d0519dd65c)
17323adacSDevin Teskeif [ ! "$_DEVICE_SUBR" ]; then _DEVICE_SUBR=1
27323adacSDevin Teske#
357ef9b75SDevin Teske# Copyright (c) 2012-2016 Devin Teske
4f8ea072aSDevin Teske# All rights reserved.
57323adacSDevin Teske#
67323adacSDevin Teske# Redistribution and use in source and binary forms, with or without
77323adacSDevin Teske# modification, are permitted provided that the following conditions
87323adacSDevin Teske# are met:
97323adacSDevin Teske# 1. Redistributions of source code must retain the above copyright
107323adacSDevin Teske#    notice, this list of conditions and the following disclaimer.
117323adacSDevin Teske# 2. Redistributions in binary form must reproduce the above copyright
127323adacSDevin Teske#    notice, this list of conditions and the following disclaimer in the
137323adacSDevin Teske#    documentation and/or other materials provided with the distribution.
147323adacSDevin Teske#
157323adacSDevin Teske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
168e37a7c8SDevin Teske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
177323adacSDevin Teske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
187323adacSDevin Teske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
197323adacSDevin Teske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
208e37a7c8SDevin Teske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
217323adacSDevin Teske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
227323adacSDevin Teske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
237323adacSDevin Teske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
247323adacSDevin Teske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
257323adacSDevin Teske# SUCH DAMAGE.
267323adacSDevin Teske#
277323adacSDevin Teske#
287323adacSDevin Teske############################################################ INCLUDES
297323adacSDevin Teske
307323adacSDevin TeskeBSDCFG_SHARE="/usr/share/bsdconfig"
317323adacSDevin Teske. $BSDCFG_SHARE/common.subr || exit 1
327323adacSDevin Teskef_dprintf "%s: loading includes..." device.subr
337323adacSDevin Teskef_include $BSDCFG_SHARE/dialog.subr
349ecd54f2SDevin Teskef_include $BSDCFG_SHARE/geom.subr
357323adacSDevin Teskef_include $BSDCFG_SHARE/strings.subr
367323adacSDevin Teskef_include $BSDCFG_SHARE/struct.subr
377323adacSDevin Teske
387323adacSDevin TeskeBSDCFG_LIBE="/usr/libexec/bsdconfig"
397323adacSDevin Teskef_include_lang $BSDCFG_LIBE/include/messages.subr
407323adacSDevin Teske
417323adacSDevin Teske############################################################ GLOBALS
427323adacSDevin Teske
439ecd54f2SDevin TeskeNDEVICES=0 # Set by f_device_register(), used by f_device_*()
447323adacSDevin Teske
459ecd54f2SDevin Teske#
469ecd54f2SDevin Teske# A "device" from legacy sysinstall's point of view (mostly)
479ecd54f2SDevin Teske#
489ecd54f2SDevin Teske# NB: Disk devices have their `private' property set to GEOM ident
499ecd54f2SDevin Teske# NB: USB devices have their `private' property set to USB disk device name
509ecd54f2SDevin Teske#
517323adacSDevin Teskef_struct_define DEVICE \
529ecd54f2SDevin Teske	capacity	\
537323adacSDevin Teske	desc		\
547323adacSDevin Teske	devname		\
557323adacSDevin Teske	enabled		\
567323adacSDevin Teske	flags		\
579ecd54f2SDevin Teske	get		\
589ecd54f2SDevin Teske	init		\
599ecd54f2SDevin Teske	name		\
607323adacSDevin Teske	private		\
619ecd54f2SDevin Teske	shutdown	\
629ecd54f2SDevin Teske	type		\
637323adacSDevin Teske	volume
647323adacSDevin Teske
657323adacSDevin Teske# Network devices have their `private' property set to this
667323adacSDevin Teskef_struct_define DEVICE_INFO \
679ecd54f2SDevin Teske	extras		\
689ecd54f2SDevin Teske	ipaddr		\
699ecd54f2SDevin Teske	ipv6addr	\
709ecd54f2SDevin Teske	netmask		\
719ecd54f2SDevin Teske	use_dhcp	\
729ecd54f2SDevin Teske	use_rtsol
737323adacSDevin Teske
749ecd54f2SDevin Teske#
759ecd54f2SDevin Teske# Device types for f_device_register(), f_device_find(), et al.
769ecd54f2SDevin Teske#
779ecd54f2SDevin Teskesetvar DEVICE_TYPE_ANY		"any"		# Any
789ecd54f2SDevin Teskesetvar DEVICE_TYPE_NONE		"NONE"		# Unknown
799ecd54f2SDevin Teskesetvar DEVICE_TYPE_DISK		"DISK"		# GEOM `DISK'
809ecd54f2SDevin Teskesetvar DEVICE_TYPE_FTP		"FTP"		# Dynamic network device
819ecd54f2SDevin Teskesetvar DEVICE_TYPE_NETWORK	"NETWORK"	# See f_device_get_all_network
829ecd54f2SDevin Teskesetvar DEVICE_TYPE_CDROM	"CDROM"		# GEOM `DISK'
839ecd54f2SDevin Teskesetvar DEVICE_TYPE_USB		"USB"		# GEOM `PART'
849ecd54f2SDevin Teskesetvar DEVICE_TYPE_DOS		"DOS"		# GEOM `DISK' `PART' or `LABEL'
859ecd54f2SDevin Teskesetvar DEVICE_TYPE_UFS		"UFS"		# GEOM `DISK' `PART' or `LABEL'
869ecd54f2SDevin Teskesetvar DEVICE_TYPE_NFS		"NFS"		# Dynamic network device
879ecd54f2SDevin Teskesetvar DEVICE_TYPE_HTTP_PROXY	"HTTP_PROXY"	# Dynamic network device
889ecd54f2SDevin Teskesetvar DEVICE_TYPE_HTTP		"HTTP"		# Dynamic network device
897323adacSDevin Teske
902cc6c69dSDevin Teske# Network devices have the following flags available
912cc6c69dSDevin Teskesetvar IF_ETHERNET	1
922cc6c69dSDevin Teskesetvar IF_WIRELESS	2
932cc6c69dSDevin Teskesetvar IF_ACTIVE	4
942cc6c69dSDevin Teske
957323adacSDevin Teske#
967323adacSDevin Teske# Default behavior is to call f_device_get_all() automatically when loaded.
977323adacSDevin Teske#
987323adacSDevin Teske: ${DEVICE_SELF_SCAN_ALL=1}
997323adacSDevin Teske
1009ecd54f2SDevin Teske#
1019ecd54f2SDevin Teske# Device Catalog variables
1029ecd54f2SDevin Teske#
1039ecd54f2SDevin TeskeDEVICE_CATALOG_APPEND_ONLY= # Used by f_device_catalog_set()
1049ecd54f2SDevin TeskeNCATALOG_DEVICES=0          # Used by f_device_catalog_*() and MAIN
1059ecd54f2SDevin Teske
1069ecd54f2SDevin Teske#
1079ecd54f2SDevin Teske# A ``catalog'' device is for mapping GEOM devices to media devices (for
1089ecd54f2SDevin Teske# example, determining if a $GEOM_CLASS_DISK geom is $DEVICE_TYPE_CDROM or
1099ecd54f2SDevin Teske# $DEVICE_TYPE_DISK) and also getting default descriptions for devices that
1109ecd54f2SDevin Teske# either lack a GEOM provided description or lack a presence in GEOM)
1119ecd54f2SDevin Teske#
1129ecd54f2SDevin Teskef_struct_define CATALOG_DEVICE \
1139ecd54f2SDevin Teske	desc	\
1149ecd54f2SDevin Teske	name	\
1159ecd54f2SDevin Teske	type
1169ecd54f2SDevin Teske
1177323adacSDevin Teske############################################################ FUNCTIONS
1187323adacSDevin Teske
1199ecd54f2SDevin Teske# f_device_register $var_to_set $name $desc $devname $type $enabled
1209ecd54f2SDevin Teske#                   $init_function $get_function $shutdown_function
1219ecd54f2SDevin Teske#                   $private $capacity
1227323adacSDevin Teske#
1239ecd54f2SDevin Teske# Register a device. A `structure' (see struct.subr) is created and if
1249ecd54f2SDevin Teske# $var_to_set is non-NULL, upon success holds the name of the struct created.
1259ecd54f2SDevin Teske# The remaining positional arguments correspond to the properties of the
1269ecd54f2SDevin Teske# `DEVICE' structure-type to be assigned (defined above).
1277323adacSDevin Teske#
1289ecd54f2SDevin Teske# If not already registered (based on $name and $type), a new device is created
1299ecd54f2SDevin Teske# and $NDEVICES is incremented.
1307323adacSDevin Teske#
1317323adacSDevin Teskef_device_register()
1327323adacSDevin Teske{
1339ecd54f2SDevin Teske	local __var_to_set="$1" __name="$2" __desc="$3" __devname="$4"
1349ecd54f2SDevin Teske	local __type="$5" __enabled="$6" __init_func="$7" __get_func="$8"
1359ecd54f2SDevin Teske	local __shutdown_func="$9" __private="${10}" __capacity="${11}"
1367323adacSDevin Teske
1379ecd54f2SDevin Teske	# Required parameter(s)
1389ecd54f2SDevin Teske	[ "$__name" ] || return $FAILURE
1399ecd54f2SDevin Teske	if [ "$__var_to_set" ]; then
1409ecd54f2SDevin Teske		setvar "$__var_to_set" "" || return $FAILURE
1419ecd54f2SDevin Teske	fi
1427323adacSDevin Teske
1439ecd54f2SDevin Teske	local __device
1449ecd54f2SDevin Teske	if f_device_find -1 "$__name" "$__type" __device; then
1459ecd54f2SDevin Teske		f_struct_free "$__device"
1469ecd54f2SDevin Teske		f_struct_new DEVICE "$__device" || return $FAILURE
1479ecd54f2SDevin Teske	else
1489ecd54f2SDevin Teske		__device=device_$(( NDEVICES + 1 ))
1499ecd54f2SDevin Teske		f_struct_new DEVICE "$__device" || return $FAILURE
1509ecd54f2SDevin Teske		NDEVICES=$(( $NDEVICES + 1 ))
1519ecd54f2SDevin Teske	fi
1529ecd54f2SDevin Teske	$__device set name     "$__name"
1539ecd54f2SDevin Teske	$__device set desc     "$__desc"
1549ecd54f2SDevin Teske	$__device set devname  "$__devname"
1559ecd54f2SDevin Teske	$__device set type     "$__type"
1569ecd54f2SDevin Teske	$__device set enabled  "$__enabled"
1579ecd54f2SDevin Teske	$__device set init     "$__init_func"
1589ecd54f2SDevin Teske	$__device set get      "$__get_func"
1599ecd54f2SDevin Teske	$__device set shutdown "$__shutdown_func"
1609ecd54f2SDevin Teske	$__device set private  "$__private"
1619ecd54f2SDevin Teske	$__device set capacity "$__capacity"
1627323adacSDevin Teske
1639ecd54f2SDevin Teske	[ "$__var_to_set" ] && setvar "$__var_to_set" "$__device"
1647323adacSDevin Teske	return $SUCCESS
1657323adacSDevin Teske}
1667323adacSDevin Teske
1677323adacSDevin Teske# f_device_reset
1687323adacSDevin Teske#
1697323adacSDevin Teske# Reset the registered device chain.
1707323adacSDevin Teske#
1717323adacSDevin Teskef_device_reset()
1727323adacSDevin Teske{
1739ecd54f2SDevin Teske	local n=1
1749ecd54f2SDevin Teske	while [ $n -le $NDEVICES ]; do
1759ecd54f2SDevin Teske		f_device_shutdown device_$n
1767323adacSDevin Teske
1779ecd54f2SDevin Teske		#
17896f88f0fSDevin Teske		# XXX This potentially leaks $dev->private if it's being
1797323adacSDevin Teske		# used to point to something dynamic, but you're not supposed
1807323adacSDevin Teske		# to call this routine at such times that some open instance
18196f88f0fSDevin Teske		# has its private member pointing somewhere anyway.
1827323adacSDevin Teske		#
1839ecd54f2SDevin Teske		f_struct_free device_$n
1849ecd54f2SDevin Teske
1859ecd54f2SDevin Teske		n=$(( $n + 1 ))
1867323adacSDevin Teske	done
1879ecd54f2SDevin Teske	NDEVICES=0
1887323adacSDevin Teske}
1897323adacSDevin Teske
1902cc6c69dSDevin Teske# f_device_reset_network
1912cc6c69dSDevin Teske#
1922cc6c69dSDevin Teske# Reset the registered network device chain.
1932cc6c69dSDevin Teske#
1942cc6c69dSDevin Teskef_device_reset_network()
1952cc6c69dSDevin Teske{
1969ecd54f2SDevin Teske	local n=1 device type private i
1979ecd54f2SDevin Teske	while [ $n -le $NDEVICES ]; do
1989ecd54f2SDevin Teske		device=device_$n
1999ecd54f2SDevin Teske		f_struct $device || continue
2009ecd54f2SDevin Teske		$device get type type
2019ecd54f2SDevin Teske		[ "$type" = "$DEVICE_TYPE_NETWORK" ] || continue
2022cc6c69dSDevin Teske
2032cc6c69dSDevin Teske		#
2042cc6c69dSDevin Teske		# Leave the device up (don't call shutdown routine)
2052cc6c69dSDevin Teske		#
2062cc6c69dSDevin Teske
2072cc6c69dSDevin Teske		# Network devices may have DEVICE_INFO private member
2089ecd54f2SDevin Teske		$device get private private
2092cc6c69dSDevin Teske		[ "$private" ] && f_struct_free "$private"
2102cc6c69dSDevin Teske
2119ecd54f2SDevin Teske		# Free the network device
2129ecd54f2SDevin Teske		f_struct_free $device
2139ecd54f2SDevin Teske
2149ecd54f2SDevin Teske		# Fill the gap we just created
2159ecd54f2SDevin Teske		i=$n
2169ecd54f2SDevin Teske		while [ $i -lt $NDEVICES ]; do
2179ecd54f2SDevin Teske			f_struct_copy device_$(( $i + 1 )) device_$i
2182cc6c69dSDevin Teske		done
2199ecd54f2SDevin Teske		f_struct_free device_$NDEVICES
2209ecd54f2SDevin Teske
2219ecd54f2SDevin Teske		# Finally decrement the number of devices
2229ecd54f2SDevin Teske		NDEVICES=$(( $NDEVICES - 1 ))
2239ecd54f2SDevin Teske
2249ecd54f2SDevin Teske		n=$(( $n + 1 ))
2259ecd54f2SDevin Teske	done
2262cc6c69dSDevin Teske}
2272cc6c69dSDevin Teske
2287323adacSDevin Teske# f_device_get_all
2297323adacSDevin Teske#
2309ecd54f2SDevin Teske# Get all device information for all devices.
2317323adacSDevin Teske#
2327323adacSDevin Teskef_device_get_all()
2337323adacSDevin Teske{
2349ecd54f2SDevin Teske	local devname type desc capacity
2357323adacSDevin Teske
2367323adacSDevin Teske	f_dprintf "f_device_get_all: Probing devices..."
2377323adacSDevin Teske	f_dialog_info "$msg_probing_devices_please_wait_this_can_take_a_while"
2387323adacSDevin Teske
2397323adacSDevin Teske	# First go for the network interfaces
2402cc6c69dSDevin Teske	f_device_get_all_network
2417323adacSDevin Teske
2429ecd54f2SDevin Teske	# Next, go for the GEOM devices we might want to use as media
2439ecd54f2SDevin Teske	local geom geoms geom_name
2449ecd54f2SDevin Teske	debug= f_geom_find "" $GEOM_CLASS_DEV geoms
2459ecd54f2SDevin Teske	for geom in $geoms; do
2469ecd54f2SDevin Teske		if ! f_device_probe_geom $geom; then
2479ecd54f2SDevin Teske			debug= $geom get name geom_name
2489ecd54f2SDevin Teske			f_dprintf "WARNING! Unable to classify %s as %s" \
2499ecd54f2SDevin Teske			          "GEOM device $geom_name" "media source"
2507323adacSDevin Teske		fi
2519ecd54f2SDevin Teske	done
2527323adacSDevin Teske}
2537323adacSDevin Teske
2542cc6c69dSDevin Teske# f_device_get_all_network
2552cc6c69dSDevin Teske#
2562cc6c69dSDevin Teske# Get all network device information for attached network devices.
2572cc6c69dSDevin Teske#
2582cc6c69dSDevin Teskef_device_get_all_network()
2592cc6c69dSDevin Teske{
2609ecd54f2SDevin Teske	local devname desc device flags
2612cc6c69dSDevin Teske	for devname in $( ifconfig -l ); do
2622cc6c69dSDevin Teske		# Eliminate network devices that don't make sense
2632cc6c69dSDevin Teske		case "$devname" in
2642cc6c69dSDevin Teske		lo*) continue ;;
2652cc6c69dSDevin Teske		esac
2662cc6c69dSDevin Teske
2672cc6c69dSDevin Teske		# Try and find its description
2682cc6c69dSDevin Teske		f_device_desc "$devname" $DEVICE_TYPE_NETWORK desc
2692cc6c69dSDevin Teske
2709ecd54f2SDevin Teske		f_dprintf "Found network device named %s" "$devname"
2719ecd54f2SDevin Teske		debug= f_device_register device $devname "$desc" \
2729ecd54f2SDevin Teske			"$devname" $DEVICE_TYPE_NETWORK 1 \
2732cc6c69dSDevin Teske			f_media_init_network "" f_media_shutdown_network "" -1
2742cc6c69dSDevin Teske
2752cc6c69dSDevin Teske		# Set flags based on media and status
2762cc6c69dSDevin Teske		flags=0
2772cc6c69dSDevin Teske		eval "$( ifconfig $devname 2> /dev/null | awk -v var=flags '
2782cc6c69dSDevin Teske		function _or(var, mask) {
2792cc6c69dSDevin Teske			printf "%s=$(( $%s | $%s ))\n", var, var, mask
2802cc6c69dSDevin Teske		}
2812cc6c69dSDevin Teske		BEGIN { S = "[[:space:]]+" }
2822cc6c69dSDevin Teske		{
2832cc6c69dSDevin Teske			if (!match($0, "^" S "(media|status):" S)) next
2842cc6c69dSDevin Teske			value = substr($0, RLENGTH + 1)
2852cc6c69dSDevin Teske			if ($1 == "media:") {
2862cc6c69dSDevin Teske				if (value ~ /Ethernet/) _or(var, "IF_ETHERNET")
2872cc6c69dSDevin Teske				if (value ~ /802\.11/) _or(var, "IF_WIRELESS")
2882cc6c69dSDevin Teske			} else if ($1 == "status:") {
2892cc6c69dSDevin Teske				if (value ~ /^active/) _or(var, "IF_ACTIVE")
2902cc6c69dSDevin Teske			}
2912cc6c69dSDevin Teske		}' )"
2929ecd54f2SDevin Teske		$device set flags $flags
2932cc6c69dSDevin Teske	done
2942cc6c69dSDevin Teske}
2952cc6c69dSDevin Teske
2969ecd54f2SDevin Teske# f_device_rescan
2977323adacSDevin Teske#
2989ecd54f2SDevin Teske# Rescan all devices, after closing previous set - convenience function.
2999ecd54f2SDevin Teske#
3009ecd54f2SDevin Teskef_device_rescan()
3019ecd54f2SDevin Teske{
3029ecd54f2SDevin Teske	f_device_reset
3039ecd54f2SDevin Teske	f_geom_rescan
3049ecd54f2SDevin Teske	f_device_get_all
3059ecd54f2SDevin Teske}
3069ecd54f2SDevin Teske
3079ecd54f2SDevin Teske# f_device_rescan_network
3089ecd54f2SDevin Teske#
3099ecd54f2SDevin Teske# Rescan all network devices, after closing previous set - for convenience.
3109ecd54f2SDevin Teske#
3119ecd54f2SDevin Teskef_device_rescan_network()
3129ecd54f2SDevin Teske{
3139ecd54f2SDevin Teske	f_device_reset_network
3149ecd54f2SDevin Teske	f_device_get_all_network
3159ecd54f2SDevin Teske}
3169ecd54f2SDevin Teske
3179ecd54f2SDevin Teske# f_device_probe_geom $geom
3189ecd54f2SDevin Teske#
3199ecd54f2SDevin Teske# Probe a single GEOM device and if it can be classified as a media source,
3209ecd54f2SDevin Teske# register it using f_device_register() with known type-specific arguments.
3219ecd54f2SDevin Teske#
3229ecd54f2SDevin Teskef_device_probe_geom()
3239ecd54f2SDevin Teske{
3249ecd54f2SDevin Teske	local geom="$1"
3259ecd54f2SDevin Teske
3269ecd54f2SDevin Teske	f_struct "$geom" || return $FAILURE
3279ecd54f2SDevin Teske
3289ecd54f2SDevin Teske	# geom associated variables
3299ecd54f2SDevin Teske	local geom_name geom_consumer provider_ref geom_provider=
3309ecd54f2SDevin Teske	local provider_geom provider_config provider_class=
3319ecd54f2SDevin Teske	local provider_config_type catalog_struct catalog_type
3329ecd54f2SDevin Teske	local disk_ident
3339ecd54f2SDevin Teske
3349ecd54f2SDevin Teske	# gnop(8)/geli(8) associated variables (p for `parent device')
3359ecd54f2SDevin Teske	local p_devname p_geom p_consumer p_provider_ref p_provider
3369ecd54f2SDevin Teske	local p_provider_config p_provider_geom p_provider_class
3379ecd54f2SDevin Teske
3389ecd54f2SDevin Teske	# md(4) associated variables
3399ecd54f2SDevin Teske	local config config_type config_file magic=
3409ecd54f2SDevin Teske
3419ecd54f2SDevin Teske	# Temporarily disable debugging to keep debug output light
3429ecd54f2SDevin Teske	local old_debug="$debug" debug=
3439ecd54f2SDevin Teske
3449ecd54f2SDevin Teske	#
3459ecd54f2SDevin Teske	# Get the GEOM name (for use below in device registration)
3469ecd54f2SDevin Teske	#
3479ecd54f2SDevin Teske	$geom get name devname || continue
3489ecd54f2SDevin Teske
3499ecd54f2SDevin Teske	#
3509ecd54f2SDevin Teske	# Attempt to get the consumer, provider, provider config, and
3519ecd54f2SDevin Teske	# provider class for this geom (errors ignored).
3529ecd54f2SDevin Teske	#
3539ecd54f2SDevin Teske	# NB: Each GEOM in the `DEV' class should have one consumer.
3549ecd54f2SDevin Teske	#     That consumer should have a reference to its provider.
3559ecd54f2SDevin Teske	#
3569ecd54f2SDevin Teske	$geom get consumer1 geom_consumer
3579ecd54f2SDevin Teske	f_struct "$geom_consumer" get provider_ref provider_ref &&
3589ecd54f2SDevin Teske		f_geom_find_by id "$provider_ref" provider geom_provider
3599ecd54f2SDevin Teske	if f_struct "$geom_provider"; then
3609ecd54f2SDevin Teske		$geom_provider get config provider_config
3619ecd54f2SDevin Teske		f_geom_parent $geom_provider provider_geom &&
3629ecd54f2SDevin Teske			f_geom_parent $provider_geom provider_class
3639ecd54f2SDevin Teske	fi
3649ecd54f2SDevin Teske
3659ecd54f2SDevin Teske	#
3669ecd54f2SDevin Teske	# Get values for device registration (errors ignored)
3679ecd54f2SDevin Teske	#
3689ecd54f2SDevin Teske	f_struct "$provider_class"  get name      type
3699ecd54f2SDevin Teske	f_struct "$geom_provider"   get mediasize capacity
3709ecd54f2SDevin Teske	f_struct "$provider_config" get descr     desc
3719ecd54f2SDevin Teske
3729ecd54f2SDevin Teske	#
3739ecd54f2SDevin Teske	# For gnop(8), geli(8), or combination thereof, change device type to
3749ecd54f2SDevin Teske	# that of the consumer
3759ecd54f2SDevin Teske	#
3769ecd54f2SDevin Teske	p_devname= p_geom= p_provider= p_provider_config=
3779ecd54f2SDevin Teske	case "$devname" in
3789ecd54f2SDevin Teske	*.nop.eli) p_devname="${devname%.nop.eli}" ;;
3799ecd54f2SDevin Teske	*.eli.nop) p_devname="${devname%.eli.nop}" ;;
3809ecd54f2SDevin Teske	*.eli)     p_devname="${devname%.eli}" ;;
3819ecd54f2SDevin Teske	*.nop)     p_devname="${devname%.nop}" ;;
3829ecd54f2SDevin Teske	esac
3839ecd54f2SDevin Teske	[ "$p_devname" ] && f_geom_find "$p_devname" $GEOM_CLASS_DEV p_geom
3849ecd54f2SDevin Teske	if [ "${p_geom:-$geom}" != "$geom" ]; then
3859ecd54f2SDevin Teske		f_struct "$p_geom" get consumer1 p_consumer
3869ecd54f2SDevin Teske		f_struct "$p_consumer" get provider_ref p_provider_ref &&
3879ecd54f2SDevin Teske			f_geom_find_by id "$p_provider_ref" provider p_provider
3889ecd54f2SDevin Teske		if f_struct "$p_provider"; then
3899ecd54f2SDevin Teske			$p_provider get config p_provider_config
3909ecd54f2SDevin Teske			f_geom_parent $p_provider p_provider_geom &&
3919ecd54f2SDevin Teske				f_geom_parent $p_provider_geom p_provider_class
3929ecd54f2SDevin Teske		fi
3939ecd54f2SDevin Teske		f_struct "$p_provider_class" get name type
3949ecd54f2SDevin Teske	fi
3959ecd54f2SDevin Teske
3969ecd54f2SDevin Teske	# Look up geom device in device catalog for default description
3979ecd54f2SDevin Teske	f_device_catalog_get \
3989ecd54f2SDevin Teske		$DEVICE_TYPE_ANY "${p_devname:-$devname}" catalog_struct
3999ecd54f2SDevin Teske	[ "$desc" ] || f_struct "catalog_device_$catalog_struct" get desc desc
4009ecd54f2SDevin Teske
4019ecd54f2SDevin Teske	# Use device catalog entry for potential re-classification(s)
4029ecd54f2SDevin Teske	f_struct "catalog_device_$catalog_struct" get type catalog_type
4039ecd54f2SDevin Teske
4049ecd54f2SDevin Teske	# Restore debugging for this next part (device registration)
4059ecd54f2SDevin Teske	debug="$old_debug"
4069ecd54f2SDevin Teske
4079ecd54f2SDevin Teske	#
4089ecd54f2SDevin Teske	# Register the device
4099ecd54f2SDevin Teske	#
4109ecd54f2SDevin Teske	local retval device
4119ecd54f2SDevin Teske	case "$type" in
4129ecd54f2SDevin Teske	$GEOM_CLASS_DISK)
4139ecd54f2SDevin Teske		# First attempt to classify by device catalog (see MAIN)
4149ecd54f2SDevin Teske		case "$catalog_type" in
4159ecd54f2SDevin Teske		$DEVICE_TYPE_CDROM)
4169ecd54f2SDevin Teske			f_dprintf "Found CDROM device for disk %s" "$devname"
4179ecd54f2SDevin Teske			debug= f_device_register device "$devname" "$desc" \
4189ecd54f2SDevin Teske				"/dev/$devname" $DEVICE_TYPE_CDROM 1 \
4199ecd54f2SDevin Teske				f_media_init_cdrom f_media_get_cdrom \
4209ecd54f2SDevin Teske				f_media_shutdown_cdrom "" "$capacity" &&
4219ecd54f2SDevin Teske				return $SUCCESS
4229ecd54f2SDevin Teske			;;
4239ecd54f2SDevin Teske		esac
4249ecd54f2SDevin Teske
4259ecd54f2SDevin Teske		# Fall back to register label device as a disk and taste it
4269ecd54f2SDevin Teske		f_dprintf "Found disk device named %s" "$devname"
4279ecd54f2SDevin Teske		debug= f_struct "$p_provider_config" get \
4289ecd54f2SDevin Teske			ident disk_ident ||
4299ecd54f2SDevin Teske			debug= f_struct "$provider_config" get \
4309ecd54f2SDevin Teske				ident disk_ident
4319ecd54f2SDevin Teske		debug= f_device_register device "$devname" "$desc" \
4329ecd54f2SDevin Teske			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
4339ecd54f2SDevin Teske			"" "" "" "$disk_ident" "$capacity"
4349ecd54f2SDevin Teske		retval=$?
4359ecd54f2SDevin Teske
4369ecd54f2SDevin Teske		# Detect ``dangerously dedicated'' filesystems (errors ignored)
4379ecd54f2SDevin Teske		f_device_probe_disk_fs device "$devname" "$capacity" &&
4389ecd54f2SDevin Teske			retval=$SUCCESS
4399ecd54f2SDevin Teske
4409ecd54f2SDevin Teske		return $retval
4419ecd54f2SDevin Teske		;;
4429ecd54f2SDevin Teske	$GEOM_CLASS_LABEL)
4439ecd54f2SDevin Teske		: fall through to below section # reduces indentation level
4449ecd54f2SDevin Teske		;;
4459ecd54f2SDevin Teske	$GEOM_CLASS_MD)
4469ecd54f2SDevin Teske		f_dprintf "Found disk device named %s" "$devname"
4479ecd54f2SDevin Teske		debug= f_device_register device "$devname" "$desc" \
4489ecd54f2SDevin Teske			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
4499ecd54f2SDevin Teske			"" "" "" "" "$capacity"
4509ecd54f2SDevin Teske		retval=$?
4519ecd54f2SDevin Teske
4529ecd54f2SDevin Teske		#
4539ecd54f2SDevin Teske		# Attempt to get file(1) magic to potentially classify as
4549ecd54f2SDevin Teske		# alternate media type. If unable to get magic, fall back to
4559ecd54f2SDevin Teske		# md(4) characteristics (such as vnode filename).
4569ecd54f2SDevin Teske		#
4579ecd54f2SDevin Teske		[ -r "/dev/$devname" ] &&
4589ecd54f2SDevin Teske			magic=$( file -bs "/dev/$devname" 2> /dev/null )
4599ecd54f2SDevin Teske		if [ ! "$magic" ]; then
4609ecd54f2SDevin Teske			# Fall back to md(4) characteristics
4619ecd54f2SDevin Teske			if f_struct "$p_provider_config"; then
4629ecd54f2SDevin Teske				config="$p_provider_config"
4639ecd54f2SDevin Teske			else
4649ecd54f2SDevin Teske				config="$provider_config"
4659ecd54f2SDevin Teske			fi
4669ecd54f2SDevin Teske			debug= f_struct "$config" get type config_type
4679ecd54f2SDevin Teske			debug= f_struct "$config" get file config_file
4689ecd54f2SDevin Teske
4699ecd54f2SDevin Teske			# Substitute magic for below based on type and file
4709ecd54f2SDevin Teske			case "$config_type=$config_file" in
4719ecd54f2SDevin Teske			vnode=*.iso) magic="ISO 9660" ;;
4729ecd54f2SDevin Teske			esac
4739ecd54f2SDevin Teske		fi
4749ecd54f2SDevin Teske		f_device_probe_disk_fs device \
4759ecd54f2SDevin Teske			"$devname" "$capacity" "$magic" &&
4769ecd54f2SDevin Teske			retval=$SUCCESS # Errors ignored
4779ecd54f2SDevin Teske
4789ecd54f2SDevin Teske		return $retval
4799ecd54f2SDevin Teske		;;
4809ecd54f2SDevin Teske	$GEOM_CLASS_PART)
4819ecd54f2SDevin Teske		if f_struct "$p_provider_config"; then
4829ecd54f2SDevin Teske			config="$p_provider_config"
4839ecd54f2SDevin Teske		else
4849ecd54f2SDevin Teske			config="$provider_config"
4859ecd54f2SDevin Teske		fi
4869ecd54f2SDevin Teske		debug= f_struct "$config" get type provider_config_type
4879ecd54f2SDevin Teske		f_device_probe_geom_part device \
4889ecd54f2SDevin Teske			"$provider_config_type" "$devname" "$capacity"
4899ecd54f2SDevin Teske		retval=$?
4909ecd54f2SDevin Teske		device_type=$DEVICE_TYPE_NONE
4919ecd54f2SDevin Teske		[ $retval -eq $SUCCESS ] &&
4929ecd54f2SDevin Teske			debug= f_struct "$device" get type device_type
4939ecd54f2SDevin Teske
4949ecd54f2SDevin Teske		# Potentially re-classify as USB device
4959ecd54f2SDevin Teske		if [ "$device_type" = "$DEVICE_TYPE_UFS" -a \
4969ecd54f2SDevin Teske		     "$catalog_type" = "$DEVICE_TYPE_USB" ]
4979ecd54f2SDevin Teske		then
4989ecd54f2SDevin Teske			f_dprintf "Found USB device for partition %s" \
4999ecd54f2SDevin Teske				  "$devname"
5009ecd54f2SDevin Teske			debug= f_struct "$p_provider_geom" get \
5019ecd54f2SDevin Teske				name disk_name ||
5029ecd54f2SDevin Teske				debug= f_struct "$provider_geom" get \
5039ecd54f2SDevin Teske					name disk_name
5049ecd54f2SDevin Teske			debug= f_device_register device "$devname" "$desc" \
5059ecd54f2SDevin Teske				"/dev/$devname" $DEVICE_TYPE_USB 1 \
5069ecd54f2SDevin Teske				f_media_init_usb f_media_get_usb \
5079ecd54f2SDevin Teske				f_media_shutdown_usb "$disk_name" "$capacity"
5089ecd54f2SDevin Teske			retval=$?
5099ecd54f2SDevin Teske		fi
5109ecd54f2SDevin Teske
5119ecd54f2SDevin Teske		return $retval
5129ecd54f2SDevin Teske		;;
5139ecd54f2SDevin Teske	$GEOM_CLASS_RAID)
5149ecd54f2SDevin Teske		# Use the provider geom name as the description
5159ecd54f2SDevin Teske		if [ ! "$desc" ]; then
5169ecd54f2SDevin Teske			f_struct "$p_provider_geom" get name desc ||
5179ecd54f2SDevin Teske				f_struct "$provider_geom" get name desc
5189ecd54f2SDevin Teske		fi
5199ecd54f2SDevin Teske
5209ecd54f2SDevin Teske		f_dprintf "Found disk device named %s" "$devname"
5219ecd54f2SDevin Teske		debug= f_device_register device \
5229ecd54f2SDevin Teske			"$devname" "${desc:-GEOM RAID device}" \
5239ecd54f2SDevin Teske			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
5249ecd54f2SDevin Teske			"" "" "" "" "$capacity"
5259ecd54f2SDevin Teske		retval=$?
5269ecd54f2SDevin Teske
5279ecd54f2SDevin Teske		# Detect ``dangerously dedicated'' filesystems
5289ecd54f2SDevin Teske		f_device_probe_disk_fs device "$devname" "$capacity" &&
5299ecd54f2SDevin Teske			retval=$SUCCESS # Errors ignored
5309ecd54f2SDevin Teske
5319ecd54f2SDevin Teske		return $retval
5329ecd54f2SDevin Teske		;;
5339ecd54f2SDevin Teske	$GEOM_CLASS_ZFS_ZVOL)
5349ecd54f2SDevin Teske		f_dprintf "Found disk device named %s" "$devname"
5359ecd54f2SDevin Teske		debug= f_device_register device \
5369ecd54f2SDevin Teske			"$devname" "${desc:-GEOM ZFS::ZVOL device}" \
5379ecd54f2SDevin Teske			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
5389ecd54f2SDevin Teske			"" "" "" "" "$capacity"
5399ecd54f2SDevin Teske		retval=$?
5409ecd54f2SDevin Teske
5419ecd54f2SDevin Teske		# Detect ``dangerously dedicated'' filesystems
5429ecd54f2SDevin Teske		f_device_probe_disk_fs device "$devname" "$capacity" &&
5439ecd54f2SDevin Teske			retval=$SUCCESS # Errors ignored
5449ecd54f2SDevin Teske
5459ecd54f2SDevin Teske		return $retval
5469ecd54f2SDevin Teske		;;
5479ecd54f2SDevin Teske	*)
5489ecd54f2SDevin Teske		return $FAILURE # Unknown GEOM class
5499ecd54f2SDevin Teske	esac
5509ecd54f2SDevin Teske
5519ecd54f2SDevin Teske	#
5529ecd54f2SDevin Teske	# Still here? Must be $GEOM_CLASS_LABEL
5539ecd54f2SDevin Teske	#
5549ecd54f2SDevin Teske
5559ecd54f2SDevin Teske	local label_geom label_devname label_devgeom= label_devconsumer
5569ecd54f2SDevin Teske	local label_devprovider= label_devprovider_ref label_devprovider_config
5579ecd54f2SDevin Teske	local label_gpart_type
5589ecd54f2SDevin Teske
5599ecd54f2SDevin Teske	if f_struct "$p_provider"; then
5609ecd54f2SDevin Teske		label_geom="$p_provider_geom"
5619ecd54f2SDevin Teske	else
5629ecd54f2SDevin Teske		label_geom="$provider_geom"
5639ecd54f2SDevin Teske	fi
5649ecd54f2SDevin Teske
5659ecd54f2SDevin Teske	case "$devname" in
5669ecd54f2SDevin Teske	gpt/*|gptid/*)
5679ecd54f2SDevin Teske		#
5689ecd54f2SDevin Teske		# Attempt to get the partition type by getting the `config'
5699ecd54f2SDevin Teske		# member of the provider for our device (which is named in the
5709ecd54f2SDevin Teske		# parent geom of our current provider).
5719ecd54f2SDevin Teske		#
5729ecd54f2SDevin Teske		debug= f_struct "$label_geom" get name label_devname &&
5739ecd54f2SDevin Teske			debug= f_geom_find "$label_devname" $GEOM_CLASS_DEV \
5749ecd54f2SDevin Teske				label_devgeom
5759ecd54f2SDevin Teske		debug= f_struct "$label_devgeom" get \
5769ecd54f2SDevin Teske			consumer1 label_devconsumer
5779ecd54f2SDevin Teske		debug= f_struct "$label_devconsumer" get \
5789ecd54f2SDevin Teske			provider_ref label_devprovider_ref &&
5799ecd54f2SDevin Teske			debug= f_geom_find_by id "$label_devprovider_ref" \
5809ecd54f2SDevin Teske				provider label_devprovider
5819ecd54f2SDevin Teske		debug= f_struct "$label_devprovider" get \
5829ecd54f2SDevin Teske			config label_devprovider_config
5839ecd54f2SDevin Teske		debug= f_struct "$label_devprovider_config" get \
5849ecd54f2SDevin Teske			type label_gpart_type
5859ecd54f2SDevin Teske
5869ecd54f2SDevin Teske		#
5879ecd54f2SDevin Teske		# Register device label based on partition type
5889ecd54f2SDevin Teske		#
5899ecd54f2SDevin Teske		f_device_probe_geom_part device \
5909ecd54f2SDevin Teske			"$label_gpart_type" "$devname" "$capacity"
5919ecd54f2SDevin Teske		return $?
5929ecd54f2SDevin Teske		;;
5939ecd54f2SDevin Teske	iso9660/*)
5949ecd54f2SDevin Teske		f_dprintf "Found CDROM device labeled %s" "$devname"
5959ecd54f2SDevin Teske		debug= f_device_register device \
5969ecd54f2SDevin Teske			"$devname" "ISO9660 file system" \
5979ecd54f2SDevin Teske			"/dev/$devname" $DEVICE_TYPE_CDROM 1 \
5989ecd54f2SDevin Teske			f_media_init_cdrom f_media_get_cdrom \
5999ecd54f2SDevin Teske			f_media_shutdown_cdrom "" "$capacity"
6009ecd54f2SDevin Teske		return $?
6019ecd54f2SDevin Teske		;;
6029ecd54f2SDevin Teske	label/*)
6039ecd54f2SDevin Teske		# For generic labels, use provider geom name as real device
6049ecd54f2SDevin Teske		debug= f_struct "$label_geom" get name label_devname
6059ecd54f2SDevin Teske
6069ecd54f2SDevin Teske		# Look up label geom device in device catalog for default desc
6079ecd54f2SDevin Teske		debug= f_device_catalog_get \
6089ecd54f2SDevin Teske			$DEVICE_TYPE_ANY "$label_devname" catalog_struct
6099ecd54f2SDevin Teske		[ "$desc" ] || debug= f_struct \
6109ecd54f2SDevin Teske			"catalog_device_$catalog_struct" get desc desc
6119ecd54f2SDevin Teske
6129ecd54f2SDevin Teske		# Use device catalog entry for potential re-classification(s)
6139ecd54f2SDevin Teske		debug= f_struct "catalog_device_$catalog_struct" get \
6149ecd54f2SDevin Teske			type catalog_type
6159ecd54f2SDevin Teske
6169ecd54f2SDevin Teske		# First attempt to classify by device catalog (see MAIN)
6179ecd54f2SDevin Teske		case "$catalog_type" in
6189ecd54f2SDevin Teske		$DEVICE_TYPE_CDROM)
6199ecd54f2SDevin Teske			f_dprintf "Found CDROM device for disk %s" "$devname"
6209ecd54f2SDevin Teske			debug= f_device_register device "$devname" "$desc" \
6219ecd54f2SDevin Teske				"/dev/$devname" $DEVICE_TYPE_CDROM 1 \
6229ecd54f2SDevin Teske				f_media_init_cdrom f_media_get_cdrom \
6239ecd54f2SDevin Teske				f_media_shutdown_cdrom "" "$capacity" &&
6249ecd54f2SDevin Teske				return $SUCCESS
6259ecd54f2SDevin Teske			;;
6269ecd54f2SDevin Teske		esac
6279ecd54f2SDevin Teske
6289ecd54f2SDevin Teske		# Fall back to register label device as a disk and taste it
6299ecd54f2SDevin Teske		f_dprintf "Found disk device labeled %s" "$devname"
6309ecd54f2SDevin Teske		debug= f_device_register device \
6319ecd54f2SDevin Teske			"$devname" "GEOM LABEL device" \
6329ecd54f2SDevin Teske			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
6339ecd54f2SDevin Teske			"" "" "" "" "$capacity"
6349ecd54f2SDevin Teske		retval=$?
6359ecd54f2SDevin Teske
6369ecd54f2SDevin Teske		# Detect ``dangerously dedicated'' filesystems (errors ignored)
6379ecd54f2SDevin Teske		f_device_probe_disk_fs device "$devname" "$capacity" &&
6389ecd54f2SDevin Teske			retval=$SUCCESS
6399ecd54f2SDevin Teske
6409ecd54f2SDevin Teske		return $retval
6419ecd54f2SDevin Teske		;;
6429ecd54f2SDevin Teske	msdosfs/*)
6439ecd54f2SDevin Teske		f_dprintf "Found DOS partition labeled %s" "$devname"
6449ecd54f2SDevin Teske		debug= f_device_register device "$devname" "DOS file system" \
6459ecd54f2SDevin Teske			"/dev/$devname" $DEVICE_TYPE_DOS 1 \
6469ecd54f2SDevin Teske			f_media_init_dos f_media_get_dos \
6479ecd54f2SDevin Teske			f_media_shutdown_dos "" "$capacity"
6489ecd54f2SDevin Teske		return $?
6499ecd54f2SDevin Teske		;;
6509ecd54f2SDevin Teske	ufs/*|ufsid/*)
6519ecd54f2SDevin Teske		f_dprintf "Found UFS partition labeled %s" "$devname"
6529ecd54f2SDevin Teske		debug= f_device_register device "$devname" "UFS file system" \
6539ecd54f2SDevin Teske			"/dev/$devname" $DEVICE_TYPE_UFS 1 \
6549ecd54f2SDevin Teske			f_media_init_ufs f_media_get_ufs \
6559ecd54f2SDevin Teske			f_media_shutdown_ufs "" "$capacity"
6569ecd54f2SDevin Teske		return $?
6579ecd54f2SDevin Teske		;;
6589ecd54f2SDevin Teske	ext2fs/*|ntfs/*|reiserfs/*)
6599ecd54f2SDevin Teske		return $FAILURE # No media device handlers for these labels
6609ecd54f2SDevin Teske		;;
6619ecd54f2SDevin Teske	esac
6629ecd54f2SDevin Teske
6639ecd54f2SDevin Teske	# Unable to classify GEOM label
6649ecd54f2SDevin Teske	return $FAILURE
6659ecd54f2SDevin Teske}
6669ecd54f2SDevin Teske
6679ecd54f2SDevin Teske# f_device_probe_geom_part $var_to_set $gpart_type $devname $capacity [$magic]
6689ecd54f2SDevin Teske#
6699ecd54f2SDevin Teske# Given a gpart(8) partition type and a device name, register the device if it
6709ecd54f2SDevin Teske# is a known partition type that we can handle. If $var_to_set is non-NULL,
6719ecd54f2SDevin Teske# upon success holds the DEVICE struct name of the registered device.
6729ecd54f2SDevin Teske#
6739ecd54f2SDevin Teske# Returns success if the device was successfully registered, failure otherwise.
6749ecd54f2SDevin Teske#
6759ecd54f2SDevin Teskef_device_probe_geom_part()
6769ecd54f2SDevin Teske{
6779ecd54f2SDevin Teske	local __var_to_set="$1" __gpart_type="$2" __devname="$3"
6789ecd54f2SDevin Teske	local __capacity="${4:--1}" __magic="$5"
6799ecd54f2SDevin Teske
6809ecd54f2SDevin Teske	#
6819ecd54f2SDevin Teske	# Register device based on partition type
6829ecd54f2SDevin Teske	# NB: !0 equates to `unused' bsdlabel
6839ecd54f2SDevin Teske	#
6849ecd54f2SDevin Teske	case "$__gpart_type" in
6859ecd54f2SDevin Teske	fat16|fat32)
6869ecd54f2SDevin Teske		f_dprintf "Found DOS partition named %s" "$__devname"
6879ecd54f2SDevin Teske		debug= f_device_register "$__var_to_set" \
6889ecd54f2SDevin Teske			"$__devname" "DOS file system" \
6899ecd54f2SDevin Teske			"/dev/$__devname" $DEVICE_TYPE_DOS 1 \
6909ecd54f2SDevin Teske			f_media_init_dos f_media_get_dos \
6919ecd54f2SDevin Teske			f_media_shutdown_dos "" "$__capacity"
6929ecd54f2SDevin Teske		return $?
6939ecd54f2SDevin Teske		;;
6949ecd54f2SDevin Teske	freebsd|!0) # Commonly used inappropriately, taste for FreeBSD
6959ecd54f2SDevin Teske		[ -r "/dev/$__devname" -a ! "$__magic" ] &&
6969ecd54f2SDevin Teske			__magic=$( file -bs "/dev/$__devname" 2> /dev/null )
6979ecd54f2SDevin Teske		case "$__magic" in
6989ecd54f2SDevin Teske		*"Unix Fast File system"*)
6999ecd54f2SDevin Teske			f_dprintf "Found UFS partition named %s" "$__devname"
7009ecd54f2SDevin Teske			debug= f_device_register "$__var_to_set" \
7019ecd54f2SDevin Teske				"$__devname" "UFS file system" \
7029ecd54f2SDevin Teske				"/dev/$__devname" $DEVICE_TYPE_UFS 1 \
7039ecd54f2SDevin Teske				f_media_init_ufs f_media_get_ufs \
7049ecd54f2SDevin Teske				f_media_shutdown_ufs "" "$__capacity"
7059ecd54f2SDevin Teske			return $?
7069ecd54f2SDevin Teske		esac
7079ecd54f2SDevin Teske		return $FAILURE
7089ecd54f2SDevin Teske		;;
7099ecd54f2SDevin Teske	freebsd-ufs)
7109ecd54f2SDevin Teske		f_dprintf "Found UFS partition named %s" "$__devname"
7119ecd54f2SDevin Teske		debug= f_device_register "$__var_to_set" \
7129ecd54f2SDevin Teske			"$__devname" "UFS file system" \
7139ecd54f2SDevin Teske			"/dev/$__devname" $DEVICE_TYPE_UFS 1 \
7149ecd54f2SDevin Teske			f_media_init_ufs f_media_get_ufs \
7159ecd54f2SDevin Teske			f_media_shutdown_ufs "" "$__capacity"
7169ecd54f2SDevin Teske		return $?
7179ecd54f2SDevin Teske		;;
7189ecd54f2SDevin Teske	apple-*|linux-*|ms-*|netbsd-*|ntfs|vmware-*)
7199ecd54f2SDevin Teske		return $FAILURE # No device types for these
7209ecd54f2SDevin Teske		;;
7219ecd54f2SDevin Teske	bios-*|ebr|efi|mbr|freebsd-boot|freebsd-swap)
7229ecd54f2SDevin Teske		return $FAILURE # Not a source for media
7239ecd54f2SDevin Teske		;;
7249ecd54f2SDevin Teske	freebsd-nandfs|freebsd-vinum|freebsd-zfs)
7259ecd54f2SDevin Teske		return $FAILURE # Unsupported as media source
7269ecd54f2SDevin Teske		;;
7279ecd54f2SDevin Teske	esac
7289ecd54f2SDevin Teske
7299ecd54f2SDevin Teske	return $FAILURE # Unknown partition type
7309ecd54f2SDevin Teske}
7319ecd54f2SDevin Teske
7329ecd54f2SDevin Teske# f_device_probe_disk_fs $var_to_set $devname [$capacity [$magic]]
7339ecd54f2SDevin Teske#
7349ecd54f2SDevin Teske# Given a device name, taste it and register the device if it is a so-called
7359ecd54f2SDevin Teske# ``dangerously dedicated'' file system written without a partition table.
7369ecd54f2SDevin Teske# Tasting is done using file(1) (specifically `file -bs') but if $magic is
7379ecd54f2SDevin Teske# present and non-NULL it is used instead. If $var_to_set is non-NULL, upon
7389ecd54f2SDevin Teske# success holds the DEVICE struct name of the registered device.
7399ecd54f2SDevin Teske#
7409ecd54f2SDevin Teske# Returns success if the device was successfully registered, failure otherwise.
7419ecd54f2SDevin Teske#
7429ecd54f2SDevin Teskef_device_probe_disk_fs()
7439ecd54f2SDevin Teske{
7449ecd54f2SDevin Teske	local __var_to_set="$1" __devname="$2" __capacity="${3:--1}"
7459ecd54f2SDevin Teske	local __magic="$4"
7469ecd54f2SDevin Teske
7479ecd54f2SDevin Teske	[ -r "/dev/${__devname#/dev/}" -a ! "$__magic" ] &&
7489ecd54f2SDevin Teske		__magic=$( file -bs "/dev/$__devname" 2> /dev/null )
7499ecd54f2SDevin Teske
7509ecd54f2SDevin Teske	case "$__magic" in
7519ecd54f2SDevin Teske	*"ISO 9660"*)
7529ecd54f2SDevin Teske		f_dprintf "Found CDROM device for disk %s" "$__devname"
7539ecd54f2SDevin Teske		debug= f_device_register "$__var_to_set" \
7549ecd54f2SDevin Teske			"$__devname" "ISO9660 file system" \
7559ecd54f2SDevin Teske			"/dev/$__devname" $DEVICE_TYPE_CDROM 1 \
7569ecd54f2SDevin Teske			f_media_init_cdrom f_media_get_cdrom \
7579ecd54f2SDevin Teske			f_media_shutdown_cdrom "" "$__capacity"
7589ecd54f2SDevin Teske		return $?
7599ecd54f2SDevin Teske		;;
7609ecd54f2SDevin Teske	*"Unix Fast File system"*)
7619ecd54f2SDevin Teske		f_dprintf "Found UFS device for disk %s" "$__devname"
7629ecd54f2SDevin Teske		debug= f_device_register "$__var_to_set" \
7639ecd54f2SDevin Teske			"$__devname" "UFS file system" \
7649ecd54f2SDevin Teske			"/dev/$__devname" $DEVICE_TYPE_UFS 1 \
7659ecd54f2SDevin Teske			f_media_init_ufs f_media_get_ufs \
7669ecd54f2SDevin Teske			f_media_shutdown_ufs "" "$__capacity"
7679ecd54f2SDevin Teske		return $?
7689ecd54f2SDevin Teske		;;
7699ecd54f2SDevin Teske	*"FAT (12 bit)"*|*"FAT (16 bit)"*|*"FAT (32 bit)"*)
7709ecd54f2SDevin Teske		f_dprintf "Found DOS device for disk %s" "$__devname"
7719ecd54f2SDevin Teske		debug= f_device_register "$__var_to_set" \
7729ecd54f2SDevin Teske			"$__devname" "DOS file system" \
7739ecd54f2SDevin Teske			"/dev/$__devname" $DEVICE_TYPE_DOS 1 \
7749ecd54f2SDevin Teske			f_media_init_dos f_media_get_dos \
7759ecd54f2SDevin Teske			f_media_shutdown_dos "" "$__capacity"
7769ecd54f2SDevin Teske		return $?
7779ecd54f2SDevin Teske		;;
7789ecd54f2SDevin Teske	esac
7799ecd54f2SDevin Teske
7809ecd54f2SDevin Teske	return $FAILURE # Unknown file system type
7819ecd54f2SDevin Teske}
7829ecd54f2SDevin Teske
7839ecd54f2SDevin Teske# f_device_catalog_get $type $name [$var_to_set]
7849ecd54f2SDevin Teske#
7859ecd54f2SDevin Teske# Fetch the struct name of the catalog device matching device $name. If $type
7869ecd54f2SDevin Teske# is either NULL, missing, or set to $DEVICE_TYPE_ANY then only $name is used.
7877323adacSDevin Teske# Returns success if a match was found, otherwise failure.
7887323adacSDevin Teske#
7899ecd54f2SDevin Teske# If $var_to_set is missing or NULL, the struct name is printed to standard out
7907323adacSDevin Teske# for capturing in a sub-shell (which is less-recommended because of
7917323adacSDevin Teske# performance degredation; for example, when called in a loop).
7927323adacSDevin Teske#
7939ecd54f2SDevin Teskef_device_catalog_get()
7947323adacSDevin Teske{
7959ecd54f2SDevin Teske	local __type="$1" __name="$2" __var_to_set="$3"
7969ecd54f2SDevin Teske	local __dname=
7977323adacSDevin Teske
7989ecd54f2SDevin Teske	# Return failure if no $name
7997323adacSDevin Teske	[ "$__name" ] || return $FAILURE
8009ecd54f2SDevin Teske
8019ecd54f2SDevin Teske	# Disable debugging to keep debug output light
8029ecd54f2SDevin Teske	local debug=
8037323adacSDevin Teske
8041bd2b932SDevin Teske	#
8051bd2b932SDevin Teske	# Attempt to create an alternate-form of $__name that contains the
8061bd2b932SDevin Teske	# first contiguous string of numbers replaced with `%d' for comparison
8071bd2b932SDevin Teske	# against stored pattern names (see MAIN).
8081bd2b932SDevin Teske	#
8099ecd54f2SDevin Teske	local __left="${__name%%[0-9]*}" __right="${__name#*[0-9]}"
8101bd2b932SDevin Teske	if [ "$__left" != "$__name" ]; then
8111bd2b932SDevin Teske		# Chop leading digits from right 'til we hit first non-digit
8121bd2b932SDevin Teske		while :; do
8131bd2b932SDevin Teske			case "$__right" in
8141bd2b932SDevin Teske			[0-9]*) __right="${__right#[0-9]}" ;;
8151bd2b932SDevin Teske			     *) break
8161bd2b932SDevin Teske			esac
8171bd2b932SDevin Teske		done
8181bd2b932SDevin Teske		__dname="${__left}%d$__right"
8191bd2b932SDevin Teske	fi
8201bd2b932SDevin Teske
8217323adacSDevin Teske	[ "$__type" = "$DEVICE_TYPE_ANY" ] && __type=
8229ecd54f2SDevin Teske	local __dev __dev_name __dev_type
8239ecd54f2SDevin Teske	for __dev in $DEVICE_CATALOG; do
8249ecd54f2SDevin Teske		catalog_device_$__dev get name __dev_name
8259ecd54f2SDevin Teske		[ "$__dev_name" = "$__name" -o "$__dev_name" = "$__dname" ] ||
8269ecd54f2SDevin Teske			continue
8279ecd54f2SDevin Teske		catalog_device_$__dev get type __dev_type
8289ecd54f2SDevin Teske		[ "${__type:-$__dev_type}" = "$__dev_type" ] || continue
8299ecd54f2SDevin Teske		if [ "$__var_to_set" ]; then
8309ecd54f2SDevin Teske			setvar "$__var_to_set" $__dev
8319ecd54f2SDevin Teske		else
8329ecd54f2SDevin Teske			echo $__dev
8339ecd54f2SDevin Teske		fi
8347323adacSDevin Teske		return $?
8357323adacSDevin Teske	done
8369ecd54f2SDevin Teske
8379ecd54f2SDevin Teske	[ "$__var_to_set" ] && setvar "$__var_to_set" ""
8387323adacSDevin Teske	return $FAILURE
8397323adacSDevin Teske}
8407323adacSDevin Teske
8419ecd54f2SDevin Teske# f_device_catalog_set $type $name $desc
8427323adacSDevin Teske#
8439ecd54f2SDevin Teske# Store a description (desc) in-association with device $type and $name.
8449ecd54f2SDevin Teske# Returns success unless $name is NULL or missing. Use f_device_catalog_get()
8459ecd54f2SDevin Teske# routine with the same $name and optionally $type to retrieve catalog device
8469ecd54f2SDevin Teske# structure (see CATALOG_DEVICE struct definition in GLOBALS section).
8477323adacSDevin Teske#
8489ecd54f2SDevin Teskef_device_catalog_set()
8497323adacSDevin Teske{
8509ecd54f2SDevin Teske	local type="$1" name="$2" desc="$3"
8519ecd54f2SDevin Teske	local struct dev dev_type found=
8529ecd54f2SDevin Teske
8537323adacSDevin Teske	[ "$name" ] || return $FAILURE
8549ecd54f2SDevin Teske
8559ecd54f2SDevin Teske	# Disable debugging to keep debug output light
8569ecd54f2SDevin Teske	local debug=
8579ecd54f2SDevin Teske
8589ecd54f2SDevin Teske	f_str2varname "$name" struct
8599ecd54f2SDevin Teske	if [ ! "$DEVICE_CATALOG_APPEND_ONLY" ]; then
8609ecd54f2SDevin Teske		for dev in $DEVICE_CATALOG; do
8619ecd54f2SDevin Teske			[ "$dev" = "$struct" ] || continue
8629ecd54f2SDevin Teske			found=1 break
8637323adacSDevin Teske		done
8647323adacSDevin Teske	fi
8659ecd54f2SDevin Teske	if [ "$found" ]; then
8669ecd54f2SDevin Teske		f_struct_free "catalog_device_$struct"
8679ecd54f2SDevin Teske	else
8689ecd54f2SDevin Teske		DEVICE_CATALOG="$DEVICE_CATALOG $struct"
8699ecd54f2SDevin Teske	fi
8709ecd54f2SDevin Teske	f_struct_new CATALOG_DEVICE "catalog_device_$struct" || return $FAILURE
8719ecd54f2SDevin Teske	catalog_device_$struct set type "$type"
8729ecd54f2SDevin Teske	catalog_device_$struct set name "$name"
8739ecd54f2SDevin Teske	catalog_device_$struct set desc "$desc"
8747323adacSDevin Teske	return $SUCCESS
8757323adacSDevin Teske}
8767323adacSDevin Teske
8777323adacSDevin Teske# f_device_desc $device_name $device_type [$var_to_set]
8787323adacSDevin Teske#
8797323adacSDevin Teske# Print a description for a device name (eg., `fxp0') given a specific device
8807323adacSDevin Teske# type/class.
8817323adacSDevin Teske#
8827323adacSDevin Teske# If $var_to_set is missing or NULL, the device description is printed to
8837323adacSDevin Teske# standard out for capturing in a sub-shell (which is less-recommended because
8847323adacSDevin Teske# of performance degredation; for example, when called in a loop).
8857323adacSDevin Teske#
8867323adacSDevin Teskef_device_desc()
8877323adacSDevin Teske{
8887323adacSDevin Teske	local __name="$1" __type="$2" __var_to_set="$3"
8897323adacSDevin Teske	local __devname __devunit __cp
8907323adacSDevin Teske
8917323adacSDevin Teske	# Check variables
8927323adacSDevin Teske	[ "$__name" ] || return $SUCCESS
8937323adacSDevin Teske	[ "$__type" = "$DEVICE_TYPE_ANY" ] && type=
8947323adacSDevin Teske	[ "$__var_to_set" ] && { setvar "$__var_to_set" "" || return; }
8957323adacSDevin Teske
8967323adacSDevin Teske	#
8979ecd54f2SDevin Teske	# Return sysctl MIB dev.NAME.UNIT.%desc if it exists, otherwise fall
8989ecd54f2SDevin Teske	# through to further alternate methods.
8997323adacSDevin Teske	#
9007323adacSDevin Teske	if f_have sysctl; then
9017323adacSDevin Teske		__devname="${__name%%[0-9]*}"
9027323adacSDevin Teske		__devunit="${__name#$__devname}"
9037323adacSDevin Teske		__devunit="${__devunit%%[!0-9]*}"
9047323adacSDevin Teske		if [ "$__var_to_set" ]; then
9057323adacSDevin Teske			if __cp=$(
9067323adacSDevin Teske				sysctl -n "dev.$__devname.$__devunit.%desc" \
9077323adacSDevin Teske				2> /dev/null
9087323adacSDevin Teske			); then
9097323adacSDevin Teske				setvar "$__var_to_set" "$__cp" &&
9107323adacSDevin Teske					return $SUCCESS
9117323adacSDevin Teske			fi
9127323adacSDevin Teske		else
9137323adacSDevin Teske			sysctl -n "dev.$__devname.$__devunit.%desc" \
9147323adacSDevin Teske				2> /dev/null && return $SUCCESS
9157323adacSDevin Teske		fi
9167323adacSDevin Teske	fi
9177323adacSDevin Teske
9189ecd54f2SDevin Teske	# Look up device in catalog for default description
9199ecd54f2SDevin Teske	local __catalog_struct
9209ecd54f2SDevin Teske	debug= f_device_catalog_get "$__type" "$__name" __catalog_struct
9219ecd54f2SDevin Teske	debug= f_struct "catalog_device_$__catalog_struct" get \
9229ecd54f2SDevin Teske		desc "$__var_to_set" && return $SUCCESS
9237323adacSDevin Teske
9247323adacSDevin Teske	#
9257323adacSDevin Teske	# Sensible fall-backs for specific types
9267323adacSDevin Teske	#
9277323adacSDevin Teske	case "$__type" in
9287323adacSDevin Teske	$DEVICE_TYPE_CDROM)   __cp="<unknown cdrom device type>" ;;
9297323adacSDevin Teske	$DEVICE_TYPE_DISK)    __cp="<unknown disk device type>" ;;
9309ecd54f2SDevin Teske	$DEVICE_TYPE_USB)     __cp="<unknown USB storage device type>" ;;
9317323adacSDevin Teske	$DEVICE_TYPE_NETWORK) __cp="<unknown network interface type>" ;;
9327323adacSDevin Teske	*)
9337323adacSDevin Teske		__cp="<unknown device type>"
9347323adacSDevin Teske	esac
9357323adacSDevin Teske
9367323adacSDevin Teske	if [ "$__var_to_set" ]; then
9377323adacSDevin Teske		setvar "$__var_to_set" "$__cp"
9387323adacSDevin Teske	else
9397323adacSDevin Teske		echo "$__cp"
9407323adacSDevin Teske	fi
9417323adacSDevin Teske
9427323adacSDevin Teske	return $FAILURE
9437323adacSDevin Teske}
9447323adacSDevin Teske
9452cc6c69dSDevin Teske# f_device_is_ethernet $device
9462cc6c69dSDevin Teske#
9472cc6c69dSDevin Teske# Returns true if $device is a wired Ethernet network interface. Otherwise
9482cc6c69dSDevin Teske# returns false. Example wired interfaces include: fxp0 em0 bge0 rl0 etc.
9492cc6c69dSDevin Teske#
9502cc6c69dSDevin Teskef_device_is_ethernet()
9512cc6c69dSDevin Teske{
9522cc6c69dSDevin Teske	local dev="$1" type flags
9532cc6c69dSDevin Teske
9542cc6c69dSDevin Teske	# Make sure we have an actual device by that name
9559ecd54f2SDevin Teske	f_struct "$dev" || return $FAILURE
9562cc6c69dSDevin Teske
9572cc6c69dSDevin Teske	# Make sure that the device is a network device
9589ecd54f2SDevin Teske	$dev get type type
9592cc6c69dSDevin Teske	[ "$type" = "$DEVICE_TYPE_NETWORK" ] || return $FAILURE
9602cc6c69dSDevin Teske
9612cc6c69dSDevin Teske	# Make sure that the media flags indicate that it is Ethernet
9629ecd54f2SDevin Teske	$dev get flags flags
9632cc6c69dSDevin Teske	[ $(( ${flags:-0} & $IF_ETHERNET )) -eq $IF_ETHERNET ]
9642cc6c69dSDevin Teske}
9652cc6c69dSDevin Teske
9662cc6c69dSDevin Teske# f_device_is_wireless $device
9672cc6c69dSDevin Teske#
9682cc6c69dSDevin Teske# Returns true if $device is a Wireless network interface. Otherwise returns
9692cc6c69dSDevin Teske# false. Examples of wireless interfaces include: iwn0
9702cc6c69dSDevin Teske#
9712cc6c69dSDevin Teskef_device_is_wireless()
9722cc6c69dSDevin Teske{
9732cc6c69dSDevin Teske	local dev="$1" type flags
9742cc6c69dSDevin Teske
9752cc6c69dSDevin Teske	# Make sure we have an actual device by that name
9769ecd54f2SDevin Teske	f_struct "$dev" || return $FAILURE
9772cc6c69dSDevin Teske
9782cc6c69dSDevin Teske	# Make sure that the device is a network device
9799ecd54f2SDevin Teske	$dev get type type
9802cc6c69dSDevin Teske	[ "$type" = "$DEVICE_TYPE_NETWORK" ] || return $FAILURE
9812cc6c69dSDevin Teske
9829ecd54f2SDevin Teske	# Make sure that the media flags indicate that it is 802.11 wireless
9839ecd54f2SDevin Teske	$dev get flags flags
9842cc6c69dSDevin Teske	[ $(( ${flags:-0} & $IF_WIRELESS )) -eq $IF_WIRELESS ]
9852cc6c69dSDevin Teske}
9862cc6c69dSDevin Teske
9872cc6c69dSDevin Teske# f_device_is_active $device
9882cc6c69dSDevin Teske#
9892cc6c69dSDevin Teske# Returns true if $device is active. Otherwise returns false. Currently this
9902cc6c69dSDevin Teske# only works for network interfaces.
9912cc6c69dSDevin Teske#
9922cc6c69dSDevin Teskef_device_is_active()
9932cc6c69dSDevin Teske{
9942cc6c69dSDevin Teske	local dev="$1" type flags=0
9952cc6c69dSDevin Teske
9962cc6c69dSDevin Teske	# Make sure we have an actual device by that name
9979ecd54f2SDevin Teske	f_struct "$dev" || return $FAILURE
9982cc6c69dSDevin Teske
9999ecd54f2SDevin Teske	$dev get type type
10002cc6c69dSDevin Teske	case "$type" in
10012cc6c69dSDevin Teske	$DEVICE_TYPE_NETWORK)
10022cc6c69dSDevin Teske		# Make sure that the media flags indicate that it is active
10039ecd54f2SDevin Teske		$dev get flags flags
10042cc6c69dSDevin Teske		[ $(( ${flags:-0} & $IF_ACTIVE )) -eq $IF_ACTIVE ]
10052cc6c69dSDevin Teske		;;
10062cc6c69dSDevin Teske	*)
10072cc6c69dSDevin Teske		return $FAILURE
10082cc6c69dSDevin Teske	esac
10092cc6c69dSDevin Teske}
10102cc6c69dSDevin Teske
10119ecd54f2SDevin Teske# f_device_find [-1] $name [$type [$var_to_set]]
10127323adacSDevin Teske#
10137323adacSDevin Teske# Find one or more registered devices by name, type, or both. Returns a space-
10147323adacSDevin Teske# separated list of devices matching the search criterion.
10157323adacSDevin Teske#
10169ecd54f2SDevin Teske# If `-1' option flag is given, only the first matching device is returned.
10179ecd54f2SDevin Teske#
10187323adacSDevin Teske# If $var_to_set is missing or NULL, the device name(s) are printed to standard
10197323adacSDevin Teske# out for capturing in a sub-shell (which is less-recommended because of
10207323adacSDevin Teske# performance degredation; for example, when called in a loop).
10217323adacSDevin Teske#
10227323adacSDevin Teskef_device_find()
10237323adacSDevin Teske{
102457ef9b75SDevin Teske	local OPTIND=1 OPTARG flag only_one=
10259ecd54f2SDevin Teske	while getopts 1 flag; do
10269ecd54f2SDevin Teske		case "$flag" in
10279ecd54f2SDevin Teske		1) only_one=1 ;;
10289ecd54f2SDevin Teske		esac
10299ecd54f2SDevin Teske	done
10309ecd54f2SDevin Teske	shift $(( $OPTIND - 1 ))
10319ecd54f2SDevin Teske
10327323adacSDevin Teske	local __name="$1" __type="${2:-$DEVICE_TYPE_ANY}" __var_to_set="$3"
10339ecd54f2SDevin Teske	local __n=1 __devname __devtype __found=
10349ecd54f2SDevin Teske	while [ $__n -le $NDEVICES ]; do
10359ecd54f2SDevin Teske		device_$__n get name __devname
10369ecd54f2SDevin Teske		device_$__n get type __devtype
10377323adacSDevin Teske		if [ "$__name" = "$__devname" -o ! "$__name" ] &&
10387323adacSDevin Teske		   [ "$__type" = "$DEVICE_TYPE_ANY" -o \
10397323adacSDevin Teske		     "$__type" = "$__devtype" ]
10407323adacSDevin Teske		then
10419ecd54f2SDevin Teske			__found="$__found device_$__n"
10429ecd54f2SDevin Teske			[ "$only_one" ] && break
10437323adacSDevin Teske		fi
10449ecd54f2SDevin Teske		__n=$(( $__n + 1 ))
10457323adacSDevin Teske	done
10469ecd54f2SDevin Teske
10477323adacSDevin Teske	if [ "$__var_to_set" ]; then
10487323adacSDevin Teske		setvar "$__var_to_set" "${__found# }"
10497323adacSDevin Teske	else
10507323adacSDevin Teske		echo $__found
10517323adacSDevin Teske	fi
10527323adacSDevin Teske	[ "$__found" ] # Return status
10537323adacSDevin Teske}
10547323adacSDevin Teske
10559ecd54f2SDevin Teske# f_device_init $device
10567323adacSDevin Teske#
10579ecd54f2SDevin Teske# Initialize a device by evaluating its `init' function. The $device argument
10589ecd54f2SDevin Teske# is a DEVICE struct name.
10597323adacSDevin Teske#
10607323adacSDevin Teskef_device_init()
10617323adacSDevin Teske{
10629ecd54f2SDevin Teske	local device="$1" init_func
10639ecd54f2SDevin Teske	f_struct "$device" || return $?
10649ecd54f2SDevin Teske	$device get init init_func
10659ecd54f2SDevin Teske	${init_func:-:} "$device"
10667323adacSDevin Teske}
10677323adacSDevin Teske
10689ecd54f2SDevin Teske# f_device_get $device $file [$probe]
10697323adacSDevin Teske#
10707323adacSDevin Teske# Read $file by evaluating the device's `get' function. The file is commonly
10717323adacSDevin Teske# produced on standard output (but it truly depends on the function called).
10729ecd54f2SDevin Teske# The $device argument is a DEVICE struct name.
10737323adacSDevin Teske#
10747323adacSDevin Teskef_device_get()
10757323adacSDevin Teske{
10769ecd54f2SDevin Teske	local device="$1" file="$2" probe="$3" get_func
10779ecd54f2SDevin Teske	f_struct "$device" || return $?
10789ecd54f2SDevin Teske	$device get get get_func
10799ecd54f2SDevin Teske	${get_func:-:} "$device" "$file" ${3+"$probe"}
10807323adacSDevin Teske}
10817323adacSDevin Teske
10829ecd54f2SDevin Teske# f_device_shutdown $device
10837323adacSDevin Teske#
10849ecd54f2SDevin Teske# Shutdown a device by evaluating its `shutdown' function. The $device argument
10859ecd54f2SDevin Teske# is a DEVICE struct name.
10867323adacSDevin Teske#
10877323adacSDevin Teskef_device_shutdown()
10887323adacSDevin Teske{
10899ecd54f2SDevin Teske	local device="$1" shutdown_func
10909ecd54f2SDevin Teske	f_struct "$device" || return $?
10919ecd54f2SDevin Teske	$device get shutdown shutdown_func
10929ecd54f2SDevin Teske	${shutdown_func:-:} "$device"
10939ecd54f2SDevin Teske}
10949ecd54f2SDevin Teske
10959ecd54f2SDevin Teske# f_devices_sort_by $property $var_to_get [$var_to_set]
10969ecd54f2SDevin Teske#
10979ecd54f2SDevin Teske# Take list of devices from $var_to_get (separated by whitespace, newline
10989ecd54f2SDevin Teske# included) and sort them by $property (e.g., `name'). The sorted list of
10999ecd54f2SDevin Teske# DEVICE struct names is returned on standard output separated by whitespace
11009ecd54f2SDevin Teske# (newline to be specific) unless $var_to_set is present and non-NULL.
11019ecd54f2SDevin Teske#
11029ecd54f2SDevin Teske# This function is a two-parter. Below is the awk(1) portion of the function,
11039ecd54f2SDevin Teske# afterward is the sh(1) function which utilizes the below awk script.
11049ecd54f2SDevin Teske#
11059ecd54f2SDevin Teskef_device_sort_by_awk='
11069ecd54f2SDevin Teske# Variables that should be defined on the invocation line:
11079ecd54f2SDevin Teske# 	-v prop="property"
110809866e97SDevin Teskefunction _asorti(src, dest)
11099ecd54f2SDevin Teske{
1110489979a7SDevin Teske	k = nitems = 0
11119ecd54f2SDevin Teske	for (i in src) dest[++nitems] = i
11129ecd54f2SDevin Teske	for (i = 1; i <= nitems; k = i++) {
11139ecd54f2SDevin Teske		idx = dest[i]
11149ecd54f2SDevin Teske		while ((k > 0) && (dest[k] > idx)) {
11159ecd54f2SDevin Teske			dest[k+1] = dest[k]; k--
11169ecd54f2SDevin Teske		}
11179ecd54f2SDevin Teske		dest[k+1] = idx
11189ecd54f2SDevin Teske	}
11199ecd54f2SDevin Teske	return nitems
11209ecd54f2SDevin Teske}
11219ecd54f2SDevin Teske{
11229ecd54f2SDevin Teske	split($0, devs, FS)
11239ecd54f2SDevin Teske	for (d in devs) {
11249ecd54f2SDevin Teske		name = ENVIRON["_struct_value_" devs[d] "_" prop]
11259ecd54f2SDevin Teske		devices[name] = devs[d]
11269ecd54f2SDevin Teske	}
11279ecd54f2SDevin Teske}
11289ecd54f2SDevin TeskeEND {
112909866e97SDevin Teske	nitems = _asorti(devices, devices_sorted)
11309ecd54f2SDevin Teske	for (i = 1; i <= nitems; i++) print devices[devices_sorted[i]]
11319ecd54f2SDevin Teske}
11329ecd54f2SDevin Teske'
11339ecd54f2SDevin Teskef_device_sort_by()
11349ecd54f2SDevin Teske{
11359ecd54f2SDevin Teske	local __property="${1:-name}" __var_to_get="$2" __var_to_set="$3"
11369ecd54f2SDevin Teske
11379ecd54f2SDevin Teske	f_isset "$__var_to_get" || return $FAILURE
11389ecd54f2SDevin Teske
11399ecd54f2SDevin Teske	local __dev
11409ecd54f2SDevin Teske	for __dev in $( f_getvar "$__var_to_get" ); do
11419ecd54f2SDevin Teske		export _struct_value_${__dev}_$__property
11429ecd54f2SDevin Teske	done
11439ecd54f2SDevin Teske
11449ecd54f2SDevin Teske	local __cp
11459ecd54f2SDevin Teske	setvar "${__var_to_set:-__cp}" "$(
11469ecd54f2SDevin Teske		f_getvar "$__var_to_get" |
11479ecd54f2SDevin Teske			awk -v prop="$__property" "$f_device_sort_by_awk"
11489ecd54f2SDevin Teske	)"
11499ecd54f2SDevin Teske	[ "$__var_to_set" ] || echo "$__cp"
11507323adacSDevin Teske}
11517323adacSDevin Teske
11527323adacSDevin Teske# f_device_menu $title $prompt $hline $device_type [$helpfile]
11537323adacSDevin Teske#
11547323adacSDevin Teske# Display a menu listing all the devices of a certain type in the system.
11557323adacSDevin Teske#
11567323adacSDevin Teskef_device_menu()
11577323adacSDevin Teske{
11587323adacSDevin Teske	f_dialog_title "$1"
11597323adacSDevin Teske	local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
11607323adacSDevin Teske	f_dialog_title_restore
11617323adacSDevin Teske
11627323adacSDevin Teske	local prompt="$2" hline="$3" type="$4" helpfile="$5"
11637323adacSDevin Teske
11649ecd54f2SDevin Teske	local devs
11659ecd54f2SDevin Teske	f_device_find "" "$type" devs || return $DIALOG_CANCEL
11667323adacSDevin Teske
11679ecd54f2SDevin Teske	local name desc menu_list=
11689ecd54f2SDevin Teske	f_device_sort_by name devs devs
11697323adacSDevin Teske	for dev in $devs; do
11709ecd54f2SDevin Teske		$dev get name name
11719ecd54f2SDevin Teske		$dev get desc desc
11729ecd54f2SDevin Teske		f_shell_escape "$name" name
117344392705SDevin Teske		f_shell_escape "$desc" desc
11749ecd54f2SDevin Teske		menu_list="$menu_list
11759ecd54f2SDevin Teske			'$name' '$desc'" # END-QUOTE
11767323adacSDevin Teske	done
11779ecd54f2SDevin Teske	menu_list="${menu_list#$NL}"
11787323adacSDevin Teske
117974036c4dSDevin Teske	local height width rows
118074036c4dSDevin Teske	eval f_dialog_menu_size height width rows \
11817323adacSDevin Teske	                        \"\$title\"  \
11827323adacSDevin Teske	                        \"\$btitle\" \
11837323adacSDevin Teske	                        \"\$prompt\" \
11847323adacSDevin Teske	                        \"\$hline\"  \
118574036c4dSDevin Teske	                        $menu_list
11867323adacSDevin Teske
11877323adacSDevin Teske	local errexit=
11887323adacSDevin Teske	case $- in *e*) errexit=1; esac
11897323adacSDevin Teske	set +e
11907323adacSDevin Teske
1191fd962ac6SDevin Teske	local mtag
11927323adacSDevin Teske	while :; do
11937323adacSDevin Teske		mtag=$( eval $DIALOG \
11947323adacSDevin Teske			--title \"\$title\"             \
11957323adacSDevin Teske			--backtitle \"\$btitle\"        \
11969ecd54f2SDevin Teske			--hline \"\$hline\"             \
11977323adacSDevin Teske			--ok-label \"\$msg_ok\"         \
11987323adacSDevin Teske			--cancel-label \"\$msg_cancel\" \
11997323adacSDevin Teske			${helpfile:+                    \
12007323adacSDevin Teske			  --help-button                 \
12017323adacSDevin Teske			  --help-label \"\$msg_help\"   \
12027323adacSDevin Teske			  ${USE_XDIALOG:+--help \"\"}   \
12037323adacSDevin Teske			}                               \
120474036c4dSDevin Teske			--menu \"\$prompt\"             \
120574036c4dSDevin Teske			$height $width $rows            \
12067323adacSDevin Teske			$menu_list                      \
12077323adacSDevin Teske			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
12087323adacSDevin Teske		)
12097323adacSDevin Teske		local retval=$?
12107323adacSDevin Teske
1211f677a9e2SDevin Teske		[ $retval -ne $DIALOG_HELP ] && break
12127323adacSDevin Teske			# Otherwise, the Help button was pressed
12137323adacSDevin Teske		f_show_help "$helpfile"
121476c853aeSDevin Teske			# ...then loop back to menu
12157323adacSDevin Teske	done
12167323adacSDevin Teske	f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
12177323adacSDevin Teske
12187323adacSDevin Teske	[ "$errexit" ] && set -e
12197323adacSDevin Teske
1220f677a9e2SDevin Teske	if [ $retval -eq $DIALOG_OK ]; then
12219ecd54f2SDevin Teske		# Clean up the output of [X]dialog(1)
1222fd962ac6SDevin Teske		f_dialog_data_sanitize mtag
12239ecd54f2SDevin Teske
12249ecd54f2SDevin Teske		# Map the user's choice back to a struct name
12259ecd54f2SDevin Teske		local index device
12269ecd54f2SDevin Teske		index=$( eval f_dialog_menutag2index \"\$mtag\" $menu_list )
12279ecd54f2SDevin Teske		device=$( set -- $devs; eval echo \${$index} )
12289ecd54f2SDevin Teske
12299ecd54f2SDevin Teske		echo "$device" >&2
1230f780b9f5SDevin Teske	fi
12317323adacSDevin Teske
12327323adacSDevin Teske	return $retval
12337323adacSDevin Teske}
12347323adacSDevin Teske
12357323adacSDevin Teske#
12367323adacSDevin Teske# Short-hand
12377323adacSDevin Teske#
12389ecd54f2SDevin Teskef_cdrom()   { f_device_catalog_set $DEVICE_TYPE_CDROM   "$1" "$2"; }
12399ecd54f2SDevin Teskef_disk()    { f_device_catalog_set $DEVICE_TYPE_DISK    "$1" "$2"; }
12409ecd54f2SDevin Teskef_usb()     { f_device_catalog_set $DEVICE_TYPE_USB     "$1" "$2"; }
12419ecd54f2SDevin Teskef_network() { f_device_catalog_set $DEVICE_TYPE_NETWORK "$1" "$2"; }
12427323adacSDevin Teske
12437323adacSDevin Teske############################################################ MAIN
12447323adacSDevin Teske
12459ecd54f2SDevin Teske#
12469ecd54f2SDevin Teske# The below classifications allow us to re-group the GEOM devices from the
12479ecd54f2SDevin Teske# `DEV' GEOM class appropriately while providing fall-back descriptions both
12489ecd54f2SDevin Teske# for making the below code more maintainable and handling the rare case the
12499ecd54f2SDevin Teske# GEOM device lacks a description.
12509ecd54f2SDevin Teske#
12519ecd54f2SDevin Teske
12529ecd54f2SDevin TeskeDEVICE_CATALOG_APPEND_ONLY=1 # Make initial loading faster
12539ecd54f2SDevin Teske
1254*77e93191SBaptiste Daroussin# CDROM, Disk, and USB devices/names
12559ecd54f2SDevin Teskef_cdrom  "cd%d"   "SCSI CDROM drive"
12569ecd54f2SDevin Teskef_cdrom  "mcd%d"  "Mitsumi (old model) CDROM drive"
12579ecd54f2SDevin Teskef_cdrom  "scd%d"  "Sony CDROM drive - CDU31/33A type"
12589ecd54f2SDevin Teskef_disk   "aacd%d" "Adaptec FSA RAID array"
12599ecd54f2SDevin Teskef_disk   "ada%d"  "ATA/SATA disk device"
12609ecd54f2SDevin Teskef_disk   "amrd%d" "AMI MegaRAID drive"
12619ecd54f2SDevin Teskef_disk   "da%d"   "SCSI disk device"
12629ecd54f2SDevin Teskef_disk   "idad%d" "Compaq RAID array"
12639ecd54f2SDevin Teskef_disk   "ipsd%d" "IBM ServeRAID RAID array"
12649ecd54f2SDevin Teskef_disk   "md%d"   "md(4) disk device"
12659ecd54f2SDevin Teskef_disk   "mfid%d" "LSI MegaRAID SAS array"
12669ecd54f2SDevin Teskef_disk   "mlxd%d" "Mylex RAID disk"
12679ecd54f2SDevin Teskef_disk   "twed%d" "3ware ATA RAID array"
12689ecd54f2SDevin Teskef_disk   "vtbd%d" "VirtIO Block Device"
12699ecd54f2SDevin Teskef_usb    "da%da"  "USB Mass Storage Device"
12707323adacSDevin Teske
12717323adacSDevin Teske# Network interfaces/names
12729ecd54f2SDevin Teskef_network "ae%d"    "Attansic/Atheros L2 Fast Ethernet"
12739ecd54f2SDevin Teskef_network "age%d"   "Attansic/Atheros L1 Gigabit Ethernet"
12749ecd54f2SDevin Teskef_network "alc%d"   "Atheros AR8131/AR8132 PCIe Ethernet"
12759ecd54f2SDevin Teskef_network "ale%d"   "Atheros AR8121/AR8113/AR8114 PCIe Ethernet"
12769ecd54f2SDevin Teskef_network "an%d"    "Aironet 4500/4800 802.11 wireless adapter"
12779ecd54f2SDevin Teskef_network "ath%d"   "Atheros IEEE 802.11 wireless adapter"
12789ecd54f2SDevin Teskef_network "aue%d"   "ADMtek USB Ethernet adapter"
12799ecd54f2SDevin Teskef_network "axe%d"   "ASIX Electronics USB Ethernet adapter"
12809ecd54f2SDevin Teskef_network "bce%d"   "Broadcom NetXtreme II Gigabit Ethernet card"
12819ecd54f2SDevin Teskef_network "bfe%d"   "Broadcom BCM440x PCI Ethernet card"
12829ecd54f2SDevin Teskef_network "bge%d"   "Broadcom BCM570x PCI Gigabit Ethernet card"
12839ecd54f2SDevin Teskef_network "bm%d"    "Apple BMAC Built-in Ethernet"
12849ecd54f2SDevin Teskef_network "bwn%d"   "Broadcom BCM43xx IEEE 802.11 wireless adapter"
12859ecd54f2SDevin Teskef_network "cas%d"   "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"
12869ecd54f2SDevin Teskef_network "cc3i%d"  "SDL HSSI sync serial PCI card"
12879ecd54f2SDevin Teskef_network "cue%d"   "CATC USB Ethernet adapter"
12889ecd54f2SDevin Teskef_network "cxgb%d"  "Chelsio T3 10Gb Ethernet card"
12899ecd54f2SDevin Teskef_network "dc%d"    "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"
12909ecd54f2SDevin Teskef_network "de%d"    "DEC DE435 PCI NIC or other DC21040-AA based card"
12919ecd54f2SDevin Teskef_network "disc%d"  "Software discard network interface"
12929ecd54f2SDevin Teskef_network "ed%d"    "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"
12939ecd54f2SDevin Teskef_network "el%d"    "3Com 3C501 Ethernet card"
12949ecd54f2SDevin Teskef_network "em%d"    "Intel(R) PRO/1000 Ethernet card"
12959ecd54f2SDevin Teskef_network "ep%d"    "3Com 3C509 Ethernet card/3C589 PCMCIA"
12969ecd54f2SDevin Teskef_network "et%d"    "Agere ET1310 based PCI Express Gigabit Ethernet card"
12979ecd54f2SDevin Teskef_network "ex%d"    "Intel EtherExpress Pro/10 Ethernet card"
12989ecd54f2SDevin Teskef_network "fe%d"    "Fujitsu MB86960A/MB86965A Ethernet card"
12999ecd54f2SDevin Teskef_network "fpa%d"   "DEC DEFPA PCI FDDI card"
13009ecd54f2SDevin Teskef_network "fwe%d"   "FireWire Ethernet emulation"
13019ecd54f2SDevin Teskef_network "fwip%d"  "IP over FireWire"
13029ecd54f2SDevin Teskef_network "fxp%d"   "Intel EtherExpress Pro/100B PCI Fast Ethernet card"
13039ecd54f2SDevin Teskef_network "gem%d"   "Apple GMAC or Sun ERI/GEM Ethernet adapter"
13049ecd54f2SDevin Teskef_network "hme%d"   "Sun HME (Happy Meal Ethernet) Ethernet adapter"
13059ecd54f2SDevin Teskef_network "ie%d"    "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"
13069ecd54f2SDevin Teskef_network "igb%d"   "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"
13079ecd54f2SDevin Teskef_network "ipw%d"   "Intel PRO/Wireless 2100 IEEE 802.11 adapter"
13089ecd54f2SDevin Teskef_network "iwi%d"   "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"
13099ecd54f2SDevin Teskef_network "iwn%d"   "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"
13109ecd54f2SDevin Teskef_network "ix%d"    "Intel Etherexpress Ethernet card"
13119ecd54f2SDevin Teskef_network "ixgbe%d" "Intel(R) PRO/10Gb Ethernet card"
13129ecd54f2SDevin Teskef_network "jme%d"   "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"
13139ecd54f2SDevin Teskef_network "kue%d"   "Kawasaki LSI USB Ethernet adapter"
13149ecd54f2SDevin Teskef_network "le%d"    "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"
13159ecd54f2SDevin Teskef_network "lge%d"   "Level 1 LXT1001 Gigabit Ethernet card"
13169ecd54f2SDevin Teskef_network "lnc%d"   "Lance/PCnet (Isolan/Novell NE2100/NE32-VL) Ethernet"
13179ecd54f2SDevin Teskef_network "lo%d"    "Loop-back (local) network interface"
13189ecd54f2SDevin Teskef_network "lp%d"    "Parallel Port IP (PLIP) peer connection"
13199ecd54f2SDevin Teskef_network "malo%d"  "Marvell Libertas 88W8335 802.11 wireless adapter"
13209ecd54f2SDevin Teskef_network "msk%d"   "Marvell/SysKonnect Yukon II Gigabit Ethernet"
13219ecd54f2SDevin Teskef_network "mxge%d"  "Myricom Myri10GE 10Gb Ethernet card"
13229ecd54f2SDevin Teskef_network "nfe%d"   "NVIDIA nForce MCP Ethernet"
13239ecd54f2SDevin Teskef_network "ng%d"    "Vimage netgraph(4) bridged Ethernet device"
13249ecd54f2SDevin Teskef_network "nge%d"   "NatSemi PCI Gigabit Ethernet card"
13259ecd54f2SDevin Teskef_network "nve%d"   "NVIDIA nForce MCP Ethernet"
13269ecd54f2SDevin Teskef_network "pcn%d"   "AMD Am79c79x PCI Ethernet card"
13279ecd54f2SDevin Teskef_network "plip%d"  "Parallel Port IP (PLIP) peer connection"
13289ecd54f2SDevin Teskef_network "ral%d"   "Ralink Technology IEEE 802.11 wireless adapter"
13299ecd54f2SDevin Teskef_network "ray%d"   "Raytheon Raylink 802.11 wireless adapter"
13309ecd54f2SDevin Teskef_network "re%d"    "RealTek 8139C+/8169/8169S/8110S PCI Ethernet adapter"
13319ecd54f2SDevin Teskef_network "rl%d"    "RealTek 8129/8139 PCI Ethernet card"
13329ecd54f2SDevin Teskef_network "rue%d"   "RealTek USB Ethernet card"
13339ecd54f2SDevin Teskef_network "rum%d"   "Ralink Technology USB IEEE 802.11 wireless adapter"
13349ecd54f2SDevin Teskef_network "sf%d"    "Adaptec AIC-6915 PCI Ethernet card"
13359ecd54f2SDevin Teskef_network "sge%d"   "Silicon Integrated Systems SiS190/191 Ethernet"
13369ecd54f2SDevin Teskef_network "sis%d"   "SiS 900/SiS 7016 PCI Ethernet card"
13379ecd54f2SDevin Teskef_network "sk%d"    "SysKonnect PCI Gigabit Ethernet card"
13389ecd54f2SDevin Teskef_network "sn%d"    "SMC/Megahertz Ethernet card"
13399ecd54f2SDevin Teskef_network "snc%d"   "SONIC Ethernet card"
13409ecd54f2SDevin Teskef_network "sr%d"    "SDL T1/E1 sync serial PCI card"
13419ecd54f2SDevin Teskef_network "ste%d"   "Sundance ST201 PCI Ethernet card"
13429ecd54f2SDevin Teskef_network "stge%d"  "Sundance/Tamarack TC9021 Gigabit Ethernet"
13439ecd54f2SDevin Teskef_network "ti%d"    "Alteon Networks PCI Gigabit Ethernet card"
13449ecd54f2SDevin Teskef_network "tl%d"    "Texas Instruments ThunderLAN PCI Ethernet card"
13459ecd54f2SDevin Teskef_network "tx%d"    "SMC 9432TX Ethernet card"
13469ecd54f2SDevin Teskef_network "txp%d"   "3Com 3cR990 Ethernet card"
13479ecd54f2SDevin Teskef_network "uath%d"  "Atheros AR5005UG and AR5005UX USB wireless adapter"
13489ecd54f2SDevin Teskef_network "upgt%d"  "Conexant/Intersil PrismGT USB wireless adapter"
13499ecd54f2SDevin Teskef_network "ural%d"  "Ralink Technology RT2500USB 802.11 wireless adapter"
13509ecd54f2SDevin Teskef_network "urtw%d"  "Realtek 8187L USB wireless adapter"
13519ecd54f2SDevin Teskef_network "vge%d"   "VIA VT612x PCI Gigabit Ethernet card"
13529ecd54f2SDevin Teskef_network "vlan%d"  "IEEE 802.1Q VLAN network interface"
13539ecd54f2SDevin Teskef_network "vr%d"    "VIA VT3043/VT86C100A Rhine PCI Ethernet card"
13549ecd54f2SDevin Teskef_network "vx%d"    "3COM 3c590 / 3c595 Ethernet card"
13559ecd54f2SDevin Teskef_network "wb%d"    "Winbond W89C840F PCI Ethernet card"
13569ecd54f2SDevin Teskef_network "wi%d"    "Lucent WaveLAN/IEEE 802.11 wireless adapter"
13579ecd54f2SDevin Teskef_network "wpi%d"   "Intel 3945ABG IEEE 802.11 wireless adapter"
13589ecd54f2SDevin Teskef_network "wx%d"    "Intel Gigabit Ethernet (82452) card"
13599ecd54f2SDevin Teskef_network "xe%d"    "Xircom/Intel EtherExpress Pro100/16 Ethernet card"
13609ecd54f2SDevin Teskef_network "xl%d"    "3COM 3c90x / 3c90xB PCI Ethernet card"
13619ecd54f2SDevin Teskef_network "zyd%d"   "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"
13627323adacSDevin Teske
13639ecd54f2SDevin TeskeDEVICE_CATALOG_APPEND_ONLY= # Additional loading modifies existing devices
13649ecd54f2SDevin Teske
13659ecd54f2SDevin Teskef_count NCATALOG_DEVICES $DEVICE_CATALOG
13669ecd54f2SDevin Teskef_dprintf "%s: Initialized device catalog with %u names/descriptions." \
13679ecd54f2SDevin Teske          device.subr $NCATALOG_DEVICES
13687323adacSDevin Teske
13697323adacSDevin Teske#
13707323adacSDevin Teske# Scan for the above devices unless requeted otherwise
13717323adacSDevin Teske#
13727323adacSDevin Teskef_dprintf "%s: DEVICE_SELF_SCAN_ALL=[%s]" device.subr "$DEVICE_SELF_SCAN_ALL"
13737323adacSDevin Teskecase "$DEVICE_SELF_SCAN_ALL" in
13747323adacSDevin Teske""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
13757323adacSDevin Teske*) f_device_get_all
13767323adacSDevin Teskeesac
13777323adacSDevin Teske
13787323adacSDevin Teskef_dprintf "%s: Successfully loaded." device.subr
13797323adacSDevin Teske
13807323adacSDevin Teskefi # ! $_DEVICE_SUBR
1381