xref: /openbsd/distrib/miniroot/install.sub (revision d485f761)
1#!/bin/sh
2#	$OpenBSD: install.sub,v 1.171 2001/10/31 01:33:24 krw Exp $
3#	$NetBSD: install.sub,v 1.5.2.8 1996/09/02 23:25:02 pk Exp $
4#
5# Copyright (c) 1997,1998 Todd Miller, Theo de Raadt
6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16# 3. All advertising materials mentioning features or use of this software
17#    must display the following acknowledgement:
18#	This product includes software developed by Todd Miller and
19#	Theo de Raadt
20# 4. The name of the author may not be used to endorse or promote products
21#    derived from this software without specific prior written permission.
22#
23# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33#
34# Copyright (c) 1996 The NetBSD Foundation, Inc.
35# All rights reserved.
36#
37# This code is derived from software contributed to The NetBSD Foundation
38# by Jason R. Thorpe.
39#
40# Redistribution and use in source and binary forms, with or without
41# modification, are permitted provided that the following conditions
42# are met:
43# 1. Redistributions of source code must retain the above copyright
44#    notice, this list of conditions and the following disclaimer.
45# 2. Redistributions in binary form must reproduce the above copyright
46#    notice, this list of conditions and the following disclaimer in the
47#    documentation and/or other materials provided with the distribution.
48# 3. All advertising materials mentioning features or use of this software
49#    must display the following acknowledgement:
50#        This product includes software developed by the NetBSD
51#        Foundation, Inc. and its contributors.
52# 4. Neither the name of The NetBSD Foundation nor the names of its
53#    contributors may be used to endorse or promote products derived
54#    from this software without specific prior written permission.
55#
56# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
57# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
58# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
59# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
60# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
61# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
62# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
63# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
64# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
65# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66# POSSIBILITY OF SUCH DAMAGE.
67#
68
69#	OpenBSD installation/upgrade script - common subroutines.
70
71ROOTDISK=				# filled in below
72VERSION=30
73VERSION_MAJOR=$(( $VERSION / 10 ))
74VERSION_MINOR=$(( $VERSION % 10 ))
75export VERSION VERSION_MAJOR VERSION_MINOR
76
77# extra "site" set can be provided by person doing install
78ALLSETS="base etc misc comp man game xbase xshare xfont xserv site"	# install
79UPGRSETS="base misc comp man game xbase xshare xfont xserv site"	# upgrade
80SNAPSETS="bin dev etc games man misc sbin \
81	  usr.bin usr.binutils usr.games usr.include \
82	  usr.lib usr.libexec usr.misc usr.sbin usr.share var"
83THESETS=					# one of the above
84
85# Path searched for sets by install_sets on the local filesystems
86local_sets_dir=
87
88# decide upon an editor
89if [ "X$EDITOR" = X ]; then
90	if [ -x /usr/bin/vi ]; then
91		EDITOR=vi
92	else
93		EDITOR=ed
94	fi
95	export EDITOR
96fi
97
98# Please don't use the 1 of n form below, good idea, wrong implementation!
99# get a reponse with default[s]
100getresp() {
101	local _shell_aware=0
102	local _no_shell=0
103
104	# -s option means exit after a shell (caller is shell-aware)
105	if [ "$1" = "-s" ]; then
106		_shell_aware=1
107		shift
108	fi
109	# -n option means don't try to run shell commands
110	if [ "$1" = "-n" ]; then
111		_no_shell=1
112		shift
113	fi
114
115	set -o noglob
116	valid="false"
117	while [ "X$valid" = "Xfalse" ]; do
118		read resp
119		if [ ${_no_shell} -eq 1 ]; then
120			test -z "$resp" && resp=$1
121		else
122			case "$resp" in
123				"")	resp=$1
124					;;
125				!)	echo "Type 'exit' to return to install."
126					sh
127					test $_shell_aware -eq 0 && continue
128					;;
129				!*)
130					eval ${resp#?}
131					test $_shell_aware -eq 0 && continue
132					;;
133			esac
134		fi
135		if [ $# -gt 1 ]; then
136			for i in $@; do
137				if [ "X$resp" = "X$i" ]; then
138					valid="true"
139				fi
140			done
141		else
142			valid="true"
143		fi
144		if [ "X$valid" = "Xfalse" ]; then
145			echo "Try again: Enter one of [$@]"
146		fi
147	done
148	set +o noglob
149}
150
151isin() {
152# test the first argument against the remaining ones, return succes on a match
153	local	_a=$1
154
155	shift
156	while [ $# != 0 ]; do
157		if [ "$_a" = "$1" ]; then return 0; fi
158		shift
159	done
160	return 1
161}
162
163addel() {
164# add first argument to list formed by the remaining arguments
165# adds to the tail if the element does not already exist
166	local	_a=$1 _seen=
167
168	shift
169	while [ $# != 0 ]; do
170		echo "$1"
171		if [ "$_a" = "$1" ]; then
172			_seen="yes"
173		fi
174		shift
175	done
176	if [ "X$_seen" = "X" ]; then
177		echo "$_a"
178	fi
179}
180
181rmel() {
182# remove first argument from list formed by the remaining arguments
183	local	_a=$1
184
185	shift
186	while [ $# != 0 ]; do
187		if [ "$_a" != "$1" ]; then
188			echo "$1"
189		fi
190		shift
191	done
192}
193
194cutword () {
195# read lines on stdin, return Nth element of each line, like cut(1)
196	local _a _n _oifs="$IFS"
197
198	# optional field separator
199	case "$1" in
200		-t?*) IFS=${1#-t}; shift;;
201	esac
202
203	_n=$1
204	while read _a; do
205		set -- $_a
206		test "$1" = "" && break
207		eval echo \$$_n
208	done
209	IFS="$_oifs"
210}
211
212cutlast () {
213# read a line of data, return last element. Equiv. of awk '{print $NF}'.
214	local _a _oifs="$IFS"
215
216	# optional field separator
217	case "$1" in
218		-t?*) IFS=${1#-t}; shift;;
219	esac
220
221	read _a; set -- $_a
222	IFS="$_oifs"
223	if [ "$1" = "" ]; then return; fi
224	while [ "$#" -gt 10 ]; do shift 10; done
225	eval echo \$$#
226}
227
228firstchar () {
229# return first character of argument
230	local _a=$1
231
232	while [ ${#_a} != 1 ]; do
233		_a=${_a%?}
234	done
235	echo $_a
236}
237
238basename () {
239	local _oifs
240
241	if [ "$1" = "" ]; then return; fi
242	_oifs="$IFS"
243	IFS="/"
244	set -- $1
245	IFS="$_oifs"
246	while [ "$#" -gt 10 ]; do shift 10; done
247	eval echo \$$#
248}
249
250isnumeric() {
251	local _a=$1
252
253	while [ ${#_a} != 0 ]; do
254		case $_a in
255			[0-9]*) ;;
256			*)	echo 0; return;;
257		esac
258		_a=${_a#?}
259	done
260	echo 1; return
261}
262
263get_ifdevs() {
264	# return available network devices
265	/sbin/ifconfig -a | egrep -v '^([[:space:]]|(lo|enc|gre|ppp|sl|tun|bridge)[[:digit:]])' | cutword -t: 1
266}
267
268bsort() {
269	local _l _a=$1
270
271	if [ $# == 0 ]; then
272		return
273	fi
274
275	if [ $# == 1 ]; then
276		echo $1; return
277	fi
278
279	shift
280	while [ $# != 0 ]; do
281		local _b=$1
282		if [[ "$_a" != "$_b" ]] ; then
283			if [[ "$_a" > "$_b" ]] ; then
284				_l="$_a $_l"; _a=$_b
285			else
286				_l="$_b $_l"
287			fi
288		fi
289		shift
290	done
291
292	echo -n "$_a "; bsort $_l
293}
294
295dir_has_sets() {
296	# return true when the directory $1 contains a set for $2...$n
297	local _dir=$1 _file
298
299	shift
300	for _file in $*
301	do
302		if [ -f $_dir/${_file}${VERSION}.tar.gz ]; then
303			return 0
304		fi
305		# Try for stupid msdos convention
306		if [ -f $_dir/${_file}${VERSION}.tgz ]; then
307			return 0
308		fi
309		# Special check for kernel
310		if [ $_file = "kernel" -a -f $_dir/bsd ]; then
311			return 0
312		fi
313	done
314	return 1
315}
316
317list_has_sets() {
318	# return true when the list $1 contains a set, given dir $2 for $3...$n
319	local _list=$1 _file
320
321	shift
322	for _file in $*
323	do
324		if isin ${_file}${VERSION}.tar.gz $_list; then
325			return 0
326		fi
327		# Try for stupid msdos convention
328		if isin ${_file}${VERSION}.tgz $_list; then
329			return 0
330		fi
331		# Special check for kernel
332		if test $_file = "kernel" && isin bsd $_list; then
333			return 0
334		fi
335	done
336	return 1
337}
338
339ftp_list_files() {
340	# log in via ftp to host $1 as user $2 with password $3
341	# and return a list of all files in the directory $4 on stdout
342	local _host=$1 _user=$2 _pass=$3 _dir=$4
343
344	shift; shift; shift; shift
345
346	ftp ${_ftp_active} -V -n $_host  << __ptf
347user $_user $_pass
348cd $_dir
349ls
350quit
351__ptf
352}
353
354get_localdir() {
355	# $1 is relative mountpoint
356	local _mp=$1 _dir=
357
358	while : ; do
359	    echo -n "Enter the pathname where the sets are stored [$_dir] "
360	    getresp "$_dir"
361	    _dir=$resp
362
363	    # Allow break-out with empty response
364	    if [ -z "$_dir" ]; then
365		echo -n "Are you sure you don't want to set the pathname? [n] "
366		getresp "n"
367		case "$resp" in
368			y*|Y*)
369				break
370				;;
371			*)
372				continue
373				;;
374		esac
375	    fi
376
377	    if dir_has_sets "$_mp/$_dir" $THESETS
378	    then
379		local_sets_dir="$_mp/$_dir"
380		break
381	    else
382		cat << __EOT
383The directory \"$local_sets_dir\" does not exist, or does not hold any of the
384upgrade sets.
385__EOT
386		echo -n "Re-enter pathname? [y] "
387		getresp "y"
388		case "$resp" in
389			y*|Y*)
390				;;
391			*)
392				local_sets_dir=
393				break
394				;;
395		esac
396	    fi
397	done
398}
399
400getanotherdisk() {
401	cat << __EOT
402
403Now you can select another disk to initialize.  (Do not re-select a disk
404you have already entered information for).  Available disks are:
405
406__EOT
407	_DKDEVS=`md_get_diskdevs`
408	echo	"$_DKDEVS"
409	echo
410	echo -n	"Which one? [done] "
411	getresp ""
412	if [ "X${resp}" = "X" ]; then
413		DISK=done
414	elif [ "X${resp}" = "Xdone" ]; then
415		DISK=done
416	elif isin $resp $_DKDEVS ; then
417		DISK="$resp"
418	else
419		echo
420		echo "The disk $resp does not exist."
421		DISK=
422	fi
423}
424
425getrootdisk() {
426	cat << __EOT
427
428The installation program needs to know which disk to consider the root disk.
429Note the unit number may be different than the unit number you used in the
430boot program (especially on a PC with multiple disk controllers).
431Available disks are:
432
433__EOT
434	local _defdsk;
435
436	_DKDEVS=`md_get_diskdevs`
437	_defdsk=`echo $_DKDEVS | cutlast`
438	if [ "${_defdsk}" != "${_DKDEVS}" ]; then
439		_defdsk=
440	fi
441	echo	"$_DKDEVS"
442	echo
443	echo -n "Which disk is the root disk? [${_defdsk}] "
444	getresp "${_defdsk}"
445	if isin $resp $_DKDEVS ; then
446		ROOTDISK="$resp"
447	else
448		echo
449		echo "The disk $resp does not exist."
450		ROOTDISK=
451	fi
452}
453
454addhostent() {
455	# $1 - IP address
456	# $2 - symbolic name
457
458	# Create an entry in the hosts table.  If no host table
459	# exists, create one.  If the symbolic name already exists,
460	# replace its entry.
461	if [ ! -f /tmp/hosts ]; then
462		echo "127.0.0.1 localhost" > /tmp/hosts
463	fi
464
465	sed "/ $2.$FQDN $2\$/d" < /tmp/hosts > /tmp/hosts.new
466	mv /tmp/hosts.new /tmp/hosts
467
468	echo "$1 $2.$FQDN $2" >> /tmp/hosts
469}
470
471addifconfig() {
472	# $1 - interface name
473	# $2 - interface symbolic name
474	# $3 - interface IP address
475	# $4 - interface netmask
476	# $5 - (optional) interface media directives
477
478	# Create a hostname.* file for the interface.
479	if [ "$3" = "dhcp" ]; then
480		echo "dhcp NONE NONE NONE $5" > /tmp/hostname.$1
481		addhostent 127.0.0.1 $2
482	else
483		echo "inet $3 $4 NONE $5" > /tmp/hostname.$1
484		addhostent $3 $2
485	fi
486}
487
488configurenetwork() {
489	local _ifsdone= _ifs _ouranswer= _reprompt=1
490
491	_IFS=`get_ifdevs`
492	resp=		# force at least one iteration
493	while [ "X${resp}" != X"done" ]; do
494		if [ $_reprompt = 1 ]; then
495			cat << __EOT
496
497You may configure the following network interfaces (the interfaces
498marked with [X] have been successfully configured):
499
500__EOT
501
502			for _ifs in $_IFS; do
503				if [ "X${_ouranswer}" = "X" ]; then
504					_ouranswer=$_ifs
505				fi
506				if isin $_ifs $_ifsdone ; then
507					echo -n "	[X] "
508				else
509					echo -n "	[ ] "
510				fi
511				echo $_ifs
512			done
513			echo
514		fi
515		echo -n	"Configure which interface? (or, enter 'done') [$_ouranswer] "
516		getresp "$_ouranswer"
517		case "$resp" in
518		"done")
519			;;
520		"")
521			_reprompt=0
522			;;
523		*)
524			_ifs=$resp
525			_ouranswer="done"
526			if isin $_ifs $_IFS ; then
527				if configure_ifs $_ifs ; then
528					_ifsdone="$_ifs $_ifsdone"
529				else
530				_ouranswer=
531				fi
532			else
533				echo "Invalid response: \"$resp\" is not in list"
534			fi
535			_reprompt=1
536			;;
537		esac
538
539	done
540}
541
542configure_ifs() {
543	local _up _if_name=$1 _if_ip _if_mask
544	local _if_symname _if_extra _hostname
545	local _dhcp_prompt
546
547	set -- `ifconfig $_if_name | sed -n '
548		1s/.*<UP,.*$/UP/p
549		1s/.*<.*>*$/DOWN/p
550		/media:/s/^.*$//
551		/status:/s/^.*$//
552		/inet/s/--> [0-9.][0-9.]*//
553		/inet/s/netmask//
554		/inet/s/broadcast//
555		/inet/s/inet// p'`
556
557	_up=$1
558	_if_ip=$2
559	_if_mask=$3
560
561	if [ $_up = "UP" ]; then
562		ifconfig $_if_name delete down
563	fi
564
565	if [ ! -x /sbin/dhclient ]; then
566		echo "DHCP install not supported"
567		echo
568	else
569		_dhcp_prompt=" (or 'dhcp')"
570	fi
571
572	# Get IP address
573	resp=		# force one iteration
574	while [ "X${resp}" = X"" ]; do
575		echo -n "IP address${_dhcp_prompt} ? [$_if_ip] "
576		getresp "$_if_ip"
577		if [ ! -x /sbin/dhclient -a "X$resp" == "Xdhcp" ]; then
578			resp=
579		fi
580		_if_ip=$resp
581	done
582
583	# Get symbolic name
584	_hostname=`hostname`
585	resp=		# force one iteration
586	while [ "X${resp}" = X"" ]; do
587		echo -n "Symbolic (host) name? [$_hostname] "
588		getresp "$_hostname"
589		_if_symname=$resp
590	done
591
592	# Get netmask
593	if [ "$_if_ip" != "dhcp" ]; then
594		resp=
595		if [ "X${_if_mask}" = X"" ]; then
596			_if_mask=255.255.255.0
597		fi
598		while [ "X${resp}" = X"" ]; do
599			echo -n "Netmask ? [$_if_mask] "
600			getresp "$_if_mask"
601			_if_mask=$resp
602		done
603	fi
604
605	if [ -n "`ifconfig -m ${_if_name} | sed -n '/media/p'`" ]; then
606		echo "Your use of the network interface may require non-default"
607		echo "media directives.  The default media is:"
608		ifconfig -m ${_if_name} | sed -n '
609			/supported/D
610			/media:/p'
611		echo "This is a list of supported media:"
612		ifconfig -m ${_if_name} | sed -n '
613			/media:/D
614			s/^	//
615			/media/p'
616		echo "If the default is not satisfactory, and you wish to use another"
617		echo "media, copy that line from above (e.g. \"media 100baseTX\")"
618		echo -n "Media directives? [$_if_extra] "
619		getresp "$_if_extra"
620		if [ "X${resp}" != X"" ]; then
621			_if_extra=$resp
622		fi
623	fi
624
625	# Configure the interface.  If it
626	# succeeds, add it to the permanent
627	# network configuration info.
628	if [ "$_if_ip" = "dhcp" ]; then
629		ifconfig ${_if_name} down ${_if_extra}
630cat > /etc/dhclient.conf << __EOT
631initial-interval 1;
632send host-name "$_hostname";
633request subnet-mask, broadcast-address, routers,
634       domain-name, domain-name-servers, host-name;
635__EOT
636		dhclient -1 ${_if_name}
637
638		set -- `ifconfig $_if_name | sed -n '
639			1s/.*<UP,.*$/UP/p
640			1s/.*<.*>*$/DOWN/p
641			/media:/s/^.*$//
642			/status:/s/^.*$//
643			/inet/s/--> [0-9.][0-9.]*//
644			/inet/s/netmask//
645			/inet/s/broadcast//
646			/inet/s/inet// p'`
647
648		if [ $1 = "UP" -a $2 = "0.0.0.0" ]; then
649			echo "hostname-associated DHCP attempt for $_if_name failed..."
650			ifconfig $_if_name delete down
651
652			cat > /etc/dhclient.conf << __EOT
653initial-interval 1;
654request subnet-mask, broadcast-address, routers,
655       domain-name, domain-name-servers, host-name;
656__EOT
657			dhclient -1 ${_if_name}
658			set -- `ifconfig $_if_name | sed -n '
659				1s/.*<UP,.*$/UP/p
660				1s/.*<.*>*$/DOWN/p
661				/media:/s/^.*$//
662				/status:/s/^.*$//
663				/inet/s/--> [0-9.][0-9.]*//
664				/inet/s/netmask//
665				/inet/s/broadcast//
666				/inet/s/inet// p'`
667
668			if [ $1 = "UP" -a $2 = "0.0.0.0" ]; then
669				echo "free-roaming DHCP attempt for $_if_name failed."
670				ifconfig $_if_name delete down
671				return 1
672			else
673				echo "DHCP attempt for $_if_name successful."
674				addifconfig ${_if_name} ${_if_symname} ${_if_ip}
675				return 0
676			fi
677		else
678			echo "DHCP configuration of $_if_name successful."
679			addifconfig ${_if_name} ${_if_symname} ${_if_ip}
680			return 0
681		fi
682	else
683		ifconfig ${_if_name} down
684		if ifconfig ${_if_name} inet \
685		    ${_if_ip} \
686		    netmask ${_if_mask} ${_if_extra} up ; then
687			addifconfig ${_if_name} ${_if_symname} ${_if_ip} ${_if_mask} "${_if_extra}"
688			return 0
689		fi
690	fi
691	return 1
692}
693
694# Returns true if $1 contains only alphanumerics
695isalphanumeric() {
696	local _n
697	_n=$1
698	while [ ${#_n} != 0 ]; do
699		case $_n in
700			[A-Za-z0-9]*)	;;
701			*)		return 1;;
702		esac
703		_n=${_n#?}
704	done
705	return 0
706}
707
708# Much of this is gratuitously stolen from /etc/netstart.
709enable_network() {
710	# Check for required network related files
711	for _netfile in hosts myname; do
712		if [ ! -f /mnt/etc/${_netfile} ]; then
713			echo "ERROR: no /mnt/etc/${_netfile}!"
714			return 1
715		fi
716	done
717
718	# Copy any required or optional files found
719	for _netfile in hosts myname dhclient.conf resolv.conf resolv.conf.tail; do
720		if [ -f /mnt/etc/${_netfile} ]; then
721			cp /mnt/etc/${_netfile} /etc/${_netfile}
722		fi
723	done
724
725	hostname=`cat /etc/myname`
726	hostname $hostname
727
728	_didnet=1
729
730	# set the address for the loopback interface
731	ifconfig lo0 inet localhost
732
733	# use loopback, not the wire
734	route -n add -host $hostname localhost > /dev/null
735	route -n add -net 127 127.0.0.1 -reject > /dev/null
736
737	# configure all of the non-loopback interfaces which we know about.
738	# refer to hostname.if(5)
739	for hn in /mnt/etc/hostname.*; do
740    		# Strip off /mnt/etc/hostname. prefix
741    		if=${hn#/mnt/etc/hostname.}
742
743    		# Interface names must be alphanumeric only.  We check to avoid
744    		# configuring backup or temp files, and to catch the "*" case.
745    		if ! isalphanumeric "$if"; then
746			continue
747    		fi
748    		ifconfig $if > /dev/null 2>&1
749    		if [ "$?" != "0" ]; then
750			continue
751    		fi
752
753    		# Now parse the hostname.* file
754    		while :; do
755			if [ "$cmd2" ]; then
756	    			# we are carrying over from the 'read dt dtaddr' last time
757	    			set -- $cmd2
758	    			af="$1" name="$2" mask="$3" bcaddr="$4" ext1="$5" cmd2=
759	    			# make sure and get any remaining args in ext2, like the read below
760	    			i=1; while [ i -lt 6 -a -n "$1" ]; do shift; let i=i+1; done
761	    			ext2="$@"
762			else
763	    			# read the next line or exit the while loop
764	    			read af name mask bcaddr ext1 ext2 || break
765			fi
766			# $af can be "dhcp", "up", "rtsol", an address family, commands, or
767			# a comment.
768			case "$af" in
769			"#"*|"!"*|"bridge"|""|"rtsol")
770				# skip comments, user commands, bridges,
771				# IPv6 rtsol and empty lines
772	    			continue
773	    			;;
774			"dhcp")
775	   			[ "$name" = "NONE" ] && name=
776	    			[ "$mask" = "NONE" ] && mask=
777	    			[ "$bcaddr" = "NONE" ] && bcaddr=
778	    			ifconfig $if $name $mask $bcaddr $ext1 $ext2 down
779	    			cmd="dhclient $if"
780	    			;;
781			"up")
782	   			# The only one of these guaranteed to be set is $if
783	    			# the remaining ones exist so that media controls work
784	    			cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 up"
785	    			;;
786			*)
787	    			read dt dtaddr
788	    			if [ "$name"  = "alias" ]; then
789					# perform a 'shift' of sorts
790					alias=$name
791					name=$mask
792					mask=$bcaddr
793					bcaddr=$ext1
794					ext1=$ext2
795					ext2=
796	    			else
797					alias=
798	    			fi
799	    			cmd="ifconfig $if $af $alias $name "
800	    			case "$dt" in
801	    			dest)
802					cmd="$cmd $dtaddr"
803					;;
804	    			[a-z!]*)
805					cmd2="$dt $dtaddr"
806					;;
807	    			esac
808	    			if [ ! -n "$name" ]; then
809		    			echo "/mnt/etc/hostname.$if: invalid network configuration file"
810					return
811	    			fi
812	    			case $af in
813	    			inet)
814					[ "$mask" ] && cmd="$cmd netmask $mask"
815					if [ "$bcaddr" -a "X$bcaddr" != "XNONE" ]; then
816		   			 	cmd="$cmd broadcast $bcaddr"
817					fi
818					[ "$alias" ] && rtcmd="; route -n add -host $name 127.0.0.1"
819					;;
820	    			inet6)
821					# Ignore IPv6 setup
822					continue
823					;;
824	    			*)      cmd="$cmd $mask $bcaddr"
825	    			esac
826	    			cmd="$cmd $ext1 $ext2$rtcmd" rtcmd=
827	    			;;
828			esac
829			eval "$cmd"
830    		done < /mnt/etc/hostname.$if
831	done
832
833	# /mnt/etc/mygate, if it exists, contains the name of my gateway host
834	# that name must be in /etc/hosts.
835	if [ -f /mnt/etc/mygate ]; then
836		route delete default > /dev/null 2>&1
837		route -n add -host default `cat /mnt/etc/mygate`
838	fi
839
840	# Get FQDN after any DHCP manipulation of resolv.conf is done
841	get_fqdn /etc/resolv.conf
842
843	# Display results...
844	echo "Network interface configuration:"
845	ifconfig -am
846
847	# enable the resolver if resolv.conf is available
848	if [ -f /etc/resolv.conf ]; then
849		route show
850		echo "\nResolver enabled."
851	else
852		route -n show
853		echo "\nResolver not enabled."
854	fi
855
856	return 0
857}
858
859
860# Print the selector and get a response
861# The list of sets is passed in as $1, sets $resp
862get_selection() {
863	local _next= _f _sets=$1
864
865	for _f in $_sets ; do
866		if isin $_f $_setsdone ; then
867			echo -n "	[X] "
868			_next=
869		else
870			echo -n "	[ ] "
871			if [ -z "$_next" ]; then
872			    _next=$_f
873			fi
874		fi
875		echo $_f
876	done
877
878	# Get the name of the file.
879	echo -n "File name? [$_next] "
880	getresp "$_next"
881}
882
883# Do globbing on the selection and parse +/-, sets _get_files and _setsdone
884# (which must exist in the local namespace) as side effects.
885glob_selection() {
886	local _selection="$1" _parent_dir="$2" _sets="$3"
887	local _action _matched _tfile _f
888
889	if [ "X${_selection}" = X"" ]; then
890		return
891	fi
892
893	# Change +/- into add/remove
894	_action=add
895	case "$_selection" in
896		+*)	_selection="${_selection#?}"
897			;;
898		-*)	_selection="${_selection#?}"
899			_action=remove
900			;;
901	esac
902
903	# Major hack to allow the user to select globbing patterns
904	set -o noglob
905	if [ X"$_selection" = X"all" ]; then
906		_selection=*
907	fi
908	_tfile=/tmp/install_case.$$	# safe in single user mode
909	cat >$_tfile << OOF
910	case \$_f in
911		$_selection)	# Add/remove file to extraction list
912			if [ "\$_action" = "add" ]; then
913				_get_files=\`addel \${_f} \${_get_files}\`
914				_setsdone=\`addel \${_f} \${_setsdone}\`
915			elif [ "\$_action" = "remove" ]; then
916				_get_files=\`rmel \${_f} \${_get_files}\`
917				_setsdone=\`rmel \${_f} \${_setsdone}\`
918			else
919				echo "Unknown action: \$_action"
920			fi
921			_matched=\$(( \$_matched + 1 ))
922			;;
923	esac
924OOF
925	set +o noglob
926
927	# Eww.
928	_matched=0
929	for _f in $_sets; do
930		. $_tfile
931	done
932	rm -f $_tfile
933
934	if [ $_matched -eq 0 ]; then
935		echo "File $_parent_dir/$_selection does not exist.  Check to make"
936		echo "sure you entered the information properly or enter 'list' for a file list."
937	fi
938}
939
940install_url() {
941# Get several parameters from the user, and xfer
942# files from the server.
943# Note:	_ftp_server_ip, _ftp_server_dir, _ftp_server_login,
944#	_ftp_server_password, and _ftp_active must be global.
945
946local _sets _kernel _f _file_list _get_files _failed_files _osetsdone
947local _url_type _url_base _reuse _minpat
948
949# Parse arguments, shell style
950while test $# != 0; do
951	case "$1" in
952		-ftp) _url_type=ftp ;;
953		-http) _url_type=http ;;
954		-reuse) _reuse=1 ;;
955		-minpat) shift; _minpat="$1" ;;
956	esac
957	shift
958done
959if [ X"${_minpat}" = X ]; then
960	_minpat='base*.tar.gz|base*.tgz|man*.tar.gz|man*.tgz|etc*.tar.gz|etc*.tgz|bsd'
961fi
962
963echo
964echo "This is an automated ${_url_type}-based installation process.  You will be asked"
965echo "questions and then the files will be retrieved iteratively via ${_url_type}."
966echo
967
968# Reuse old values w/o prompting for anything?
969if [ X"$_reuse" = X"1" ]; then
970	_reuse=
971	if eval test X"\$_installed_via_${_url_type}" = X"1"; then
972		echo -n "Use values from previous ${_url_type} install? [y] "
973		getresp y
974		case "$resp" in
975			y*|Y*)
976				_reuse=1;;
977		esac
978	fi
979fi
980if [ X"$_reuse" = X ]; then
981	# Proxy the connections?
982	if [ "X${_proxy_host}" = X"" ]; then
983		_proxy_host=none
984	fi
985	echo -n "HTTP/FTP proxy URL? (e.g. \"http://proxy:8080\", or \"none\") [${_proxy_host}] "
986	getresp "${_proxy_host}"
987	if [ "X${resp}" = X"none" ]; then
988		unset _proxy_host ftp_proxy http_proxy
989	else
990		_proxy_host=$resp
991		export ftp_proxy=${_proxy_host}
992		export http_proxy=${_proxy_host}
993	fi
994	if [ "${_url_type}" = "ftp" -a "X$ftp_proxy" = "X" ]; then
995		# Use active mode ftp? (irrelevant if using a proxy)
996		case "${_ftp_active}" in
997			-A)	resp=y ;;
998			*)	resp=n ;;
999		esac
1000		echo "By default, ftp will attempt a passive connection and fall back to a normal"
1001		echo "(active) connection if that doesn't work.  However, there are some very"
1002		echo "old ftp servers that claim to support passive mode, but really do not."
1003		echo "In this case, you should explicitly request an active session."
1004		echo -n "Do you want to use active ftp? [${resp}] "
1005		getresp "${resp}"
1006		case "$resp" in
1007			y*|Y*)	_ftp_active=-A ;;
1008			*)	unset _ftp_active ;;
1009		esac
1010	fi
1011
1012	# Provide a list of possible servers
1013	test -z "$_ftp_getlist" && _ftp_getlist=y
1014	echo -n "Do you want a list of potential ${_url_type} servers? [${_ftp_getlist}] "
1015	getresp $_ftp_getlist
1016	case "$resp" in
1017	n*|N*)	_ftp_getlist=n
1018		;;
1019	*)
1020		_ftp_getlist=y
1021		ftphost=129.128.5.191
1022		if [ "X${_resolver_enabled}" = X"TRUE" ]; then
1023			ftphost=ftp.openbsd.org
1024		fi
1025		ftp ${_ftp_active} -V -a -o /tmp/ftplist ftp://${ftphost}/pub/OpenBSD/${VERSION_MAJOR}.${VERSION_MINOR}/ftplist > /dev/null
1026		cat /tmp/ftplist | grep "^${_url_type}:" | cat -n | less -XE
1027		;;
1028	esac
1029
1030	# Get server IP address
1031	resp=		# force one iteration
1032	while [ "X${resp}" = X"" ]; do
1033		if [ -f /tmp/ftplist ]; then
1034			eval echo -n "Server IP address, hostname, or list#? [\$_${_url_type}_server_ip]\ "
1035		else
1036			eval echo -n "Server IP address, or hostname? [\$_${_url_type}_server_ip]\ "
1037		fi
1038		eval getresp "\$_${_url_type}_server_ip"
1039		if [ "X$resp" = "X?" -a -f /tmp/ftplist ]; then
1040			cat /tmp/ftplist | grep "^${_url_type}:" | cat -n | less -XE
1041			resp=
1042		elif [ -n "$resp" -a `isnumeric $resp` -eq 1 -a ${resp:-0} -ge 1 \
1043		    -a -f /tmp/ftplist ]; then
1044			maxlines=`grep "^${_url_type}:" /tmp/ftplist | cat -n |
1045			    sed -n -e '$p' | cutword 1`
1046			if [ $maxlines -lt $resp ]; then
1047				echo "There is no ${resp}th line in the list."
1048				resp=
1049				continue
1050			fi
1051			tline=`grep "^${_url_type}:" /tmp/ftplist | sed -n -e "${resp}p"`
1052			url=`echo $tline | sed -e "s/^${_url_type}:\/\///" |
1053			    cutword -t' ' 1 | cutword -t' ' 1`
1054			host=`echo $url | cutword -t/ 1`
1055			path=`echo $url | sed -e "s/^${host}\///"`
1056			path="${path}/${VERSION_MAJOR}.${VERSION_MINOR}/${ARCH}"
1057			eval _${_url_type}_server_ip=$host
1058			eval _${_url_type}_server_dir=$path
1059			resp=		# do it again, just to double check
1060			echo "Using	$tline"
1061		else
1062			eval _${_url_type}_server_ip="$resp"
1063		fi
1064	done
1065
1066	# Get server directory
1067	if [ "${_url_type}" = "ftp" -a "X${_ftp_server_dir}" = X"" ]; then
1068		# Default ftp dir
1069		_ftp_server_dir="pub/OpenBSD/${VERSION_MAJOR}.${VERSION_MINOR}/${ARCH}"
1070	fi
1071	resp=		# force one iteration
1072	while [ "X${resp}" = X"" ]; do
1073		eval echo -n "Server directory? [\$_${_url_type}_server_dir]\ "
1074		eval getresp "\$_${_url_type}_server_dir"
1075		eval _${_url_type}_server_dir=$resp
1076	done
1077
1078	if [ "${_url_type}" = "ftp" ]; then
1079		# Need default values even if we proxy ftp...
1080		if [ "X${_ftp_server_login}" = X"" ]; then
1081			_ftp_server_login=anonymous
1082		fi
1083		if [ "X${_ftp_server_password}" = X"" ]; then
1084			_ftp_server_password=root@`hostname`.${FQDN}
1085		fi
1086
1087		# Get login name
1088		resp=		# force one iteration
1089		while [ "X${resp}" = X"" ]; do
1090			echo -n "Login? [${_ftp_server_login}] "
1091			getresp "${_ftp_server_login}"
1092			_ftp_server_login=$resp
1093		done
1094
1095		# Get password unless anonymous
1096		if [ ${_ftp_server_login} != "anonymous" ]; then
1097			resp=		# force one iteration
1098			while [ "X${resp}" = X"" ]; do
1099				echo -n "Password (will not echo): "
1100				stty -echo
1101				getresp -n "${_ftp_server_password}"
1102				stty echo
1103				echo
1104				_ftp_server_password=$resp
1105			done
1106		else
1107			# only used by ftp_list_files()
1108			_ftp_server_password=root@`hostname`.${FQDN}
1109		fi
1110	fi
1111fi
1112
1113# Build up the base url since it is so nasty...
1114if [ "${_url_type}" = "ftp" -a "${_ftp_server_login}" != "anonymous" ]; then
1115	_url_base=ftp://${_ftp_server_login}:${_ftp_server_password}@${_ftp_server_ip}/${_ftp_server_dir}
1116else
1117	eval _url_base=${_url_type}://\$_${_url_type}_server_ip/\$_${_url_type}_server_dir
1118fi
1119
1120# Get list of files from the server.
1121# XXX - check for nil $_file_list and deal
1122if [ "${_url_type}" = "ftp" -a "X${ftp_proxy}" = X"" ]; then
1123	_file_list=`ftp_list_files "$_ftp_server_ip" "$_ftp_server_login" "$_ftp_server_password" "$_ftp_server_dir"`
1124else
1125	# Assumes index file is "index.txt" for http (or proxy)
1126	# We can't use index.html since the format is server-dependent
1127	_file_list=`ftp -o - -V ${_url_base}/index.txt | sed 's/
1128//'`
1129fi
1130
1131_sets=
1132if list_has_sets "$_file_list" $THESETS; then
1133	for _f in $THESETS ; do
1134		if [ "X${_f}" = "Xkernel" ]; then
1135			if isin bsd $_file_list; then
1136				_kernel=bsd
1137			fi
1138		elif isin ${_f}${VERSION}.tar.gz $_file_list; then
1139			_sets="$_sets ${_f}${VERSION}.tar.gz"
1140		elif isin ${_f}${VERSION}.tgz $_file_list; then
1141			_sets="$_sets ${_f}${VERSION}.tgz"
1142		fi
1143	done
1144else
1145	eval echo "There are no OpenBSD install sets available in \"\$_${_url_type}_server_dir\"."
1146	echo -n "Search for *.tar.gz and *.tgz files? [y] "
1147	getresp "y"
1148	case "$resp" in
1149		n*|N*)	return ;;
1150		*)	;;
1151	esac
1152	# *.tar.gz and *.tgz are possible sets
1153	_sets=
1154	_kernel=
1155	for _f in ${_file_list} ; do
1156		case "$_f" in
1157		    *.tar.gz|*.tgz)	_sets="$_sets ${_f}"
1158		esac
1159	done
1160	if [ "X${_sets}" = X"" ]; then
1161		echo "There are no *.tar.gz or *.tgz files in that dir."
1162		echo -n "See a directory listing? [y] "
1163		getresp "y"
1164		case "$resp" in
1165			n*|N*)	return ;;
1166			*)	;;
1167		esac
1168		echo
1169		echo "${_file_list}"
1170		echo
1171		return
1172	else
1173		echo "Adding *.tar.gz and *.tgz files to selector."
1174	fi
1175fi
1176
1177# Yes, all those blackslashes really are necesary...
1178eval echo "\\\\n"\
1179"You will now be asked for files to extract. In addition to the files listed,\\\\n"\
1180"you may select any file located at\\\\n"\
1181"	\$_${_url_type}_server_ip:\$_${_url_type}_server_dir\\\\n"\
1182"You can also enter \'all\' to install all the standard sets, or \'list\' to list\\\\n"\
1183"the files available.  When you are done selecting files, enter \'done\'. Some of\\\\n"\
1184"these sets are required for your ${MODE} and some are optional -- you will want\\\\n"\
1185"at least the base and bsd sets.  Consult the installation notes if you are not\\\\n"\
1186"sure which sets are required!"
1187_osetsdone="$_setsdone"
1188# Set the minimal default
1189for _f in $_sets $_kernel; do
1190	eval "case $_f in \
1191		${_minpat}) \
1192			if ! isin \${_f} \${_setsdone}; then \
1193				_get_files=\`addel \${_f} \${_get_files}\` ; \
1194				_setsdone=\`addel \${_f} \${_setsdone}\` ; \
1195			fi ;; \
1196	esac"
1197done
1198
1199# Allow the user to select/de-select additional sets
1200while : ; do
1201	echo
1202	echo "The following sets are available for extraction."
1203	echo "Enter filename, \`list', \`all', or \`done'."
1204	echo "You may de-select a set by prepending a '-' to its name."
1205	echo
1206	get_selection "$_sets $_kernel"
1207
1208	if [ "X${resp}" = X"done" ]; then
1209		break
1210	elif [ "X${resp}" = X"list" ]; then
1211		echo
1212		eval echo "\$_${_url_type}_server_dir:"
1213		echo "${_file_list}"
1214		continue
1215	fi
1216
1217	eval glob_selection \"$resp\" \$_${_url_type}_server_dir \"$_sets $_kernel\"
1218done
1219
1220# User may have said "done" without selecting any files
1221if [ "X${_get_files}" = X"" ]; then
1222	return
1223fi
1224
1225# Stash the fact that we configured and downloaded via this url method
1226eval _installed_via_${_url_type}=1
1227
1228echo
1229echo "Fetching files via ${_url_type} may take a long time, especially over a slow network"
1230echo -n "connection.  Ready to download files? [y] "
1231getresp "y"
1232case "$resp" in
1233	y*|Y*)
1234		;;
1235	*)
1236		_setsdone="$_osetsdone"
1237		return
1238		;;
1239esac
1240
1241# Download the files one at a time and keep track of which ones failed
1242while test -n "${_get_files}" ; do
1243	_failed_files=
1244	echo
1245	for _f in $_get_files ; do
1246		echo "Getting ${_f} ..."
1247		if [ "X${_f}" = "X${_kernel}" ]; then
1248			( cd /mnt ; ftp ${_ftp_active} -V -m ${_url_base}/${_f} )
1249		else
1250			( cd /mnt ; ftp ${_ftp_active} -o - -V -m ${_url_base}/${_f} | tar zxpf - )
1251		fi
1252		if [ $? -ne 0 ]; then
1253			# Mark xfer as having failed,.
1254			_setsdone=`rmel $_f $_setsdone`
1255			_failed_files="${_failed_files} ${_f}"
1256		fi
1257	done
1258
1259	# Give them the option of refetching failed files.
1260	_get_files=
1261	while test -n "${_failed_files}" ; do
1262		echo
1263		echo "The following files failed to transfer and extract correctly:"
1264		echo "Choose which one(s) to refetch or 'done' to exit selector."
1265		echo "You may de-select a file by prepending a '-' to its name."
1266		echo
1267		get_selection "$_failed_files"
1268
1269		if [ "X${resp}" = X"done" ]; then
1270			break
1271		elif [ "X${resp}" = X"list" ]; then
1272			echo
1273			eval echo "\$_${_url_type}_server_dir:"
1274			echo "${_file_list}"
1275			echo
1276			continue
1277		fi
1278
1279		eval glob_selection \"$resp\" \$_${_url_type}_server_dir \"$_failed_files\"
1280	done
1281done
1282}
1283
1284install_from_mounted_fs() {
1285# $1 - directory containing installation sets
1286local _sets= _kernel _f _get_files _failed_files _osetsdone
1287
1288if [ ! -d $1 ]; then
1289	echo "No such directory: $1"
1290	return
1291fi
1292
1293if dir_has_sets $1 $THESETS; then
1294	for _f in $THESETS ; do
1295		if [ "X${_f}" = "Xkernel" ]; then
1296			if [ -f $1/bsd ]; then
1297				_kernel=bsd
1298			fi
1299		elif [ -f $1/${_f}${VERSION}.tar.gz ]; then
1300			_sets="$_sets ${_f}${VERSION}.tar.gz"
1301		elif [ -f $1/${_f}${VERSION}.tgz ]; then
1302			_sets="$_sets ${_f}${VERSION}.tgz"
1303		fi
1304	done
1305else
1306	echo "There are no OpenBSD install sets available in \"$1\"."
1307	echo -n "Search for *.tar.gz and *.tgz files? [y] "
1308	getresp "y"
1309	case "$resp" in
1310		n*|N*)	return ;;
1311		*)	;;
1312	esac
1313	# *.tar.gz and *.tgz are possible sets
1314	_sets=
1315	_kernel=
1316	_sets=`cd $1 ; echo *.tar.gz *.tgz`
1317	if [ "X${_sets}" = X'*.tar.gz *.tgz' ]; then
1318		echo "There are no *.tar.gz or *.tgz files in that dir."
1319		echo -n "See a directory listing? [y] "
1320		getresp "y"
1321		case "$resp" in
1322			n*|N*)	return ;;
1323			*)	;;
1324		esac
1325		echo
1326		( cd $1 && ls )
1327		echo
1328		return
1329	else
1330		echo "Adding *.tar.gz and *.tgz files to selector."
1331	fi
1332fi
1333
1334echo "\n"\
1335"You will now be asked for files to extract.  In addition to the\n"\
1336"files listed in the selector you may enter any file located in\n"\
1337"$1.  You can also enter 'all' to install all the standard\n"\
1338"sets, or 'list' to list the files avilable in $1.\n"\
1339"When you are done selecting files, enter 'done'.\n"\
1340"Some of these sets are required for your ${MODE} and some are optional --\n"\
1341"You will want at least the base and bsd sets.\n"\
1342"Consult the installation notes if you are not sure which sets are required!"
1343_osetsdone="$_setsdone"
1344# Set a minimal default
1345for _f in $_sets $_kernel; do
1346	case "$_f" in
1347		base*.tar.gz|base*.tgz|man*.tar.gz|man*.tgz|etc*.tar.gz|etc*.tgz|bsd)
1348			if ! isin ${_f} ${_setsdone}; then
1349				_get_files=`addel ${_f} ${_get_files}`
1350				_setsdone=`addel ${_f} ${_setsdone}`
1351			fi
1352			;;
1353	esac
1354done
1355
1356# Allow the user to select/de-select additional sets
1357while : ; do
1358	echo
1359	echo "The following sets are available for extraction."
1360	echo "Enter filename, \`list', \`all', or \`done'."
1361	echo "You may de-select a set by prepending a '-' to its name."
1362	echo
1363	get_selection "$_sets $_kernel"
1364
1365	if [ "X${resp}" = X"done" ]; then
1366		break
1367	elif [ "X${resp}" = X"list" ]; then
1368		echo
1369		echo "${1}:"
1370		( cd $1 && ls )
1371		continue
1372	fi
1373
1374	glob_selection "$resp" "$1" "$_sets $_kernel"
1375done
1376
1377# User may have said "done" without selecting any files
1378if [ "X${_get_files}" = X"" ]; then
1379	return
1380fi
1381
1382echo
1383echo -n "Ready to extract selected file sets? [y] "
1384getresp "y"
1385case "$resp" in
1386	y*|Y*)
1387		;;
1388	*)
1389		_setsdone="$_osetsdone"
1390		return
1391		;;
1392esac
1393
1394# Extract the files one at a time and keep track of which ones failed
1395while test -n "${_get_files}" ; do
1396	_failed_files=
1397	echo
1398	for _f in $_get_files ; do
1399		echo "$1/${_f}:"
1400		if [ "X${_f}" = "X${_kernel}" ]; then
1401			ftp -V -m -o /mnt/$_f file:$1/$_f
1402		else
1403			ftp -V -m -o - file:$1/$_f | (cd /mnt; tar -zxpf -)
1404		fi
1405		if [ $? -ne 0 ]; then
1406			# Mark xfer as having failed,.
1407			_setsdone=`rmel $_f $_setsdone`
1408			_failed_files="${_failed_files} ${_f}"
1409		fi
1410	done
1411
1412	# Give them the option of retrying failed files.
1413	_get_files=
1414	while test -n "${_failed_files}" ; do
1415		echo
1416		echo "The following files failed to extract correctly:"
1417		echo "Choose which one(s) to retry or 'done' to exit selector."
1418		echo "You may de-select a file by prepending a '-' to its name."
1419		echo
1420		get_selection "$_failed_files"
1421
1422		if [ "X${resp}" = X"done" ]; then
1423			break
1424		elif [ "X${resp}" = X"list" ]; then
1425			echo
1426			echo "${1}:"
1427			( cd $1 && ls )
1428			echo
1429			continue
1430		fi
1431
1432		glob_selection "$resp" "$1" "$_failed_files"
1433	done
1434done
1435}
1436
1437install_cdrom() {
1438local _drive _range _part _fstype _directory _n
1439
1440# Get the cdrom device info
1441_CDDEVS=`md_get_cddevs`
1442if [ "X${_CDDEVS}" = X"" ]; then
1443	echo "No CD-ROM devices were found.  Aborting."
1444	return
1445fi
1446
1447cat << __EOT
1448
1449The following CD-ROM devices are installed on your system.
1450Please make sure the CD is in the CD-ROM drive and select
1451the device containing the CD with the installation sets:
1452
1453$_CDDEVS
1454
1455__EOT
1456_drive=`echo $_CDDEVS | cutword 1`
1457echo -n	"Which CD-ROM contains the installation media? [$_drive] "
1458getresp "$_drive"
1459case "$resp" in
1460	abort)
1461		echo "Aborting."
1462		return
1463		;;
1464
1465	*)
1466		if isin $resp $_CDDEVS ; then
1467			_drive=$resp
1468		else
1469			echo
1470			echo "The CD-ROM $resp does not exist."
1471			echo "Aborting."
1472			return
1473		fi
1474		;;
1475esac
1476
1477# If it is an ISO9660 CD-ROM, we don't need to ask any other questions
1478_n=0
1479until disklabel $_drive >/tmp/label.$_drive 2>&1; do
1480	# Try up to 6 times to access the CD
1481	if egrep -q '(Input/output error)|(sector size 0)' /tmp/label.$_drive; then
1482		_n=$(( $_n + 1 ))
1483		if [ _n -le 5 ]; then
1484			echo "I/O error accessing $_drive; retrying"
1485			sleep 10
1486		else
1487			echo "Cannot access $_drive.  Aborting."
1488			return
1489		fi
1490	else
1491		break
1492	fi
1493done
1494echo
1495if grep -q '^ *c: .*ISO9660' /tmp/label.$_drive; then
1496	_fstype=cd9660
1497	_part=c
1498else
1499	# Get partition from user
1500	_range=`md_get_partition_range`
1501	resp=		# force one iteration
1502	while [ "X${resp}" = X"" ]; do
1503		echo -n 'CD-ROM partition to mount (normally "c")? [c] '
1504		getresp c
1505		case "$resp" in
1506			$_range)
1507				_part=$resp
1508				;;
1509
1510			*)
1511				echo "Invalid response: $resp"
1512				resp=		# force loop to repeat
1513				;;
1514		esac
1515	done
1516
1517	# Ask for filesystem type
1518	cat << __EOT
1519
1520There are two CD-ROM filesystem types currently supported by this program:
1521cd9660		ISO-9660
1522ffs		Berkeley Fast Filesystem
1523
1524__EOT
1525	resp=		# force one iteration
1526	while [ "X${resp}" = X"" ]; do
1527		echo -n "Which filesystem type? [cd9660] "
1528		getresp "cd9660"
1529		case "$resp" in
1530			cd9660|ffs)
1531				_fstype=$resp
1532				;;
1533
1534			*)
1535				echo "Invalid response: $resp"
1536				resp=		# force loop to repeat
1537				;;
1538		esac
1539	done
1540fi
1541rm -f /tmp/label.$_drive
1542
1543# Mount the CD-ROM
1544if ! mount -t ${_fstype} -o ro \
1545    /dev/${_drive}${_part} /mnt2 ; then
1546	echo "Cannot mount CD-ROM drive.  Aborting."
1547	return
1548fi
1549
1550# Get the directory where the file lives
1551if [ "X${_directory}" = X"" ]; then
1552	_directory="/${VERSION_MAJOR}.${VERSION_MINOR}/${ARCH}"
1553fi
1554resp=		# force one iteration
1555while [ "X${resp}" = X"" ]; do
1556	echo "Enter the directory relative to the mount point that"
1557	echo -n "contains the file. [${_directory}] "
1558	getresp "${_directory}"
1559done
1560_directory=$resp
1561
1562install_from_mounted_fs /mnt2/${_directory}
1563umount -f /mnt2 > /dev/null 2>&1
1564}
1565
1566mount_a_disk() {
1567# Mount a disk on /mnt2. The set of disk devices to choose from
1568# is $_DKDEVS.
1569# returns 0 on failure.
1570
1571local _drive _def_partition _partition_range _partition _fstype
1572local _fsopts _directory _md_fstype _md_fsopts
1573
1574getresp "abort"
1575case "$resp" in
1576	abort)
1577		echo "Aborting."
1578		return 0
1579		;;
1580
1581	*)
1582		if isin $resp $_DKDEVS ; then
1583			_drive=$resp
1584		else
1585			echo
1586			echo "The disk $resp does not exist."
1587			echo "Aborting."
1588			return 0
1589		fi
1590		;;
1591esac
1592
1593# Get partition
1594cat << __EOT
1595
1596The following partitions have been found on $_drive:
1597
1598__EOT
1599disklabel $_drive 2>/dev/null | grep '^  .:'
1600echo
1601_likely_partition_range=`disklabel $_drive 2>/dev/null | \
1602    sed -n -e '/swap/s/.*//' -e '/unused/s/.*//' \
1603	-e '/^  .:/{s/^  \(.\).*/\1/;H;}' \
1604	-e '${g;s/\n//g;s/^/[/;s/$/]/p;}'`
1605_partition_range=`disklabel $_drive 2>/dev/null | \
1606    sed -n -e '/^  .:/{s/^  \(.\).*/\1/;H;}' \
1607	-e '${g;s/\n//g;s/^/[/;s/$/]/p;}'`
1608_def_partition=`echo $_likely_partition_range | \
1609    sed -n 's/^\[\(.\).*\]/\1/p'`
1610if [ -z "$_def_partition" ]; then
1611	_def_partition=`echo $_partition_range | \
1612	    sed -n 's/^\[\(.\).*\]/\1/p'`
1613	if [ -z "$_def_partition" ]; then
1614		echo "There are no usable partitions on that disk"
1615		return 0
1616	fi
1617fi
1618resp=		# force one iteration
1619while [ "X${resp}" = X"" ]; do
1620	echo -n "Partition? [$_def_partition] "
1621	getresp "$_def_partition"
1622	case "$resp" in
1623		$_partition_range)
1624			_partition=$resp
1625			;;
1626
1627		*)
1628			echo "Invalid response: $resp"
1629			resp=		# force loop to repeat
1630			;;
1631	esac
1632done
1633
1634# Ask for filesystem type
1635cat << __EOT
1636
1637The following filesystem types are supported:
1638default		(deduced from the disklabel)
1639ffs
1640__EOT
1641_md_fstype=`md_native_fstype`
1642_md_fsopts=`md_native_fsopts`
1643if [ ! -z "$_md_fstype" ]; then
1644	echo "	$_md_fstype"
1645else
1646	_md_fstype="_undefined_"
1647fi
1648resp=		# force one iteration
1649while [ "X${resp}" = X"" ]; do
1650	echo -n "Which filesystem type? [default] "
1651	getresp "default"
1652	case "$resp" in
1653		default)
1654			_fstype=
1655			_fsopts="ro"
1656			;;
1657		ffs)
1658			_fstype="-t $resp"
1659			_fsopts="async,ro"
1660			;;
1661		$_md_fstype)
1662			_fstype="-t $resp"
1663			_fsopts=$_md_fsopts
1664			;;
1665		*)
1666			echo "Invalid response: $resp"
1667			resp=		# force loop to repeat
1668			;;
1669	esac
1670done
1671
1672# Mount the disk
1673if ! mount $_fstype -o $_fsopts /dev/${_drive}${_partition} /mnt2; then
1674	echo "Cannot mount disk.  Aborting."
1675	return 0
1676fi
1677return 1
1678}
1679
1680install_disk() {
1681local _directory
1682
1683cat << __EOT
1684
1685The following disk devices are installed on your system; please select
1686the disk device containing the partition with the installation sets:
1687
1688__EOT
1689_DKDEVS=`md_get_diskdevs`
1690echo    "$_DKDEVS"
1691echo
1692echo -n	"Which is the disk with the installation sets? [abort] "
1693
1694if mount_a_disk ; then
1695	return
1696fi
1697
1698# Get the directory where the file lives
1699resp=		# force one iteration
1700while [ "X${resp}" = X"" ]; do
1701	echo "Enter the directory relative to the mount point that"
1702	echo -n "contains the file. [${_directory}] "
1703	getresp "${_directory}"
1704done
1705_directory=$resp
1706
1707install_from_mounted_fs /mnt2/${_directory}
1708umount -f /mnt2 > /dev/null 2>&1
1709}
1710
1711install_nfs() {
1712# Get the IP address of the server
1713resp=		# force one iteration
1714while [ "X${resp}" = X"" ]; do
1715	echo -n "Server IP address or hostname? [${_nfs_server_ip}] "
1716	getresp "${_nfs_server_ip}"
1717done
1718_nfs_server_ip=$resp
1719
1720# Get server path to mount
1721resp=		# force one iteration
1722while [ "X${resp}" = X"" ]; do
1723	echo -n "Filesystem on server to mount? [${_nfs_server_path}] "
1724	getresp "${_nfs_server_path}"
1725done
1726_nfs_server_path=$resp
1727
1728# Determine use of TCP
1729echo -n "Use TCP transport (only works with capable NFS server)? [n] "
1730getresp "n"
1731case "$resp" in
1732	y*|Y*)
1733		_nfs_tcp="-T"
1734		;;
1735
1736	*)
1737		_nfs_tcp=
1738		;;
1739esac
1740
1741# Mount the server
1742mkdir /mnt2 > /dev/null 2>&1
1743if ! mount_nfs $_nfs_tcp ${_nfs_server_ip}:${_nfs_server_path} \
1744    /mnt2 ; then
1745	echo "Cannot mount NFS server.  Aborting."
1746	return
1747fi
1748
1749# Get the directory where the file lives
1750resp=		# force one iteration
1751while [ "X${resp}" = X"" ]; do
1752	echo "Enter the directory relative to the mount point that"
1753	echo -n "contains the file. [${_nfs_directory}] "
1754	getresp "${_nfs_directory}"
1755done
1756_nfs_directory=$resp
1757
1758install_from_mounted_fs /mnt2/${_nfs_directory}
1759umount -f /mnt2 > /dev/null 2>&1
1760}
1761
1762install_tape() {
1763local _xcmd
1764
1765# Get the name of the tape from the user.
1766cat << __EOT
1767
1768The installation program needs to know which tape device to use.  Make
1769sure you use a "no rewind on close" device.
1770
1771__EOT
1772_tape=`basename $TAPE`
1773resp=		# force one iteration
1774while [ "X${resp}" = X"" ]; do
1775	echo -n "Name of tape device? [${_tape}]"
1776	getresp "${_tape}"
1777done
1778_tape=`basename $resp`
1779TAPE="/dev/${_tape}"
1780if [ ! -c $TAPE ]; then
1781	echo "$TAPE does not exist or is not a character special file."
1782	echo "Aborting."
1783	return
1784fi
1785export TAPE
1786
1787# Rewind the tape device
1788echo -n "Rewinding tape..."
1789if ! mt rewind ; then
1790	echo "$TAPE may not be attached to the system or may not be"
1791	echo "a tape device.  Aborting."
1792	return
1793fi
1794echo "done."
1795
1796# Get the file number
1797resp=		# force one iteration
1798while [ "X${resp}" = X"" ]; do
1799	echo -n "File number? "
1800	getresp ""
1801	case "$resp" in
1802		[1-9]*)
1803			_nskip=$(( $resp - 1 ))
1804			;;
1805
1806		*)
1807			echo "Invalid file number ${resp}."
1808			resp=		# force loop to repeat
1809			;;
1810	esac
1811done
1812
1813# Skip to correct file.
1814echo -n "Skipping to source file..."
1815if [ "X${_nskip}" != X"0" ]; then
1816	if ! mt fsf $_nskip ; then
1817		echo "Could not skip $_nskip files.  Aborting."
1818		return
1819	fi
1820fi
1821echo "done."
1822
1823cat << __EOT
1824
1825There are 2 different ways the file can be stored on tape:
1826
18271) an image of a gzipped tar file
18282) a standard tar image
1829
1830__EOT
1831resp=		# force one iteration
1832while [ "X${resp}" = X"" ]; do
1833	echo -n "Which way is it? [1] "
1834	getresp "1"
1835	case "$resp" in
1836	1)
1837		_xcmd="tar -zxvpf -"
1838		;;
1839
1840	2)
1841		_xcmd="tar -xvpf -"
1842		;;
1843
1844	*)
1845		echo "Invalid response: $resp."
1846		resp=		# force loop to repeat
1847		;;
1848	esac
1849	( cd /mnt; dd if=$TAPE | $_xcmd )
1850done
1851echo "Extraction complete."
1852}
1853
1854get_timezone() {
1855local _a _zonepath
1856
1857#
1858# If the zoneinfo is not on the installation medium or on the
1859# installed filesystem, set TZ to GMT and return immediatly.
1860#
1861if [ ! -e /usr/share/zoneinfo -a ! -e /mnt/usr/share/zoneinfo ]; then
1862	TZ=GMT
1863	return
1864fi
1865if [ ! -d /usr/share/zoneinfo ]; then
1866	_zonepath=/mnt
1867else
1868	_zonepath=
1869fi
1870
1871cat << __EOT
1872
1873Select a time zone for your location. Timezones are represented on the system
1874by a directory structure rooted in "/usr/share/timezone". Most timezones can
1875be selected by entering a token like "CET" or "GMT-6".  Other zones are
1876grouped by continent or country, with detailed zone information separated by
1877a slash ("/"), e.g. "US/Pacific" or "Canada/Mountain".
1878
1879To get a listing of what's available in /usr/share/zoneinfo, enter "?"
1880at the prompts below.
1881
1882__EOT
1883if [ X$TZ = X ]; then
1884	TZ=`ls -l /mnt/etc/localtime 2>/dev/null | cutlast`
1885	TZ=${TZ#/usr/share/zoneinfo/}
1886fi
1887while : ; do
1888	echo -n	"What timezone are you in? [\`?' for list] [$TZ] "
1889	getresp "$TZ"
1890	case "$resp" in
1891	"")
1892		echo "Timezone defaults to GMT"
1893		TZ="GMT"
1894		break;
1895		;;
1896	"?")
1897		ls -F ${_zonepath}/usr/share/zoneinfo
1898		;;
1899	*)
1900		_a=$resp
1901		while [ -d ${_zonepath}/usr/share/zoneinfo/$_a ]; do
1902			echo -n "There are several timezones available"
1903			echo " within zone '$_a'"
1904			echo -n "Select a sub-timezone [\`?' for list]: "
1905			getresp ""
1906			case "$resp" in
1907			"?") ls -F ${_zonepath}/usr/share/zoneinfo/$_a ;;
1908			*)	_a=${_a}/${resp}
1909				if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then
1910					break;
1911				fi
1912				;;
1913			esac
1914		done
1915		if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then
1916			TZ="$_a"
1917			echo "You have selected timezone \"$_a\"".
1918			return
1919		fi
1920		echo "'/usr/share/zoneinfo/$_a' is not a valid timezone on this system."
1921		;;
1922	esac
1923done
1924}
1925
1926sane_install() {
1927	if [ ! -s /mnt/bsd ]; then
1928		cat << __EOT
1929
1930Warning, no kernel (/mnt/bsd) installed!  You did not unpack a file set
1931containing a kernel--this is needed to boot.  Please note that the install
1932kernel is *not* suitable for general use.
1933__EOT
1934	elif [ ! -f /mnt/bin/cat ]; then
1935		cat << __EOT
1936
1937You still do not have a /bin/cat in your filesystem (i.e. a sample random file
1938which you probably want).  This seems to indicate that you are still missing
1939important distribution files.
1940__EOT
1941	elif [ ! -d /mnt/etc -o ! -d /mnt/usr/share/zoneinfo -o ! -d /mnt/dev ]; then
1942		cat << __EOT
1943
1944Something needed to complete the installation seems to be missing, did you
1945forget to extract a required set?
1946__EOT
1947	else
1948		return 0;
1949	fi
1950
1951	cat << __EOT
1952
1953You will now be given the chance to install the missing set(s).  You can
1954enter '!' at the prompt to escape to a shell and fix things by hand if you wish.
1955
1956__EOT
1957
1958	return 1
1959}
1960
1961install_sets() {
1962local _yup="FALSE" _have_nfs
1963
1964# Can we do an NFS install?
1965test -f /sbin/mount_nfs && _have_nfs=true
1966
1967# Ask the user which media to load the distribution from.
1968cat << __EOT
1969It is now time to extract the installation sets onto the hard disk.  Make sure
1970the sets are either on a local device (i.e. tape, CD-ROM) or on a network
1971server.  You will have the chance to repeat this step or to extract sets from
1972several places, so you don't have to try to load all the sets in one try and
1973can recover from some errors.
1974
1975__EOT
1976
1977if [ "X$local_sets_dir" != "X" ]; then
1978	install_from_mounted_fs ${local_sets_dir}
1979	if [ X"$_setsdone" != X ]; then
1980		_yup="TRUE"
1981	fi
1982fi
1983
1984# Go on prodding for alternate locations
1985resp=		# force at least one iteration
1986while [ X"${resp}" = X ]; do
1987	# If _yup is not FALSE, it means that we extracted sets above.
1988	# If that's the case, bypass the menu the first time.
1989	if [ X"$_yup" = X"FALSE" ]; then
1990		echo -n	"Install from (f)tp, (h)ttp, (t)ape, (C)D-ROM"
1991		test -n "$_have_nfs" && echo -n ", (N)FS"
1992		echo -n " or local (d)isk? "
1993		getresp ""
1994		case "$resp" in
1995		d*|D*)
1996			install_disk
1997			resp=d
1998			;;
1999		f*|F*)
2000			test -n "$_didnet" || donetconfig
2001			install_url -ftp
2002			resp=f
2003			;;
2004		h*|H*)
2005			test -n "$_didnet" || donetconfig
2006			install_url -http
2007			resp=h
2008			;;
2009		t*|T*)
2010			install_tape
2011			resp=t
2012			;;
2013		c*|C*)
2014			install_cdrom
2015			resp=c
2016			;;
2017		n*|N*)
2018			test -n "$_didnet" || donetconfig
2019			if [ -n "$_have_nfs" ]; then
2020				install_nfs
2021				resp=n
2022			else
2023				echo "Invalid response: $resp"
2024				resp=
2025			fi
2026			;;
2027		*)
2028			echo "Invalid response: $resp"
2029			resp=
2030			;;
2031		esac
2032	else
2033		_yup="FALSE"	# So we'll ask next time
2034	fi
2035
2036	# Perform sanity checks...
2037	if sane_install; then
2038		# Give the user the opportunity to extract more sets. They
2039		# don't necessarily have to come from the same media.
2040		echo
2041		echo -n	"Extract more sets? [n] "
2042		getresp "n"
2043		case "$resp" in
2044		y*|Y*)
2045			# Force loop to repeat
2046			resp=
2047			;;
2048
2049		*)
2050			;;
2051		esac
2052	else
2053		# Not sane, don't exit loop.
2054		resp=
2055	fi
2056done
2057}
2058
2059munge_fstab() {
2060local _fstab _fstab_shadow _dev _mp _fstype _dev _options
2061
2062# Create a 'shadow' fstab to use for mounting and unmounting all
2063# of the target filesystems relative to /mnt.
2064_fstab=$1
2065_fstab_shadow=$2
2066( while read _dev _mp _fstype _options _rest; do
2067	# Skip comment lines, non-ffs filesystems and
2068        # 'noauto' filesystems.
2069	case "$_dev" in
2070		\#*)	continue;;
2071		*)	;;
2072	esac
2073	case "$_fstype" in
2074		ffs)	;;
2075		*)	continue;;
2076	esac
2077	case "$_options" in
2078		*noauto*)    continue;;
2079		*)      ;;
2080	esac
2081	# Don't use soft updates
2082        _options="$(echo ${_options} | sed 's/,softdep,/,/; s/,softdep//; s/softdep,//')"
2083	if [ "$_mp" = "/" ]; then
2084	        _mp=""
2085	fi
2086	echo $_dev /mnt$_mp $_fstype $_options $_rest
2087    done ) < $_fstab > $_fstab_shadow
2088}
2089
2090mount_fs() {
2091# Must mount filesystems manually, one at a time, so we can make
2092# sure the mount points exist.
2093# $1 is a file in fstab format
2094local _fstab=$1
2095local _async=$2
2096
2097( while read line; do
2098	set -- $line
2099	_dev=$1
2100	_mp=$2
2101	_fstype=$3
2102	_opt=$4
2103
2104	# If not the root filesystem, make sure the mount
2105	# point is present.
2106	if [ "X{$_mp}" != X"/mnt" ]; then
2107		mkdir -p $_mp
2108	fi
2109
2110	# Mount the filesystem.  If the mount fails, exit
2111	# with an error condition to tell the outer
2112	# later to bail.
2113	if ! mount -v -t $_fstype $_async -o $_opt $_dev $_mp ; then
2114		# error message displayed by mount
2115		exit 1
2116	fi
2117done ) < $_fstab
2118
2119if [ "X${?}" != X"0" ]; then
2120	cat << __EOT
2121
2122FATAL ERROR:  Cannot mount filesystems.  Double-check your configuration
2123and restart the installation process.
2124__EOT
2125	exit
2126fi
2127}
2128
2129unmount_fs() {
2130# Unmount all filesystems and check their integrity.
2131# Usage: [-check] <fstab file>
2132local _check _fstab _pid
2133
2134if [ "$1" = "-check" ]; then
2135	_check=1
2136	_fstab=$2
2137else
2138	_check=0
2139	_fstab=$1
2140fi
2141
2142if [ ! \( -f $_fstab -a -s $_fstab \) ]; then
2143	echo "fstab empty" > /dev/tty
2144	return
2145fi
2146
2147(
2148	_devs=
2149	_mps=
2150	# maintain reverse order
2151	while read line; do
2152		set -- $line
2153		_devs="$1 ${_devs}"
2154		_mps="$2 ${_mps}"
2155	done
2156	echo -n "Unmounting filesystems... "
2157	for _mp in ${_mps}; do
2158		echo -n "${_mp} "
2159		umount ${_mp}
2160	done
2161	echo "... Done."
2162
2163	if [ $_check = 1 ]; then
2164		echo "Checking filesystem integrity..."
2165		for _dev in ${_devs}; do
2166			echo  "${_dev}"
2167			fsck -f ${_dev}
2168		done
2169		echo "... Done."
2170	fi
2171) < $_fstab
2172}
2173
2174remount_fs() {
2175( while read line; do
2176	set -- $line
2177	_dev=$1
2178	_mp=$2
2179	_fstype=$3
2180	_opt=$4
2181
2182	if ! mount -u -o $_opt $_dev $_mp ; then
2183		# error message displayed by mount
2184		exit 1
2185	fi
2186done ) < $1
2187}
2188
2189check_fs() {
2190# Check filesystem integrity.
2191# $1 is a file in fstab format
2192local _fstab=$1
2193
2194(
2195	_devs=
2196	_mps=
2197	while read line; do
2198		set -- $line
2199		_devs="$1 ${_devs}"
2200		_mps="$2 ${_mps}"
2201	done
2202
2203	echo "Checking filesystem integrity..."
2204	for _dev in ${_devs}; do
2205		echo  "${_dev}"
2206		fsck -f ${_dev}
2207	done
2208	echo "Done."
2209) < $_fstab
2210}
2211
2212get_fqdn() {
2213	# Find LAST instance of DOMAIN or SEARCH and extract first domain name
2214	# on that line as FQDN. Then ask user, just to be sure.
2215
2216	if [ -f "$1" ]; then
2217		FQDN=`sed -n \
2218			-e '/^domain[[:space:]][[:space:]]*/{s///;s/\([^[:space:]]*\).*$/\1/;h;}' \
2219			-e '/^search[[:space:]][[:space:]]*/{s///;s/\([^[:space:]]*\).*$/\1/;h;}' \
2220			-e '${g;p;}' $1`
2221	fi
2222
2223	resp=		# force at least one iteration
2224	while [ "X${resp}" = X"" ]; do
2225		echo -n "Enter DNS domain name (e.g. \"bar.com\"): [$FQDN] "
2226		getresp "$FQDN"
2227	done
2228
2229	FQDN=$resp
2230}
2231
2232donetconfig() {
2233	_didnet=1
2234	resp=		# force at least one iteration
2235	_nam=
2236	if [ -f /tmp/myname ]; then
2237		_nam=`cat /tmp/myname`
2238	fi
2239	while [ "X${resp}" = X"" ]; do
2240		echo -n "Enter system hostname (short form, e.g. \"foo\"): [$_nam] "
2241		getresp "$_nam"
2242	done
2243	hostname $resp
2244	echo $resp > /tmp/myname
2245
2246	echo
2247	echo "If you have any devices being configured by a DHCP server"
2248	echo "it is recommended that you do not enter a default route or"
2249	echo "any name servers."
2250	echo
2251
2252	# Get FQDN before creation of hosts file entries in addhostent()
2253	if [ -f /tmp/resolv.conf.shadow ]; then
2254		get_fqdn /tmp/resolv.conf.shadow
2255	else
2256		# If install is being re-run, save a few keystrokes
2257		get_fqdn /tmp/resolv.conf
2258	fi
2259
2260	configurenetwork
2261
2262	resp=`route -n show |
2263	    grep '^default' |
2264	    sed -e 's/^default          //' -e 's/ .*//'`
2265	if [ "X${resp}" = "X" ]; then
2266		resp=none
2267		if [ -f /tmp/mygate ]; then
2268			resp=`cat /etc/mygate`
2269			if [ "X${resp}" = "X" ]; then
2270				resp="none";
2271			fi
2272		fi
2273	fi
2274	echo -n "Enter IP address of default route: [$resp] "
2275	getresp "$resp"
2276	if [ "X${resp}" != X"none" ]; then
2277		route delete default > /dev/null 2>&1
2278		if route add default $resp > /dev/null ; then
2279			echo $resp > /tmp/mygate
2280		fi
2281	fi
2282
2283	resp="none"
2284	if [ -f /etc/resolv.conf ]; then
2285		resp=
2286		for n in `grep '^nameserver ' /etc/resolv.conf | \
2287		    sed -e 's/^nameserver //'`; do
2288			if [ "X${resp}" = "X" ]; then
2289				resp="$n"
2290			else
2291				resp="$resp $n"
2292			fi
2293		done
2294	elif [ -f /tmp/resolv.conf ]; then
2295		resp=
2296		for n in `grep '^nameserver ' /tmp/resolv.conf | \
2297		    sed -e 's/^nameserver //'`; do
2298			if [ "X${resp}" = "X" ]; then
2299				resp="$n"
2300			else
2301				resp="$resp $n"
2302			fi
2303		done
2304	fi
2305	echo -n	"Enter IP address of primary nameserver: [$resp] "
2306	getresp "$resp"
2307	if [ "X${resp}" != X"none" ]; then
2308		echo "search $FQDN" > /tmp/resolv.conf
2309		for n in `echo ${resp}`; do
2310			echo "nameserver $n" >> /tmp/resolv.conf
2311		done
2312		echo "lookup file bind" >> /tmp/resolv.conf
2313
2314		echo -n "Would you like to use the nameserver now? [y] "
2315		getresp "y"
2316		case "$resp" in
2317			y*|Y*)
2318				cp /tmp/resolv.conf \
2319				    /tmp/resolv.conf.shadow
2320				;;
2321
2322			*)
2323				;;
2324		esac
2325	fi
2326
2327	if [ ! -f /tmp/resolv.conf.shadow ]; then
2328		echo
2329		echo "The host table is as follows:"
2330		echo
2331		cat /tmp/hosts
2332	cat << __hosts_table_1
2333
2334You may want to edit the host table in the event that you are doing an
2335NFS installation or an FTP installation without a name server and want
2336to refer to the server by name rather than by its numeric ip address.
2337__hosts_table_1
2338		echo -n "Would you like to edit the host table with ${EDITOR}? [n] "
2339		getresp "n"
2340		case "$resp" in
2341			y*|Y*)
2342				${EDITOR} /tmp/hosts
2343				;;
2344
2345			*)
2346				;;
2347		esac
2348	fi
2349
2350	cat << \__network_config_2
2351
2352You will now be given the opportunity to escape to the command shell to do
2353any additional network configuration you may need.  This may include adding
2354additional routes, if needed.  In addition, you might take this opportunity
2355to redo the default route in the event that it failed above.
2356__network_config_2
2357	echo -n "Escape to shell? [n] "
2358	getresp "n"
2359	case "$resp" in
2360		y*|Y*)
2361			echo "Type 'exit' to return to install."
2362			sh
2363			;;
2364
2365		*)
2366			;;
2367	esac
2368}
2369
2370populateusrlocal() {
2371	if [ -f /mnt/etc/mtree/BSD.local.dist ]; then
2372		/mnt/usr/sbin/chroot /mnt /usr/sbin/mtree -Uedqn -p /usr/local -f /etc/mtree/BSD.local.dist >/dev/null
2373	fi
2374}
2375