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