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