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