xref: /freebsd/usr.sbin/bsdconfig/share/device.subr (revision 2e3f49888ec8851bafb22011533217487764fdb0)
1if [ ! "$_DEVICE_SUBR" ]; then _DEVICE_SUBR=1
2#
3# Copyright (c) 2012-2016 Devin Teske
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27#
28############################################################ INCLUDES
29
30BSDCFG_SHARE="/usr/share/bsdconfig"
31. $BSDCFG_SHARE/common.subr || exit 1
32f_dprintf "%s: loading includes..." device.subr
33f_include $BSDCFG_SHARE/dialog.subr
34f_include $BSDCFG_SHARE/geom.subr
35f_include $BSDCFG_SHARE/strings.subr
36f_include $BSDCFG_SHARE/struct.subr
37
38BSDCFG_LIBE="/usr/libexec/bsdconfig"
39f_include_lang $BSDCFG_LIBE/include/messages.subr
40
41############################################################ GLOBALS
42
43NDEVICES=0 # Set by f_device_register(), used by f_device_*()
44
45#
46# A "device" from legacy sysinstall's point of view (mostly)
47#
48# NB: Disk devices have their `private' property set to GEOM ident
49# NB: USB devices have their `private' property set to USB disk device name
50#
51f_struct_define DEVICE \
52	capacity	\
53	desc		\
54	devname		\
55	enabled		\
56	flags		\
57	get		\
58	init		\
59	name		\
60	private		\
61	shutdown	\
62	type		\
63	volume
64
65# Network devices have their `private' property set to this
66f_struct_define DEVICE_INFO \
67	extras		\
68	ipaddr		\
69	ipv6addr	\
70	netmask		\
71	use_dhcp	\
72	use_rtsol
73
74#
75# Device types for f_device_register(), f_device_find(), et al.
76#
77setvar DEVICE_TYPE_ANY		"any"		# Any
78setvar DEVICE_TYPE_NONE		"NONE"		# Unknown
79setvar DEVICE_TYPE_DISK		"DISK"		# GEOM `DISK'
80setvar DEVICE_TYPE_FTP		"FTP"		# Dynamic network device
81setvar DEVICE_TYPE_NETWORK	"NETWORK"	# See f_device_get_all_network
82setvar DEVICE_TYPE_CDROM	"CDROM"		# GEOM `DISK'
83setvar DEVICE_TYPE_USB		"USB"		# GEOM `PART'
84setvar DEVICE_TYPE_DOS		"DOS"		# GEOM `DISK' `PART' or `LABEL'
85setvar DEVICE_TYPE_UFS		"UFS"		# GEOM `DISK' `PART' or `LABEL'
86setvar DEVICE_TYPE_NFS		"NFS"		# Dynamic network device
87setvar DEVICE_TYPE_HTTP_PROXY	"HTTP_PROXY"	# Dynamic network device
88setvar DEVICE_TYPE_HTTP		"HTTP"		# Dynamic network device
89
90# Network devices have the following flags available
91setvar IF_ETHERNET	1
92setvar IF_WIRELESS	2
93setvar IF_ACTIVE	4
94
95#
96# Default behavior is to call f_device_get_all() automatically when loaded.
97#
98: ${DEVICE_SELF_SCAN_ALL=1}
99
100#
101# Device Catalog variables
102#
103DEVICE_CATALOG_APPEND_ONLY= # Used by f_device_catalog_set()
104NCATALOG_DEVICES=0          # Used by f_device_catalog_*() and MAIN
105
106#
107# A ``catalog'' device is for mapping GEOM devices to media devices (for
108# example, determining if a $GEOM_CLASS_DISK geom is $DEVICE_TYPE_CDROM or
109# $DEVICE_TYPE_DISK) and also getting default descriptions for devices that
110# either lack a GEOM provided description or lack a presence in GEOM)
111#
112f_struct_define CATALOG_DEVICE \
113	desc	\
114	name	\
115	type
116
117############################################################ FUNCTIONS
118
119# f_device_register $var_to_set $name $desc $devname $type $enabled
120#                   $init_function $get_function $shutdown_function
121#                   $private $capacity
122#
123# Register a device. A `structure' (see struct.subr) is created and if
124# $var_to_set is non-NULL, upon success holds the name of the struct created.
125# The remaining positional arguments correspond to the properties of the
126# `DEVICE' structure-type to be assigned (defined above).
127#
128# If not already registered (based on $name and $type), a new device is created
129# and $NDEVICES is incremented.
130#
131f_device_register()
132{
133	local __var_to_set="$1" __name="$2" __desc="$3" __devname="$4"
134	local __type="$5" __enabled="$6" __init_func="$7" __get_func="$8"
135	local __shutdown_func="$9" __private="${10}" __capacity="${11}"
136
137	# Required parameter(s)
138	[ "$__name" ] || return $FAILURE
139	if [ "$__var_to_set" ]; then
140		setvar "$__var_to_set" "" || return $FAILURE
141	fi
142
143	local __device
144	if f_device_find -1 "$__name" "$__type" __device; then
145		f_struct_free "$__device"
146		f_struct_new DEVICE "$__device" || return $FAILURE
147	else
148		__device=device_$(( NDEVICES + 1 ))
149		f_struct_new DEVICE "$__device" || return $FAILURE
150		NDEVICES=$(( $NDEVICES + 1 ))
151	fi
152	$__device set name     "$__name"
153	$__device set desc     "$__desc"
154	$__device set devname  "$__devname"
155	$__device set type     "$__type"
156	$__device set enabled  "$__enabled"
157	$__device set init     "$__init_func"
158	$__device set get      "$__get_func"
159	$__device set shutdown "$__shutdown_func"
160	$__device set private  "$__private"
161	$__device set capacity "$__capacity"
162
163	[ "$__var_to_set" ] && setvar "$__var_to_set" "$__device"
164	return $SUCCESS
165}
166
167# f_device_reset
168#
169# Reset the registered device chain.
170#
171f_device_reset()
172{
173	local n=1
174	while [ $n -le $NDEVICES ]; do
175		f_device_shutdown device_$n
176
177		#
178		# XXX This potentially leaks $dev->private if it's being
179		# used to point to something dynamic, but you're not supposed
180		# to call this routine at such times that some open instance
181		# has its private member pointing somewhere anyway.
182		#
183		f_struct_free device_$n
184
185		n=$(( $n + 1 ))
186	done
187	NDEVICES=0
188}
189
190# f_device_reset_network
191#
192# Reset the registered network device chain.
193#
194f_device_reset_network()
195{
196	local n=1 device type private i
197	while [ $n -le $NDEVICES ]; do
198		device=device_$n
199		f_struct $device || continue
200		$device get type type
201		[ "$type" = "$DEVICE_TYPE_NETWORK" ] || continue
202
203		#
204		# Leave the device up (don't call shutdown routine)
205		#
206
207		# Network devices may have DEVICE_INFO private member
208		$device get private private
209		[ "$private" ] && f_struct_free "$private"
210
211		# Free the network device
212		f_struct_free $device
213
214		# Fill the gap we just created
215		i=$n
216		while [ $i -lt $NDEVICES ]; do
217			f_struct_copy device_$(( $i + 1 )) device_$i
218		done
219		f_struct_free device_$NDEVICES
220
221		# Finally decrement the number of devices
222		NDEVICES=$(( $NDEVICES - 1 ))
223
224		n=$(( $n + 1 ))
225	done
226}
227
228# f_device_get_all
229#
230# Get all device information for all devices.
231#
232f_device_get_all()
233{
234	local devname type desc capacity
235
236	f_dprintf "f_device_get_all: Probing devices..."
237	f_dialog_info "$msg_probing_devices_please_wait_this_can_take_a_while"
238
239	# First go for the network interfaces
240	f_device_get_all_network
241
242	# Next, go for the GEOM devices we might want to use as media
243	local geom geoms geom_name
244	debug= f_geom_find "" $GEOM_CLASS_DEV geoms
245	for geom in $geoms; do
246		if ! f_device_probe_geom $geom; then
247			debug= $geom get name geom_name
248			f_dprintf "WARNING! Unable to classify %s as %s" \
249			          "GEOM device $geom_name" "media source"
250		fi
251	done
252}
253
254# f_device_get_all_network
255#
256# Get all network device information for attached network devices.
257#
258f_device_get_all_network()
259{
260	local devname desc device flags
261	for devname in $( ifconfig -l ); do
262		# Eliminate network devices that don't make sense
263		case "$devname" in
264		lo*) continue ;;
265		esac
266
267		# Try and find its description
268		f_device_desc "$devname" $DEVICE_TYPE_NETWORK desc
269
270		f_dprintf "Found network device named %s" "$devname"
271		debug= f_device_register device $devname "$desc" \
272			"$devname" $DEVICE_TYPE_NETWORK 1 \
273			f_media_init_network "" f_media_shutdown_network "" -1
274
275		# Set flags based on media and status
276		flags=0
277		eval "$( ifconfig $devname 2> /dev/null | awk -v var=flags '
278		function _or(var, mask) {
279			printf "%s=$(( $%s | $%s ))\n", var, var, mask
280		}
281		BEGIN { S = "[[:space:]]+" }
282		{
283			if (!match($0, "^" S "(media|status):" S)) next
284			value = substr($0, RLENGTH + 1)
285			if ($1 == "media:") {
286				if (value ~ /Ethernet/) _or(var, "IF_ETHERNET")
287				if (value ~ /802\.11/) _or(var, "IF_WIRELESS")
288			} else if ($1 == "status:") {
289				if (value ~ /^active/) _or(var, "IF_ACTIVE")
290			}
291		}' )"
292		$device set flags $flags
293	done
294}
295
296# f_device_rescan
297#
298# Rescan all devices, after closing previous set - convenience function.
299#
300f_device_rescan()
301{
302	f_device_reset
303	f_geom_rescan
304	f_device_get_all
305}
306
307# f_device_rescan_network
308#
309# Rescan all network devices, after closing previous set - for convenience.
310#
311f_device_rescan_network()
312{
313	f_device_reset_network
314	f_device_get_all_network
315}
316
317# f_device_probe_geom $geom
318#
319# Probe a single GEOM device and if it can be classified as a media source,
320# register it using f_device_register() with known type-specific arguments.
321#
322f_device_probe_geom()
323{
324	local geom="$1"
325
326	f_struct "$geom" || return $FAILURE
327
328	# geom associated variables
329	local geom_name geom_consumer provider_ref geom_provider=
330	local provider_geom provider_config provider_class=
331	local provider_config_type catalog_struct catalog_type
332	local disk_ident
333
334	# gnop(8)/geli(8) associated variables (p for `parent device')
335	local p_devname p_geom p_consumer p_provider_ref p_provider
336	local p_provider_config p_provider_geom p_provider_class
337
338	# md(4) associated variables
339	local config config_type config_file magic=
340
341	# Temporarily disable debugging to keep debug output light
342	local old_debug="$debug" debug=
343
344	#
345	# Get the GEOM name (for use below in device registration)
346	#
347	$geom get name devname || continue
348
349	#
350	# Attempt to get the consumer, provider, provider config, and
351	# provider class for this geom (errors ignored).
352	#
353	# NB: Each GEOM in the `DEV' class should have one consumer.
354	#     That consumer should have a reference to its provider.
355	#
356	$geom get consumer1 geom_consumer
357	f_struct "$geom_consumer" get provider_ref provider_ref &&
358		f_geom_find_by id "$provider_ref" provider geom_provider
359	if f_struct "$geom_provider"; then
360		$geom_provider get config provider_config
361		f_geom_parent $geom_provider provider_geom &&
362			f_geom_parent $provider_geom provider_class
363	fi
364
365	#
366	# Get values for device registration (errors ignored)
367	#
368	f_struct "$provider_class"  get name      type
369	f_struct "$geom_provider"   get mediasize capacity
370	f_struct "$provider_config" get descr     desc
371
372	#
373	# For gnop(8), geli(8), or combination thereof, change device type to
374	# that of the consumer
375	#
376	p_devname= p_geom= p_provider= p_provider_config=
377	case "$devname" in
378	*.nop.eli) p_devname="${devname%.nop.eli}" ;;
379	*.eli.nop) p_devname="${devname%.eli.nop}" ;;
380	*.eli)     p_devname="${devname%.eli}" ;;
381	*.nop)     p_devname="${devname%.nop}" ;;
382	esac
383	[ "$p_devname" ] && f_geom_find "$p_devname" $GEOM_CLASS_DEV p_geom
384	if [ "${p_geom:-$geom}" != "$geom" ]; then
385		f_struct "$p_geom" get consumer1 p_consumer
386		f_struct "$p_consumer" get provider_ref p_provider_ref &&
387			f_geom_find_by id "$p_provider_ref" provider p_provider
388		if f_struct "$p_provider"; then
389			$p_provider get config p_provider_config
390			f_geom_parent $p_provider p_provider_geom &&
391				f_geom_parent $p_provider_geom p_provider_class
392		fi
393		f_struct "$p_provider_class" get name type
394	fi
395
396	# Look up geom device in device catalog for default description
397	f_device_catalog_get \
398		$DEVICE_TYPE_ANY "${p_devname:-$devname}" catalog_struct
399	[ "$desc" ] || f_struct "catalog_device_$catalog_struct" get desc desc
400
401	# Use device catalog entry for potential re-classification(s)
402	f_struct "catalog_device_$catalog_struct" get type catalog_type
403
404	# Restore debugging for this next part (device registration)
405	debug="$old_debug"
406
407	#
408	# Register the device
409	#
410	local retval device
411	case "$type" in
412	$GEOM_CLASS_DISK)
413		# First attempt to classify by device catalog (see MAIN)
414		case "$catalog_type" in
415		$DEVICE_TYPE_CDROM)
416			f_dprintf "Found CDROM device for disk %s" "$devname"
417			debug= f_device_register device "$devname" "$desc" \
418				"/dev/$devname" $DEVICE_TYPE_CDROM 1 \
419				f_media_init_cdrom f_media_get_cdrom \
420				f_media_shutdown_cdrom "" "$capacity" &&
421				return $SUCCESS
422			;;
423		esac
424
425		# Fall back to register label device as a disk and taste it
426		f_dprintf "Found disk device named %s" "$devname"
427		debug= f_struct "$p_provider_config" get \
428			ident disk_ident ||
429			debug= f_struct "$provider_config" get \
430				ident disk_ident
431		debug= f_device_register device "$devname" "$desc" \
432			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
433			"" "" "" "$disk_ident" "$capacity"
434		retval=$?
435
436		# Detect ``dangerously dedicated'' filesystems (errors ignored)
437		f_device_probe_disk_fs device "$devname" "$capacity" &&
438			retval=$SUCCESS
439
440		return $retval
441		;;
442	$GEOM_CLASS_LABEL)
443		: fall through to below section # reduces indentation level
444		;;
445	$GEOM_CLASS_MD)
446		f_dprintf "Found disk device named %s" "$devname"
447		debug= f_device_register device "$devname" "$desc" \
448			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
449			"" "" "" "" "$capacity"
450		retval=$?
451
452		#
453		# Attempt to get file(1) magic to potentially classify as
454		# alternate media type. If unable to get magic, fall back to
455		# md(4) characteristics (such as vnode filename).
456		#
457		[ -r "/dev/$devname" ] &&
458			magic=$( file -bs "/dev/$devname" 2> /dev/null )
459		if [ ! "$magic" ]; then
460			# Fall back to md(4) characteristics
461			if f_struct "$p_provider_config"; then
462				config="$p_provider_config"
463			else
464				config="$provider_config"
465			fi
466			debug= f_struct "$config" get type config_type
467			debug= f_struct "$config" get file config_file
468
469			# Substitute magic for below based on type and file
470			case "$config_type=$config_file" in
471			vnode=*.iso) magic="ISO 9660" ;;
472			esac
473		fi
474		f_device_probe_disk_fs device \
475			"$devname" "$capacity" "$magic" &&
476			retval=$SUCCESS # Errors ignored
477
478		return $retval
479		;;
480	$GEOM_CLASS_PART)
481		if f_struct "$p_provider_config"; then
482			config="$p_provider_config"
483		else
484			config="$provider_config"
485		fi
486		debug= f_struct "$config" get type provider_config_type
487		f_device_probe_geom_part device \
488			"$provider_config_type" "$devname" "$capacity"
489		retval=$?
490		device_type=$DEVICE_TYPE_NONE
491		[ $retval -eq $SUCCESS ] &&
492			debug= f_struct "$device" get type device_type
493
494		# Potentially re-classify as USB device
495		if [ "$device_type" = "$DEVICE_TYPE_UFS" -a \
496		     "$catalog_type" = "$DEVICE_TYPE_USB" ]
497		then
498			f_dprintf "Found USB device for partition %s" \
499				  "$devname"
500			debug= f_struct "$p_provider_geom" get \
501				name disk_name ||
502				debug= f_struct "$provider_geom" get \
503					name disk_name
504			debug= f_device_register device "$devname" "$desc" \
505				"/dev/$devname" $DEVICE_TYPE_USB 1 \
506				f_media_init_usb f_media_get_usb \
507				f_media_shutdown_usb "$disk_name" "$capacity"
508			retval=$?
509		fi
510
511		return $retval
512		;;
513	$GEOM_CLASS_RAID)
514		# Use the provider geom name as the description
515		if [ ! "$desc" ]; then
516			f_struct "$p_provider_geom" get name desc ||
517				f_struct "$provider_geom" get name desc
518		fi
519
520		f_dprintf "Found disk device named %s" "$devname"
521		debug= f_device_register device \
522			"$devname" "${desc:-GEOM RAID device}" \
523			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
524			"" "" "" "" "$capacity"
525		retval=$?
526
527		# Detect ``dangerously dedicated'' filesystems
528		f_device_probe_disk_fs device "$devname" "$capacity" &&
529			retval=$SUCCESS # Errors ignored
530
531		return $retval
532		;;
533	$GEOM_CLASS_ZFS_ZVOL)
534		f_dprintf "Found disk device named %s" "$devname"
535		debug= f_device_register device \
536			"$devname" "${desc:-GEOM ZFS::ZVOL device}" \
537			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
538			"" "" "" "" "$capacity"
539		retval=$?
540
541		# Detect ``dangerously dedicated'' filesystems
542		f_device_probe_disk_fs device "$devname" "$capacity" &&
543			retval=$SUCCESS # Errors ignored
544
545		return $retval
546		;;
547	*)
548		return $FAILURE # Unknown GEOM class
549	esac
550
551	#
552	# Still here? Must be $GEOM_CLASS_LABEL
553	#
554
555	local label_geom label_devname label_devgeom= label_devconsumer
556	local label_devprovider= label_devprovider_ref label_devprovider_config
557	local label_gpart_type
558
559	if f_struct "$p_provider"; then
560		label_geom="$p_provider_geom"
561	else
562		label_geom="$provider_geom"
563	fi
564
565	case "$devname" in
566	gpt/*|gptid/*)
567		#
568		# Attempt to get the partition type by getting the `config'
569		# member of the provider for our device (which is named in the
570		# parent geom of our current provider).
571		#
572		debug= f_struct "$label_geom" get name label_devname &&
573			debug= f_geom_find "$label_devname" $GEOM_CLASS_DEV \
574				label_devgeom
575		debug= f_struct "$label_devgeom" get \
576			consumer1 label_devconsumer
577		debug= f_struct "$label_devconsumer" get \
578			provider_ref label_devprovider_ref &&
579			debug= f_geom_find_by id "$label_devprovider_ref" \
580				provider label_devprovider
581		debug= f_struct "$label_devprovider" get \
582			config label_devprovider_config
583		debug= f_struct "$label_devprovider_config" get \
584			type label_gpart_type
585
586		#
587		# Register device label based on partition type
588		#
589		f_device_probe_geom_part device \
590			"$label_gpart_type" "$devname" "$capacity"
591		return $?
592		;;
593	iso9660/*)
594		f_dprintf "Found CDROM device labeled %s" "$devname"
595		debug= f_device_register device \
596			"$devname" "ISO9660 file system" \
597			"/dev/$devname" $DEVICE_TYPE_CDROM 1 \
598			f_media_init_cdrom f_media_get_cdrom \
599			f_media_shutdown_cdrom "" "$capacity"
600		return $?
601		;;
602	label/*)
603		# For generic labels, use provider geom name as real device
604		debug= f_struct "$label_geom" get name label_devname
605
606		# Look up label geom device in device catalog for default desc
607		debug= f_device_catalog_get \
608			$DEVICE_TYPE_ANY "$label_devname" catalog_struct
609		[ "$desc" ] || debug= f_struct \
610			"catalog_device_$catalog_struct" get desc desc
611
612		# Use device catalog entry for potential re-classification(s)
613		debug= f_struct "catalog_device_$catalog_struct" get \
614			type catalog_type
615
616		# First attempt to classify by device catalog (see MAIN)
617		case "$catalog_type" in
618		$DEVICE_TYPE_CDROM)
619			f_dprintf "Found CDROM device for disk %s" "$devname"
620			debug= f_device_register device "$devname" "$desc" \
621				"/dev/$devname" $DEVICE_TYPE_CDROM 1 \
622				f_media_init_cdrom f_media_get_cdrom \
623				f_media_shutdown_cdrom "" "$capacity" &&
624				return $SUCCESS
625			;;
626		esac
627
628		# Fall back to register label device as a disk and taste it
629		f_dprintf "Found disk device labeled %s" "$devname"
630		debug= f_device_register device \
631			"$devname" "GEOM LABEL device" \
632			"/dev/$devname" $DEVICE_TYPE_DISK 1 \
633			"" "" "" "" "$capacity"
634		retval=$?
635
636		# Detect ``dangerously dedicated'' filesystems (errors ignored)
637		f_device_probe_disk_fs device "$devname" "$capacity" &&
638			retval=$SUCCESS
639
640		return $retval
641		;;
642	msdosfs/*)
643		f_dprintf "Found DOS partition labeled %s" "$devname"
644		debug= f_device_register device "$devname" "DOS file system" \
645			"/dev/$devname" $DEVICE_TYPE_DOS 1 \
646			f_media_init_dos f_media_get_dos \
647			f_media_shutdown_dos "" "$capacity"
648		return $?
649		;;
650	ufs/*|ufsid/*)
651		f_dprintf "Found UFS partition labeled %s" "$devname"
652		debug= f_device_register device "$devname" "UFS file system" \
653			"/dev/$devname" $DEVICE_TYPE_UFS 1 \
654			f_media_init_ufs f_media_get_ufs \
655			f_media_shutdown_ufs "" "$capacity"
656		return $?
657		;;
658	ext2fs/*|ntfs/*|reiserfs/*)
659		return $FAILURE # No media device handlers for these labels
660		;;
661	esac
662
663	# Unable to classify GEOM label
664	return $FAILURE
665}
666
667# f_device_probe_geom_part $var_to_set $gpart_type $devname $capacity [$magic]
668#
669# Given a gpart(8) partition type and a device name, register the device if it
670# is a known partition type that we can handle. If $var_to_set is non-NULL,
671# upon success holds the DEVICE struct name of the registered device.
672#
673# Returns success if the device was successfully registered, failure otherwise.
674#
675f_device_probe_geom_part()
676{
677	local __var_to_set="$1" __gpart_type="$2" __devname="$3"
678	local __capacity="${4:--1}" __magic="$5"
679
680	#
681	# Register device based on partition type
682	# NB: !0 equates to `unused' bsdlabel
683	#
684	case "$__gpart_type" in
685	fat16|fat32)
686		f_dprintf "Found DOS partition named %s" "$__devname"
687		debug= f_device_register "$__var_to_set" \
688			"$__devname" "DOS file system" \
689			"/dev/$__devname" $DEVICE_TYPE_DOS 1 \
690			f_media_init_dos f_media_get_dos \
691			f_media_shutdown_dos "" "$__capacity"
692		return $?
693		;;
694	freebsd|!0) # Commonly used inappropriately, taste for FreeBSD
695		[ -r "/dev/$__devname" -a ! "$__magic" ] &&
696			__magic=$( file -bs "/dev/$__devname" 2> /dev/null )
697		case "$__magic" in
698		*"Unix Fast File system"*)
699			f_dprintf "Found UFS partition named %s" "$__devname"
700			debug= f_device_register "$__var_to_set" \
701				"$__devname" "UFS file system" \
702				"/dev/$__devname" $DEVICE_TYPE_UFS 1 \
703				f_media_init_ufs f_media_get_ufs \
704				f_media_shutdown_ufs "" "$__capacity"
705			return $?
706		esac
707		return $FAILURE
708		;;
709	freebsd-ufs)
710		f_dprintf "Found UFS partition named %s" "$__devname"
711		debug= f_device_register "$__var_to_set" \
712			"$__devname" "UFS file system" \
713			"/dev/$__devname" $DEVICE_TYPE_UFS 1 \
714			f_media_init_ufs f_media_get_ufs \
715			f_media_shutdown_ufs "" "$__capacity"
716		return $?
717		;;
718	apple-*|linux-*|ms-*|netbsd-*|ntfs|vmware-*)
719		return $FAILURE # No device types for these
720		;;
721	bios-*|ebr|efi|mbr|freebsd-boot|freebsd-swap)
722		return $FAILURE # Not a source for media
723		;;
724	freebsd-nandfs|freebsd-vinum|freebsd-zfs)
725		return $FAILURE # Unsupported as media source
726		;;
727	esac
728
729	return $FAILURE # Unknown partition type
730}
731
732# f_device_probe_disk_fs $var_to_set $devname [$capacity [$magic]]
733#
734# Given a device name, taste it and register the device if it is a so-called
735# ``dangerously dedicated'' file system written without a partition table.
736# Tasting is done using file(1) (specifically `file -bs') but if $magic is
737# present and non-NULL it is used instead. If $var_to_set is non-NULL, upon
738# success holds the DEVICE struct name of the registered device.
739#
740# Returns success if the device was successfully registered, failure otherwise.
741#
742f_device_probe_disk_fs()
743{
744	local __var_to_set="$1" __devname="$2" __capacity="${3:--1}"
745	local __magic="$4"
746
747	[ -r "/dev/${__devname#/dev/}" -a ! "$__magic" ] &&
748		__magic=$( file -bs "/dev/$__devname" 2> /dev/null )
749
750	case "$__magic" in
751	*"ISO 9660"*)
752		f_dprintf "Found CDROM device for disk %s" "$__devname"
753		debug= f_device_register "$__var_to_set" \
754			"$__devname" "ISO9660 file system" \
755			"/dev/$__devname" $DEVICE_TYPE_CDROM 1 \
756			f_media_init_cdrom f_media_get_cdrom \
757			f_media_shutdown_cdrom "" "$__capacity"
758		return $?
759		;;
760	*"Unix Fast File system"*)
761		f_dprintf "Found UFS device for disk %s" "$__devname"
762		debug= f_device_register "$__var_to_set" \
763			"$__devname" "UFS file system" \
764			"/dev/$__devname" $DEVICE_TYPE_UFS 1 \
765			f_media_init_ufs f_media_get_ufs \
766			f_media_shutdown_ufs "" "$__capacity"
767		return $?
768		;;
769	*"FAT (12 bit)"*|*"FAT (16 bit)"*|*"FAT (32 bit)"*)
770		f_dprintf "Found DOS device for disk %s" "$__devname"
771		debug= f_device_register "$__var_to_set" \
772			"$__devname" "DOS file system" \
773			"/dev/$__devname" $DEVICE_TYPE_DOS 1 \
774			f_media_init_dos f_media_get_dos \
775			f_media_shutdown_dos "" "$__capacity"
776		return $?
777		;;
778	esac
779
780	return $FAILURE # Unknown file system type
781}
782
783# f_device_catalog_get $type $name [$var_to_set]
784#
785# Fetch the struct name of the catalog device matching device $name. If $type
786# is either NULL, missing, or set to $DEVICE_TYPE_ANY then only $name is used.
787# Returns success if a match was found, otherwise failure.
788#
789# If $var_to_set is missing or NULL, the struct name is printed to standard out
790# for capturing in a sub-shell (which is less-recommended because of
791# performance degredation; for example, when called in a loop).
792#
793f_device_catalog_get()
794{
795	local __type="$1" __name="$2" __var_to_set="$3"
796	local __dname=
797
798	# Return failure if no $name
799	[ "$__name" ] || return $FAILURE
800
801	# Disable debugging to keep debug output light
802	local debug=
803
804	#
805	# Attempt to create an alternate-form of $__name that contains the
806	# first contiguous string of numbers replaced with `%d' for comparison
807	# against stored pattern names (see MAIN).
808	#
809	local __left="${__name%%[0-9]*}" __right="${__name#*[0-9]}"
810	if [ "$__left" != "$__name" ]; then
811		# Chop leading digits from right 'til we hit first non-digit
812		while :; do
813			case "$__right" in
814			[0-9]*) __right="${__right#[0-9]}" ;;
815			     *) break
816			esac
817		done
818		__dname="${__left}%d$__right"
819	fi
820
821	[ "$__type" = "$DEVICE_TYPE_ANY" ] && __type=
822	local __dev __dev_name __dev_type
823	for __dev in $DEVICE_CATALOG; do
824		catalog_device_$__dev get name __dev_name
825		[ "$__dev_name" = "$__name" -o "$__dev_name" = "$__dname" ] ||
826			continue
827		catalog_device_$__dev get type __dev_type
828		[ "${__type:-$__dev_type}" = "$__dev_type" ] || continue
829		if [ "$__var_to_set" ]; then
830			setvar "$__var_to_set" $__dev
831		else
832			echo $__dev
833		fi
834		return $?
835	done
836
837	[ "$__var_to_set" ] && setvar "$__var_to_set" ""
838	return $FAILURE
839}
840
841# f_device_catalog_set $type $name $desc
842#
843# Store a description (desc) in-association with device $type and $name.
844# Returns success unless $name is NULL or missing. Use f_device_catalog_get()
845# routine with the same $name and optionally $type to retrieve catalog device
846# structure (see CATALOG_DEVICE struct definition in GLOBALS section).
847#
848f_device_catalog_set()
849{
850	local type="$1" name="$2" desc="$3"
851	local struct dev dev_type found=
852
853	[ "$name" ] || return $FAILURE
854
855	# Disable debugging to keep debug output light
856	local debug=
857
858	f_str2varname "$name" struct
859	if [ ! "$DEVICE_CATALOG_APPEND_ONLY" ]; then
860		for dev in $DEVICE_CATALOG; do
861			[ "$dev" = "$struct" ] || continue
862			found=1 break
863		done
864	fi
865	if [ "$found" ]; then
866		f_struct_free "catalog_device_$struct"
867	else
868		DEVICE_CATALOG="$DEVICE_CATALOG $struct"
869	fi
870	f_struct_new CATALOG_DEVICE "catalog_device_$struct" || return $FAILURE
871	catalog_device_$struct set type "$type"
872	catalog_device_$struct set name "$name"
873	catalog_device_$struct set desc "$desc"
874	return $SUCCESS
875}
876
877# f_device_desc $device_name $device_type [$var_to_set]
878#
879# Print a description for a device name (eg., `fxp0') given a specific device
880# type/class.
881#
882# If $var_to_set is missing or NULL, the device description is printed to
883# standard out for capturing in a sub-shell (which is less-recommended because
884# of performance degredation; for example, when called in a loop).
885#
886f_device_desc()
887{
888	local __name="$1" __type="$2" __var_to_set="$3"
889	local __devname __devunit __cp
890
891	# Check variables
892	[ "$__name" ] || return $SUCCESS
893	[ "$__type" = "$DEVICE_TYPE_ANY" ] && type=
894	[ "$__var_to_set" ] && { setvar "$__var_to_set" "" || return; }
895
896	#
897	# Return sysctl MIB dev.NAME.UNIT.%desc if it exists, otherwise fall
898	# through to further alternate methods.
899	#
900	if f_have sysctl; then
901		__devname="${__name%%[0-9]*}"
902		__devunit="${__name#$__devname}"
903		__devunit="${__devunit%%[!0-9]*}"
904		if [ "$__var_to_set" ]; then
905			if __cp=$(
906				sysctl -n "dev.$__devname.$__devunit.%desc" \
907				2> /dev/null
908			); then
909				setvar "$__var_to_set" "$__cp" &&
910					return $SUCCESS
911			fi
912		else
913			sysctl -n "dev.$__devname.$__devunit.%desc" \
914				2> /dev/null && return $SUCCESS
915		fi
916	fi
917
918	# Look up device in catalog for default description
919	local __catalog_struct
920	debug= f_device_catalog_get "$__type" "$__name" __catalog_struct
921	debug= f_struct "catalog_device_$__catalog_struct" get \
922		desc "$__var_to_set" && return $SUCCESS
923
924	#
925	# Sensible fall-backs for specific types
926	#
927	case "$__type" in
928	$DEVICE_TYPE_CDROM)   __cp="<unknown cdrom device type>" ;;
929	$DEVICE_TYPE_DISK)    __cp="<unknown disk device type>" ;;
930	$DEVICE_TYPE_USB)     __cp="<unknown USB storage device type>" ;;
931	$DEVICE_TYPE_NETWORK) __cp="<unknown network interface type>" ;;
932	*)
933		__cp="<unknown device type>"
934	esac
935
936	if [ "$__var_to_set" ]; then
937		setvar "$__var_to_set" "$__cp"
938	else
939		echo "$__cp"
940	fi
941
942	return $FAILURE
943}
944
945# f_device_is_ethernet $device
946#
947# Returns true if $device is a wired Ethernet network interface. Otherwise
948# returns false. Example wired interfaces include: fxp0 em0 bge0 rl0 etc.
949#
950f_device_is_ethernet()
951{
952	local dev="$1" type flags
953
954	# Make sure we have an actual device by that name
955	f_struct "$dev" || return $FAILURE
956
957	# Make sure that the device is a network device
958	$dev get type type
959	[ "$type" = "$DEVICE_TYPE_NETWORK" ] || return $FAILURE
960
961	# Make sure that the media flags indicate that it is Ethernet
962	$dev get flags flags
963	[ $(( ${flags:-0} & $IF_ETHERNET )) -eq $IF_ETHERNET ]
964}
965
966# f_device_is_wireless $device
967#
968# Returns true if $device is a Wireless network interface. Otherwise returns
969# false. Examples of wireless interfaces include: iwn0
970#
971f_device_is_wireless()
972{
973	local dev="$1" type flags
974
975	# Make sure we have an actual device by that name
976	f_struct "$dev" || return $FAILURE
977
978	# Make sure that the device is a network device
979	$dev get type type
980	[ "$type" = "$DEVICE_TYPE_NETWORK" ] || return $FAILURE
981
982	# Make sure that the media flags indicate that it is 802.11 wireless
983	$dev get flags flags
984	[ $(( ${flags:-0} & $IF_WIRELESS )) -eq $IF_WIRELESS ]
985}
986
987# f_device_is_active $device
988#
989# Returns true if $device is active. Otherwise returns false. Currently this
990# only works for network interfaces.
991#
992f_device_is_active()
993{
994	local dev="$1" type flags=0
995
996	# Make sure we have an actual device by that name
997	f_struct "$dev" || return $FAILURE
998
999	$dev get type type
1000	case "$type" in
1001	$DEVICE_TYPE_NETWORK)
1002		# Make sure that the media flags indicate that it is active
1003		$dev get flags flags
1004		[ $(( ${flags:-0} & $IF_ACTIVE )) -eq $IF_ACTIVE ]
1005		;;
1006	*)
1007		return $FAILURE
1008	esac
1009}
1010
1011# f_device_find [-1] $name [$type [$var_to_set]]
1012#
1013# Find one or more registered devices by name, type, or both. Returns a space-
1014# separated list of devices matching the search criterion.
1015#
1016# If `-1' option flag is given, only the first matching device is returned.
1017#
1018# If $var_to_set is missing or NULL, the device name(s) are printed to standard
1019# out for capturing in a sub-shell (which is less-recommended because of
1020# performance degredation; for example, when called in a loop).
1021#
1022f_device_find()
1023{
1024	local OPTIND=1 OPTARG flag only_one=
1025	while getopts 1 flag; do
1026		case "$flag" in
1027		1) only_one=1 ;;
1028		esac
1029	done
1030	shift $(( $OPTIND - 1 ))
1031
1032	local __name="$1" __type="${2:-$DEVICE_TYPE_ANY}" __var_to_set="$3"
1033	local __n=1 __devname __devtype __found=
1034	while [ $__n -le $NDEVICES ]; do
1035		device_$__n get name __devname
1036		device_$__n get type __devtype
1037		if [ "$__name" = "$__devname" -o ! "$__name" ] &&
1038		   [ "$__type" = "$DEVICE_TYPE_ANY" -o \
1039		     "$__type" = "$__devtype" ]
1040		then
1041			__found="$__found device_$__n"
1042			[ "$only_one" ] && break
1043		fi
1044		__n=$(( $__n + 1 ))
1045	done
1046
1047	if [ "$__var_to_set" ]; then
1048		setvar "$__var_to_set" "${__found# }"
1049	else
1050		echo $__found
1051	fi
1052	[ "$__found" ] # Return status
1053}
1054
1055# f_device_init $device
1056#
1057# Initialize a device by evaluating its `init' function. The $device argument
1058# is a DEVICE struct name.
1059#
1060f_device_init()
1061{
1062	local device="$1" init_func
1063	f_struct "$device" || return $?
1064	$device get init init_func
1065	${init_func:-:} "$device"
1066}
1067
1068# f_device_get $device $file [$probe]
1069#
1070# Read $file by evaluating the device's `get' function. The file is commonly
1071# produced on standard output (but it truly depends on the function called).
1072# The $device argument is a DEVICE struct name.
1073#
1074f_device_get()
1075{
1076	local device="$1" file="$2" probe="$3" get_func
1077	f_struct "$device" || return $?
1078	$device get get get_func
1079	${get_func:-:} "$device" "$file" ${3+"$probe"}
1080}
1081
1082# f_device_shutdown $device
1083#
1084# Shutdown a device by evaluating its `shutdown' function. The $device argument
1085# is a DEVICE struct name.
1086#
1087f_device_shutdown()
1088{
1089	local device="$1" shutdown_func
1090	f_struct "$device" || return $?
1091	$device get shutdown shutdown_func
1092	${shutdown_func:-:} "$device"
1093}
1094
1095# f_devices_sort_by $property $var_to_get [$var_to_set]
1096#
1097# Take list of devices from $var_to_get (separated by whitespace, newline
1098# included) and sort them by $property (e.g., `name'). The sorted list of
1099# DEVICE struct names is returned on standard output separated by whitespace
1100# (newline to be specific) unless $var_to_set is present and non-NULL.
1101#
1102# This function is a two-parter. Below is the awk(1) portion of the function,
1103# afterward is the sh(1) function which utilizes the below awk script.
1104#
1105f_device_sort_by_awk='
1106# Variables that should be defined on the invocation line:
1107# 	-v prop="property"
1108function _asorti(src, dest)
1109{
1110	k = nitems = 0
1111	for (i in src) dest[++nitems] = i
1112	for (i = 1; i <= nitems; k = i++) {
1113		idx = dest[i]
1114		while ((k > 0) && (dest[k] > idx)) {
1115			dest[k+1] = dest[k]; k--
1116		}
1117		dest[k+1] = idx
1118	}
1119	return nitems
1120}
1121{
1122	split($0, devs, FS)
1123	for (d in devs) {
1124		name = ENVIRON["_struct_value_" devs[d] "_" prop]
1125		devices[name] = devs[d]
1126	}
1127}
1128END {
1129	nitems = _asorti(devices, devices_sorted)
1130	for (i = 1; i <= nitems; i++) print devices[devices_sorted[i]]
1131}
1132'
1133f_device_sort_by()
1134{
1135	local __property="${1:-name}" __var_to_get="$2" __var_to_set="$3"
1136
1137	f_isset "$__var_to_get" || return $FAILURE
1138
1139	local __dev
1140	for __dev in $( f_getvar "$__var_to_get" ); do
1141		export _struct_value_${__dev}_$__property
1142	done
1143
1144	local __cp
1145	setvar "${__var_to_set:-__cp}" "$(
1146		f_getvar "$__var_to_get" |
1147			awk -v prop="$__property" "$f_device_sort_by_awk"
1148	)"
1149	[ "$__var_to_set" ] || echo "$__cp"
1150}
1151
1152# f_device_menu $title $prompt $hline $device_type [$helpfile]
1153#
1154# Display a menu listing all the devices of a certain type in the system.
1155#
1156f_device_menu()
1157{
1158	f_dialog_title "$1"
1159	local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
1160	f_dialog_title_restore
1161
1162	local prompt="$2" hline="$3" type="$4" helpfile="$5"
1163
1164	local devs
1165	f_device_find "" "$type" devs || return $DIALOG_CANCEL
1166
1167	local name desc menu_list=
1168	f_device_sort_by name devs devs
1169	for dev in $devs; do
1170		$dev get name name
1171		$dev get desc desc
1172		f_shell_escape "$name" name
1173		f_shell_escape "$desc" desc
1174		menu_list="$menu_list
1175			'$name' '$desc'" # END-QUOTE
1176	done
1177	menu_list="${menu_list#$NL}"
1178
1179	local height width rows
1180	eval f_dialog_menu_size height width rows \
1181	                        \"\$title\"  \
1182	                        \"\$btitle\" \
1183	                        \"\$prompt\" \
1184	                        \"\$hline\"  \
1185	                        $menu_list
1186
1187	local errexit=
1188	case $- in *e*) errexit=1; esac
1189	set +e
1190
1191	local mtag
1192	while :; do
1193		mtag=$( eval $DIALOG \
1194			--title \"\$title\"             \
1195			--backtitle \"\$btitle\"        \
1196			--hline \"\$hline\"             \
1197			--ok-label \"\$msg_ok\"         \
1198			--cancel-label \"\$msg_cancel\" \
1199			${helpfile:+                    \
1200			  --help-button                 \
1201			  --help-label \"\$msg_help\"   \
1202			  ${USE_XDIALOG:+--help \"\"}   \
1203			}                               \
1204			--menu \"\$prompt\"             \
1205			$height $width $rows            \
1206			$menu_list                      \
1207			2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
1208		)
1209		local retval=$?
1210
1211		[ $retval -ne $DIALOG_HELP ] && break
1212			# Otherwise, the Help button was pressed
1213		f_show_help "$helpfile"
1214			# ...then loop back to menu
1215	done
1216	f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
1217
1218	[ "$errexit" ] && set -e
1219
1220	if [ $retval -eq $DIALOG_OK ]; then
1221		# Clean up the output of [X]dialog(1)
1222		f_dialog_data_sanitize mtag
1223
1224		# Map the user's choice back to a struct name
1225		local index device
1226		index=$( eval f_dialog_menutag2index \"\$mtag\" $menu_list )
1227		device=$( set -- $devs; eval echo \${$index} )
1228
1229		echo "$device" >&2
1230	fi
1231
1232	return $retval
1233}
1234
1235#
1236# Short-hand
1237#
1238f_cdrom()   { f_device_catalog_set $DEVICE_TYPE_CDROM   "$1" "$2"; }
1239f_disk()    { f_device_catalog_set $DEVICE_TYPE_DISK    "$1" "$2"; }
1240f_usb()     { f_device_catalog_set $DEVICE_TYPE_USB     "$1" "$2"; }
1241f_network() { f_device_catalog_set $DEVICE_TYPE_NETWORK "$1" "$2"; }
1242
1243############################################################ MAIN
1244
1245#
1246# The below classifications allow us to re-group the GEOM devices from the
1247# `DEV' GEOM class appropriately while providing fall-back descriptions both
1248# for making the below code more maintainable and handling the rare case the
1249# GEOM device lacks a description.
1250#
1251
1252DEVICE_CATALOG_APPEND_ONLY=1 # Make initial loading faster
1253
1254# CDROM, Disk, and USB devices/names
1255f_cdrom  "cd%d"   "SCSI CDROM drive"
1256f_cdrom  "mcd%d"  "Mitsumi (old model) CDROM drive"
1257f_cdrom  "scd%d"  "Sony CDROM drive - CDU31/33A type"
1258f_disk   "aacd%d" "Adaptec FSA RAID array"
1259f_disk   "ada%d"  "ATA/SATA disk device"
1260f_disk   "amrd%d" "AMI MegaRAID drive"
1261f_disk   "da%d"   "SCSI disk device"
1262f_disk   "idad%d" "Compaq RAID array"
1263f_disk   "ipsd%d" "IBM ServeRAID RAID array"
1264f_disk   "md%d"   "md(4) disk device"
1265f_disk   "mfid%d" "LSI MegaRAID SAS array"
1266f_disk   "mlxd%d" "Mylex RAID disk"
1267f_disk   "twed%d" "3ware ATA RAID array"
1268f_disk   "vtbd%d" "VirtIO Block Device"
1269f_usb    "da%da"  "USB Mass Storage Device"
1270
1271# Network interfaces/names
1272f_network "ae%d"    "Attansic/Atheros L2 Fast Ethernet"
1273f_network "age%d"   "Attansic/Atheros L1 Gigabit Ethernet"
1274f_network "alc%d"   "Atheros AR8131/AR8132 PCIe Ethernet"
1275f_network "ale%d"   "Atheros AR8121/AR8113/AR8114 PCIe Ethernet"
1276f_network "an%d"    "Aironet 4500/4800 802.11 wireless adapter"
1277f_network "ath%d"   "Atheros IEEE 802.11 wireless adapter"
1278f_network "aue%d"   "ADMtek USB Ethernet adapter"
1279f_network "axe%d"   "ASIX Electronics USB Ethernet adapter"
1280f_network "bce%d"   "Broadcom NetXtreme II Gigabit Ethernet card"
1281f_network "bfe%d"   "Broadcom BCM440x PCI Ethernet card"
1282f_network "bge%d"   "Broadcom BCM570x PCI Gigabit Ethernet card"
1283f_network "bm%d"    "Apple BMAC Built-in Ethernet"
1284f_network "bwn%d"   "Broadcom BCM43xx IEEE 802.11 wireless adapter"
1285f_network "cas%d"   "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"
1286f_network "cc3i%d"  "SDL HSSI sync serial PCI card"
1287f_network "cue%d"   "CATC USB Ethernet adapter"
1288f_network "cxgb%d"  "Chelsio T3 10Gb Ethernet card"
1289f_network "dc%d"    "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"
1290f_network "de%d"    "DEC DE435 PCI NIC or other DC21040-AA based card"
1291f_network "disc%d"  "Software discard network interface"
1292f_network "ed%d"    "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"
1293f_network "el%d"    "3Com 3C501 Ethernet card"
1294f_network "em%d"    "Intel(R) PRO/1000 Ethernet card"
1295f_network "ep%d"    "3Com 3C509 Ethernet card/3C589 PCMCIA"
1296f_network "et%d"    "Agere ET1310 based PCI Express Gigabit Ethernet card"
1297f_network "ex%d"    "Intel EtherExpress Pro/10 Ethernet card"
1298f_network "fe%d"    "Fujitsu MB86960A/MB86965A Ethernet card"
1299f_network "fpa%d"   "DEC DEFPA PCI FDDI card"
1300f_network "fwe%d"   "FireWire Ethernet emulation"
1301f_network "fwip%d"  "IP over FireWire"
1302f_network "fxp%d"   "Intel EtherExpress Pro/100B PCI Fast Ethernet card"
1303f_network "gem%d"   "Apple GMAC or Sun ERI/GEM Ethernet adapter"
1304f_network "hme%d"   "Sun HME (Happy Meal Ethernet) Ethernet adapter"
1305f_network "ie%d"    "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"
1306f_network "igb%d"   "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"
1307f_network "ipw%d"   "Intel PRO/Wireless 2100 IEEE 802.11 adapter"
1308f_network "iwi%d"   "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"
1309f_network "iwn%d"   "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"
1310f_network "ix%d"    "Intel Etherexpress Ethernet card"
1311f_network "ixgbe%d" "Intel(R) PRO/10Gb Ethernet card"
1312f_network "jme%d"   "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"
1313f_network "kue%d"   "Kawasaki LSI USB Ethernet adapter"
1314f_network "le%d"    "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"
1315f_network "lge%d"   "Level 1 LXT1001 Gigabit Ethernet card"
1316f_network "lnc%d"   "Lance/PCnet (Isolan/Novell NE2100/NE32-VL) Ethernet"
1317f_network "lo%d"    "Loop-back (local) network interface"
1318f_network "lp%d"    "Parallel Port IP (PLIP) peer connection"
1319f_network "malo%d"  "Marvell Libertas 88W8335 802.11 wireless adapter"
1320f_network "msk%d"   "Marvell/SysKonnect Yukon II Gigabit Ethernet"
1321f_network "mxge%d"  "Myricom Myri10GE 10Gb Ethernet card"
1322f_network "nfe%d"   "NVIDIA nForce MCP Ethernet"
1323f_network "ng%d"    "Vimage netgraph(4) bridged Ethernet device"
1324f_network "nge%d"   "NatSemi PCI Gigabit Ethernet card"
1325f_network "nve%d"   "NVIDIA nForce MCP Ethernet"
1326f_network "pcn%d"   "AMD Am79c79x PCI Ethernet card"
1327f_network "plip%d"  "Parallel Port IP (PLIP) peer connection"
1328f_network "ral%d"   "Ralink Technology IEEE 802.11 wireless adapter"
1329f_network "ray%d"   "Raytheon Raylink 802.11 wireless adapter"
1330f_network "re%d"    "RealTek 8139C+/8169/8169S/8110S PCI Ethernet adapter"
1331f_network "rl%d"    "RealTek 8129/8139 PCI Ethernet card"
1332f_network "rue%d"   "RealTek USB Ethernet card"
1333f_network "rum%d"   "Ralink Technology USB IEEE 802.11 wireless adapter"
1334f_network "sf%d"    "Adaptec AIC-6915 PCI Ethernet card"
1335f_network "sge%d"   "Silicon Integrated Systems SiS190/191 Ethernet"
1336f_network "sis%d"   "SiS 900/SiS 7016 PCI Ethernet card"
1337f_network "sk%d"    "SysKonnect PCI Gigabit Ethernet card"
1338f_network "sn%d"    "SMC/Megahertz Ethernet card"
1339f_network "snc%d"   "SONIC Ethernet card"
1340f_network "sr%d"    "SDL T1/E1 sync serial PCI card"
1341f_network "ste%d"   "Sundance ST201 PCI Ethernet card"
1342f_network "stge%d"  "Sundance/Tamarack TC9021 Gigabit Ethernet"
1343f_network "ti%d"    "Alteon Networks PCI Gigabit Ethernet card"
1344f_network "tl%d"    "Texas Instruments ThunderLAN PCI Ethernet card"
1345f_network "tx%d"    "SMC 9432TX Ethernet card"
1346f_network "txp%d"   "3Com 3cR990 Ethernet card"
1347f_network "uath%d"  "Atheros AR5005UG and AR5005UX USB wireless adapter"
1348f_network "upgt%d"  "Conexant/Intersil PrismGT USB wireless adapter"
1349f_network "ural%d"  "Ralink Technology RT2500USB 802.11 wireless adapter"
1350f_network "urtw%d"  "Realtek 8187L USB wireless adapter"
1351f_network "vge%d"   "VIA VT612x PCI Gigabit Ethernet card"
1352f_network "vlan%d"  "IEEE 802.1Q VLAN network interface"
1353f_network "vr%d"    "VIA VT3043/VT86C100A Rhine PCI Ethernet card"
1354f_network "vx%d"    "3COM 3c590 / 3c595 Ethernet card"
1355f_network "wb%d"    "Winbond W89C840F PCI Ethernet card"
1356f_network "wi%d"    "Lucent WaveLAN/IEEE 802.11 wireless adapter"
1357f_network "wpi%d"   "Intel 3945ABG IEEE 802.11 wireless adapter"
1358f_network "wx%d"    "Intel Gigabit Ethernet (82452) card"
1359f_network "xe%d"    "Xircom/Intel EtherExpress Pro100/16 Ethernet card"
1360f_network "xl%d"    "3COM 3c90x / 3c90xB PCI Ethernet card"
1361f_network "zyd%d"   "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"
1362
1363DEVICE_CATALOG_APPEND_ONLY= # Additional loading modifies existing devices
1364
1365f_count NCATALOG_DEVICES $DEVICE_CATALOG
1366f_dprintf "%s: Initialized device catalog with %u names/descriptions." \
1367          device.subr $NCATALOG_DEVICES
1368
1369#
1370# Scan for the above devices unless requeted otherwise
1371#
1372f_dprintf "%s: DEVICE_SELF_SCAN_ALL=[%s]" device.subr "$DEVICE_SELF_SCAN_ALL"
1373case "$DEVICE_SELF_SCAN_ALL" in
1374""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
1375*) f_device_get_all
1376esac
1377
1378f_dprintf "%s: Successfully loaded." device.subr
1379
1380fi # ! $_DEVICE_SUBR
1381