Deleted Added
full compact
device.subr (251364) device.subr (252112)
1if [ ! "$_DEVICE_SUBR" ]; then _DEVICE_SUBR=1
2#
3# Copyright (c) 2012-2013 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 (INLUDING, 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#
1if [ ! "$_DEVICE_SUBR" ]; then _DEVICE_SUBR=1
2#
3# Copyright (c) 2012-2013 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 (INLUDING, 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: head/usr.sbin/bsdconfig/share/device.subr 251364 2013-06-04 03:47:21Z dteske $
27# $FreeBSD: head/usr.sbin/bsdconfig/share/device.subr 252112 2013-06-23 10:48:26Z dteske $
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/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
43DEVICES=
44DEVICE_NAMES=
45
46# A "device" from sysinstall's point of view
47f_struct_define DEVICE \
48 name \
49 desc \
50 devname \
51 type \
52 enabled \
53 init \
54 get \
55 shutdown \
56 flags \
57 private \
58 volume
59
60# Network devices have their `private' property set to this
61f_struct_define DEVICE_INFO \
62 use_rtsol use_dhcp ipaddr ipv6addr netmask extras
63
64setvar DEVICE_TYPE_NONE 1
65setvar DEVICE_TYPE_DISK 2
66setvar DEVICE_TYPE_FLOPPY 3
67setvar DEVICE_TYPE_FTP 4
68setvar DEVICE_TYPE_NETWORK 5
69setvar DEVICE_TYPE_CDROM 6
70setvar DEVICE_TYPE_USB 7
71setvar DEVICE_TYPE_DOS 8
72setvar DEVICE_TYPE_UFS 9
73setvar DEVICE_TYPE_NFS 10
74setvar DEVICE_TYPE_ANY 11
75setvar DEVICE_TYPE_HTTP_PROXY 12
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/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
43DEVICES=
44DEVICE_NAMES=
45
46# A "device" from sysinstall's point of view
47f_struct_define DEVICE \
48 name \
49 desc \
50 devname \
51 type \
52 enabled \
53 init \
54 get \
55 shutdown \
56 flags \
57 private \
58 volume
59
60# Network devices have their `private' property set to this
61f_struct_define DEVICE_INFO \
62 use_rtsol use_dhcp ipaddr ipv6addr netmask extras
63
64setvar DEVICE_TYPE_NONE 1
65setvar DEVICE_TYPE_DISK 2
66setvar DEVICE_TYPE_FLOPPY 3
67setvar DEVICE_TYPE_FTP 4
68setvar DEVICE_TYPE_NETWORK 5
69setvar DEVICE_TYPE_CDROM 6
70setvar DEVICE_TYPE_USB 7
71setvar DEVICE_TYPE_DOS 8
72setvar DEVICE_TYPE_UFS 9
73setvar DEVICE_TYPE_NFS 10
74setvar DEVICE_TYPE_ANY 11
75setvar DEVICE_TYPE_HTTP_PROXY 12
76setvar DEVICE_TYPE_HTTP 13
76
77#
78# Default behavior is to call f_device_get_all() automatically when loaded.
79#
80: ${DEVICE_SELF_SCAN_ALL=1}
81
82############################################################ FUNCTIONS
83
84# f_device_try $name [$i [$var_path]]
85#
86# Test a particular device. If $i is given, then $name is expected to contain a
87# single "%d" where $i will be inserted using printf. If $var_path is given,
88# it is used as a variable name to provide the caller the device pathname.
89#
90# Returns success if the device path exists and is a cdev.
91#
92f_device_try()
93{
94 local name="$1" i="$2" var_path="$3" unit
95 if [ "$i" ]; then
96 unit=$( printf "$name" "$i" )
97 else
98 unit="$name"
99 fi
100 case "$unit" in
101 /dev/*) : good ;; # already qualified
102 *) unit="/dev/$unit" ;;
103 esac
104 [ "$var_path" ] && setvar "$var_path" "$unit"
105 f_dprintf "f_device_try: making sure %s is a device node" "$unit"
106 if [ -c "$unit" ]; then
107 f_dprintf "f_device_try: %s is a cdev [good]" "$unit"
108 return $SUCCESS
109 else
110 f_dprintf "f_device_try: %s is not a cdev [skip]" "$unit"
111 return $FAILURE
112 fi
113}
114
115# f_device_register $name $desc $devname $type $enabled $init_function \
116# $get_function $shutdown_function $private
117#
118# Register a device. A `structure' (see struct.subr) is created with the name
119# device_$name (so make sure $name contains only alpha-numeric characters or
120# the underscore, `_'). The remaining arguments after $name correspond to the
121# properties of the `DEVICE' structure-type (defined above).
122#
123# If not already registered, the device is then appended to the DEVICES
124# environment variable, a space-separated list of all registered devices.
125#
126f_device_register()
127{
128 local name="$1" desc="$2" devname="$3" type="$4" enabled="$5"
129 local init_func="$6" get_func="$7" shutdown_func="$8" private="$9"
130
131 f_struct_new DEVICE "device_$name" || return $FAILURE
132 device_$name set name "$name"
133 device_$name set desc "$desc"
134 device_$name set devname "$devname"
135 device_$name set type "$type"
136 device_$name set enabled "$enabled"
137 device_$name set init "$init_func"
138 device_$name set get "$get_func"
139 device_$name set shutdown "$shutdown_func"
140 device_$name set private "$private"
141
142 # Scan our global register to see if it needs ammending
143 local dev found=
144 for dev in $DEVICES; do
145 [ "$dev" = "$name" ] || continue
146 found=1 && break
147 done
148 [ "$found" ] || DEVICES="$DEVICES $name"
149
150 return $SUCCESS
151}
152
153# f_device_reset
154#
155# Reset the registered device chain.
156#
157f_device_reset()
158{
159 local dev
160 for dev in $DEVICES; do
161 f_device_shutdown $dev
162
163 #
164 # XXX this potentially leaks $dev->private if it's being
165 # used to point to something dynamic, but you're not supposed
166 # to call this routine at such times that some open instance
167 # has its private member pointing somewhere anyway. XXX
168 #
169 f_struct_free device_$dev
170 done
171 DEVICES=
172}
173
174# f_device_get_all
175#
176# Get all device information for devices we have attached.
177#
178f_device_get_all()
179{
180 local devname desc
181
182 f_dprintf "f_device_get_all: Probing devices..."
183 f_dialog_info "$msg_probing_devices_please_wait_this_can_take_a_while"
184
185 # First go for the network interfaces
186 for devname in $( ifconfig -l ); do
187 # Eliminate network devices that don't make sense
188 case "$devname" in
189 lo*) continue ;;
190 esac
191
192 # Try and find its description
193 f_device_desc "$devname" $DEVICE_TYPE_NETWORK desc
194
195 f_dprintf "Found a network device named %s" "$devname"
196 f_device_register $devname \
197 "$desc" "$devname" $DEVICE_TYPE_NETWORK 1 \
198 f_media_init_network "" f_media_shutdown_network ""
199 done
200
201 # Next, try to find all the types of devices one might use
202 # as a media source for content
203 #
204
205 local dev desc type max n=0
206 for dev in $DEVICE_NAMES; do
207 n=$(( $n + 1 ))
208 # Get the desc, type, and max (with debugging disabled)
209 # NOTE: Bypassing f_device_name_get() for efficiency
210 debug= f_getvar _device_desc$n desc
211 debug= f_getvar _device_type$n type
212 debug= f_getvar _device_max$n max
213
214 local k=0
215 while [ $k -lt ${max:-0} ]; do
216 i=$k k=$(( $k + 1 ))
217 devname=""
218 case "$type" in
219 $DEVICE_TYPE_CDROM)
220 f_device_try "$dev" "$i" devname || continue
221 f_device_register "${devname##*/}" "$desc" \
222 "$devname" $DEVICE_TYPE_CDROM 1 \
223 f_media_init_cdrom f_media_get_cdrom \
224 f_media_shutdown_cdrom ""
225 f_dprintf "Found a CDROM device for %s" \
226 "$devname"
227 ;;
228 $DEVICE_TYPE_FLOPPY)
229 f_device_try "$dev" "$i" devname || continue
230 f_device_register "${devname##*/}" "$desc" \
231 "$devname" $DEVICE_TYPE_FLOPPY 1 \
232 f_media_init_floppy \
233 f_media_get_floppy \
234 f_media_shutdown_floppy ""
235 f_dprintf "Found a floppy device for %s" \
236 "$devname"
237 ;;
238 $DEVICE_TYPE_USB)
239 f_device_try "$dev" "$i" devname || continue
240 f_device_register "${devname##*/}" "$desc" \
241 "$devname" $DEVICE_TYPE_USB 1 \
242 f_media_init_usb f_media_get_usb \
243 f_media_shutdown_usb ""
244 f_dprintf "Found a USB disk for %s" "$devname"
245 ;;
246 esac
247 done
248 done
249
250 # Register ISO9660 providers as CDROM devices
251 for devname in /dev/iso9660/*; do
252 f_device_try "$devname" || continue
253 f_device_register "${devname##*/}" "ISO9660 file system" \
254 "$devname" $DEVICE_TYPE_CDROM 1 \
255 f_media_init_cdrom f_media_get_cdrom \
256 f_media_shutdown_cdrom ""
257 f_dprintf "Found a CDROM device for %s" "$devname"
258 done
259
260 # Scan for mdconfig(8)-created md(4) devices
261 local filename
262 for devname in /dev/md[0-9] /dev/md[0-9][0-9]; do
263 f_device_try "$devname" || continue
264
265 # See if the md(4) device is a vnode type backed by a file
266 filename=$( sysctl kern.geom.conftxt |
267 awk -v devname="${devname##*/}" \
268 '
269 ( $2 == "MD" ) && \
270 ( $3 == devname ) && \
271 ( $(NF-2) == "vnode" ) && \
272 ( $(NF-1) == "file" ) \
273 {
274 print $NF
275 }
276 ' )
277 case "$filename" in
278 *.iso) # Register the device as an ISO9660 provider
279 f_device_register "${devname##*/}" \
280 "md(4) vnode file system" \
281 "$devname" $DEVICE_TYPE_CDROM 1 \
282 f_media_init_cdrom f_media_get_cdrom \
283 f_media_shutdown_cdrom ""
284 f_dprintf "Found a CDROM device for %s" "$devname"
285 ;;
286 esac
287 done
288
289 # Finally go get the disks and look for partitions to register
290 local diskname slices index type rest slice part
291 for diskname in $( sysctl -n kern.disks ); do
292
293 case "$diskname" in
294 cd*)
295 # XXX
296 # Due to unknown reasons, kern.disks returns SCSI
297 # CDROM as a valid disk. This will prevent bsdconfig
298 # from presenting SCSI CDROMs as available disks in
299 # various menus. Why GEOM treats SCSI CDROM as a disk
300 # is beyond me and that should be investigated.
301 # For temporary workaround, ignore SCSI CDROM device.
302 #
303 continue ;;
304 esac
305
306 # Try to create a list of partitions and their types,
307 # consisting of "N,typeN ..." (e.g., "1,0xa5 2,0x06").
308 if ! slices=$( fdisk -p "$diskname" 2> /dev/null |
309 awk '( $1 == "p" ) { print $2","$3 }' )
310 then
311 f_dprintf "Unable to open disk %s" "$diskname"
312 continue
313 fi
314
315 f_device_register "$diskname" "" \
316 "/dev/$diskname" $DEVICE_TYPE_DISK 0
317 f_dprintf "Found a disk device named %s" "$diskname"
318
319 # Look for existing partitions to register
320 for slice in $slices; do
321 index="${slice%%,*}" type="${slice#*,}"
322 slice=${diskname}s$index
323 case "$type" in
324 0x01|0x04|0x06|0x0b|0x0c|0x0e|0xef)
325 # DOS partitions to add as "DOS media devices"
326 f_device_register "$slice" "" \
327 "/dev/$slice" $DEVICE_TYPE_DOS 1 \
328 f_media_init_dos f_media_get_dos \
329 f_media_shutdown_dos ""
330 f_dprintf "Found a DOS partition %s" "$slice"
331 ;;
332 0xa5) # FreeBSD partition
333 for part in $(
334 bsdlabel -r $slice 2> /dev/null |
335 awk -v slice="$slice" '
336 ( $1 ~ /[abdefgh]:/ ) {
337 printf "%s%s\n",
338 slice,
339 substr($1,1,1)
340 }'
341 ); do
342 f_quietly dumpfs -m /dev/$part ||
343 continue
344 f_device_register \
345 "$part" "" "/dev/$part" \
346 $DEVICE_TYPE_UFS 1 \
347 f_media_init_ufs \
348 f_media_get_ufs \
349 f_media_shutdown_ufs ""
350 f_dprintf "Found a UFS partition %s" \
351 "$part"
352 done # parts
353 ;;
354 esac
355 done # slices
356
357 done # disks
358}
359
360# f_device_name_get $type $name type|desc|max [$var_to_set]
361#
362# Fetch the device type (type), description (desc), or maximum number of
363# devices to scan for (max) associated with device $name and $type. If $type is
364# either NULL, missing, or set to $DEVICE_TYPE_ANY then only $name is used.
365# Returns success if a match was found, otherwise failure.
366#
367# If $var_to_set is missing or NULL, the device name is printed to standard out
368# for capturing in a sub-shell (which is less-recommended because of
369# performance degredation; for example, when called in a loop).
370#
371f_device_name_get()
372{
373 local __type="$1" __name="$2" __prop="$3" __var_to_set="$4"
374 local __dev __devtype __n=0
375
376 # Return failure if no $name or $prop is an unknown property
377 [ "$__name" ] || return $FAILURE
378 case "$__prop" in type|desc|max) : good ;;
379 *) return $FAILURE; esac
380
381 [ "$__type" = "$DEVICE_TYPE_ANY" ] && __type=
382 for __dev in $DEVICE_NAMES; do
383 __n=$(( $__n + 1 ))
384 [ "$__dev" = "$__name" ] || continue
385 f_getvar _device_type$__n __devtype
386 [ "${__type:-$__devtype}" = "$__devtype" ] || continue
387 f_getvar _device_$__prop$__n $__var_to_set
388 return $?
389 done
390 return $FAILURE
391}
392
393# f_device_name_set $type $name $desc [$max]
394#
395# Store a description (desc) and [optionally] maximum number of devices to scan
396# for (max) in-association with device $type and $name. Returns success unless
397# $name is NULL or missing. Use the f_device_name_get() routine with the same
398# $name and optionally $type to retrieve one of type, desc, or max properties.
399#
400f_device_name_set()
401{
402 local type="$1" name="$2" desc="$3" max="$4"
403 local dev devtype n=0 found=
404 [ "$name" ] || return $FAILURE
405 for dev in $DEVICE_NAMES; do
406 n=$(( $n + 1 ))
407 [ "$dev" = "$name" ] || continue
408 if f_getvar _device_type$n devtype; then
409 # Allow multiple entries with same name but diff type
410 [ "$devtype" = "$type" ] || continue
411 fi
412 found=1 && break
413 done
414 if [ ! "$found" ]; then
415 DEVICE_NAMES="$DEVICE_NAMES $name"
416 n=$(( $n + 1 ))
417 fi
418 setvar _device_type$n "$type"
419 setvar _device_desc$n "$desc"
420 [ "${4+set}" ] && setvar _device_max$n "$max"
421 return $SUCCESS
422}
423
424# f_device_desc $device_name $device_type [$var_to_set]
425#
426# Print a description for a device name (eg., `fxp0') given a specific device
427# type/class.
428#
429# If $var_to_set is missing or NULL, the device description is printed to
430# standard out for capturing in a sub-shell (which is less-recommended because
431# of performance degredation; for example, when called in a loop).
432#
433f_device_desc()
434{
435 local __name="$1" __type="$2" __var_to_set="$3"
436 local __devname __devunit __cp
437
438 # Check variables
439 [ "$__name" ] || return $SUCCESS
440 [ "$__type" = "$DEVICE_TYPE_ANY" ] && type=
441 [ "$__var_to_set" ] && { setvar "$__var_to_set" "" || return; }
442
443 #
444 # Return sysctl MIB dev.NAME.UNIT.%desc if it exists,
445 # otherwise fall through to below static list.
446 #
447 if f_have sysctl; then
448 __devname="${__name%%[0-9]*}"
449 __devunit="${__name#$__devname}"
450 __devunit="${__devunit%%[!0-9]*}"
451 if [ "$__var_to_set" ]; then
452 if __cp=$(
453 sysctl -n "dev.$__devname.$__devunit.%desc" \
454 2> /dev/null
455 ); then
456 setvar "$__var_to_set" "$__cp" &&
457 return $SUCCESS
458 fi
459 else
460 sysctl -n "dev.$__devname.$__devunit.%desc" \
461 2> /dev/null && return $SUCCESS
462 fi
463 fi
464
465 local __dev __devtype __n=0
466 for __dev in $DEVICE_NAMES; do
467 __n=$(( $__n + 1 ))
468 debug= f_getvar _device_type$__n __devtype
469 [ "${__type:-$__devtype}" = "$__devtype" ] || continue
470 if [ "$__devtype" = "$DEVICE_TYPE_NETWORK" ]; then
471 __devname=$( f_substr "$__name" 0 ${#__dev} )
472 [ "$__devname" = "$__dev" ] || continue
473 else
474 __devname="${__name%%[0-9]*}"
475 __devunit="${__name#$__devname}"
476 __devunit="${__devunit%%[!0-9]*}"
477 __devname=$( printf "$__dev" $__devunit )
478 [ "$__devname" = "$__name" ] || continue
479 fi
480 debug= f_getvar _device_desc$__n $__var_to_set
481 return $?
482 done
483
484 #
485 # Sensible fall-backs for specific types
486 #
487 case "$__type" in
488 $DEVICE_TYPE_CDROM) __cp="<unknown cdrom device type>";;
489 $DEVICE_TYPE_DISK) __cp="<unknown disk device type>";;
490 $DEVICE_TYPE_FLOPPY) __cp="<unknown floppy device type>";;
491 $DEVICE_TYPE_USB) __cp="<unknown usb storage device type>";;
492 $DEVICE_TYPE_NETWORK) __cp="<unknown network interface type>";;
493 *)
494 __cp="<unknown device type>"
495 esac
496
497 if [ "$__var_to_set" ]; then
498 setvar "$__var_to_set" "$__cp"
499 else
500 echo "$__cp"
501 fi
502
503 return $FAILURE
504}
505
506# f_device_rescan
507#
508# Rescan all devices, after closing previous set - convenience function.
509#
510f_device_rescan()
511{
512 f_device_reset
513 f_device_get_all
514}
515
516# f_device_find $name [$type [$var_to_set]]
517#
518# Find one or more registered devices by name, type, or both. Returns a space-
519# separated list of devices matching the search criterion.
520#
521# If $var_to_set is missing or NULL, the device name(s) are printed to standard
522# out for capturing in a sub-shell (which is less-recommended because of
523# performance degredation; for example, when called in a loop).
524#
525f_device_find()
526{
527 local __name="$1" __type="${2:-$DEVICE_TYPE_ANY}" __var_to_set="$3"
528 local __dev __devname __devtype __found=
529 for __dev in $DEVICES; do
530 device_$__dev get name __devname
531 device_$__dev get type __devtype
532 if [ "$__name" = "$__devname" -o ! "$__name" ] &&
533 [ "$__type" = "$DEVICE_TYPE_ANY" -o \
534 "$__type" = "$__devtype" ]
535 then
536 __found="$__found $__dev"
537 fi
538 done
539 if [ "$__var_to_set" ]; then
540 setvar "$__var_to_set" "${__found# }"
541 else
542 echo $__found
543 fi
544 [ "$__found" ] # Return status
545}
546
547# f_device_init $name
548#
549# Initialize a device by evaluating its `init' function.
550#
551f_device_init()
552{
553 local name="$1" init_func
554 device_$name get init init_func || return
555 ${init_func:-:} $name
556}
557
558# f_device_get $name $file [$probe]
559#
560# Read $file by evaluating the device's `get' function. The file is commonly
561# produced on standard output (but it truly depends on the function called).
562#
563f_device_get()
564{
565 local name="$1" file="$2" probe="$3" get_func
566 device_$name get get get_func || return
567 ${get_func:-:} $name "$file" ${3+"$probe"}
568}
569
570# f_device_shutdown $name
571#
572# Shutdown a device by evaluating its `shutdown' function.
573#
574f_device_shutdown()
575{
576 local name="$1" shutdown_func
577 device_$name get shutdown shutdown_func || return
578 ${shutdown_func:-:} $name
579}
580
581# f_device_menu $title $prompt $hline $device_type [$helpfile]
582#
583# Display a menu listing all the devices of a certain type in the system.
584#
585f_device_menu()
586{
587 f_dialog_title "$1"
588 local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
589 f_dialog_title_restore
590
591 local prompt="$2" hline="$3" type="$4" helpfile="$5"
592
593 local dev devtype devs=
594 for dev in $DEVICES; do
595 device_$dev get type devtype || continue
596 [ "$devtype" = "$type" ] || continue
597 devs="$devs $dev"
598 done
599 [ "$devs" ] || return $FAILURE
600
601 local desc menu_list=
602 for dev in $devs; do
603 device_$dev get desc desc
604 f_shell_escape "$desc" desc
605 menu_list="$menu_list '$dev' '$desc'"
606 done
607
608 local height width rows
609 eval f_dialog_menu_size height width rows \
610 \"\$title\" \
611 \"\$btitle\" \
612 \"\$prompt\" \
613 \"\$hline\" \
614 $menu_list
615
616 local errexit=
617 case $- in *e*) errexit=1; esac
618 set +e
619
620 local mtag
621 while :; do
622 mtag=$( eval $DIALOG \
623 --title \"\$title\" \
624 --backtitle \"\$btitle\" \
625 --ok-label \"\$msg_ok\" \
626 --cancel-label \"\$msg_cancel\" \
627 ${helpfile:+ \
628 --help-button \
629 --help-label \"\$msg_help\" \
630 ${USE_XDIALOG:+--help \"\"} \
631 } \
632 --menu \"\$prompt\" \
633 $height $width $rows \
634 $menu_list \
635 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
636 )
637 local retval=$?
638
639 [ $retval -ne 2 ] && break
640 # Otherwise, the Help button was pressed
641 f_show_help "$helpfile"
642 # ...then loop back to menu
643 done
644 f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
645
646 [ "$errexit" ] && set -e
647
648 if [ $retval -eq 0 ]; then
649 # Clean up the output of [X]dialog(1) and return it
650 f_dialog_data_sanitize mtag
651 echo "$mtag" >&2
652 fi
653
654 return $retval
655}
656
657#
658# Short-hand
659#
660f_cdrom() { f_device_name_set $DEVICE_TYPE_CDROM "$1" "$2" "$3"; }
661f_disk() { f_device_name_set $DEVICE_TYPE_DISK "$1" "$2" "$3"; }
662f_floppy() { f_device_name_set $DEVICE_TYPE_FLOPPY "$1" "$2" "$3"; }
663f_serial() { f_device_name_set $DEVICE_TYPE_NETWORK "$1" "$2" "$3"; }
664f_usb() { f_device_name_set $DEVICE_TYPE_USB "$1" "$2" "$3"; }
665f_network() { f_device_name_set $DEVICE_TYPE_NETWORK "$1" "$2"; }
666
667############################################################ MAIN
668
669# CDROM, Disk, Floppy, Serial, and USB devices/names
670f_cdrom "cd%d" "SCSI CDROM drive" 4
671f_cdrom "mcd%d" "Mitsumi (old model) CDROM drive" 4
672f_cdrom "scd%d" "Sony CDROM drive - CDU31/33A type" 4
673f_disk "aacd%d" "Adaptec FSA RAID array" 4
674f_disk "ada%d" "ATA/SATA disk device" 16
675f_disk "amrd%d" "AMI MegaRAID drive" 4
676f_disk "da%d" "SCSI disk device" 16
677f_disk "idad%d" "Compaq RAID array" 4
678f_disk "ipsd%d" "IBM ServeRAID RAID array" 4
679f_disk "mfid%d" "LSI MegaRAID SAS array" 4
680f_disk "mlxd%d" "Mylex RAID disk" 4
681f_disk "twed%d" "3ware ATA RAID array" 4
682f_floppy "fd%d" "Floppy Drive unit A" 4
683f_serial "cuau%d" "%s on device %s (COM%d)" 16
684f_usb "da%da" "USB Mass Storage Device" 16
685
686# Network interfaces/names
687f_network "ae" "Attansic/Atheros L2 Fast Ethernet"
688f_network "age" "Attansic/Atheros L1 Gigabit Ethernet"
689f_network "alc" "Atheros AR8131/AR8132 PCIe Ethernet"
690f_network "ale" "Atheros AR8121/AR8113/AR8114 PCIe Ethernet"
691f_network "an" "Aironet 4500/4800 802.11 wireless adapter"
692f_network "ath" "Atheros IEEE 802.11 wireless adapter"
693f_network "aue" "ADMtek USB Ethernet adapter"
694f_network "axe" "ASIX Electronics USB Ethernet adapter"
695f_network "bce" "Broadcom NetXtreme II Gigabit Ethernet card"
696f_network "bfe" "Broadcom BCM440x PCI Ethernet card"
697f_network "bge" "Broadcom BCM570x PCI Gigabit Ethernet card"
698f_network "bm" "Apple BMAC Built-in Ethernet"
699f_network "bwn" "Broadcom BCM43xx IEEE 802.11 wireless adapter"
700f_network "cas" "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"
701f_network "cc3i" "SDL HSSI sync serial PCI card"
702f_network "cue" "CATC USB Ethernet adapter"
703f_network "cxgb" "Chelsio T3 10Gb Ethernet card"
704f_network "dc" "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"
705f_network "de" "DEC DE435 PCI NIC or other DC21040-AA based card"
706f_network "disc" "Software discard network interface"
707f_network "ed" "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"
708f_network "el" "3Com 3C501 Ethernet card"
709f_network "em" "Intel(R) PRO/1000 Ethernet card"
710f_network "en" "Efficient Networks ATM PCI card"
711f_network "ep" "3Com 3C509 Ethernet card/3C589 PCMCIA"
712f_network "et" "Agere ET1310 based PCI Express Gigabit Ethernet card"
713f_network "ex" "Intel EtherExpress Pro/10 Ethernet card"
714f_network "fe" "Fujitsu MB86960A/MB86965A Ethernet card"
715f_network "fpa" "DEC DEFPA PCI FDDI card"
716f_network "fwe" "FireWire Ethernet emulation"
717f_network "fwip" "IP over FireWire"
718f_network "fxp" "Intel EtherExpress Pro/100B PCI Fast Ethernet card"
719f_network "gem" "Apple GMAC or Sun ERI/GEM Ethernet adapter"
720f_network "hme" "Sun HME (Happy Meal Ethernet) Ethernet adapter"
721f_network "ie" "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"
722f_network "igb" "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"
723f_network "ipw" "Intel PRO/Wireless 2100 IEEE 802.11 adapter"
724f_network "iwi" "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"
725f_network "iwn" "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"
726f_network "ixgbe" "Intel(R) PRO/10Gb Ethernet card"
727f_network "ixgb" "Intel(R) PRO/10Gb Ethernet card"
728f_network "ix" "Intel Etherexpress Ethernet card"
729 # Maintain sequential order of above(3): ixgbe ixgb ix
730f_network "jme" "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"
731f_network "kue" "Kawasaki LSI USB Ethernet adapter"
732f_network "le" "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"
733f_network "lge" "Level 1 LXT1001 Gigabit Ethernet card"
734f_network "lnc" "Lance/PCnet (Isolan/Novell NE2100/NE32-VL) Ethernet"
735f_network "lo" "Loop-back (local) network interface"
736f_network "lp" "Parallel Port IP (PLIP) peer connection"
737f_network "malo" "Marvell Libertas 88W8335 802.11 wireless adapter"
738f_network "msk" "Marvell/SysKonnect Yukon II Gigabit Ethernet"
739f_network "mxge" "Myricom Myri10GE 10Gb Ethernet card"
740f_network "nfe" "NVIDIA nForce MCP Ethernet"
741f_network "nge" "NatSemi PCI Gigabit Ethernet card"
742f_network "ng" "Vimage netgraph(4) bridged Ethernet device"
743 # Maintain sequential order of above(2): nge ng
744f_network "nve" "NVIDIA nForce MCP Ethernet"
745f_network "nxge" "Neterion Xframe 10GbE Server/Storage adapter"
746f_network "pcn" "AMD Am79c79x PCI Ethernet card"
747f_network "plip" "Parallel Port IP (PLIP) peer connection"
748f_network "ral" "Ralink Technology IEEE 802.11 wireless adapter"
749f_network "ray" "Raytheon Raylink 802.11 wireless adapter"
750f_network "re" "RealTek 8139C+/8169/8169S/8110S PCI Ethernet adapter"
751f_network "rl" "RealTek 8129/8139 PCI Ethernet card"
752f_network "rue" "RealTek USB Ethernet card"
753f_network "rum" "Ralink Technology USB IEEE 802.11 wireless adapter"
754f_network "sf" "Adaptec AIC-6915 PCI Ethernet card"
755f_network "sge" "Silicon Integrated Systems SiS190/191 Ethernet"
756f_network "sis" "SiS 900/SiS 7016 PCI Ethernet card"
757f_network "sk" "SysKonnect PCI Gigabit Ethernet card"
758f_network "snc" "SONIC Ethernet card"
759f_network "sn" "SMC/Megahertz Ethernet card"
760 # Maintain sequential order of above(2): snc sn
761f_network "sr" "SDL T1/E1 sync serial PCI card"
762f_network "ste" "Sundance ST201 PCI Ethernet card"
763f_network "stge" "Sundance/Tamarack TC9021 Gigabit Ethernet"
764f_network "ti" "Alteon Networks PCI Gigabit Ethernet card"
765f_network "tl" "Texas Instruments ThunderLAN PCI Ethernet card"
766f_network "txp" "3Com 3cR990 Ethernet card"
767f_network "tx" "SMC 9432TX Ethernet card"
768 # Maintain sequential order of above(2): txp tx
769f_network "uath" "Atheros AR5005UG and AR5005UX USB wireless adapter"
770f_network "upgt" "Conexant/Intersil PrismGT USB wireless adapter"
771f_network "ural" "Ralink Technology RT2500USB 802.11 wireless adapter"
772f_network "urtw" "Realtek 8187L USB wireless adapter"
773f_network "vge" "VIA VT612x PCI Gigabit Ethernet card"
774f_network "vlan" "IEEE 802.1Q VLAN network interface"
775f_network "vr" "VIA VT3043/VT86C100A Rhine PCI Ethernet card"
776f_network "vx" "3COM 3c590 / 3c595 Ethernet card"
777f_network "wb" "Winbond W89C840F PCI Ethernet card"
778f_network "wi" "Lucent WaveLAN/IEEE 802.11 wireless adapter"
779f_network "wpi" "Intel 3945ABG IEEE 802.11 wireless adapter"
780f_network "wx" "Intel Gigabit Ethernet (82452) card"
781f_network "xe" "Xircom/Intel EtherExpress Pro100/16 Ethernet card"
782f_network "xl" "3COM 3c90x / 3c90xB PCI Ethernet card"
783f_network "zyd" "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"
784
785f_dprintf "%s: Initialized %u known device names/descriptions." device.subr \
786 "$( set -- $DEVICE_NAMES; echo $# )"
787
788#
789# Scan for the above devices unless requeted otherwise
790#
791f_dprintf "%s: DEVICE_SELF_SCAN_ALL=[%s]" device.subr "$DEVICE_SELF_SCAN_ALL"
792case "$DEVICE_SELF_SCAN_ALL" in
793""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
794*) f_device_get_all
795esac
796
797f_dprintf "%s: Successfully loaded." device.subr
798
799fi # ! $_DEVICE_SUBR
77
78#
79# Default behavior is to call f_device_get_all() automatically when loaded.
80#
81: ${DEVICE_SELF_SCAN_ALL=1}
82
83############################################################ FUNCTIONS
84
85# f_device_try $name [$i [$var_path]]
86#
87# Test a particular device. If $i is given, then $name is expected to contain a
88# single "%d" where $i will be inserted using printf. If $var_path is given,
89# it is used as a variable name to provide the caller the device pathname.
90#
91# Returns success if the device path exists and is a cdev.
92#
93f_device_try()
94{
95 local name="$1" i="$2" var_path="$3" unit
96 if [ "$i" ]; then
97 unit=$( printf "$name" "$i" )
98 else
99 unit="$name"
100 fi
101 case "$unit" in
102 /dev/*) : good ;; # already qualified
103 *) unit="/dev/$unit" ;;
104 esac
105 [ "$var_path" ] && setvar "$var_path" "$unit"
106 f_dprintf "f_device_try: making sure %s is a device node" "$unit"
107 if [ -c "$unit" ]; then
108 f_dprintf "f_device_try: %s is a cdev [good]" "$unit"
109 return $SUCCESS
110 else
111 f_dprintf "f_device_try: %s is not a cdev [skip]" "$unit"
112 return $FAILURE
113 fi
114}
115
116# f_device_register $name $desc $devname $type $enabled $init_function \
117# $get_function $shutdown_function $private
118#
119# Register a device. A `structure' (see struct.subr) is created with the name
120# device_$name (so make sure $name contains only alpha-numeric characters or
121# the underscore, `_'). The remaining arguments after $name correspond to the
122# properties of the `DEVICE' structure-type (defined above).
123#
124# If not already registered, the device is then appended to the DEVICES
125# environment variable, a space-separated list of all registered devices.
126#
127f_device_register()
128{
129 local name="$1" desc="$2" devname="$3" type="$4" enabled="$5"
130 local init_func="$6" get_func="$7" shutdown_func="$8" private="$9"
131
132 f_struct_new DEVICE "device_$name" || return $FAILURE
133 device_$name set name "$name"
134 device_$name set desc "$desc"
135 device_$name set devname "$devname"
136 device_$name set type "$type"
137 device_$name set enabled "$enabled"
138 device_$name set init "$init_func"
139 device_$name set get "$get_func"
140 device_$name set shutdown "$shutdown_func"
141 device_$name set private "$private"
142
143 # Scan our global register to see if it needs ammending
144 local dev found=
145 for dev in $DEVICES; do
146 [ "$dev" = "$name" ] || continue
147 found=1 && break
148 done
149 [ "$found" ] || DEVICES="$DEVICES $name"
150
151 return $SUCCESS
152}
153
154# f_device_reset
155#
156# Reset the registered device chain.
157#
158f_device_reset()
159{
160 local dev
161 for dev in $DEVICES; do
162 f_device_shutdown $dev
163
164 #
165 # XXX this potentially leaks $dev->private if it's being
166 # used to point to something dynamic, but you're not supposed
167 # to call this routine at such times that some open instance
168 # has its private member pointing somewhere anyway. XXX
169 #
170 f_struct_free device_$dev
171 done
172 DEVICES=
173}
174
175# f_device_get_all
176#
177# Get all device information for devices we have attached.
178#
179f_device_get_all()
180{
181 local devname desc
182
183 f_dprintf "f_device_get_all: Probing devices..."
184 f_dialog_info "$msg_probing_devices_please_wait_this_can_take_a_while"
185
186 # First go for the network interfaces
187 for devname in $( ifconfig -l ); do
188 # Eliminate network devices that don't make sense
189 case "$devname" in
190 lo*) continue ;;
191 esac
192
193 # Try and find its description
194 f_device_desc "$devname" $DEVICE_TYPE_NETWORK desc
195
196 f_dprintf "Found a network device named %s" "$devname"
197 f_device_register $devname \
198 "$desc" "$devname" $DEVICE_TYPE_NETWORK 1 \
199 f_media_init_network "" f_media_shutdown_network ""
200 done
201
202 # Next, try to find all the types of devices one might use
203 # as a media source for content
204 #
205
206 local dev desc type max n=0
207 for dev in $DEVICE_NAMES; do
208 n=$(( $n + 1 ))
209 # Get the desc, type, and max (with debugging disabled)
210 # NOTE: Bypassing f_device_name_get() for efficiency
211 debug= f_getvar _device_desc$n desc
212 debug= f_getvar _device_type$n type
213 debug= f_getvar _device_max$n max
214
215 local k=0
216 while [ $k -lt ${max:-0} ]; do
217 i=$k k=$(( $k + 1 ))
218 devname=""
219 case "$type" in
220 $DEVICE_TYPE_CDROM)
221 f_device_try "$dev" "$i" devname || continue
222 f_device_register "${devname##*/}" "$desc" \
223 "$devname" $DEVICE_TYPE_CDROM 1 \
224 f_media_init_cdrom f_media_get_cdrom \
225 f_media_shutdown_cdrom ""
226 f_dprintf "Found a CDROM device for %s" \
227 "$devname"
228 ;;
229 $DEVICE_TYPE_FLOPPY)
230 f_device_try "$dev" "$i" devname || continue
231 f_device_register "${devname##*/}" "$desc" \
232 "$devname" $DEVICE_TYPE_FLOPPY 1 \
233 f_media_init_floppy \
234 f_media_get_floppy \
235 f_media_shutdown_floppy ""
236 f_dprintf "Found a floppy device for %s" \
237 "$devname"
238 ;;
239 $DEVICE_TYPE_USB)
240 f_device_try "$dev" "$i" devname || continue
241 f_device_register "${devname##*/}" "$desc" \
242 "$devname" $DEVICE_TYPE_USB 1 \
243 f_media_init_usb f_media_get_usb \
244 f_media_shutdown_usb ""
245 f_dprintf "Found a USB disk for %s" "$devname"
246 ;;
247 esac
248 done
249 done
250
251 # Register ISO9660 providers as CDROM devices
252 for devname in /dev/iso9660/*; do
253 f_device_try "$devname" || continue
254 f_device_register "${devname##*/}" "ISO9660 file system" \
255 "$devname" $DEVICE_TYPE_CDROM 1 \
256 f_media_init_cdrom f_media_get_cdrom \
257 f_media_shutdown_cdrom ""
258 f_dprintf "Found a CDROM device for %s" "$devname"
259 done
260
261 # Scan for mdconfig(8)-created md(4) devices
262 local filename
263 for devname in /dev/md[0-9] /dev/md[0-9][0-9]; do
264 f_device_try "$devname" || continue
265
266 # See if the md(4) device is a vnode type backed by a file
267 filename=$( sysctl kern.geom.conftxt |
268 awk -v devname="${devname##*/}" \
269 '
270 ( $2 == "MD" ) && \
271 ( $3 == devname ) && \
272 ( $(NF-2) == "vnode" ) && \
273 ( $(NF-1) == "file" ) \
274 {
275 print $NF
276 }
277 ' )
278 case "$filename" in
279 *.iso) # Register the device as an ISO9660 provider
280 f_device_register "${devname##*/}" \
281 "md(4) vnode file system" \
282 "$devname" $DEVICE_TYPE_CDROM 1 \
283 f_media_init_cdrom f_media_get_cdrom \
284 f_media_shutdown_cdrom ""
285 f_dprintf "Found a CDROM device for %s" "$devname"
286 ;;
287 esac
288 done
289
290 # Finally go get the disks and look for partitions to register
291 local diskname slices index type rest slice part
292 for diskname in $( sysctl -n kern.disks ); do
293
294 case "$diskname" in
295 cd*)
296 # XXX
297 # Due to unknown reasons, kern.disks returns SCSI
298 # CDROM as a valid disk. This will prevent bsdconfig
299 # from presenting SCSI CDROMs as available disks in
300 # various menus. Why GEOM treats SCSI CDROM as a disk
301 # is beyond me and that should be investigated.
302 # For temporary workaround, ignore SCSI CDROM device.
303 #
304 continue ;;
305 esac
306
307 # Try to create a list of partitions and their types,
308 # consisting of "N,typeN ..." (e.g., "1,0xa5 2,0x06").
309 if ! slices=$( fdisk -p "$diskname" 2> /dev/null |
310 awk '( $1 == "p" ) { print $2","$3 }' )
311 then
312 f_dprintf "Unable to open disk %s" "$diskname"
313 continue
314 fi
315
316 f_device_register "$diskname" "" \
317 "/dev/$diskname" $DEVICE_TYPE_DISK 0
318 f_dprintf "Found a disk device named %s" "$diskname"
319
320 # Look for existing partitions to register
321 for slice in $slices; do
322 index="${slice%%,*}" type="${slice#*,}"
323 slice=${diskname}s$index
324 case "$type" in
325 0x01|0x04|0x06|0x0b|0x0c|0x0e|0xef)
326 # DOS partitions to add as "DOS media devices"
327 f_device_register "$slice" "" \
328 "/dev/$slice" $DEVICE_TYPE_DOS 1 \
329 f_media_init_dos f_media_get_dos \
330 f_media_shutdown_dos ""
331 f_dprintf "Found a DOS partition %s" "$slice"
332 ;;
333 0xa5) # FreeBSD partition
334 for part in $(
335 bsdlabel -r $slice 2> /dev/null |
336 awk -v slice="$slice" '
337 ( $1 ~ /[abdefgh]:/ ) {
338 printf "%s%s\n",
339 slice,
340 substr($1,1,1)
341 }'
342 ); do
343 f_quietly dumpfs -m /dev/$part ||
344 continue
345 f_device_register \
346 "$part" "" "/dev/$part" \
347 $DEVICE_TYPE_UFS 1 \
348 f_media_init_ufs \
349 f_media_get_ufs \
350 f_media_shutdown_ufs ""
351 f_dprintf "Found a UFS partition %s" \
352 "$part"
353 done # parts
354 ;;
355 esac
356 done # slices
357
358 done # disks
359}
360
361# f_device_name_get $type $name type|desc|max [$var_to_set]
362#
363# Fetch the device type (type), description (desc), or maximum number of
364# devices to scan for (max) associated with device $name and $type. If $type is
365# either NULL, missing, or set to $DEVICE_TYPE_ANY then only $name is used.
366# Returns success if a match was found, otherwise failure.
367#
368# If $var_to_set is missing or NULL, the device name is printed to standard out
369# for capturing in a sub-shell (which is less-recommended because of
370# performance degredation; for example, when called in a loop).
371#
372f_device_name_get()
373{
374 local __type="$1" __name="$2" __prop="$3" __var_to_set="$4"
375 local __dev __devtype __n=0
376
377 # Return failure if no $name or $prop is an unknown property
378 [ "$__name" ] || return $FAILURE
379 case "$__prop" in type|desc|max) : good ;;
380 *) return $FAILURE; esac
381
382 [ "$__type" = "$DEVICE_TYPE_ANY" ] && __type=
383 for __dev in $DEVICE_NAMES; do
384 __n=$(( $__n + 1 ))
385 [ "$__dev" = "$__name" ] || continue
386 f_getvar _device_type$__n __devtype
387 [ "${__type:-$__devtype}" = "$__devtype" ] || continue
388 f_getvar _device_$__prop$__n $__var_to_set
389 return $?
390 done
391 return $FAILURE
392}
393
394# f_device_name_set $type $name $desc [$max]
395#
396# Store a description (desc) and [optionally] maximum number of devices to scan
397# for (max) in-association with device $type and $name. Returns success unless
398# $name is NULL or missing. Use the f_device_name_get() routine with the same
399# $name and optionally $type to retrieve one of type, desc, or max properties.
400#
401f_device_name_set()
402{
403 local type="$1" name="$2" desc="$3" max="$4"
404 local dev devtype n=0 found=
405 [ "$name" ] || return $FAILURE
406 for dev in $DEVICE_NAMES; do
407 n=$(( $n + 1 ))
408 [ "$dev" = "$name" ] || continue
409 if f_getvar _device_type$n devtype; then
410 # Allow multiple entries with same name but diff type
411 [ "$devtype" = "$type" ] || continue
412 fi
413 found=1 && break
414 done
415 if [ ! "$found" ]; then
416 DEVICE_NAMES="$DEVICE_NAMES $name"
417 n=$(( $n + 1 ))
418 fi
419 setvar _device_type$n "$type"
420 setvar _device_desc$n "$desc"
421 [ "${4+set}" ] && setvar _device_max$n "$max"
422 return $SUCCESS
423}
424
425# f_device_desc $device_name $device_type [$var_to_set]
426#
427# Print a description for a device name (eg., `fxp0') given a specific device
428# type/class.
429#
430# If $var_to_set is missing or NULL, the device description is printed to
431# standard out for capturing in a sub-shell (which is less-recommended because
432# of performance degredation; for example, when called in a loop).
433#
434f_device_desc()
435{
436 local __name="$1" __type="$2" __var_to_set="$3"
437 local __devname __devunit __cp
438
439 # Check variables
440 [ "$__name" ] || return $SUCCESS
441 [ "$__type" = "$DEVICE_TYPE_ANY" ] && type=
442 [ "$__var_to_set" ] && { setvar "$__var_to_set" "" || return; }
443
444 #
445 # Return sysctl MIB dev.NAME.UNIT.%desc if it exists,
446 # otherwise fall through to below static list.
447 #
448 if f_have sysctl; then
449 __devname="${__name%%[0-9]*}"
450 __devunit="${__name#$__devname}"
451 __devunit="${__devunit%%[!0-9]*}"
452 if [ "$__var_to_set" ]; then
453 if __cp=$(
454 sysctl -n "dev.$__devname.$__devunit.%desc" \
455 2> /dev/null
456 ); then
457 setvar "$__var_to_set" "$__cp" &&
458 return $SUCCESS
459 fi
460 else
461 sysctl -n "dev.$__devname.$__devunit.%desc" \
462 2> /dev/null && return $SUCCESS
463 fi
464 fi
465
466 local __dev __devtype __n=0
467 for __dev in $DEVICE_NAMES; do
468 __n=$(( $__n + 1 ))
469 debug= f_getvar _device_type$__n __devtype
470 [ "${__type:-$__devtype}" = "$__devtype" ] || continue
471 if [ "$__devtype" = "$DEVICE_TYPE_NETWORK" ]; then
472 __devname=$( f_substr "$__name" 0 ${#__dev} )
473 [ "$__devname" = "$__dev" ] || continue
474 else
475 __devname="${__name%%[0-9]*}"
476 __devunit="${__name#$__devname}"
477 __devunit="${__devunit%%[!0-9]*}"
478 __devname=$( printf "$__dev" $__devunit )
479 [ "$__devname" = "$__name" ] || continue
480 fi
481 debug= f_getvar _device_desc$__n $__var_to_set
482 return $?
483 done
484
485 #
486 # Sensible fall-backs for specific types
487 #
488 case "$__type" in
489 $DEVICE_TYPE_CDROM) __cp="<unknown cdrom device type>";;
490 $DEVICE_TYPE_DISK) __cp="<unknown disk device type>";;
491 $DEVICE_TYPE_FLOPPY) __cp="<unknown floppy device type>";;
492 $DEVICE_TYPE_USB) __cp="<unknown usb storage device type>";;
493 $DEVICE_TYPE_NETWORK) __cp="<unknown network interface type>";;
494 *)
495 __cp="<unknown device type>"
496 esac
497
498 if [ "$__var_to_set" ]; then
499 setvar "$__var_to_set" "$__cp"
500 else
501 echo "$__cp"
502 fi
503
504 return $FAILURE
505}
506
507# f_device_rescan
508#
509# Rescan all devices, after closing previous set - convenience function.
510#
511f_device_rescan()
512{
513 f_device_reset
514 f_device_get_all
515}
516
517# f_device_find $name [$type [$var_to_set]]
518#
519# Find one or more registered devices by name, type, or both. Returns a space-
520# separated list of devices matching the search criterion.
521#
522# If $var_to_set is missing or NULL, the device name(s) are printed to standard
523# out for capturing in a sub-shell (which is less-recommended because of
524# performance degredation; for example, when called in a loop).
525#
526f_device_find()
527{
528 local __name="$1" __type="${2:-$DEVICE_TYPE_ANY}" __var_to_set="$3"
529 local __dev __devname __devtype __found=
530 for __dev in $DEVICES; do
531 device_$__dev get name __devname
532 device_$__dev get type __devtype
533 if [ "$__name" = "$__devname" -o ! "$__name" ] &&
534 [ "$__type" = "$DEVICE_TYPE_ANY" -o \
535 "$__type" = "$__devtype" ]
536 then
537 __found="$__found $__dev"
538 fi
539 done
540 if [ "$__var_to_set" ]; then
541 setvar "$__var_to_set" "${__found# }"
542 else
543 echo $__found
544 fi
545 [ "$__found" ] # Return status
546}
547
548# f_device_init $name
549#
550# Initialize a device by evaluating its `init' function.
551#
552f_device_init()
553{
554 local name="$1" init_func
555 device_$name get init init_func || return
556 ${init_func:-:} $name
557}
558
559# f_device_get $name $file [$probe]
560#
561# Read $file by evaluating the device's `get' function. The file is commonly
562# produced on standard output (but it truly depends on the function called).
563#
564f_device_get()
565{
566 local name="$1" file="$2" probe="$3" get_func
567 device_$name get get get_func || return
568 ${get_func:-:} $name "$file" ${3+"$probe"}
569}
570
571# f_device_shutdown $name
572#
573# Shutdown a device by evaluating its `shutdown' function.
574#
575f_device_shutdown()
576{
577 local name="$1" shutdown_func
578 device_$name get shutdown shutdown_func || return
579 ${shutdown_func:-:} $name
580}
581
582# f_device_menu $title $prompt $hline $device_type [$helpfile]
583#
584# Display a menu listing all the devices of a certain type in the system.
585#
586f_device_menu()
587{
588 f_dialog_title "$1"
589 local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
590 f_dialog_title_restore
591
592 local prompt="$2" hline="$3" type="$4" helpfile="$5"
593
594 local dev devtype devs=
595 for dev in $DEVICES; do
596 device_$dev get type devtype || continue
597 [ "$devtype" = "$type" ] || continue
598 devs="$devs $dev"
599 done
600 [ "$devs" ] || return $FAILURE
601
602 local desc menu_list=
603 for dev in $devs; do
604 device_$dev get desc desc
605 f_shell_escape "$desc" desc
606 menu_list="$menu_list '$dev' '$desc'"
607 done
608
609 local height width rows
610 eval f_dialog_menu_size height width rows \
611 \"\$title\" \
612 \"\$btitle\" \
613 \"\$prompt\" \
614 \"\$hline\" \
615 $menu_list
616
617 local errexit=
618 case $- in *e*) errexit=1; esac
619 set +e
620
621 local mtag
622 while :; do
623 mtag=$( eval $DIALOG \
624 --title \"\$title\" \
625 --backtitle \"\$btitle\" \
626 --ok-label \"\$msg_ok\" \
627 --cancel-label \"\$msg_cancel\" \
628 ${helpfile:+ \
629 --help-button \
630 --help-label \"\$msg_help\" \
631 ${USE_XDIALOG:+--help \"\"} \
632 } \
633 --menu \"\$prompt\" \
634 $height $width $rows \
635 $menu_list \
636 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
637 )
638 local retval=$?
639
640 [ $retval -ne 2 ] && break
641 # Otherwise, the Help button was pressed
642 f_show_help "$helpfile"
643 # ...then loop back to menu
644 done
645 f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
646
647 [ "$errexit" ] && set -e
648
649 if [ $retval -eq 0 ]; then
650 # Clean up the output of [X]dialog(1) and return it
651 f_dialog_data_sanitize mtag
652 echo "$mtag" >&2
653 fi
654
655 return $retval
656}
657
658#
659# Short-hand
660#
661f_cdrom() { f_device_name_set $DEVICE_TYPE_CDROM "$1" "$2" "$3"; }
662f_disk() { f_device_name_set $DEVICE_TYPE_DISK "$1" "$2" "$3"; }
663f_floppy() { f_device_name_set $DEVICE_TYPE_FLOPPY "$1" "$2" "$3"; }
664f_serial() { f_device_name_set $DEVICE_TYPE_NETWORK "$1" "$2" "$3"; }
665f_usb() { f_device_name_set $DEVICE_TYPE_USB "$1" "$2" "$3"; }
666f_network() { f_device_name_set $DEVICE_TYPE_NETWORK "$1" "$2"; }
667
668############################################################ MAIN
669
670# CDROM, Disk, Floppy, Serial, and USB devices/names
671f_cdrom "cd%d" "SCSI CDROM drive" 4
672f_cdrom "mcd%d" "Mitsumi (old model) CDROM drive" 4
673f_cdrom "scd%d" "Sony CDROM drive - CDU31/33A type" 4
674f_disk "aacd%d" "Adaptec FSA RAID array" 4
675f_disk "ada%d" "ATA/SATA disk device" 16
676f_disk "amrd%d" "AMI MegaRAID drive" 4
677f_disk "da%d" "SCSI disk device" 16
678f_disk "idad%d" "Compaq RAID array" 4
679f_disk "ipsd%d" "IBM ServeRAID RAID array" 4
680f_disk "mfid%d" "LSI MegaRAID SAS array" 4
681f_disk "mlxd%d" "Mylex RAID disk" 4
682f_disk "twed%d" "3ware ATA RAID array" 4
683f_floppy "fd%d" "Floppy Drive unit A" 4
684f_serial "cuau%d" "%s on device %s (COM%d)" 16
685f_usb "da%da" "USB Mass Storage Device" 16
686
687# Network interfaces/names
688f_network "ae" "Attansic/Atheros L2 Fast Ethernet"
689f_network "age" "Attansic/Atheros L1 Gigabit Ethernet"
690f_network "alc" "Atheros AR8131/AR8132 PCIe Ethernet"
691f_network "ale" "Atheros AR8121/AR8113/AR8114 PCIe Ethernet"
692f_network "an" "Aironet 4500/4800 802.11 wireless adapter"
693f_network "ath" "Atheros IEEE 802.11 wireless adapter"
694f_network "aue" "ADMtek USB Ethernet adapter"
695f_network "axe" "ASIX Electronics USB Ethernet adapter"
696f_network "bce" "Broadcom NetXtreme II Gigabit Ethernet card"
697f_network "bfe" "Broadcom BCM440x PCI Ethernet card"
698f_network "bge" "Broadcom BCM570x PCI Gigabit Ethernet card"
699f_network "bm" "Apple BMAC Built-in Ethernet"
700f_network "bwn" "Broadcom BCM43xx IEEE 802.11 wireless adapter"
701f_network "cas" "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"
702f_network "cc3i" "SDL HSSI sync serial PCI card"
703f_network "cue" "CATC USB Ethernet adapter"
704f_network "cxgb" "Chelsio T3 10Gb Ethernet card"
705f_network "dc" "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"
706f_network "de" "DEC DE435 PCI NIC or other DC21040-AA based card"
707f_network "disc" "Software discard network interface"
708f_network "ed" "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"
709f_network "el" "3Com 3C501 Ethernet card"
710f_network "em" "Intel(R) PRO/1000 Ethernet card"
711f_network "en" "Efficient Networks ATM PCI card"
712f_network "ep" "3Com 3C509 Ethernet card/3C589 PCMCIA"
713f_network "et" "Agere ET1310 based PCI Express Gigabit Ethernet card"
714f_network "ex" "Intel EtherExpress Pro/10 Ethernet card"
715f_network "fe" "Fujitsu MB86960A/MB86965A Ethernet card"
716f_network "fpa" "DEC DEFPA PCI FDDI card"
717f_network "fwe" "FireWire Ethernet emulation"
718f_network "fwip" "IP over FireWire"
719f_network "fxp" "Intel EtherExpress Pro/100B PCI Fast Ethernet card"
720f_network "gem" "Apple GMAC or Sun ERI/GEM Ethernet adapter"
721f_network "hme" "Sun HME (Happy Meal Ethernet) Ethernet adapter"
722f_network "ie" "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"
723f_network "igb" "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"
724f_network "ipw" "Intel PRO/Wireless 2100 IEEE 802.11 adapter"
725f_network "iwi" "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"
726f_network "iwn" "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"
727f_network "ixgbe" "Intel(R) PRO/10Gb Ethernet card"
728f_network "ixgb" "Intel(R) PRO/10Gb Ethernet card"
729f_network "ix" "Intel Etherexpress Ethernet card"
730 # Maintain sequential order of above(3): ixgbe ixgb ix
731f_network "jme" "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"
732f_network "kue" "Kawasaki LSI USB Ethernet adapter"
733f_network "le" "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"
734f_network "lge" "Level 1 LXT1001 Gigabit Ethernet card"
735f_network "lnc" "Lance/PCnet (Isolan/Novell NE2100/NE32-VL) Ethernet"
736f_network "lo" "Loop-back (local) network interface"
737f_network "lp" "Parallel Port IP (PLIP) peer connection"
738f_network "malo" "Marvell Libertas 88W8335 802.11 wireless adapter"
739f_network "msk" "Marvell/SysKonnect Yukon II Gigabit Ethernet"
740f_network "mxge" "Myricom Myri10GE 10Gb Ethernet card"
741f_network "nfe" "NVIDIA nForce MCP Ethernet"
742f_network "nge" "NatSemi PCI Gigabit Ethernet card"
743f_network "ng" "Vimage netgraph(4) bridged Ethernet device"
744 # Maintain sequential order of above(2): nge ng
745f_network "nve" "NVIDIA nForce MCP Ethernet"
746f_network "nxge" "Neterion Xframe 10GbE Server/Storage adapter"
747f_network "pcn" "AMD Am79c79x PCI Ethernet card"
748f_network "plip" "Parallel Port IP (PLIP) peer connection"
749f_network "ral" "Ralink Technology IEEE 802.11 wireless adapter"
750f_network "ray" "Raytheon Raylink 802.11 wireless adapter"
751f_network "re" "RealTek 8139C+/8169/8169S/8110S PCI Ethernet adapter"
752f_network "rl" "RealTek 8129/8139 PCI Ethernet card"
753f_network "rue" "RealTek USB Ethernet card"
754f_network "rum" "Ralink Technology USB IEEE 802.11 wireless adapter"
755f_network "sf" "Adaptec AIC-6915 PCI Ethernet card"
756f_network "sge" "Silicon Integrated Systems SiS190/191 Ethernet"
757f_network "sis" "SiS 900/SiS 7016 PCI Ethernet card"
758f_network "sk" "SysKonnect PCI Gigabit Ethernet card"
759f_network "snc" "SONIC Ethernet card"
760f_network "sn" "SMC/Megahertz Ethernet card"
761 # Maintain sequential order of above(2): snc sn
762f_network "sr" "SDL T1/E1 sync serial PCI card"
763f_network "ste" "Sundance ST201 PCI Ethernet card"
764f_network "stge" "Sundance/Tamarack TC9021 Gigabit Ethernet"
765f_network "ti" "Alteon Networks PCI Gigabit Ethernet card"
766f_network "tl" "Texas Instruments ThunderLAN PCI Ethernet card"
767f_network "txp" "3Com 3cR990 Ethernet card"
768f_network "tx" "SMC 9432TX Ethernet card"
769 # Maintain sequential order of above(2): txp tx
770f_network "uath" "Atheros AR5005UG and AR5005UX USB wireless adapter"
771f_network "upgt" "Conexant/Intersil PrismGT USB wireless adapter"
772f_network "ural" "Ralink Technology RT2500USB 802.11 wireless adapter"
773f_network "urtw" "Realtek 8187L USB wireless adapter"
774f_network "vge" "VIA VT612x PCI Gigabit Ethernet card"
775f_network "vlan" "IEEE 802.1Q VLAN network interface"
776f_network "vr" "VIA VT3043/VT86C100A Rhine PCI Ethernet card"
777f_network "vx" "3COM 3c590 / 3c595 Ethernet card"
778f_network "wb" "Winbond W89C840F PCI Ethernet card"
779f_network "wi" "Lucent WaveLAN/IEEE 802.11 wireless adapter"
780f_network "wpi" "Intel 3945ABG IEEE 802.11 wireless adapter"
781f_network "wx" "Intel Gigabit Ethernet (82452) card"
782f_network "xe" "Xircom/Intel EtherExpress Pro100/16 Ethernet card"
783f_network "xl" "3COM 3c90x / 3c90xB PCI Ethernet card"
784f_network "zyd" "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"
785
786f_dprintf "%s: Initialized %u known device names/descriptions." device.subr \
787 "$( set -- $DEVICE_NAMES; echo $# )"
788
789#
790# Scan for the above devices unless requeted otherwise
791#
792f_dprintf "%s: DEVICE_SELF_SCAN_ALL=[%s]" device.subr "$DEVICE_SELF_SCAN_ALL"
793case "$DEVICE_SELF_SCAN_ALL" in
794""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
795*) f_device_get_all
796esac
797
798f_dprintf "%s: Successfully loaded." device.subr
799
800fi # ! $_DEVICE_SUBR