1# $OpenBSD: install.sub,v 1.638 2011/04/18 16:52:10 thib Exp $ 2# $NetBSD: install.sub,v 1.5.2.8 1996/09/02 23:25:02 pk Exp $ 3# 4# Copyright (c) 1997-2009 Todd Miller, Theo de Raadt, Ken Westerback 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26# 27# Copyright (c) 1996 The NetBSD Foundation, Inc. 28# All rights reserved. 29# 30# This code is derived from software contributed to The NetBSD Foundation 31# by Jason R. Thorpe. 32# 33# Redistribution and use in source and binary forms, with or without 34# modification, are permitted provided that the following conditions 35# are met: 36# 1. Redistributions of source code must retain the above copyright 37# notice, this list of conditions and the following disclaimer. 38# 2. Redistributions in binary form must reproduce the above copyright 39# notice, this list of conditions and the following disclaimer in the 40# documentation and/or other materials provided with the distribution. 41# 42# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 43# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 44# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 45# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 46# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 47# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 48# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 49# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 50# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 51# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 52# POSSIBILITY OF SUCH DAMAGE. 53# 54 55# OpenBSD install/upgrade script common subroutines and initialization code 56 57# Include machine-dependent functions and definitions. 58# 59# The following functions must be provided: 60# md_congrats() - display friendly message 61# md_installboot() - install boot-blocks on disk 62# md_prep_disklabel() - put an OpenBSD disklabel on the disk 63# md_consoleinfo() - set CDEV, CTTY, CSPEED, CPROM 64# 65# The following variables can be provided if required: 66# MDSETS - list of files to add to THESETS 67# MDTERM - 'vt220' assumed if not provided 68# MDDKDEVS - '/^[sw]d[0-9][0-9]* /s/ .*//p' assumed if not provided 69# MDCDDEVS - '/^cd[0-9][0-9]* /s/ .*//p' assumed if not provided 70# MDMTDEVS - '/^[cms]t[0-9][0-9]* /s/ .*//p' 71# MDXAPERTURE - set machdep.allowaperture=value in sysctl.conf 72. install.md 73 74set_term() { 75 local _layouts 76 77 export TERM=${TERM:-${MDTERM:-vt220}} 78 if [[ -n $CONSOLE ]]; then 79 ask "Terminal type?" $TERM 80 export TERM=$resp 81 else 82 [[ -x /sbin/kbd ]] || return 83 _layouts=$(bsort $(kbd -l | egrep -v "^(user|tables|encoding)")) 84 while :; do 85 ask "Choose your keyboard layout ('?' or 'L' for list)" "default" 86 case $resp in 87 "?"|L|l) echo "Available layouts: $_layouts" ;; 88 default) return ;; 89 *) kbd $resp && { echo $resp >/tmp/kbdtype ; return ; } ;; 90 esac 91 done 92 fi 93} 94 95# Echo the file $1 to standard output, skipping any lines that begin with a 96# '#'. i.e. strip comment lines from the file. 97stripcom () { 98 local _l 99 100 [[ -f $1 ]] || return 101 102 while read _l; do 103 [[ -n ${_l%%#*} ]] && echo $_l 104 done <$1 105} 106 107# Prints the supplied parameters properly escaped for future sh/ksh parsing. 108# Quotes are added if needed, so you should not do that yourself. 109quote() ( 110 # Since this is a subshell we won't pollute the calling namespace 111 for a; do 112 alias Q=$a; a=$(alias Q); print -rn -- " ${a#Q=}" 113 done | sed '1s/ //' 114 echo 115) 116 117scan_dmesg() { 118 bsort $(sed -ne "$1" /var/run/dmesg.boot) 119} 120 121scan_disknames() { 122 local _n _oifs=$IFS 123 IFS="," 124 bsort $(for _n in $(sysctl -n hw.disknames); do echo "${_n%%:*} "; done | sed -ne "$1") 125 IFS=$_oifs 126} 127 128get_dkdevs () { 129 echo $(scan_disknames "${MDDKDEVS:-/^[sw]d[0-9][0-9]* /s/ .*//p}") 130} 131 132get_cddevs () { 133 echo $(scan_disknames "${MDCDDEVS:-/^cd[0-9][0-9]* /s/ .*//p}") 134} 135 136get_ifdevs() { 137 ifconfig "$@" 2>&- \ 138 | egrep -v '^[[:space:]]|(bridge|enc|gif|gre|lo|pflog|pfsync|ppp|sl|tun)[[:digit:]]+:' \ 139 | sed -ne 's/^\(.*\):.*/\1/p' 140} 141 142get_drive() { 143 ask_which "$1" "contains the $MODE media" "$2" "$3" 144 [[ $resp == done ]] && return 1 145 makedev $resp || return 1 146 return 0 147} 148 149mount_mnt2() { 150 local _dev=$1 _opts _file=/tmp/parts.$1 _parts 151 152 disklabel $_dev 2>/dev/null | grep '^ [a-p]: ' \ 153 | egrep -v "swap|unused" >$_file 154 155 _parts=$(sed -e 's/^ \(.\): .*/\1/' $_file) 156 set -- $_parts 157 [[ $# == 0 ]] && { echo "No filesystems found on $_dev." ; return 1 ; } 158 159 if isin "c" $_parts; then 160 # Don't ask questions if 'c' contains a filesystem. 161 resp=c 162 elif [[ $# == 1 ]]; then 163 # Don't ask questions if there's only one choice. 164 resp=$1 165 else 166 # Display partitions with filesystems and ask which to use. 167 cat /tmp/parts.$_dev 168 ask_which "$_dev partition" "has the $MODE sets" \ 169 '$(disklabel '$_dev' 2>/dev/null | grep "^ [a-p]: " | 170 egrep -v "swap|unused" | 171 sed '\''s/^ \(.\): .*/\1/'\'')' 172 [[ $resp == done ]] && return 1 173 fi 174 175 # Always mount msdos partitions with -s to get lower case names. 176 grep -q "^ $resp: .*MSDOS" $_file && _opts="-s" 177 mount -o ro,$_opts /dev/$_dev$resp /mnt2 178} 179 180# Ask for a password, saving the input in $resp. 181# Display $1 as the prompt. 182# *Don't* allow the '!' options that ask does. 183# *Don't* echo input. 184# *Don't* interpret "\" as escape character. 185askpass() { 186 set -o noglob 187 stty -echo 188 read -r resp?"$1 " 189 stty echo 190 set +o noglob 191 echo 192} 193 194# Make sure lock is initially released 195rm -df /tmp/lock 196 197# Acquire lock 198lock() { 199 while ! mkdir /tmp/lock 2>&- && sleep .1; do done 200} 201 202# Release lock 203unlock() { 204 rm -d /tmp/lock 2>&- 205} 206 207# Add trap to kill the listener process 208retrap() { 209 trap '>&- && kill -KILL $cppid 2>&-; echo; stty echo; exit 0' \ 210 INT EXIT TERM 211} 212 213# The dmesg listener will check for the existance of this file and send a 214# signal to the child process if the dmesg output differs from the contents 215# of that file 216rm -f /tmp/update 217 218# Start listener process looking for dmesg changes 219( 220 while :; do 221 lock 222 if test -e /tmp/update && [[ "`dmesg`" != "`cat /tmp/update`" ]]; then 223 dmesg >/tmp/update 224 kill -TERM 2>&- $$ || exit 1 225 fi 226 unlock 227 sleep .5 228 done 229) |& 230cppid=$! 231 232# Kill the child on exit 233retrap 234 235# Issue a read into the global variable $resp. If the dmesg output is 236# changed while inside this function, the current read will be aborted 237# and the function will return a non-zero value. Normally, the caller 238# will then reprint any prompt and call the function again. 239_ask() { 240 local _int _redo=0 _pid 241 242 trap "_int=1" INT 243 trap "_redo=1" TERM 244 lock; dmesg >/tmp/update; unlock 245 read resp 246 lock; rm /tmp/update; unlock 247 if (( _redo )); then 248 stty raw 249 stty -raw 250 else 251 case $resp in 252 !) echo "Type 'exit' to return to install." 253 sh 254 _redo=1 255 ;; 256 !*) eval "${resp#?}" 257 _redo=1 258 ;; 259 esac 260 fi 261 retrap 262 (( _int )) && kill -INT $$ 263 return $_redo 264} 265 266# Ask for user input. 267# 268# $1 = the question to ask the user 269# $2 = the default answer 270# 271# Save the user input (or the default) in $resp. 272# 273# Allow the user to escape to shells ('!') or execute commands 274# ('!foo') before entering the input. 275ask() { 276 local _question=$1 _default=$2 277 278 while :; do 279 echo -n "$_question " 280 [[ -z $_default ]] || echo -n "[$_default] " 281 _ask && : ${resp:=$_default} && break 282 done 283} 284 285# Ask for a password twice, saving the input in $_password 286askpassword() { 287 local _oifs=$IFS 288 IFS= 289 while :; do 290 askpass "Password for $1 account? (will not echo)" 291 _password=$resp 292 293 askpass "Password for $1 account? (again)" 294 # N.B.: Need quotes around $resp and $_password to preserve leading 295 # or trailing spaces. 296 [[ "$resp" == "$_password" ]] && break 297 298 echo "Passwords do not match, try again." 299 done 300 IFS=$_oifs 301} 302 303user_setup() { 304 local _q="Setup a user? (enter a lower-case loginname, or 'no')" 305 306 while :; do 307 ask "$_q" no 308 case $resp in 309 n|no) return ;; 310 y|yes) _q="No really, what is the lower-case loginname, or 'no'?" 311 continue ;; 312 root|daemon|operator|bin|smmsp|popa3d) ;; 313 sshd|uucp|www|named|proxy|nobody|ftp) ;; 314 [a-z]*([a-z0-9_])) 315 (( ${#resp} <= 31 )) && break ;; 316 esac 317 echo "$resp is not a useable loginname." 318 done 319 user=$resp 320 while :; do 321 ask "Full user name for $user?" $user 322 case $resp in 323 *[:\&,]*) 324 echo "':', '&' or ',' are not allowed." ;; 325 *) 326 (( ${#resp} <= 100 )) && break 327 echo "Too long." ;; 328 esac 329 done 330 username=$resp 331 332 askpassword $user 333 userpass=$_password 334 335 if [[ $sshd == y ]]; then 336 ask_yn "Since you set up a user, disable sshd(8) logins to root?" yes 337 sshd_disableroot=$resp 338 fi 339 340} 341 342# Ask for user input until a non-empty reply is entered. 343# 344# $1 = the question to ask the user 345# $2 = the default answer 346# 347# Save the user input (or the default) in $resp. 348ask_until() { 349 resp= 350 while [[ -z $resp ]] ; do 351 ask "$1" "$2" 352 done 353} 354 355# Ask the user for a y or n, and insist on 'y', 'yes', 'n' or 'no'. 356# 357# $1 = the question to ask the user 358# $2 = the default answer (assumed to be 'n' if empty). 359# 360# Return 'y' or 'n' in $resp. 361ask_yn() { 362 local _q=$1 _a=${2:-no} _resp 363 typeset -l _resp 364 365 while :; do 366 ask "$_q" "$_a" 367 _resp=$resp 368 case $_resp in 369 y|yes) resp=y ; return ;; 370 n|no) resp=n ; return ;; 371 esac 372 done 373} 374 375# Ask for the user to select one value from a list, or 'done'. 376# 377# $1 = name of the list items (disk, cd, etc.) 378# $2 = question to ask 379# $3 = list of valid choices 380# $4 = default choice, if it is not specified use the first item in $3 381# 382# N.B.! $3 and $4 will be "expanded" using eval, so be sure to escape them 383# if they contain spooky stuff 384# 385# At exit $resp holds selected item, or 'done' 386ask_which() { 387 local _name=$1 _query=$2 _list=$3 _def=$4 _dynlist _dyndef 388 389 while :; do 390 # Put both lines in ask prompt, rather than use a 391 # separate 'echo' to ensure the entire question is 392 # re-ask'ed after a '!' or '!foo' shell escape. 393 eval "_dynlist=\"$_list\"" 394 eval "_dyndef=\"$_def\"" 395 396 # Clean away whitespace and determine the default 397 set -o noglob 398 set -- $_dyndef; _dyndef="$1" 399 set -- $_dynlist; _dynlist="$*" 400 set +o noglob 401 (( $# < 1 )) && resp=done && return 402 403 : ${_dyndef:=$1} 404 echo "Available ${_name}s are: $_dynlist." 405 echo -n "Which one $_query? (or 'done') " 406 [[ -n $_dyndef ]] && echo -n "[$_dyndef] " 407 _ask || continue 408 [[ -z $resp ]] && resp="$_dyndef" 409 410 # Quote $resp to prevent user from confusing isin() by 411 # entering something like 'a a'. 412 isin "$resp" $_dynlist done && break 413 echo "'$resp' is not a valid choice." 414 done 415} 416 417# test the first argument against the remaining ones, return success on a match 418isin() { 419 local _a=$1 _b 420 421 shift 422 for _b; do 423 [[ $_a == $_b ]] && return 0 424 done 425 return 1 426} 427 428# add first argument to list formed by the remaining arguments 429# adds to the tail if the element does not already exist 430addel() { 431 local _a=$1 432 433 shift 434 435 echo -n "$*" 436 isin "$_a" $* || echo -n " $_a" 437} 438 439# remove all occurrences of first argument from list formed by 440# the remaining arguments 441rmel() { 442 local _a=$1 _b 443 444 shift 445 for _b; do 446 [[ $_a != $_b ]] && echo -n "$_b " 447 done 448} 449 450bsort() { 451 local _l _a=$1 _b 452 453 [[ $# -gt 0 ]] || return 454 455 shift 456 for _b; do 457 if [[ $_a != $_b ]] ; then 458 if [[ $_a > $_b ]] ; then 459 _l="$_a $_l"; _a=$_b 460 else 461 _l="$_b $_l" 462 fi 463 fi 464 done 465 466 # Output the smallest value found. 467 echo -n "$_a " 468 469 # Sort remaining values. 470 bsort $_l 471} 472 473# show a list (passed via ordered arguments) in column output using ls 474showcols() { 475 local _l _cdir=/tmp/cdir 476 set -A _clist 477 mkdir -p $_cdir 478 rm -rf -- $_cdir/* 479 while read _l; do 480 [ "$_l" ] || continue 481 mkdir -p /tmp/cdir/"$_l" 482 _clist[${#_clist[*]}]="$_l" 483 done 484 (cd $_cdir; ls -Cdf "${_clist[@]}") 485 rm -rf -- $_cdir 486} 487 488# Offer to shell out for manual network configuration, and do so if 489# the user accepts the offer. 490manual_net_cfg() { 491 ask_yn "Do you want to do any manual network configuration?" 492 493 [[ $resp == y ]] && { echo "Type 'exit' to return to $MODE." ; sh ; } 494} 495 496# Create a device. 497# 498# $1 = name of the device to create. 499makedev() { 500 local _dev=$1 501 502 if [[ ! -r /dev/MAKEDEV ]] ; then 503 echo "MAKEDEV not found. Can't create device nodes." 504 return 1 505 fi 506 507 (cd /dev && sh MAKEDEV "$_dev") >/dev/null 2>&1 508} 509 510# Create an entry in the hosts file. If an entry with the 511# same symbolic name and address family already exists, delete it. 512# $1 - IP address (v6 if it contains ':', else v4) 513# $2 - symbolic name 514addhostent() { 515 local _addr=$1 _name=$2 _delim="." 516 517 [[ -z $_addr || -z $_name ]] && return 518 519 [[ $_addr == *:* ]] && _delim=":" 520 521 sed "/^[0-9a-fA-F]*[$_delim].*[ ]$_name\$/d" /tmp/hosts \ 522 >/tmp/hosts.new 2>/dev/null 523 mv /tmp/hosts.new /tmp/hosts 524 525 echo "$_addr $_name" >>/tmp/hosts 526} 527 528# Show list of available sets and let the user select which sets to install. 529# 530# $1 = available sets 531# $2 = already selected sets 532# 533# Set $resp to list of selected sets. 534select_sets() { 535 local _avail=$1 _selected=$2 _f _action _col=$COLUMNS 536 # account for 4 spaces added to the sets list 537 let COLUMNS=_col-8 538 539 cat <<__EOT 540 541Select sets by entering a set name, a file name pattern or 'all'. De-select 542sets by prepending a '-' to the set name, file name pattern or 'all'. Selected 543sets are labelled '[X]'. 544__EOT 545 while :; do 546 for _f in $_avail; do 547 isin $_f $_selected && echo "[X] $_f" || echo "[ ] $_f" 548 done | showcols | sed 's/^/ /' 549 ask "Set name(s)? (or 'abort' or 'done')" done 550 551 set -o noglob 552 for resp in $resp; do 553 case $resp in 554 abort) _selected=; break 2 ;; 555 done) break 2 ;; 556 -*) _action=rmel ;; 557 *) _action=addel ;; 558 esac 559 resp=${resp#[+-]} 560 [[ $resp = all ]] && resp=* 561 562 for _f in $_avail; do 563 [[ $_f = $resp ]] && _selected=$($_action $_f $_selected) 564 done 565 done 566 done 567 568 set +o noglob 569 COLUMNS=$_col 570 571 resp=$_selected 572} 573 574configure_ifs() { 575 local _first _ifdevs _ifs _name _hn _vl=0 _vd _vi _p _tags 576 577 # In case of restart, discover last vlan configured. 578 while :; do 579 _vd=$(ifconfig vlan$_vl 2>&1) 580 [[ $_vd == @(*no such interface*) ]] && break 581 [[ $_vd == @(vlan$_vl: flags=0<>*) ]] && break 582 : $(( _vl++ )) 583 done 584 _vd= 585 586 while :; do 587 # Create new vlan if possible. 588 ifconfig vlan$_vl create >/dev/null 2>&1 589 ask_which "network interface" "do you wish to configure" \ 590 '$(get_ifdevs)' \ 591 ${_p:-'$( (ifconfig netboot 2>/dev/null | sed -n '\''1s/:.*//p'\''; get_ifdevs) | sed q )'} 592 [[ $resp == done ]] && break 593 594 _ifs=$resp 595 _hn=/tmp/hostname.$_ifs 596 rm -f $_hn 597 598 # If the offered vlan is chosen, ask the relevant 599 # questions and bring it up 600 if [[ $_ifs == vlan[0-9]* ]]; then 601 # Get existing tag for this vlan. 602 _vi=$(ifconfig $_ifs 2>/dev/null | \ 603 sed -n 's/vlan: \([0-9]*\).*/\1/p') 604 # Get list of all in-use tags. 605 _tags=$(ifconfig vlan 2>/dev/null | \ 606 sed -n 's/vlan: \([0-9]*\).*/\1/p') 607 # Current tag is a valid tag for this vlan. 608 [[ -n $_tags ]] && _tags=$(rmel "$_vi" $_tags) 609 if [[ -z $_vi ]]; then 610 _vi=0 611 while (( (_vi += 1) < 4096 )); do 612 ! isin "$_vi" $_tags && break 613 done 614 fi 615 _ifdevs=$(get_ifdevs) 616 set -- $_ifdevs 617 while [[ $1 == vlan[0-9]* ]]; do 618 shift 619 done 620 ask "Which interface:tag should $_ifs be on?" "${_vd:=$1}:$_vi" 621 _vd=${resp%%:*} 622 _vi=${resp##*:} 623 624 # Validate that $_vd is a real interface 625 if ! (isin "$_vd" $_ifdevs && [[ $_vd != vlan[0-9]* ]]); then 626 echo "Invalid interface choice '$_vd'" 627 _vd= 628 continue 629 fi 630 631 # Validate range of $_vi as 1-4095, and $_vi not in use. 632 if (( _vi < 1 || _vi > 4095 )) || isin "$_vi" $_tags; then 633 echo "Invalid or in-use vlan tag '$_vi'" 634 continue 635 fi 636 637 # hostname.$_vd must say something, anything, to 638 # make sure it is up. 639 grep -qs "^up" /tmp/hostname.$_vd || \ 640 echo "up" >>/tmp/hostname.$_vd 641 ifconfig $_vd up 642 643 # Make sure a hostname.$_ifs is created with this info. 644 ifconfig $_ifs destroy >/dev/null 2>&1 645 ifconfig $_ifs vlan $_vi vlandev $_vd 646 echo "vlan $_vi vlandev $_vd" >>$_hn 647 # Create a new vlan if we just configured the highest. 648 [[ ${_ifs##vlan} == $_vl ]] && (( _vl += 1 )) 649 fi 650 651 # Test if it is an 802.11 interface 652 ifconfig $_ifs 2>&- | grep -q "^[[:space:]]*ieee80211:" && 653 ieee80211_config $_ifs $_hn 654 655 # First interface configured will use the hostname without 656 # asking the user. 657 resp=$(hostname -s) 658 [[ -n $_first && $_first != $_ifs ]] && \ 659 ask "Symbolic (host) name for $_ifs?" $resp 660 _name=$resp 661 662 v4_config $_ifs $_name $_hn 663 v6_config $_ifs $_name $_hn 664 665 if [[ -f $_hn ]]; then 666 chmod 640 $_hn 667 (( nifs += 1 )) 668 : ${_first:=$_ifs} 669 _p=done 670 fi 671 done 672} 673 674# Output '<UP | DOWN> [<addr> <netmask> <rest of inet line>]'. 675# 676# $1 == interface 677v4_info() { 678 ifconfig $1 inet | sed -n ' 679 1s/.*<UP,.*/UP/p 680 1s/.*<.*/DOWN/p 681 /inet/s/netmask// 682 /inet/s///p' 683} 684 685# Obtain and output the inet6 information related to the given 686# interface. Should output '<UP/DOWN> <addr> <prefixlen> <rest of inet line> '. 687# 688# $1 == interface 689v6_info() { 690 ifconfig $1 inet6 | sed -n ' 691 1s/.*<UP,.*/UP/p 692 1s/.*<.*/DOWN/p 693 /scopeid/d 694 /inet6/s///p' 695} 696 697# Construct etc/dhclient.conf and issue DHCP request. Return FALSE if 698# no IP address assigned to $1. 699# 700# $1 == interface 701# $2 == hostname (optional). 702dhcp_request() { 703 local _ifs=$1 _hn=$2 704 705 echo "lookup file bind" >/etc/resolv.conf.tail 706 707 if [[ -n $_hn ]]; then 708 _hn="send host-name \"$_hn\";" 709 echo "Issuing hostname-associated DHCP request for $_ifs." 710 else 711 echo "Issuing free-roaming DHCP request for $_ifs." 712 fi 713 714 cat >/etc/dhclient.conf <<__EOT 715initial-interval 1; 716$_hn 717request subnet-mask, broadcast-address, routers, domain-name, 718 domain-name-servers, host-name; 719__EOT 720 721 ifconfig $_ifs group dhcp >/dev/null 2>&1 722 dhclient $_ifs 723 724 set -- $(v4_info $_ifs) 725 726 if [[ $1 == UP && -n $2 ]]; then 727 # Move configuration files to where they will be copied to the 728 # installed system. Overwrites configuration information from 729 # last successful dhcp attempt. 730 mv /etc/dhclient.conf /tmp/dhclient.conf 731 mv /etc/resolv.conf.tail /tmp/resolv.conf.tail 732 return 0 733 fi 734 735 ifconfig $_ifs delete down -group dhcp 2>&- 736 rm /etc/dhclient.conf /etc/resolv.conf.tail 737 return 1 738} 739 740# Convert a hex value to dotted decimal format 741hextodec() { 742 local _d _b 743 744 for _b in $(echo ${1#0x} | sed 's/\(..\)/\1 /g'); do 745 _d=$_d.$((0x$_b)) 746 done 747 echo ${_d#.} 748} 749 750# Perform an 802.11 interface network scan. 751# The result is cached in $WLANLIST 752# $1 == interface 753ieee80211_scan() { 754 # N.B. Skipping quoted nwid's for now 755 [[ -f $WLANLIST ]] || 756 ifconfig $1 scan | 757 sed -n 's/^ nwid \([^"]\)/\1/p' > $WLANLIST 758 cat $WLANLIST 759} 760 761# Configures an 802.11 interface 762# 763# $1 == interface 764# $2 == hostname 765ieee80211_config() { 766 local _ifs=$1 _hn=$2 _prompt _nwid _haswpa=0 _err 767 768 # Reset 802.11 settings and determine wpa capability 769 ifconfig $_ifs -nwid -nwkey 770 ifconfig $_ifs -wpa 2>&- && _haswpa=1 771 772 # Empty scan cache 773 rm -f $WLANLIST 774 775 while [[ -z $_nwid ]]; do 776 ask_until "Access point? (ESSID, 'any', list# or '?')" "any" 777 case "$resp" in 778 +([0-9])) 779 _nwid=$(ieee80211_scan $_ifs | sed -n "${resp}s/ .*//p") 780 [[ -z $_nwid ]] && echo "There is no line $resp." 781 ;; 782 \?) ieee80211_scan $_ifs | 783 sed -n 's/^\([^ ]*\) chan .* bssid \([^ ]*\) .*$/ \1 (\2)/p' | 784 less -XEN 785 ;; 786 *) _nwid=$resp ;; 787 esac 788 done 789 790 # 'any' implies that only open access points are considered 791 if [[ $_nwid != any ]]; then 792 ifconfig $_ifs nwid "$_nwid" 793 quote nwid "$_nwid" >>$_hn 794 795 _prompt="Security protocol? (O)pen, (W)EP" 796 [[ $_haswpa == 1 ]] && _prompt="$_prompt, WPA-(P)SK" 797 while :; do 798 ask_until "$_prompt" "O" 799 case "$_haswpa-$resp" in 800 ?-[Oo]) break 801 ;; 802 ?-[Ww]) ask_until "WEP key? (will echo)" 803 # Make sure ifconfig accepts the key 804 if _err=$(ifconfig $_ifs nwkey "$resp" 2>&1) && 805 [[ -z $_err ]]; then 806 quote nwkey "$resp" >>$_hn 807 break 808 fi 809 echo "$_err" 810 ;; 811 1-[Pp]) ask_until "WPA passphrase? (will echo)" 812 # Make sure ifconfig accepts the key 813 if ifconfig $_ifs wpakey "$resp"; then 814 quote wpakey "$resp" >>$_hn 815 break 816 fi 817 ;; 818 *) echo "'$resp' is not a valid choice." 819 ;; 820 esac 821 done 822 fi 823} 824 825v4_config() { 826 local _ifs=$1 _name=$2 _hn=$3 _prompt _addr _mask 827 828 if ifconfig $_ifs | grep 'groups:.* dhcp' >/dev/null 2>&1; then 829 _addr=dhcp 830 else 831 set -- $(v4_info $_ifs) 832 if [[ -n $2 ]]; then 833 _addr=$2; _mask=$(hextodec $3) 834 ifconfig $_ifs inet $_addr delete 835 fi 836 fi 837 838 if [[ -x /sbin/dhclient ]]; then 839 _prompt="or 'dhcp' " 840 # Don't make 'dhcp' the default if dhcp was already used. 841 ifconfig dhcp >/dev/null 2>&1 || _addr=dhcp 842 fi 843 _prompt="IPv4 address for $_ifs? (${_prompt}or 'none')" 844 845 ask_until "$_prompt" "$_addr" 846 case $resp in 847 none) ;; 848 dhcp) if [[ ! -x /sbin/dhclient ]]; then 849 echo "DHCP not possible - no /sbin/dhclient." 850 elif dhcp_request $_ifs "$_name" || dhcp_request $_ifs ; then 851 # Add hosts entry. Overwrites previous entry if any. 852 set -- $(v4_info $_ifs) 853 addhostent "$2" "$_name" 854 echo "dhcp" >>$_hn 855 # Create a new bpf in case we start another dhclient 856 makedev bpf$(ls /dev | grep -c "^bpf[0-9]") 857 fi 858 ;; 859 *) _addr=$resp 860 ask_until "Netmask?" "${_mask:=255.255.255.0}" 861 ifconfig $_ifs -group dhcp >/dev/null 2>&1 862 if ifconfig $_ifs inet $_addr netmask $resp up ; then 863 addhostent "$_addr" "$_name" 864 echo "inet $_addr $resp" >>$_hn 865 fi 866 ;; 867 esac 868} 869 870v6_config() { 871 local _ifs=$1 _name=$2 _hn=$3 _addr _prefixlen _prompt 872 873 ifconfig lo0 inet6 >/dev/null 2>&1 || return 874 875 set -- $(v6_info $_ifs) 876 [[ -n $2 ]] && { _addr=$2; _prefixlen=$3; } 877 878 [[ -x /sbin/rtsol ]] && _prompt="or 'rtsol' " 879 _prompt="IPv6 address for $_ifs? (${_prompt}or 'none')" 880 ask_until "$_prompt" "${_addr:-none}" 881 882 case $resp in 883 none) return 884 ;; 885 rtsol) [[ ! -x /sbin/rtsol ]] && { echo "No /sbin/rtsol." ; return ; } 886 ifconfig $_ifs up 887 if rtsol -F $_ifs; then 888 set -- $(v6_info $_ifs) 889 addhostent "$2" "$_name" 890 echo "up\nrtsol" >>$_hn 891 fi 892 return 893 ;; 894 esac 895 896 _addr=$resp 897 ask_until "IPv6 prefix length for $_ifs?" "${_prefixlen:=64}" 898 ifconfig $_ifs inet6 $_addr prefixlen $resp up || return 899 echo "inet6 $_addr $resp" >>$_hn 900 addhostent "$_addr" "$_name" 901 902 v6_defroute $_ifs 903 [[ $resp == none ]] && return 904 route -n add -inet6 -host default "$resp" || return 905 echo "$resp" >>/tmp/mygate 906} 907 908v4_defroute() { 909 local _dr _prompt=" or 'none'" 910 911 # Get/Confirm an IPv4 default route if an IPv4 address was configured. 912 [[ -n $(ifconfig | sed -ne '/[ ]inet .* broadcast /p') ]] || return 913 914 # If only one interface, and it is running dhclient, ask nothing 915 [[ -f /tmp/dhclient.conf && $nifs == 1 ]] && return 916 917 [[ -x /sbin/dhclient ]] && _prompt=", 'dhcp'$_prompt" 918 _prompt="Default IPv4 route? (IPv4 address$_prompt)" 919 920 _dr=$(route -n show -inet | sed -ne '/^default */{s///; s/ .*//; p;}') 921 [[ -f /tmp/dhclient.conf ]] && _dr=dhcp 922 923 while :; do 924 ask_until "$_prompt" "$_dr" 925 [[ $resp == @(none|dhcp) ]] && break 926 route delete -inet default >/dev/null 2>&1 927 route -n add -inet -host default "$resp" && { echo "$resp" >/tmp/mygate ; break ; } 928 # Put the old default route back. The new one did not work. 929 route -n add -inet -host default $_dr >/dev/null 2>&1 930 done 931} 932 933v6_defroute() { 934 local _if=$1 _routers _oifs 935 936 if [[ -z $(route -n show -inet6 | sed -ne '/^default */{s///; s/ .*//; p;}') ]]; then 937 resp=none 938 return 939 fi 940 941 if [[ -x /sbin/ping6 ]]; then 942 _routers=$(ping6 -n -c 2 ff02::2%$_if 2>&1 | sed -n \ 943 -e '/bytes from/{s/^.*from //;s/,.*$//;p;}') 944 fi 945 946 _oifs=$IFS 947 IFS= 948 PS3="IPv6 default router? (list #, IPv6 address or 'none'): " 949 select i in $_routers; do 950 case $i in 951 "") resp=$REPLY 952 [[ -n $resp ]] && break 953 ;; 954 *) resp=$i 955 break 956 ;; 957 esac 958 done 959 IFS=$_oifs 960} 961 962# Much of this is gratuitously stolen from /etc/netstart. 963enable_network() { 964 local _f _gw 965 966 # Copy any network configuration files. N.B.: hosts already copied. 967 for _f in dhclient.conf resolv.conf resolv.conf.tail; do 968 if [ -f /mnt/etc/$_f ]; then 969 cp /mnt/etc/$_f /etc/$_f 970 fi 971 done 972 973 # Set the address for the loopback interface. Bringing the 974 # interface up, automatically invokes the IPv6 address ::1. 975 ifconfig lo0 inet 127.0.0.1/8 976 977 # configure all of the non-loopback interfaces which we know about. 978 # refer to hostname.if(5) 979 for hn in /mnt/etc/hostname.*; do 980 (( nifs += 1 )) 981 982 # Strip off /mnt/etc/hostname. prefix 983 if=${hn#/mnt/etc/hostname.} 984 985 # Check for ifconfig'able interface. 986 (ifconfig $if||ifconfig $if create)> /dev/null 2>&1 || continue 987 988 # Now parse the hostname.* file 989 while :; do 990 if [ "$cmd2" ]; then 991 # we are carrying over from the 'read dt dtaddr' last time 992 set -- $cmd2 993 af=$1 name=$2 mask=$3 bcaddr=$4 ext1=$5 cmd2= 994 # make sure and get any remaining args in ext2, like the read below 995 i=1; while [ i -lt 6 -a -n "$1" ]; do shift; let i=i+1; done 996 ext2="$@" 997 else 998 # read the next line or exit the while loop 999 read af name mask bcaddr ext1 ext2 || break 1000 fi 1001 # $af can be "dhcp", "up", "rtsol", an address family, commands, or 1002 # a comment. 1003 case $af in 1004 "#"*|"!"*|"bridge"|"") 1005 # skip comments, user commands, bridges, 1006 # and empty lines 1007 continue 1008 ;; 1009 "dhcp") [ "$name" = "NONE" ] && name= 1010 [ "$mask" = "NONE" ] && mask= 1011 [ "$bcaddr" = "NONE" ] && bcaddr= 1012 dhcpif="$dhcpif $if" 1013 cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 down" 1014 cmd="$cmd; dhclient $if" 1015 # Create a new bpf in case we start another dhclient 1016 makedev bpf$(ls /dev | grep -c "^bpf[0-9]") 1017 ;; 1018 "rtsol") 1019 rtsolif="$rtsolif $if" 1020 cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 up" 1021 ;; 1022 "up") 1023 # The only one of these guaranteed to be set is $if 1024 # the remaining ones exist so that media controls work 1025 cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 up" 1026 ;; 1027 *) read dt dtaddr 1028 if [ "$name" = "alias" ]; then 1029 # perform a 'shift' of sorts 1030 alias=$name 1031 name=$mask 1032 mask=$bcaddr 1033 bcaddr=$ext1 1034 ext1=$ext2 1035 ext2= 1036 else 1037 alias= 1038 fi 1039 cmd="ifconfig $if $af $alias $name " 1040 case $dt in 1041 dest) cmd="$cmd $dtaddr" 1042 ;; 1043 [a-z!]*) 1044 cmd2="$dt $dtaddr" 1045 ;; 1046 esac 1047 if [ -z "$name" ]; then 1048 echo "/mnt/etc/hostname.$if: invalid network configuration file" 1049 return 1050 fi 1051 case $af in 1052 inet) [ "$mask" ] && cmd="$cmd netmask $mask" 1053 if [ "$bcaddr" -a "$bcaddr" != "NONE" ]; then 1054 cmd="$cmd broadcast $bcaddr" 1055 fi 1056 [ "$alias" ] && rtcmd="; route -qn add -host $name 127.0.0.1" 1057 ;; 1058 inet6) 1059 [ "$mask" ] && cmd="$cmd prefixlen $mask" 1060 cmd="$cmd $bcaddr" 1061 ;; 1062 *) cmd="$cmd $mask $bcaddr" 1063 ;; 1064 esac 1065 cmd="$cmd $ext1 $ext2$rtcmd" rtcmd= 1066 ;; 1067 esac 1068 eval "$cmd" 1069 done </mnt/etc/hostname.$if 1070 done 1071 1072 [[ -n $rtsolif ]] && /mnt/sbin/rtsol -F $rtsolif 1073 1074 # /mnt/etc/mygate, if it exists, contains the address(es) of my 1075 # default gateway(s). Use for ipv4 if no interfaces configured via 1076 # dhcp. Use for ipv6 if no interfaces configured via rtsol. 1077 [[ -z $dhcpif ]] && stripcom /mnt/etc/mygate | while read _gw; do 1078 [[ $_gw == @(*:*) ]] && continue 1079 route -qn delete default >/dev/null 2>&1 1080 route -qn add -host default $_gw && break 1081 done 1082 [[ -z $rtsolif ]] && stripcom /mnt/etc/mygate | while read _gw; do 1083 [[ $_gw == !(*:*) ]] && continue 1084 route -qn delete -inet6 default >/dev/null 2>&1 1085 route -qn add -host -inet6 default $_gw && break 1086 done 1087 1088 route -qn add -net 127 127.0.0.1 -reject >/dev/null 1089} 1090 1091# Install a user-selected subset of the files in $2 from the source 1092# named in $1. Display an error message for failed installs so the 1093# user will know to try again. 1094install_files() { 1095 local _src=$1 _files=$2 _f _sets _get_sets _n _col=$COLUMNS 1096 1097 # Initialize _sets to the list of sets found in _src, and initialize 1098 # _get_sets to the intersection of _sets and DEFAULTSETS. 1099 # 1100 # Sets will be installed in the order given in THESETS to ensure proper 1101 # installation. So, to minimize user confusion display the sets in the 1102 # order in which they will be installed. 1103 for _f in $THESETS; do 1104 isin $_f $_files || continue; 1105 _sets=$(addel $_f $_sets) 1106 if [[ -z $DISPLAY && ! -d /mnt/etc/X11 ]]; then 1107 # No displays and X isn't installed ==> skip X sets 1108 isin ${_f%${VERSION}.tgz} xbase xetc xshare xfont xserv && continue 1109 fi 1110 isin $_f $DEFAULTSETS "site$VERSION-$(hostname -s).tgz" && \ 1111 _get_sets=$(addel $_f $_get_sets) 1112 done 1113 1114 if [[ -z $_sets ]]; then 1115 # Show $_src, but delete any ftp password. 1116 echo -n "Looked at " 1117 echo $_src | sed -e 's/\(^ftp:\/\/[^/]*\)\(:[^/]*\)\(@.*\)/\1\3/' 1118 echo "and found no $OBSD sets. The set names looked for were:" 1119 1120 let COLUMNS=_col-8 1121 for _n in $THESETS; do echo $_n; done | showcols | sed 's/^/ /' 1122 COLUMNS=$_col 1123 1124 echo 1125 return 1126 fi 1127 1128 resp=y 1129 isin INSTALL.$ARCH $_files || 1130 ask_yn "INSTALL.$ARCH not found. Use sets found here anyway?" 1131 [[ $resp = n ]] && return 1132 1133 select_sets "$_sets" "$_get_sets" 1134 1135 [[ -n $resp ]] || return 1136 _get_sets=$resp 1137 1138 [[ $resp = n ]] && return 1139 1140 shacmd="cat" 1141 [[ -x /bin/sha256 ]] && shacmd="sha256 /tmp/h" 1142 1143 for _f in $THESETS ; do 1144 isin $_f $_get_sets || continue 1145 echo -n "Getting $_f ..." 1146 rm -f /tmp/h 1147 case $_f in 1148 *.tgz) ftp $FTPOPTS -o - -m "$_src/$_f" | \ 1149 $shacmd | tar zxphf - -C /mnt 1150 ;; 1151 *) ftp $FTPOPTS -o - -m "$_src/$_f" | \ 1152 $shacmd > "/mnt/$_f" 1153 ;; 1154 esac 1155 if [ $? -ne 0 ]; then 1156 echo "'$_f' did not install correctly." 1157 elif [ -f /tmp/h -a -f "/var/hash/$_f" ]; then 1158 if [ "$(</tmp/h)" != "$(</var/hash/$_f)" ]; then 1159 echo "The SHA256 hash $(cat /tmp/h)" 1160 echo "for $_f did not match what this bsd.rd expected." 1161 # XXX should mark failure somehow 1162 fi 1163 DEFAULTSETS=$(rmel $_f $DEFAULTSETS) 1164 GOTSETS="$GOTSETS $_f" 1165 else 1166 DEFAULTSETS=$(rmel $_f $DEFAULTSETS) 1167 GOTSETS="$GOTSETS $_f" 1168 fi 1169 done 1170} 1171 1172# Encode $1 as specified for usercodes and passwords in RFC 1738 1173# section 3.1 and section 5. 1174# 1175# Escape everything between 0x20 and 0x7e to avoid both illegal url 1176# characters and characters causing problems during script processing. 1177# 1178# *NOTE* 1179# 1) quotes around $1 are required to preserve trailing or 1180# embedded blanks in usercodes and passwords. 1181# 2) substitute '%' FIRST so it doesn't eliminate '%' chars we insert. 1182encode_for_url() { 1183 echo "$1" | sed -e " 1184s/%/%25/g 1185s/ /%20/g 1186s/!/%21/g 1187s/\"/%22/g 1188s/#/%23/g 1189s/\\\$/%24/g 1190s/&/%26/g 1191s/'/%27/g 1192s/(/%28/g 1193s/)/%29/g 1194s/\*/%2a/g 1195s/+/%2b/g 1196s/,/%2c/g 1197s/-/%2d/g 1198s/\./%2e/g 1199s/\//%2f/g 1200s/:/%3a/g 1201s/;/%3b/g 1202s/</%3c/g 1203s/=/%3d/g 1204s/>/%3e/g 1205s/?/%3f/g 1206s/@/%40/g 1207s/\[/%5b/g 1208s/\\\\/%5c/g 1209s/]/%5d/g 1210s/\^/%5e/g 1211s/_/%5f/g 1212s/\`/%60/g 1213s/{/%7b/g 1214s/|/%7c/g 1215s/}/%7d/g 1216s/~/%7e/g 1217" 1218} 1219 1220# Check for the presence of an error message in the output of the ftp commands 1221# used to get the list of files in a directory. 1222# 1223# $1 = error message to look for 1224# $2 = ftp command output 1225ftp_error() { 1226 if [[ -n $(echo "$2" | grep "$1") ]]; then 1227 echo $1 1228 return 0 1229 fi 1230 return 1 1231} 1232 1233startftplist() { 1234 # If no networks are configured, we do not need the ftplist file 1235 (( nifs < 1 )) && return 1236 1237 # Make sure the ftp subshell gets its own process group 1238 set -m 1239 ( 1240 # ftp.openbsd.org == 129.128.5.191 and will remain at 1241 # that address for the foreseeable future. 1242 ftp $FTPOPTS -a -o - "http://129.128.5.191/cgi-bin/ftplist.cgi?path=$FTPSETDIR" \ 1243 2>/tmp/ftplisterr > $SERVERLISTALL 1244 1245 # Remember finish time for adjusting the received timestamp 1246 echo -n $SECONDS >$SERVERLISTSEC 1247 ) & ftppid=$! 1248 set +m 1249 1250 # If the ftp process takes more than 12 seconds, kill it 1251 # XXX We are relying on the pid space not randomly biting us -- 1252 # XXX ftp could terminate early, and the pid could be reused 1253 (sleep 12; kill -INT -$ftppid >/dev/null 2>&1) & 1254} 1255 1256# Wait for the ftp process to finish, or be killed after the timeout 1257# XXX contains a bit of debug code for now 1258waitftplist() { 1259 local _dot # XXX 1260 1261 [[ -z $ftppid ]] && return 1262 while [[ -n $(jobs $ftppid 2>/dev/null) ]]; do 1263 echo -n . # XXX 1264 _dot=. # XXX 1265 sleep 0.2 # XXX 1266 done 1267 [[ -n $_dot ]] && echo # XXX 1268} 1269 1270# If possible, print the timestamp received from the ftplist.cgi output, 1271# adjusted with the time elapsed since it was received 1272ftp_time() { 1273 local _ftplist_sec=$(cat $SERVERLISTSEC 2>&-) 1274 local _time=$(sed '/^TIME=\([0-9]*\)$/!d;s//\1/;q' $SERVERLISTALL 2>&-) 1275 [[ -n $_ftplist_sec && -n $_time ]] && 1276 echo $((_time + SECONDS - _ftplist_sec)) 1277} 1278 1279# Get several parameters from the user, and xfer 1280# files from the server. 1281# $1 = url type (ftp or http) 1282# Note: _ftp_server_ip, _ftp_server_dir, _ftp_server_login, 1283# and FTPOPTS must be global. 1284install_url() { 1285 local _url_type=$1 _file_list _url_base _oifs _prompt _passwd _mirror 1286 eval local _server_ip=\$_${_url_type}_server_ip \ 1287 _server_dir=\$_${_url_type}_server_dir 1288 1289 waitftplist 1290 ask "HTTP/FTP proxy URL? (e.g. 'http://proxy:8080', or 'none')" \ 1291 "${ftp_proxy:-none}" 1292 unset ftp_proxy http_proxy 1293 [[ $resp == none ]] || export ftp_proxy=$resp http_proxy=$resp 1294 1295 if [[ -s $SERVERLISTALL ]]; then 1296 _prompt="Server? (hostname, list#, 'done' or '?')" 1297 sed -n "s,^${_url_type}://"'\([[A-Za-z0-9\:_][]A-Za-z0-9:._-]*\),\1,p' \ 1298 $SERVERLISTALL > $SERVERLIST 1299 set -- $(sed q $SERVERLIST) 1300 _server_ip=${1%%/*} 1301 else 1302 echo "(Was not able to get ftplist from ftp.openbsd.org, but that is OK)" 1303 _prompt="Server? (hostname or 'done')" 1304 fi 1305 1306 # Get server IP address or hostname 1307 while :; do 1308 ask_until "$_prompt" "$_server_ip" 1309 case $resp in 1310 done) return ;; 1311 "?") [[ -s $SERVERLIST ]] || continue 1312 less -XEN < $SERVERLIST 1313 ;; 1314 +([0-9])) 1315 # A numeric hostname is ignored. A number is only used 1316 # as a line number in $SERVERLIST. 1317 [[ -s $SERVERLIST ]] || continue 1318 set -- $(sed -n "${resp}p" $SERVERLIST) 1319 [[ $# -lt 1 ]] && { echo "There is no line $resp." ; continue ; } 1320 _server_ip=${1%%/*} 1321 # Repeat loop to get user to confirm server address. 1322 ;; 1323 +([A-Za-z0-9\:.\[\]_-])) 1324 _server_ip=$resp 1325 break 1326 ;; 1327 *) echo "'$resp' is not a valid hostname." 1328 ;; 1329 esac 1330 done 1331 eval _${_url_type}_server_ip=$_server_ip 1332 1333 # Get directory info from *last* line starting with the server 1334 # name. This means the last install from a mirror will not keep 1335 # the specific directory info. But an install from a local 1336 # server *will* remember the specific directory info. 1337 set -- $(sed "/^$_server_ip/x;\$!d;x" $SERVERLIST 2>&-) 1338 resp=${1#*/} 1339 # If there is no directory specified, don't use the server name! 1340 [[ $resp == "$1" ]] && resp= 1341 if (( $# > 1 )); then 1342 # It's a mirror, since it has location info. 1343 resp=$resp/$FTPSETDIR 1344 _mirror=yes 1345 fi 1346 1347 ask_until "Server directory?" "${resp:-pub/OpenBSD/$FTPSETDIR}" 1348 _server_dir=$resp 1349 eval _${_url_type}_server_dir=$_server_dir 1350 1351 if [[ $_url_type == ftp ]]; then 1352 # Get login name, setting IFS to nothing so trailing or 1353 # embedded blanks are preserved! 1354 _oifs=$IFS 1355 IFS= 1356 ask_until "Login?" "${_ftp_server_login:=anonymous}" 1357 _ftp_server_login=$resp 1358 1359 # Get password unless login in 'anonymous' or 'ftp' 1360 if [[ $_ftp_server_login == @(anonymous|ftp) ]]; then 1361 _passwd=root@`hostname` 1362 else 1363 resp= 1364 while [[ -z $resp ]] ; do 1365 askpass "Password? (will not echo)" 1366 done 1367 _passwd=$resp 1368 fi 1369 IFS=$_oifs 1370 fi 1371 1372 # Build up the base url since it is so nasty... 1373 _url_base=$_url_type:// 1374 if [[ $_url_type == ftp && $_ftp_server_login != anonymous ]]; then 1375 _url_base=$_url_base$(encode_for_url "$_ftp_server_login"):$(encode_for_url "$_passwd")@ 1376 fi 1377 _url_base=$_url_base$_server_ip/$_server_dir 1378 1379 # XXX Workaround for problems ftp'ing out from a v6 only host. 1380 ifconfig lo0 127.0.0.1 1381 1382 # Get list of files from the server. 1383 if [[ $_url_type == ftp && -z $ftp_proxy ]] ; then 1384 _file_list=$(ftp $FTPOPTS "$_url_base/") 1385 ftp_error "Login failed." "$_file_list" && return 1386 ftp_error "No such file or directory." "$_file_list" && return 1387 else 1388 # Assumes index file is "index.txt" for http (or proxy) 1389 # We can't use index.html since the format is server-dependent 1390 _file_list=$(ftp $FTPOPTS -o - "$_url_base/index.txt" | \ 1391 sed -e 's/^.* //' | sed -e 's/ 1392//') 1393 fi 1394 1395 install_files "$_url_base" "$_file_list" 1396 1397 # Remember where we installed from 1398 installedfrom=$_url_type://$_server_ip/$_server_dir 1399 1400 # Bake a package path if we installed from a mirror 1401 if [[ -n $_mirror ]]; then 1402 package_path=$(print -r -- "$installedfrom" | 1403 sed -E "/\/(snapshots|[0-9]\.[0-9])\/($ARCH)\/*$/!d 1404 s!!/\1/packages/$(arch -s)/!;q") 1405 else 1406 package_path= 1407 fi 1408} 1409 1410install_mounted_fs() { 1411 local _dir 1412 1413 while :; do 1414 ask_until "Pathname to the sets? (or 'done')" "$SETDIR" 1415 [[ $resp == done ]] && return 1416 # Accept a valid /mnt2 or /mnt relative path. 1417 [[ -d /mnt2/$resp ]] && { _dir=/mnt2/$resp ; break ; } 1418 [[ -d /mnt/$resp ]] && { _dir=/mnt/$resp ; break ; } 1419 # Accept a valid absolute path. 1420 [[ -d /$resp ]] && { _dir=/$resp ; break ; } 1421 echo "The directory '$resp' does not exist." 1422 done 1423 1424 install_files "file://$_dir" "$(ls $_dir/)" 1425} 1426 1427install_cdrom() { 1428 get_drive "CD-ROM" '$(get_cddevs)' || return 1429 mount_mnt2 $resp || return 1430 1431 install_mounted_fs 1432} 1433 1434install_disk() { 1435 ask_yn "Is the disk partition already mounted?" 1436 if [[ $resp == n ]]; then 1437 get_drive "disk" '$(bsort $(get_dkdevs))' \ 1438 '$(bsort $(rmel $ROOTDISK $(get_dkdevs)))' || return 1439 mount_mnt2 $resp || return 1440 fi 1441 1442 install_mounted_fs 1443} 1444 1445install_nfs() { 1446 local _tcp 1447 1448 # Get the IP address of the server. 1449 ask_until "Server IP address or hostname?" "$NFS_ADDR" 1450 NFS_ADDR=$resp 1451 1452 # Get the server path to mount. 1453 ask_until "Filesystem on server to mount?" "$NFS_PATH" 1454 NFS_PATH=$resp 1455 1456 # Determine use of TCP 1457 ask_yn "Use TCP transport? (requires TCP-capable NFS server)" 1458 [[ $resp == y ]] && _tcp=-T 1459 1460 # Mount the server 1461 mount_nfs $_tcp -o ro -R 5 $NFS_ADDR:$NFS_PATH /mnt2 || return 1462 1463 install_mounted_fs 1464} 1465 1466install_tape() { 1467 local _z _bs 1468 1469 # Get the name of the tape device. 1470 get_drive "tape drive" '$MTDEVS' || return 1471 export TAPE=/dev/nr$resp 1472 if [[ ! -c $TAPE ]]; then 1473 echo "$TAPE is not a character special file." 1474 return 1475 fi 1476 1477 # Rewind the tape device. 1478 echo -n "Rewinding $TAPE (mt rewind)..." 1479 mt rewind || return 1480 echo "done." 1481 1482 # Extract the desired files. 1483 while :; do 1484 ask_until "Skip how many files? (or 'done')" 0 1485 [[ $resp == done ]] && return 1486 [[ $resp == +([0-9]) ]] || continue 1487 (($resp < 0)) && continue 1488 1489 if (($resp > 0)); then 1490 echo -n "Skipping $resp file(s)..." 1491 mt fsf $resp || return 1492 echo "done." 1493 elif [[ -n $_bs ]]; then 1494 # Dance to start of next file. 1495 mt bsf ; mt fsf 1496 fi 1497 1498 unset _z 1499 ask_yn "Is the file gzipped?" yes 1500 [[ $resp == y ]] && _z=z 1501 1502 # Get the blocksize to use. If the file isn't gzipped then 1503 # default to the 20 x 512 = 10,240 byte tar default. 1504 [[ $_z == z ]] || _bs=10240 1505 ask_until "Blocksize for this file?" "${_bs:-8k}" 1506 [[ $resp == done ]] && return 1507 _bs=$resp 1508 1509 dd if=$TAPE bs=$_bs | tar ${_z}xvphf - -C /mnt || return 1510 done 1511} 1512 1513set_timezone() { 1514 local _zonefile=$1 _zonepath _zsed _tz _zoneroot=/usr/share/zoneinfo 1515 1516 # If the timezone file is not available, 1517 # return immediately. 1518 1519 [[ ! -f $_zonefile ]] && return 1520 1521 # If configured in a previous call, return immediately 1522 [[ -n $TZ ]] && return 1523 1524 if [[ -h /mnt/etc/localtime ]]; then 1525 TZ=$(ls -l /mnt/etc/localtime 2>/dev/null) 1526 TZ=${TZ#*${_zoneroot#/mnt}/} 1527 fi 1528 1529 waitftplist 1530 if [[ -s $SERVERLISTALL ]]; then 1531 _tz=$(sed -ne '/^TZ=/s/TZ=//p' <$SERVERLISTALL) 1532 [[ -n $_tz ]] && isin "$_tz" `cat $_zonefile` && TZ=$_tz 1533 fi 1534 1535 # If neither the base or SERVERLIST gave a hint, and this is the 1536 # early question, give up, and ask after the sets are installed 1537 [[ $_zonefile = /var/tzlist && -z $TZ ]] && return 1538 1539 while :; do 1540 ask "What timezone are you in? ('?' for list)" "$TZ" 1541 _zonepath=${resp%%*(/)} 1542 case $_zonepath in 1543 "") continue ;; 1544 "?") grep -v /. $_zonefile | showcols 1545 continue ;; 1546 esac 1547 1548 while isin $_zonepath/ $(cat $_zonefile); do 1549 ask "What sub-timezone of '$_zonepath' are you in? ('?' for list)" 1550 _zsed=$(echo $_zonepath/ | sed 's,/,\\/,g') 1551 resp=${resp%%*(/)} 1552 case $resp in 1553 "") ;; 1554 "?") sed -n "/^$_zsed/{s/$_zsed//;/\/./!p;}" $_zonefile | showcols ;; 1555 *) _zonepath=$_zonepath/$resp ;; 1556 esac 1557 done 1558 1559 if isin $_zonepath $(cat $_zonefile); then 1560 TZ=${_zonepath#$_zoneroot} 1561 return 1562 fi 1563 1564 echo -n "'${_zonepath}'" 1565 echo " is not a valid timezone on this system." 1566 done 1567} 1568 1569# Check that missing required sets were deliberately skipped. 1570sane_install() { 1571 local _q=$1 _s _m 1572 1573 for _s in $SANESETS; do 1574 isin $_s $DEFAULTSETS || continue 1575 # If sane_install has no argument, harass the user. 1576 resp=n 1577 [[ -z $_q ]] && ask_yn "Are you *SURE* your $MODE is complete without '$_s'?" 1578 [[ $resp == n ]] && _m="$_m $_s" 1579 done 1580 1581 [[ -n $_m ]] && return 1 1582 return 0 1583} 1584 1585# Ask the user for locations of sets, and then install whatever sets the 1586# user selects from that location. Repeat as many times as the user 1587# needs to get all desired sets. 1588install_sets() { 1589 local _d _locs="disk ftp http" 1590 1591 echo 1592 1593 [[ -s $SERVERLISTALL ]] && \ 1594 _d=$(sed -ne '/^method=/s/method=//p' $SERVERLISTALL) 1595 1596 ifconfig netboot >/dev/null 2>&1 && : ${_d:=http} 1597 [[ -n $(get_cddevs) ]] && { _locs="cd $_locs" ; : ${_d:=cd} ; } 1598 [[ -x /sbin/mount_nfs ]] && _locs="$_locs nfs" 1599 [[ -n $MTDEVS && -x /bin/mt ]] && _locs="$_locs tape" 1600 : ${_d:=http} 1601 1602 if ! isin "$_d" $_locs; then 1603 for a in http ftp cd nfs tape disk; do 1604 isin $a $_locs && _d=$a && break 1605 done 1606 fi 1607 1608 echo "Let's $MODE the sets!" 1609 while :; do 1610 umount -f /mnt2 >/dev/null 2>&1 1611 [[ -n $method ]] && _d=$method 1612 sane_install quiet && _d=done 1613 1614 ask "Location of sets? ($_locs or 'done')" "$_d" 1615 case $resp in 1616 done) sane_install && return ;; 1617 c*|C*) isin cd $_locs && install_cdrom && method=cd ;; 1618 d*|D*) install_disk && method=disk ;; 1619 f*|F*) isin ftp $_locs && install_url ftp && method=ftp ;; 1620 h*|H*) isin http $_locs && install_url http && method=http ;; 1621 n*|N*) isin nfs $_locs && install_nfs && method=nfs ;; 1622 t*|T*) isin tape $_locs && install_tape && method=tape ;; 1623 esac 1624 done 1625} 1626 1627# Create a skeletal but useful /etc/fstab from /tmp/fstab by stripping all 1628# comment lines and dropping all filesystems which 1629# 1630# 1) can't be mounted (no mount_* command is found), 1631# 2) have 'xx' in the option field (usually /altroot), 1632# 3) have 'noauto' in the option field, 1633# 4) are nfs (since name resolution may not be present), 1634# 5) are on a vnd device. 1635# 1636# In addition, 1637# 1638# 1) delete 'softdep' options (no soft updates in ramdisk kernels), 1639# 2) mount non-ffs filesystems read only, 1640# 3) prepend '/mnt' to all mount points, 1641# 4) delete any trailing '/' from the mount point (e.g. root), 1642# 1643# If no /etc/fstab is created, do not proceed with install/upgrade. 1644munge_fstab() { 1645 local _dev _mp _fstype _opt _rest 1646 1647 while read _dev _mp _fstype _opt _rest; do 1648 # Drop irrelevant lines and filesystems. 1649 [[ $_dev == @(/dev/vnd*|\#*) || \ 1650 $_fstype == nfs || \ 1651 ! -f /sbin/mount_$_fstype || \ 1652 $_opt == *noauto* || \ 1653 $_opt == *xx* ]] && continue 1654 1655 # Remove any softdep options, as soft updates are not 1656 # available in the ramdisk kernels. 1657 _opt=$(echo $_opt | sed -e 's/softdep//') 1658 1659 # Change read-only ffs to read-write since we'll potentially 1660 # write to these filesystems. 1661 [[ $_fstype == ffs ]] && _opt=$(echo $_opt | sed -e 's/ro/rw/') 1662 1663 # Mount non-ffs filesystems read only. 1664 [[ $_fstype == ffs ]] || _opt=$(echo $_opt | sed -e 's/rw/ro/') 1665 1666 # Write fs entry in fstab. 1667 # 1) prepend '/mnt' to the mount point. 1668 # 2) remove a trailing '/' from the mount point (e.g. root). 1669 echo $_dev /mnt${_mp%/} $_fstype $_opt $_rest 1670 1671 done </tmp/fstab >/etc/fstab 1672 1673 # If no /etc/fstab was created, we have nowhere to $MODE to. 1674 if [ ! -s /etc/fstab ]; then 1675 echo "Unable to create valid /etc/fstab." 1676 exit 1677 fi 1678} 1679 1680# Must mount filesystems manually, one at a time, so we can make 1681# sure the mount points exist. 1682mount_fs() { 1683 local _async=$1 _dev _mp _fstype _opt _rest _msg _fail 1684 1685 while read _dev _mp _fstype _opt _rest; do 1686 # If not the root filesystem, make sure the mount 1687 # point is present. 1688 [ "$_mp" = "/mnt" ] || mkdir -p $_mp 1689 1690 # Mount the filesystem. Remember any failure. 1691 _msg=$(mount -v -t $_fstype $_async -o $_opt $_dev $_mp) || 1692 _fail="$_fail\n$_mp ($_dev)" 1693 echo $_msg | sed -e 's/, ctime=[^,)]*//' 1694 done </etc/fstab 1695 1696 if [[ -n $_fail ]]; then 1697 # One or more mounts failed. Continue or abort? 1698 echo "\nWARNING! The following filesystems were not properly mounted:$_fail" 1699 ask_yn "Continue anyway?" no 1700 if [[ $resp == n ]]; then 1701 exit 1702 fi 1703 fi 1704} 1705 1706# Return the device name for the supplied device, which may be a disklabel UID. 1707getdevname() { 1708 local _dev=$1 1709 if [[ ${#_dev} == 18 && $_dev == +([0-9a-f]).[a-p] || 1710 ${#_dev} == 16 && $_dev == +([0-9a-f]) ]]; then 1711 # Lookup device name matching the disklabel UID 1712 sysctl -n hw.disknames | 1713 sed -nE "s/^(.*,)*(.*):${_dev%.?}.*/\\2/p" 1714 else 1715 _dev=${_dev#/dev/} 1716 print -r -- "${_dev%[a-p]}" 1717 fi 1718} 1719 1720# Preen all filesystems in /etc/fstab that have a /sbin/fsck_XXX and a 1721# fs_passno > 0, showing individual results, but skipping $ROOTDEV. This was 1722# already fsck'ed successfully. 1723# 1724# Exit if any fsck's fail (but do them all before exiting!). 1725check_fs() { 1726 local _dev _mp _fstype _rest _fail _f _passno 1727 1728 ask_yn "Force checking of clean non-root filesystems?" 1729 [[ $resp == y ]] && _f=f 1730 1731 while read _dev _mp _fstype _rest _rest _passno _rest; do 1732 [ "$_dev" != /dev/"$ROOTDEV" ] || continue 1733 [ -f "/sbin/fsck_$_fstype" ] || continue 1734 # Make sure device exists before fsck'ing it. 1735 makedev "$(getdevname "$_dev")" || continue 1736 [[ $_passno > 0 ]] || continue 1737 echo -n "fsck -${_f}p $_dev..." 1738 if ! fsck -${_f}p $_dev >/dev/null 2>&1; then 1739 echo "FAILED. You must fsck $_dev manually." 1740 _fail=y 1741 else 1742 echo "OK." 1743 fi 1744 done </etc/fstab 1745 1746 [ "$_fail" ] && exit 1747} 1748 1749# Extract fully qualified domain name from current hostname. If none is 1750# currently set, use 'my.domain'. 1751get_fqdn() { 1752 local _dn 1753 1754 _dn=$(hostname) 1755 _dn=${_dn#$(hostname -s)} 1756 _dn=${_dn#.} 1757 1758 echo "${_dn:=my.domain}" 1759} 1760 1761donetconfig() { 1762 local _dn _ns _n 1763 1764 configure_ifs 1765 v4_defroute 1766 1767 # As dhclient will populate /etc/resolv.conf, a symbolic link to 1768 # /tmp/resolv.conf.shadow, mv any such file to /tmp/resolv.conf 1769 # so it will eventually be copied to /mnt/etc/resolv.conf and will 1770 # not in the meantime remove the user's ability to choose to use it 1771 # or not, during the rest of the install. 1772 if [ -f /tmp/resolv.conf.shadow ]; then 1773 mv /tmp/resolv.conf.shadow /tmp/resolv.conf 1774 # Get nameserver address(es). Store as a blank separated list. 1775 for _n in $(grep '^nameserver ' /tmp/resolv.conf); do 1776 [[ $_n == nameserver ]] || _ns="$_ns$_n " 1777 done 1778 # Zap trailing space in _ns. 1779 set -- $_ns 1780 _ns=$* 1781 # Get default fully qualified domain name from *first* domain 1782 # given on *last* search or domain statement. 1783 _dn=$(sed -n \ 1784 -e '/^domain[[:space:]][[:space:]]*/{s///;s/\([^[:space:]]*\).*$/\1/;h;}' \ 1785 -e '/^search[[:space:]][[:space:]]*/{s///;s/\([^[:space:]]*\).*$/\1/;h;}' \ 1786 -e '${g;p;}' /tmp/resolv.conf) 1787 fi 1788 1789 # Get & apply fully qualified domain name to hostname. 1790 resp="${_dn:=$(get_fqdn)}" 1791 if [[ ! -f /tmp/dhclient.conf || $nifs != 1 ]]; then 1792 ask "DNS domain name? (e.g. 'bar.com')" "$resp" 1793 else 1794 echo "Using DNS domainname $resp" 1795 fi 1796 hostname "$(hostname -s).$resp" 1797 1798 # If only one interface, and it is running dhclient, ask nothing 1799 # else Get/Confirm nameservers 1800 resp="${_ns:=none}" 1801 if [[ ! -f /tmp/dhclient.conf || $nifs != 1 || $resp == none ]]; then 1802 ask "DNS nameservers? (IP address list or 'none')" "$resp" 1803 else 1804 echo "Using DNS nameservers at $resp" 1805 fi 1806 # Construct appropriate resolv.conf. 1807 if [[ $resp != none ]]; then 1808 echo "lookup file bind" >/tmp/resolv.conf 1809 for _ns in $resp; do 1810 echo "nameserver $_ns" >>/tmp/resolv.conf 1811 done 1812 cp /tmp/resolv.conf /tmp/resolv.conf.shadow 1813 fi 1814 1815 manual_net_cfg 1816} 1817 1818populateusrlocal() { 1819 if [ -f /mnt/etc/mtree/BSD.local.dist ]; then 1820 /mnt/usr/sbin/chroot /mnt /usr/sbin/mtree -Uedqn -p /usr/local -f /etc/mtree/BSD.local.dist >/dev/null 1821 fi 1822} 1823 1824apply() 1825{ 1826 if [[ $sshd == n ]]; then 1827 echo "sshd_flags=NO # disabled during install" \ 1828 >>/mnt/etc/rc.conf.local 1829 fi 1830 if [[ $sshd_disableroot == y ]]; then 1831 sed -e "/^#\(PermitRootLogin\) yes/s//\1 no/" \ 1832 < /mnt/etc/ssh/sshd_config > /tmp/sshd_config 1833 cp /tmp/sshd_config /mnt/etc/ssh/sshd_config 1834 fi 1835 if [[ $ntpd == y ]]; then 1836 echo "ntpd_flags= # enabled during install" \ 1837 >>/mnt/etc/rc.conf.local 1838 if [[ $ntpd_server != default ]]; then 1839 # Comment out the default 'servers' line, and add a 1840 # 'servers' line with the first token in $resp as the 1841 # server. 1842 set -- $ntpd_server 1843 sed -e "s/^servers /#&/;/#server /a\\ 1844servers $1 1845" /mnt/etc/ntpd.conf >/tmp/ntpd.conf 1846 cp /tmp/ntpd.conf /mnt/etc/ntpd.conf 1847 fi 1848 fi 1849 1850 if [[ $x11 == y ]]; then 1851 sed -e "/^#\(machdep\.allowaperture=${MDXAPERTURE}\)/s//\1 /" \ 1852 /mnt/etc/sysctl.conf >/tmp/sysctl.conf 1853 cp /tmp/sysctl.conf /mnt/etc/sysctl.conf 1854 fi 1855 1856 if [[ $xdm == y && -x /mnt/usr/X11R6/bin/xdm ]]; then 1857 echo "xdm_flags= # enabled during install" \ 1858 >>/mnt/etc/rc.conf.local 1859 fi 1860 1861 if [[ $defcons == y ]]; then 1862 cp /mnt/etc/ttys /tmp/ttys 1863 sed -e "/^$CTTY/s/std.9600/std.${CSPEED}/" \ 1864 -e "/^$CTTY/s/unknown/vt220 /" \ 1865 -e "/$CTTY/s/off.*/on secure/" /tmp/ttys >/mnt/etc/ttys 1866 [[ -n $CPROM ]] && \ 1867 echo "stty $CPROM $CSPEED\nset tty $CPROM" >>/mnt/etc/boot.conf 1868 fi 1869 1870 ln -sf /usr/share/zoneinfo/$TZ /mnt/etc/localtime 1871} 1872 1873questions() { 1874 local _d _xdmask=y _def 1875 1876 ask_yn "Start sshd(8) by default?" yes 1877 sshd=$resp 1878 1879 ask_yn "Start ntpd(8) by default?" 1880 ntpd=$resp 1881 if [[ $resp == y ]]; then 1882 ask "NTP server? (hostname or 'default')" default 1883 ntpd_server=$resp 1884 fi 1885 1886 def=no 1887 [[ -n $DISPLAY ]] && def=yes 1888 if [[ -n $MDXAPERTURE ]]; then 1889 ask_yn "Do you expect to run the X Window System?" $def 1890 x11=$resp 1891 _xdmask=$resp # if aperture was n, do not ask for xdm 1892 fi 1893 1894 if [[ -n $MDXDM && $_xdmask == y ]]; then 1895 ask_yn "Do you want the X Window System to be started by xdm(1)?" 1896 xdm=$resp 1897 fi 1898 1899 if [[ -n $CDEV ]]; then 1900 _d=${CPROM:-$CDEV} 1901 ask_yn "Change the default console to $_d?" 1902 defcons=$resp 1903 if [[ $resp == y ]]; then 1904 ask_which "speed" "should $_d use" \ 1905 "9600 19200 38400 57600 115200" $CSPEED 1906 case $resp in 1907 done) defcons=n ;; 1908 *) CSPEED=$resp ;; 1909 esac 1910 fi 1911 fi 1912} 1913 1914finish_up() { 1915 local _dev _mp _fstype _rest 1916 1917 # Mount all known swap partitions. This gives systems with little 1918 # memory a better chance at running 'MAKEDEV all'. 1919 if [[ -x /mnt/sbin/swapctl ]]; then 1920 /mnt/sbin/swapctl -a /dev/$SWAPDEV >/dev/null 2>&1 1921 # Can't do chmod && swapctl -A because devices are not yet 1922 # created on install'ed systems. On upgrade'ed system there 1923 # is a small chance the device does not exist on the ramdisk 1924 # and will thus not get mounted. 1925 while read _dev _mp _fstype _rest; do 1926 [[ $_fstype == swap ]] && \ 1927 /mnt/sbin/swapctl -a $_dev >/dev/null 2>&1 1928 done </mnt/etc/fstab 1929 fi 1930 1931 if grep -qs '^rtsol' /mnt/etc/hostname.*; then 1932 sed -e "/^#\(net\.inet6\.ip6\.accept_rtadv\)/s//\1/" \ 1933 /mnt/etc/sysctl.conf >/tmp/sysctl.conf 1934 cp /tmp/sysctl.conf /mnt/etc/sysctl.conf 1935 fi 1936 1937 # Create or update pkg.conf with the new package path, if any 1938 if [[ -n $package_path ]]; then 1939 grep -v '^[ ]*installpath[ ]*=' /mnt/etc/pkg.conf 2>&- > /tmp/pkgconf 1940 print -r -- "installpath = $package_path" >> /tmp/pkgconf 1941 cp /tmp/pkgconf /mnt/etc/pkg.conf 1942 fi 1943 1944 echo -n "Making all device nodes..." 1945 (cd /mnt/dev; sh MAKEDEV all 1946 # Make sure any devices we found during probe are created in the 1947 # installed system. 1948 for _dev in $(get_dkdevs) $(get_cddevs) $MTDEVS ; do 1949 sh MAKEDEV $_dev 1950 done 1951 ) 1952 echo "done." 1953 1954 populateusrlocal 1955 1956 [ -x /mnt/$MODE.site ] && /mnt/usr/sbin/chroot /mnt /$MODE.site 1957 1958 md_installboot $ROOTDISK 1959 1960 # Pat on the back. 1961 cat <<__EOT 1962 1963CONGRATULATIONS! Your OpenBSD $MODE has been successfully completed! 1964To boot the new system, enter 'reboot' at the command prompt. 1965__EOT 1966 [[ $MODE == install ]] && cat <<__EOT 1967When you login to your new system the first time, please read your mail 1968using the 'mail' command. 1969__EOT 1970 1971 md_congrats 1972} 1973 1974# ####################################################################### 1975# 1976# Initial actions common to both installs and upgrades. 1977# 1978# Some may require machine dependent routines, which may 1979# call functions defined above, so it's safest to put this 1980# code here rather than at the top of the file. 1981# 1982# ####################################################################### 1983 1984ROOTDISK= 1985ROOTDEV= 1986package_path= 1987 1988SETDIR="$VNAME/$ARCH" 1989FTPDIR="pub/OpenBSD/$VNAME" 1990FTPOPTS="-V" 1991SERVERLISTALL=/tmp/serverlistall 1992SERVERLISTSEC=/tmp/serverlistsec 1993SERVERLIST=/tmp/serverlist 1994WLANLIST=/tmp/wlanlist 1995FSTABFLAG=-f 1996 1997# Do not limit ourselves during installs or upgrades. 1998for _opt in d f l m n p s; do 1999 ulimit -$_opt unlimited 2000done 2001 2002# Extract and save one boot's worth of dmesg 2003dmesg | sed -ne '/^OpenBSD /h;/^OpenBSD /!H;${g;p;}' >/var/run/dmesg.boot 2004 2005# Are we in a real release, or a snapshot? If this is a snapshot 2006# install media, default us to a snapshot directory. 2007FTPSETDIR=$SETDIR 2008set -- $(scan_dmesg "/^OpenBSD $VNAME\([^ ]*\).*$/s//\1/p") 2009[[ $1 == -!(stable) ]] && FTPSETDIR=snapshots/$ARCH 2010 2011# Scan /var/run/dmesg.boot for interesting devices. 2012MTDEVS=$(scan_dmesg "${MDMTDEVS:-/^[cms]t[0-9][0-9]* /s/ .*//p}") 2013nifs=0 2014DISPLAY=$(scan_dmesg '/^wsdisplay[0-9]* /s/ .*//p') 2015 2016CONSOLE=$(scan_dmesg '/^\([^ ]*\).*: console$/s//\1/p') 2017CONSOLE=${CONSOLE% } 2018[[ -n $CONSOLE ]] && CSPEED=$(stty speed) 2019 2020# Look for the serial device matching the console. If we are not installing 2021# from a serial console, just find the first serial device that could be used 2022# as a console. If a suitable device is found, set CDEV, CTTY, CSPEED, CPROM. 2023md_consoleinfo 2024 2025# Selected sets will be installed in the order they are listed in $THESETS. 2026# Ensure that siteXX.tgz is the *last* set listed so its contents overwrite 2027# the contents of the other sets, not the other way around. 2028THESETS="bsd bsd.rd bsd.mp $MDSETS" 2029: ${DEFAULTSETS:="bsd bsd.rd"} 2030for _set in base etc comp man game xbase xetc xshare xfont xserv site ; do 2031 [[ $MODE == upgrade && ( $_set == etc || $_set == xetc ) ]] && continue 2032 THESETS="$THESETS ${_set}${VERSION}.tgz" 2033 isin $_set site && continue 2034 DEFAULTSETS="$DEFAULTSETS ${_set}${VERSION}.tgz" 2035done 2036# Since etc${VERSION}.tgz is not in DEFAULTSETS for upgrades, it can always be 2037# in SANESETS. 2038SANESETS="${SANESETS:-bsd} base${VERSION}.tgz etc${VERSION}.tgz" 2039 2040# prepare COLUMNS sanely 2041COLUMNS=$(stty -a | sed -n '/columns/{s/^.* \([0-9]*\) columns.*$/\1/;p;}') 2042[ COLUMNS -eq 0 ] && COLUMNS=80 2043 2044# decide upon an editor 2045: ${EDITOR:=ed} 2046[[ -x /usr/bin/vi ]] && EDITOR=vi 2047export EDITOR COLUMNS 2048 2049# umount all filesystems, just in case we are re-running install or upgrade. 2050cd / 2051umount -af 1>/dev/null 2>&1 2052 2053# make sure only successful dhcp requests retain their state 2054for _ifs in $(get_ifdevs dhcp); do 2055 set -- $(v4_info $_ifs) 2056 [[ $1 == UP && -n $2 ]] && continue 2057 ifconfig $_ifs delete down -group dhcp 2>&- 2058done 2059 2060cat <<__EOT 2061At any prompt except password prompts you can escape to a shell by 2062typing '!'. Default answers are shown in []'s and are selected by 2063pressing RETURN. You can exit this program at any time by pressing 2064Control-C, but this can leave your system in an inconsistent state. 2065 2066__EOT 2067 2068# Configure the terminal and keyboard. 2069set_term 2070 2071if [[ $MODE == install ]]; then 2072 ask_until "System hostname? (short form, e.g. 'foo')" "$(hostname -s)" 2073 [[ ${resp%%.*} != $(hostname -s) ]] && hostname $resp 2074 THESETS="$THESETS site$VERSION-$(hostname -s).tgz" 2075 2076 echo 2077 donetconfig 2078 2079 (( nifs != 0 )) && startftplist 2080 2081 echo 2082 while :; do 2083 askpassword root 2084 _rootpass="$_password" 2085 [[ -n "$_password" ]] && break 2086 echo "The root password must be set." 2087 done 2088 2089 questions 2090 user_setup 2091 2092 set_timezone /var/tzlist 2093 echo 2094fi 2095 2096# Get ROOTDISK, ROOTDEV and SWAPDEV. 2097while :; do 2098 ask_which "disk" "is the root disk" '$(get_dkdevs | sed s,^$,none, )' 2099 [[ $resp == done ]] && exit 2100 [[ $resp != none ]] && break 2101done 2102makedev $resp || exit 2103 2104ROOTDISK=$resp 2105ROOTDEV=${ROOTDISK}a 2106SWAPDEV=${ROOTDISK}b 2107