summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsdconfig/share
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bsdconfig/share')
-rw-r--r--usr.sbin/bsdconfig/share/Makefile6
-rw-r--r--usr.sbin/bsdconfig/share/common.subr42
-rw-r--r--usr.sbin/bsdconfig/share/device.subr799
-rw-r--r--usr.sbin/bsdconfig/share/media/Makefile13
-rw-r--r--usr.sbin/bsdconfig/share/media/any.subr152
-rw-r--r--usr.sbin/bsdconfig/share/media/cdrom.subr210
-rw-r--r--usr.sbin/bsdconfig/share/media/common.subr109
-rw-r--r--usr.sbin/bsdconfig/share/media/directory.subr146
-rw-r--r--usr.sbin/bsdconfig/share/media/dos.subr164
-rw-r--r--usr.sbin/bsdconfig/share/media/floppy.subr214
-rw-r--r--usr.sbin/bsdconfig/share/media/ftp.subr893
-rw-r--r--usr.sbin/bsdconfig/share/media/httpproxy.subr433
-rw-r--r--usr.sbin/bsdconfig/share/media/network.subr182
-rw-r--r--usr.sbin/bsdconfig/share/media/nfs.subr251
-rw-r--r--usr.sbin/bsdconfig/share/media/options.subr308
-rw-r--r--usr.sbin/bsdconfig/share/media/tcpip.subr1688
-rw-r--r--usr.sbin/bsdconfig/share/media/ufs.subr193
-rw-r--r--usr.sbin/bsdconfig/share/media/usb.subr174
-rw-r--r--usr.sbin/bsdconfig/share/script.subr33
-rw-r--r--usr.sbin/bsdconfig/share/strings.subr68
-rw-r--r--usr.sbin/bsdconfig/share/struct.subr206
-rw-r--r--usr.sbin/bsdconfig/share/variable.subr68
22 files changed, 6332 insertions, 20 deletions
diff --git a/usr.sbin/bsdconfig/share/Makefile b/usr.sbin/bsdconfig/share/Makefile
index cd56dfc..4c20c2b 100644
--- a/usr.sbin/bsdconfig/share/Makefile
+++ b/usr.sbin/bsdconfig/share/Makefile
@@ -2,9 +2,11 @@
NO_OBJ=
+SUBDIR= media
+
FILESDIR= ${SHAREDIR}/bsdconfig
-FILES= common.subr dialog.subr mustberoot.subr script.subr \
- strings.subr sysrc.subr variable.subr
+FILES= common.subr device.subr dialog.subr mustberoot.subr \
+ script.subr strings.subr struct.subr sysrc.subr variable.subr
beforeinstall:
mkdir -p ${DESTDIR}${FILESDIR}
diff --git a/usr.sbin/bsdconfig/share/common.subr b/usr.sbin/bsdconfig/share/common.subr
index c66a54f..cb9096f 100644
--- a/usr.sbin/bsdconfig/share/common.subr
+++ b/usr.sbin/bsdconfig/share/common.subr
@@ -1,7 +1,7 @@
if [ ! "$_COMMON_SUBR" ]; then _COMMON_SUBR=1
#
# Copyright (c) 2012 Ron McDowell
-# Copyright (c) 2012 Devin Teske
+# Copyright (c) 2012-2013 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -127,15 +127,15 @@ f_have()
#
f_getvar()
{
- local var_to_get="$1" var_to_set="$2"
- [ "$var_to_set" ] || local value
- eval ${var_to_set:-value}=\"\${$var_to_get}\"
- eval [ \"\${$var_to_get+set}\" ]
- local retval=$?
+ local __var_to_get="$1" __var_to_set="$2"
+ [ "$__var_to_set" ] || local value
+ eval ${__var_to_set:-value}=\"\${$__var_to_get}\"
+ eval [ \"\${$__var_to_get+set}\" ]
+ local __retval=$?
eval f_dprintf '"f_getvar: var=[%s] value=[%s] r=%u"' \
- \"\$var_to_get\" \"\$${var_to_set:-value}\" \$retval
- [ "$var_to_set" ] || { [ "$value" ] && echo "$value"; }
- return $retval
+ \"\$__var_to_get\" \"\$${__var_to_set:-value}\" \$__retval
+ [ "$__var_to_set" ] || { [ "$value" ] && echo "$value"; }
+ return $__retval
}
# f_die [ $status [ $fmt [ $opts ... ]]]
@@ -574,6 +574,30 @@ f_index_menusel_command()
echo "$command"
}
+# f_running_as_init
+#
+# Returns true if running as init(1).
+#
+f_running_as_init()
+{
+ #
+ # When a custom init(8) performs an exec(3) to invoke a shell script,
+ # PID 1 becomes sh(1) and $PPID is set to 1 in the executed script.
+ #
+ [ ${PPID:-0} -eq 1 ] # Return status
+}
+
+# f_mounted $local_directory
+#
+# Return success if a filesystem is mounted on a particular directory.
+#
+f_mounted()
+{
+ local dir="$1"
+ [ -d "$dir" ] || return $FAILURE
+ mount | grep -Eq " on $dir \([^)]+\)$"
+}
+
############################################################ MAIN
#
diff --git a/usr.sbin/bsdconfig/share/device.subr b/usr.sbin/bsdconfig/share/device.subr
new file mode 100644
index 0000000..473838b
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/device.subr
@@ -0,0 +1,799 @@
+if [ ! "$_DEVICE_SUBR" ]; then _DEVICE_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/strings.subr
+f_include $BSDCFG_SHARE/struct.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+DEVICES=
+DEVICE_NAMES=
+
+# A "device" from sysinstall's point of view
+f_struct_define DEVICE \
+ name \
+ desc \
+ devname \
+ type \
+ enabled \
+ init \
+ get \
+ shutdown \
+ flags \
+ private \
+ volume
+
+# Network devices have their `private' property set to this
+f_struct_define DEVICE_INFO \
+ use_rtsol use_dhcp ipaddr ipv6addr netmask extras
+
+setvar DEVICE_TYPE_NONE 1
+setvar DEVICE_TYPE_DISK 2
+setvar DEVICE_TYPE_FLOPPY 3
+setvar DEVICE_TYPE_FTP 4
+setvar DEVICE_TYPE_NETWORK 5
+setvar DEVICE_TYPE_CDROM 6
+setvar DEVICE_TYPE_USB 7
+setvar DEVICE_TYPE_DOS 8
+setvar DEVICE_TYPE_UFS 9
+setvar DEVICE_TYPE_NFS 10
+setvar DEVICE_TYPE_ANY 11
+setvar DEVICE_TYPE_HTTP_PROXY 12
+
+#
+# Default behavior is to call f_device_get_all() automatically when loaded.
+#
+: ${DEVICE_SELF_SCAN_ALL=1}
+
+############################################################ FUNCTIONS
+
+# f_device_try $name [$i [$var_path]]
+#
+# Test a particular device. If $i is given, then $name is expected to contain a
+# single "%d" where $i will be inserted using printf. If $var_path is given,
+# it is used as a variable name to provide the caller the device pathname.
+#
+# Returns success if the device path exists and is a cdev.
+#
+f_device_try()
+{
+ local name="$1" i="$2" var_path="$3" unit
+ if [ "$i" ]; then
+ unit=$( printf "$name" "$i" )
+ else
+ unit="$name"
+ fi
+ case "$unit" in
+ /dev/*) : good ;; # already qualified
+ *) unit="/dev/$unit" ;;
+ esac
+ [ "$var_path" ] && setvar "$var_path" "$unit"
+ f_dprintf "f_device_try: making sure %s is a device node" "$unit"
+ if [ -c "$unit" ]; then
+ f_dprintf "f_device_try: %s is a cdev [good]" "$unit"
+ return $SUCCESS
+ else
+ f_dprintf "f_device_try: %s is not a cdev [skip]" "$unit"
+ return $FAILURE
+ fi
+}
+
+# f_device_register $name $desc $devname $type $enabled $init_function \
+# $get_function $shutdown_function $private
+#
+# Register a device. A `structure' (see struct.subr) is created with the name
+# device_$name (so make sure $name contains only alpha-numeric characters or
+# the underscore, `_'). The remaining arguments after $name correspond to the
+# properties of the `DEVICE' structure-type (defined above).
+#
+# If not already registered, the device is then appended to the DEVICES
+# environment variable, a space-separated list of all registered devices.
+#
+f_device_register()
+{
+ local name="$1" desc="$2" devname="$3" type="$4" enabled="$5"
+ local init_func="$6" get_func="$7" shutdown_func="$8" private="$9"
+
+ f_struct_new DEVICE "device_$name" || return $FAILURE
+ device_$name set name "$name"
+ device_$name set desc "$desc"
+ device_$name set devname "$devname"
+ device_$name set type "$type"
+ device_$name set enabled "$enabled"
+ device_$name set init "$init_func"
+ device_$name set get "$get_func"
+ device_$name set shutdown "$shutdown_func"
+ device_$name set private "$private"
+
+ # Scan our global register to see if it needs ammending
+ local dev found=
+ for dev in $DEVICES; do
+ [ "$dev" = "$name" ] || continue
+ found=1 && break
+ done
+ [ "$found" ] || DEVICES="$DEVICES $name"
+
+ return $SUCCESS
+}
+
+# f_device_reset
+#
+# Reset the registered device chain.
+#
+f_device_reset()
+{
+ local dev
+ for dev in $DEVICES; do
+ f_device_shutdown $dev
+
+ #
+ # XXX this potentially leaks $dev->private if it's being
+ # used to point to something dynamic, but you're not supposed
+ # to call this routine at such times that some open instance
+ # has its private member pointing somewhere anyway. XXX
+ #
+ f_struct_free device_$dev
+ done
+ DEVICES=
+}
+
+# f_device_get_all
+#
+# Get all device information for devices we have attached.
+#
+f_device_get_all()
+{
+ local devname desc
+
+ f_dprintf "f_device_get_all: Probing devices..."
+ f_dialog_info "$msg_probing_devices_please_wait_this_can_take_a_while"
+
+ # First go for the network interfaces
+ for devname in $( ifconfig -l ); do
+ # Eliminate network devices that don't make sense
+ case "$devname" in
+ lo*) continue ;;
+ esac
+
+ # Try and find its description
+ f_device_desc "$devname" $DEVICE_TYPE_NETWORK desc
+
+ f_dprintf "Found a network device named %s" "$devname"
+ f_device_register $devname \
+ "$desc" "$devname" $DEVICE_TYPE_NETWORK 1 \
+ f_media_init_network "" f_media_shutdown_network ""
+ done
+
+ # Next, try to find all the types of devices one might use
+ # as a media source for content
+ #
+
+ local dev desc type max n=0
+ for dev in $DEVICE_NAMES; do
+ n=$(( $n + 1 ))
+ # Get the desc, type, and max (with debugging disabled)
+ # NOTE: Bypassing f_device_name_get() for efficiency
+ debug= f_getvar _device_desc$n desc
+ debug= f_getvar _device_type$n type
+ debug= f_getvar _device_max$n max
+
+ local k=0
+ while [ $k -lt ${max:-0} ]; do
+ i=$k k=$(( $k + 1 ))
+ devname=""
+ case "$type" in
+ $DEVICE_TYPE_CDROM)
+ f_device_try "$dev" "$i" devname || continue
+ f_device_register "${devname##*/}" "$desc" \
+ "$devname" $DEVICE_TYPE_CDROM 1 \
+ f_media_init_cdrom f_media_get_cdrom \
+ f_media_shutdown_cdrom ""
+ f_dprintf "Found a CDROM device for %s" \
+ "$devname"
+ ;;
+ $DEVICE_TYPE_FLOPPY)
+ f_device_try "$dev" "$i" devname || continue
+ f_device_register "${devname##*/}" "$desc" \
+ "$devname" $DEVICE_TYPE_FLOPPY 1 \
+ f_media_init_floppy \
+ f_media_get_floppy \
+ f_media_shutdown_floppy ""
+ f_dprintf "Found a floppy device for %s" \
+ "$devname"
+ ;;
+ $DEVICE_TYPE_USB)
+ f_device_try "$dev" "$i" devname || continue
+ f_device_register "${devname##*/}" "$desc" \
+ "$devname" $DEVICE_TYPE_USB 1 \
+ f_media_init_usb f_media_get_usb \
+ f_media_shutdown_usb ""
+ f_dprintf "Found a USB disk for %s" "$devname"
+ ;;
+ esac
+ done
+ done
+
+ # Register ISO9660 providers as CDROM devices
+ for devname in /dev/iso9660/*; do
+ f_device_try "$devname" || continue
+ f_device_register "${devname##*/}" "ISO9660 file system" \
+ "$devname" $DEVICE_TYPE_CDROM 1 \
+ f_media_init_cdrom f_media_get_cdrom \
+ f_media_shutdown_cdrom ""
+ f_dprintf "Found a CDROM device for %s" "$devname"
+ done
+
+ # Scan for mdconfig(8)-created md(4) devices
+ local filename
+ for devname in /dev/md[0-9] /dev/md[0-9][0-9]; do
+ f_device_try "$devname" || continue
+
+ # See if the md(4) device is a vnode type backed by a file
+ filename=$( sysctl kern.geom.conftxt |
+ awk -v devname="${devname##*/}" \
+ '
+ ( $2 == "MD" ) && \
+ ( $3 == devname ) && \
+ ( $(NF-2) == "vnode" ) && \
+ ( $(NF-1) == "file" ) \
+ {
+ print $NF
+ }
+ ' )
+ case "$filename" in
+ *.iso) # Register the device as an ISO9660 provider
+ f_device_register "${devname##*/}" \
+ "md(4) vnode file system" \
+ "$devname" $DEVICE_TYPE_CDROM 1 \
+ f_media_init_cdrom f_media_get_cdrom \
+ f_media_shutdown_cdrom ""
+ f_dprintf "Found a CDROM device for %s" "$devname"
+ ;;
+ esac
+ done
+
+ # Finally go get the disks and look for partitions to register
+ local diskname slices index type rest slice part
+ for diskname in $( sysctl -n kern.disks ); do
+
+ case "$diskname" in
+ cd*)
+ # XXX
+ # Due to unknown reasons, kern.disks returns SCSI
+ # CDROM as a valid disk. This will prevent bsdconfig
+ # from presenting SCSI CDROMs as available disks in
+ # various menus. Why GEOM treats SCSI CDROM as a disk
+ # is beyond me and that should be investigated.
+ # For temporary workaround, ignore SCSI CDROM device.
+ #
+ continue ;;
+ esac
+
+ # Try to create a list of partitions and their types,
+ # consisting of "N,typeN ..." (e.g., "1,0xa5 2,0x06").
+ if ! slices=$( fdisk -p "$diskname" 2> /dev/null |
+ awk '( $1 == "p" ) { print $2","$3 }' )
+ then
+ f_dprintf "Unable to open disk %s" "$diskname"
+ continue
+ fi
+
+ f_device_register "$diskname" "" \
+ "/dev/$diskname" $DEVICE_TYPE_DISK 0
+ f_dprintf "Found a disk device named %s" "$diskname"
+
+ # Look for existing partitions to register
+ for slice in $slices; do
+ index="${slice%%,*}" type="${slice#*,}"
+ slice=${diskname}s$index
+ case "$type" in
+ 0x01|0x04|0x06|0x0b|0x0c|0x0e|0xef)
+ # DOS partitions to add as "DOS media devices"
+ f_device_register "$slice" "" \
+ "/dev/$slice" $DEVICE_TYPE_DOS 1 \
+ f_media_init_dos f_media_get_dos \
+ f_media_shutdown_dos ""
+ f_dprintf "Found a DOS partition %s" "$slice"
+ ;;
+ 0xa5) # FreeBSD partition
+ for part in $(
+ bsdlabel -r $slice 2> /dev/null |
+ awk -v slice="$slice" '
+ ( $1 ~ /[abdefgh]:/ ) {
+ printf "%s%s\n",
+ slice,
+ substr($1,1,1)
+ }'
+ ); do
+ f_quietly dumpfs -m /dev/$part ||
+ continue
+ f_device_register \
+ "$part" "" "/dev/$part" \
+ $DEVICE_TYPE_UFS 1 \
+ f_media_init_ufs \
+ f_media_get_ufs \
+ f_media_shutdown_ufs ""
+ f_dprintf "Found a UFS partition %s" \
+ "$part"
+ done # parts
+ ;;
+ esac
+ done # slices
+
+ done # disks
+}
+
+# f_device_name_get $type $name type|desc|max [$var_to_set]
+#
+# Fetch the device type (type), description (desc), or maximum number of
+# devices to scan for (max) associated with device $name and $type. If $type is
+# either NULL, missing, or set to $DEVICE_TYPE_ANY then only $name is used.
+# Returns success if a match was found, otherwise failure.
+#
+# If $var_to_set is missing or NULL, the device name is printed to standard out
+# for capturing in a sub-shell (which is less-recommended because of
+# performance degredation; for example, when called in a loop).
+#
+f_device_name_get()
+{
+ local __type="$1" __name="$2" __prop="$3" __var_to_set="$4"
+ local __dev __devtype __n=0
+
+ # Return failure if no $name or $prop is an unknown property
+ [ "$__name" ] || return $FAILURE
+ case "$__prop" in type|desc|max) : good ;;
+ *) return $FAILURE; esac
+
+ [ "$__type" = "$DEVICE_TYPE_ANY" ] && __type=
+ for __dev in $DEVICE_NAMES; do
+ __n=$(( $__n + 1 ))
+ [ "$__dev" = "$__name" ] || continue
+ f_getvar _device_type$__n __devtype
+ [ "${__type:-$__devtype}" = "$__devtype" ] || continue
+ f_getvar _device_$__prop$__n $__var_to_set
+ return $?
+ done
+ return $FAILURE
+}
+
+# f_device_name_set $type $name $desc [$max]
+#
+# Store a description (desc) and [optionally] maximum number of devices to scan
+# for (max) in-association with device $type and $name. Returns success. Use
+# the f_device_name_get() routine with the same $name and [optionally] $type to
+# retrieve one of type, desc, or max properties.
+#
+f_device_name_set()
+{
+ local type="$1" name="$2" desc="$3" max="$4"
+ local dev devtype n=0 found=
+ [ "$name" ] || return $FAILURE
+ for dev in $DEVICE_NAMES; do
+ n=$(( $n + 1 ))
+ [ "$dev" = "$name" ] || continue
+ if f_getvar _device_type$n devtype; then
+ # Allow multiple entries with same name but diff type
+ [ "$devtype" = "$type" ] || continue
+ fi
+ found=1 && break
+ done
+ if [ ! "$found" ]; then
+ DEVICE_NAMES="$DEVICE_NAMES $name"
+ n=$(( $n + 1 ))
+ fi
+ setvar _device_type$n "$type"
+ setvar _device_desc$n "$desc"
+ [ "${4+set}" ] && setvar _device_max$n "$max"
+ return $SUCCESS
+}
+
+# f_device_desc $device_name $device_type [$var_to_set]
+#
+# Print a description for a device name (eg., `fxp0') given a specific device
+# type/class.
+#
+# If $var_to_set is missing or NULL, the device description is printed to
+# standard out for capturing in a sub-shell (which is less-recommended because
+# of performance degredation; for example, when called in a loop).
+#
+f_device_desc()
+{
+ local __name="$1" __type="$2" __var_to_set="$3"
+ local __devname __devunit __cp
+
+ # Check variables
+ [ "$__name" ] || return $SUCCESS
+ [ "$__type" = "$DEVICE_TYPE_ANY" ] && type=
+ [ "$__var_to_set" ] && { setvar "$__var_to_set" "" || return; }
+
+ #
+ # Return sysctl MIB dev.NAME.UNIT.%desc if it exists,
+ # otherwise fall through to below static list.
+ #
+ if f_have sysctl; then
+ __devname="${__name%%[0-9]*}"
+ __devunit="${__name#$__devname}"
+ __devunit="${__devunit%%[!0-9]*}"
+ if [ "$__var_to_set" ]; then
+ if __cp=$(
+ sysctl -n "dev.$__devname.$__devunit.%desc" \
+ 2> /dev/null
+ ); then
+ setvar "$__var_to_set" "$__cp" &&
+ return $SUCCESS
+ fi
+ else
+ sysctl -n "dev.$__devname.$__devunit.%desc" \
+ 2> /dev/null && return $SUCCESS
+ fi
+ fi
+
+ local __dev __devtype __n=0
+ for __dev in $DEVICE_NAMES; do
+ __n=$(( $__n + 1 ))
+ debug= f_getvar _device_type$__n __devtype
+ [ "${__type:-$__devtype}" = "$__devtype" ] || continue
+ if [ "$__devtype" = "$DEVICE_TYPE_NETWORK" ]; then
+ __devname=$( f_substr "$__name" 0 ${#__dev} )
+ [ "$__devname" = "$__dev" ] || continue
+ else
+ __devname="${__name%%[0-9]*}"
+ __devunit="${__name#$__devname}"
+ __devunit="${__devunit%%[!0-9]*}"
+ __devname=$( printf "$__dev" $__devunit )
+ [ "$__devname" = "$__name" ] || continue
+ fi
+ debug= f_getvar _device_desc$__n $__var_to_set
+ return $?
+ done
+
+ #
+ # Sensible fall-backs for specific types
+ #
+ case "$__type" in
+ $DEVICE_TYPE_CDROM) __cp="<unknown cdrom device type>";;
+ $DEVICE_TYPE_DISK) __cp="<unknown disk device type>";;
+ $DEVICE_TYPE_FLOPPY) __cp="<unknown floppy device type>";;
+ $DEVICE_TYPE_USB) __cp="<unknown usb storage device type>";;
+ $DEVICE_TYPE_NETWORK) __cp="<unknown network interface type>";;
+ *)
+ __cp="<unknown device type>"
+ esac
+
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$__cp"
+ else
+ echo "$__cp"
+ fi
+
+ return $FAILURE
+}
+
+# f_device_rescan
+#
+# Rescan all devices, after closing previous set - convenience function.
+#
+f_device_rescan()
+{
+ f_device_reset
+ f_device_get_all
+}
+
+# f_device_find $name [$type [$var_to_set]]
+#
+# Find one or more registered devices by name, type, or both. Returns a space-
+# separated list of devices matching the search criterion.
+#
+# If $var_to_set is missing or NULL, the device name(s) are printed to standard
+# out for capturing in a sub-shell (which is less-recommended because of
+# performance degredation; for example, when called in a loop).
+#
+f_device_find()
+{
+ local __name="$1" __type="${2:-$DEVICE_TYPE_ANY}" __var_to_set="$3"
+ local __dev __devname __devtype __found=
+ for __dev in $DEVICES; do
+ device_$__dev get name __devname
+ device_$__dev get type __devtype
+ if [ "$__name" = "$__devname" -o ! "$__name" ] &&
+ [ "$__type" = "$DEVICE_TYPE_ANY" -o \
+ "$__type" = "$__devtype" ]
+ then
+ __found="$__found $__dev"
+ fi
+ done
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "${__found# }"
+ else
+ echo $__found
+ fi
+ [ "$__found" ] # Return status
+}
+
+# f_device_init $name
+#
+# Initialize a device by evaluating its `init' function.
+#
+f_device_init()
+{
+ local name="$1" init_func
+ device_$name get init init_func || return
+ ${init_func:-:} $name
+}
+
+# f_device_get $name $file [$probe]
+#
+# Read $file by evaluating the device's `get' function. The file is commonly
+# produced on standard output (but it truly depends on the function called).
+#
+f_device_get()
+{
+ local name="$1" file="$2" probe="$3" get_func
+ device_$name get get get_func || return
+ ${get_func:-:} $name "$file" ${3+"$probe"}
+}
+
+# f_device_shutdown $name
+#
+# Shutdown a device by evaluating its `shutdown' function.
+#
+f_device_shutdown()
+{
+ local name="$1" shutdown_func
+ device_$name get shutdown shutdown_func || return
+ ${shutdown_func:-:} $name
+}
+
+# f_device_menu $title $prompt $hline $device_type [$helpfile]
+#
+# Display a menu listing all the devices of a certain type in the system.
+#
+f_device_menu()
+{
+ f_dialog_title "$1"
+ local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+
+ local prompt="$2" hline="$3" type="$4" helpfile="$5"
+
+ local dev devtype devs=
+ for dev in $DEVICES; do
+ device_$dev get type devtype || continue
+ [ "$devtype" = "$type" ] || continue
+ devs="$devs $dev"
+ done
+ [ "$devs" ] || return $FAILURE
+
+ local sanitize_awk="{ gsub(/'/, \"'\\\\''\"); print }"
+
+ local desc menu_list=
+ for dev in $devs; do
+ device_$dev get desc desc
+ desc=$( echo "$desc" | awk "$sanitize_awk" )
+ menu_list="$menu_list '$dev' '$desc'"
+ done
+
+ local size mtag
+ size=$( eval f_dialog_menu_size \
+ \"\$title\" \
+ \"\$btitle\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ local errexit=
+ case $- in *e*) errexit=1; esac
+ set +e
+
+ while :; do
+ mtag=$( eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ ${helpfile:+ \
+ --help-button \
+ --help-label \"\$msg_help\" \
+ ${USE_XDIALOG:+--help \"\"} \
+ } \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+ )
+ local retval=$?
+
+ [ $retval -ne 2 ] && break
+ # Otherwise, the Help button was pressed
+ f_show_help "$helpfile"
+ # Loop back to menu
+ done
+ f_dprintf "retval=%u mtag=[%s]" $retval "$mtag"
+
+ [ "$errexit" ] && set -e
+
+ [ $retval -eq 0 ] && echo "$mtag" >&2
+
+ return $retval
+}
+
+#
+# Short-hand
+#
+f_cdrom() { f_device_name_set $DEVICE_TYPE_CDROM "$1" "$2" "$3"; }
+f_disk() { f_device_name_set $DEVICE_TYPE_DISK "$1" "$2" "$3"; }
+f_floppy() { f_device_name_set $DEVICE_TYPE_FLOPPY "$1" "$2" "$3"; }
+f_serial() { f_device_name_set $DEVICE_TYPE_NETWORK "$1" "$2" "$3"; }
+f_usb() { f_device_name_set $DEVICE_TYPE_USB "$1" "$2" "$3"; }
+f_network() { f_device_name_set $DEVICE_TYPE_NETWORK "$1" "$2"; }
+
+############################################################ MAIN
+
+# CDROM, Disk, Floppy, Serial, and USB devices/names
+f_cdrom "acd%d" "ATAPI/IDE CDROM" 4
+f_cdrom "cd%d" "SCSI CDROM drive" 4
+f_cdrom "mcd%d" "Mitsumi (old model) CDROM drive" 4
+f_cdrom "scd%d" "Sony CDROM drive - CDU31/33A type" 4
+f_disk "aacd%d" "Adaptec FSA RAID array" 4
+f_disk "ad%d" "ATA/IDE disk device" 16
+f_disk "ada%d" "SATA disk device" 16
+f_disk "afd%d" "ATAPI/IDE floppy device" 4
+f_disk "amrd%d" "AMI MegaRAID drive" 4
+f_disk "ar%d" "ATA/IDE RAID device" 16
+f_disk "da%d" "SCSI disk device" 16
+f_disk "idad%d" "Compaq RAID array" 4
+f_disk "ipsd%d" "IBM ServeRAID RAID array" 4
+f_disk "mfid%d" "LSI MegaRAID SAS array" 4
+f_disk "mlxd%d" "Mylex RAID disk" 4
+f_disk "twed%d" "3ware ATA RAID array" 4
+f_floppy "fd%d" "Floppy Drive unit A" 4
+f_serial "cuau%d" "%s on device %s (COM%d)" 16
+f_usb "da%da" "USB Mass Storage Device" 16
+
+# Network interfaces/names
+f_network "ae" "Attansic/Atheros L2 Fast Ethernet"
+f_network "age" "Attansic/Atheros L1 Gigabit Ethernet"
+f_network "alc" "Atheros AR8131/AR8132 PCIe Ethernet"
+f_network "ale" "Atheros AR8121/AR8113/AR8114 PCIe Ethernet"
+f_network "an" "Aironet 4500/4800 802.11 wireless adapter"
+f_network "ath" "Atheros IEEE 802.11 wireless adapter"
+f_network "aue" "ADMtek USB Ethernet adapter"
+f_network "axe" "ASIX Electronics USB Ethernet adapter"
+f_network "bce" "Broadcom NetXtreme II Gigabit Ethernet card"
+f_network "bfe" "Broadcom BCM440x PCI Ethernet card"
+f_network "bge" "Broadcom BCM570x PCI Gigabit Ethernet card"
+f_network "bm" "Apple BMAC Built-in Ethernet"
+f_network "bwn" "Broadcom BCM43xx IEEE 802.11 wireless adapter"
+f_network "cas" "Sun Cassini/Cassini+ or NS DP83065 Saturn Ethernet"
+f_network "cc3i" "SDL HSSI sync serial PCI card"
+f_network "cue" "CATC USB Ethernet adapter"
+f_network "cxgb" "Chelsio T3 10Gb Ethernet card"
+f_network "dc" "DEC/Intel 21143 (and clones) PCI Fast Ethernet card"
+f_network "de" "DEC DE435 PCI NIC or other DC21040-AA based card"
+f_network "disc" "Software discard network interface"
+f_network "ed" "Novell NE1000/2000; 3C503; NE2000-compatible PCMCIA"
+f_network "el" "3Com 3C501 Ethernet card"
+f_network "em" "Intel(R) PRO/1000 Ethernet card"
+f_network "en" "Efficient Networks ATM PCI card"
+f_network "ep" "3Com 3C509 Ethernet card/3C589 PCMCIA"
+f_network "et" "Agere ET1310 based PCI Express Gigabit Ethernet card"
+f_network "ex" "Intel EtherExpress Pro/10 Ethernet card"
+f_network "fe" "Fujitsu MB86960A/MB86965A Ethernet card"
+f_network "fpa" "DEC DEFPA PCI FDDI card"
+f_network "fwe" "FireWire Ethernet emulation"
+f_network "fwip" "IP over FireWire"
+f_network "fxp" "Intel EtherExpress Pro/100B PCI Fast Ethernet card"
+f_network "gem" "Apple GMAC or Sun ERI/GEM Ethernet adapter"
+f_network "hme" "Sun HME (Happy Meal Ethernet) Ethernet adapter"
+f_network "ie" "AT&T StarLAN 10 and EN100; 3Com 3C507; NI5210"
+f_network "igb" "Intel(R) PRO/1000 PCI Express Gigabit Ethernet card"
+f_network "ipw" "Intel PRO/Wireless 2100 IEEE 802.11 adapter"
+f_network "iwi" "Intel PRO/Wireless 2200BG/2225BG/2915ABG adapter"
+f_network "iwn" "Intel Wireless WiFi Link 4965AGN IEEE 802.11n adapter"
+f_network "ixgbe" "Intel(R) PRO/10Gb Ethernet card"
+f_network "ixgb" "Intel(R) PRO/10Gb Ethernet card"
+f_network "ix" "Intel Etherexpress Ethernet card"
+ # Maintain sequential order of above(3): ixgbe ixgb ix
+f_network "jme" "JMicron JMC250 Gigabit/JMC260 Fast Ethernet"
+f_network "kue" "Kawasaki LSI USB Ethernet adapter"
+f_network "le" "AMD Am7900 LANCE or Am79C9xx PCnet Ethernet adapter"
+f_network "lge" "Level 1 LXT1001 Gigabit Ethernet card"
+f_network "lnc" "Lance/PCnet (Isolan/Novell NE2100/NE32-VL) Ethernet"
+f_network "lo" "Loop-back (local) network interface"
+f_network "lp" "Parallel Port IP (PLIP) peer connection"
+f_network "malo" "Marvell Libertas 88W8335 802.11 wireless adapter"
+f_network "msk" "Marvell/SysKonnect Yukon II Gigabit Ethernet"
+f_network "mxge" "Myricom Myri10GE 10Gb Ethernet card"
+f_network "nfe" "NVIDIA nForce MCP Ethernet"
+f_network "nge" "NatSemi PCI Gigabit Ethernet card"
+f_network "ng" "Vimage netgraph(4) bridged Ethernet device"
+ # Maintain sequential order of above(2): nge ng
+f_network "nve" "NVIDIA nForce MCP Ethernet"
+f_network "nxge" "Neterion Xframe 10GbE Server/Storage adapter"
+f_network "pcn" "AMD Am79c79x PCI Ethernet card"
+f_network "plip" "Parallel Port IP (PLIP) peer connection"
+f_network "ral" "Ralink Technology IEEE 802.11 wireless adapter"
+f_network "ray" "Raytheon Raylink 802.11 wireless adapter"
+f_network "re" "RealTek 8139C+/8169/8169S/8110S PCI Ethernet adapter"
+f_network "rl" "RealTek 8129/8139 PCI Ethernet card"
+f_network "rue" "RealTek USB Ethernet card"
+f_network "rum" "Ralink Technology USB IEEE 802.11 wireless adapter"
+f_network "sf" "Adaptec AIC-6915 PCI Ethernet card"
+f_network "sge" "Silicon Integrated Systems SiS190/191 Ethernet"
+f_network "sis" "SiS 900/SiS 7016 PCI Ethernet card"
+f_network "sk" "SysKonnect PCI Gigabit Ethernet card"
+f_network "snc" "SONIC Ethernet card"
+f_network "sn" "SMC/Megahertz Ethernet card"
+ # Maintain sequential order of above(2): snc sn
+f_network "sr" "SDL T1/E1 sync serial PCI card"
+f_network "ste" "Sundance ST201 PCI Ethernet card"
+f_network "stge" "Sundance/Tamarack TC9021 Gigabit Ethernet"
+f_network "ti" "Alteon Networks PCI Gigabit Ethernet card"
+f_network "tl" "Texas Instruments ThunderLAN PCI Ethernet card"
+f_network "txp" "3Com 3cR990 Ethernet card"
+f_network "tx" "SMC 9432TX Ethernet card"
+ # Maintain sequential order of above(2): txp tx
+f_network "uath" "Atheros AR5005UG and AR5005UX USB wireless adapter"
+f_network "upgt" "Conexant/Intersil PrismGT USB wireless adapter"
+f_network "ural" "Ralink Technology RT2500USB 802.11 wireless adapter"
+f_network "urtw" "Realtek 8187L USB wireless adapter"
+f_network "vge" "VIA VT612x PCI Gigabit Ethernet card"
+f_network "vlan" "IEEE 802.1Q VLAN network interface"
+f_network "vr" "VIA VT3043/VT86C100A Rhine PCI Ethernet card"
+f_network "vx" "3COM 3c590 / 3c595 Ethernet card"
+f_network "wb" "Winbond W89C840F PCI Ethernet card"
+f_network "wi" "Lucent WaveLAN/IEEE 802.11 wireless adapter"
+f_network "wpi" "Intel 3945ABG IEEE 802.11 wireless adapter"
+f_network "wx" "Intel Gigabit Ethernet (82452) card"
+f_network "xe" "Xircom/Intel EtherExpress Pro100/16 Ethernet card"
+f_network "xl" "3COM 3c90x / 3c90xB PCI Ethernet card"
+f_network "zyd" "ZyDAS ZD1211/ZD1211B USB 802.11 wireless adapter"
+
+f_dprintf "%s: Initialized %u known device names/descriptions." device.subr \
+ "$( set -- $DEVICE_NAMES; echo $# )"
+
+#
+# Scan for the above devices unless requeted otherwise
+#
+f_dprintf "%s: DEVICE_SELF_SCAN_ALL=[%s]" device.subr "$DEVICE_SELF_SCAN_ALL"
+case "$DEVICE_SELF_SCAN_ALL" in
+""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
+*) f_device_get_all
+esac
+
+f_dprintf "%s: Successfully loaded." device.subr
+
+fi # ! $_DEVICE_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/Makefile b/usr.sbin/bsdconfig/share/media/Makefile
new file mode 100644
index 0000000..ebd7c96
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+NO_OBJ=
+
+FILESDIR= ${SHAREDIR}/bsdconfig/media
+FILES= any.subr cdrom.subr common.subr directory.subr dos.subr \
+ floppy.subr ftp.subr httpproxy.subr network.subr nfs.subr \
+ options.subr tcpip.subr ufs.subr usb.subr
+
+beforeinstall:
+ mkdir -p ${DESTDIR}${FILESDIR}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/share/media/any.subr b/usr.sbin/bsdconfig/share/media/any.subr
new file mode 100644
index 0000000..f64710f
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/any.subr
@@ -0,0 +1,152 @@
+if [ ! "$_MEDIA_ANY_SUBR" ]; then _MEDIA_ANY_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/any.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/media/cdrom.subr
+f_include $BSDCFG_SHARE/media/directory.subr
+f_include $BSDCFG_SHARE/media/dos.subr
+f_include $BSDCFG_SHARE/media/floppy.subr
+f_include $BSDCFG_SHARE/media/ftp.subr
+f_include $BSDCFG_SHARE/media/httpproxy.subr
+f_include $BSDCFG_SHARE/media/nfs.subr
+f_include $BSDCFG_SHARE/media/options.subr
+f_include $BSDCFG_SHARE/media/ufs.subr
+f_include $BSDCFG_SHARE/media/usb.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+MEDIA_HELPFILE=$BSDCFG_LIBE/include/media.hlp
+
+############################################################ FUNCTIONS
+
+# f_media_get_type
+#
+# Prompt the user to select amongst the known media types (included above).
+#
+# If the user does not cancel or press Esc, invokes the f_media_set_* function
+# associated with the chosen media type. If after all that we have a struct
+# named `device_media' then success is returned, otherwise failure.
+#
+# NOTE: The f_media_set_* function should create the `device_media' struct.
+# See `struct.subr' and the above `media/*.subr' includes for more details.
+#
+f_media_get_type()
+{
+ f_dialog_title "$msg_choose_installation_media"
+ local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ local prompt="$msg_choose_installation_media_description"
+ local hline="$hline_choose_help_for_more_information_on_media_types"
+ local menu_list size
+
+ menu_list="
+ '1 $msg_cd_dvd' '$msg_install_from_a_freebsd_cd_dvd'
+ '2 $msg_ftp' '$msg_install_from_an_ftp_server'
+ '3 $msg_ftp_passive'
+ '$msg_install_from_an_ftp_server_thru_firewall'
+ '4 $msg_http' '$msg_install_from_an_ftp_server_thru_proxy'
+ '5 $msg_directory' '$msg_install_from_the_existing_filesystem'
+ '6 $msg_nfs' '$msg_install_over_nfs'
+ '7 $msg_dos' '$msg_install_from_a_dos_partition'
+ '8 $msg_ufs' '$msg_install_from_a_ufs_partition'
+ '9 $msg_floppy' '$msg_install_from_a_floppy_disk_set'
+ 'A $msg_usb' '$msg_install_from_a_usb_drive'
+ 'X $msg_options' '$msg_view_set_various_media_options'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_size \
+ \"\$title\" \
+ \"\$btitle\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ local dialog_menu
+
+ while :; do
+ dialog_menu=$( eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --help-button \
+ --help-label \"\$msg_help\" \
+ ${USE_XDIALOG:+--help \"\"} \
+ --menu \"\$prompt\" $size $menu_list \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+ )
+ local retval=$?
+ setvar DIALOG_MENU_$$ "$dialog_menu"
+
+ local mtag
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=%s mtag=[%s]" $retval "$mtag"
+
+ if [ $retval -eq 2 ]; then
+ # The Help button was pressed
+ f_show_help "$MEDIA_HELPFILE"
+ continue
+ elif [ $retval -ne 0 ]; then
+ return $FAILURE
+ fi
+
+ case "$mtag" in
+ ?" $msg_cd_dvd") f_media_set_cdrom ;;
+ ?" $msg_ftp") f_media_set_ftp_active ;;
+ ?" $msg_ftp_passive") f_media_set_ftp_passive ;;
+ ?" $msg_http") f_media_set_http_proxy ;;
+ ?" $msg_directory") f_media_set_directory ;;
+ ?" $msg_dos") f_media_set_dos ;;
+ ?" $msg_nfs") f_media_set_nfs ;;
+ ?" $msg_ufs") f_media_set_ufs ;;
+ ?" $msg_floppy") f_media_set_floppy ;;
+ ?" $msg_usb") f_media_set_usb ;;
+ ?" $msg_options")
+ f_media_options_menu
+ continue
+ ;;
+ esac
+ break
+ done
+
+ f_struct device_media || return $FAILURE
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/any.subr
+
+fi # ! $_MEDIA_ANY_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/cdrom.subr b/usr.sbin/bsdconfig/share/media/cdrom.subr
new file mode 100644
index 0000000..f22ebd2
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/cdrom.subr
@@ -0,0 +1,210 @@
+if [ ! "$_MEDIA_CDROM_SUBR" ]; then _MEDIA_CDROM_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/cdrom.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/common.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+CDROM_MOUNTED=
+CDROM_PREVIOUSLY_MOUNTED=
+CDROM_INIT_QUIET=
+
+############################################################ FUNCTIONS
+
+# f_media_set_cdrom
+#
+# Return success if we both found and set the media type to be a CD.
+#
+f_media_set_cdrom()
+{
+ f_media_close
+
+ local devs ndevs
+ f_device_find "" $DEVICE_TYPE_CDROM devs
+ ndevs=$( set -- $devs; echo $# )
+
+ if [ ${ndevs:=0} -eq 0 ]; then
+ f_interactive && f_dialog_msgbox "$msg_no_cd_dvd_devices_found"
+ return $FAILURE
+ elif [ $ndevs -gt 1 ]; then
+ local title="$msg_choose_a_cd_dvd_type"
+ local prompt="$msg_please_select_a_cd_dvd_drive"
+ local hline=""
+
+ local dev retval
+ dev=$( f_device_menu \
+ "$title" "$prompt" "$hline" $DEVICE_TYPE_CDROM \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
+ retval=$?
+ [ "$dev" ] || return $FAILURE
+
+ f_device_find "$dev" $DEVICE_TYPE_CDROM devs
+ [ "$devs" ] || return $FAILURE
+ dev="${devs%%[$IFS]*}"
+
+ f_struct_copy device_$dev device_media
+ [ $retval -eq $SUCCESS ] || return $FAILURE
+ else
+ f_struct_copy device_$devs device_media
+ fi
+
+ f_struct device_media || return $FAILURE
+}
+
+# f_media_init_cdrom $device
+#
+# Initializes the CDROM media device. Returns success if able to mount the CD
+# device using mount_cd9660(8).
+#
+f_media_init_cdrom()
+{
+ local dev="$1" devname err
+
+ device_$dev get devname devname || return $FAILURE
+ f_dprintf "Init routine called for CDROM device. devname=[%s]" \
+ "$devname"
+
+ if [ "$CDROM_MOUNTED" ]; then
+ f_dprintf "CDROM device already mounted."
+ return $SUCCESS
+ fi
+
+ if [ ! -e "$MOUNTPOINT" ] &&
+ ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
+ then
+ f_dialog_msgbox "$err"
+ return $FAILURE
+ fi
+
+ if ! err=$( mount_cd9660 "$devname" "$MOUNTPOINT" 2>&1 )
+ then
+ err="${err#mount_cd9660: }"; err="${err#$devname: }"
+ case "$err" in
+ "Device busy")
+ # Perhaps the CDROM drive is already mounted as /cdrom
+ if f_mounted /cdrom; then
+ CDROM_PREVIOUSLY_MOUNTED=1
+ MOUNTPOINT=/cdrom
+ err=
+ fi
+ ;;
+ esac
+ case "$err" in
+ "") : good ;; # no error
+ *)
+ [ "$CDROM_INIT_QUIET" ] ||
+ f_show_msg "$msg_error_mounting_device" \
+ "$devname" "$MOUNTPOINT" "$err"
+ return $FAILURE
+ esac
+ fi
+ CDROM_MOUNTED=1
+
+ : xxx # /cdrom.inf has been deprecated since 9.0-R
+
+ # No other CDROM media validation at this time
+
+ return $SUCCESS
+}
+
+# f_media_get_cdrom $device $file [$probe_only]
+#
+# Returns data from $file on a mounted CDROM device. Similar to cat(1).
+# $probe_only is currently unused by this media type.
+#
+f_media_get_cdrom()
+{
+ local dev="$1" file="$2" probe_only="$3"
+
+ f_dprintf "f_media_get_cdrom: dev=[%s] file=[%s] probe_only=%s" \
+ "$dev" "$file" "$probe_only"
+
+ f_media_generic_get "$MOUNTPOINT" "$file"
+}
+
+# f_media_shutdown_cdrom $device
+#
+# Shuts down the CDROM device and ejects the media using f_media_eject_cdrom(),
+# below. Return status should be ignored.
+#
+f_media_shutdown_cdrom()
+{
+ local dev="$1" err
+
+ [ "$CDROM_MOUNTED" ] || return
+
+ if [ "$CDROM_PREVIOUSLY_MOUNTED" ]; then
+ CDROM_MOUNTED=
+ return $SUCCESS
+ fi
+
+ if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ err="${err#umount: }"; err="${err#*: }"
+ f_show_msg "$msg_could_not_unmount_the_cdrom_dvd" \
+ "$MOUNTPOINT" "$err"
+ else
+ CDROM_MOUNTED=
+ fi
+
+ f_media_eject_cdrom "$dev"
+}
+
+# f_media_eject_cdrom $device
+#
+# Eject the media from the CDROM device. Returns success.
+#
+f_media_eject_cdrom()
+{
+ local dev="$1" devname err
+ device_$dev get name devname || return $SUCCESS
+ case "$devname" in /dev/iso9660/*) return $SUCCESS; esac
+ f_dprintf "Ejecting CDROM/DVD at %s" "$devname"
+ if ! err=$( cdcontrol -f "$devname" eject 2>&1 ); then
+ f_dprintf "Could not eject the CDROM/DVD from %s: %s" \
+ "$devname" "${err#cdcontrol: }"
+ fi
+ return $SUCCESS
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/cdrom.subr
+
+fi # ! $_MEDIA_CDROM_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/common.subr b/usr.sbin/bsdconfig/share/media/common.subr
new file mode 100644
index 0000000..589bbdc
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/common.subr
@@ -0,0 +1,109 @@
+if [ ! "$_MEDIA_COMMON_SUBR" ]; then _MEDIA_COMMON_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/common.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+
+############################################################ GLOBALS
+
+#
+# Where to mount media
+#
+MOUNTPOINT=/dist
+
+############################################################ FUNCTIONS
+
+# f_media_open
+#
+# Returms success if able to initialize the media device.
+#
+f_media_open()
+{
+ { # Verify and initialize device media if-defined
+ f_struct device_media &&
+ f_media_verify &&
+ f_device_init media
+ } || return $FAILURE
+}
+
+# f_media_close
+#
+# Shuts down the media device, see f_device_shutdown() from device.subr for
+# more details.
+#
+f_media_close()
+{
+ f_struct device_media &&
+ f_device_shutdown media
+ f_struct_free device_media
+}
+
+# f_media_verify
+#
+# Returns success if the media device is available, and if not, prompts the
+# user to select a media type. See f_media_get_type() from media/any.subr for
+# more details.
+#
+f_media_verify()
+{
+ f_struct device_media || f_media_get_type
+}
+
+# f_media_generic_get $base $file
+#
+# A generic open which follows a well-known "path" of places to look.
+#
+f_media_generic_get()
+{
+ local base="$1" file="$2" rel path
+
+ f_getvar $VAR_RELNAME rel
+ for path in \
+ "$base/$file" \
+ "$base/FreeBSD/$file" \
+ "$base/releases/$file" \
+ "$base/$rel/$file" \
+ ; do
+ if [ -f "$path" -a -r "$path" ]; then
+ cat "$path"
+ return
+ fi
+ done
+ cat "$base/releases/$rel/$file" # Final path to try
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/common.subr
+
+fi # ! $_MEDIA_COMMON_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/directory.subr b/usr.sbin/bsdconfig/share/media/directory.subr
new file mode 100644
index 0000000..3831140
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/directory.subr
@@ -0,0 +1,146 @@
+if [ ! "$_MEDIA_DIRECTORY_SUBR" ]; then _MEDIA_DIRECTORY_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/directory.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/common.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+DIRECTORY_CHECKED=
+
+############################################################ FUNCTIONS
+
+# f_media_set_directory
+#
+# Return success if we both found and set the media type to be a local
+# directory.
+#
+# Variables from variable.subr that can be used to script user input:
+#
+# VAR_DIRECTORY_PATH
+# Path to an existing directory containing the FreeBSD
+# distribution files.
+#
+f_media_set_directory()
+{
+ local path
+
+ f_media_close
+
+ f_variable_get_value $VAR_DIRECTORY_PATH \
+ "$msg_enter_a_fully_qualified_pathname_for_the_directory"
+ f_getvar $VAR_DIRECTORY_PATH path
+ [ "$path" ] || return $FAILURE
+
+ f_struct_new DEVICE device_directory
+ device_directory set get f_media_get_directory
+ device_directory set init f_media_init_directory
+ device_directory set shutdown f_media_shutdown_directory
+ device_directory set private "$path"
+
+ f_struct_copy device_directory device_media
+ f_struct_free device_directory
+
+ f_struct device_media || return $FAILURE
+}
+
+# f_media_init_directory $device
+#
+# Initializes the Directory media device. Returns success if the directory path
+# both exists and is a directory.
+#
+f_media_init_directory()
+{
+ local dev="$1" path
+
+ device_$dev get private path || return $FAILURE
+ f_dprintf "Init routine called for Directory device. path=[%s]" \
+ "$path"
+
+ # Track whether we've been through here before (for remote filesystems
+ # mounted in the directory path, not repeating these queries saves us
+ # valuable time for slow/uncooperative links).
+ if [ "$DIRECTORY_CHECKED" ]; then
+ f_dprintf "Directory device already checked."
+ return $SUCCESS
+ fi
+
+ if [ ! -e "$path" ]; then
+ f_show_msg "$msg_no_such_file_or_directory" \
+ "f_media_init_directory" "$path"
+ return $FAILURE
+ elif [ ! -d "$path" ]; then
+ f_show_msg "$msg_not_a_directory" \
+ "f_media_init_directory" "$path"
+ return $FAILURE
+ fi
+ DIRECTORY_CHECKED=1
+ return $SUCCESS
+}
+
+# f_media_get_directory $device $file [$probe_only]
+#
+# Returns data from $file in the existing/current filesystem. Similar to
+# cat(1). $probe_only is currently unused by this media type.
+#
+f_media_get_directory()
+{
+ local dev="$1" file="$2" probe_only="$3" path
+
+ f_dprintf "f_media_get_directory: dev=[%s] file=[%s] probe_only=%s" \
+ "$dev" "$file" "$probe_only"
+
+ device_$dev get private path
+ f_media_generic_get "$path" "$file"
+}
+
+# f_media_shutdown_directory $device
+#
+# Shuts down the Directory device. Return status should be ignored.
+#
+f_media_shutdown_directory()
+{
+ DIRECTORY_CHECKED=
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/directory.subr
+
+fi # ! $_MEDIA_DIRECTORY_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/dos.subr b/usr.sbin/bsdconfig/share/media/dos.subr
new file mode 100644
index 0000000..3e59fb6
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/dos.subr
@@ -0,0 +1,164 @@
+if [ ! "$_MEDIA_DOS_SUBR" ]; then _MEDIA_DOS_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/dos.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/common.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+DOS_MOUNTED=
+
+############################################################ FUNCTIONS
+
+# f_media_set_dos
+#
+# Return success if we both found and set the media type to be a DOS partition.
+#
+f_media_set_dos()
+{
+ f_media_close
+
+ local devs ndevs
+ f_device_find "" $DEVICE_TYPE_DOS devs
+ ndevs=$( set -- $devs; echo $# )
+
+ if [ ${ndevs:=0} -eq 0 ]; then
+ f_dialog_msgbox "$msg_no_dos_primary_partitions_found"
+ return $FAILURE
+ elif [ $ndevs -gt 1 ]; then
+ local title="$msg_choose_a_dos_partition"
+ local prompt="$msg_please_select_dos_partition"
+ local hline=""
+
+ local dev retval
+ dev=$( f_device_menu \
+ "$title" "$prompt" "$hline" $DEVICE_TYPE_DOS \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
+ retval=$?
+ [ "$dev" ] || return $FAILURE
+
+ f_device_find "$dev" $DEVICE_TYPE_DOS devs
+ [ "$devs" ] || return $FAILURE
+ dev="${devs%%[$IFS]*}"
+
+ f_struct_copy device_$dev device_media
+ [ $retval -eq $SUCCESS ] || return $FAILURE
+ else
+ f_struct_copy device_$devs device_media
+ fi
+
+ f_struct device_media || return $FAILURE
+}
+
+# f_media_init_dos $device
+#
+# Initializes the DOS media device. Returns success if able to mount the DOS
+# partition device using mount_msdosfs(8).
+#
+f_media_init_dos()
+{
+ local dev="$1" devname err
+
+ device_$dev get devname devname || return $FAILURE
+ f_dprintf "Init routine called for DOS device. devname=[%s]" \
+ "$devname"
+
+ if [ "$DOS_MOUNTED" ]; then
+ f_dprintf "DOS device already mounted."
+ return $SUCCESS
+ fi
+
+ if [ ! -e "$MOUNTPOINT" ] &&
+ ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
+ then
+ f_dialog_msgbox "$err"
+ return $FAILURE
+ fi
+
+ if ! err=$( mount_msdosfs "$devname" "$MOUNTPOINT" 2>&1 )
+ then
+ err="${err#mount_msdosfs: }"; err="${err#$devname: }"
+ f_show_msg "$msg_error_mounting_device" \
+ "$devname" "$MOUNTPOINT" "$err"
+ return $FAILURE
+ fi
+ DOS_MOUNTED=1
+ return $SUCCESS
+}
+
+# f_media_get_dos $device $file [$probe_only]
+#
+# Returns data from $file on a mounted DOS partition device. Similar to cat(1).
+# $probe_only is currently unused by this media type.
+#
+f_media_get_dos()
+{
+ local dev="$1" file="$2" probe_only="$3"
+
+ f_dprintf "f_media_get_dos: dev=[%s] file=[%s] probe_only=%s" \
+ "$dev" "$file" "$probe_only"
+
+ f_media_generic_get "$MOUNTPOINT" "$file"
+}
+
+# f_media_shutdown_dos $device
+#
+# Shuts down the DOS partition device using umount(8). Return status should be
+# ignored.
+#
+f_media_shutdown_dos()
+{
+ local dev="$1" err
+
+ [ "$DOS_MOUNTED" ] || return
+
+ if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ err="${err#umount: }"; err="${err#*: }"
+ f_show_msg "$msg_could_not_unmount_the_dos_partition" \
+ "$MOUNTPOINT" "$err"
+ else
+ DOS_MOUNTED=
+ fi
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/dos.subr
+
+fi # ! $_MEDIA_DOS_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/floppy.subr b/usr.sbin/bsdconfig/share/media/floppy.subr
new file mode 100644
index 0000000..c874c61
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/floppy.subr
@@ -0,0 +1,214 @@
+if [ ! "$_MEDIA_FLOPPY_SUBR" ]; then _MEDIA_FLOPPY_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/floppy.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/common.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+FLOPPY_MOUNTED=
+FLOPPY_DISTWANTED=
+
+############################################################ FUNCTIONS
+
+# f_media_set_floppy
+#
+# Return success if we both found and set the media type to be a floppy.
+#
+f_media_set_floppy()
+{
+ f_media_close
+
+ local devs ndevs
+ f_device_find "" $DEVICE_TYPE_FLOPPY devs
+ ndevs=$( set -- $devs; echo $# )
+
+ if [ ${ndevs:=0} -eq 0 ]; then
+ f_interactive && f_dialog_msgbox "$msg_no_floppy_devices_found"
+ return $FAILURE
+ elif [ $ndevs -gt 1 ]; then
+ local title="$msg_choose_a_floppy_drive"
+ local prompt="$msg_please_select_a_floppy_drive"
+ local hline=""
+
+ local dev retval
+ dev=$( f_device_menu \
+ "$title" "$prompt" "$hline" $DEVICE_TYPE_FLOPPY \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
+ retval=$?
+ [ "$dev" ] || return $FAILURE
+
+ f_device_find "$dev" $DEVICE_TYPE_FLOPPY devs
+ [ "$devs" ] || return $FAILURE
+ dev="${devs%%[$IFS]*}"
+
+ f_struct_copy device_$dev device_media
+ [ $retval -eq $SUCCESS ] || return $FAILURE
+ else
+ f_struct_copy device_$devs device_media
+ fi
+
+ f_struct device_media &&
+ device_media unset private
+
+ f_struct device_media || return $FAILURE
+}
+
+# f_media_init_floppy $device
+#
+# Initializes the Floppy media device. Returns success if able to mount the
+# Floppy disk device using either mount_msdosfs(8) or mount(8) (tried in that
+# order).
+#
+f_media_init_floppy()
+{
+ local dev="$1" devname err
+
+ device_$dev get devname devname || return $FAILURE
+ f_dprintf "Init floppy called for %s distribution. devname=[%s]" \
+ "${FLOPPY_DISTWANTED:-some}" "$devname"
+
+ if [ "$FLOPPY_MOUNTED" ]; then
+ f_dprintf "Floppy device already mounted."
+ return $SUCCESS
+ fi
+
+ local mp
+ device_$dev get private mp
+ if [ ! -e "${mp:=$MOUNTPOINT}" ] && ! f_quietly mkdir -p "$mp"; then
+ f_show_msg "$msg_unable_to_make_directory_mountpoint" \
+ "$mp" "$devname"
+ return $FAILURE
+ fi
+
+ if f_interactive; then
+ local desc
+ device_$dev get desc desc
+ if [ "$FLOPPY_DISTWANTED" ]; then
+ f_show_msg "$msg_please_insert_floppy_in_drive" "$desc"
+ else
+ f_show_msg "$msg_please_insert_floppy_containing" \
+ "$FLOPPY_DISTWANTED" "$desc"
+ fi
+ fi
+
+ if ! {
+ f_quietly mount_msdosfs -o ro -m 0777 -u 0 -g 0 "$devname" "$mp" ||
+ err=$( mount -o ro "$devname" "$mp" 2>&1 )
+ }; then
+ err="${err#mount: }"; err="${err#*: }"
+ local name
+ device_$dev get name name
+ f_show_msg "$msg_error_mounting_floppy_device" \
+ "$name" "$devname" "$mp" "$err"
+ return $FAILURE
+ fi
+ FLOPPY_MOUNTED=1
+ FLOPPY_DISTWANTED=
+ return $SUCCESS
+}
+
+# f_media_get_floppy $device $file [$probe_only]
+#
+# Returns data from $file on a mounted Floppy disk device. Similar to cat(1).
+# If $probe_only is present and non-null, limits retries to zero.
+#
+f_media_get_floppy()
+{
+ local dev="$1" file="$2" probe_only="$3"
+
+ f_dprintf "f_media_get_floppy: dev=[%s] file=[%s] probe_only=%s" \
+ "$dev" "$file" "$probe_only"
+
+ #
+ # floppies don't use f_media_generic_get() because it's too expensive
+ # to speculatively open files on a floppy disk. Make user get it
+ # right or give up with floppies.
+ #
+ local mp
+ device_$dev get private mp
+ local fp="${mp:=$MOUNTPOINT}/$file"
+ if ! [ -f "$fp" -a -r "$fp" ]; then
+ local nretries=4
+ [ "$probe_only" ] && return $FAILURE
+ while ! [ -f "$fp" -a -r "$fp" ]; do
+ if [ $nretries -eq 0 ]; then
+ f_show_msg "$msg_failed_to_get_floppy_file" \
+ "$fp"
+ return $FAILURE
+ fi
+ FLOPPY_DISTWANTED="$fp"
+ f_media_shutdown_floppy "$dev"
+ f_media_init_floppy "$dev" || return $FAILURE
+ nretries=$(( $nretries - 1 ))
+ done
+ fi
+ cat "$fp"
+}
+
+# f_media_shutdown_floppy $device
+#
+# Shuts down the Floppy disk device using umount(8). Return status should be
+# ignored.
+#
+f_media_shutdown_floppy()
+{
+ local dev="$1" err mp
+
+ [ "$FLOPPY_MOUNTED" ] || return
+
+ device_$dev get private mp
+ if ! err=$( umount -f "${mp:=$MOUNTPOINT}" 2>&1 ); then
+ err="${err#umount: }"; err="${err#*:}"
+ f_dprintf "Umount of floppy on %s failed: %s" "$mp" "$err"
+ else
+ FLOPPY_MOUNTED=
+ if f_interactive && [ "$_systemState" != "fixit" ]; then
+ local desc
+ device_$dev get desc desc
+ f_show_msg "$msg_you_may_remove_the_floppy" "$desc"
+ fi
+ fi
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/floppy.subr
+
+fi # ! $_MEDIA_FLOPPY_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/ftp.subr b/usr.sbin/bsdconfig/share/media/ftp.subr
new file mode 100644
index 0000000..ecc7724
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/ftp.subr
@@ -0,0 +1,893 @@
+if [ ! "$_MEDIA_FTP_SUBR" ]; then _MEDIA_FTP_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/ftp.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/strings.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/common.subr
+f_include $BSDCFG_SHARE/media/tcpip.subr
+f_include $BSDCFG_SHARE/media/network.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+FTP_SKIP_RESOLV=
+
+URL_MAX=261261 # according to actual fetch(1) test-results
+
+FTP_DIRS="
+ .
+ releases/$UNAME_P
+ snapshots/$UNAME_P
+ pub/FreeBSD
+ pub/FreeBSD/releases/$UNAME_P
+ pub/FreeBSD/snapshots/$UNAME_P
+ pub/FreeBSD-Archive/old-releases/$UNAME_P
+" # END-QUOTE
+
+############################################################ FUNCTIONS
+
+# f_dialog_menu_media_ftp
+#
+# Prompt the user to select from a range of ``built-in'' FTP servers or specify
+# their own. If the user makes a choice and doesn't cancel or press Esc, stores
+# the user's choice in VAR_FTP_PATH (see variables.subr) and returns success.
+#
+f_dialog_menu_media_ftp()
+{
+ f_dialog_title "$msg_please_select_a_freebsd_ftp_distribution_site"
+ local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+
+ local prompt="$msg_please_select_the_site_closest_to_you_or_other"
+ local hline="$msg_select_a_site_thats_close"
+ local menu_list="
+ '$msg_main_site' 'ftp.freebsd.org'
+ 'URL' '$msg_specify_some_other_ftp_site'
+ '$msg_snapshots_server_japan'
+ 'snapshots.jp.freebsd.org'
+ '$msg_snapshots_server_sweden'
+ 'snapshots.se.freebsd.org'
+ 'IPv6 $msg_main_site' 'ftp.freebsd.org'
+ ' IPv6 $msg_ireland' 'ftp3.ie.freebsd.org'
+ ' IPv6 $msg_israel' 'ftp.il.freebsd.org'
+ ' IPv6 $msg_japan' 'ftp2.jp.freebsd.org'
+ ' IPv6 $msg_usa' 'ftp4.us.freebsd.org'
+ ' IPv6 $msg_turkey' 'ftp2.tr.freebsd.org'
+ '$msg_primary' 'ftp1.freebsd.org'
+ ' $msg_primary #2' 'ftp2.freebsd.org'
+ ' $msg_primary #3' 'ftp3.freebsd.org'
+ ' $msg_primary #4' 'ftp4.freebsd.org'
+ ' $msg_primary #5' 'ftp5.freebsd.org'
+ ' $msg_primary #6' 'ftp6.freebsd.org'
+ ' $msg_primary #7' 'ftp7.freebsd.org'
+ ' $msg_primary #8' 'ftp8.freebsd.org'
+ ' $msg_primary #9' 'ftp9.freebsd.org'
+ ' $msg_primary #10' 'ftp10.freebsd.org'
+ ' $msg_primary #11' 'ftp11.freebsd.org'
+ ' $msg_primary #12' 'ftp12.freebsd.org'
+ ' $msg_primary #13' 'ftp13.freebsd.org'
+ ' $msg_primary #14' 'ftp14.freebsd.org'
+ '$msg_argentina' 'ftp.ar.freebsd.org'
+ '$msg_australia' 'ftp.au.freebsd.org'
+ ' $msg_australia #2' 'ftp2.au.freebsd.org'
+ ' $msg_australia #3' 'ftp3.au.freebsd.org'
+ '$msg_austria' 'ftp.at.freebsd.org'
+ ' $msg_austria #2' 'ftp2.at.freebsd.org'
+ '$msg_brazil' 'ftp.br.freebsd.org'
+ ' $msg_brazil #2' 'ftp2.br.freebsd.org'
+ ' $msg_brazil #3' 'ftp3.br.freebsd.org'
+ ' $msg_brazil #4' 'ftp4.br.freebsd.org'
+ ' $msg_brazil #5' 'ftp5.br.freebsd.org'
+ ' $msg_brazil #6' 'ftp6.br.freebsd.org'
+ ' $msg_brazil #7' 'ftp7.br.freebsd.org'
+ '$msg_canada' 'ftp.ca.freebsd.org'
+ '$msg_china' 'ftp.cn.freebsd.org'
+ ' $msg_china #2' 'ftp2.cn.freebsd.org'
+ '$msg_croatia' 'ftp.hr.freebsd.org'
+ '$msg_czech_republic' 'ftp.cz.freebsd.org'
+ '$msg_denmark' 'ftp.dk.freebsd.org'
+ ' $msg_denmark #2' 'ftp2.dk.freebsd.org'
+ '$msg_estonia' 'ftp.ee.freebsd.org'
+ '$msg_finland' 'ftp.fi.freebsd.org'
+ '$msg_france' 'ftp.fr.freebsd.org'
+ ' $msg_france #2' 'ftp2.fr.freebsd.org'
+ ' $msg_france #3' 'ftp3.fr.freebsd.org'
+ ' $msg_france #5' 'ftp5.fr.freebsd.org'
+ ' $msg_france #6' 'ftp6.fr.freebsd.org'
+ ' $msg_france #8' 'ftp8.fr.freebsd.org'
+ '$msg_germany' 'ftp.de.freebsd.org'
+ ' $msg_germany #2' 'ftp2.de.freebsd.org'
+ ' $msg_germany #3' 'ftp3.de.freebsd.org'
+ ' $msg_germany #4' 'ftp4.de.freebsd.org'
+ ' $msg_germany #5' 'ftp5.de.freebsd.org'
+ ' $msg_germany #6' 'ftp6.de.freebsd.org'
+ ' $msg_germany #7' 'ftp7.de.freebsd.org'
+ ' $msg_germany #8' 'ftp8.de.freebsd.org'
+ '$msg_greece' 'ftp.gr.freebsd.org'
+ ' $msg_greece #2' 'ftp2.gr.freebsd.org'
+ '$msg_hungary' 'ftp.hu.freebsd.org'
+ '$msg_iceland' 'ftp.is.freebsd.org'
+ '$msg_ireland' 'ftp.ie.freebsd.org'
+ ' $msg_ireland #2' 'ftp2.ie.freebsd.org'
+ ' $msg_ireland #3' 'ftp3.ie.freebsd.org'
+ '$msg_israel' 'ftp.il.freebsd.org'
+ '$msg_italy' 'ftp.it.freebsd.org'
+ '$msg_japan' 'ftp.jp.freebsd.org'
+ ' $msg_japan #2' 'ftp2.jp.freebsd.org'
+ ' $msg_japan #3' 'ftp3.jp.freebsd.org'
+ ' $msg_japan #4' 'ftp4.jp.freebsd.org'
+ ' $msg_japan #5' 'ftp5.jp.freebsd.org'
+ ' $msg_japan #6' 'ftp6.jp.freebsd.org'
+ ' $msg_japan #7' 'ftp7.jp.freebsd.org'
+ ' $msg_japan #8' 'ftp8.jp.freebsd.org'
+ ' $msg_japan #9' 'ftp9.jp.freebsd.org'
+ '$msg_korea' 'ftp.kr.freebsd.org'
+ ' $msg_korea #2' 'ftp2.kr.freebsd.org'
+ '$msg_lithuania' 'ftp.lt.freebsd.org'
+ '$msg_netherlands' 'ftp.nl.freebsd.org'
+ ' $msg_netherlands #2' 'ftp2.nl.freebsd.org'
+ '$msg_norway' 'ftp.no.freebsd.org'
+ ' $msg_norway #3' 'ftp3.no.freebsd.org'
+ '$msg_poland' 'ftp.pl.freebsd.org'
+ ' $msg_poland #2' 'ftp2.pl.freebsd.org'
+ ' $msg_poland #5' 'ftp5.pl.freebsd.org'
+ '$msg_portugal' 'ftp.pt.freebsd.org'
+ ' $msg_portugal #2' 'ftp2.pt.freebsd.org'
+ ' $msg_portugal #4' 'ftp4.pt.freebsd.org'
+ '$msg_romania' 'ftp.ro.freebsd.org'
+ '$msg_russia' 'ftp.ru.freebsd.org'
+ ' $msg_russia #2' 'ftp2.ru.freebsd.org'
+ ' $msg_russia #3' 'ftp3.ru.freebsd.org'
+ ' $msg_russia #4' 'ftp4.ru.freebsd.org'
+ '$msg_singapore' 'ftp.sg.freebsd.org'
+ '$msg_slovak_republic' 'ftp.sk.freebsd.org'
+ '$msg_slovenia' 'ftp.si.freebsd.org'
+ ' $msg_slovenia #2' 'ftp2.si.freebsd.org'
+ '$msg_south_africa' 'ftp.za.freebsd.org'
+ ' $msg_south_africa #2' 'ftp2.za.freebsd.org'
+ ' $msg_south_africa #3' 'ftp3.za.freebsd.org'
+ ' $msg_south_africa #4' 'ftp4.za.freebsd.org'
+ '$msg_spain' 'ftp.es.freebsd.org'
+ ' $msg_spain #2' 'ftp2.es.freebsd.org'
+ ' $msg_spain #3' 'ftp3.es.freebsd.org'
+ '$msg_sweden' 'ftp.se.freebsd.org'
+ ' $msg_sweden #2' 'ftp2.se.freebsd.org'
+ ' $msg_sweden #3' 'ftp3.se.freebsd.org'
+ ' $msg_sweden #4' 'ftp4.se.freebsd.org'
+ ' $msg_sweden #5' 'ftp5.se.freebsd.org'
+ '$msg_switzerland' 'ftp.ch.freebsd.org'
+ ' $msg_switzerland #2' 'ftp2.ch.freebsd.org'
+ '$msg_taiwan' 'ftp.tw.freebsd.org'
+ ' $msg_taiwan #2' 'ftp2.tw.freebsd.org'
+ ' $msg_taiwan #3' 'ftp3.tw.freebsd.org'
+ ' $msg_taiwan #4' 'ftp4.tw.freebsd.org'
+ ' $msg_taiwan #6' 'ftp6.tw.freebsd.org'
+ ' $msg_taiwan #11' 'ftp11.tw.freebsd.org'
+ '$msg_turkey' 'ftp.tr.freebsd.org'
+ ' $msg_turkey #2' 'ftp2.tr.freebsd.org'
+ '$msg_uk' 'ftp.uk.freebsd.org'
+ ' $msg_uk #2' 'ftp2.uk.freebsd.org'
+ ' $msg_uk #3' 'ftp3.uk.freebsd.org'
+ ' $msg_uk #4' 'ftp4.uk.freebsd.org'
+ ' $msg_uk #5' 'ftp5.uk.freebsd.org'
+ ' $msg_uk #6' 'ftp6.uk.freebsd.org'
+ '$msg_ukraine' 'ftp.ua.freebsd.org'
+ ' $msg_ukraine #2' 'ftp2.ua.freebsd.org'
+ ' $msg_ukraine #5' 'ftp5.ua.freebsd.org'
+ ' $msg_ukraine #6' 'ftp6.ua.freebsd.org'
+ ' $msg_ukraine #7' 'ftp7.ua.freebsd.org'
+ ' $msg_ukraine #8' 'ftp8.ua.freebsd.org'
+ '$msg_usa #1' 'ftp1.us.freebsd.org'
+ ' $msg_usa #2' 'ftp2.us.freebsd.org'
+ ' $msg_usa #3' 'ftp3.us.freebsd.org'
+ ' $msg_usa #4' 'ftp4.us.freebsd.org'
+ ' $msg_usa #5' 'ftp5.us.freebsd.org'
+ ' $msg_usa #6' 'ftp6.us.freebsd.org'
+ ' $msg_usa #7' 'ftp7.us.freebsd.org'
+ ' $msg_usa #8' 'ftp8.us.freebsd.org'
+ ' $msg_usa #9' 'ftp9.us.freebsd.org'
+ ' $msg_usa #10' 'ftp10.us.freebsd.org'
+ ' $msg_usa #11' 'ftp11.us.freebsd.org'
+ ' $msg_usa #12' 'ftp12.us.freebsd.org'
+ ' $msg_usa #13' 'ftp13.us.freebsd.org'
+ ' $msg_usa #14' 'ftp14.us.freebsd.org'
+ ' $msg_usa #15' 'ftp15.us.freebsd.org'
+ " # END-QUOTE
+
+ local size
+ size=$( eval f_dialog_menu_size \
+ \"\$title\" \
+ \"\$btitle\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ local dialog_menu retval mtag value
+ dialog_menu=$( eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --hline \"\$hline\" \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_cancel\" \
+ --menu \"\$prompt\" $size \
+ $menu_list \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+ )
+ retval=$?
+ setvar DIALOG_MENU_$$ "$dialog_menu"
+ mtag=$( f_dialog_menutag )
+
+ [ $retval -eq 0 ] || return $FAILURE
+
+ case "$mtag" in
+ URL) setvar $VAR_FTP_PATH "other" ;;
+ *)
+ value=$( eval f_dialog_menutag2item \"\$mtag\" $menu_list )
+ setvar $VAR_FTP_PATH "ftp://$value"
+ esac
+
+ return $SUCCESS
+}
+
+# f_media_set_ftp
+#
+# Return success if we both found and set the media type to be an FTP server.
+# Variables from variable.subr that can be used to script user input:
+#
+# VAR_FTP_PATH
+# Can be a URL (including "ftp://" protocol-prefix) or "other"
+# (user is prompted to enter FTP URL). If a URL, can optionally
+# contain directory prefix after hostname/port. Valid examples
+# include:
+# ftp://myhost
+# ftp://somename:21/pub/
+# ftp://192.168.2.3/pub/
+# ftp://[::1]:21/
+# The default port if not specified is 21.
+# VAR_NAMESERVER [Optional]
+# If set, overrides resolv.conf(5) and sets the nameserver that
+# is used to convert names into addresses (when a name converts
+# into multiple addresses, the first address to successfully
+# connect is used).
+#
+# Meanwhile, the following variables from variable.subr are set after
+# successful execution:
+#
+# VAR_FTP_HOST
+# The FTP host to connect to, parsed from VAR_FTP_PATH. In the
+# example case of IPv6 where VAR_FTP_PATH is a "ftp://[::1]" this
+# variable will be set to "::1" (the outer brackets are removed).
+# VAR_FTP_PORT
+# The TCP port to connect to, parsed from VAR_FTP_PATH. Usually
+# 21 unless VAR_FTP_PATH was of one of the following forms:
+# ftp://hostname:OTHER_PORT
+# ftp://hostname:OTHER_PORT/*
+# ftp://ip:OTHER_PORT
+# ftp://ip:OTHER_PORT/*
+# ftp://[ip6]:OTHER_PORT
+# ftp://[ip6]:OTHER_PORT/*
+# VAR_FTP_DIR
+# If VAR_FTP_PATH contained a directory element (e.g.,
+# "ftp://localhost/pub") this variable contains only the
+# directory element (e.g., "/pub").
+#
+f_media_set_ftp()
+{
+ f_media_close
+
+ local url
+ f_getvar $VAR_FTP_PATH url
+
+ # If we've been through here before ...
+ if f_struct device_network && [ "${url#$msg_other}" ]; then
+ f_dialog_yesno "$msg_reuse_old_ftp_site_selection_values" ||
+ url=
+ fi
+
+ if [ ! "$url" ]; then
+ f_dialog_menu_media_ftp || return $FAILURE
+ f_getvar $VAR_FTP_PATH url
+ fi
+ [ "$url" ] || return $FAILURE
+
+ case "$url" in
+ other)
+ setvar $VAR_FTP_PATH "ftp://"
+ f_variable_get_value $VAR_FTP_PATH \
+ "$msg_please_specify_url_of_a_freebsd_distribution"
+ f_getvar $VAR_FTP_PATH url
+ if [ ! "${url#ftp://}" ]; then
+ unset $VAR_FTP_PATH
+ return $FAILURE
+ fi
+ if [ ${#url} -gt ${URL_MAX:-261261} ]; then
+ f_show_msg "$msg_length_of_specified_url_is_too_long" \
+ ${#url} ${URL_MAX:-261261}
+ unset $VAR_FTP_PATH
+ return $FAILURE
+ fi
+ case "$url" in
+ ftp://*) : valid URL ;;
+ *)
+ f_show_msg "$msg_sorry_invalid_url" "$url"
+ unset $VAR_FTP_PATH
+ return $FAILURE
+ esac
+ esac
+ case "$url" in
+ ftp://*) : valid URL ;;
+ *)
+ f_show_msg "$msg_sorry_invalid_url" "$url"
+ unset $VAR_FTP_PATH
+ return $FAILURE
+ esac
+
+ # Set the name of the FTP device to the URL
+ f_struct_new DEVICE device_ftp
+ device_ftp set name "$url"
+
+ if ! f_struct device_network ||
+ ! f_dialog_yesno "$msg_youve_already_done_the_network_configuration"
+ then
+ f_struct device_network &&
+ f_device_shutdown network
+ if ! f_device_select_tcp; then
+ unset $VAR_FTP_PATH
+ return $FAILURE
+ fi
+ local dev
+ f_getvar $VAR_NETWORK_DEVICE dev
+ f_struct_copy "device_$dev" device_network
+ fi
+ if ! f_device_init network; then
+ f_dprintf "f_media_set_ftp: %s" "$msg_net_device_init_failed"
+ unset $VAR_FTP_PATH
+ return $FAILURE
+ fi
+
+ local hostname="${url#*://}" port=21 dir=/
+ case "$hostname" in
+ "["*"]")
+ hostname="${hostname#\[}"
+ hostname="${hostname%%\]*}"
+ ;;
+ "["*"]/"*)
+ hostname="${hostname#\[}"
+ dir="/${hostname#*/}"
+ hostname="${hostname%%\]*}"
+ ;;
+ *"/"*)
+ dir="/${hostname#*/}"
+ hostname="${hostname%%/*}"
+ ;;
+ "["*"]:"*)
+ hostname="${hostname#\[}"
+ port="${hostname#*\]:}"
+ port="${port%%[!0-9]*}"
+ hostname="${hostname%%\]:*}"
+ ;;
+ *)
+ hostname="${hostname%%/*}"
+ esac
+
+ f_dprintf "hostname = \`%s'" "$hostname"
+ f_dprintf "dir = \`%s'" "$dir"
+ f_dprintf "port \# = \`%d'" "$port"
+
+ local ns
+ f_getvar $VAR_NAMESERVER ns
+ [ "$ns" ] || f_resolv_conf_nameservers ns
+ if [ "$ns" -a ! "$FTP_SKIP_RESOLV" ] && ! {
+ f_validate_ipaddr "$hostname" ||
+ f_validate_ipaddr6 "$hostname"
+ }; then
+ f_show_info "$msg_looking_up_host" "$hostname"
+ f_dprintf "%s: Looking up hostname, %s, using host(1)" \
+ "f_media_set_ftp" "$hostname"
+ if ! f_quietly f_host_lookup "$hostname"; then
+ f_show_msg "$msg_cannot_resolve_hostname" "$hostname"
+ f_struct device_network &&
+ f_device_shutdown network
+ f_struct_free device_network
+ unset $VAR_FTP_PATH
+ return $FAILURE
+ fi
+ f_dprintf "Found DNS entry for %s successfully." "$hostname"
+ fi
+
+ setvar $VAR_FTP_HOST "$hostname"
+ setvar $VAR_FTP_PORT "$port"
+ setvar $VAR_FTP_DIR "$dir"
+
+ device_ftp set type $DEVICE_TYPE_FTP
+ device_ftp set init f_media_init_ftp
+ device_ftp set get f_media_get_ftp
+ device_ftp set shutdown f_media_shutdown_ftp
+ device_ftp set private network
+ f_struct_copy device_ftp device_media
+ f_struct_free device_ftp
+
+ return $SUCCESS
+}
+
+# f_media_set_ftp_active
+#
+# Wrapper to f_media_set_ftp to access FTP servers actively.
+#
+f_media_set_ftp_active()
+{
+ setvar $VAR_FTP_STATE "active"
+ f_media_set_ftp
+}
+
+# f_media_set_ftp_passive
+#
+# Wrapper to f_media_set_ftp to access FTP servers passively.
+#
+f_media_set_ftp_passive()
+{
+ setvar $VAR_FTP_STATE "passive"
+ f_media_set_ftp
+}
+
+# f_media_set_ftp_userpass
+#
+# Prompt the user to enter/confirm the username/password variables that will
+# be used to communicate with the FTP servers. Returns success if the user does
+# not cancel or press Esc to either username or password.
+#
+# Variables from variable.subr that can be used to script user input:
+#
+# VAR_FTP_USER
+# The username to send via ftp(1) when connecting to an FTP
+# server.
+# VAR_FTP_PASS
+# The password to send with the above username.
+#
+# Does not prompt for confirmation of values if VAR_NONINTERACTIVE is set (see
+# variable.subr for more information).
+#
+f_media_set_ftp_userpass()
+{
+ local user pass
+ f_variable_get_value $VAR_FTP_USER \
+ "$msg_please_enter_the_username_you_wish_to_login_as"
+ f_getvar $VAR_FTP_USER user
+ if [ "$user" ]; then
+ f_variable_get_value $VAR_FTP_PASS \
+ "$msg_please_enter_the_password_for_this_user"
+ f_getvar $VAR_FTP_PASS pass
+ else
+ pass=
+ fi
+ [ "$pass" ] # Return status
+}
+
+# f_device_network_up $device
+#
+# Brings up attached network device, if any - takes FTP device as arg.
+#
+f_device_network_up()
+{
+ local dev="$1" netDev
+ device_$dev get private netDev || return $SUCCESS # No net == happy net
+ f_device_init $netDev
+}
+
+# f_device_network_down $device
+#
+# Brings down attached network device, if any - takes FTP device as arg.
+#
+f_device_network_down()
+{
+ local dev="$1" netDev
+ device_$dev get private netDev || return $SUCCESS
+ f_device_shutdown $netDev
+}
+
+# f_media_init_ftp $device
+#
+# Initializes the FTP media device. Returns success if both able to log into
+# the FTP server and confirm the existence of at least one known release path
+# using ftp(1).
+#
+# Variables from variable.subr used to initialize the connection are as follows
+# (all of which are configured by f_media_set_ftp above):
+#
+# VAR_FTP_PATH
+# The unparsed FTP URL representing the server to contact.
+# Usually "ftp://server" for example. Can contain TCP port number
+# and/or directory path (but should not contain username/password
+# info).
+# VAR_FTP_HOST
+# The FTP host to connect to. Can be an IPv4 address (e.g.,
+# 127.0.0.1), IPv6 address (e.g., ::1), or DNS hostname. Usually
+# set automatically in f_media_set_ftp() by parsing VAR_FTP_PATH.
+# VAR_FTP_PORT
+# The TCP port to connect to. Usually set automatically in
+# f_media_set_ftp() by parsing VAR_FTP_PATH.
+# VAR_FTP_DIR
+# The base FTP directory to use when downloading files from the
+# FTP server. Usually set automatically in f_media_set_ftp() by
+# parsing VAR_FTP_PATH.
+# VAR_FTP_USER [Optional]
+# If unset, defaults to using anonymous access.
+# VAR_FTP_PASS [Optional]
+# If unset, defaults to a sensible value.
+#
+# In addition, the following (managed either manually or by f_media_set_ftp_*):
+#
+# VAR_FTP_STATE
+# Sets FTPMODE for ftp(1) and can be one of:
+# active active mode FTP only
+# auto automatic determination of passive or active
+# (this is the default)
+# gate gate-ftp mode
+# passive passive mode FTP only
+# See ftp(1) for additional information.
+#
+# And last, but not least (managed automatically or manually):
+#
+# VAR_RELNAME
+# Defaults to being set to $(uname -r) but can be overridden.
+# This sets the name of a release to look for as part of a well
+# known set of paths to search for release data once connected
+# via FTP. If set to "__RELEASE" or "any" then the VAR_FTP_DIR is
+# taken as the absolute path to the release and no further
+# searching is done (see FTP_DIRS above in the GLOBALS section
+# for a list of well known paths that are used when searching for
+# a VAR_RELNAME sub-directory).
+#
+f_media_init_ftp()
+{
+ local dev="$1"
+
+ local url
+ device_$dev get name url
+ f_dprintf "Init routine called for FTP device. url=[%s]" "$url"
+
+ if [ "$FTP_INITIALIZED" ]; then
+ f_dprintf "FTP device already initialized."
+ return $SUCCESS
+ fi
+
+ # If we can't initialize the network, bag it!
+ f_device_network_up $dev || return $FAILURE
+
+ local cp
+ while :; do
+ f_getvar $VAR_FTP_PATH cp
+ if [ ! "$cp" ]; then
+ if ! f_media_set_ftp ||
+ ! f_getvar $VAR_FTP_PATH cp ||
+ [ ! "$cp" ]
+ then
+ f_dialog_msgbox \
+ "$msg_unable_to_get_proper_ftp_path"
+ f_device_network_down $dev
+ return $FAILURE
+ fi
+ fi
+
+ local ftp_host ftp_dir
+ if ! {
+ f_getvar $VAR_FTP_HOST ftp_host &&
+ f_getvar $VAR_FTP_DIR ftp_dir
+ }; then
+ f_dialog_msgbox "$msg_missing_ftp_host_or_directory"
+ f_device_network_down $dev
+ return $FAILURE
+ fi
+
+ local ftp_port
+ f_getvar $VAR_FTP_PORT ftp_port
+ local host="$ftp_host" port="${ftp_port:+:$ftp_port}"
+ case "$host" in *:*) host="[$host]"; esac
+
+ local user pass use_anon=""
+ f_getvar $VAR_FTP_USER user
+ if [ ! "$user" ]; then
+ user="anonymous"
+ use_anon=1
+ fi
+ if ! f_getvar $VAR_FTP_PASS pass; then
+ f_getvar $VAR_HOSTNAME cp
+ if f_running_as_init; then
+ pass="installer@$cp"
+ else
+ local name="$( id -un 2> /dev/null )"
+ pass="${name:-ftp}@$cp"
+ fi
+ fi
+
+ f_show_info "$msg_logging_in_to_user_at_host" \
+ "$user" "$ftp_host"
+
+ local userpass=""
+ if [ ! "$use_anon" ] && [ "$user" -o "$pass" ]; then
+ userpass="$user${pass:+:$( f_uriencode "$pass" )}"
+ userpass="$userpass${userpass:+@}"
+ fi
+
+ local mode rx
+ f_getvar $VAR_FTP_STATE mode
+
+ if [ "$ftp_dir" ]; then
+ if ! rx=$(
+ printf 'cd "%s"\npwd\n' "$ftp_dir" | eval \
+ FTPMODE=\"\$mode\" \
+ ${use_anon:+FTPANONPASS=\"\$pass\"} \
+ ftp -V ${use_anon:+-a} \
+ \"ftp://\$userpass\$host\$port\" \
+ 2>&1
+ ); then
+ f_show_msg "$msg_couldnt_open_ftp_connection" \
+ "$ftp_host" "$rx"
+ break # to failure
+ fi
+ if echo "$rx" | awk -v dir="/${ftp_dir#/}" '
+ BEGIN { found = 0 }
+ /^Remote directory: / {
+ sub(/^[^:]*:[[:space:]]*/, "")
+ if ($0 != dir) next
+ found = 1; exit
+ }
+ END { exit ! found }
+ '; then
+ setvar $VAR_FTP_DIR "$ftp_dir"
+ setvar $VAR_FTP_PATH \
+ "ftp://$ftp_host/${ftp_dir#/}"
+ else
+ f_show_msg \
+ "$msg_please_check_the_url_and_try_again" \
+ "ftp://$ftp_host/${ftp_dir#/}"
+ break # to failure
+ fi
+ fi
+
+ #
+ # Now that we've verified that the path we're given is ok,
+ # let's try to be a bit intelligent in locating the release we
+ # are looking for. First off, if the release is specified as
+ # "__RELEASE" or "any", then just assume that the current
+ # directory is the one we want and give up.
+ #
+ local rel
+ f_getvar $VAR_RELNAME rel
+ f_dprintf "f_media_init_ftp: rel=[%s]" "$rel"
+
+ case "$rel" in
+ __RELEASE|any)
+ FTP_INITIALIZED=YES
+ return $SUCCESS
+ ;;
+ *)
+ #
+ # Ok, since we have a release variable, let's walk
+ # through the list of directories looking for a release
+ # directory. First successful CWD wins.
+ #
+ if ! rx=$(
+ for dir in $FTP_DIRS; do
+ # Avoid confusing some servers
+ [ "$dir" = "." ] && continue
+ printf 'cd "/%s/%s"\npwd\n' \
+ "$dir" "$rel"
+ done | eval \
+ FTPMODE=\"\$mode\" \
+ ${use_anon:+FTPANONPASS=\"\$pass\"} \
+ ftp -V ${use_anon:+-a} \
+ \"ftp://\$userpass\$host\$port\" \
+ 2>&1
+ ); then
+ f_show_msg "$msg_couldnt_open_ftp_connection" \
+ "$ftp_host" "$rx"
+ break # to failure
+ fi
+
+ local fdir
+ if fdir=$( echo "$rx" | awk '
+ BEGIN { found = 0 }
+ /^Remote directory: / {
+ sub(/^[^:]*:[[:space:]]*/, "")
+ if ($0 == "/") next
+ # Exit after the first dir
+ found++; print; exit
+ }
+ END { exit ! found }
+ ' ); then
+ setvar $VAR_FTP_DIR "$fdir"
+ setvar $VAR_FTP_PATH "ftp://$ftp_host$fdir"
+ FTP_INITIALIZED=YES
+ return $SUCCESS
+ else
+ f_yesno "$msg_cant_find_distribution" \
+ "$rel" "$ftp_host"
+ if [ $? -eq $SUCCESS ]; then
+ unset $VAR_FTP_PATH
+ f_media_set_ftp && continue
+ fi
+ fi
+ esac
+ break # to failure
+ done
+
+ unset FTP_INITIALIZED $VAR_FTP_PATH
+ f_device_network_down $dev
+ return $FAILURE
+}
+
+# f_media_get_ftp $device $file [$probe_only]
+#
+# Returns data from $file on an FTP server using ftp(1). Please note that
+# $device is unused but must be present (even if null). Information is instead
+# gathered from the environment. $probe_only is currently unused by this media
+# type.
+#
+# Variables from variable.subr used to configure the connection are as follows
+# (all of which are configured by f_media_set_ftp above):
+#
+# VAR_FTP_HOST
+# FTP host to connect to. Can be an IPv4 address, IPv6 address,
+# or DNS hostname of your choice.
+# VAR_FTP_PORT
+# TCP port to connect on; see f_media_set_ftp() above.
+# VAR_FTP_USER [Optional]
+# If unset, defaults to using anonymous access.
+# VAR_FTP_PASS [Optional]
+# If unset, defaults to a sensible value.
+#
+# In addition, the following (managed either manually or by f_media_set_ftp_*):
+#
+# VAR_FTP_STATE
+# Sets FTPMODE for ftp(1) and can be one of:
+# active active mode FTP only
+# auto automatic determination of passive or active
+# (this is the default)
+# gate gate-ftp mode
+# passive passive mode FTP only
+# See ftp(1) for additional information.
+#
+# See variable.subr for additional information.
+#
+# Example usage:
+# f_media_set_ftp
+# f_media_get_ftp media $file
+#
+f_media_get_ftp()
+{
+ local dev="$1" file="$2" probe_only="$3"
+
+ f_dprintf "f_media_get_ftp: dev=[%s] file=[%s] probe_only=%s" \
+ "$dev" "$file" "$probe_only"
+
+ local ftp_host ftp_port
+ f_getvar $VAR_FTP_HOST ftp_host
+ f_getvar $VAR_FTP_PORT ftp_port
+
+ if [ ! "$FTP_INITIALIZED" ]; then
+ f_dprintf "No FTP connection open, can't get file %s" "$file"
+ return $FAILURE
+ fi
+
+ if ! {
+ f_validate_ipaddr "$ftp_host" ||
+ f_validate_ipaddr6 "$ftp_host" ||
+ {
+ f_dprintf "%s: Looking up hostname, %s, using host(1)" \
+ "f_media_get_ftp" "$ftp_host"
+ f_host_lookup "$ftp_host" hosts
+ }
+ }; then
+ # All the above validations failed
+ [ "$hosts" ] && f_dialog_msgbox "$hosts"
+ return $FAILURE
+ elif [ ! "$hosts" ]; then
+ # One of the first two validations passed
+ hosts="$ftp_host"
+ fi
+
+ local host connected=
+ for host in $hosts; do
+ f_quietly nc -nz "$host" "$ftp_port" || continue
+ connected=1; break
+ done
+ if [ ! "$connected" ]; then
+ f_show_msg "$msg_couldnt_connect_to_ftp_server %s:%s" \
+ "$ftp_host" "$ftp_port"
+ return $FAILURE
+ fi
+
+ local user pass use_anon=""
+ f_getvar $VAR_FTP_USER user
+ if [ ! "$user" ]; then
+ user="anonymous"
+ use_anon=1
+ fi
+ if ! f_getvar $VAR_FTP_PASS pass; then
+ f_getvar $VAR_HOSTNAME cp
+ if f_running_as_init; then
+ pass="installer@$cp"
+ else
+ local name="$( id -un 2> /dev/null )"
+ pass="${name:-ftp}@$cp"
+ fi
+ fi
+
+ local userpass=""
+ if [ ! "$use_anon" ] && [ "$user" -o "$pass" ]; then
+ userpass="$user${pass:+:$( f_uriencode "$pass" )}"
+ userpass="$userpass${userpass:+@}"
+ fi
+
+ local ftp_dir mode rx
+ f_getvar $VAR_FTP_DIR ftp_dir
+ f_getvar $VAR_FTP_STATE mode
+
+ local dir="${ftp_dir#/}"
+ local port="${ftp_port:+:$ftp_port}"
+ case "$host" in *:*) host="[$host]"; esac
+
+ f_dprintf "sending ftp request for: %s" "ftp://$host$port/$dir/$file"
+
+ eval FTPMODE=\"\$mode\" ${use_anon:+FTPANONPASS=\"\$pass\"} \
+ ftp -V ${use_anon:+-a} -o - \
+ \"ftp://\$userpass\$host\$port/\$dir/\$file\" 2> /dev/null
+ local retval=$?
+
+ [ $retval -eq $SUCCESS ] || f_dprintf "request failed!"
+ return $retval
+}
+
+# f_media_shutdown_ftp $device
+#
+# Shuts down the FTP device. Return status should be ignored. Note that since
+# we don't maintain an open connection to the FTP server there's nothing to do.
+#
+f_media_shutdown_ftp()
+{
+ [ "$FTP_INITIALIZED" ] || return $SUCCESS
+
+ unset FTP_INITIALIZED
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/ftp.subr
+
+fi # ! $_MEDIA_FTP_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/httpproxy.subr b/usr.sbin/bsdconfig/share/media/httpproxy.subr
new file mode 100644
index 0000000..fad1007
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/httpproxy.subr
@@ -0,0 +1,433 @@
+if [ ! "$_MEDIA_HTTPPROXY_SUBR" ]; then _MEDIA_HTTPPROXY_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/httpproxy.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/ftp.subr
+f_include $BSDCFG_SHARE/media/tcpip.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ FUNCTIONS
+
+# f_media_set_http_proxy
+#
+# Return success if we both found and set the media type to be an ftp server,
+# accessed via http proxy.
+#
+# Variables from variable.subr that can be used to script user input:
+#
+# VAR_HTTP_PROXY
+# HTTP Proxy server to use. Valid examples include:
+# myhost
+# somename:3128
+# 192.168.2.3
+# [::1]:8080
+# The default port if not specified is 3128.
+#
+# Variables from variable.subr that are set after successful execution include
+# the following:
+#
+# VAR_HTTP_PROXY_HOST The host portion of VAR_HTTP_PROXY.
+# VAR_HTTP_PROXY_PORT The TCP port parsed from VAR_HTTP_PROXY.
+#
+# See also f_media_set_ftp() for additional variables.
+#
+f_media_set_http_proxy()
+{
+ FTP_SKIP_RESOLV=1 f_media_set_ftp || return $FAILURE
+
+ f_variable_get_value $VAR_HTTP_PROXY \
+ "$msg_please_enter_the_address_of_the_http_proxy"
+
+ local proxy
+ f_getvar $VAR_HTTP_PROXY proxy
+ [ "$proxy" ] || return $FAILURE
+
+ local hostname="$proxy" port=3128
+ case "$hostname" in
+ "["*"]")
+ hostname="${hostname#\[}"
+ hostname="${hostname%\]}"
+ ;;
+ "["*"]:")
+ hostname="${hostname#\[}"
+ port="${hostname#*\]:}"
+ port="${port%%[!0-9]*}"
+ hostname="${hostname%%\]:*}"
+ ;;
+ *":"*)
+ port="${hostname#*:}"
+ hostname="${hostname%%:*}"
+ esac
+
+ setvar $VAR_HTTP_PROXY_HOST "$hostname"
+ setvar $VAR_HTTP_PROXY_PORT "$port"
+
+ if f_debugging; then
+ f_dprintf "VAR_FTP_PATH : %s" "$( f_getvar $VAR_FTP_PATH )"
+ f_dprintf "VAR_HTTP_PROXY_HOST, _PORT: %s:%s" \
+ "$( f_getvar $VAR_HTTP_PROXY_HOST )" \
+ "$( f_getvar $VAR_HTTP_PROXY_PORT )"
+ fi
+
+ # media device has been set by f_media_set_ftp(), overwrite partly:
+ device_media set type $DEVICE_TYPE_HTTP_PROXY
+ device_media set init f_media_init_http_proxy
+ device_media set get f_media_get_http_proxy
+ device_media unset shutdown
+
+ return $SUCCESS
+}
+
+# f_http_proxy_check_access [$connect_only]
+#
+# Return success if able list a remote FTP directory via HTTP proxy. If
+# $connect_only is present and non-null, then returns success if a connection
+# can be made. Variables from variable.subr that can be used to script user
+# input:
+#
+# VAR_HTTP_PROXY_HOST
+# The HTTP proxy server host name, IPv4 address or IPv6 address.
+# Valid examples include:
+# myhost
+# 192.168.2.3
+# ::1
+# VAR_HTTP_PROXY_PORT
+# The TCP port to connect to when communicating with the HTTP
+# proxy server.
+# VAR_HTTP_PROXY_PATH
+# The FTP URL sent to the HTTP proxy server. Unused if
+# $connect_only is present and non-NULL.
+#
+f_http_proxy_check_access()
+{
+ local connect_only="$1" hosts=""
+
+ local proxy_host proxy_port
+ f_getvar $VAR_HTTP_PROXY_HOST proxy_host
+ f_getvar $VAR_HTTP_PROXY_PORT proxy_port
+
+ if ! {
+ f_validate_ipaddr "$proxy_host" ||
+ f_validate_ipaddr6 "$proxy_host" ||
+ {
+ f_dprintf "%s: Looking up hostname, %s, using host(1)" \
+ "f_http_proxy_check_access" "$proxy_host"
+ f_host_lookup "$proxy_host" hosts
+ }
+ }; then
+ # All the above validations failed
+ [ "$hosts" ] && f_dialog_msgbox "$hosts"
+ unset $VAR_HTTP_PROXY_HOST
+ return $FAILURE
+ elif [ ! "$hosts" ]; then
+ # One of the first two validations passed
+ hosts="$proxy_host"
+ fi
+
+ local host connected=
+ for host in $hosts; do
+ f_quietly nc -nz "$host" "$proxy_port" || continue
+ connected=1; break
+ done
+ if [ ! "$connected" ]; then
+ f_show_msg "$msg_couldnt_connect_to_proxy %s:%s" \
+ "$proxy_host" "$proxy_port"
+ unset $VAR_HTTP_PROXY_HOST
+ return $FAILURE
+ fi
+ [ "$connect_only" ] && return $SUCCESS
+
+ #
+ # Some proxies fetch files with certain extensions in "ascii mode"
+ # instead of "binary mode" for FTP. The FTP server then translates all
+ # LF to CRLF.
+ #
+ # You can force Squid to use binary mode by appending ";type=i" to the
+ # URL, which is what sysinstall(8) has traditionally done.
+ #
+
+ local proxy_path
+ f_getvar $VAR_HTTP_PROXY_PATH proxy_path
+ f_show_info "$msg_checking_access_to" "$proxy_path"
+
+ local rx
+ if ! rx=$(
+ printf "GET %s/ HTTP/1.0\r\n\r\n" "${proxy_path%/}" |
+ nc -n "$host" "$proxy_port"
+ ); then
+ f_show_msg "$msg_couldnt_connect_to_proxy %s:%s" \
+ "$proxy_host" "$proxy_port"
+ unset $VAR_HTTP_PROXY_HOST
+ return $FAILURE
+ fi
+
+ local hdr
+ hdr=$( echo "$rx" | awk '/^\r$/{exit}{print}' )
+
+ local http_found=$FAILURE
+ if echo "$hdr" | awk '
+ BEGIN { found = 0 }
+ /^HTTP.... 200 / {
+ found = 1
+ exit
+ }
+ END { exit ! found }
+ '; then
+ http_found=$SUCCESS
+ fi
+
+ #
+ # Scan the headers of the response
+ # this is extremely quick'n dity
+ #
+
+ unset $VAR_HTTP_FTP_MODE
+ if echo "$hdr" | awk '
+ BEGIN { found = 0 }
+ {
+ if (!match($0, /^Server: /)) next
+ found = ( substr($0, 9, 5) ~ /[Ss]quid/ )
+ }
+ END { exit ! found }
+ '; then
+ setvar $VAR_HTTP_FTP_MODE ";type=i"
+ else
+ setvar $VAR_HTTP_FTP_MODE ""
+ fi
+
+ return $http_found
+}
+
+# f_media_init_http_proxy $device
+#
+# Initializes the HTTP Proxy media device. Returns success if able to confirm
+# the existence of at least one known FTP server release path via HTTP proxy
+# using f_http_proxy_check_access(), above.
+#
+# Variables from variable.subr that can be used to script user input:
+#
+# VAR_HTTP_PROXY_HOST
+# The HTTP proxy server to connect to. Usually set by having
+# f_media_set_http_proxy() parse VAR_HTTP_PROXY. Must be set.
+# Also see f_http_proxy_check_access() for additional variables.
+# VAR_RELNAME
+# Usually set to `uname -r' but can be overridden.
+# VAR_FTP_PATH
+# The FTP URL to send to the HTTP proxy server. Usually set by
+# calling f_media_set_ftp().
+#
+# Meanwhile, after successful execution, the following variables (also from
+# variable.subr) are set:
+#
+# VAR_HTTP_PROXY_PATH
+# The [possibly] adjusted VAR_FTP_PATH that was found to contain
+# a valid FreeBSD repository.
+#
+f_media_init_http_proxy()
+{
+ local dev="$1"
+ f_dprintf "Init routine called for HTTP Proxy device. dev=[%s]" "$dev"
+
+ #
+ # First verify access
+ #
+ local connect_only=1
+ f_http_proxy_check_access $connect_only
+
+ local proxy_host
+ f_getvar $VAR_HTTP_PROXY_HOST proxy_host
+ while [ ! "$proxy_host" ]; do
+ f_media_set_http_proxy || return $FAILURE
+ f_http_proxy_check_access $connect_only
+ f_getvar $VAR_HTTP_PROXY_HOST proxy_host
+ done
+
+ local rel proxy_path http_found=$FAILURE
+ while :; do
+ #
+ # If the release is specified as "__RELEASE" or "any", then
+ # just assume that the path the user gave is ok.
+ #
+ f_getvar $VAR_RELNAME rel
+ f_dprintf "f_media_init_http_proxy: rel=[%s]" "$rel"
+
+ case "$rel" in
+ __RELEASE|any)
+ f_getvar $VAR_FTP_PATH $VAR_HTTP_PROXY_PATH
+ f_http_proxy_check_access
+ http_found=$?
+ ;;
+ *)
+ local fdir fp
+ f_getvar $VAR_FTP_PATH fp
+ for fdir in $FTP_DIRS; do
+ setvar $VAR_HTTP_PROXY_PATH "$fp/$fdir/$rel"
+ if f_http_proxy_check_access; then
+ http_found=$SUCCESS
+ break
+ fi
+ done
+ esac
+
+ [ $http_found -eq $SUCCESS ] && break
+
+ f_getvar $VAR_HTTP_PROXY_PATH proxy_path
+ f_show_msg "$msg_please_check_the_url_and_try_again" \
+ "$proxy_path"
+
+ unset $VAR_HTTP_PROXY_PATH
+ f_media_set_http_proxy || break
+ done
+
+ return $http_found
+}
+
+# f_media_get_http_proxy $device $file [$probe_only]
+#
+# Returns data from $file on an FTP server via HTTP proxy using nc(1). Please
+# note that $device is unused but must be present (even if null). Information
+# is instead gathered from the environment. $probe_only is currently unused by
+# this media type.
+#
+# The variables used to configure the connection are as follows (all of which
+# are configured by f_media_set_http_proxy above):
+#
+# VAR_HTTP_PROXY_HOST
+# HTTP proxy host to connect. Can be an IPv4 address, IPv6
+# address, or DNS hostname of your choice.
+# VAR_HTTP_PROXY_PORT
+# TCP port to connect on; see f_media_set_http_proxy above.
+# VAR_HTTP_PROXY_PATH
+# URL (including "ftp://" protocol-prefix) of FTP directory to
+# use as a prefix when requesting $file via HTTP proxy.
+#
+# See variable.subr for additional information.
+#
+# Example usage:
+# f_media_set_http_proxy
+# f_media_get_http_proxy media $file
+#
+f_media_get_http_proxy()
+{
+ local dev="$1" file="$2" probe_only="$3" hosts=
+
+ f_dprintf "f_media_get_http_proxy: dev=[%s] file=[%s] probe_only=%s" \
+ "$dev" "$file" "$probe_only"
+
+ local proxy_host proxy_port
+ f_getvar $VAR_HTTP_PROXY_HOST proxy_host
+ f_getvar $VAR_HTTP_PROXY_PORT proxy_port
+
+ if ! {
+ f_validate_ipaddr "$proxy_host" ||
+ f_validate_ipaddr6 "$proxy_host" ||
+ {
+ f_dprintf "%s: Looking up hostname, %s, using host(1)" \
+ "f_media_get_http_proxy" "$proxy_host"
+ f_host_lookup "$proxy_host" hosts
+ }
+ }; then
+ # All the above validations failed
+ [ "$hosts" ] && f_dialog_msgbox "$hosts"
+ return $FAILURE
+ elif [ ! "$hosts" ]; then
+ # One of the first two validations passed
+ hosts="$proxy_host"
+ fi
+
+ local host connected=
+ for host in $hosts; do
+ f_quietly nc -nz "$host" "$proxy_port" || continue
+ connected=1; break
+ done
+ if [ ! "$connected" ]; then
+ f_show_msg "$msg_couldnt_connect_to_proxy %s:%s" \
+ "$proxy_host" "$proxy_port"
+ return $FAILURE
+ fi
+
+ local proxy_path mode
+ f_getvar $VAR_HTTP_PROXY_PATH proxy_path
+ f_getvar $VAR_HTTP_FTP_MODE mode
+ local url="${proxy_path%/}/$file$mode" rx
+
+ f_dprintf "sending http request for: %s" "$url"
+ printf "GET %s HTTP/1.0\r\n\r\n" "$url" | nc -n "$host" "$proxy_port" |
+ (
+ #
+ # scan the headers of the response
+ # this is extremely quick'n dirty
+ #
+
+ rv=0
+ while read LINE; do
+ case "$LINE" in
+ HTTP*)
+ f_dprintf "received response: %s" "$LINE"
+ set -- $LINE; rv=$2
+ f_isinteger "$rv" || rv=0
+ ;;
+ *)
+ [ "${LINE% }" ] || break # End of headers
+ esac
+ done
+
+ [ $rv -ge 500 ] && exit 5
+ [ $rv -eq 404 ] && exit 44
+ [ $rv -ge 400 ] && exit 4
+ [ $rv -ge 300 ] && exit 3
+ [ $rv -eq 200 ] || exit $FAILURE
+
+ cat # output the rest ``as-is''
+ exit 200
+ )
+ local retval=$?
+ [ $retval -eq 200 ] && return $SUCCESS
+
+ case "$retval" in
+ 5) f_show_msg "$msg_server_error_when_requesting_url" "$url" ;;
+ 44) f_show_msg "$msg_url_was_not_found" "$url" ;;
+ 4) f_show_msg "$msg_client_error" ;;
+ *) f_show_msg "$msg_error_when_requesting_url" "$url" ;;
+ esac
+ return $FAILURE
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/httpproxy.subr
+
+fi # ! $_MEDIA_HTTPPROXY_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/network.subr b/usr.sbin/bsdconfig/share/media/network.subr
new file mode 100644
index 0000000..d9fe8e6
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/network.subr
@@ -0,0 +1,182 @@
+if [ ! "$_MEDIA_NETWORK_SUBR" ]; then _MEDIA_NETWORK_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/network.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/media/tcpip.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+NETWORK_INITIALIZED=
+
+############################################################ FUNCTIONS
+
+# f_media_init_network $device
+#
+# Initialize a network device (such as `fxp0', `em0', etc.). Returns success if
+# able to successfully initialize the device. If not running as init (basically
+# from the FreeBSD install media) then assume that the network has already been
+# initialized and returns success.
+#
+# The variables (from variable.subr) used to initialize the network are as
+# follows (all of which are configured either automatically or manaully):
+#
+# VAR_IFCONFIG + device_name (e.g., `ifconfig_em0')
+# Automatically populated but can be overridden in a script. This
+# defines the ifconfig(8) properties specific to a chosen network
+# interface device. Optional if VAR_IPV6ADDR is set.
+# VAR_IPV6ADDR [Optional]
+# If not running as init (and setting up RTSOL connections for
+# the interface), then must be set manually. If set, used as the
+# IPv6 configuration for the given network interface device.
+# VAR_GATEWAY [Optional]
+# If not running as init (and setting up a static connection for
+# the interface) then must be set (usually via rc.conf(5), but
+# can be set manually to override). If unset, the user is warned
+# but not prevented from proceeding (as most connections need a
+# default route but not everyone).
+#
+f_media_init_network()
+{
+ local dev="$1"
+
+ f_dprintf "Init routine called for network device \`%s'." "$dev"
+ if [ "$NETWORK_INITIALIZED" ]; then
+ f_dprintf "Network already initialized."
+ return $SUCCESS
+ elif ! f_running_as_init; then
+ f_dprintf "Not running as init -- calling the deed done."
+ NETWORK_INITIALIZED=1
+ return $SUCCESS
+ fi
+
+ if [ ! -e "$RESOLV_CONF" ]; then
+ if ! f_config_resolv; then
+ f_show_msg "$msg_cant_seem_to_write_out_resolv_conf" \
+ "$RESOLV_CONF"
+ return $FAILURE
+ fi
+ fi
+
+ local cp
+ if f_getvar $VAR_IFCONFIG$dev cp; then
+ #
+ # If this interface isn't a DHCP one, bring it up.
+ # If it is, then it's already up.
+ #
+ case "$cp" in
+ *DHCP*)
+ f_dprintf "A DHCP interface. Should already be up."
+ ;;
+ *)
+ f_dprintf "Not a DHCP interface."
+ if ! f_quietly ifconfig "$dev" $cp; then
+ f_show_msg "$msg_unable_to_configure_device" \
+ "$dev"
+ return $FAILURE
+ fi
+ local rp
+ f_getvar $VAR_GATEWAY rp
+ if [ ! "$rp" ]; then
+ f_dialog_msgbox "$msg_no_gateway_has_been_set"
+ else
+ #
+ # Explicitly flush all routes to get back to a
+ # known sane state. We don't need to check this
+ # exit code because if anything fails it will
+ # show up in the route add below.
+ #
+ f_quietly route -n flush
+ f_dprintf "Adding default route to %s." "$rp"
+ if ! f_quietly route -n add default "$rp"; then
+ f_dialog_msgbox \
+ "$msg_failed_to_add_default_route"
+ return $FAILURE
+ fi
+ fi
+ esac
+ elif ! { f_getvar $VAR_IPV6ADDR cp && [ "$cp" ]; }; then
+ f_show_msg "$msg_device_is_not_configured" "$dev"
+ return $FAILURE
+ fi
+
+ f_dprintf "Network initialized successfully."
+ NETWORK_INITIALIZED=1
+ return $SUCCESS
+}
+
+# f_media_shutdown_network $device
+#
+# Shuts down the configured network device (e.g., `fxp0', `em0', etc.) and
+# deletes the default route (if configured). Returns failure if the device
+# passed has not been configured. If not running as init (basically from the
+# FreeBSD install media) then does nothing and returns success.
+#
+f_media_shutdown_network()
+{
+ local dev="$1" cp
+
+ f_dprintf "Shutdown called for network device %s" "$dev"
+ if [ ! "$NETWORK_INITIALIZED" ]; then
+ f_dprintf "Network not initialized -- nothing to do."
+ return $SUCCESS
+ fi
+
+ unset NETWORK_INITIALIZED
+ unset $VAR_NETWORK_DEVICE
+
+ if ! f_running_as_init; then
+ f_dprintf "Not running as init -- calling the deed done."
+ return $SUCCESS
+ fi
+
+ f_getvar $VAR_IFCONFIG$dev cp || return $FAILURE
+ f_dprintf "ifconfig %s down" "$dev"
+ f_quietly ifconfig $dev down ||
+ f_show_msg "$msg_unable_to_down_the_interface_properly" "$dev"
+
+ if f_getvar $VAR_GATEWAY cp; then
+ f_dprintf "Deleting default route."
+ f_quietly route -n delete default
+ fi
+
+ return $SUCCESS
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/network.subr
+
+fi # ! $_MEDIA_NETWORK_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/nfs.subr b/usr.sbin/bsdconfig/share/media/nfs.subr
new file mode 100644
index 0000000..461db1c
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/nfs.subr
@@ -0,0 +1,251 @@
+if [ ! "$_MEDIA_NFS_SUBR" ]; then _MEDIA_NFS_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/nfs.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/common.subr
+f_include $BSDCFG_SHARE/media/tcpip.subr
+f_include $BSDCFG_SHARE/media/network.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+NFS_MOUNTED=
+
+############################################################ FUNCTIONS
+
+# f_media_set_nfs
+#
+# Return success if we both found and set the media type to be an NFS server.
+# Variables from variable.subr that can be used to script user input:
+#
+# VAR_NFS_PATH
+# The NFS path specification (host:path) to use when mounting the
+# remote repository.
+# VAR_NAMESERVER [Optional]
+# Automatically populated from resolv.conf(5) but can be
+# overridden. If set, the host portion of VAR_NFS_PATH is
+# looked up using f_host_lookup() from `tcpip.subr'.
+#
+# Meanwhile, the following variables from variable.subr are set after
+# successful execution:
+#
+# VAR_NFS_HOST
+# The host portion of the NFS path specification, parsed from
+# VAR_NFS_PATH.
+#
+f_media_set_nfs()
+{
+ local nfs
+
+ f_media_close
+
+ f_variable_get_value $VAR_NFS_PATH \
+ "$msg_please_enter_the_full_nfs_file_specification"
+ f_getvar $VAR_NFS_PATH nfs
+ [ "$nfs" ] || return $FAILURE
+
+ case "$nfs" in
+ *:*) : valid NFS path ;;
+ *)
+ f_dialog_msgbox "$msg_invalid_nfs_path_specification"
+ return $FAILURE
+ esac
+
+ f_struct_new DEVICE device_nfs
+ device_nfs set name "$nfs"
+
+ if ! f_struct device_network ||
+ ! f_dialog_yesno "$msg_youve_already_done_the_network_configuration"
+ then
+ f_struct device_network &&
+ f_device_shutdown network
+ f_device_select_tcp || return $FAILURE
+ local dev
+ f_getvar $VAR_NETWORK_DEVICE dev
+ f_struct_copy "device_$dev" device_network
+ fi
+ f_device_init network ||
+ f_dprintf "%s: $msg_net_device_init_failed\n" f_media_set_nfs
+
+ local hostname="${nfs%%:*}"
+ if f_quietly f_getvar $VAR_NAMESERVER && ! {
+ f_validate_ipaddr "$hostname" ||
+ f_validate_ipaddr6 "$hostname"
+ }; then
+ f_show_info "$msg_looking_up_host" "$hostname"
+ f_dprintf "%s Looking up hostname, %s, using host(1)" \
+ "f_media_set_nfs" "$hostname"
+ if ! f_quietly f_host_lookup "$hostname"; then
+ f_show_msg "$msg_cannot_resolve_hostname" "$hostname"
+ f_struct device_network &&
+ f_device_shutdown network
+ f_struct_free device_network
+ unset $VAR_NFS_PATH
+ return $FAILURE
+ fi
+ f_dprintf "Found DNS entry for %s successfully." "$hostname"
+ fi
+
+ setvar $VAR_NFS_HOST "$hostname"
+
+ device_nfs set type $DEVICE_TYPE_NFS
+ device_nfs set init f_media_init_nfs
+ device_nfs set get f_media_get_nfs
+ device_nfs set shutdown f_media_shutdown_nfs
+ device_nfs set private device_network # in name only (deref'd later)
+
+ f_struct_copy device_nfs device_media
+ f_struct_free device_nfs
+
+ return $SUCCESS
+}
+
+# f_media_init_nfs $device
+#
+# Initializes the NFS media device. Returns success if able to mount the NFS
+# device using mount_nfs(1).
+#
+# The variables (from variable.subr) used to initialize the NFS mount are as
+# follows (all of which are configured manually/optionally from the options
+# menu):
+#
+# VAR_NFS_TCP [Optional]
+# If non-NULL, adds the "tcp" option via `-o' to mount_nfs(8).
+# VAR_NFS_V3 [Optional]
+# If non-NULL, adds the "nfsv3" option via `-o' to mount_nfs(8).
+# VAR_NFS_SECURE [Optional]
+# If non-NULL, adds the "-P" flag to mount_nfs(8).
+# VAR_SLOW_ETHER [Optional]
+# If non-NULL, adjusts the read/write size to avoid timeouts.
+#
+f_media_init_nfs()
+{
+ local dev="$1" name err
+
+ device_$dev get name name || return $FAILURE
+ f_dprintf "Init routine called for NFS device. name=[%s]" \
+ "$name"
+
+ if [ "$NFS_MOUNTED" ]; then
+ f_dprintf "NFS device already mounted."
+ return $SUCCESS
+ fi
+
+ if ! f_device_init network; then
+ f_dprintf "f_media_init_nfs: %s" "$msg_net_device_init_failed"
+ return $FAILURE
+ fi
+
+ if [ ! -e "$MOUNTPOINT" ] &&
+ ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
+ then
+ f_dialog_msgbox "$err"
+ return $FAILURE
+ fi
+
+ local cp tcp="" use3="" secure="" readsize=4096 writesize=4096
+ f_getvar $VAR_NFS_TCP cp
+ [ "$cp" = "YES" ] && tcp=1
+ f_getvar $VAR_NFS_V3 cp
+ [ "$cp" = "YES" ] && use3=1
+ f_getvar $VAR_NFS_SECURE cp
+ [ "$cp" = "YES" ] && secure=1
+ f_getvar $VAR_SLOW_ETHER cp
+ [ "$cp" = "YES" ] && readsize=1024 writesize=1024
+
+ local options="rsize=$readsize,wsize=$writesize"
+ [ "$use3" ] && options="$options,nfsv3"
+ [ "$tcp" ] && options="$options,tcp"
+
+ if ! err=$( mount_nfs \
+ ${secure:+-P} -o "$options" "$name" "$MOUNTPOINT" 2>&1 )
+ then
+ err="${err#mount_nfs: }"
+ f_show_msg "$msg_error_mounting_device" \
+ "$name" "$MOUNTPOINT" "$err"
+ f_struct device_network &&
+ f_device_shutdown network
+ return $FAILURE
+ fi
+ NFS_MOUNTED=1
+
+ f_dprintf "Mounted NFS device %s onto %s" "$name" "$MOUNTPOINT"
+
+ return $SUCCESS
+}
+
+# f_media_get_nfs $device $file [$probe_only]
+#
+# Returns data from $file on a mounted NFS device. Similar to cat(1).
+# $probe_only is currently unused by this media type.
+#
+f_media_get_nfs()
+{
+ local dev="$1" file="$2" probe_only="$3"
+
+ f_dprintf "f_media_get_nfs: dev=[%s] file=[%s] probe_only=%s" \
+ "$dev" "$file" "$probe_only"
+
+ f_media_generic_get "$MOUNTPOINT" "$file"
+}
+
+# f_media_shutdown_nfs $device
+#
+# Shuts down the NFS device using umount(8). Return status should be ignored.
+#
+f_media_shutdown_nfs()
+{
+ local dev="$1" err
+
+ [ "$NFS_MOUNTED" ] || return
+
+ f_dprintf "Unmounting NFS partition on %s" "$MOUNTPOINT"
+ if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ err="${err#umount: }"; err="${err#*: }"
+ f_show_msg "$msg_could_not_unmount_the_nfs_partition" \
+ "$MOUNTPOINT" "$err"
+ else
+ NFS_MOUNTED=
+ fi
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/nfs.subr
+
+fi # ! $_MEDIA_NFS_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/options.subr b/usr.sbin/bsdconfig/share/media/options.subr
new file mode 100644
index 0000000..c32bec5
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/options.subr
@@ -0,0 +1,308 @@
+if [ ! "$_MEDIA_OPTIONS_SUBR" ]; then _MEDIA_OPTIONS_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/options.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/any.subr
+f_include $BSDCFG_SHARE/media/ftp.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+OPTIONS_HELPFILE=$BSDCFG_LIBE/include/options.hlp
+
+############################################################ FUNCTIONS
+
+# f_media_options_menu
+#
+# Prompt the user to confirm/edit various media settings. Returns success.
+#
+f_media_options_menu()
+{
+ f_dialog_title "$msg_options_editor"
+ local title="$DIALOG_TITLE" btitle="$DIALOG_BACKTITLE"
+ f_dialog_title_restore
+ local prompt=""
+ local hline="$hline_arrows_tab_enter"
+ local menu_list size cp
+
+ #
+ # A hack so that the dialogs below are always interactive in a script
+ #
+ local old_interactive=
+ if ! f_interactive; then
+ f_getvar $VAR_NONINTERACTIVE old_interactive
+ unset $VAR_NONINTERACTIVE
+ fi
+
+ while :; do
+ menu_list=""
+
+ f_getvar $VAR_NFS_SECURE cp
+ if [ "$cp" = "YES" ]; then menu_list="$menu_list
+ ' $msg_nfs_secure' 'YES'
+ '$msg_nfs_server_talks_only_on_a_secure_port'"
+ else menu_list="$menu_list
+ ' $msg_nfs_secure' 'NO'
+ '$msg_nfs_server_talks_only_on_a_secure_port'"
+ fi
+
+ f_getvar $VAR_SLOW_ETHER cp
+ if [ "$cp" = "YES" ]; then menu_list="$menu_list
+ ' $msg_nfs_slow' 'YES'
+ '$msg_user_is_using_a_slow_pc_or_ethernet_card'"
+ else menu_list="$menu_list
+ ' $msg_nfs_slow' 'NO'
+ '$msg_user_is_using_a_slow_pc_or_ethernet_card'"
+ fi
+
+ f_getvar $VAR_NFS_TCP cp
+ if [ "$cp" = "YES" ]; then menu_list="$menu_list
+ ' $msg_nfs_tcp' 'YES' '$msg_use_tcp_protocol_for_nfs'"
+ else menu_list="$menu_list
+ ' $msg_nfs_tcp' 'NO' '$msg_use_tcp_protocol_for_nfs'"
+ fi
+
+ f_getvar $VAR_NFS_V3 cp
+ if [ "$cp" = "YES" ]; then menu_list="$menu_list
+ ' $msg_nfs_version_3' 'YES' '$msg_use_nfs_version_3'"
+ else menu_list="$menu_list
+ ' $msg_nfs_version_3' 'NO' '$msg_use_nfs_version_3'"
+ fi
+
+ f_getvar $VAR_DEBUG cp
+ if [ "$cp" ]; then menu_list="$menu_list
+ ' $msg_debugging' 'YES'
+ '$msg_emit_extra_debugging_output'"
+ else menu_list="$menu_list
+ ' $msg_debugging' 'NO'
+ '$msg_emit_extra_debugging_output'"
+ fi
+
+ f_getvar $VAR_TRY_DHCP cp
+ if [ "$cp" = "YES" ]; then menu_list="$menu_list
+ ' $msg_dhcp' 'YES'
+ '$msg_attempt_automatic_dhcp_configuration'"
+ else menu_list="$menu_list
+ ' $msg_dhcp' 'NO'
+ '$msg_attempt_automatic_dhcp_configuration'"
+ fi
+
+ f_getvar $VAR_TRY_RTSOL cp
+ if [ "$cp" = "YES" ]; then menu_list="$menu_list
+ ' $msg_ipv6' 'YES'
+ '$msg_attempt_ipv6_configuration_of_interfaces'"
+ else menu_list="$menu_list
+ ' $msg_ipv6' 'NO'
+ '$msg_attempt_ipv6_configuration_of_interfaces'"
+ fi
+
+ f_getvar $VAR_FTP_USER cp
+ menu_list="$menu_list
+ ' $msg_ftp_username' '$cp'
+ '$msg_username_and_password_to_use'"
+
+ f_getvar $VAR_EDITOR cp
+ menu_list="$menu_list
+ ' $msg_editor' '$cp' '$msg_which_text_editor_to_use'"
+
+ f_getvar $VAR_RELNAME cp
+ menu_list="$menu_list
+ ' $msg_release_name' '$cp'
+ '$msg_which_release_to_attempt_to_load'"
+
+ if f_struct device_media; then
+ device_media get type cp
+ case "$cp" in
+ $DEVICE_TYPE_UFS|$DEVICE_TYPE_DISK)
+ cp="$msg_file_system";;
+ $DEVICE_TYPE_DIRECTORY)
+ cp="$msg_directory";;
+ $DEVICE_TYPE_FLOPPY)
+ cp="$msg_floppy";;
+ $DEVICE_TYPE_FTP)
+ cp="$msg_ftp";;
+ $DEVICE_TYPE_HTTP_PROXY)
+ cp="$msg_http_proxy";;
+ $DEVICE_TYPE_CDROM)
+ cp="$msg_cdrom";;
+ $DEVICE_TYPE_USB)
+ cp="$msg_usb";;
+ $DEVICE_TYPE_DOS)
+ cp="$msg_dos";;
+ $DEVICE_TYPE_NFS)
+ cp="$msg_nfs";;
+ *)
+ cp="<$msg_unknown>"
+ esac
+ else
+ cp="<$msg_not_yet_set>"
+ fi
+ menu_list="$menu_list
+ ' $msg_media_type' '$cp'
+ '$msg_the_current_installation_media_type'"
+
+ f_getvar $VAR_MEDIA_TIMEOUT cp
+ menu_list="$menu_list
+ ' $msg_media_timeout' '$cp'
+ '$msg_timeout_value_in_seconds_for_slow_media'"
+
+ menu_list="$menu_list
+ ' $msg_rescan_devices' '<*>'
+ '$msg_rerun_bsdconfig_initial_device_probe'
+ ' $msg_use_defaults' '[${msg_reset}]'
+ '$msg_reset_all_values_to_startup_defaults'
+ " # END-QUOTE
+
+ size=$( eval f_dialog_menu_with_help_size \
+ \"\$title\" \
+ \"\$btitle\" \
+ \"\$prompt\" \
+ \"\$hline\" \
+ $menu_list )
+
+ local dialog_menu
+
+ dialog_menu=$( eval $DIALOG \
+ --title \"\$title\" \
+ --backtitle \"\$btitle\" \
+ --hline \"\$hline\" \
+ --item-help \
+ --ok-label \"\$msg_ok\" \
+ --cancel-label \"\$msg_done\" \
+ --help-button \
+ --help-label \"\$msg_help\" \
+ ${USE_XDIALOG:+--help \"\"} \
+ --menu \"\$prompt\" $size $menu_list \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+ )
+ local retval=$?
+ setvar DIALOG_MENU_$$ "$dialog_menu"
+
+ local mtag
+ mtag=$( f_dialog_menutag )
+ f_dprintf "retval=%s mtag=[%s]" $retval "$mtag"
+
+ if [ $retval -eq 2 ]; then
+ # The Help button was pressed
+ f_show_help "$OPTIONS_HELPFILE"
+ continue
+ elif [ $retval -ne 0 ]; then
+ break # to success
+ fi
+
+ case "$mtag" in
+ " $msg_nfs_secure")
+ f_getvar $VAR_NFS_SECURE cp
+ if [ "$cp" = "YES" ]; then
+ export $VAR_NFS_SECURE="NO"
+ else
+ export $VAR_NFS_SECURE="YES"
+ fi ;;
+ " $msg_nfs_slow")
+ f_getvar $VAR_SLOW_ETHER cp
+ if [ "$cp" = "YES" ]; then
+ export $VAR_SLOW_ETHER="NO"
+ else
+ export $VAR_SLOW_ETHER="YES"
+ fi ;;
+ " $msg_nfs_tcp")
+ f_getvar $VAR_NFS_TCP cp
+ if [ "$cp" = "YES" ]; then
+ export $VAR_NFS_TCP="NO"
+ else
+ export $VAR_NFS_TCP="YES"
+ fi ;;
+ " $msg_nfs_version_3")
+ f_getvar $VAR_NFS_V3 cp
+ if [ "$cp" = "YES" ]; then
+ export $VAR_NFS_V3="NO"
+ else
+ export $VAR_NFS_V3="YES"
+ fi ;;
+ " $msg_debugging")
+ if f_getvar $VAR_DEBUG cp && [ "$cp" ]; then
+ unset $VAR_DEBUG
+ else
+ export $VAR_DEBUG=1
+ fi ;;
+ " $msg_dhcp")
+ f_getvar $VAR_TRY_DHCP cp
+ if [ "$cp" = "YES" ]; then
+ export $VAR_TRY_DHCP="NO"
+ else
+ export $VAR_TRY_DHCP="YES"
+ fi ;;
+ " $msg_ipv6")
+ f_getvar $VAR_TRY_RTSOL cp
+ if [ "$cp" = "YES" ]; then
+ export $VAR_TRY_RTSOL="NO"
+ else
+ export $VAR_TRY_RTSOL="YES"
+ fi ;;
+ " $msg_ftp_username")
+ f_media_set_ftp_userpass ;;
+ " $msg_editor")
+ f_variable_get_value $VAR_EDITOR \
+ "$msg_please_specify_the_name_of_the_text_editor"
+ ;;
+ " $msg_release_name")
+ f_variable_get_value $VAR_RELNAME \
+ "$msg_please_specify_the_release_you_wish_to_load"
+ ;;
+ " $msg_media_type")
+ f_media_get_type ;;
+ " $msg_media_timeout")
+ f_variable_get_value $VAR_MEDIA_TIMEOUT \
+ "$msg_please_specify_the_number_of_seconds_to_wait"
+ ;;
+ " $msg_rescan_devices")
+ f_device_rescan ;;
+ " $msg_use_defaults")
+ f_variable_set_defaults ;;
+ esac
+ done
+
+ # Restore old VAR_NONINTERACTIVE if needed.
+ [ "$old_interactive" ] &&
+ setvar $VAR_NONINTERACTIVE "$old_interactive"
+
+ return $SUCCESS
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/options.subr
+
+fi # ! $_MEDIA_OPTIONS_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/tcpip.subr b/usr.sbin/bsdconfig/share/media/tcpip.subr
new file mode 100644
index 0000000..0bf0487
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/tcpip.subr
@@ -0,0 +1,1688 @@
+if [ ! "$_MEDIA_TCPIP_SUBR" ]; then _MEDIA_TCPIP_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/tcpip.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/variable.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+TCP_HELPFILE=$BSDCFG_LIBE/include/tcp.hlp
+NETWORK_DEVICE_HELPFILE=$BSDCFG_LIBE/include/network_device.hlp
+
+############################################################ GLOBALS
+
+#
+# Path to resolv.conf(5).
+#
+: ${RESOLV_CONF:="/etc/resolv.conf"}
+
+#
+# Path to nsswitch.conf(5).
+#
+: ${NSSWITCH_CONF:="/etc/nsswitch.conf"}
+
+#
+# Path to hosts(5)
+#
+: ${ETC_HOSTS:="/etc/hosts"}
+
+#
+# Structure of dhclient.leases(5) lease { ... } entry
+#
+f_struct_define DHCP_LEASE \
+ interface \
+ fixed_address \
+ filename \
+ server_name \
+ script \
+ medium \
+ host_name \
+ subnet_mask \
+ routers \
+ domain_name_servers \
+ domain_name \
+ broadcast_address \
+ dhcp_lease_time \
+ dhcp_message_type \
+ dhcp_server_identifier \
+ dhcp_renewal_time \
+ dhcp_rebinding_time \
+ renew \
+ rebind \
+ expire
+
+############################################################ FUNCTIONS
+
+# f_validate_hostname $hostname
+#
+# Returns zero if the given argument (a fully-qualified hostname) is compliant
+# with standards set-forth in RFC's 952 and 1123 of the Network Working Group:
+#
+# RFC 952 - DoD Internet host table specification
+# http://tools.ietf.org/html/rfc952
+#
+# RFC 1123 - Requirements for Internet Hosts - Application and Support
+# http://tools.ietf.org/html/rfc1123
+#
+# See http://en.wikipedia.org/wiki/Hostname for a brief overview.
+#
+# The return status for invalid hostnames is one of:
+# 255 Entire hostname exceeds the maximum length of 255 characters.
+# 63 One or more individual labels within the hostname (separated by
+# dots) exceeds the maximum of 63 characters.
+# 1 One or more individual labels within the hostname contains one
+# or more invalid characters.
+# 2 One or more individual labels within the hostname starts or
+# ends with a hyphen (hyphens are allowed, but a label cannot
+# begin or end with a hyphen).
+# 3 One or more individual labels within the hostname are null.
+#
+# f_dialog_validate_hostname $hostname
+#
+# If the hostname is determined to be invalid, the appropriate error will be
+# displayed using the f_show_msg function.
+#
+f_validate_hostname()
+{
+ local fqhn="$1"
+
+ # Return error if the hostname exceeds 255 characters
+ [ ${#fqhn} -gt 255 ] && return 255
+
+ local IFS="." # Split on `dot'
+ for label in $fqhn; do
+ # Return error if the label exceeds 63 characters
+ [ ${#label} -gt 63 ] && return 63
+
+ # Return error if the label is null
+ [ "$label" ] || return 3
+
+ # Return error if label begins/ends with dash
+ case "$label" in -*|*-) return 2; esac
+
+ # Return error if the label contains any invalid chars
+ case "$label" in *[!0-9a-zA-Z-]*) return 1; esac
+ done
+
+ return $SUCCESS
+}
+
+# f_inet_atoi $ipv4_address [$var_to_set]
+#
+# Convert an IPv4 address or mask from dotted-quad notation (e.g., `127.0.0.1'
+# or `255.255.255.0') to a 32-bit unsigned integer for the purpose of network
+# and broadcast calculations. For example, one can validate that two addresses
+# are on the same network:
+#
+# f_inet_atoi 1.2.3.4 ip1num
+# f_inet_atoi 1.2.4.5 ip2num
+# f_inet_atoi 255.255.0.0 masknum
+# if [ $(( $ip1num & $masknum )) -eq \
+# $(( $ip2num & $masknum )) ]
+# then
+# : IP addresses are on same network
+# fi
+#
+# See f_validate_ipaddr() below for an additional example usage, on calculating
+# network and broadcast addresses.
+#
+# If $var_to_set is missing or NULL, the converted IP address is printed to
+# standard output for capturing in a sub-shell (which is less-recommended
+# because of performance degredation; for example, when called in a loop).
+#
+f_inet_atoi()
+{
+ local __addr="$1" __var_to_set="$2" __num=0
+ if f_validate_ipaddr "$__addr"; then
+ __num=$( IFS=.; set -- $__addr; \
+ echo $(( ($1 << 24) + ($2 << 16) + ($3 << 8) + $4 )) )
+ fi
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" $__num
+ else
+ echo $__num
+ fi
+}
+
+# f_validate_ipaddr $ipaddr [$netmask]
+#
+# Returns zero if the given argument (an IP address) is of the proper format.
+#
+# The return status for invalid IP address is one of:
+# 1 One or more individual octets within the IP address (separated
+# by dots) contains one or more invalid characters.
+# 2 One or more individual octets within the IP address are null
+# and/or missing.
+# 3 One or more individual octets within the IP address exceeds the
+# maximum of 255 (or 2^8, being an octet comprised of 8 bits).
+# 4 The IP address has either too few or too many octets.
+#
+# If a netmask is provided, the IP address is checked further:
+#
+# 5 The IP address must not be the network or broadcast address.
+#
+f_validate_ipaddr()
+{
+ local ip="$1" mask="$2"
+
+ # Track number of octets for error checking
+ local noctets=0
+
+ local oldIFS="$IFS"
+ local IFS="." # Split on `dot'
+ for octet in $ip; do
+ # Return error if the octet is null
+ [ "$octet" ] || return 2
+
+ # Return error if not a whole integer
+ f_isinteger "$octet" || return 1
+
+ # Return error if not a positive integer
+ [ $octet -ge 0 ] || return 1
+
+ # Return error if the octet exceeds 255
+ [ $octet -gt 255 ] && return 3
+
+ noctets=$(( $noctets + 1 ))
+ done
+ IFS="$oldIFS"
+
+ [ $noctets -eq 4 ] || return 4
+
+ #
+ # The IP address must not be network or broadcast address.
+ #
+ if [ "$mask" ]; then
+ local ipnum masknum netnum bcastnum
+ local max_addr=4294967295 # 255.255.255.255
+
+ f_inet_atoi $ip ipnum
+ f_inet_atoi $mask masknum
+
+ netnum=$(( $ipnum & $masknum ))
+ bcastnum=$(( ($ipnum & $masknum)+$max_addr-$masknum ))
+
+ if [ "$masknum" ] &&
+ [ $ipnum -eq $netnum -o $ipnum -eq $bcastnum ]
+ then
+ return 5
+ fi
+ fi
+
+ return $SUCCESS
+}
+
+# f_validate_ipaddr6 $ipv6_addr
+#
+# Returns zero if the given argument (an IPv6 address) is of the proper format.
+#
+# The return status for invalid IP address is one of:
+# 1 One or more individual segments within the IP address
+# (separated by colons) contains one or more invalid characters.
+# Segments must contain only combinations of the characters 0-9,
+# A-F, or a-f.
+# 2 Too many/incorrect null segments. A single null segment is
+# allowed within the IP address (separated by colons) but not
+# allowed at the beginning or end (unless a double-null segment;
+# i.e., "::*" or "*::").
+# 3 One or more individual segments within the IP address
+# (separated by colons) exceeds the length of 4 hex-digits.
+# 4 The IP address entered has either too few (less than 3), too
+# many (more than 8), or not enough segments, separated by
+# colons.
+# 5* The IPv4 address at the end of the IPv6 address is invalid.
+# * When there is an error with the dotted-quad IPv4 address at the
+# end of the IPv6 address, the return value of 5 is OR'd with a
+# bit-shifted (<< 4) return of f_validate_ipaddr.
+#
+f_validate_ipaddr6()
+{
+ local ip="${1%\%*}" # removing the interface specification if-present
+
+ local IFS=":" # Split on `colon'
+ set -- $ip:
+
+ # Return error if too many or too few segments
+ # Using 9 as max in case of leading or trailing null spanner
+ [ $# -gt 9 -o $# -lt 3 ] && return 4
+
+ local h="[0-9A-Fa-f]"
+ local nulls=0 nsegments=$# contains_ipv4_segment=
+
+ while [ $# -gt 0 ]; do
+
+ segment="${1%:}"
+ shift
+
+ #
+ # Return error if this segment makes one null too-many. A
+ # single null segment is allowed anywhere in the middle as well
+ # as double null segments are allowed at the beginning or end
+ # (but not both).
+ #
+ if [ ! "$segment" ]; then
+ nulls=$(( $nulls + 1 ))
+ if [ $nulls -eq 3 ]; then
+ # Only valid syntax for 3 nulls is `::'
+ [ "$ip" = "::" ] || return 2
+ elif [ $nulls -eq 2 ]; then
+ # Only valid if begins/ends with `::'
+ case "$ip" in
+ ::*|*::) : fall thru ;;
+ *) return 2
+ esac
+ fi
+ continue
+ fi
+
+ #
+ # Return error if not a valid hexadecimal short
+ #
+ case "$segment" in
+ $h|$h$h|$h$h$h|$h$h$h$h)
+ : valid segment of 1-4 hexadecimal digits
+ ;;
+ *[!0-9A-Fa-f]*)
+ # Segment contains at least one invalid char
+
+ # Return error immediately if not last segment
+ [ $# -eq 0 ] || return 1
+
+ # Otherwise, check for legacy IPv4 notation
+ case "$segment" in
+ *[!0-9.]*)
+ # Segment contains at least one invalid
+ # character even for an IPv4 address
+ return 1
+ esac
+
+ # Return error if not enough segments
+ if [ $nulls -eq 0 ]; then
+ [ $nsegments -eq 7 ] || return 4
+ fi
+
+ contains_ipv4_segment=1
+
+ # Validate the IPv4 address
+ f_validate_ipaddr "$segment" ||
+ return $(( 5 | $? << 4 ))
+ ;;
+ *)
+ # Segment characters are all valid but too many
+ return 3
+ esac
+
+ done
+
+ if [ $nulls -eq 1 ]; then
+ # Single null segment cannot be at beginning/end
+ case "$ip" in
+ :*|*:) return 2
+ esac
+ fi
+
+ #
+ # A legacy IPv4 address can span the last two 16-bit segments,
+ # reducing the amount of maximum allowable segments by-one.
+ #
+ maxsegments=8
+ if [ "$contains_ipv4_segment" ]; then
+ maxsegments=7
+ fi
+
+ case $nulls in
+ # Return error if missing segments with no null spanner
+ 0) [ $nsegments -eq $maxsegments ] || return 4 ;;
+ # Return error if null spanner with too many segments
+ 1) [ $nsegments -le $maxsegments ] || return 4 ;;
+ # Return error if leading/trailing `::' with too many segments
+ 2) [ $nsegments -le $(( $maxsegments + 1 )) ] || return 4 ;;
+ esac
+
+ return $SUCCESS
+}
+
+# f_validate_netmask $netmask
+#
+# Returns zero if the given argument (a subnet mask) is of the proper format.
+#
+# The return status for invalid netmask is one of:
+# 1 One or more individual fields within the subnet mask (separated
+# by dots) contains one or more invalid characters.
+# 2 One or more individual fields within the subnet mask are null
+# and/or missing.
+# 3 One or more individual fields within the subnet mask exceeds
+# the maximum of 255 (a full 8-bit register).
+# 4 The subnet mask has either too few or too many fields.
+# 5 One or more individual fields within the subnet mask is an
+# invalid integer (only 0,128,192,224,240,248,252,254,255 are
+# valid integers).
+#
+f_validate_netmask()
+{
+ local mask="$1"
+
+ # Track number of fields for error checking
+ local nfields=0
+
+ local IFS="." # Split on `dot'
+ for field in $mask; do
+ # Return error if the field is null
+ [ "$field" ] || return 2
+
+ # Return error if not a whole positive integer
+ f_isinteger "$field" || return 1
+
+ # Return error if the field exceeds 255
+ [ $field -gt 255 ] && return 3
+
+ # Return error if the field is an invalid integer
+ case "$field" in
+ 0|128|192|224|240|248|252|254|255) :;;
+ *) return 5;;
+ esac
+
+ nfields=$(( $nfields + 1 ))
+ done
+
+ [ $nfields -eq 4 ] || return 4
+}
+
+# f_validate_gateway $gateway $ipaddr $netmask
+#
+# Validate an IPv4 default gateway (aka router) address for a given IP address
+# making sure the two are in the same network (able to ``talk'' to each other).
+# Returns success if $ipaddr and $gateway are in the same network given subnet
+# mask $netmask.
+#
+f_validate_gateway()
+{
+ local gateway="$1" ipaddr="$2" netmask="$3"
+ local gwnum ipnum masknum
+
+ f_validate_ipaddr "$gateway" "$netmask" || return $FAILURE
+
+ f_inet_atoi "$netmask" masknum
+ f_inet_atoi "$ipaddr" ipnum
+ f_inet_atoi "$gateway" gwnum
+
+ # Gateway must be within set of IPs reachable through interface
+ [ $(( $ipnum & $masknum )) -eq \
+ $(( $gwnum & $masknum )) ] # Return status
+}
+
+# f_dialog_validate_tcpip $hostname $gateway $nameserver $ipaddr $netmask
+#
+# Returns success if the arguments provided are valid for accessing a TCP/IP
+# network, otherwise returns failure.
+#
+f_dialog_validate_tcpip()
+{
+ local hostname="$1" gateway="$2" nameserver="$3"
+ local ipaddr="$4" netmask="$5"
+ local ipnum masknum
+
+ if [ ! "$hostname" ]; then
+ f_dialog_msgbox "$msg_must_specify_a_host_name_of_some_sort"
+ elif ! f_validate_hostname "$hostname"; then
+ f_dialog_msgbox "$msg_invalid_hostname_value"
+ elif [ "$netmask" ] && ! f_validate_netmask "$netmask"; then
+ f_dialog_msgbox "$msg_invalid_netmask_value"
+ elif [ "$nameserver" ] &&
+ ! f_validate_ipaddr "$nameserver" &&
+ ! f_validate_ipaddr6 "$nameserver"; then
+ f_dialog_msgbox "$msg_invalid_name_server_ip_address_specified"
+ elif [ "$ipaddr" ] && ! f_validate_ipaddr "$ipaddr" "$netmask"; then
+ f_dialog_msgbox "$msg_invalid_ipv4_address"
+ elif [ "$gateway" -a "$gateway" != "NO" ] &&
+ ! f_validate_gateway "$gateway" "$ipaddr" "$netmask"; then
+ f_dialog_msgbox "$msg_invalid_gateway_ipv4_address_specified"
+ else
+ return $SUCCESS
+ fi
+
+ return $FAILURE
+}
+
+# f_ifconfig_inet $interface [$var_to_set]
+#
+# Returns the IPv4 address associated with $interface. If $var_to_set is
+# missing or NULL, the IP address is printed to standard output for capturing
+# in a sub-shell (which is less-recommended because of performance degredation;
+# for example, when called in a loop).
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_ifconfig_inet_awk='
+BEGIN { found = 0 }
+( $1 == "inet" ) \
+{
+ print $2
+ found = 1
+ exit
+}
+END { exit ! found }
+'
+f_ifconfig_inet()
+{
+ local __interface="$1" __var_to_set="$2"
+ if [ "$__var_to_set" ]; then
+ local __ip
+ __ip=$( ifconfig "$__interface" 2> /dev/null |
+ awk "$f_ifconfig_inet_awk" )
+ setvar "$__var_to_set" "$__ip"
+ else
+ ifconfig "$__interface" 2> /dev/null |
+ awk "$f_ifconfig_inet_awk"
+ fi
+}
+
+# f_ifconfig_inet6 $interface [$var_to_set]
+#
+# Returns the IPv6 address associated with $interface. If $var_to_set is
+# missing or NULL, the IP address is printed to standard output for capturing
+# in a sub-shell (which is less-recommended because of performance degredation;
+# for example, when called in a loop).
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_ifconfig_inet6_awk='
+BEGIN { found = 0 }
+( $1 == "inet6" ) \
+{
+ print $2
+ found = 1
+ exit
+}
+END { exit ! found }
+'
+f_ifconfig_inet6()
+{
+ local __interface="$1" __var_to_set="$2"
+ if [ "$__var_to_set" ]; then
+ local __ip6
+ __ip6=$( ifconfig "$__interface" 2> /dev/null |
+ awk "$f_ifconfig_inet6_awk" )
+ setvar "$__var_to_set" "$__ip6"
+ else
+ ifconfig "$__interface" 2> /dev/null |
+ awk "$f_ifconfig_inet6_awk"
+ fi
+}
+
+# f_ifconfig_netmask $interface [$var_to_set]
+#
+# Returns the IPv4 subnet mask associated with $interface. If $var_to_set is
+# missing or NULL, the netmask is printed to standard output for capturing in a
+# sub-shell (which is less-recommended because of performance degredation; for
+# example, when called in a loop).
+#
+f_ifconfig_netmask()
+{
+ local __interface="$1" __var_to_set="$2" __octets
+ __octets=$( ifconfig "$__interface" 2> /dev/null | awk \
+ '
+ BEGIN { found = 0 }
+ ( $1 == "inet" ) \
+ {
+ printf "%s %s %s %s\n",
+ substr($4,3,2),
+ substr($4,5,2),
+ substr($4,7,2),
+ substr($4,9,2)
+ found = 1
+ exit
+ }
+ END { exit ! found }
+ ' ) || return $FAILURE
+
+ local __octet __netmask=
+ for __octet in $__octets; do
+ __netmask="$__netmask.$( printf "%u" "0x$__octet" )"
+ done
+ __netmask="${__netmask#.}"
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$__netmask"
+ else
+ echo $__netmask
+ fi
+}
+
+# f_route_get_default [$var_to_set]
+#
+# Returns the IP address of the currently active default router. If $var_to_set
+# is missing or NULL, the IP address is printed to standard output for
+# capturing in a sub-shell (which is less-recommended because of performance
+# degredation; for example, when called in a loop).
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_route_get_default='
+BEGIN { found = 0 }
+( $1 == "gateway:" ) \
+{
+ print $2
+ found = 1
+ exit
+}
+END { exit ! found }
+'
+f_route_get_default()
+{
+ local __var_to_set="$1"
+ if [ "$__var_to_set" ]; then
+ local __ip
+ __ip=$( route -n get default 2> /dev/null |
+ awk "$f_route_get_default_awk" )
+ setvar "$__var_to_set" "$__ip"
+ else
+ route -n get default 2> /dev/null |
+ awk "$f_route_get_default_awk"
+ fi
+}
+
+# f_resolv_conf_nameservers [$var_to_set]
+#
+# Returns nameserver(s) configured in resolv.conf(5). If $var_to_set is missing
+# or NULL, the list of nameservers is printed to standard output for capturing
+# in a sub-shell (which is less-recommended because of performance degredation;
+# for example, when called in a loop).
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_resolv_conf_nameservers_awk='
+BEGIN { found = 0 }
+( $1 == "nameserver" ) \
+{
+ print $2
+ found = 1
+}
+END { exit ! found }
+'
+f_resolv_conf_nameservers()
+{
+ local __var_to_set="$1"
+ if [ "$__var_to_set" ]; then
+ local __ns
+ __ns=$( awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \
+ 2> /dev/null )
+ setvar "$__var_to_set" "$__ns"
+ else
+ awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \
+ 2> /dev/null
+ fi
+}
+
+# f_config_resolv
+#
+# Attempts to configure resolv.conf(5) and ilk. Returns success if able to
+# write the file(s), otherwise returns error status.
+#
+# Variables from variable.subr that are used in configuring resolv.conf(5) are
+# as follows (all of which can be configured automatically through functions
+# like f_dhcp_get_info() or manually):
+#
+# VAR_NAMESERVER
+# The nameserver to add in resolv.conf(5).
+# VAR_DOMAINNAME
+# The domain to configure in resolv.conf(5). Also used in the
+# configuration of hosts(5).
+# VAR_IPADDR
+# The IPv4 address to configure in hosts(5).
+# VAR_IPV6ADDR
+# The IPv6 address to configure in hosts(5).
+# VAR_HOSTNAME
+# The hostname to associate with the IPv4 and/or IPv6 address in
+# hosts(5).
+#
+f_config_resolv()
+{
+ local cp c6p dp hp
+
+ f_getvar $VAR_NAMESERVER cp
+ if [ "$cp" ]; then
+ case "$RESOLV_CONF" in
+ */*) f_quietly mkdir -p "${RESOLV_CONF%/*}" ;;
+ esac
+
+ # Attempt to create/truncate the file
+ ( :> "$RESOLV_CONF" ) 2> /dev/null || return $FAILURE
+
+ f_getvar $VAR_DOMAINNAME dp &&
+ printf "domain\t%s\n" "$dp" >> "$RESOLV_CONF"
+ printf "nameserver\t%s\n" "$cp" >> "$RESOLV_CONF"
+
+ f_dprintf "Wrote out %s" "$RESOLV_CONF"
+ fi
+
+ f_getvar $VAR_DOMAINNAME dp
+ f_getvar $VAR_IPADDR cp
+ f_getvar $VAR_IPV6ADDR c6p
+ f_getvar $VAR_HOSTNAME hp
+
+ # Attempt to create the file if it doesn't already exist
+ if [ ! -e "$ETC_HOSTS" ]; then
+ case "$ETC_HOSTS" in
+ */*) f_quietly mkdir -p "${ETC_HOSTS%/*}" ;;
+ esac
+
+ ( :> "$ETC_HOSTS" ) 2> /dev/null || return $FAILURE
+ fi
+
+ # Scan the file and add ourselves if not already configured
+ awk -v dn="$dp" -v ip4="$cp" -v ip6="$c6p" -v hn="$hp" '
+ BEGIN {
+ local4found = local6found = 0
+ hn4found = hn6found = h4found = h6found = 0
+ h = ( match(hn, /\./) ? substr(hn, 0, RSTART-1) : "" )
+ }
+ ($1 == "127.0.0.1") { local4found = 1 }
+ ($1 == "::1") { local6found = 1 }
+ {
+ for (n = 2; n <= NF; n++)
+ {
+ if ( $1 == ip4 ) {
+ if ( $n == h ) h4found = 1
+ if ( $n == hn ) hn4found = 1
+ if ( $n == hn "." ) hn4found = 1
+ }
+ if ( $1 == ip6 ) {
+ if ( $n == h ) h6found = 1
+ if ( $n == hn ) hn6found = 1
+ if ( $n == hn "." ) hn6found = 1
+ }
+ }
+ }
+ END {
+ hosts = FILENAME
+
+ if ( ! local6found )
+ printf "::1\t\t\tlocalhost%s\n",
+ ( dn ? " localhost." dn : "" ) >> hosts
+ if ( ! local4found )
+ printf "127.0.0.1\t\tlocalhost%s\n",
+ ( dn ? " localhost." dn : "" ) >> hosts
+
+ if ( ip6 && ! (h6found && hn6found))
+ {
+ printf "%s\t%s %s\n", ip6, hn, h >> hosts
+ printf "%s\t%s.\n", ip6, hn >> hosts
+ }
+ else if ( ip6 )
+ {
+ if ( ! h6found )
+ printf "%s\t%s.\n", ip6, h >> hosts
+ if ( ! hn6found )
+ printf "%s\t%s\n", ip6, hn >> hosts
+ }
+
+ if ( ip4 && ! (h4found && hn4found))
+ {
+ printf "%s\t\t%s %s\n", ip4, hn, h >> hosts
+ printf "%s\t\t%s.\n", ip4, hn >> hosts
+ }
+ else if ( ip4 )
+ {
+ if ( ! h4found )
+ printf "%s\t\t%s.\n", ip4, h >> hosts
+ if ( ! hn4found )
+ printf "%s\t\t%s\n", ip4, hn >> hosts
+ }
+ }
+ ' "$ETC_HOSTS" 2> /dev/null || return $FAILURE
+
+ f_dprintf "Wrote out %s" "$ETC_HOSTS"
+ return $SUCCESS
+}
+
+# f_dhcp_parse_leases $leasefile struct_name
+#
+# Parse $leasefile and store the information for the most recent lease in a
+# struct (see struct.subr for additional details) named `struct_name'. See
+# DHCP_LEASE struct definition in the GLOBALS section above.
+#
+f_dhcp_parse_leases()
+{
+ local leasefile="$1" struct_name="$2"
+
+ [ "$struct_name" ] || return $FAILURE
+
+ if [ ! -e "$leasefile" ]; then
+ f_dprintf "%s: No such file or directory" "$leasefile"
+ return $FAILURE
+ fi
+
+ f_struct "$struct_name" && f_struct_free "$struct_name"
+ f_struct_new DHCP_LEASE "$struct_name"
+
+ eval "$( awk -v struct="$struct_name" '
+ BEGIN {
+ lease_found = 0
+ keyword_list = " \
+ interface \
+ fixed-address \
+ filename \
+ server-name \
+ script \
+ medium \
+ "
+ split(keyword_list, keywords, FS)
+
+ time_list = "renew rebind expire"
+ split(time_list, times, FS)
+
+ option_list = " \
+ host-name \
+ subnet-mask \
+ routers \
+ domain-name-servers \
+ domain-name \
+ broadcast-address \
+ dhcp-lease-time \
+ dhcp-message-type \
+ dhcp-server-identifier \
+ dhcp-renewal-time \
+ dhcp-rebinding-time \
+ "
+ split(option_list, options, FS)
+ }
+ function set_value(prop,value)
+ {
+ lease_found = 1
+ gsub(/[^[:alnum:]_]/, "_", prop)
+ sub(/;$/, "", value)
+ sub(/^"/, "", value)
+ sub(/"$/, "", value)
+ sub(/,.*/, "", value)
+ printf "%s set %s \"%s\"\n", struct, prop, value
+ }
+ /^lease {$/, /^}$/ \
+ {
+ if ( $0 ~ /^lease {$/ ) next
+ if ( $0 ~ /^}$/ ) exit
+
+ for (k in keywords)
+ {
+ keyword = keywords[k]
+ if ( $1 == keyword )
+ {
+ set_value(keyword, $2)
+ next
+ }
+ }
+
+ for (t in times)
+ {
+ time = times[t]
+ if ( $1 == time )
+ {
+ set_value(time, $2 " " $3 " " $4)
+ next
+ }
+ }
+
+ if ( $1 != "option" ) next
+ for (o in options)
+ {
+ option = options[o]
+ if ( $2 == option )
+ {
+ set_value(option, $3)
+ next
+ }
+ }
+ }
+ EXIT {
+ if ( ! lease_found )
+ {
+ printf "f_struct_free \"%s\"\n", struct
+ print "return $FAILURE"
+ }
+ }
+ ' "$leasefile" )"
+}
+
+# f_dhcp_get_info $interface
+#
+# Parse the dhclient(8) lease database for $interface to obtain all the
+# necessary IPv4 details necessary to communicate on the network. The retrieved
+# information is stored in VAR_IPADDR, VAR_NETMASK, VAR_GATEWAY, and
+# VAR_NAMESERVER.
+#
+# If reading the lease database fails, values are obtained from ifconfig(8) and
+# route(8). If the DHCP lease did not provide a nameserver (or likewise, we
+# were unable to parse the lease database), fall-back to resolv.conf(5) for
+# obtaining the nameserver. Always returns success.
+#
+f_dhcp_get_info()
+{
+ local interface="$1" cp
+ local leasefile="/var/db/dhclient.leases.$interface"
+
+ # If it fails, do it the old-fashioned way
+ if f_dhcp_parse_leases "$leasefile" lease; then
+ lease get fixed_address $VAR_IPADDR
+ lease get subnet_mask $VAR_NETMASK
+ lease get routers cp
+ setvar $VAR_GATEWAY "${cp%%,*}"
+ lease get domain_name_servers cp
+ setvar $VAR_NAMESERVER "${cp%%,*}"
+ lease get host_name cp &&
+ setvar $VAR_HOSTNAME "$cp"
+ f_struct_free lease
+ else
+ # Bah, now we have to get the information from ifconfig
+ if f_debugging; then
+ f_dprintf "DHCP configured interface returns %s" \
+ "$( ifconfig "$interface" )"
+ fi
+ f_ifconfig_inet "$interface" $VAR_IPADDR
+ f_ifconfig_netmask "$interface" $VAR_NETMASK
+ f_route_get_default $VAR_GATEWAY
+ fi
+
+ # If we didn't get a name server value, hunt for it in resolv.conf
+ local ns
+ if [ -r "$RESOLV_CONF" ] && ! {
+ f_getvar $VAR_NAMESERVER ns || [ "$ns" ]
+ }; then
+ f_resolv_conf_nameservers cp &&
+ setvar $VAR_NAMESERVER ${cp%%[$IFS]*}
+ fi
+
+ return $SUCCESS
+}
+
+# f_rtsol_get_info $interface
+#
+# Returns the rtsol-provided IPv6 address associated with $interface. The
+# retrieved IP address is stored in VAR_IPV6ADDR. Always returns success.
+#
+f_rtsol_get_info()
+{
+ local interface="$1" cp
+ cp=$( ifconfig "$interface" 2> /dev/null | awk \
+ '
+ BEGIN { found = 0 }
+ ( $1 == "inet6" ) && ( $2 ~ /^fe80:/ ) \
+ {
+ print $2
+ found = 1
+ exit
+ }
+ END { exit ! found }
+ ' ) && setvar $VAR_IPV6ADDR "$cp"
+}
+
+# f_host_lookup $host [$var_to_set]
+#
+# Use host(1) to lookup (or reverse) an Internet number from (or to) a name.
+# Multiple answers are returned separated by a single space. If host(1) does
+# not exit cleanly, its full output is provided and the return status is 1.
+#
+# If nsswitch.conf(5) has been configured to query local access first for the
+# `hosts' database, we'll manually check hosts(5) first (preventing host(1)
+# from hanging in the event that DNS goes awry).
+#
+# If $var_to_set is missing or NULL, the list of IP addresses is printed to
+# standard output for capturing in a sub-shell (which is less-recommended
+# because of performance degredation; for example, when called in a loop).
+#
+# The variables from variable.subr used in looking up the host are as follows
+# (which are set manually):
+#
+# VAR_IPV6_ENABLE [Optional]
+# If set to "YES", enables the lookup of IPv6 addresses and IPv4
+# address. IPv6 addresses, if any, will come before IPv4. Note
+# that if nsswitch.conf(5) shows an affinity for "files" for the
+# "host" database and there is a valid entry in hosts(5) for
+# $host, this setting currently has no effect (an IPv4 address
+# can supersede an IPv6 address). By design, hosts(5) overrides
+# any preferential treatment. Otherwise, if this variable is not
+# set, IPv6 addresses will not be used (IPv4 addresses will
+# specifically be requested from DNS).
+#
+# This function is a two-parter. Below is the awk(1) portion of the function,
+# afterward is the sh(1) function which utilizes the below awk script.
+#
+f_host_lookup_awk='
+BEGIN{ addrs = "" }
+!/^[[:space:]]*(#|$)/ \
+{
+ for (n=1; n++ < NF;) if ($n == name)
+ addrs = addrs (addrs ? " " : "") $1
+}
+END {
+ if (addrs) print addrs
+ exit !addrs
+}
+'
+f_host_lookup()
+{
+ local __host="$1" __var_to_set="$2"
+ f_dprintf "f_host_lookup: host=[%s]" "$__host"
+
+ # If we're configured to look at local files first, do that
+ if awk '/^hosts:/{exit !($2=="files")}' "$NSSWITCH_CONF"; then
+ if [ "$__var_to_set" ]; then
+ local __cp
+ if __cp=$( awk -v name="$__host" \
+ "$f_host_lookup_awk" "$ETC_HOSTS" )
+ then
+ setvar "$__var_to_set" "$__cp"
+ return $SUCCESS
+ fi
+ else
+ awk -v name="$__host" \
+ "$f_host_lookup_awk" "$ETC_HOSTS" &&
+ return $SUCCESS
+ fi
+ fi
+
+ #
+ # Fall back to host(1) -- which is further governed by nsswitch.conf(5)
+ #
+
+ local __output __ip6 __addrs="" __wait=""
+ f_getvar $VAR_MEDIA_TIMEOUT __wait
+ [ "$__wait" ] && __wait="-W $(( $__wait / 2 ))"
+ f_getvar $VAR_IPV6_ENABLE __ip6
+ if [ "$__ip6" = "YES" ]; then
+ if ! __output=$( host -t AAAA $__wait -- "$__host" 2>&1 ); then
+ # An error occurred, display in-full and return error
+ [ "$__var_to_set" ] &&
+ setvar "$__var_to_set" "$__output"
+ return $FAILURE
+ fi
+ __addrs=$( echo "$__output" | awk '/ address /{print $NF}' )
+ fi
+ if ! __output=$( host -t A $__wait -- "$__host" 2>&1 ); then
+ # An error occurred, display it in-full and return error
+ [ "$__var_to_set" ] && setvar "$__var_to_set" "$__output"
+ return $FAILURE
+ fi
+ __addrs="$__addrs${__addrs:+ }$(
+ echo "$__output" | awk '/ address /{print $NF}' )"
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$__addrs"
+ else
+ echo $__addrs
+ fi
+}
+
+# f_device_dialog_tcp $device
+#
+# This is it - how to get TCP setup values. Prompt the user to edit/confirm the
+# interface, gateway, nameserver, and hostname settings -- all required for
+# general TCP/IP access.
+#
+# Variables from variable.subr that can be used to sript user input:
+#
+# VAR_NO_INET6
+# If set, prevents asking the user if they would like to use
+# rtsol(8) to check for an IPv6 router.
+# VAR_TRY_RTSOL
+# If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the
+# user if they would like to try the IPv6 RouTer SOLicitation
+# utility (rtsol(8)) to get IPv6 information. Ignored if
+# VAR_NO_INET6 is set.
+# VAR_TRY_DHCP
+# If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the
+# user if they would like to try to acquire IPv4 connection
+# settings from a DHCP server using dhclient(8).
+#
+# VAR_GATEWAY Default gateway to use.
+# VAR_IPADDR Interface address to assign.
+# VAR_NETMASK Interface subnet mask.
+# VAR_EXTRAS Extra interface options to ifconfig(8).
+# VAR_HOSTNAME Hostname to set.
+# VAR_DOMAINNAME Domain name to use.
+# VAR_NAMESERVER DNS nameserver to use when making lookups.
+# VAR_IPV6ADDR IPv6 interface address.
+#
+# In addition, the following variables are used in acquiring network settings
+# from the user:
+#
+# VAR_NONINTERACTIVE
+# If set (such as when running in a script), prevents asking the
+# user questions or displaying the usual prompts, etc.
+# VAR_NETINTERACTIVE
+# The one exception to VAR_NONINTERACTIVE is VAR_NETINTERACTIVE,
+# which if set will prompt the user to try RTSOL (unless
+# VAR_TRY_RTSOL has been set), try DHCP (unless VAR_TRY_DHCP has
+# been set), and display the network verification dialog. This
+# allows you to have a mostly non-interactive script that still
+# prompts for network setup/confirmation.
+#
+# After successfull execution, the following variables are set:
+#
+# VAR_IFCONFIG + $device (e.g., `ifconfig_em0')
+# Defines the ifconfig(8) properties specific to $device.
+#
+f_device_dialog_tcp()
+{
+ local dev="$1" cp n
+ local use_dhcp="" use_rtsol=""
+ local _ipaddr _netmask _extras
+
+ [ "$dev" ] || return $FAILURE
+
+ # Initialize vars from previous device values
+ local private
+ device_$dev get private private
+ if [ "$private" ] && f_struct "$private"; then
+ $private get ipaddr _ipaddr
+ $private get netmask _netmask
+ $private get extras _extras
+ $private get use_dhcp use_dhcp
+ $private get use_rtsol use_rtsol
+ else # See if there are any defaults
+
+ #
+ # This is a hack so that the dialogs below are interactive in a
+ # script if we have requested interactive behavior.
+ #
+ local old_interactive=
+ if ! f_interactive && f_netinteractive; then
+ f_getvar $VAR_NONINTERACTIVE old_interactive
+ unset $VAR_NONINTERACTIVE
+ fi
+
+
+ #
+ # Try a RTSOL scan if such behavior is desired.
+ # If the variable was configured and is YES, do it.
+ # If it was configured to anything else, treat it as NO.
+ # Otherwise, ask the question interactively.
+ #
+ local try6
+ if ! f_quietly f_getvar $VAR_NO_INET6 && {
+ { f_getvar $VAR_TRY_RTSOL try6 && [ "$try6" = "YES" ]; } ||
+ {
+ ! f_quietly f_getvar $VAR_TRY_RTSOL &&
+ f_dialog_noyes "$msg_try_ipv6_configuration"
+ }
+ }; then
+ local i
+
+ f_quietly sysctl net.inet6.ip6.forwarding=0
+ f_quietly sysctl net.inet6.ip6.accept_rtadv=1
+ f_quietly ifconfig $dev up
+
+ i=$( sysctl -n net.inet6.ip6.dad_count )
+ sleep $(( $i + 1 ))
+
+ f_quietly mkdir -p /var/run
+ f_dialog_info "$msg_scanning_for_ra_servers"
+ if f_quietly rtsol $dev; then
+ i=$( sysctl -n net.inet6.ip6.dad_count )
+ sleep $(( $i + 1 ))
+ f_rtsol_get_info $dev
+ use_rtsol=1
+ else
+ use_rtsol=
+ fi
+ fi
+
+ #
+ # Try a DHCP scan if such behavior is desired.
+ # If the variable was configured and is YES, do it.
+ # If it was configured to anything else, treat it as NO.
+ # Otherwise, ask the question interactively.
+ #
+ local try4
+ if { f_getvar $VAR_TRY_DHCP try4 && [ "$try4" = "YES" ]; } || {
+ ! f_quietly f_getvar $VAR_TRY_DHCP &&
+ f_dialog_noyes "$msg_try_dhcp_configuration"
+ }; then
+ f_quietly ifconfig $dev delete
+ f_quietly mkdir -p /var/db
+ f_quietly mkdir -p /var/run
+ f_quietly mkdir -p /tmp
+
+ local msg="$msg_scanning_for_dhcp_servers"
+ trap - SIGINT
+ ( # Execute in sub-shell to allow/catch Ctrl-C
+ trap 'exit $FAILURE' SIGINT
+ if [ "$USE_XDIALOG" ]; then
+ f_quietly dhclient $dev |
+ f_xdialog_info "$msg"
+ else
+ f_dialog_info "$msg"
+ f_quietly dhclient $dev
+ fi
+ )
+ local retval=$?
+ trap 'f_interrupt' SIGINT
+ if [ $retval -eq $SUCCESS ]; then
+ f_dhcp_get_info $dev
+ use_dhcp=1
+ else
+ use_dhcp=
+ fi
+ fi
+
+ # Restore old VAR_NONINTERACTIVE if needed.
+ [ "$old_interactive" ] &&
+ setvar $VAR_NONINTERACTIVE "$old_interactive"
+
+ # Special hack so it doesn't show up oddly in the menu
+ local gw
+ if f_getvar $VAR_GATEWAY gw && [ "$gw" = "NO" ]; then
+ setvar $VAR_GATEWAY ""
+ fi
+
+ # Get old IP address from variable space, if available
+ if [ ! "$_ipaddr" ]; then
+ if f_getvar $VAR_IPADDR cp; then
+ _ipaddr="$cp"
+ elif f_getvar ${dev}_$VAR_IPADDR cp; then
+ _ipaddr="$cp"
+ fi
+ fi
+
+ # Get old netmask from variable space, if available
+ if [ ! "$_netmask" ]; then
+ if f_getvar $VAR_NETMASK cp; then
+ _netmask="$cp"
+ elif f_getvar ${dev}_$VAR_NETMASK cp; then
+ _netmask="$cp"
+ fi
+ fi
+
+ # Get old extras string from variable space, if available
+ if [ ! "$_extras" ]; then
+ if f_getvar $VAR_EXTRAS cp; then
+ _extras="$cp"
+ elif f_getvar ${dev}_$VAR_EXTRAS cp; then
+ _extras="$cp"
+ fi
+ fi
+ fi
+
+ # Look up values already recorded with the system, or blank the string
+ # variables ready to accept some new data
+ local _hostname _gateway _nameserver
+ f_getvar $VAR_HOSTNAME _hostname
+ case "$_hostname" in
+ *.*) : do nothing ;; # Already fully-qualified
+ *)
+ f_getvar $VAR_DOMAINNAME cp
+ [ "$cp" ] && _hostname="$_hostname.$cp"
+ esac
+ f_getvar $VAR_GATEWAY _gateway
+ f_getvar $VAR_NAMESERVER _nameserver
+
+ # Re-check variables for initial inheritance before heading into dialog
+ [ "$_hostname" ] || _hostname="${HOSTNAME:-$( hostname )}"
+ [ "$_gateway" ] || f_route_get_default _gateway
+ [ ! "$_nameserver" ] &&
+ f_resolv_conf_nameservers cp && _nameserver=${cp%%[$IFS]*}
+ [ "$_ipaddr" ] || f_ifconfig_inet $dev _ipaddr
+ [ "$_netmask" ] || f_ifconfig_netmask $dev _netmask
+
+ # If non-interactive, jump over dialog section and into config section
+ if f_netinteractive || f_interactive || [ ! "$_hostname" ]
+ then
+ [ ! "$_hostname" ] && f_interactive &&
+ f_dialog_msgbox "$msg_hostname_variable_not_set"
+
+ local title=" $msg_network_configuration "
+ local hline="$hline_alnum_arrows_punc_tab_enter"
+ local extras_help="$tcplayout_extras_help"
+
+ # Modify the help line for PLIP config
+ [ "${dev#plip}" != "$dev" ] &&
+ extras_help="$tcplayout_extras_help_for_plip"
+
+ f_getvar $VAR_IPV6ADDR cp && [ "$cp" ] &&
+ title="$title($msg_ipv6_ready) "
+
+ if [ ! "$USE_XDIALOG" ]; then
+ local prompt="$msg_dialog_mixedform_navigation_help"
+ # Calculate center position for displaying device label
+ local devlabel="$msg_configuration_for_interface $dev"
+ local width=54
+ local n=$(( $width/2 - (${#devlabel} + 4)/2 - 2 ))
+
+ while :; do
+ cp=$( $DIALOG \
+ --title "$title" \
+ --backtitle "$DIALOG_BACKTITLE" \
+ --hline "$hline" \
+ --item-help \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --help-button \
+ --help-label "$msg_help" \
+ --mixedform "$prompt" 16 $width 9 \
+ "$msg_host_name_including_domain:" 1 2 \
+ "$_hostname" 2 3 45 255 0 \
+ "$tcplayout_hostname_help" \
+ "$msg_ipv4_gateway:" 3 2 \
+ "$_gateway" 4 3 16 15 0 \
+ "$tcplayout_gateway_help" \
+ "$msg_name_server:" 3 31 \
+ "$_nameserver" 4 32 16 15 0 \
+ "$tcplayout_nameserver_help" \
+ "- $devlabel -" 5 $n "" 0 0 0 0 3 "" \
+ "$msg_ipv4_address:" 6 6 \
+ "$_ipaddr" 7 7 16 15 0 \
+ "$tcplayout_ipaddr_help" \
+ "$msg_netmask:" 6 31 \
+ "$_netmask" 7 32 16 15 0 \
+ "$tcplayout_netmask_help" \
+ "$msg_extra_options_to_ifconfig" 8 6 \
+ "$_extras" 9 7 41 2048 0 \
+ "$extras_help" \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
+
+ # --mixed-form always returns 0, we have to
+ # use the returned data to determine button
+ if [ ! "$cp" ]; then
+ # User either chose "Cancel", pressed
+ # ESC, or blanked every form field
+ return $FAILURE
+ else
+ n=$( echo "$cp" | f_number_of_lines )
+ [ $n -eq 1 ] && case "$cp" in HELP*)
+ # User chose "Help"
+ f_show_help "$TCP_HELPFILE"
+ continue
+ esac
+ fi
+
+ # Turn mixed-form results into env variables
+ eval "$( echo "$cp" | awk '
+ BEGIN {
+ n = 0
+ field[++n] = "_hostname"
+ field[++n] = "_gateway"
+ field[++n] = "_nameserver"
+ field[++n] = "_ipaddr"
+ field[++n] = "_netmask"
+ field[++n] = "_extras"
+ nfields = n
+ n = 0
+ }
+ {
+ gsub(/'\''/, "'\'\\\\\'\''")
+ sub(/[[:space:]]*$/, "")
+ value[field[++n]] = $0
+ }
+ END {
+ for ( n = 1; n <= nfields; n++ )
+ {
+ printf "%s='\''%s'\'';\n",
+ field[n],
+ value[field[n]]
+ }
+ }' )"
+
+ f_dialog_validate_tcpip \
+ "$_hostname" \
+ "$_gateway" \
+ "$_nameserver" \
+ "$_ipaddr" \
+ "$_netmask" \
+ && break
+ done
+ else
+ # Xdialog(1) does not support --mixed-form
+ # Create a persistent menu instead
+
+ f_dialog_title "$msg_network_configuration"
+ local prompt=""
+
+ while :; do
+ cp=$( $DIALOG \
+ --title "$DIALOG_TITLE" \
+ --backtitle "$DIALOG_BACKTITLE" \
+ --hline "$hline" \
+ --item-help \
+ --ok-label "$msg_ok" \
+ --cancel-label "$msg_cancel" \
+ --help "" \
+ --menu "$prompt" 21 60 8 \
+ "$msg_accept_continue" "" \
+ "$tcplayout_accept_cont_help" \
+ "$msg_host_name_including_domain:" \
+ "$_hostname" \
+ "$tcplayout_hostname_help" \
+ "$msg_ipv4_gateway:" "$_gateway" \
+ "$tcplayout_gateway_help" \
+ "$msg_name_server:" "$_nameserver" \
+ "$tcplayout_nameserver_help" \
+ "$msg_ipv4_address:" "$_ipaddr" \
+ "$tcplayout_ipaddr_help" \
+ "$msg_netmask:" "$_netmask" \
+ "$tcplayout_netmask_help" \
+ "$msg_extra_options_to_ifconfig" \
+ "$_extras" "$extras_help" \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD
+ )
+ local retval=$?
+ f_dprintf "retval=%u mtag=[%s]" $retval "$cp"
+
+ if [ $retval -eq 2 ]; then
+ # The Help button was pressed
+ f_show_help "$TCP_HELPFILE"
+ continue
+ elif [ $retval -ne 0 ]; then
+ # User chose "Cancel" or pressed ESC
+ f_dialog_title_restore
+ return $FAILURE
+ fi
+
+ case "$cp" in
+ "$msg_accept_continue")
+ f_dialog_validate_tcpip \
+ "$_hostname" \
+ "$_gateway" \
+ "$_nameserver" \
+ "$_ipaddr" \
+ "$_netmask" \
+ && break ;;
+ "$msg_host_name_including_domain:")
+ cp=$( f_dialog_input "$cp" \
+ "$_hostname"
+ ) && _hostname="$cp" ;;
+ "$msg_ipv4_gateway:")
+ cp=$( f_dialog_input "$cp" \
+ "$_gateway"
+ ) && _gateway="$cp" ;;
+ "$msg_name_server:")
+ cp=$( f_dialog_input "$cp" \
+ "$_nameserver"
+ ) && _nameserver="$cp" ;;
+ "$msg_ipv4_address:")
+ cp=$( f_dialog_input "$cp" \
+ "$_ipaddr"
+ ) && _ipaddr="$cp" ;;
+ "$msg_netmask:")
+ cp=$( f_dialog_input "$cp" \
+ "$_netmask"
+ ) && _netmask="$cp" ;;
+ "$msg_extra_options_to_ifconfig")
+ cp=$( f_dialog_input "$cp" \
+ "$_extras"
+ ) && _extras="$cp" ;;
+ esac
+ done
+
+ f_dialog_title_restore
+
+ fi # XDIALOG
+
+ fi # interactive
+
+ # We actually need to inform the rest of bsdconfig about this
+ # data now if the user hasn't selected cancel.
+
+ if [ "$_hostname" ]; then
+ setvar $VAR_HOSTNAME "$_hostname"
+ f_quietly hostname "$_hostname"
+ case "$_hostname" in
+ *.*) setvar $VAR_DOMAINNAME "${_hostname#*.}" ;;
+ esac
+ fi
+ [ "$_gateway" ] && setvar $VAR_GATEWAY "$_gateway"
+ [ "$_nameserver" ] && setvar $VAR_NAMESERVER "$_nameserver"
+ [ "$_ipaddr" ] && setvar $VAR_IPADDR "$_ipaddr"
+ [ "$_netmask" ] && setvar $VAR_NETMASK "$_netmask"
+ [ "$_extras" ] && setvar $VAR_EXTRAS "$_extras"
+
+ f_dprintf "Creating struct DEVICE_INFO devinfo_%s" "$dev"
+ f_struct_new DEVICE_INFO devinfo_$dev
+ device_$dev set private devinfo_$dev
+
+ devinfo_$dev set ipaddr $_ipaddr
+ devinfo_$dev set netmask $_netmask
+ devinfo_$dev set extras $_extras
+ devinfo_$dev set use_rtsol $use_rtsol
+ devinfo_$dev set use_dhcp $use_dhcp
+
+ if [ "$use_dhcp" -o "$_ipaddr" ]; then
+ if [ "$use_dhcp" ]; then
+ cp="DHCP${extras:+ $extras}"
+ else
+ cp="inet $_ipaddr netmask $_netmask${extras:+ $extras}"
+ fi
+ setvar $VAR_IFCONFIG$dev "$cp"
+ fi
+ [ "$use_rtsol" ] &&
+ setvar $VAR_IPV6_ENABLE "YES"
+
+ [ "$use_dhcp" ] ||
+ f_config_resolv # XXX this will do it on the MFS copy
+
+ return $SUCCESS
+}
+
+# f_device_scan_tcp [$var_to_set]
+#
+# Scan for the first active/configured TCP/IP device. The name of the interface
+# is printed to stderr like other dialog(1)-based functions (stdout is reserved
+# for dialog(1) interaction) if $var_to_set is missing or NULL. Returns failure
+# if no active/configured interface
+#
+f_device_scan_tcp()
+{
+ local __var_to_set="$1" __iface
+ for __iface in $( ifconfig -l ); do
+ if ifconfig $__iface | awk '
+ BEGIN {
+ has_inet = has_inet6 = is_ethernet = 0
+ is_usable = 1
+ }
+ ( $1 == "status:" && $2 != "active" ) { is_usable = 0; exit }
+ ( $1 == "inet" ) {
+ if ($2 == "0.0.0.0") { is_usable = 0; exit }
+ has_inet++
+ }
+ ( $1 == "inet6") { has_inet6++ }
+ ( $1 == "media:" ) {
+ if ($2 != "Ethernet") { is_usable = 0; exit }
+ is_ethernet = 1
+ }
+ END {
+ if (!(is_ethernet && (has_inet || has_inet6)))
+ is_usable = 0
+ exit ! is_usable
+ }'; then
+ f_interactive &&
+ f_show_msg "$msg_using_interface" "$__iface"
+ f_dprintf "f_device_scan_tcp found %s" "$__iface"
+ if [ "$__var_to_set" ]; then
+ setvar "$__var_to_set" "$__iface"
+ else
+ echo "$__iface" >&2
+ fi
+ return $SUCCESS
+ fi
+ done
+
+ return $FAILURE
+}
+
+# f_device_select_tcp
+#
+# Prompt the user to select network interface to use for TCP/IP access.
+# Variables from variable.subr that can be used to script user input:
+#
+# VAR_NETWORK_DEVICE [Optional]
+# Either a comma-separated list of network interfaces to try when
+# setting up network access (e.g., "fxp0,em0") or "ANY" (case-
+# sensitive) to indicate that the first active and configured
+# interface is acceptable. If unset, the user is presented with a
+# menu of all available network interfaces.
+#
+# Returns success if a valid network interface has been selected.
+#
+f_device_select_tcp()
+{
+ local devs dev cnt network_dev
+ f_getvar $VAR_NETWORK_DEVICE network_dev
+
+ f_dprintf "f_device_select_tcp: %s=[%s]" \
+ VAR_NETWORK_DEVICE "$network_dev"
+
+ if [ "$network_dev" ]; then
+ #
+ # This can be set to several types of values. If set to ANY,
+ # scan all network devices looking for a valid link, and go
+ # with the first device found. Can also be specified as a
+ # comma delimited list, with each network device tried in
+ # order. Can also be set to a single network device.
+ #
+ [ "$network_dev" = "ANY" ] && f_device_scan_tcp network_dev
+
+ while [ "$network_dev" ]; do
+ case "$network_dev" in
+ *,*) dev="${network_dev%%,*}"
+ network_dev="${network_dev#*,}"
+ ;;
+ *) dev="$network_dev"
+ network_dev=
+ esac
+
+ f_device_find "$dev" $DEVICE_TYPE_NETWORK devs
+ cnt=$( set -- $devs; echo $# )
+
+ if [ ${cnt:=0} -gt 0 ]; then
+ dev="${devs%%[$IFS]*}"
+ f_device_dialog_tcp $dev
+ if [ $? -eq $SUCCESS ]; then
+ setvar $VAR_NETWORK_DEVICE $dev
+ return $SUCCESS
+ fi
+ fi
+ done
+
+ f_interactive && f_dialog_msgbox "$msg_no_network_devices"
+ return $FAILURE
+
+ fi # $network_dev
+
+ f_device_find "" $DEVICE_TYPE_NETWORK devs
+ cnt=$( set -- $devs; echo $# )
+ dev="${devs%%[$IFS]*}"
+
+ f_quietly f_getvar NETWORK_CONFIGURED # for debugging info
+ if ! f_running_as_init &&
+ ! [ "${NETWORK_CONFIGURED+set}" -a "$NETWORK_CONFIGURED" = "NO" ]
+ then
+ trap 'f_interrupt' SIGINT
+ if f_dialog_yesno "$msg_assume_network_is_already_configured"
+ then
+ setvar $VAR_NETWORK_DEVICE $dev
+ return $SUCCESS
+ fi
+ fi
+
+ local retval=$SUCCESS
+ if [ ${cnt:=0} -eq 0 ]; then
+ f_dialog_msgbox "$msg_no_network_devices"
+ retval=$FAILURE
+ elif [ $cnt -eq 1 ]; then
+ f_device_dialog_tcp $dev
+ retval=$?
+ [ $retval -eq $SUCCESS ] && setvar $VAR_NETWORK_DEVICE $dev
+ else
+ local title="$msg_network_interface_information_required"
+ local prompt="$msg_please_select_ethernet_device_to_configure"
+ local hline="$hline_arrows_tab_enter"
+
+ dev=$( f_device_menu \
+ "$title" "$prompt" "$hline" $DEVICE_TYPE_NETWORK \
+ "$NETWORK_DEVICE_HELPFILE" \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
+ retval=$?
+ [ "$dev" ] || return $FAILURE
+
+ f_device_find "$dev" $DEVICE_TYPE_NETWORK devs
+ [ "$devs" ] || return $FAILURE
+ dev="${devs%%[$IFS]*}"
+
+ f_device_dialog_tcp $dev
+ retval=$?
+ if [ $retval -eq $SUCCESS ]; then
+ f_struct_copy device_$dev device_network
+ setvar $VAR_NETWORK_DEVICE network
+ else
+ f_struct_free device_network
+ fi
+ fi
+
+ return $retval
+}
+
+# f_dialog_menu_select_tcp
+#
+# Like f_dialog_select_tcp() above, but do it from a menu that doesn't care
+# about status. In other words, where f_dialog_select_tcp() will not display a
+# menu if scripted, this function will always display the menu of available
+# network interfaces.
+#
+f_dialog_menu_select_tcp()
+{
+ local private use_dhcp name
+ NETWORK_CONFIGURED=NO f_device_select_tcp
+ if f_struct device_network &&
+ device_network get private private &&
+ f_struct_copy "$private" di &&
+ di get use_dhcp use_dhcp &&
+ [ ! "$use_dhcp" ] &&
+ device_network get name name &&
+ f_yesno "$msg_would_you_like_to_bring_interface_up" "$name"
+ then
+ if ! f_device_init network; then
+ f_show_msg "$msg_initialization_of_device_failed" \
+ "$name"
+ fi
+ fi
+ return $SUCCESS
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/tcpip.subr
+
+fi # ! $_MEDIA_TCPIP_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/ufs.subr b/usr.sbin/bsdconfig/share/media/ufs.subr
new file mode 100644
index 0000000..0b70f09
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/ufs.subr
@@ -0,0 +1,193 @@
+if [ ! "$_MEDIA_UFS_SUBR" ]; then _MEDIA_UFS_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/ufs.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/common.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+UFS_MOUNTED=
+
+############################################################ FUNCTIONS
+
+# f_media_set_ufs
+#
+# Return success if we both found and set the media type to be a UFS partition.
+# Variables from variable.subr that can be used to script user input:
+#
+# VAR_UFS_PATH
+# Path to a UFS character device node to be used with mount(8) in
+# mounting a UFS formatted partition. Valid examples include:
+# /dev/da0s1a
+# /dev/ad4s1e
+# However, other forms may be valid (see mount(8) for additional
+# information).
+#
+f_media_set_ufs()
+{
+ local ufs
+
+ f_media_close
+
+ local devs ndevs
+ f_device_find "" $DEVICE_TYPE_UFS devs
+ ndevs=$( set -- $devs; echo $# )
+
+ if [ ${ndevs:=0} -eq 0 ]; then
+ f_variable_get_value $VAR_UFS_PATH \
+ "$msg_enter_the_device_name_of_a_ufs_formatted_partition"
+ f_getvar $VAR_UFS_PATH ufs
+ [ "$ufs" ] || return $FAILURE
+
+ local fstype
+ fstype=$( df -nT $ufs 2> /dev/null |
+ awk '!/Type/{print $2;exit}' )
+
+ f_struct_new DEVICE device_ufs
+ device_ufs set name ${fstype:-ufs}
+ device_ufs set devname "$ufs"
+ device_ufs set get f_media_get_ufs
+ device_ufs set init f_media_init_ufs
+ device_ufs set shutdown f_media_shutdown_ufs
+ device_ufs unset private
+
+ f_struct_copy device_ufs device_media
+ f_struct_free device_ufs
+ elif [ $ndevs -gt 1 ]; then
+ local title="$msg_choose_a_ufs_partition"
+ local prompt="$msg_please_select_ufs_partition"
+ local hline=""
+
+ local dev retval
+ dev=$( f_device_menu \
+ "$title" "$prompt" "$hline" $DEVICE_TYPE_UFS \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
+ retval=$?
+ [ "$dev" ] || return $FAILURE
+
+ f_struct_copy device_$dev device_media
+ [ $retval -eq $SUCCESS ] || return $FAILURE
+ else
+ f_struct_copy device_$devs device_media
+ fi
+
+ f_struct device_media || return $FAILURE
+}
+
+# f_media_init_ufs $device
+#
+# Initializes the UFS media device. Returns success if able to mount the UFS
+# partition device using mount(1).
+#
+f_media_init_ufs()
+{
+ local dev="$1" devname err
+
+ device_$dev get devname devname || return $FAILURE
+ f_dprintf "Init routine called for UFS device. devname=[%s]" \
+ "$devname"
+
+ if [ "$UFS_MOUNTED" ]; then
+ f_dprintf "UFS device already mounted."
+ return $SUCCESS
+ fi
+
+ if [ ! -e "$devname" ]; then
+ f_show_msg "$msg_no_such_file_or_directory" \
+ "f_media_init_ufs" "$devname"
+ return $FAILURE
+ fi
+
+ if [ ! -e "$MOUNTPOINT" ] &&
+ ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
+ then
+ f_dialog_msgbox "$err"
+ return $FAILURE
+ fi
+
+ if ! err=$( mount "$devname" "$MOUNTPOINT" 2>&1 )
+ then
+ err="${err#mount: }"; err="${err#$devname : }"
+ f_show_msg "$msg_error_mounting_device" \
+ "$devname" "$MOUNTPOINT" "$err"
+ return $FAILURE
+ fi
+ UFS_MOUNTED=1
+ return $SUCCESS
+}
+
+# f_media_get_ufs $device $file [$probe_only]
+#
+# Returns data from $file on a mounted UFS partition device. Similar to cat(1).
+# $probe_only is currently unused by this media type.
+#
+f_media_get_ufs()
+{
+ local dev="$1" file="$2" probe_only="$3"
+
+ f_dprintf "f_media_get_ufs: dev=[%s] file=[%s] probe_only=%s" \
+ "$dev" "$file" "$probe_only"
+
+ f_media_generic_get "$MOUNTPOINT" "$file"
+}
+
+# f_media_shutdown_ufs $device
+#
+# Shuts down the UFS device using umount(8). Return status should be ignored.
+#
+f_media_shutdown_ufs()
+{
+ local dev="$1" err
+
+ [ "$UFS_MOUNTED" ] || return
+
+ if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ err="${err#umount: }"; err="${err#*: }"
+ f_show_msg "$msg_could_not_unmount_the_ufs_partition" \
+ "$MOUNTPOINT" "$err"
+ else
+ UFS_MOUNTED=
+ fi
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/ufs.subr
+
+fi # ! $_MEDIA_UFS_SUBR
diff --git a/usr.sbin/bsdconfig/share/media/usb.subr b/usr.sbin/bsdconfig/share/media/usb.subr
new file mode 100644
index 0000000..c7fc973
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/usb.subr
@@ -0,0 +1,174 @@
+if [ ! "$_MEDIA_USB_SUBR" ]; then _MEDIA_USB_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+f_dprintf "%s: loading includes..." media/usb.subr
+f_include $BSDCFG_SHARE/struct.subr
+f_include $BSDCFG_SHARE/device.subr
+f_include $BSDCFG_SHARE/dialog.subr
+f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/common.subr
+
+BSDCFG_LIBE="/usr/libexec/bsdconfig"
+f_include_lang $BSDCFG_LIBE/include/messages.subr
+
+############################################################ GLOBALS
+
+USB_MOUNTED=
+
+############################################################ FUNCTIONS
+
+# f_media_set_usb
+#
+# Attempt to use USB as the media type. Return success if we both found and set
+# the media type to be a USB drive.
+#
+f_media_set_usb()
+{
+ f_media_close
+
+ local devs ndevs
+ f_device_find "" $DEVICE_TYPE_USB devs
+ ndevs=$( set -- $devs; echo $# )
+
+ if [ ${ndevs:=0} -eq 0 ]; then
+ f_dialog_msgbox "$msg_no_usb_devices_found"
+ return $FAILURE
+ elif [ $ndevs -gt 1 ]; then
+ local title="$msg_choose_a_usb_drive"
+ local prompt="$msg_please_select_a_usb_drive"
+ local hline=""
+
+ local dev retval
+ dev=$( f_device_menu \
+ "$title" "$prompt" "$hline" $DEVICE_TYPE_USB \
+ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD )
+ retval=$?
+ [ "$dev" ] || return $FAILURE
+
+ f_device_find "$dev" $DEVICE_TYPE_USB devs
+ [ "$devs" ] || return $FAILURE
+ dev="${devs%%[$IFS]*}"
+
+ f_struct_copy device_$dev device_media
+ [ $retval -eq $SUCCESS ] || return $FAILURE
+ else
+ f_struct_copy device_$devs device_media
+ fi
+
+ f_struct device_media &&
+ device_media unset private
+
+ if f_interactive; then
+ local name
+ f_struct device_media get name name
+ f_show_msg "$msg_using_usb_device" "$name"
+ fi
+
+ f_struct device_media || return $FAILURE
+}
+
+# f_media_init_usb $device
+#
+# Initializes the USB media device. Returns success if able to mount the USB
+# disk device using mount(8).
+#
+f_media_init_usb()
+{
+ local dev="$1" devname err
+
+ device_$dev get devname devname || return $FAILURE
+ f_dprintf "Init routine called for USB device. devname=[%s]" \
+ "$devname"
+
+ if [ "$USB_MOUNTED" ]; then
+ f_dprintf "USB device already mounted."
+ return $SUCCESS
+ fi
+
+ if [ ! -e "$MOUNTPOINT" ] &&
+ ! err=$( mkdir -p "$MOUNTPOINT" 2>&1 )
+ then
+ f_dialog_msgbox "$err"
+ return $FAILURE
+ fi
+
+ if err=$( mount "$devname" "$MOUNTPOINT" 2>&1 ); then
+ USB_MOUNTED=1
+ return $SUCCESS
+ fi
+
+ err="${err#mount: }"; err="${err#$devname: }"
+ f_show_msg "$msg_error_mounting_usb_drive" \
+ "$devname" "$MOUNTPOINT" "$err"
+ return $FAILURE
+}
+
+# f_media_get_usb $device $file [$probe_only]
+#
+# Returns data from $file on a mounted USB disk device. Similar to cat(1).
+# $probe_only is currently unused by this media type.
+#
+f_media_get_usb()
+{
+ local dev="$1" file="$2" probe_only="$3"
+
+ f_dprintf "f_media_get_usb: dev=[%s] file=[%s] probe_only=%s" \
+ "$dev" "$file" "$probe_only"
+
+ f_media_generic_get "$MOUNTPOINT" "$file"
+}
+
+# f_media_shutdown_usb $device
+#
+# Shuts down the USB disk device using umount(8). Return status should be
+# ignored.
+#
+f_media_shutdown_usb()
+{
+ local dev="$1" err
+
+ [ "$USB_MOUNTED" ] || return
+
+ if ! err=$( umount -f "$MOUNTPOINT" 2>&1 ); then
+ err="${err#umount: }"; err="${err#*: }"
+ f_show_msg "$msg_could_not_unmount_the_ufs_partition" \
+ "$MOUNTPOINT" "$err"
+ else
+ USB_MOUNTED=
+ fi
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." media/usb.subr
+
+fi # ! $_MEDIA_USB_SUBR
diff --git a/usr.sbin/bsdconfig/share/script.subr b/usr.sbin/bsdconfig/share/script.subr
index 84d1cab..3ea5dd5 100644
--- a/usr.sbin/bsdconfig/share/script.subr
+++ b/usr.sbin/bsdconfig/share/script.subr
@@ -1,6 +1,6 @@
if [ ! "$_SCRIPT_SUBR" ]; then _SCRIPT_SUBR=1
#
-# Copyright (c) 2012 Devin Teske
+# Copyright (c) 2012-2013 Devin Teske
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,10 @@ if [ ! "$_SCRIPT_SUBR" ]; then _SCRIPT_SUBR=1
BSDCFG_SHARE="/usr/share/bsdconfig"
. $BSDCFG_SHARE/common.subr || exit 1
f_dprintf "%s: loading includes..." script.subr
+f_include $BSDCFG_SHARE/device.subr
f_include $BSDCFG_SHARE/variable.subr
+f_include $BSDCFG_SHARE/media/any.subr
+f_include $BSDCFG_SHARE/media/tcpip.subr
############################################################ GLOBALS
@@ -75,11 +78,13 @@ f_dispatch()
local func="$1" resword="${2:-$1}"
f_dprintf "f_dispatch: calling resword \`%s'" "$resword"
eval $func
- local retval=$? _ignore_this_error
- f_getvar $VAR_NO_ERROR _ignore_this_error
- [ $retval -eq $SUCCESS ] ||
+ local retval=$?
+ if [ $retval -ne $SUCCESS ]; then
+ local _ignore_this_error
+ f_getvar $VAR_NO_ERROR _ignore_this_error
[ "$_ignore_this_error" ] || f_die $retval \
- "$msg_command_failed_rest_of_script_aborted" "$resword"
+ "$msg_command_failed_rest_of_script_aborted" "$resword"
+ fi
unset $VAR_NO_ERROR
}
@@ -146,8 +151,26 @@ f_script_load()
#
# Reserved words meant for scripting
#
+f_resword_new deviceRescan f_device_rescan
f_resword_new dumpVariables f_dump_variables
f_resword_new loadConfig f_script_load
+f_resword_new mediaClose f_media_close
+f_resword_new mediaGetType f_media_get_type
+f_resword_new mediaOpen f_media_open
+f_resword_new mediaSetCDROM f_media_set_cdrom
+f_resword_new mediaSetDOS f_media_set_dos
+f_resword_new mediaSetFTP f_media_set_ftp
+f_resword_new mediaSetFTPActive f_media_set_ftp_active
+f_resword_new mediaSetFTPPassive f_media_set_ftp_passive
+f_resword_new mediaSetFTPUserPass f_media_set_ftp_userpass
+f_resword_new mediaSetFloppy f_media_set_floppy
+f_resword_new mediaSetHTTP f_media_set_http_proxy
+f_resword_new mediaSetHTTPProxy f_media_set_http_proxy
+f_resword_new mediaSetNFS f_media_set_nfs
+f_resword_new mediaSetUFS f_media_set_ufs
+f_resword_new mediaSetUSB f_media_set_usb
+f_resword_new optionsEditor f_media_options_menu
+f_resword_new tcpMenuSelect f_dialog_menu_select_tcp
f_dprintf "%s: Successfully loaded." script.subr
diff --git a/usr.sbin/bsdconfig/share/strings.subr b/usr.sbin/bsdconfig/share/strings.subr
index 6fe0f32..5b9f51e 100644
--- a/usr.sbin/bsdconfig/share/strings.subr
+++ b/usr.sbin/bsdconfig/share/strings.subr
@@ -1,6 +1,6 @@
if [ ! "$_STRINGS_SUBR" ]; then _STRINGS_SUBR=1
#
-# Copyright (c) 2006-2012 Devin Teske
+# Copyright (c) 2006-2013 Devin Teske
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -101,6 +101,72 @@ f_isinteger()
( : $((0/$arg)) ) > /dev/null 2>&1
}
+# f_uriencode [$text]
+#
+# Encode $text for the purpose of embedding safely into a URL. Non-alphanumeric
+# characters are converted to `%XX' sequence where XX represents the hexa-
+# decimal ordinal of the non-alphanumeric character. If $text is missing, data
+# is instead read from standard input.
+#
+f_uriencode_awk='
+BEGIN {
+ output = ""
+ for (n = 0; n < 256; n++) pack[sprintf("%c", n)] = sprintf("%%%02x", n)
+}
+{
+ sline = ""
+ slen = length($0)
+ for (n = 1; n <= slen; n++) {
+ char = substr($0, n, 1)
+ if ( char !~ /^[[:alnum:]_]$/ ) char = pack[char]
+ sline = sline char
+ }
+ output = output ( output ? "%0a" : "" ) sline
+}
+END { print output }
+'
+f_uriencode()
+{
+ if [ $# -gt 0 ]; then
+ echo "$1" | awk "$f_uriencode_awk"
+ else
+ awk "$f_uriencode_awk"
+ fi
+}
+
+# f_uridecode [$text]
+#
+# Decode $text from a URI. Encoded characters are converted from their `%XX'
+# sequence into original unencoded ASCII sequences. If $text is missing, data
+# is instead read from standard input.
+#
+f_uridecode_awk='
+BEGIN { for (n = 0; n < 256; n++) chr[n] = sprintf("%c", n) }
+{
+ sline = ""
+ slen = length($0)
+ for (n = 1; n <= slen; n++)
+ {
+ seq = substr($0, n, 3)
+ if ( seq ~ /^%[[:xdigit:]][[:xdigit:]]$/ ) {
+ hex = substr(seq, 2, 2)
+ sline = sline chr[sprintf("%u", "0x"hex)]
+ n += 2
+ } else
+ sline = sline substr(seq, 1, 1)
+ }
+ print sline
+}
+'
+f_uridecode()
+{
+ if [ $# -gt 0 ]; then
+ echo "$1" | awk "$f_uridecode_awk"
+ else
+ awk "$f_uridecode_awk"
+ fi
+}
+
f_dprintf "%s: Successfully loaded." strings.subr
fi # ! $_STRINGS_SUBR
diff --git a/usr.sbin/bsdconfig/share/struct.subr b/usr.sbin/bsdconfig/share/struct.subr
new file mode 100644
index 0000000..3c6f90f
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/struct.subr
@@ -0,0 +1,206 @@
+if [ ! "$_STRUCT_SUBR" ]; then _STRUCT_SUBR=1
+#
+# Copyright (c) 2012-2013 Devin Teske
+# All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+############################################################ INCLUDES
+
+BSDCFG_SHARE="/usr/share/bsdconfig"
+. $BSDCFG_SHARE/common.subr || exit 1
+
+############################################################ FUNCTIONS
+
+# f_struct_define $type $member_name1 ...
+#
+# Define a new `structure' type $type made up of the properties $member_name1
+# $member_name2 and so-on. Properties are not typed and can hold any type of
+# data (including names of other structs).
+#
+# Before creating instances of a struct (using f_struct_new $type $name) you
+# should use this function to define $type.
+#
+# Both $type and member names should consist only of alpha-numeric letters or
+# the underscore.
+#
+f_struct_define()
+{
+ local type="$1"
+ [ "$type" ] || return $FAILURE
+ shift
+ setvar "_struct_typedef_$type" "$*"
+}
+
+# f_struct_new $type $name
+#
+# Create a new `structure' named $name of type $type. There are two ways to
+# access properties of a struct, but they are not equal (each method has its
+# own unique benefits, discussed below).
+#
+# The primary method of accessing (both setting and getting) properties of any
+# struct is through the f_struct() function below.
+#
+# The secondary method of accessing data is by using $name as a function.
+#
+# Both access methods are cross-platform compatible with any version of sh(1).
+# Below is an example of the primary access method:
+#
+# f_struct_new MY_STRUCT_TYPE my_struct
+# f_struct my_struct set abc 123
+# f_struct my_struct get abc # prints 123 to stdout
+# f_struct my_struct get abc abc # sets local variable $abc to 123
+#
+# Alternatively, the secondary access method (details below):
+#
+# f_struct_new MY_STRUCT_TYPE my_struct
+# my_struct set abc 123
+# my_struct get abc # prints 123 to stdout
+# my_struct get abc abc # sets local variable $abc to 123
+#
+# The secondary form should only be used if/when:
+# + You are certain that the structure already exists
+# + You want a syntax error if/when the struct does not exist
+#
+# The primary benefit to the secondary form is syntax cleanliness and read-
+# ability. If you are unsure if a given struct exists (which would cause a
+# syntax error when using this form), you can use the primary access method to
+# first test for the existence of the struct. For example:
+#
+# if f_struct my_struct; then
+# my_struct get abc # only executed if my_struct exists
+# fi
+#
+# For more information, see the f_struct() function.
+#
+f_struct_new()
+{
+ local type="$1" name="$2"
+ f_dprintf "f_struct_new: type=[%s] name=[%s]" "$type" "$name"
+ [ "$name" ] || return $FAILURE
+ setvar "_struct_type_$name" "$type" || return $FAILURE
+ # OK to use bare $name at this point
+ eval $name\(\){ f_struct $name \"\$@\"\; }
+}
+
+# f_struct $name
+# f_struct $name get $property [$var_to_set]
+# f_struct $name set $property $new_value
+# f_struct $name unset $property
+#
+# Access routine for getting, setting, unsetting, and testing properties of
+# `structures'.
+#
+# If only given $name, returns success if struct $name has been created (using
+# the f_struct_new() function above).
+#
+# For getting properties of a struct (versus setting) there are two methods of
+# access. If $var_to_set is missing or NULL, the value of the property is
+# printed to standard output for capturing in a sub-shell (which is less-
+# recommended because of performance degredation; for example, when called in a
+# loop). Returns success unless the property is unset.
+#
+# For setting properties of a struct, sets the value of $property to $new_value
+# and returns success.
+#
+# For unsetting, the underlying environment variable associated with the given
+# $property is unset.
+#
+f_struct()
+{
+ local __name="$1" __action="$2" __property="$3"
+ case $# in
+ 0) return $FAILURE ;;
+ 1) f_have $__name ;;
+ *) case "$__action" in
+ get) local __var_to_set="$4"
+ f_getvar "_struct_value_${__name}_$__property" "$__var_to_set"
+ ;;
+ set) local new_value="$4"
+ setvar "_struct_value_${__name}_$__property" "$new_value" ;;
+ unset) unset "_struct_value_${__name}_$__property" ;;
+ esac
+ esac
+ # Return the status of the last command above
+}
+
+# f_struct_free $name
+#
+# Unset the collection of environment variables and accessor-function
+# associated with struct $name.
+#
+f_struct_free()
+{
+ local name="$1" type member members
+ f_getvar "_struct_type_$name" type
+ f_dprintf "f_struct_free: name=[%s] type=[%s]" "$name" "$type"
+ [ "$name" ] || return $FAILURE
+ f_getvar "_struct_typedef_$type" members
+ for member in $members; do
+ f_struct "$name" unset $member
+ done
+ unset -f "$name"
+ unset "_struct_type_$name"
+}
+
+# f_struct_copy $from_name $to_name
+#
+# Copy the properties of one struct to another. If struct $to_name does not
+# exist, it is created. If struct $from_name does not exist, nothing is done
+# and struct $to_name remains unmodified.
+#
+# Returns success unless struct $to_name did not exist and f_struct_new() was
+# unable to create it.
+#
+f_struct_copy()
+{
+ local from_name="$1" to_name="$2" type
+ f_dprintf "f_struct_copy: from_name=[%s] to_name=[%s]" \
+ "$from_name" "$to_name"
+ f_getvar "_struct_type_$from_name" type
+ f_struct "$to_name" ||
+ f_struct_new "$type" "$to_name" || return $FAILURE
+ f_struct "$from_name" || return $SUCCESS
+ f_dprintf "f_struct_copy: copying properties from %s to %s" \
+ "$from_name" "$to_name"
+ local property properties from_value n=0 k=0
+ f_getvar "_struct_typedef_$type" properties
+ for property in $properties; do
+ k=$(( $k + 1 ))
+ if f_struct "$from_name" get $property from_value; then
+ f_struct "$to_name" set $property "$from_value"
+ n=$(( $n + 1 ))
+ else
+ f_struct "$to_name" unset $property
+ fi
+ done
+ f_dprintf "f_struct_copy: copied %u of %u properties from %s to %s" \
+ "$n" "$k" "$from_name" "$to_name"
+}
+
+############################################################ MAIN
+
+f_dprintf "%s: Successfully loaded." struct.subr
+
+fi # ! $_STRUCT_SUBR
diff --git a/usr.sbin/bsdconfig/share/variable.subr b/usr.sbin/bsdconfig/share/variable.subr
index 235f6dc..7a066421 100644
--- a/usr.sbin/bsdconfig/share/variable.subr
+++ b/usr.sbin/bsdconfig/share/variable.subr
@@ -1,6 +1,6 @@
if [ ! "$_VARIABLE_SUBR" ]; then _VARIABLE_SUBR=1
#
-# Copyright (c) 2012 Devin Teske
+# Copyright (c) 2012-2013 Devin Teske
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -109,7 +109,15 @@ f_variable_set_defaults()
#
# Initialize various user-edittable values to their defaults
#
- setvar $VAR_RELNAME "$UNAME_R"
+ setvar $VAR_EDITOR "${EDITOR:-/usr/bin/ee}"
+ setvar $VAR_FTP_STATE "passive"
+ setvar $VAR_FTP_USER "ftp"
+ setvar $VAR_HOSTNAME "$( hostname )"
+ setvar $VAR_MEDIA_TIMEOUT "300"
+ setvar $VAR_NFS_SECURE "NO"
+ setvar $VAR_NFS_TCP "NO"
+ setvar $VAR_NFS_V3 "YES"
+ setvar $VAR_RELNAME "$UNAME_R"
f_dprintf "f_variable_set_defaults: Defaults initialized."
}
@@ -158,17 +166,71 @@ f_interactive()
! f_getvar $VAR_NONINTERACTIVE value || [ ! "$value" ]
}
+# f_netinteractive()
+#
+# Has the user specifically requested the network-portion of configuration and
+# setup to be performed interactively? Returns success if the user has asked
+# for the network configuration to be done interactively even if perhaps over-
+# all non-interactive mode has been requested (by setting nonInteractive).
+#
+# Returns success if $netInteractive is set and non-NULL.
+#
+f_netinteractive()
+{
+ local value
+ f_getvar $VAR_NETINTERACTIVE value && [ "$value" ]
+}
+
############################################################ MAIN
#
# Variables that can be tweaked from config files
#
+# Handle Variable Name
f_variable_new VAR_CONFIG_FILE configFile
f_variable_new VAR_DEBUG debug
f_variable_new VAR_DEBUG_FILE debugFile
-f_variable_new VAR_NO_ERROR noError
+f_variable_new VAR_DIRECTORY_PATH _directoryPath
+f_variable_new VAR_DOMAINNAME domainname
+f_variable_new VAR_EDITOR editor
+f_variable_new VAR_EXTRAS ifconfig_
+f_variable_new VAR_FTP_DIR ftpDirectory
+f_variable_new VAR_FTP_HOST ftpHost
+f_variable_new VAR_FTP_PASS ftpPass
+f_variable_new VAR_FTP_PATH _ftpPath
+f_variable_new VAR_FTP_PORT ftpPort
+f_variable_new VAR_FTP_STATE ftpState
+f_variable_new VAR_FTP_USER ftpUser
+f_variable_new VAR_GATEWAY defaultrouter
+f_variable_new VAR_HOSTNAME hostname
+f_variable_new VAR_HTTP_FTP_MODE httpFtpMode
+f_variable_new VAR_HTTP_PROXY httpProxy
+f_variable_new VAR_HTTP_PROXY_HOST httpProxyHost
+f_variable_new VAR_HTTP_PROXY_PATH _httpProxyPath
+f_variable_new VAR_HTTP_PROXY_PORT httpProxyPort
+f_variable_new VAR_IFCONFIG ifconfig_
+f_variable_new VAR_IPADDR ipaddr
+f_variable_new VAR_IPV6ADDR ipv6addr
+f_variable_new VAR_IPV6_ENABLE ipv6_activate_all_interfaces
+f_variable_new VAR_MEDIA_TIMEOUT MEDIA_TIMEOUT
+f_variable_new VAR_MEDIA_TYPE mediaType
+f_variable_new VAR_NAMESERVER nameserver
+f_variable_new VAR_NETINTERACTIVE netInteractive
+f_variable_new VAR_NETMASK netmask
+f_variable_new VAR_NETWORK_DEVICE netDev
+f_variable_new VAR_NFS_HOST nfsHost
+f_variable_new VAR_NFS_PATH nfsPath
+f_variable_new VAR_NFS_SECURE nfs_reserved_port_only
+f_variable_new VAR_NFS_TCP nfs_use_tcp
+f_variable_new VAR_NFS_V3 nfs_use_v3
f_variable_new VAR_NONINTERACTIVE nonInteractive
+f_variable_new VAR_NO_ERROR noError
+f_variable_new VAR_NO_INET6 noInet6
f_variable_new VAR_RELNAME releaseName
+f_variable_new VAR_SLOW_ETHER slowEthernetCard
+f_variable_new VAR_TRY_DHCP tryDHCP
+f_variable_new VAR_TRY_RTSOL tryRTSOL
+f_variable_new VAR_UFS_PATH ufs
#
# Self-initialize unless requested otherwise
OpenPOWER on IntegriCloud