Home | History | Annotate | Line # | Download | only in miniroot
install.sub revision 1.47
      1 #!/bin/sh
      2 #	$NetBSD: install.sub,v 1.47 2019/04/04 20:51:35 christos Exp $
      3 #
      4 # Copyright (c) 1996 The NetBSD Foundation, Inc.
      5 # All rights reserved.
      6 #
      7 # This code is derived from software contributed to The NetBSD Foundation
      8 # by Jason R. Thorpe.
      9 #
     10 # Redistribution and use in source and binary forms, with or without
     11 # modification, are permitted provided that the following conditions
     12 # are met:
     13 # 1. Redistributions of source code must retain the above copyright
     14 #    notice, this list of conditions and the following disclaimer.
     15 # 2. Redistributions in binary form must reproduce the above copyright
     16 #    notice, this list of conditions and the following disclaimer in the
     17 #    documentation and/or other materials provided with the distribution.
     18 #
     19 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29 # POSSIBILITY OF SUCH DAMAGE.
     30 #
     31 
     32 #	NetBSD installation/upgrade script - common subroutines.
     33 
     34 ROOTDISK=""				# filled in below
     35 VERSION=				# filled in automatically (see list)
     36 export VERSION
     37 
     38 ALLSETS="base comp etc games man misc text"	# default install sets
     39 UPGRSETS="base comp games man misc text"	# default upgrade sets
     40 THESETS=					# one of the above
     41 
     42 local_sets_dir=""			# Path searched for sets by install_sets
     43 					# on the local filesystems
     44 
     45 # decide upon an editor
     46 if [ X$EDITOR = X ]; then
     47 	if [ -x /usr/bin/vi ]; then
     48 		EDITOR=vi
     49 	else
     50 		EDITOR=ed
     51 	fi
     52 fi
     53 
     54 getresp() {
     55 	read resp
     56 	if [ -z "$resp" ]; then
     57 		resp=$1
     58 	fi
     59 }
     60 
     61 isin() {
     62 # test the first argument against the remaining ones, return succes on a match
     63 	_a=$1; shift
     64 	while [ $# != 0 ]; do
     65 		if [ "$_a" = "$1" ]; then return 0; fi
     66 		shift
     67 	done
     68 	return 1
     69 }
     70 
     71 rmel() {
     72 # remove first argument from list formed by the remaining arguments
     73 	local	_a
     74 
     75 	_a=$1; shift
     76 	while [ $# != 0 ]; do
     77 		if [ "$_a" != "$1" ]; then
     78 			echo "$1";
     79 		fi
     80 		shift
     81 	done
     82 }
     83 
     84 cutword () {
     85 # read a line of data, return Nth element.
     86 	local _a
     87 	local _n
     88 	local _oifs
     89 
     90 	# optional field separator
     91 	_oifs="$IFS"
     92 	case "$1" in
     93 		-t?*) IFS=${1#-t}; shift;;
     94 	esac
     95 
     96 	_n=$1
     97 	read _a; set -- $_a
     98 	IFS="$_oifs"
     99 	if [ "$1" = "" ]; then return; fi
    100 	eval echo \$$_n
    101 }
    102 
    103 cutlast () {
    104 # read a line of data, return last element. Equiv. of awk '{print $NF}'.
    105 	local _a
    106 	local _oifs
    107 
    108 	# optional field separator
    109 	_oifs="$IFS"
    110 	case "$1" in
    111 		-t?*) IFS=${1#-t}; shift;;
    112 	esac
    113 
    114 	read _a; set -- $_a
    115 	IFS="$_oifs"
    116 	if [ "$1" = "" ]; then return; fi
    117 	while [ "$#" -gt 10 ]; do shift 10; done
    118 	eval echo \$$#
    119 }
    120 
    121 firstchar () {
    122 # return first character of argument
    123 	local _a
    124 	_a=$1
    125 	while [ ${#_a} != 1 ]; do
    126 		_a=${_a%?}
    127 	done
    128 	echo $_a
    129 }
    130 
    131 basename () {
    132 	local _oifs
    133 	if [ "$1" = "" ]; then return; fi
    134 	_oifs="$IFS"
    135 	IFS="/"
    136 	set -- $1
    137 	IFS="$_oifs"
    138 	while [ "$#" -gt 10 ]; do shift 10; done
    139 	eval echo \$$#
    140 }
    141 
    142 dir_has_sets() {
    143 	# return true when the directory $1 contains a set for $2...$n
    144 	local _dir
    145 	local _file
    146 
    147 	_dir=$1; shift
    148 	for _file in $*
    149 	do
    150 		if [ -f $_dir/${_file}.tar.gz ]; then
    151 			return 0
    152 		fi
    153 		# Try for stupid msdos convention
    154 		if [ -f $_dir/${_file}.tgz ]; then
    155 			return 0
    156 		fi
    157 		# Try for uncompressed files
    158 		if [ -f $_dir/${_file}.tar ]; then
    159 			return 0
    160 		fi
    161 		# Try for split files
    162 		if [ -f $_dir/${_file}${VERSION}.aa ]; then
    163 			return 0
    164 		fi
    165 	done
    166 	return 1
    167 }
    168 
    169 twiddle() {
    170 # spin the propeller so we don't get bored
    171 	while : ; do  
    172 		sleep 1; echo -n "/";
    173 		sleep 1; echo -n "-";
    174 		sleep 1; echo -n "\\";
    175 		sleep 1; echo -n "|";
    176 	done > /dev/tty & echo $!
    177 }
    178 
    179 get_localdir() {
    180 	# $1 is relative mountpoint
    181 	local _mp
    182 	local _dir
    183 
    184 	_mp=$1
    185 	_dir=
    186 	while : ; do
    187 	    if [ X$_mp != X ]; then
    188 		cat << __get_localdir_1
    189 Note: your filesystems are mounted under the temporary mount point \"$_mp\".
    190 The pathname you are requested to enter below should NOT include the \"$_mp\"
    191 prefix.
    192 __get_localdir_1
    193 	    fi
    194 	    echo -n "Enter the pathname where the sets are stored [$_dir] "
    195 	    getresp "$_dir"
    196 	    _dir=$resp
    197 
    198 	    # Allow break-out with empty response
    199 	    if [ -z "$_dir" ]; then
    200 		echo -n "Are you sure you don't want to set the pathname? [n] "
    201 		getresp "n"
    202 		case "$resp" in
    203 			y*|Y*)
    204 				break
    205 				;;
    206 			*)
    207 				continue
    208 				;;
    209 		esac
    210 	    fi
    211 
    212 	    if dir_has_sets "$_mp/$_dir" $THESETS
    213 	    then
    214 		local_sets_dir="$_mp/$_dir"
    215 		break
    216 	    else
    217 		cat << __get_localdir_2
    218 The directory \"$_mp/$_dir\" does not exist, or does not hold any of the
    219 upgrade sets.
    220 __get_localdir_2
    221 		echo -n "Re-enter pathname? [y] "
    222 		getresp "y"
    223 		case "$resp" in
    224 			y*|Y*)
    225 				;;
    226 			*)
    227 				local_sets_dir=""
    228 				break
    229 				;;
    230 		esac
    231 	    fi
    232 	done
    233 }
    234 
    235 getrootdisk() {
    236 	cat << \__getrootdisk_1
    237 
    238 The installation program needs to know which disk to consider
    239 the root disk.  Note the unit number may be different than
    240 the unit number you used in the standalone installation
    241 program.
    242 
    243 Available disks are:
    244 
    245 __getrootdisk_1
    246 	_DKDEVS=$(md_get_diskdevs)
    247 	echo	"$_DKDEVS"
    248 	echo	""
    249 	echo -n	"Which disk is the root disk? "
    250 	getresp ""
    251 	if isin $resp $_DKDEVS ; then
    252 		ROOTDISK="$resp"
    253 	else
    254 		echo ""
    255 		echo "The disk $resp does not exist."
    256 		ROOTDISK=""
    257 	fi
    258 }
    259 
    260 labelmoredisks() {
    261 	cat << \__labelmoredisks_1
    262 
    263 You may label the following disks:
    264 
    265 __labelmoredisks_1
    266 	echo "$_DKDEVS"
    267 	echo	""
    268 	echo -n	"Label which disk? [done] "
    269 	getresp "done"
    270 	case "$resp" in
    271 		"done")
    272 			;;
    273 
    274 		*)
    275 			if isin $resp $_DKDEVS ; then
    276 				md_labeldisk $resp
    277 			else
    278 				echo ""
    279 				echo "The disk $resp does not exist."
    280 			fi
    281 			;;
    282 	esac
    283 }
    284 
    285 addhostent() {
    286 	# $1 - IP address
    287 	# $2 - symbolic name
    288 
    289 	local fqdn
    290 
    291 	# Create an entry in the hosts table.  If no host table
    292 	# exists, create one.  If the IP address already exists,
    293 	# replace its entry.
    294 	if [ ! -f /tmp/hosts ]; then
    295 		echo "127.0.0.1 localhost" > /tmp/hosts
    296 	fi
    297 
    298 	sed "/^$1 /d" < /tmp/hosts > /tmp/hosts.new
    299 	mv /tmp/hosts.new /tmp/hosts
    300 
    301 	if [ X${FQDN} != X ]; then
    302 		fqdn=$2.$FQDN
    303 	fi
    304 	echo "$1 $2 $fqdn" >> /tmp/hosts
    305 }
    306 
    307 addifconfig() {
    308 	# $1 - interface name
    309 	# $2 - interface symbolic name
    310 	# $3 - interface IP address
    311 	# $4 - interface netmask
    312 	# $5 - (optional) interface link-layer medium, preceded by "media ", else ""
    313 	# $6 - (optional) interface link-layer directives
    314 	local _m
    315 
    316 	# Create a ifconfig.* file for the interface.
    317 	echo "inet $2 netmask $4 $5 $6" > /tmp/ifconfig.$1
    318 
    319 	addhostent $3 $2
    320 }
    321 
    322 configurenetwork() {
    323 	local _ifsdone
    324 	local _ifs
    325 
    326 #	_IFS=$(md_get_ifdevs)
    327 	_IFS=$(ifconfig -l | sed '
    328 		s/lo0//
    329 		s/ppp[0-9]//g
    330 		s/sl[0-9]//g
    331 		s/tun[0-9]//g')
    332 
    333 	_ifsdone=""
    334 	resp=""		# force at least one iteration
    335 	while [ "${resp}" != "done" ]; do
    336 	cat << \__configurenetwork_1
    337 
    338 You may configure the following network interfaces (the interfaces
    339 marked with [X] have been successfully configured):
    340 
    341 __configurenetwork_1
    342 
    343 		for _ifs in $_IFS; do
    344 			if isin $_ifs $_ifsdone ; then
    345 				echo -n "[X] "
    346 			else
    347 				echo -n "    "
    348 			fi
    349 			echo $_ifs
    350 		done
    351 		echo	""
    352 		echo -n	"Configure which interface? [done] "
    353 		getresp "done"
    354 		case "$resp" in
    355 		"done")
    356 			;;
    357 		*)
    358 			_ifs=$resp
    359 			if isin $_ifs $_IFS ; then
    360 				if configure_ifs $_ifs ; then
    361 					_ifsdone="$_ifs $_ifsdone"
    362 				fi
    363 			else
    364 				echo "Invalid response: \"$resp\" is not in list"
    365 			fi
    366 			;;
    367 		esac
    368 	done
    369 }
    370 
    371 configure_ifs() {
    372 
    373 	local _up
    374 	local _interface_name
    375 	local _interface_ip
    376 	local _interface_mask
    377 	local _interface_symname
    378 	local _interface_extra
    379 	local _interface_mediumtype
    380 	local _interface_supported_media
    381 	local _m
    382 	local _t
    383 
    384 	_interface_name=$1
    385 	_up=DOWN
    386 	if isin $_interface_name $(ifconfig -l -u); then
    387 		_up=UP
    388 	fi
    389 
    390 	_interface_supported_media=$(ifconfig -m $_interface_name | sed -n '
    391 		/^[ 	]*media autoselect/d
    392 		4,$s/[ 	]*media //p')
    393 
    394 	# get current "media" "ip" and "netmask" ("broadcast")
    395 	_t=$(ifconfig $_interface_name | sed -n '
    396 		s/^[ 	]*media: [^ 	]* \([^ ][^ ]*\).*/\1/p')
    397 
    398 	if [ "$_t" != "manual" ] && [ "$_t" != "media:" ] && [ "$_t" != "autoselect" ];
    399 	then
    400 		_interface_mediumtype=$1
    401 	fi
    402 
    403 	set -- $(ifconfig $_interface_name | sed -n '
    404 		/^[ 	]*inet/{
    405 		s/inet//
    406 		s/--> [0-9.][0-9.]*//
    407 		s/netmask//
    408 		s/broadcast//
    409 		p;}')
    410 
    411 	_interface_ip=$1
    412 	_interface_mask=$2
    413 
    414 	# Get IP address
    415 	resp=""		# force one iteration
    416 	while [ -z "${resp}" ]; do
    417 		echo -n "IP address? [$_interface_ip] "
    418 		getresp "$_interface_ip"
    419 		_interface_ip=$resp
    420 	done
    421 
    422 	# Get symbolic name
    423 	resp=""		# force one iteration
    424 	while [ -z "${resp}" ]; do
    425 		echo -n "Symbolic (host) name? "
    426 		getresp ""
    427 		_interface_symname=$resp
    428 	done
    429 
    430 	# Get netmask
    431 	resp=""		# force one iteration
    432 	while [ -n "${resp}" ]; do
    433 		echo -n "Netmask? [$_interface_mask] "
    434 		getresp "$_interface_mask"
    435 		_interface_mask=$resp
    436 	done
    437 
    438 	echo "Your network interface might require explicit selection"
    439 	echo "of the type of network medium attached. Supported media:"
    440 	echo "$_interface_supported_media"
    441 	echo -n "Additional media type arguments (none)? [$_interface_mediumtype] "
    442 	getresp "$_interface_mediumtype"
    443 	_m=""
    444 	if [ "${resp:-none}" != "none" ]; then
    445 		_interface_mediumtype=$resp
    446 		_m="media ${resp}"
    447 	fi
    448 
    449 
    450 	echo "Your network interface might require additional link-layer"
    451 	echo "directives (like 'link0'). If this is the case you can enter"
    452 	echo "these at the next prompt."
    453 	echo ""
    454 	echo -n "Additional link-layer arguments (none)? [$_interface_extra] "
    455 	getresp "$_interface_extra"
    456 	if [ "${resp:-none}" != "none" ]; then
    457 		_interface_extra=$resp
    458 	fi
    459 
    460 	# Configure the interface.  If it
    461 	# succeeds, add it to the permanent
    462 	# network configuration info.
    463 	if [ $_up != "UP" ]; then
    464 		ifconfig ${_interface_name} down
    465 		if ifconfig ${_interface_name} inet \
    466 		    ${_interface_ip} \
    467 		    netmask ${_interface_mask} \
    468 		    ${_interface_extra} ${_m} up ; then
    469 			addifconfig \
    470 			    "${_interface_name}" \
    471 			    "${_interface_symname}" \
    472 			    "${_interface_ip}" \
    473 			    "${_interface_mask}" \
    474 			    "${_m}" \
    475 			    "${_interface_extra}"
    476 			return 0
    477 		fi
    478 	else
    479 		echo "Interface ${_interface_name} is already active."
    480 		echo "Just saving configuration on new root filesystem."
    481 		addifconfig \
    482 		    "${_interface_name}" \
    483 		    "${_interface_symname}" \
    484 		    "${_interface_ip}" \
    485 		    "${_interface_mask}" \
    486 		    "${_m}" \
    487 		    "${_interface_extra}"
    488 	fi
    489 	return 1
    490 }
    491 
    492 # Much of this is gratuitously stolen from /etc/rc.d/network.
    493 enable_network() {
    494 
    495 	# Set up the hostname.
    496 	if [ -f /mnt/etc/myname ]; then
    497 		hostname=$(cat /mnt/etc/myname)
    498 	elif [ -f /mnt/etc/rc.conf ];then
    499 		hostname=$(sh -c '. /mnt/etc/rc.conf ; echo $hostname')
    500 	else
    501 		echo "ERROR: no /etc/myname!"
    502 		return 1
    503 	fi
    504 	if [ -z "$hostname" ];then
    505 		echo "ERROR: hostname not set in /etc/myname or /etc/rc.conf!"
    506 		return 1
    507 	fi
    508 	hostname $hostname
    509 
    510 	# configure all the interfaces which we know about.
    511 if [ -f /mnt/etc/rc.conf ]; then
    512 (
    513 	# assume network interface configuration style 1.2D and up
    514 	if [ -f /mnt/etc/defaults/rc.conf ]; then
    515 		. /mnt/etc/defaults/rc.conf
    516 	fi
    517 	. /mnt/etc/rc.conf
    518 
    519 	if [ "$net_interfaces" != NO ]; then
    520 		if [ "$auto_ifconfig" = YES ]; then
    521 			tmp="$(ifconfig -l)"
    522 		else
    523 			tmp="$net_interfaces"
    524 		fi
    525 		echo -n "configuring network interfaces:"
    526 		for i in $tmp; do
    527 			eval $(echo 'args=$ifconfig_'$i)
    528 			if [ ! -z "$args" ]; then
    529 				echo -n " $i"
    530 				ifconfig $i $args
    531 			elif [ -f /mnt/etc/ifconfig.$i ]; then
    532 				echo -n " $i"
    533 				(while read args; do
    534 					ifconfig $i $args
    535 				done) < /mnt/etc/ifconfig.$i
    536 			elif [ "$auto_ifconfig" != YES ]; then
    537 				echo
    538 				echo -n "/mnt/etc/ifconfig.$i missing"
    539 				echo -n "& ifconfig_$i not set"
    540 				echo "; interface $i can't be configured"
    541 			fi
    542 		done
    543 		echo "."
    544 	fi
    545 )
    546 else
    547 (
    548 	tmp="$IFS"
    549 	IFS="$IFS."
    550 	set -- $(echo /mnt/etc/hostname*)
    551 	IFS=$tmp
    552 	unset tmp
    553 
    554 	while [ $# -ge 2 ] ; do
    555 		shift		# get rid of "hostname"
    556 		(
    557 			read af name mask bcaddr extras
    558 			read dt dtaddr
    559 
    560 			if [ ! -n "$name" ]; then
    561 		    echo "/etc/hostname.$1: invalid network configuration file"
    562 				exit
    563 			fi
    564 
    565 			cmd="ifconfig $1 $af $name "
    566 			if [ "${dt}" = "dest" ]; then cmd="$cmd $dtaddr"; fi
    567 			if [ -n "$mask" ]; then cmd="$cmd netmask $mask"; fi
    568 			if [ "${bcaddr:-NONE}" != "NONE" ]; then
    569 				cmd="$cmd broadcast $bcaddr";
    570 			fi
    571 			cmd="$cmd $extras"
    572 
    573 			$cmd
    574 		) < /mnt/etc/hostname.$1
    575 		shift
    576 	done
    577 )
    578 fi
    579 
    580 	# set the address for the loopback interface
    581 	ifconfig lo0 inet localhost
    582 
    583 	# use loopback, not the wire
    584 	route add $hostname localhost
    585 
    586 	# /etc/mygate, if it exists, contains the name of my gateway host
    587 	# that name must be in /etc/hosts.
    588 	if [ -f /mnt/etc/mygate ]; then
    589 		route delete default > /dev/null 2>&1
    590 		route add default $(cat /mnt/etc/mygate)
    591 	fi
    592 
    593 	# enable the resolver, if appropriate.
    594 	if [ -f /mnt/etc/resolv.conf ]; then
    595 		_resolver_enabled="TRUE"
    596 		cp /mnt/etc/resolv.conf /tmp/resolv.conf.shadow
    597 	fi
    598 
    599 	# Display results...
    600 	echo	"Network interface configuration:"
    601 	ifconfig -a
    602 
    603 	echo	""
    604 
    605 	if [ "${_resolver_enabled:-FALSE}" = "TRUE" ]; then
    606 		netstat -r
    607 		echo	""
    608 		echo	"Resolver enabled."
    609 	else
    610 		netstat -rn
    611 		echo	""
    612 		echo	"Resolver not enabled."
    613 	fi
    614 
    615 	return 0
    616 }
    617 
    618 install_ftp() {
    619 	local	_f
    620 	local	_sets
    621 	local	_next
    622 
    623 	# Build a script to extract valid files from a list
    624 	# of filenames on stdin.
    625 	# XXX : Can we use this on more places? Leo.
    626 
    627 	echo "#!/bin/sh" > /tmp/fname_filter.sh
    628 	echo "while read line; do"	>> /tmp/fname_filter.sh
    629 	echo "    case \$line in"	>> /tmp/fname_filter.sh
    630 	for _f in $THESETS; do
    631 		echo "    $_f.tar.gz|$_f.tgz|$_f.tar|$_f.${VERSION}.aa)" \
    632 					>> /tmp/fname_filter.sh
    633 		echo '        echo -n "$line ";;' \
    634 					>> /tmp/fname_filter.sh
    635 	done
    636 	echo "        *) ;;"		>> /tmp/fname_filter.sh
    637 	echo "    esac"			>> /tmp/fname_filter.sh
    638 	echo "done"			>> /tmp/fname_filter.sh
    639 
    640 	# Get several parameters from the user, and create
    641 	# a shell script that directs the appropriate
    642 	# commands into ftp.
    643 	cat << \__install_ftp_1
    644 
    645 This is an automated ftp-based installation process.  You will be asked
    646 several questions.  The correct set of commands will be placed in a script
    647 that will be fed to ftp(1).
    648 
    649 __install_ftp_1
    650 	# Get server IP address
    651 	resp=""		# force one iteration
    652 	while [ -z "${resp}" ]; do
    653 		echo -n "Server IP? [${_ftp_server_ip}] "
    654 		getresp "${_ftp_server_ip}"
    655 		_ftp_server_ip=$resp
    656 	done
    657 
    658 	# Get login name
    659 	resp=""		# force one iteration
    660 	while [ -z "${resp}" ]; do
    661 		echo -n "Login? [${_ftp_server_login}] "
    662 		getresp "${_ftp_server_login}"
    663 		_ftp_server_login=$resp 
    664 	done
    665 
    666 	# Get password
    667 	resp=""		# force one iteration
    668 	while [ -z "${resp}" ]; do
    669 		echo -n "Password? "
    670 		stty -echo
    671 		getresp ""
    672 		echo ""
    673 		stty echo
    674 		_ftp_server_password=$resp
    675 	done
    676 
    677 	cat << \__install_ftp_2
    678 
    679 You will be asked to enter the name of the directory that contains the
    680 installation sets. When you enter a '?' you will see a listing of the
    681 current directory on the server.
    682 __install_ftp_2
    683 	_sets=""
    684 	while [ -z "$_sets" ]
    685 	do
    686 		resp=""		# force one iteration
    687 		while [ -z "${resp}" ]; do
    688 			echo -n "Server directory? [${_ftp_server_dir}] "
    689 		    getresp "${_ftp_server_dir}"
    690 		    if [ -z "$resp" ] && [ -z "$_ftp_server_dir" ]; then
    691 			resp=""
    692 		    fi
    693 		done
    694 		if [ $resp != '?' ]; then
    695 			_ftp_server_dir=$resp
    696 		fi
    697 
    698 		# Build the basics of an ftp-script...
    699 		echo "#!/bin/sh" > /tmp/ftp-script.sh
    700 		echo "cd /mnt" >> /tmp/ftp-script.sh
    701 		echo "ftp -e -i -n $_ftp_server_ip << \__end_commands" >> \
    702 		    /tmp/ftp-script.sh
    703 		echo "user $_ftp_server_login $_ftp_server_password" >> \
    704 		    /tmp/ftp-script.sh
    705 		echo "bin" >> /tmp/ftp-script.sh
    706 		echo "cd $_ftp_server_dir" >> /tmp/ftp-script.sh
    707 
    708 		# Make a copy of this script that lists the directory
    709 		# contents, and use that to determine the files to get.
    710 		cat /tmp/ftp-script.sh	>  /tmp/ftp-dir.sh
    711 		echo "nlist"		>> /tmp/ftp-dir.sh
    712 		echo "quit"		>> /tmp/ftp-dir.sh
    713 		echo "__end_commands"	>> /tmp/ftp-dir.sh
    714 
    715 		if [ $resp = '?' ]; then
    716 			sh /tmp/ftp-dir.sh
    717 		else
    718 			_sets=$(sh /tmp/ftp-dir.sh | sh /tmp/fname_filter.sh)
    719 		fi
    720 	done
    721 	rm -f /tmp/ftp-dir.sh /tmp/fname_filter.sh
    722 
    723 	while : ; do
    724 		echo "The following sets are available for extraction:"
    725 		echo "(marked sets are already on the extraction list)"
    726 		echo ""
    727 
    728 		_next=""
    729 		for _f in $_sets ; do
    730 			if isin $_f $_setsdone; then
    731 				echo -n "[X] "
    732 				_next=""
    733 			else
    734 				echo -n "    "
    735 				if [ -z "$_next" ]; then _next=$_f; fi
    736 			fi
    737 			echo $_f
    738 		done
    739 		echo ""
    740 
    741 		# Get name of the file and add extraction command
    742 		# to the ftp-script.
    743 		if [ -z "$_next" ]; then resp=n; else resp=y; fi
    744 		echo -n "Continue to add filenames [$resp]? "
    745 		getresp "$resp"
    746 		if [ "$resp" = "n" ]; then
    747 			break
    748 		fi
    749 
    750 		echo -n "File name [$_next]? "
    751 		getresp "$_next"
    752 		if isin $resp $_sets; then
    753 			echo "get $resp |\"pax -zr${verbose_flag}pe\"" >> \
    754 					/tmp/ftp-script.sh
    755 			_setsdone="$resp $_setsdone"
    756 		else
    757 			echo "You entered an invalid filename."
    758 			echo ""
    759 		fi
    760 	done
    761 
    762 	echo "quit" >> /tmp/ftp-script.sh
    763 	echo "__end_commands" >> /tmp/ftp-script.sh
    764 
    765 	sh /tmp/ftp-script.sh
    766 	rm -f /tmp/ftp-script.sh
    767 	echo "Extraction complete."
    768 }
    769 
    770 install_from_mounted_fs() {
    771 	# $1 - directory containing installation sets
    772 	local _filename
    773 	local _sets
    774 	local _next
    775 	local _all
    776 	local _f
    777 	local _dirname
    778 
    779 	_dirname=$1
    780 	_sets=""
    781 
    782 	if ! dir_has_sets ${_dirname} $THESETS
    783 	then
    784 
    785 		echo ""
    786 		echo "The directory at the mount point, \"${_dirname}\", contains: "
    787 		echo ""
    788 		ls -F ${_dirname}
    789 		echo ""
    790 		echo    "Enter the subdirectory relative to the mountpoint, that"
    791 		echo -n "contains the savesets: [try this directory] "
    792 		getresp ""
    793 		if [ -n "${resp}" ]; then
    794 			_dirname=${_dirname}/$resp
    795 		fi
    796 
    797 		while ! dir_has_sets ${_dirname} $THESETS; do
    798 			echo ""
    799 			echo -n "There are no NetBSD install sets available in "
    800 			echo "\"${_dirname}\"."
    801 			echo "\"${_dirname}\" contains: "
    802 			echo ""
    803 			ls -F ${_dirname}
    804 			echo ""
    805 			echo -n "Enter subdirectory: [try other install media] "
    806 			getresp ""
    807 			if [ -z "${resp}" ]; then
    808 				return
    809 			fi
    810 			if [ ! -d ${_dirname}/${resp} ]; then
    811 				echo "\"${resp}\" is no directory; try again."
    812 			else
    813 				_dirname=${_dirname}/$resp
    814 			fi
    815 		done
    816 	fi
    817 
    818 	for _f in $THESETS ; do
    819 		if [ -f ${_dirname}/${_f}.tar.gz ]; then
    820 			_sets="$_sets ${_f}.tar.gz"
    821 		elif [ -f ${_dirname}/${_f}.tgz ]; then
    822 			_sets="$_sets ${_f}.tgz"
    823 		elif [ -f ${_dirname}/${_f}.tar ]; then
    824 			_sets="$_sets ${_f}.tar"
    825 		elif [ -f ${_dirname}/${_f}${VERSION}.aa ]; then
    826 			_sets="$_sets ${_f}${VERSION}"
    827 		fi
    828 	done
    829 
    830 	while : ; do
    831 		echo "The following sets are available for extraction:"
    832 		echo "(marked sets have already been extracted)"
    833 		echo ""
    834 
    835 		_next=""
    836 		_all=""
    837 		for _f in $_sets ; do
    838 			if isin $_f $_setsdone; then
    839 				echo -n "[X] "
    840 				_next=""
    841 			else
    842 				echo -n "    "
    843 				if [ -z "$_next" ]; then
    844 					_next=$_f;
    845 				fi
    846 				_all="$_all $_f"
    847 			fi
    848 			echo $_f
    849 		done
    850 		echo ""
    851 
    852 		# Get the name of the file.
    853 		if [ -z "$_next" ]; then
    854 			resp=n
    855 		else
    856 			resp=y
    857 		fi
    858 		echo -n "Continue extraction [$resp]?"
    859 		getresp "$resp"
    860 		if [ "$resp" = "n" ]; then
    861 			break
    862 		fi
    863 
    864 		echo -n "File name(s) (or "all") [$_next]? "
    865 		getresp "$_next"
    866 		if [ "x$resp" = xall ]; then
    867 			resp="$_all"
    868 		fi
    869 
    870 		for _f in $resp; do
    871 			_filename="/${_dirname}/$_f"
    872 
    873 			# Ensure file exists
    874 			if [ ! -f $_filename ]; then
    875 				if [ -f ${_filename}.aa ]; then
    876 					_filename=${_filename}.\?\?
    877 				else
    878 			 echo "File $_filename does not exist.  Check to make"
    879 			 echo "sure you entered the information properly."
    880 			 continue 2
    881 				fi
    882 			fi
    883 
    884 			# Extract file
    885 			echo "Extracting the $_f set:"
    886 			case "$_filename" in
    887 			*.tar)
    888 				(cd /mnt; pax -r${verbose_flag}pe < $_filename)
    889 				;;
    890 			*)
    891 				cat $_filename | \
    892 					(cd /mnt; pax -zr${verbose_flag}pe)
    893 				;;
    894 			esac
    895 			echo "Extraction complete."
    896 			_setsdone="$_f $_setsdone"
    897 		done
    898 
    899 	done
    900 }
    901 
    902 install_cdrom() {
    903 	local _drive
    904 	local _partition_range
    905 	local _partition
    906 	local _fstype
    907 	local _directory
    908 
    909 	# Get the cdrom device info
    910 	cat << \__install_cdrom_1
    911 
    912 The following CD-ROM devices are installed on your system; please select
    913 the CD-ROM device containing the partition with the installation sets:
    914 
    915 __install_cdrom_1
    916 	_CDDEVS=$(md_get_cddevs)
    917 	echo    "$_CDDEVS"
    918 	echo	""
    919 	echo -n	"Which is the CD-ROM with the installation media? [abort] "
    920 	getresp "abort"
    921 	case "$resp" in
    922 		abort)
    923 			echo "Aborting."
    924 			return
    925 			;;
    926 
    927 		*)
    928 			if isin $resp $_CDDEVS ; then
    929 				_drive=$resp
    930 			else
    931 				echo ""
    932 				echo "The CD-ROM $resp does not exist."
    933 				echo "Aborting."
    934 				return
    935 			fi
    936 			;;
    937 	esac
    938 
    939 	# Get partition
    940 	_partition_range=$(md_get_partition_range)
    941 	resp=""		# force one iteration
    942 	while [ -z "${resp}" ]; do
    943 		echo -n "Partition? [a] "
    944 		getresp "a"
    945 		case "$resp" in
    946 			$_partition_range)
    947 				_partition=$resp
    948 				;;
    949 
    950 			*)
    951 				echo "Invalid response: $resp"
    952 				resp=""		# force loop to repeat
    953 				;;
    954 		esac
    955 	done
    956 
    957 	# Ask for filesystem type
    958 	cat << \__install_cdrom_2
    959 
    960 There are two CD-ROM filesystem types currently supported by this program:
    961 	1) ISO-9660 (cd9660)
    962 	2) Berkeley Fast Filesystem (ffs)
    963 
    964 __install_cdrom_2
    965 	resp=""		# force one iteration
    966 	while [ -z "${resp}" ]; do
    967 		echo -n "Which filesystem type? [cd9660] "
    968 		getresp "cd9660"
    969 		case "$resp" in
    970 			cd9660|ffs)
    971 				_fstype=$resp
    972 				;;
    973 
    974 			*)
    975 				echo "Invalid response: $resp"
    976 				resp=""		# force loop to repeat
    977 				;;
    978 		esac
    979 	done
    980 
    981 	# Mount the CD-ROM
    982 	if ! mount -t ${_fstype} -o ro \
    983 	    /dev/${_drive}${_partition} /mnt2 ; then
    984 		echo "Cannot mount CD-ROM drive.  Aborting."
    985 		return
    986 	fi
    987 
    988 	install_from_mounted_fs /mnt2
    989 	umount -f /mnt2 > /dev/null 2>&1
    990 }
    991 
    992 mount_a_disk() {
    993 	# Mount a disk on /mnt2. The set of disk devices to choose from
    994 	# is $_DKDEVS.
    995 	# returns 0 on failure.
    996 
    997 	local _drive
    998 	local _partition_range
    999 	local _partition
   1000 	local _fstype
   1001 	local _fsopts
   1002 	local _directory
   1003 	local _md_fstype
   1004 	local _md_fsopts
   1005 
   1006 	getresp "abort"
   1007 	case "$resp" in
   1008 		abort)
   1009 			echo "Aborting."
   1010 			return 0
   1011 			;;
   1012 
   1013 		*)
   1014 			if isin $resp $_DKDEVS ; then
   1015 				_drive=$resp
   1016 			else
   1017 				echo ""
   1018 				echo "The disk $resp does not exist."
   1019 				echo "Aborting."
   1020 				return 0
   1021 			fi
   1022 			;;
   1023 	esac
   1024 
   1025 	# Get partition
   1026 	_partition_range=$(md_get_partition_range)
   1027 	resp=""		# force one iteration
   1028 	while [ -z "${resp}" ]; do
   1029 		echo -n "Partition? [d] "
   1030 		getresp "d"
   1031 		case "$resp" in
   1032 			$_partition_range)
   1033 				_partition=$resp
   1034 				;;
   1035 
   1036 			*)
   1037 				echo "Invalid response: $resp"
   1038 				resp=""		# force loop to repeat
   1039 				;;
   1040 		esac
   1041 	done
   1042 
   1043 	# Ask for filesystem type
   1044 	cat << \__mount_a_disk_2
   1045 
   1046 The following filesystem types are supported:
   1047 	1) ffs
   1048 	2) cd9660
   1049 __mount_a_disk_2
   1050 	_md_fstype=$(md_native_fstype)
   1051 	_md_fsopts=$(md_native_fsopts)
   1052 	if [ ! -z "$_md_fstype" ]; then
   1053 		echo "	3) $_md_fstype"
   1054 	else
   1055 		_md_fstype="_undefined_"
   1056 	fi
   1057 	resp=""		# force one iteration
   1058 	while [ -z "${resp}" ]; do
   1059 		echo -n "Which filesystem type? [ffs] "
   1060 		getresp "ffs"
   1061 		case "$resp" in
   1062 			ffs|cd9660)
   1063 				_fstype=$resp
   1064 				_fsopts="ro"
   1065 				;;
   1066 			$_md_fstype)
   1067 				_fstype=$resp
   1068 				_fsopts=$_md_fsopts
   1069 				;;
   1070 			*)
   1071 				echo "Invalid response: $resp"
   1072 				resp=""		# force loop to repeat
   1073 				;;
   1074 		esac
   1075 	done
   1076 
   1077 	# Mount the disk
   1078 	if ! mount -t ${_fstype} -o $_fsopts \
   1079 	    /dev/${_drive}${_partition} /mnt2 ; then
   1080 		echo "Cannot mount disk.  Aborting."
   1081 		return 0
   1082 	fi
   1083 	return 1
   1084 }
   1085 
   1086 install_disk() {
   1087 	local _directory
   1088 
   1089 	cat << \__install_disk_1
   1090 
   1091 Ok, lets install from a disk.  The file-system the install sets on may
   1092 already mounted, or we might have to mount the filesystem to get to it.
   1093 
   1094 __install_disk_1
   1095 
   1096 	echo -n "Is the file-system with the install sets already mounted? [n] "
   1097 	getresp "n"
   1098 	case $resp in
   1099 	y*|Y*)
   1100 		echo "What mount point are the sets located in? [] "
   1101 		getresp ""
   1102 		if [ -d "$resp" ]; then
   1103 			install_from_mounted_fs $resp
   1104 		else
   1105 			echo "$resp: Not a directory, aborting..."
   1106 		fi
   1107 		return
   1108 		;;
   1109 	*)
   1110 		;;
   1111 	esac
   1112 
   1113 	cat << \__install_disk_2
   1114 
   1115 The following disk devices are installed on your system; please select
   1116 the disk device containing the partition with the installation sets:
   1117 
   1118 __install_disk_2
   1119 	_DKDEVS=$(md_get_diskdevs)
   1120 	echo    "$_DKDEVS"
   1121 	echo	""
   1122 	echo -n	"Which is the disk with the installation sets? [abort] "
   1123 
   1124 	if mount_a_disk ; then
   1125 		return
   1126 	fi
   1127 
   1128 	install_from_mounted_fs /mnt2
   1129 	umount -f /mnt2 > /dev/null 2>&1
   1130 }
   1131 
   1132 install_nfs() {
   1133 	# Get the IP address of the server
   1134 	resp=""		# force one iteration
   1135 	while [ -z "${resp}" ]; do
   1136 		echo -n "Server IP address? [${_nfs_server_ip}] "
   1137 		getresp "${_nfs_server_ip}"
   1138 	done
   1139 	_nfs_server_ip=$resp
   1140 
   1141 	# Get server path to mount
   1142 	resp=""		# force one iteration
   1143 	while [ -z "${resp}" ]; do
   1144 		echo -n "Filesystem on server to mount? [${_nfs_server_path}] "
   1145 		getresp "${_nfs_server_path}"
   1146 	done
   1147 	_nfs_server_path=$resp
   1148 
   1149 	# Determine use of TCP
   1150 	echo -n "Use TCP transport (only works with capable NFS server)? [n] "
   1151 	getresp "n"
   1152 	case "$resp" in
   1153 		y*|Y*)
   1154 			_nfs_tcp="-T"
   1155 			;;
   1156 
   1157 		*)
   1158 			echo -n "Use small NFS transfers (needed when server "
   1159 			echo "or client"
   1160 			echo -n "has a slow network card)? [n] "
   1161 			getresp "n"
   1162 			case "$resp" in
   1163 			y*|Y*)
   1164 				_nfs_tcp="-r 1024 -w 1024"
   1165 				;;
   1166 
   1167 			*)
   1168 				_nfs_tcp=""
   1169 				;;
   1170 			esac
   1171 			;;
   1172 	esac
   1173 
   1174 	# Mount the server
   1175 	mkdir /mnt2 > /dev/null 2>&1
   1176 	if ! mount_nfs $_nfs_tcp ${_nfs_server_ip}:${_nfs_server_path} \
   1177 	    /mnt2 ; then
   1178 		echo "Cannot mount NFS server.  Aborting."
   1179 		return
   1180 	fi
   1181 
   1182 	install_from_mounted_fs /mnt2
   1183 	umount -f /mnt2 > /dev/null 2>&1
   1184 }
   1185 
   1186 install_tape() {
   1187 	local _xcmd
   1188 
   1189 	# Get the name of the tape from the user.
   1190 	cat << \__install_tape_1
   1191 
   1192 The installation program needs to know which tape device to use.  Make
   1193 sure you use a "no rewind on close" device.
   1194 
   1195 __install_tape_1
   1196 	_tape=$(basename $TAPE)
   1197 	resp=""		# force one iteration
   1198 	while [ -z "${resp}" ]; do
   1199 		echo -n "Name of tape device? [${_tape}]"
   1200 		getresp "${_tape}"
   1201 	done
   1202 	_tape=$(basename $resp)
   1203 	TAPE="/dev/${_tape}"
   1204 	if [ ! -c $TAPE ]; then
   1205 		echo "$TAPE does not exist or is not a character special file."
   1206 		echo "Aborting."
   1207 		return
   1208 	fi
   1209 	export TAPE
   1210 
   1211 	# Rewind the tape device
   1212 	echo -n "Rewinding tape..."
   1213 	if ! mt rewind ; then
   1214 		echo "$TAPE may not be attached to the system or may not be"
   1215 		echo "a tape device.  Aborting."
   1216 		return
   1217 	fi
   1218 	echo "done."
   1219 
   1220 	# Get the file number
   1221 	resp=""		# force one iteration
   1222 	while [ -z "${resp}" ]; do
   1223 		echo -n "File number? "
   1224 		getresp ""
   1225 		case "$resp" in
   1226 			[1-9]*)
   1227 				_nskip=$(expr $resp - 1)
   1228 				;;
   1229 
   1230 			*)
   1231 				echo "Invalid file number ${resp}."
   1232 				resp=""		# fore loop to repeat
   1233 				;;
   1234 		esac
   1235 	done
   1236 
   1237 	# Skip to correct file.
   1238 	echo -n "Skipping to source file..."
   1239 	if [ "${_nskip}" != "0" ]; then
   1240 		if ! mt fsf $_nskip ; then
   1241 			echo "Could not skip $_nskip files.  Aborting."
   1242 			return
   1243 		fi
   1244 	fi
   1245 	echo "done."
   1246 
   1247 	cat << \__install_tape_2
   1248 
   1249 There are 2 different ways the file can be stored on tape:
   1250 
   1251 	1) an image of a gzipped tar file
   1252 	2) a standard tar image
   1253 
   1254 __install_tape_2
   1255 	resp=""		# force one iteration
   1256 	while [ -z "${resp}" ]; do
   1257 		echo -n "Which way is it? [1] "
   1258 		getresp "1"
   1259 		case "$resp" in
   1260 		1)
   1261 			_xcmd="pax -zr${verbose_flag}pe"
   1262 			;;
   1263 
   1264 		2)
   1265 			_xcmd="pax -r${verbose_flag}pe"
   1266 			;;
   1267 
   1268 		*)
   1269 			echo "Invalid response: $resp."
   1270 			resp=""		# force loop to repeat
   1271 			;;
   1272 		esac
   1273 		( cd /mnt; dd if=$TAPE | $_xcmd )
   1274 	done
   1275 	echo "Extraction complete."
   1276 }
   1277 
   1278 get_timezone() {
   1279 	local _a
   1280 	local _zonepath
   1281 
   1282 	#
   1283 	# If the zoneinfo is not on the installation medium or on the
   1284 	# installed filesystem, set TZ to GMT and return immediatly.
   1285 	#
   1286 	if [ ! -e /usr/share/zoneinfo ] && [ ! -e /mnt/usr/share/zoneinfo ]; then
   1287 		TZ=GMT
   1288 		return
   1289 	fi
   1290 	if [ ! -d /usr/share/zoneinfo ]; then
   1291 		_zonepath=/mnt
   1292 	else
   1293 		_zonepath=""
   1294 	fi
   1295 		
   1296 cat << \__get_timezone_1
   1297 
   1298 Select a time zone for your location. Timezones are represented on the
   1299 system by a directory structure rooted in "/usr/share/zoneinfo". Most
   1300 timezones can be selected by entering a token like "MET" or "GMT-6".
   1301 Other zones are grouped by continent, with detailed zone information
   1302 separated by a slash ("/"), e.g. "US/Pacific".
   1303 
   1304 To get a listing of what's available in /usr/share/zoneinfo, enter "?"
   1305 at the prompts below.
   1306 
   1307 __get_timezone_1
   1308 	if [ X$TZ = X ]; then
   1309 		TZ=$(ls -l /mnt/etc/localtime 2>/dev/null | cutlast)
   1310 		TZ=${TZ#/usr/share/zoneinfo/}
   1311 	fi
   1312 	while :; do
   1313 		echo -n	"What timezone are you in ['?' for list] [$TZ]? "
   1314 		getresp "$TZ"
   1315 		case "$resp" in
   1316 		"")
   1317 			echo "Timezone defaults to GMT"
   1318 			TZ="GMT"
   1319 			break;
   1320 			;;
   1321 		"?")
   1322 			ls ${_zonepath}/usr/share/zoneinfo
   1323 			;;
   1324 		*)
   1325 			_a=$resp
   1326 			while [ -d ${_zonepath}/usr/share/zoneinfo/$_a ]; do
   1327 				echo -n "There are several timezones available"
   1328 				echo " within zone '$_a'"
   1329 				echo -n "Select a sub-timezone ['?' for list]: "
   1330 				getresp ""
   1331 				case "$resp" in
   1332 				"?") ls ${_zonepath}/usr/share/zoneinfo/$_a ;;
   1333 				*)	_a=${_a}/${resp}
   1334 					if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then
   1335 						break;
   1336 					fi
   1337 					;;
   1338 				esac
   1339 			done
   1340 			if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then
   1341 				TZ="$_a"
   1342 				echo "You have selected timezone \"$_a\"".
   1343 				break 2
   1344 			fi
   1345 			echo "'/usr/share/zoneinfo/$_a' is not a valid timezone on this system."
   1346 			;;
   1347 		esac
   1348 	done
   1349 }
   1350 
   1351 install_sets()
   1352 {
   1353 	local _yup
   1354 	_yup="FALSE"
   1355 
   1356 	# Ask the user which media to load the distribution from.
   1357 	# Ask the user if they want verbose extraction.  They might not want
   1358 	# it on, eg, SPARC frame buffer console.
   1359 	cat << \__install_sets_1
   1360 
   1361 It is now time to extract the installation sets onto the hard disk.
   1362 Make sure the sets are either on a local device (i.e. tape, CD-ROM) or on a
   1363 network server.
   1364 
   1365 Would you like to see each file listed during extraction (verbose) mode?
   1366 On some console hardware, such as serial consoles and Sun frame buffers,
   1367 this can extend the total extraction time.
   1368 __install_sets_1
   1369 	echo -n "Use verbose listing for extractions? [y] "
   1370 	getresp "y"
   1371 	case "$resp" in
   1372 	y*|Y*)
   1373 		verbose_flag=v
   1374 		;;
   1375 	*)
   1376 		echo "Not using verbose listing."
   1377 		verbose_flag=""
   1378 		;;
   1379 	esac
   1380 
   1381 	if [ -d ${Default_sets_dir:-/dev/null} ]; then
   1382 		if dir_has_sets $Default_sets_dir $THESETS; then
   1383 			local_sets_dir=$Default_sets_dir
   1384 		fi
   1385 	fi
   1386 	if [ -n "${local_sets_dir}" ]; then
   1387 		install_from_mounted_fs ${local_sets_dir}
   1388 		if [ X"$_setsdone" != X ]; then
   1389 			_yup="TRUE"
   1390 		fi
   1391 	fi
   1392 
   1393 	# Go on prodding for alternate locations
   1394 	resp=""		# force at least one iteration
   1395 	while [ X"${resp}" = X ]; do
   1396 		# If _yup is not FALSE, it means that we extracted sets above.
   1397 		# If that's the case, bypass the menu the first time.
   1398 		if [ X"$_yup" = X"FALSE" ]; then
   1399 			echo -n	"Install from (f)tp, (t)ape, (C)D-ROM, (N)FS"
   1400 			echo -n " or local (d)isk? "
   1401 			getresp ""
   1402 			case "$resp" in
   1403 			d*|D*)
   1404 				install_disk
   1405 				;;
   1406 			f*|F*)
   1407 				install_ftp
   1408 				;;
   1409 			t*|T*)
   1410 				install_tape
   1411 				;;
   1412 			c*|C*)
   1413 				install_cdrom
   1414 				;;
   1415 			n*|N*)
   1416 				install_nfs
   1417 				;;
   1418 			*)
   1419 				echo "Invalid response: $resp"
   1420 				resp=""
   1421 				;;
   1422 			esac
   1423 		else
   1424 			_yup="FALSE"	# So we'll ask next time
   1425 		fi
   1426 
   1427 		# Give the user the opportunity to extract more sets. They
   1428 		# don't necessarily have to come from the same media.
   1429 		echo	""
   1430 		echo -n	"Extract more sets? [n] "
   1431 		getresp "n"
   1432 		case "$resp" in
   1433 		y*|Y*)
   1434 			# Force loop to repeat
   1435 			resp=""
   1436 			;;
   1437 
   1438 		*)
   1439 			;;
   1440 		esac
   1441 	done
   1442 }
   1443 
   1444 munge_fstab()
   1445 {
   1446 	local _fstab
   1447 	local _fstab_shadow
   1448 	local _dev
   1449 	local _mp
   1450 	local _fstype
   1451 	local _rest
   1452 
   1453 	# Now that the 'real' fstab is configured, we munge it into a 'shadow'
   1454 	# fstab which we'll use for mounting and unmounting all of the target
   1455 	# filesystems relative to /mnt.  Mount all filesystems.
   1456 	_fstab=$1
   1457 	_fstab_shadow=$2
   1458 	( while read _dev _mp _fstype _rest; do
   1459 		# Skip comment lines
   1460 		case "$_dev" in
   1461 			\#*)	continue;;
   1462 			*)	;;
   1463 		esac
   1464 		# and some filesystem types (like there are swap,kernfs,...)
   1465 		case "$_fstype" in
   1466 			ffs|ufs|nfs)	;;
   1467 			*)	continue;;
   1468 		esac
   1469 		if [ "$_mp" = "/" ]; then
   1470 			echo $_dev /mnt $_fstype $_rest
   1471 		else
   1472 			echo $_dev /mnt$_mp $_fstype $_rest
   1473 		fi
   1474 	    done ) < $_fstab > $_fstab_shadow
   1475 }
   1476 
   1477 mount_fs()
   1478 {
   1479 	# Must mount filesystems manually, one at a time, so we can make
   1480 	# sure the mount points exist.
   1481 	# $1 is a file in fstab format
   1482 	local _fstab
   1483 
   1484 	_fstab=$1
   1485 
   1486 	( while read line; do
   1487 		set -- $line
   1488 		_dev=$1
   1489 		_mp=$2
   1490 		_fstype=$3
   1491 		_opt=$4
   1492 
   1493 		# If not the root filesystem, make sure the mount
   1494 		# point is present.
   1495 		if [ "$_mp" != "/mnt" ]; then
   1496 			mkdir -p $_mp
   1497 		fi
   1498 
   1499 		# Mount the filesystem.  If the mount fails, exit
   1500 		# with an error condition to tell the outer
   1501 		# later to bail.
   1502 		if ! mount -v -t $_fstype -o async -o $_opt $_dev $_mp ; then
   1503 			# error message displated by mount
   1504 			exit 1
   1505 		fi
   1506 	done ) < $_fstab
   1507 
   1508 	if [ "$?" != "0" ]; then
   1509 		cat << \__mount_filesystems_1
   1510 
   1511 FATAL ERROR:  Cannot mount filesystems.  Double-check your configuration
   1512 and restart the installation process.
   1513 __mount_filesystems_1
   1514 		exit
   1515 	fi
   1516 }
   1517 
   1518 unmount_fs()
   1519 {
   1520 	# Unmount all filesystems and check their integrity.
   1521 	# Usage: [-fast] <fstab file>
   1522 	local _fast
   1523 	local _fstab
   1524 	local _pid
   1525 
   1526 	if [ "$1" = "-fast" ]; then
   1527 		_fast=1
   1528 		_fstab=$2
   1529 	else
   1530 		_fast=0
   1531 		_fstab=$1
   1532 	fi
   1533 
   1534 	if [ ! \( -f $_fstab -a -s $_fstab \) ]; then
   1535 		echo "fstab empty" > /dev/tty
   1536 		return
   1537 	fi
   1538 
   1539 	if [ $_fast = 0 ]; then
   1540 		echo -n	"Syncing disks..."
   1541 		_pid=$(twiddle)
   1542 		sync; sleep 4; sync; sleep 2; sync; sleep 2
   1543 		kill $_pid
   1544 		echo	"done."
   1545 	fi
   1546 
   1547 	(
   1548 		_devs=""
   1549 		_mps=""
   1550 		# maintain reverse order
   1551 		while read line; do
   1552 			set -- $line
   1553 			_devs="$1 ${_devs}"
   1554 			_mps="$2 ${_mps}"
   1555 		done
   1556 		echo -n "Umounting filesystems... "
   1557 		for _mp in ${_mps}; do
   1558 			echo -n "${_mp} "
   1559 			umount ${_mp}
   1560 		done
   1561 		echo "Done."
   1562 
   1563 		if [ $_fast = 0 ]; then
   1564 			exit
   1565 		fi
   1566 		echo "Checking filesystem integrity..."
   1567 		for _dev in ${_devs}; do
   1568 			echo  "${_dev}"
   1569 			fsck -f ${_dev}
   1570 		done
   1571 		echo "Done."
   1572 	) < $_fstab
   1573 }
   1574 
   1575 check_fs()
   1576 {
   1577 	# Check filesystem integrity.
   1578 	# $1 is a file in fstab format
   1579 	local _fstab
   1580 
   1581 	_fstab=$1
   1582 
   1583 	(
   1584 		_devs=""
   1585 		_mps=""
   1586 		while read line; do
   1587 			set -- $line
   1588 			_devs="$1 ${_devs}"
   1589 			_mps="$2 ${_mps}"
   1590 		done
   1591 
   1592 		echo "Checking filesystem integrity..."
   1593 		for _dev in ${_devs}; do
   1594 			echo  "${_dev}"
   1595 			fsck -f ${_dev}
   1596 		done
   1597 		echo "Done."
   1598 	) < $_fstab
   1599 }
   1600