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