# $OpenBSD: install.sub,v 1.248 2002/07/18 00:36:44 krw Exp $ # $NetBSD: install.sub,v 1.5.2.8 1996/09/02 23:25:02 pk Exp $ # # Copyright (c) 1997-2002 Todd Miller, Theo de Raadt, Ken Westerback # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Todd Miller and # Theo de Raadt # 4. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Copyright (c) 1996 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by Jason R. Thorpe. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by the NetBSD # Foundation, Inc. and its contributors. # 4. Neither the name of The NetBSD Foundation nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # OpenBSD install/upgrade script common subroutines and initialization code # Include machine-dependent functions and definitions. # # The following functions must be provided: # md_congrats() - display friendly message # md_installboot() - install boot-blocks on disk # md_prep_disklabel() - label the root disk # md_set_term() - set up terminal # # The following variables can be provided if required: # MDTERM - 'vt220' assumed if not provided # MDFSTYPE - nothing assumed if not provided # MDFSOPTS - nothing assumed if not provided # MDDISKDEVS - '/^[sw]d[0-9][0-9]* /s/ .*//p' assumed if not provided # MDCDDEVS - '/^cd[0-9][0-9]* /s/ .*//p' assumed if not provided # MDXAPERTURE - if not empty, set machdep.allowaperture=value in sysctl.conf . install.md set_term() { [ "$TERM" ] && return ask "Specify terminal type:" ${MDTERM:-vt220} TERM=$resp export TERM md_set_term } welcome_banner() { cat << __EOT Welcome to the OpenBSD/${ARCH} ${VERSION_MAJOR}.${VERSION_MINOR} ${MODE} program. This program will help you ${MODE} OpenBSD in a simple and rational way. __EOT if [ "$MODE" = "upgrade" ]; then cat << __EOT As a reminder, installing the 'etc' binary set is NOT recommended. Once the rest of your system has been upgraded, you should manually merge any changes to files in the 'etc' set into those files which already exist on your system. __EOT else cat << __EOT You'll be asked several questions, and it would probably be useful to have your disk's hardware manual, the installation notes, and a calculator handy. __EOT fi cat << __EOT As with anything that modifies your disk's contents, this program can cause SIGNIFICANT data loss, and you are advised to make sure your data is backed up before beginning the installation process. Default answers are displayed in brackets after the questions. You can hit Control-C at any time to quit, but if you do so at a prompt, you may have to hit return. Also, quitting in the middle of an ${MODE} may leave your system in an inconsistent state. If you hit Control-C and restart the ${MODE}, the ${MODE} program will remember many of your old answers. At any prompt except password prompts you can run a shell command by typing '!foo', or escape to a shell by typing '!'. __EOT } get_dkdevs() { bsort `sed -ne "${MDDISKDEVS:-/^[sw]d[0-9][0-9]* /s/ .*//p}" /var/run/dmesg.boot` } get_cddevs() { bsort `sed -ne "${MDCDDEVS:-/^cd[0-9][0-9]* /s/ .*//p}" /var/run/dmesg.boot` } get_ifdevs() { /sbin/ifconfig -a | egrep -v '^([[:space:]]|(lo|enc|gre|ppp|sl|tun|bridge)[[:digit:]])' | cutword -t: 1 } # Ask for a password, saving the input in $resp. # Display $1 as the prompt. # *Don't* allow the '!' options that ask does. # *Don't* echo input. askpass() { set -o noglob stty -echo read resp?"$1 " stty echo set +o noglob echo } # Ask for user input. # # $1 = the question to ask the user # $2 = the default answer # # Save the user input (or the default) in $resp. # # Allow the user to escape to shells ('!') or execute commands # ('!foo') before entering the input. ask() { echo -n "$1 " [ $# -lt 2 ] || echo -n "[$2] " set -o noglob while : ; do read resp case $resp in !) echo "Type 'exit' to return to install." sh ;; !*) eval ${resp#?} ;; *) : ${resp:=$2} break ;; esac done set +o noglob } # Ask for user input until a non-empty reply is entered. # # $1 = the question to ask the user # $2 = the default answer # # Save the user input (or the default) in $resp. ask_until () { resp= while [ -z "$resp" ] ; do ask "$1" "$2" done } # Ask for the user to select a device from a list generated by scanning # /var/run/dmesg.boot, and make the device if it doesn't exist. # # $1 = question to ask # $2 = list of devices from /var/run/dmesg.boot scan # $3 = default device # # $resp holds device selected at exit, or 'done' ask_fordev () { local _query=$1 _devs=$2 _defdev=$3 [ "$_defdev" ] || _defdev=done resp= while [ -z "$resp" ]; do echo "\nAvailable devices are:\n\n${_devs}\n" ask "$_query (or done)" "$_defdev" if isin $resp $_devs ; then makedev $resp || resp= elif [ "$resp" != "done" ]; then echo "\n'$resp' does not exist." resp= fi done } # test the first argument against the remaining ones, return success on a match isin() { local _a=$1 _b shift for _b; do [ "$_a" = "$_b" ] && return 0 done return 1 } # add first argument to list formed by the remaining arguments # adds to the tail if the element does not already exist addel() { local _a=$1 _b _seen=false shift for _b; do echo "$_b" [ "$_a" = "$_b" ] && _seen=true done $_seen || echo "$_a" } # remove all occurrences of first argument from list formed by # the remaining arguments rmel() { local _a=$1 _b shift for _b; do [ "$_a" != "$_b" ] && echo "$_b" done } # read lines on stdin, return Nth element of each line, like cut(1) cutword () { local _a _n _oifs=$IFS # optional field separator case $1 in -t?*) IFS=${1#-t}; shift;; esac _n=$1 while read _a; do set -- $_a [ "$1" ] || break eval echo \$$_n done IFS=$_oifs } # read a line of data, return last element. Equiv. of awk '{print $NF}'. cutlast () { read _a; set -- $_a [ $# -gt 0 ] || return eval echo \$\{$#\} } bsort() { local _l _a=$1 _b case $# in 0) return;; 1) echo $1; return;; esac shift for _b; do if [[ "$_a" != "$_b" ]] ; then if [[ "$_a" > "$_b" ]] ; then _l="$_a $_l"; _a=$_b else _l="$_b $_l" fi fi done echo -n $_a # Prevent a trailing blank on the output, and thus a bad value # for cutlast or cutword, by outputting blanks only when $_l # has values to sort. if [[ -n "$_l" ]] ; then echo -n " " bsort $_l fi } # log in via ftp to host $1 as user $2 with password $3 # and return a list of all files in the directory $4 on stdout ftp_list_files() { ftp ${_ftp_active} -V -n "$1" << __EOT user "$2" "$3" cd "$4" ls quit __EOT } # $1 is the mountpoint the local directory will be relative to. # $2 is the default directory get_setsdir() { local _mp=$1 _dir=$2 _mounted SETSDIR= _mounted=`mount | sed -ne "/\(.*\)\/\(${_mp#/}\)\/*\(.*\) type.*/s//\/\3/p"` if [ -z "$_mounted" ]; then echo "No filesystems mounted at or below ${_mp}." return fi while : ; do ask "Enter the pathname where the sets are stored (or '?')" "$_dir" case $resp in "?") cat << __EOT The following filesystems are mounted at or below ${_mp} and are therefore possible sources for ${MODE} sets: ${_mounted} __EOT continue ;; "") ;; *) if [ -d "${_mp}/${resp}" ]; then SETSDIR=${_mp}/${resp} return fi echo "The directory '${resp}' does not exist." ;; esac ask "\nRe-enter pathname?" y case $resp in y*|Y*) ;; *) break ;; esac done } makedev() { local _d=$1 if [ ! -c /dev/r${_d}c ]; then if [ -r /dev/MAKEDEV ]; then (cd /dev; sh MAKEDEV $_d) else echo "Device nodes for $_d are missing, and MAKEDEV" echo "does not exist to create them with. Sorry." false fi fi } get_rootdisk() { local _defdsk ROOTDISK= _defdsk=`echo $DKDEVS | cutlast` [ "$_defdsk" = "$DKDEVS" ] || _defdsk= cat << __EOT The installation program needs to know which disk to consider the root disk. Note the unit number may be different than the unit number you used in the boot program (especially on a machine with multiple disk controllers). __EOT ask_fordev "Which disk is the root disk?" "$DKDEVS" "$_defdsk" [ "$resp" = "done" ] && exit ROOTDISK=$resp ROOTDEV=${ROOTDISK}a } # Create an entry in the hosts file. If an entry with the # same symbolic name already exists, delete it. # $1 - IP address # $2 - symbolic name addhostent() { sed "/ $2\$/d" /tmp/hosts > /tmp/hosts.new mv /tmp/hosts.new /tmp/hosts echo "$1 $2" >> /tmp/hosts } # Create a hostname.* file for the interface. # $1 - interface name # $2 - interface symbolic name # $3 - interface IP address # $4 - interface netmask # $5 - (optional) interface media directives addifconfig() { if [ "$3" = "dhcp" ]; then echo "dhcp NONE NONE NONE $5" > /tmp/hostname.$1 addhostent 127.0.0.1 $2 else echo "inet $3 $4 NONE $5" > /tmp/hostname.$1 addhostent $3 $2 fi } # Show selection list and get user response to give question # in global _resp. # # $1 = full list to display # $2 = list of already selected elements # $3 = question to ask user do_selection_list() { local _next _elem for _elem in $1; do if isin $_elem $2; then echo -n " [X] " else echo -n " [ ] " : ${_next:=$_elem} fi echo $_elem done : ${_next:=done} ask "\n$3 (or 'done')" "$_next" } configure_all_interfaces() { local _ifsdone _ifs while : ; do cat << __EOT You may configure the following network interfaces (the interfaces marked with [X] have been successfully configured): __EOT do_selection_list "$IFDEVS" "$_ifsdone" "Configure which interface?" case $resp in "done") break ;; *) _ifs=$resp if isin $_ifs $IFDEVS ; then if configure_ifs $_ifs ; then _ifsdone="$_ifs $_ifsdone" fi else echo "Invalid response: '$resp' is not in list" fi ;; esac done } configure_ifs() { local _up _if_name=$1 _if_ip _if_mask local _if_symname _if_extra _hostname local _dhcp_prompt set -- `ifconfig $_if_name | sed -n ' 1s/.**$/DOWN/p /media:/s/^.*$// /status:/s/^.*$// /inet/s/--> [0-9.][0-9.]*// /inet/s/netmask// /inet/s/broadcast// /inet/s/inet// p'` _up=$1 _if_ip=$2 _if_mask=$3 [ $_up = "UP" ] && ifconfig $_if_name delete down [ -x /sbin/dhclient ] && _dhcp_prompt=" (or 'dhcp')" # Get IP address resp= while [ -z "$resp" ] ; do ask "IP address${_dhcp_prompt}?" "$_if_ip" if [ ! -x /sbin/dhclient -a "$resp" == "dhcp" ]; then echo "DHCP is not supported." resp= fi done _if_ip=$resp # Get symbolic name _hostname=`hostname` ask_until "Symbolic (host) name?" "$_hostname" _if_symname=$resp # Get netmask if [ "$_if_ip" != "dhcp" ]; then ask_until "Netmask?" "${_if_mask:=255.255.255.0}" _if_mask=$resp fi if [ "`ifconfig -m ${_if_name} | sed -n '/media/p'`" ]; then cat << __EOT Your use of the network interface may require non-default media directives. The default media is: __EOT ifconfig -m ${_if_name} | sed -n ' /supported/D /media:/p' echo "This is a list of supported media:" ifconfig -m ${_if_name} | sed -n ' /media:/D s/^ // /media/p' cat << __EOT If the default is not satisfactory, and you wish to use another media, copy that line from above (e.g. "media 100baseTX") __EOT ask "Media directives?" _if_extra=$resp fi # Configure the interface. If it # succeeds, add it to the permanent # network configuration info. if [ "$_if_ip" = "dhcp" ]; then ifconfig ${_if_name} down ${_if_extra} cat > /etc/dhclient.conf << __EOT initial-interval 1; send host-name "$_hostname"; request subnet-mask, broadcast-address, routers, domain-name, domain-name-servers, host-name; __EOT dhclient -1 ${_if_name} set -- `ifconfig $_if_name | sed -n ' 1s/.**$/DOWN/p /media:/s/^.*$// /status:/s/^.*$// /inet/s/--> [0-9.][0-9.]*// /inet/s/netmask// /inet/s/broadcast// /inet/s/inet// p'` if [ $1 = "UP" -a $2 = "0.0.0.0" ]; then echo "hostname-associated DHCP attempt for $_if_name failed..." ifconfig $_if_name delete down cat > /etc/dhclient.conf << __EOT initial-interval 1; request subnet-mask, broadcast-address, routers, domain-name, domain-name-servers, host-name; __EOT dhclient -1 ${_if_name} set -- `ifconfig $_if_name | sed -n ' 1s/.**$/DOWN/p /media:/s/^.*$// /status:/s/^.*$// /inet/s/--> [0-9.][0-9.]*// /inet/s/netmask// /inet/s/broadcast// /inet/s/inet// p'` if [ $1 = "UP" -a $2 = "0.0.0.0" ]; then echo "free-roaming DHCP attempt for $_if_name failed." ifconfig $_if_name delete down return 1 else echo "DHCP attempt for $_if_name successful." addifconfig ${_if_name} ${_if_symname} ${_if_ip} return 0 fi else echo "DHCP configuration of $_if_name successful." addifconfig ${_if_name} ${_if_symname} ${_if_ip} return 0 fi else ifconfig ${_if_name} down if ifconfig ${_if_name} inet \ ${_if_ip} \ netmask ${_if_mask} ${_if_extra} up then addifconfig ${_if_name} ${_if_symname} ${_if_ip} ${_if_mask} "$_if_extra" return 0 fi fi return 1 } # Returns true if $1 contains only alphanumerics isalphanumeric() { local _n _n=$1 while [ ${#_n} != 0 ]; do case $_n in [A-Za-z0-9]*) ;; *) return 1;; esac _n=${_n#?} done return 0 } # Much of this is gratuitously stolen from /etc/netstart. enable_network() { # Check for required network related files for _netfile in hosts myname; do if [ ! -f /mnt/etc/${_netfile} ]; then echo "ERROR: no /mnt/etc/${_netfile}!" return 1 fi done # Copy any required or optional files found for _netfile in hosts myname dhclient.conf resolv.conf resolv.conf.tail protocols services; do if [ -f /mnt/etc/${_netfile} ]; then cp /mnt/etc/${_netfile} /etc/${_netfile} fi done hostname=`cat /etc/myname` hostname $hostname DIDNET=y # set the address for the loopback interface ifconfig lo0 inet localhost # use loopback, not the wire route -n add -host $hostname localhost > /dev/null route -n add -net 127 127.0.0.1 -reject > /dev/null # configure all of the non-loopback interfaces which we know about. # refer to hostname.if(5) for hn in /mnt/etc/hostname.*; do # Strip off /mnt/etc/hostname. prefix if=${hn#/mnt/etc/hostname.} # Interface names must be alphanumeric only. We check to avoid # configuring backup or temp files, and to catch the "*" case. if ! isalphanumeric "$if"; then continue fi ifconfig $if > /dev/null 2>&1 if [ $? -ne 0 ]; then continue fi # Now parse the hostname.* file while :; do if [ "$cmd2" ]; then # we are carrying over from the 'read dt dtaddr' last time set -- $cmd2 af=$1 name=$2 mask=$3 bcaddr=$4 ext1=$5 cmd2= # make sure and get any remaining args in ext2, like the read below i=1; while [ i -lt 6 -a -n "$1" ]; do shift; let i=i+1; done ext2="$@" else # read the next line or exit the while loop read af name mask bcaddr ext1 ext2 || break fi # $af can be "dhcp", "up", "rtsol", an address family, commands, or # a comment. case $af in "#"*|"!"*|"bridge"|""|"rtsol") # skip comments, user commands, bridges, # IPv6 rtsol and empty lines continue ;; "dhcp") [ "$name" = "NONE" ] && name= [ "$mask" = "NONE" ] && mask= [ "$bcaddr" = "NONE" ] && bcaddr= ifconfig $if $name $mask $bcaddr $ext1 $ext2 down cmd="dhclient $if" ;; "up") # The only one of these guaranteed to be set is $if # the remaining ones exist so that media controls work cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 up" ;; *) read dt dtaddr if [ "$name" = "alias" ]; then # perform a 'shift' of sorts alias=$name name=$mask mask=$bcaddr bcaddr=$ext1 ext1=$ext2 ext2= else alias= fi cmd="ifconfig $if $af $alias $name " case $dt in dest) cmd="$cmd $dtaddr" ;; [a-z!]*) cmd2="$dt $dtaddr" ;; esac if [ ! -n "$name" ]; then echo "/mnt/etc/hostname.$if: invalid network configuration file" return fi case $af in inet) [ "$mask" ] && cmd="$cmd netmask $mask" if [ "$bcaddr" -a "$bcaddr" != "NONE" ]; then cmd="$cmd broadcast $bcaddr" fi [ "$alias" ] && rtcmd="; route -n add -host $name 127.0.0.1" ;; inet6) # Ignore IPv6 setup continue ;; *) cmd="$cmd $mask $bcaddr" esac cmd="$cmd $ext1 $ext2$rtcmd" rtcmd= ;; esac eval "$cmd" done < /mnt/etc/hostname.$if done # /mnt/etc/mygate, if it exists, contains the name of my gateway host # that name must be in /etc/hosts. if [ -f /mnt/etc/mygate ]; then route delete default > /dev/null 2>&1 route -n add -host default `cat /mnt/etc/mygate` fi # Get FQDN after any DHCP manipulation of resolv.conf is done get_fqdn /etc/resolv.conf # Display results... echo "Network interface configuration:" ifconfig -am # enable the resolver if resolv.conf is available if [ -f /etc/resolv.conf ]; then route show echo "\nResolver enabled." else route -n show echo "\nResolver not enabled." fi return 0 } # Do globbing on the selection and parse +/-, sets the global # GET_FILES appropriately. glob_selection() { local _selection=$1 _src=$2 local _action _nomatch _f # Change +/- into add/remove, but ignore bare '+' or '-' _action=addel case $_selection in ""|+|-) return ;; +*) _selection=${_selection#?} ;; -*) _selection=${_selection#?} _action=rmel ;; esac [ "$_selection" = "all" ] && _selection=* set -o noglob for _f in $SETS; do eval "case $_f in $_selection) GET_FILES=\`$_action $_f \$GET_FILES\` _nomatch=false ;; esac" done set +o noglob if $_nomatch; then cat << __EOT The file '${_src}/${_selection}' does not exist. Check to make sure you entered the name properly. __EOT fi } # Set global SETS to either # 1) a list of sets found in both $1 and $THESETS, where # $2 is the location that generated the list of files in $1. # or # 2) a list of .tgz or .tar.gz files found in $2 get_sets () { local _f _file_list=$1 _src=$2 SETS= for _f in $THESETS ; do if [ "$_f" = "kernel" ]; then if isin bsd $_file_list; then SETS="$SETS bsd" fi elif isin ${_f}${VERSION}.tar.gz $_file_list; then SETS="$SETS ${_f}${VERSION}.tar.gz" elif isin ${_f}${VERSION}.tgz $_file_list; then SETS="$SETS ${_f}${VERSION}.tgz" fi done if [ -z "$SETS" ]; then cat << __EOT The directory '${_src}' contains no OpenBSD ${VERSION_MAJOR}.${VERSION_MINOR} ${MODE} sets. __EOT ask "Search for other *.tar.gz and *.tgz files?" y case $resp in n*|N*) return ;; esac # *.tar.gz and *.tgz are possible sets for _f in $_file_list ; do case $_f in *.tar.gz|*.tgz) SETS="$SETS ${_f}" esac done fi if [ -z "$SETS" ]; then ask "There are no *.tar.gz or *.tgz files in ${_src}.\nSee a directory listing?" y case $resp in n*|N*) return ;; esac echo "\n${_file_list}\n" return fi } # Set global GET_FILES to the list of sets requested by the user. # $1 = list of files available in source directory or url. # $2 = source directory or url get_get_files () { local _files=$1 _src=$2 GET_FILES= get_sets "$_files" "$_src" [ "$SETS" ] || return cat << __EOT You will now be asked which sets to ${MODE}. Some of these sets are required for your ${MODE} and some are optional. You will want at least the base and bsd sets. Consult the installation notes if you are not sure which sets are required! __EOT # Set the default list of files for _f in $SETS ; do # $SETS contains only .tgz and .tar.gz file names and 'bsd'. case $_f in base*|bsd|comp*|etc*|game*|man*|misc*) isin $_f $SETSDONE || GET_FILES=`addel $_f $GET_FILES` ;; esac done # Allow the user to select/de-select additional sets while : ; do cat << __EOT The following sets are available. Enter a filename, 'all' to select all the sets, or 'done'. You may de-select a set by prepending a '-' to its name. __EOT do_selection_list "$SETS" "$GET_FILES" "File Name?" [ "$resp" = "done" ] && break glob_selection "$resp" "$_src" done } # Install the list of files in the global GET_FILES from the source # named in $1. Display an error message for failed installs so the # user will know to try again. install_get_files () { local _f _src=$1 ask "Ready to ${MODE} sets?" y case $resp in n*|N*) return ;; esac echo for _f in $GET_FILES ; do echo "Getting ${_f} ..." case $_f in *.tar.gz|*.tgz) ftp ${_ftp_active} -o - -V -m "${_src}/${_f}" | tar zxpf - -C /mnt ;; *) ftp ${_ftp_active} -o "/mnt/${_f}" -V -m "${_src}/${_f}" ;; esac if [ $? -ne 0 ]; then echo "'${_f}' did not install correctly." else SETSDONE=`addel ${_f} ${SETSDONE}` fi done } # Encode $1 as specified for usercodes and passwords in RFC 1738 # section 3.1, and now supported by our in-tree ftp: # # ':' -> '%3a' # '@' -> '%40' # '/' -> '%2f' # # *NOTE* quotes around $1 are required to preserve trailing or # embeddded blanks in usercodes and passwords! encode_for_url() { echo "$1" | sed -e 's/:/%3a/g' -e 's/@/%40/g' -e 's/\//%2f/g' } # Get several parameters from the user, and xfer # files from the server. # $1 = url type (ftp or http) # Note: _ftp_server_ip, _ftp_server_dir, _ftp_server_login, # _ftp_server_password, and _ftp_active must be global. install_url() { local _f _file_list _url_type=$1 _url_base _url_login _url_pass _oifs donetconfig cat << __EOT This is an automated ${_url_type}-based installation process. You will be asked questions and then the files will be retrieved iteratively via ${_url_type}. __EOT # Proxy the connections? : ${_proxy_host:=none} ask "HTTP/FTP proxy URL? (e.g. 'http://proxy:8080', or 'none')" "$_proxy_host" if [ "$resp" = "none" ]; then unset _proxy_host ftp_proxy http_proxy else _proxy_host=$resp export ftp_proxy=${_proxy_host} export http_proxy=${_proxy_host} fi if [ "$_url_type" = "ftp" -a -z "$ftp_proxy" ]; then # Use active mode ftp? (irrelevant if using a proxy) case $_ftp_active in -A) resp=y ;; *) resp=n ;; esac cat << __EOT By default, ftp will attempt a passive connection and fall back to a normal (active) connection if that does not work. However, there are some very old ftp servers that claim to support passive mode, but really do not. In this case, you should explicitly request an active session. __EOT ask "Do you want to use active ftp?" "$resp" case $resp in y*|Y*) _ftp_active=-A ;; *) unset _ftp_active ;; esac fi # Provide a list of possible servers : ${_ftp_getlist:=y} ask "Do you want a list of potential ${_url_type} servers?" "$_ftp_getlist" case $resp in n*|N*) _ftp_getlist=n ;; *) _ftp_getlist=y # ftp.openbsd.org == 129.128.5.191 and will remain at # that address for the forseeable future. ftp ${_ftp_active} -V -a -o /tmp/ftplist ftp://129.128.5.191/pub/OpenBSD/${VERSION_MAJOR}.${VERSION_MINOR}/ftplist > /dev/null grep "^${_url_type}:" /tmp/ftplist | cat -n | less -XE ;; esac # Get server IP address or hostname resp= while [ -z "$resp" ] ; do if [ ! -f /tmp/ftplist ]; then eval ask \"Server IP address, or hostname?\" \"\$_${_url_type}_server_ip\" continue; fi eval ask \"Server IP address, hostname, or list#?\" \"\$_${_url_type}_server_ip\" case $resp in "?") grep "^${_url_type}:" /tmp/ftplist | cat -n | less -XE resp= ;; +([0-9])) maxlines=`grep "^${_url_type}:" /tmp/ftplist | sed -ne '$='` if [ $maxlines -lt $resp -o $resp -lt 1 ]; then echo "There is no ${resp}th line in the list." else tline=`grep "^${_url_type}:" /tmp/ftplist | sed -ne "${resp}p"` url=`echo $tline | sed -e "s/^${_url_type}:\/\///" | cutword -t' ' 1 | cutword -t' ' 1` host=`echo $url | cutword -t/ 1` path=`echo $url | sed -e "s/^${host}\///"` path=${path}/${VERSION_MAJOR}.${VERSION_MINOR}/${ARCH} eval _${_url_type}_server_ip=$host eval _${_url_type}_server_dir=$path echo "Using $tline" fi # Always do it again, just to double check resp= ;; *) ;; esac done eval _${_url_type}_server_ip=$resp # Get server directory if [ "$_url_type" = "ftp" -a -z "$_ftp_server_dir" ] ; then # Default ftp dir _ftp_server_dir=pub/OpenBSD/${VERSION_MAJOR}.${VERSION_MINOR}/${ARCH} fi eval ask_until \"Server directory?\" \"\$_${_url_type}_server_dir\" eval _${_url_type}_server_dir=$resp if [ "$_url_type" = "ftp" ]; then # Get login name, setting IFS to nothing so trailing or # embedded blanks are preserved! _oifs=$IFS IFS= ask_until "Login?" "${_ftp_server_login:=anonymous}" _ftp_server_login=$resp # Get password unless anonymous _ftp_server_password=root@`hostname`.$FQDN if [ "$_ftp_server_login" != "anonymous" ]; then resp= while [ -z "$resp" ] ; do askpass "Password (will not echo):" done _ftp_server_password=$resp fi IFS=$_oifs fi # Build up the base url since it is so nasty... if [ "$_url_type" = "ftp" -a "$_ftp_server_login" != "anonymous" ]; then _url_login=`encode_for_url "$_ftp_server_login"` _url_pass=`encode_for_url "$_ftp_server_password"` _url_base=ftp://${_url_login}:${_url_pass}@${_ftp_server_ip}/${_ftp_server_dir} else eval _url_base=${_url_type}://\$_${_url_type}_server_ip/\$_${_url_type}_server_dir fi # Get list of files from the server. # XXX - check for nil $_file_list and deal if [ "$_url_type" = "ftp" -a -z "$ftp_proxy" ] ; then _file_list=`ftp_list_files "$_ftp_server_ip" "$_ftp_server_login" "$_ftp_server_password" "$_ftp_server_dir"` else # Assumes index file is "index.txt" for http (or proxy) # We can't use index.html since the format is server-dependent _file_list=`ftp -o - -V "${_url_base}/index.txt" | sed 's/ //'` fi get_get_files "$_file_list" "`eval echo \\$_${_url_type}_server_dir`" # User may have selected no files [ "$GET_FILES" ] || return cat << __EOT Fetching files via ${_url_type} may take a long time, especially over a slow network connection. __EOT install_get_files "$_url_base" } # $1 - mount point directory is relative to # $2 - default directory install_mounted_fs() { local _f get_setsdir "$1" "$2" [ -d "$SETSDIR" ] || return get_get_files "`ls -l ${SETSDIR}`" "$SETSDIR" # User may have selected no files [ "$GET_FILES" ] || return install_get_files "file:$SETSDIR" } install_cdrom() { local _drive _part _fstype _directory _n # Get the cdrom device info if [ -z "$CDDEVS" ]; then echo "No CD-ROM devices are available." return fi cat << __EOT Please make sure the CD is in the CD-ROM drive and select the device containing the CD with the installation sets. __EOT ask_fordev "Which CD-ROM contains the installation media?" "$CDDEVS" "`echo $CDDEVS | cutword 1`" [ "$resp" = "done" ] && return _drive=$resp # If it is an ISO9660 CD-ROM, we don't need to ask any other questions _n=0 until disklabel $_drive >/tmp/label.$_drive 2>&1; do # Try up to 6 times to access the CD if egrep -q '(Input/output error)|(sector size 0)' /tmp/label.$_drive; then _n=$(( $_n + 1 )) if [ _n -le 5 ]; then echo "I/O error accessing $_drive; retrying" sleep 10 else echo "Cannot access $_drive." return fi else break fi done echo if grep -q '^ *c: .*ISO9660' /tmp/label.$_drive; then _fstype=cd9660 _part=c else # Get partition from user resp= while [ -z "$resp" ] ; do ask "CD-ROM partition to mount? (normally 'c')" c case $resp in [a-p]) _part=$resp ;; *) echo "Invalid response: $resp" # force loop to repeat resp= ;; esac done # Ask for filesystem type cat << __EOT There are two CD-ROM filesystem types currently supported by this program: cd9660 ISO-9660 ffs Berkeley Fast Filesystem __EOT resp= while [ -z "$resp" ] ; do ask "Which filesystem type?" cd9660 case $resp in cd9660|ffs) _fstype=$resp ;; *) echo "Invalid response: '$resp'" # force loop to repeat resp= ;; esac done fi rm -f /tmp/label.$_drive # Mount the CD-ROM if ! mount -t ${_fstype} -o ro /dev/${_drive}${_part} /mnt2 ; then echo "Cannot mount CD-ROM drive." return fi install_mounted_fs /mnt2 "${VERSION_MAJOR}.${VERSION_MINOR}/${ARCH}" umount -f /mnt2 > /dev/null 2>&1 } mount_a_disk() { # Mount a disk on /mnt2. The set of disk devices to choose from # is $DKDEVS. # returns 0 on success, 1 on failure local _drive _def_partition _partition_range _partition local _fstype _fsopts cat << __EOT Please select the disk device containing the partition with the installation sets. __EOT ask_fordev "Which is the disk with the installation sets?" "$DKDEVS" [ "$resp" = "done" ] && return 1 _drive=$resp # Get partition cat << __EOT The following partitions have been found on $_drive: __EOT disklabel $_drive 2>/dev/null | grep '^ .:' echo _likely_partition_range=`disklabel $_drive 2>/dev/null | \ sed -n -e '/swap/s/.*//' -e '/unused/s/.*//' \ -e '/^ .:/{s/^ \(.\).*/\1/;H;}' \ -e '${g;s/\n//g;s/^/[/;s/$/]/p;}'` _partition_range=`disklabel $_drive 2>/dev/null | \ sed -n -e '/^ .:/{s/^ \(.\).*/\1/;H;}' \ -e '${g;s/\n//g;s/^/[/;s/$/]/p;}'` _def_partition=`echo $_likely_partition_range | \ sed -n 's/^\[\(.\).*\]/\1/p'` if [ -z "$_def_partition" ]; then _def_partition=`echo $_partition_range | \ sed -n 's/^\[\(.\).*\]/\1/p'` if [ -z "$_def_partition" ]; then echo "There are no usable partitions on that disk" return 1 fi fi resp= while [ -z "$resp" ]; do ask "Partition?" "$_def_partition" case $resp in $_partition_range) _partition=$resp ;; *) echo "Invalid response: $resp" # force loop to repeat resp= ;; esac done # Ask for filesystem type cat << __EOT The following filesystem types are supported: default (deduced from the disklabel) ffs $MDFSTYPE __EOT resp= while [ -z "$resp" ]; do ask "Which filesystem type?" default case $resp in default) ;; ffs) _fstype="-t ffs" _fsopts=async ;; $MDFSTYPE) _fstype="-t $resp" _fsopts=$MDFSOPTS ;; *) echo "Invalid response: $resp" # force loop to repeat resp= ;; esac done # Mount the disk read-only if ! mount $_fstype -o ro,$_fsopts /dev/${_drive}${_partition} /mnt2; then echo "Cannot mount disk." return 1 fi return 0 } install_disk() { if mount_a_disk; then install_mounted_fs /mnt2 umount -f /mnt2 > /dev/null 2>&1 fi } install_nfs() { # Can we actually mount NFS filesystems? if [ ! -f /sbin/mount_nfs ]; then echo "/sbin/mount_nfs not found. Cannot mount NFS filesystems." return fi donetconfig # Get the IP address of the server ask_until "Server IP address or hostname?" "$_nfs_server_ip" _nfs_server_ip=$resp # Get server path to mount ask_until "Filesystem on server to mount?" "$_nfs_server_path" _nfs_server_path=$resp # Determine use of TCP ask "Use TCP transport? (only works with capable NFS server)" n case $resp in y*|Y*) _nfs_tcp=-T ;; *) _nfs_tcp= ;; esac # Mount the server if ! mount_nfs $_nfs_tcp -o ro ${_nfs_server_ip}:${_nfs_server_path} /mnt2 ; then echo "Cannot mount NFS server." return fi install_mounted_fs /mnt2 umount -f /mnt2 > /dev/null 2>&1 } install_tape() { local _xcmd # Get the name of the tape from the user. cat << __EOT The installation program needs to know which tape device to use. Make sure you use a "no rewind on close" device. __EOT ask_until "Name of tape device?" "${TAPE##*/}" TAPE=/dev/${resp##*/} if [ ! -c $TAPE ]; then echo "$TAPE does not exist or is not a character special file." return fi export TAPE # Rewind the tape device echo -n "Rewinding ${TAPE} (mt rewind)..." if ! mt rewind ; then echo "FAILED." return fi echo "done." # Get the file number resp= while [ -z "$resp" ]; do ask "File number?" case $resp in [1-9]*) _nskip=$(( $resp - 1 )) ;; *) echo "Invalid file number ${resp}." # force loop to repeat resp= ;; esac done # Skip to correct file. if [ $_nskip -ne 0 ]; then echo -n "Skipping to source file (mt fsf ${_nskip})..." if ! mt fsf $_nskip ; then echo "FAILED. Could not skip $_nskip files." return fi echo "done." fi cat << __EOT There are 2 different ways the file can be stored on tape: 1) an image of a gzipped tar file 2) a standard tar image __EOT resp= while [ -z "$resp" ]; do ask "Which way is it?" 1 case $resp in 1) _xcmd="tar -zxvpf -" ;; 2) _xcmd="tar -xvpf -" ;; *) echo "Invalid response: $resp." # force loop to repeat resp= ;; esac ( cd /mnt; dd if=$TAPE | $_xcmd ) done echo "Extraction complete." } set_timezone() { local _zoneroot=/mnt/usr/share/zoneinfo/ _zonepath # If the timezone directory structure is not # available, return immediately. [ ! -d $_zoneroot ] && return cat << __EOT Select a time zone for your location. Timezones are represented on the system by a directory structure rooted in "/usr/share/timezone". Most timezones can be selected by entering a token like "CET" or "GMT-6". Other zones are grouped by continent or country, with detailed zone information separated by a slash ("/"), e.g. "US/Pacific" or "Canada/Mountain". __EOT if [ -L /mnt/etc/localtime ]; then TZ=`ls -l /mnt/etc/localtime 2>/dev/null | cutlast` TZ=${TZ#${_zoneroot#/mnt}} fi : ${TZ:=GMT} while : ; do _zonepath=$_zoneroot ask "What timezone are you in? ('?' for list)" "$TZ" if [ "$resp" = "?" ]; then ls -F ${_zonepath} continue; fi _zonepath=${_zonepath}${resp} while [ -d "$_zonepath" ]; do echo -n "Select a sub-timezone of " ask "'${_zonepath#$_zoneroot}' ('?' for list):" if [ "$resp" = "?" ]; then ls -F ${_zonepath} else _zonepath=${_zonepath}/${resp} fi done if [ -f "$_zonepath" ]; then TZ=${_zonepath#$_zoneroot} echo "You have selected timezone '$TZ'". ln -sf /usr/share/zoneinfo/$TZ /mnt/etc/localtime return fi echo -n "'${_zonepath#$_zoneroot}'" echo " is not a valid timezone on this system." done } sane_install() { if [ ! -s /mnt/bsd ]; then cat << __EOT Warning, no kernel (/mnt/bsd) installed! You did not unpack a file set containing a kernel -- this is needed to boot. Please note that the install kernel is *not* suitable for general use. __EOT elif [ ! -f /mnt/bin/cat ]; then cat << __EOT You still do not have a /bin/cat in your filesystem (i.e. a sample random file which you probably want). This seems to indicate that you are still missing important distribution files. __EOT elif [ ! -x /mnt/dev/MAKEDEV ]; then cat << __EOT No /dev/MAKEDEV has been installed yet. __EOT elif [ ! -d /mnt/etc -o ! -d /mnt/usr/share/zoneinfo -o ! -d /mnt/dev ]; then cat << __EOT One or more of /etc, /usr/share/zoneinfo or /dev is missing. Did you forget to extract a required set? __EOT else return 0 fi cat << __EOT You will now be given the chance to install the missing set(s). You can enter '!' at the prompt to escape to a shell and fix things by hand if you wish. __EOT return 1 } # Ask the user for locations of sets, and then install whatever sets the # user selects from that location. Repeat as many times as the user # needs to get all desired sets. install_sets() { cat << __EOT You will now be asked for the location of the ${MODE} sets you want to use, and then which sets to actually use. These steps will repeat until you are satisfied that all the sets you want have been loaded. Thus you will be able to load sets from multiple locations, and you can recover from some errors. __EOT while : ; do cat << __EOT Sets can be located on a (m)ounted filesystem (c)drom, (d)isk or (t)ape device (f)tp, (n)fs or (h)ttp server __EOT ask "Where are the ${MODE} sets you want to use? (m, c, f, etc.)" case $resp in c*|C*) install_cdrom ;; d*|D*) install_disk ;; f*|F*) install_url ftp ;; h*|H*) install_url http ;; m*|M*) install_mounted_fs /mnt ;; n*|N*) install_nfs ;; t*|T*) install_tape ;; *) echo "Invalid response: $resp" ;; esac # Give the user the opportunity to extract more sets. ask "\nExtract more sets?" n case $resp in n*|N*) # Perform sanity checks... sane_install && break ask "\nDo you want to extract more sets?" y case $resp in n*|N*) break ;; esac ;; esac done } # Create a /etc/fstab from /tmp/fstab. Ensure /etc/fstab # 1) contains only ffs filesystems # 2) contains only filesystems without the 'noauto' option # 3) contains no 'softdep' options # 4) mounts all filesystems relative to /mnt # # If no /etc/fstab is created, do not proceed with install/upgrade. munge_fstab() { local _dev _mp _fstype _opt _rest while read _dev _mp _fstype _opt _rest; do # Skip comment lines. case $_dev in \#*) continue ;; esac # Skip noauto filesystems. case $_opt in *noauto*) continue ;; esac # Skip filesystems we can't mount. [ -f "/sbin/mount_${_fstype}" ] || continue # Remove any softdep options, as soft updates are not # available in the ramdisk kernels. _opt="$(echo ${_opt} | \ sed -e 's/^softdep$//; s/^softdep,//; s/,softdep,/,/; s/,softdep$//;')" # Mount non-ffs filesystems read-only [ "$_fstype" = "ffs" ] || \ _opt="$(echo ${_opt} | \ sed -e 's/^rw$/ro/; s/^rw,/ro,/; s/,rw,/,ro,/; s/,rw$/,ro/')" # Avoid '/mnt/' in root fs entry in munged fstab [ "$_mp" = "/" ] && _mp= # Write fs entry in fstab. echo $_dev /mnt$_mp $_fstype $_opt $_rest done < /tmp/fstab > /etc/fstab # If no /etc/fstab was created, we have nowhere to ${MODE} to. if [ ! -s /etc/fstab ]; then echo "Unable to create valid /etc/fstab." exit fi } # Must mount filesystems manually, one at a time, so we can make # sure the mount points exist. mount_fs() { local _async=$1 _dev _mp _fstype _opt _rest while read _dev _mp _fstype _opt _rest; do # If not the root filesystem, make sure the mount # point is present. [ "$_mp" = "/mnt" ] || mkdir -p $_mp # Mount the filesystem. If the mount fails, exit. if ! mount -v -t $_fstype $_async -o $_opt $_dev $_mp ; then # In addition to the error message displayed by mount ... cat << __EOT FATAL ERROR: Cannot mount filesystems. Double-check your configuration and restart the ${MODE}. __EOT exit fi done < /etc/fstab } # Script is exiting. Clean up as much as possible. cleanup_on_exit() { echo "\nCleaning up..." # Kill any running dhclient, so a restart will not # find /dev/bpf0 busy. if [ -f /var/run/dhclient.pid ]; then echo "Stopping dhclient" kill -HUP `sed -ne "1p" /var/run/dhclient.pid` > /dev/null 2>&1 rm -f /var/run/dhclient.pid fi if [ -f /etc/fstab ]; then umount -av elif [ ! "`df /`" = "`df /mnt`" ]; then umount -v /mnt fi echo "Done." } # Remount all filesystems in /etc/fstab with the options from # /etc/fstab, i.e. without any options such as async which # may have been used in the first mount. remount_fs() { local _dev _mp _fstype _opt _rest while read _dev _mp _fstype _opt _rest; do mount -u -o $_opt $_dev $_mp || exit done < /etc/fstab } # Preen all filesystems in /etc/fstab that have a /sbin/fsck_XXX, # showing individual results, but skipping $ROOTDEV. This was already # fsck'ed successfully. # # Exit if any fsck's fail (but do them all before exiting!). check_fs() { local _dev _mp _fstype _rest _badfsck=0 _root=$1 echo "Checking non-root filesystems..." while read _dev _mp _fstype _rest; do [ "$_dev" != "$_root" ] || continue [ -f "/sbin/fsck_$_fstype" ] || continue echo -n "fsck -p ${_dev}..." if ! fsck -fp ${_dev} > /dev/null 2>&1; then echo "FAILED. You must fsck this device manually." _fail=y else echo "OK." fi done < /etc/fstab echo "...Done." [ "$_fail" ] && exit } # Find LAST instance of DOMAIN or SEARCH and extract first domain name # on that line as FQDN. Then ask user, just to be sure. # $1 = resolv.conf file to search for FQDN # $2 = hosts file to add FQDN information to get_fqdn() { if [ -f "$1" ]; then FQDN=`sed -n \ -e '/^domain[[:space:]][[:space:]]*/{s///;s/\([^[:space:]]*\).*$/\1/;h;}' \ -e '/^search[[:space:]][[:space:]]*/{s///;s/\([^[:space:]]*\).*$/\1/;h;}' \ -e '${g;p;}' $1` fi if [ -f "$2" -a -n "$FQDN" ]; then # Add FQDN to hosts file entries created by addhostent, changing # lines like # 1.2.3.4 hostname # to # 1.2.3.4 hostname.$FQDN hostname sed "s/\\(.*\\)[[:space:]]\\(.*\\)\$/\\1 \\2.$FQDN \\2/" $2 > $2.new mv $2.new $2 else ask "Enter DNS domain name (e.g. 'bar.com'):" "$FQDN" FQDN=$resp fi } donetconfig() { local _nam [ "$DIDNET" ] && return DIDNET=y _nam= [ -f /tmp/myname ] && _nam=`cat /tmp/myname` ask_until "Enter system hostname (short form, e.g. 'foo'):" "$_nam" hostname $resp echo $resp > /tmp/myname # Always create new hosts file. If install.sh has been # restarted, an existing one may contain information which # will conflict with the information about to be entered. # Also ensures logic to put FQDN in hosts file will create # hosts file lines in correct format. echo "::1 localhost\n127.0.0.1 localhost" > /tmp/hosts # Remove any existing hostname.* files. If install.sh has # been restarted, this ensures a correct list of configured # interfaces is displayed, and gives the user a chance to # change which interfaces are to be configured. rm -f /tmp/hostname.* # Revoke any previous decision on whether or not to use # a nameserver during installation. rm -f /tmp/resolv.conf.shadow cat << __EOT If any interfaces will be configured using a DHCP server it is recommended that you do not enter a DNS domain name, a default route, or any name servers. __EOT FQDN= get_fqdn /tmp/resolv.conf configure_all_interfaces # As dhclient will populate /etc/resolv.conf, a symbolic link to # /tmp/resolv.conf.shadow, mv any such file to /tmp/resolv.conf # so it will eventually be copied to /mnt/etc/resolv.conf and will # not in the meantime remove the user's ability to choose to use it # or not, during the rest of the install. if [ -f /tmp/resolv.conf.shadow ]; then mv /tmp/resolv.conf.shadow /tmp/resolv.conf fi # Get any DHCP supplied FQDN, and in any case apply FQDN to # the host names in /tmp/hosts, all without asking for any more # user confirmation. This means DHCP supplied information will # override a user supplied (or previous DHCP supplied) FQDN. get_fqdn /tmp/resolv.conf /tmp/hosts # Also add FQDN to myname if [ "$FQDN" ]; then sed "s/\\(.*\\)\$/\\1.${FQDN}/" /tmp/myname > /tmp/myname.new mv /tmp/myname.new /tmp/myname fi resp=`route -n show | sed -ne '/^default */{ s/// s/ .*// p }'` if [ -z "$resp" ] ; then resp=none if [ -f /tmp/mygate ]; then resp=`cat /etc/mygate` : ${_resp:=none} fi fi ask "Enter IP address of default route:" "$resp" if [ "$resp" != "none" ]; then route delete default > /dev/null 2>&1 if route add default $resp > /dev/null ; then echo $resp > /tmp/mygate fi fi resp=none if [ -f /tmp/resolv.conf ]; then resp= for n in `sed -ne '/^nameserver /s///p' /tmp/resolv.conf` do if [ -z "$resp" ] ; then resp=$n else resp="$resp $n" fi done fi ask "Enter IP address of primary nameserver:" "$resp" if [ "$resp" != "none" ]; then echo "search $FQDN" > /tmp/resolv.conf for n in `echo ${resp}`; do echo "nameserver $n" >> /tmp/resolv.conf done echo "lookup file bind" >> /tmp/resolv.conf ask "Would you like to use the nameserver now?" y case $resp in y*|Y*) cp /tmp/resolv.conf /tmp/resolv.conf.shadow ;; esac fi if [ ! -f /tmp/resolv.conf.shadow ]; then echo "\nThe host table is as follows:\n" cat /tmp/hosts cat << __EOT You may want to edit the host table in the event that you are doing an NFS installation or an FTP installation without a name server and want to refer to the server by name rather than by its numeric ip address. __EOT ask "Would you like to edit the host table with ${EDITOR}?" n case $resp in y*|Y*) ${EDITOR} /tmp/hosts ;; esac fi cat << __EOT You will now be given the opportunity to escape to the command shell to do any additional network configuration you may need. This may include adding additional routes, if needed. In addition, you might take this opportunity to redo the default route in the event that it failed above. __EOT ask "Escape to shell?" n case $resp in y*|Y*) echo "Type 'exit' to return to install." sh ;; esac } populateusrlocal() { if [ -f /mnt/etc/mtree/BSD.local.dist ]; then /mnt/usr/sbin/chroot /mnt /usr/sbin/mtree -Uedqn -p /usr/local -f /etc/mtree/BSD.local.dist >/dev/null fi } set_machdep_apertureallowed() { [ "$MDXAPERTURE" ] || return ask "\nDo you expect to run the X Window System?" y case $resp in y*|Y*) sed -e "/^#\(machdep\.allowaperture=${MDXAPERTURE}\)/s//\1 /" \ /mnt/etc/sysctl.conf > /tmp/sysctl.conf echo "machdep.allowaperture enabled in /etc/sysctl.conf. Read xf86(4) for details." ;; esac } finish_up() { set_timezone echo -n "Making all device nodes (by running /dev/MAKEDEV all) ..." cd /mnt/dev sh MAKEDEV all echo "... done." cd / md_installboot $ROOTDISK populateusrlocal # XXXXX - what is this for? [ -x /mnt/${MODE}.site ] && /mnt/usr/sbin/chroot /mnt /${MODE}.site # Unmount filesystems, etc. Disable trap that would do same on exit. # Do this manually rather than through the trap so congrats is # the last message printed. trap - HUP INT QUIT TERM EXIT cleanup_on_exit # Pat on the back. cat << __EOT CONGRATULATIONS! Your OpenBSD ${MODE} has been successfully completed! To boot the new system, enter halt at the command prompt. Once the system has halted, reset the machine and boot from the disk. __EOT md_congrats } # ####################################################################### # # Initial actions common to both installs and upgrades. # # Some may require machine dependent routines, which may # call functions defined above, so it's safest to put this # code here rather than at the top of the file. # # ####################################################################### ROOTDISK= ROOTDEV= VERSION=31 VERSION_MAJOR=$(( $VERSION / 10 )) VERSION_MINOR=$(( $VERSION % 10 )) export VERSION VERSION_MAJOR VERSION_MINOR # Extract and save one boot's worth of dmesg dmesg | sed -ne '/^OpenBSD /h;/^OpenBSD /!H;${g;p;}' > /var/run/dmesg.boot # Scan /var/run/dmesg.boot for disks and cds DKDEVS=`get_dkdevs` CDDEVS=`get_cddevs` IFDEVS=`get_ifdevs` # extra "site" set can be provided by person doing install or upgrade. THESETS="base etc misc comp man game xbase xshare xfont xserv site $MDSETS" # Global variable using during sets installation SETS= SETSDIR= SETSDONE= GET_FILES= # decide upon an editor if [ -z "$EDITOR" ] ; then EDITOR=ed [ -x /usr/bin/vi ] && EDITOR=vi export EDITOR fi # Cleanup when the script exits. trap 'cleanup_on_exit' EXIT trap 'exit 2' HUP INT QUIT TERM # Good {morning,afternoon,evening,night}. welcome_banner | more if [ -f /etc/fstab -a "$MODE" = "install" ]; then cat << __EOT You seem to be trying to restart an interrupted installation! You can skip the disk preparation steps and continue, or you can reboot and start over. __EOT echo -n "Skip disk initialization and p" else echo -n "\nP" fi ask "roceed with ${MODE}?" n case $resp in y*|Y*) echo "\nCool! Let's get to it...\n" ;; *) cat << __EOT Enter 'halt' at the prompt to gracefully exit OpenBSD. You can then power cycle the machine and boot your original OS. __EOT exit ;; esac # Deal with terminal issues set_term