diff options
Diffstat (limited to 'usr.sbin/bsdconfig/share/media')
-rw-r--r-- | usr.sbin/bsdconfig/share/media/Makefile | 13 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/any.subr | 152 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/cdrom.subr | 210 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/common.subr | 109 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/directory.subr | 146 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/dos.subr | 164 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/floppy.subr | 214 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/ftp.subr | 893 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/httpproxy.subr | 433 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/network.subr | 182 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/nfs.subr | 251 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/options.subr | 308 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/tcpip.subr | 1688 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/ufs.subr | 193 | ||||
-rw-r--r-- | usr.sbin/bsdconfig/share/media/usb.subr | 174 |
15 files changed, 5130 insertions, 0 deletions
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 |