1# $MirOS: src/distrib/common/install.sub,v 1.70 2014/03/30 11:03:32 tg Exp $ 2# $OpenBSD: install.sub,v 1.388 2005/07/02 00:55:48 uwe Exp $ 3# $NetBSD: install.sub,v 1.5.2.8 1996/09/02 23:25:02 pk Exp $ 4# 5# Copyright (c) 2003, 2004, 2005, 2008, 2009, 2010, 2011, 2013, 2014 6# Thorsten “mirabilos” Glaser <tg@mirbsd.org> 7# Copyright (c) 1997-2005 Todd Miller, Theo de Raadt, Ken Westerback 8# All rights reserved. 9# 10# Redistribution and use in source and binary forms, with or without 11# modification, are permitted provided that the following conditions 12# are met: 13# 1. Redistributions of source code must retain the above copyright 14# notice, this list of conditions and the following disclaimer. 15# 2. Redistributions in binary form must reproduce the above copyright 16# notice, this list of conditions and the following disclaimer in the 17# documentation and/or other materials provided with the distribution. 18# 19# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29# 30# Copyright (c) 1996 The NetBSD Foundation, Inc. 31# All rights reserved. 32# 33# This code is derived from software contributed to The NetBSD Foundation 34# by Jason R. Thorpe. 35# 36# Redistribution and use in source and binary forms, with or without 37# modification, are permitted provided that the following conditions 38# are met: 39# 1. Redistributions of source code must retain the above copyright 40# notice, this list of conditions and the following disclaimer. 41# 2. Redistributions in binary form must reproduce the above copyright 42# notice, this list of conditions and the following disclaimer in the 43# documentation and/or other materials provided with the distribution. 44# 3. All advertising materials mentioning features or use of this software 45# must display the following acknowledgement: 46# This product includes software developed by the NetBSD 47# Foundation, Inc. and its contributors. 48# 4. Neither the name of The NetBSD Foundation nor the names of its 49# contributors may be used to endorse or promote products derived 50# from this software without specific prior written permission. 51# 52# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 53# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 54# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 56# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 59# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 60# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 61# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 62# POSSIBILITY OF SUCH DAMAGE. 63# 64 65# MirBSD install/upgrade script common subroutines and initialization code 66 67# Include machine-dependent functions and definitions. 68# 69# The following functions must be provided: 70# md_congrats() - display friendly message 71# md_prep_disklabel() - put an OpenBSD disklabel on the disk 72# 73# The following variables can be provided if required: 74# MDSETS - list of files to add to THESETS 75# MDFSTYPE - nothing assumed if not provided 76# MDFSOPTS - nothing assumed if not provided 77# MDDKDEVS - '/^r*a*[swi]d[0-9][0-9]* /s/ .*//p' assumed if not provided 78# MDCDDEVS - '/^cd[0-9][0-9]* /s/ .*//p' assumed if not provided 79# MDMTDEVS - '/^[cmsw]t[0-9][0-9]* /s/ .*//p' 80# MDXAPERTURE - set machdep.allowaperture=value in sysctl.conf 81. /etc/functions 82. install.md 83 84if _vbox_check; then 85 echo Sorry, WirrtualBox is not supported. 86 echo To continue on your own risk: ':>/allow-vbox' 87 echo But remember that vbox is buggy and often broken! 88 test -e /allow-vbox || exit 1 89fi 90 91set_term() { 92 typeset TERMS=vt100,vt220,wsvtg,wsvt25,dumb 93 echo "Possible types: $TERMS" 94 ask "Terminal type?" ${TERM:-vt220} 95 TERM=$resp 96 export TERM 97 98 [[ -x /sbin/kbd ]] || return 99 while :; do 100 ask "kbd(8) mapping? ('?' for list)" "none" 101 [[ $resp = none ]] && return 102 [[ $resp = @(\?|+([0-9])) && -z ${layouts[0]} ]] && \ 103 set -A layouts -- $(kbd -lq | \ 104 egrep '^..\.?(nodead|dvorak)?$' | sort) 105 [[ $resp = +([0-9]) ]] && resp=${layouts[$resp]} 106 [[ $resp = [a-z]* ]] && if kbd $resp; then 107 echo $resp >/tmp/kbdtype 108 return 109 fi 110 [[ $resp = \? ]] || continue 111 print Available keyboard mappings: 112 typeset -iR3 i=0 113 while (( i < ${#layouts[*]} )); do 114 print "$i) ${layouts[i]}" 115 let i++ 116 done | rs 117 done 118} 119 120welcome() { 121 typeset _q 122 123 cat <<__EOT 124 125Welcome to the ${OBSD} $MODE program (old, rewrite in progress). 126 127This programme will help you $MODE MirOS. At any prompt except password 128prompts you can run a shell command by typing '!foo', or escape to a shell 129by typing '!'. Default answers are shown in []s and are selected by just 130RETURN, but sometimes there is no default. At any time you can exit this 131programme by pressing Control-C and then RETURN, but quitting during an 132$MODE can leave your system in an inconsistent state. 133 134__EOT 135 136 # Configure the terminal and keyboard. 137 set_term 138 139 cat <<__EOT 140 141IS YOUR DATA BACKED UP? As with anything that modifies disk contents, this 142program can cause SIGNIFICANT data loss. 143 144__EOT 145 146 case $MODE in 147 upgrade) 148 cat <<__EOT 149NOTE: before your system has been upgraded, you must manually merge any changes 150to files in the 'etc' and 'xetc' sets into the files already on your system. 151 152__EOT 153 _q="Proceed with upgrade?" 154 ;; 155 156 install) 157 cat <<__EOT 158It is often helpful to have the installation notes handy. For complex disk 159configurations, relevant disk hardware manuals and a calculator are useful. 160 161__EOT 162 163 if [ -f /etc/fstab ]; then 164 cat <<__EOT 165You seem to be trying to restart an interrupted installation! You can skip 166the disk preparation steps and continue, or you can reboot and start over. 167 168__EOT 169 _q="Skip disk initialization?" 170 else 171 _q="Proceed with install?" 172 fi 173 ;; 174 esac 175 176 ask_yn "$_q" 177 if [[ $resp = n ]]; then 178 cat <<__EOT 179 180Enter 'halt -p' or 'reboot' at the prompt to gracefully exit MirBSD. 181You can then power cycle the machine and boot BSD or your other OSes. 182__EOT 183 exit 184 fi 185 186 echo "Cool! Let's get to it." 187} 188 189scan_dmesg() { 190 bsort $(sed -ne "$1" /var/run/dmesg.boot) 191} 192 193# Get the first (lowest unit #) serial device if any, if MDSERIAL is set. 194# NOTE: Only single digit serial devices (<dev>0 -> <dev>9) are looked for. 195get_serialdev() { 196 typeset _d _bd 197 198 [[ -n $MDSERIAL ]] || exit 199 set -- $MDSERIAL 200 _d=$1 201 _bd=$2 202 set -- $(scan_dmesg "/^${_d}\([0-9]\) .*/s//\1/p") 203 [[ -z $1 ]] || echo "$_bd$1" 204} 205 206get_drive() { 207 ask_which "$1" "contains the $MODE media" "$2" 208 [[ $resp = done ]] && return 1 209 makedev $resp || return 1 210 return 0 211} 212 213get_partition() { 214 typeset _drive=$1 _fstypes=$2 _part _fst 215 216 # Create file /tmp/parts.$_drive where each line is of the 217 # form "<partition letter> <fs type>". 218 disklabel $_drive 2>/dev/null \ 219 | grep '^ [a-p]: ' \ 220 | egrep -v "swap|unused" \ 221 | sed -e 's/^ \(.\): *[^ ]* *[^ ]* *\([^ ]*\) .*/\1 \2/' \ 222 >/tmp/parts.$_drive 223 224 disklabel $_drive 2>/dev/null | grep '^ .:' 225 226 ask_which "$_drive partition" "has the $MODE sets" \ 227 "$(sed -e 's/^\(.\).*/\1/' /tmp/parts.$_drive)" 228 [[ $resp = done ]] && return 1 229 230 _part=$resp 231 _fst=$(sed -ne "/^$_part /s///p" /tmp/parts.$_drive) 232 233 ask_which "filesystem type" "should be used to mount $_drive$_part" "$_fst $_fstypes ffs" 234 case $resp in 235 done) return 1 ;; 236 $_fst) resp="$_part" ;; 237 *) resp="$_part $resp" ;; 238 esac 239 240 return 0 241} 242 243# Ask for a password, saving the input in $resp. 244# Display $1 as the prompt. 245# *Don't* allow the '!' options that ask does. 246# *Don't* echo input. 247askpass() { 248 set -o noglob 249 stty -echo 250 read resp?"$1 " 251 stty echo 252 set +o noglob 253 echo 254} 255 256# Ask for user input. 257# 258# $1 = the question to ask the user 259# $2 = the default answer 260# 261# Save the user input (or the default) in $resp. 262# 263# Allow the user to escape to shells ('!') or execute commands 264# ('!foo') before entering the input. 265ask() { 266 typeset _question=$1 _default=$2 267 268 set -o noglob 269 while :; do 270 echo -n "$_question " 271 [[ -z $_default ]] || echo -n "[$_default] " 272 read resp 273 case $resp in 274 !) echo "Type 'exit' to return to install." 275 sh 276 ;; 277 !*) eval ${resp#?} 278 ;; 279 *) : ${resp:=$_default} 280 break 281 ;; 282 esac 283 done 284 set +o noglob 285} 286 287# Ask for user input until a non-empty reply is entered. 288# 289# $1 = the question to ask the user 290# $2 = the default answer 291# 292# Save the user input (or the default) in $resp. 293ask_until() { 294 resp= 295 while [[ -z $resp ]]; do 296 ask "$1" "$2" 297 done 298} 299 300# Ask the user for a y or n, and insist on 'y', 'yes', 'n' or 'no'. 301# 302# $1 = the question to ask the user 303# $2 = the default answer (assumed to be 'n' if empty). 304# 305# Return 'y' or 'n' in $resp. 306ask_yn() { 307 typeset _q=$1 _a=${2:-no} _resp 308 typeset -l _resp 309 310 while :; do 311 ask "$_q" "$_a" 312 _resp=$resp 313 case $_resp in 314 y|yes) resp=y; return ;; 315 n|no) resp=n; return ;; 316 esac 317 done 318 } 319 320# Ask for the user to select one value from a list, or 'done'. 321# 322# $1 = name of the list items (disk, cd, etc.) 323# $2 = question to ask 324# $3 = list of valid choices 325# $4 = default choice, if it is not specified use the first item in $3 326# $5 = error message if no items in $3, defaults to 'No $1s found.' 327# 328# At exit $resp holds selected item, or 'done' 329ask_which() { 330 typeset _name=$1 _query=$2 _list=$3 _def=$4 _err=$5 331 332 set -- $_list 333 if (( $# < 1 )); then 334 echo "${_err:=No ${_name}s found}." 335 resp=done 336 return 337 fi 338 : ${_def:=$1} 339 340 # Eliminate extraneous (especially trailing) whitespace in _list. 341 _list="$*" 342 343 while :; do 344 # Put both lines in ask prompt, rather than use a 345 # separate 'echo' to ensure the entire question is 346 # re-ask'ed after a '!' or '!foo' shell escape. 347 ask "Available ${_name}s are: $_list.\nWhich one $_query? (or 'done')" "$_def" 348 349 # Quote $resp to prevent user from confusing isin() by 350 # entering something like 'a a'. 351 isin "$resp" $_list done && break 352 echo "'$resp' is not a valid choice." 353 done 354} 355 356# test the first argument against the remaining ones, return success on a match 357isin() { 358 typeset _a=$1 _b 359 360 shift 361 for _b; do 362 [[ $_a = $_b ]] && return 0 363 done 364 return 1 365} 366 367# add first argument to list formed by the remaining arguments 368# adds to the tail if the element does not already exist 369addel() { 370 typeset _a=$1 371 372 shift 373 374 echo -n "$*" 375 isin "$_a" $* || echo -n " $_a" 376} 377 378# remove all occurrences of first argument from list formed by 379# the remaining arguments 380rmel() { 381 typeset _a=$1 _b 382 383 shift 384 for _b; do 385 [[ $_a != $_b ]] && echo -n "$_b " 386 done 387} 388 389bsort() { 390 typeset _l _a=$1 _b 391 392 (( $# > 0 )) || return 393 394 shift 395 for _b; do 396 if [[ $_a != $_b ]]; then 397 if [[ $_a >$_b ]]; then 398 _l="$_a $_l"; _a=$_b 399 else 400 _l="$_b $_l" 401 fi 402 fi 403 done 404 405 # Output the smallest value found. 406 echo -n "$_a " 407 408 # Sort remaining values. 409 bsort $_l 410} 411 412# Add interesting/useful comments from mnt/etc/$1 to /tmp/$1. 413# 414# $1 == file in /tmp and /mnt/etc directories 415save_comments() { 416 typeset _file=$1 417 418 if [[ -f /mnt/etc/$_file ]]; then 419 grep "^#" /mnt/etc/$_file >/tmp/$_file.new 420 [[ -f /tmp/$_file ]] && cat /tmp/$_file >>/tmp/$_file.new 421 mv /tmp/$_file.new /tmp/$_file 422 fi 423} 424 425# Offer to edit a file in /tmp and execute ${EDITOR} to do so if the user 426# accepts the offer. 427# 428# $1 == file in /tmp to edit 429edit_tmp_file() { 430 typeset _file=$1 431 432 ask_yn "Edit $_file with $EDITOR?" 433 [[ $resp = y ]] && $EDITOR /tmp/$_file 434} 435 436# Offer to shell out for manual network configuration, and do so if 437# the user accepts the offer. 438manual_net_cfg() { 439 typeset _x 440 441 ask_yn "Do you want to do any manual network configuration?" 442 443 [[ $resp = y ]] && { echo "Type 'exit' to return to $MODE."; sh; } 444 445 # the network is now up… 446 pf=https 447 ftp -h 2>&1 | fgrep https >/dev/null 2>&1 || pf=http 448 _getrnd net $pf 449 _ntp 450} 451 452# log in via ftp to host $1 as user $2 with password $3 453# and return a list of all files in the directory $4 on stdout 454ftp_list_files() { 455 ftp ${_ftp_active} -V -n "$1" <<__EOT 456user "$2" "$3" 457cd "$4" 458ls 459quit 460__EOT 461} 462 463# Create a device. 464# 465# $1 = name of the device to create. 466makedev() { 467 typeset _dev=$1 468 469 if [[ ! -r /dev/MAKEDEV ]]; then 470 echo "MAKEDEV not found. Can't create device nodes." 471 return 1 472 fi 473 474 cd /dev; mksh MAKEDEV $_dev || return 1 ; cd - >/dev/null 475} 476 477# Create an entry in the hosts file. If an entry with the 478# same symbolic name and address family already exists, delete it. 479# $1 - IP address (v6 if it contains ':', else v4) 480# $2 - symbolic name 481addhostent() { 482 typeset _addr=$1 _name=$2 _leader 483 484 if [[ $_addr = *:* ]]; then 485 _leader='/^[0-9a-fA-F]*:' 486 else 487 _leader='/^[0-9]*\.' 488 fi 489 sed "${_leader}.*[ ]$_name\$/d" /tmp/hosts >/tmp/hosts.new 490 echo "$_addr $_name" >>/tmp/hosts.new 491 mv /tmp/hosts.new /tmp/hosts 492} 493 494# Show list of available sets and let the user select which sets to install. 495# 496# $1 = available sets 497# $2 = already selected sets 498# 499# Set $resp to list of selected sets. 500select_sets() { 501 typeset _avail=$1 _selected=$2 _next _f _action 502 503 cat <<__EOT 504 505Select sets by entering a set name, a file name pattern or 'all'. De-select 506sets by prepending a '-' to the set name, file name pattern or 'all'. Selected 507sets are labelled '[x]'. 508__EOT 509 while :; do 510 _action= 511 _next= 512 echo 513 for _f in $_avail; do 514 if isin $_f $_selected; then 515 echo " [X] $_f" 516 else 517 echo " [ ] $_f" 518 : ${_next:=$_f} 519 fi 520 done 521 : ${_next:=done} 522 523 ask "Set name? (or 'done')" "$_next" 524 case $resp in 525 done) break ;; 526 -*) _action=rmel ;; 527 esac 528 529 : ${_action:=addel} 530 resp=${resp#+|-} 531 532 case $resp in 533 "") continue ;; 534 all) resp=* ;; 535 esac 536 537 # Use @($resp) rather than just $resp to protect 538 # against silly user input that might cause syntax 539 # errors. 540 for _f in $_avail; do 541 eval "case $_f in 542 @($resp)) _selected=\`$_action $_f \$_selected\` ;; 543 esac" 544 done 545 done 546 547 resp=$_selected 548} 549 550configure_ifs() { 551 typeset _IFDEVS=$(ifconfig -l) _ifs _name _media _hn 552 553 while :; do 554 ask_which "interface" "do you wish to initialise" "$_IFDEVS" \ 555 "" "No more interfaces to initialise" 556 [[ $resp = done ]] && break 557 558 _ifs=$resp 559 _hn=/tmp/hostname.$_ifs 560 561 # Get symbolic name - will be used in DHCP requests. 562 ask "Symbolic (host) name for $_ifs?" "$(hostname -s)" 563 _name=$resp 564 565 # Get and apply media options. 566 _media=$(ifconfig -m $_ifs | grep "media ") 567 if [[ -n $_media ]]; then 568 cat <<__EOT 569The media options for $_ifs are currently 570$(ifconfig -m $_ifs | sed -n '/supported/D;/media:/p') 571__EOT 572 ask_yn "Do you want to change the media options?" 573 case $resp in 574 y) cat <<__EOT 575Supported media options for $_ifs are: 576$_media 577__EOT 578 ask "Media options for $_ifs?" 579 _media=$resp 580 ifconfig $_ifs $_media || return 1 581 ;; 582 n) _media= 583 ;; 584 esac 585 fi 586 587 rm -f $_hn 588 v4_config "$_ifs" "$_media" "$_name" "$_hn" 589 v6_config "$_ifs" "$_media" "$_name" "$_hn" 590 591 [[ -f $_hn ]] && _IFDEVS=$(rmel "$_ifs" $_IFDEVS) 592 done 593} 594 595# Output '<UP | DOWN> [<addr> <netmask> <rest of inet line>]'. 596# 597# $1 == interface 598v4_info() { 599 ifconfig $1 inet | sed -n ' 600 1s/.*<UP,.*/UP/p 601 1s/.*<.*/DOWN/p 602 /inet/s/netmask// 603 /inet/s///p' 604} 605 606# Obtain and output the inet6 information related to the given 607# interface. Should output '<UP/DOWN> <addr> <prefixlen> <rest of inet line> '. 608# 609# $1 == interface 610v6_info() { 611 ifconfig $1 inet6 | sed -n ' 612 1s/.*<UP,.*/UP/p 613 1s/.*<.*/DOWN/p 614 /scopeid/d 615 /inet6/s///p' 616} 617 618# Construct etc/dhclient.conf and issue DHCP request. Return FALSE if 619# no IP address assigned to $1. 620# 621# $1 == interface 622# $2 == hostname (optional). 623dhcp_request() { 624 typeset _ifs=$1 _hn=$2 625 626 echo "lookup file bind" >/etc/resolv.conf.tail 627 628 if [[ -n $_hn ]]; then 629 _hn="send host-name \"$_hn\";" 630 echo "Issuing hostname-associated DHCP request for $_ifs." 631 else 632 echo "Issuing free-roaming DHCP request for $_ifs." 633 fi 634 635 cat >/etc/dhclient.conf <<__EOT 636initial-interval 1; 637$_hn 638request subnet-mask, broadcast-address, routers, domain-name, 639 domain-name-servers, host-name; 640__EOT 641 642 dhclient $_ifs 643 644 set -- $(v4_info $_ifs) 645 646 if [[ $1 = UP && -n $2 ]]; then 647 # Move configuration files to where they will be copied to the 648 # installed system. Overwrites configuration information from 649 # last successful dhcp attempt. 650 mv /etc/dhclient.conf /tmp/dhclient.conf 651 mv /etc/resolv.conf.tail /tmp/resolv.conf.tail 652 return 0 653 fi 654 655 ifconfig $_ifs delete down 656 rm /etc/dhclient.conf /etc/resolv.conf.tail 657 return 1 658} 659 660v4_config() { 661 typeset _ifs=$1 _media=$2 _name=$3 _hn=$4 _prompt 662 663 set -- $(v4_info $_ifs) 664 if [[ -n $2 ]]; then 665 ifconfig $_ifs inet $2 delete 666 [[ $2 != "0.0.0.0" ]] && { _addr=$2; _mask=$3; } 667 fi 668 669 [[ -x /sbin/dhclient ]] && _prompt=" or 'dhcp'" 670 _prompt="IPv4 address for $_ifs? (or 'none'$_prompt)" 671 672 ask_until "$_prompt" "$_addr" 673 case $resp in 674 none) ;; 675 dhcp) if [[ ! -x /sbin/dhclient ]]; then 676 echo "DHCP not possible - no /sbin/dhclient." 677 elif dhcp_request $_ifs "$_name" || dhcp_request $_ifs ; then 678 addhostent "127.0.0.1" "$_name" 679 echo "dhcp NONE NONE NONE $_media" >>$_hn 680 dhcp_requested=", 'dhcp'" 681 fi 682 ;; 683 *) _addr=$resp 684 ask_until "Netmask?" "${_mask:=255.255.255.0}" 685 if ifconfig $_ifs inet $_addr netmask $resp up ; then 686 addhostent "$_addr" "$_name" 687 echo "inet $_addr $resp NONE $_media" >$_hn 688 fi 689 ;; 690 esac 691} 692 693v6_config() { 694 typeset _ifs=$1 _media=$2 _name=$3 _hn=$4 _addr _prefixlen _prompt _eui 695 696 ifconfig lo0 inet6 >/dev/null 2>&1 || return 697 698 set -- $(v6_info $_ifs) 699 [[ -n $2 ]] && { _addr=$2; _prefixlen=$3; } 700 701 [[ -x /sbin/rtsol ]] && _prompt="or 'rtsol' " 702 echo To append EUI64 automatically, let the address end with two colons. 703 _prompt="IPv6 address for $_ifs? (${_prompt}or 'none')" 704 ask_until "$_prompt" "${_addr:-none}" 705 706 case $resp in 707 none) return 708 ;; 709 rtsol) [[ ! -x /sbin/rtsol ]] && { echo "No /sbin/rtsol." ; return ; } 710 sysctl -w net.inet6.ip6.accept_rtadv=1 711 ifconfig $_ifs up 712 rtsol $_ifs 713 addhostent "::1" "$_name" 714 echo "up\nrtsol $media" >>$_hn 715 return 716 ;; 717 *::) _eui=eui64 718 ;; 719 esac 720 721 _addr=$resp 722 ask_until "IPv6 prefix length for $_ifs?" "${_prefixlen:=64}" 723 ifconfig $_ifs inet6 $_addr prefixlen $resp $_eui up || return 724 echo inet6 $_addr $resp $_eui $media >>$_hn 725 if [[ -n $_eui ]]; then 726 set -- $(v6_info $_ifs) 727 [[ -n $2 ]] && _addr=$2 728 fi 729 addhostent "$_addr" "$_name" 730 731 v6_defroute $_ifs 732 [[ $resp = none ]] && return 733 route -n add -inet6 default "$resp" || return 734 echo "route add -inet6 default $resp" >>$_hn 735} 736 737v4_defroute() { 738 typeset _dr _fls _prompt=" or 'none'" 739 740 _prompt="Default IPv4 route? (IPv4 address$dhcp_requested$_prompt)" 741 742 _dr=$(route -n show -inet | sed -ne '/^default */{s///; s/ .*//; p;}') 743 [[ -f /tmp/dhclient.conf ]] && _dr=dhcp 744 745 while :; do 746 ask_until "$_prompt" "$_dr" 747 [[ $resp = @(none|dhcp) ]] && break 748 route -n delete -inet default >/dev/null 2>&1 749 route -n add -inet default "$resp" && { 750 set -A _fls -- /tmp/hostname.* 751 (( ${#_fls[*]} == 1 )) || _fls=/tmp/hostname.local 752 echo "route add -inet default $resp" >>$_fls 753 break 754 } 755 # Put the old default route back. The new one did not work. 756 route -n add -inet default $_dr >/dev/null 2>&1 757 done 758} 759 760v6_defroute() { 761 typeset _if=$1 _routers _oifs 762 763 if [[ -n $(route -n show -inet6 | sed -ne '/^default */{s///; s/ .*//; p;}') ]]; then 764 resp=none 765 return 766 fi 767 768 if [[ -x /sbin/ping6 ]]; then 769 _routers=$(ping6 -n -c 2 ff02::2%$_if 2>&1 | sed -n \ 770 -e '/bytes from/{s/^.*from //;s/,.*$//;p;}') 771 fi 772 773 _oifs=$IFS 774 IFS= 775 PS3="IPv6 default router? (list #, IPv6 address or 'none'): " 776 select i in $_routers; do 777 case $i in 778 "") resp=$REPLY 779 [[ -n $resp ]] && break 780 ;; 781 *) resp=$i 782 break 783 ;; 784 esac 785 done 786 IFS=$_oifs 787} 788 789# Much of this is gratuitously stolen from /etc/netstart. 790enable_network() { 791 typeset _netfile 792 793 # Copy any required or optional files found 794 for _netfile in hosts dhclient.conf resolv.conf resolv.conf.tail protocols services; do 795 if [ -f /mnt/etc/${_netfile} ]; then 796 cp /mnt/etc/${_netfile} /etc/${_netfile} 797 fi 798 done 799 800 # Set the address for the loopback interface. Bringing the 801 # interface up, automatically invokes the IPv6 address ::1. 802 ifconfig lo0 inet 127.0.0.1 803 804 # configure all of the non-loopback interfaces which we know about. 805 # refer to hostname.if(5) 806 for hn in /mnt/etc/hostname.*; do 807 # Strip off /mnt/etc/hostname. prefix 808 if=${hn#/mnt/etc/hostname.} 809 810 # Check for ifconfig'able interface. 811 ifconfig $if >/dev/null 2>&1 || continue 812 813 # Now parse the hostname.* file 814 while :; do 815 if [ "$cmd2" ]; then 816 # we are carrying over from the 817 # 'read dt dtaddr' last time 818 set -A i -- $cmd2 819 af=${i[0]} 820 name=${i[1]} 821 mask=${i[2]} 822 bcaddr=${i[3]} 823 ext1=${i[4]} 824 unset i[0] i[1] i[2] i[3] i[4] 825 ext2="${i[*]}" 826 cmd2= 827 else 828 # read the next line or exit the while loop 829 read af name mask bcaddr ext1 ext2 || break 830 fi 831 # $af can be "dhcp", "up", "rtsol", an address family, commands, or 832 # a comment. 833 case $af in 834 "route"|"!route") 835 routep="-n $name" 836 [ x"$name" = x"+n" ] && routep= 837 cmd="/sbin/route ${routep} ${mask} ${bcaddr} ${ext1} ${ext2}" 838 ;; 839 "#"*|"!"*|"bridge"|"") 840 # skip comments, user commands, bridges, 841 # and empty lines 842 continue 843 ;; 844 "dhcp") [ "$name" = "NONE" ] && name= 845 [ "$mask" = "NONE" ] && mask= 846 [ "$bcaddr" = "NONE" ] && bcaddr= 847 ifconfig $if $name $mask $bcaddr $ext1 $ext2 down 848 cmd="dhclient $if" 849 ;; 850 "rtsol") 851 ifconfig $if $name $mask $bcaddr $ext1 $ext2 up 852 rtsif="$rtsif $if" 853 cmd= 854 ;; 855 "up") 856 # The only one of these guaranteed to be set is $if 857 # the remaining ones exist so that media controls work 858 cmd="ifconfig $if $name $mask $bcaddr $ext1 $ext2 up" 859 ;; 860 *) read dt dtaddr 861 if [ "$name" = "alias" ]; then 862 # perform a 'shift' of sorts 863 alias=$name 864 name=$mask 865 mask=$bcaddr 866 bcaddr=$ext1 867 ext1=$ext2 868 ext2= 869 else 870 alias= 871 fi 872 cmd="ifconfig $if $af $alias $name " 873 case $dt in 874 dest) cmd="$cmd $dtaddr" 875 ;; 876 [a-z!]*) 877 cmd2="$dt $dtaddr" 878 ;; 879 esac 880 if [ ! -n "$name" ]; then 881 echo "/mnt/etc/hostname.$if: invalid network configuration file" 882 return 883 fi 884 case $af in 885 inet) [ "$mask" ] && cmd="$cmd netmask $mask" 886 if [ "$bcaddr" -a "$bcaddr" != "NONE" ]; then 887 cmd="$cmd broadcast $bcaddr" 888 fi 889 [ "$alias" ] && rtcmd="; route -qn add -host $name 127.0.0.1" 890 ;; 891 inet6) 892 [ "$mask" ] && cmd="$cmd prefixlen $mask" 893 cmd="$cmd $bcaddr" 894 ;; 895 *) cmd="$cmd $mask $bcaddr" 896 esac 897 cmd="$cmd $ext1 $ext2$rtcmd" rtcmd= 898 ;; 899 esac 900 eval "$cmd" 901 done </mnt/etc/hostname.$if 902 done 903 904 # Use loopback, not the wire. 905 route -qn add -host $(hostname) 127.0.0.1 >/dev/null 906 route -qn add -net 127 127.0.0.1 -reject >/dev/null 907 908 # Grab default route, if existent 909 if [ -s /mnt/etc/hostname.local ]; then 910 cmd="$(grep ^route /mnt/etc/hostname.local | grep default)" 911 [[ -n $cmd ]] && eval "$cmd" 912 fi 913 914 # Display results... 915 echo "Network interface configuration:" 916 ifconfig -am 917 918 # enable the resolver if resolv.conf is available 919 route -n show 920 if [ -f /etc/resolv.conf ]; then 921 echo "\nResolver enabled." 922 else 923 echo "\nResolver not enabled." 924 fi 925} 926 927# Install a user-selected subset of the files in $2 from the source 928# named in $1. Display an error message for failed installs so the 929# user will know to try again. 930install_files() { 931 typeset _src=$1 _files=$2 _f _sets _get_sets 932 933 # Initialize _sets to the list of sets found in _src, and initialize 934 # _get_sets to the intersection of _sets and DEFAULTSETS. 935 # 936 # Sets will be installed in the order given in THESETS to ensure proper 937 # installation. So, to minimize user confusion display the sets in the 938 # order in which they will be installed. 939 for _f in $THESETS; do 940 isin $_f $_files || continue; 941 _sets=$(addel $_f $_sets) 942 isin $_f $DEFAULTSETS && _get_sets=$(addel $_f $_get_sets) 943 done 944 945 if [[ -z $_sets ]]; then 946 # Show $_src, but delete any ftp password. 947 cat <<__EOT 948No $OBSD sets were found at 949 950 $(echo $_src | sed -e 's/\(^ftp:\/\/[^/]*\)\(:[^/]*\)\(@.*\)/\1\3/') 951 952Set names are: $THESETS 953__EOT 954 return 955 fi 956 957 select_sets "$_sets" "$_get_sets" 958 959 [[ -n $resp ]] || return 960 _get_sets=$resp 961 962 ask_yn "Ready to $MODE sets?" yes 963 [[ $resp = n ]] && return 964 965 for _f in $THESETS; do 966 isin $_f $_get_sets || continue 967 echo "Getting $_f ..." 968 case $_f in 969 *.ngz) ftp $_ftp_active -o - -V -m "$_src/$_f" | \ 970 gzip -dcf | tar -M lncp -xphf - -C /mnt 971 ;; 972 *) ftp $_ftp_active -o "/mnt/$_f" -V -m "$_src/$_f" 973 ;; 974 esac 975 if [ $? -ne 0 ]; then 976 echo "'$_f' did not install correctly." 977 else 978 DEFAULTSETS=$(rmel $_f $DEFAULTSETS) 979 fi 980 done 981} 982 983# Encode $1 as specified for usercodes and passwords in RFC 1738 984# section 3.1 and section 5. 985# 986# Escape everything between 0x20 and 0x7e to avoid both illegal url 987# characters and characters causing problems during script processing. 988# 989# *NOTE* 990# 1) quotes around $1 are required to preserve trailing or 991# embeddded blanks in usercodes and passwords. 992# 2) substitute '%' FIRST so it doesn't eliminate '%' chars we insert. 993encode_for_url() { 994 print -nr -- "$1" | sed -e ' 995s.%.%25.g 996s.;.%3B.g 997s./.%2F.g 998s.?.%3F.g 999s.:.%3A.g 1000s.@.%40.g 1001s.&.%26.g 1002s.=.%3D.g 1003s.+.%2B.g 1004s.\$.%24.g 1005s.,.%2C.g 1006s. .%09.g 1007s. .%20.g 1008s.<.%3C.g 1009s.>.%3E.g 1010s.#.%23.g 1011s.".%22.g 1012s.{.%7B.g 1013s.}.%7D.g 1014s.|.%7C.g 1015s.\\.%5C.g 1016s.\^.%5E.g 1017s.\[.%5B.g 1018s.].%5D.g 1019s.`.%60.g 1020s.'\''.%27.g 1021s/!/%21/g 1022s/(/%28/g 1023s/)/%29/g 1024s/\*/%2a/g 1025s/-/%2d/g 1026s/\./%2e/g 1027s/_/%5f/g 1028s/~/%7e/g 1029' 1030} 1031 1032# Check for the presence of an error message in the output of the ftp commands 1033# used to get the list of files in a directory. 1034# 1035# $1 = error message to look for 1036# $2 = ftp command output 1037ftp_error() { 1038 if [[ -n $(echo "$2" | grep "$1") ]]; then 1039 echo $1 1040 return 0 1041 fi 1042 return 1 1043} 1044 1045# Get several parameters from the user, and xfer 1046# files from the server. 1047# $1 = url type (ftp, http or https) 1048# Note: _ftp_server_ip, _ftp_server_dir, _ftp_server_login, 1049# and _ftp_active must be global. 1050install_url() { 1051 typeset _url_type=$1 _file_list _url_base _oifs _prompt _passwd 1052 1053 ask "HTTP/FTP proxy URL? (e.g. 'http://proxy:8080', or 'none')" \ 1054 "${ftp_proxy:-none}" 1055 unset ftp_proxy http_proxy 1056 [[ $resp = none ]] || export ftp_proxy=$resp http_proxy=$resp 1057 1058 rm -f $SERVERLIST 1059# ask_yn "Display the list of known $_url_type servers?" "${_get_server_list:-yes}" 1060# _get_server_list=$resp 1061 _get_server_list=n 1062# if [[ $_get_server_list = y ]]; then 1063# # ftp.openbsd.org == 129.128.5.191 and will remain at 1064# # that address for the forseeable future. 1065# echo -n "Getting the list from 129.128.5.191 (ftp.openbsd.org)..." 1066# ftp $_ftp_active -V -a -o - \ 1067# ftp://129.128.5.191/$FTPDIR/ftplist 2>/tmp/ftplisterr \ 1068# | sed -ne "/^${_url_type}:\/\//s///p" >$SERVERLIST 1069# if [[ -s $SERVERLIST ]]; then 1070# echo "done." 1071# _prompt="Server? (IP address, hostname, list#, 'done' or '?')" 1072# sed = $SERVERLIST | sed 'N;s/\n/ /' | less -XE 1073# else 1074# echo "FAILED." 1075# cat /tmp/ftplisterr 1076# fi 1077# fi 1078 1079 # Get server IP address or hostname 1080 : ${_prompt:="Server? (IP address, hostname or 'done')"} 1081 eval ': ${_'${_url_type}'_server_ip:=www.mirbsd.org}' 1082 while :; do 1083 eval resp=\$_${_url_type}_server_ip 1084 ask_until "$_prompt" "$resp" 1085 case $resp in 1086 done) return ;; 1087 "?") [[ -s $SERVERLIST ]] || continue 1088 sed = $SERVERLIST | sed 'N;s/\n/ /' | less -XE 1089 ;; 1090 +([0-9])) 1091 # A numeric hostname is ignored. A number is only used 1092 # as a line number in $SERVERLIST. 1093 [[ -s $SERVERLIST ]] || continue 1094 set -- $(sed -ne "${resp}p" $SERVERLIST) 1095 if (( $# < 1 )); then 1096 echo "There is no line $resp." 1097 continue 1098 fi 1099 echo "Using $*" 1100 eval _${_url_type}_server_ip=${1%%/*} 1101 eval _${_url_type}_server_dir=${1#*/}/$SETDIR 1102 # Repeat loop to get user to confirm server address. 1103 ;; 1104 *) eval _${_url_type}_server_ip=$resp 1105 break 1106 ;; 1107 esac 1108 done 1109 1110 # Some older servers lie about their support for passive mode ftp, so 1111 # ask the user if it worth trying passive mode to the chosen server. 1112 # Irrelevant if using a proxy. 1113 if [[ $_url_type = ftp && -z $ftp_proxy ]]; then 1114 case $_ftp_active in 1115 -A) resp=no ;; 1116 *) resp=yes ;; 1117 esac 1118 1119 unset _ftp_active 1120 ask_yn "Does the server support passive mode ftp?" $resp 1121 [[ $resp = n ]] && _ftp_active=-A 1122 fi 1123 1124 # Get server directory 1125 eval resp=\$_${_url_type}_server_dir 1126 ask_until "Server directory?" "${resp:-$FTPDIR$SETDIR}" 1127 eval _${_url_type}_server_dir=$resp 1128 1129 if [[ $_url_type = ftp ]]; then 1130 # Get login name, setting IFS to nothing so trailing or 1131 # embedded blanks are preserved! 1132 _oifs=$IFS 1133 IFS= 1134 ask_until "Login?" "${_ftp_server_login:=anonymous}" 1135 _ftp_server_login=$resp 1136 1137 # Get password unless anonymous 1138 _passwd=root@$(hostname) 1139 if [[ $_ftp_server_login != anonymous ]]; then 1140 resp= 1141 while [[ -z $resp ]]; do 1142 askpass "Password? (will not echo)" 1143 done 1144 _passwd=$resp 1145 fi 1146 IFS=$_oifs 1147 fi 1148 1149 # Build up the base url since it is so nasty... 1150 _url_base=$_url_type:// 1151 if [[ $_url_type = ftp && $_ftp_server_login != anonymous ]]; then 1152 _url_base=$_url_base$(encode_for_url "$_ftp_server_login"):$(encode_for_url "$_passwd")@ 1153 fi 1154 eval _url_base=$_url_base\$_${_url_type}_server_ip/\$_${_url_type}_server_dir 1155 1156 # XXX Workaround for problems ftp'ing out from a v6 only host. 1157 ifconfig lo0 127.0.0.1 1158 1159 # Get list of files from the server. 1160 if [[ $_url_type = ftp && -z $ftp_proxy ]]; then 1161 _file_list=$(ftp_list_files "$_ftp_server_ip" "$_ftp_server_login" "$_passwd" "$_ftp_server_dir") 1162 ftp_error "Login failed." "$_file_list" && return 1163 ftp_error "No such file or directory." "$_file_list" && return 1164 else 1165 # Assumes index file is "index.txt" for http (or proxy) 1166 # We can't use index.html since the format is server-dependent 1167 _file_list=$(ftp -o - -V "$_url_base/index.txt" | sed 's/ 1168//') 1169 fi 1170 1171 install_files "$_url_base" "$_file_list" 1172} 1173 1174install_mounted_fs() { 1175 typeset _dir 1176 1177 while :; do 1178 ask_until "Pathname to the sets? (or 'done')" "$SETDIR" 1179 [[ $resp = done ]] && return 1180 # Accept a valid /mnt2 or /mnt relative path. 1181 [[ -d /mnt2/$resp ]] && { _dir=/mnt2/$resp ; break ; } 1182 [[ -d /mnt/$resp ]] && { _dir=/mnt/$resp ; break ; } 1183 # Accept a valid absolute path. 1184 [[ -d /$resp ]] && { _dir=/$resp ; break ; } 1185 echo "The directory '$resp' does not exist." 1186 done 1187 1188 install_files "file://$_dir" "$(ls -l $_dir)" 1189} 1190 1191install_cdrom() { 1192 typeset _drive _part=c _fstype _err=0 1193 1194 get_drive "CD-ROM" "$CDDEVS" || return 1195 _drive=$resp 1196 1197 set -- $(disklabel $_drive 2>&1 | grep '^ c: ') || _err=1 1198 case $_err:$4 in 1199 1*|0:ISO9660) 1200 _fstype=cd9660 ;; 1201 0:UDF) _fstype=udf ;; 1202 *) get_partition $_drive "cd9660" || return 1203 set -- $resp 1204 _part=$1 1205 [[ -n $2 ]] && _fstype=$2 1206 ;; 1207 esac 1208 1209 mount -t $_fstype -o ro /dev/$_drive$_part /mnt2 || return 1210 install_mounted_fs 1211} 1212 1213install_disk() { 1214 typeset _drive _dev _fstype _fsopts 1215 1216 ask_yn "Is the disk partition already mounted?" 1217 if [[ $resp = n ]]; then 1218 get_drive "disk" "$DKDEVS" || return 1219 _drive=$resp 1220 1221 get_partition $_drive "$MDFSTYPE" || return 1222 set -- $resp 1223 _dev=/dev/$_drive$1 1224 [[ -n $2 ]] && _fstype="-t $2" 1225 [[ $_fstype = $MDFSTYPE ]] && _fsopts=$MDFSOPTS 1226 1227 if [[ -z $(mount | grep "^$_dev") ]]; then 1228 mount $_fstype -o ro,$_fsopts $_dev /mnt2 || return 1229 fi 1230 fi 1231 install_mounted_fs 1232} 1233 1234install_nfs() { 1235 typeset _tcp 1236 1237 # Get the IP address of the server. 1238 ask_until "Server IP address or hostname?" "$NFS_ADDR" 1239 NFS_ADDR=$resp 1240 1241 # Get the server path to mount. 1242 ask_until "Filesystem on server to mount?" "$NFS_PATH" 1243 NFS_PATH=$resp 1244 1245 # Determine use of TCP 1246 ask_yn "Use TCP transport? (requires TCP-capable NFS server)" yes 1247 [[ $resp = y ]] && _tcp=-T 1248 1249 # Mount the server 1250 mount_nfs $_tcp -o ro $NFS_ADDR:$NFS_PATH /mnt2 || return 1251 1252 install_mounted_fs 1253} 1254 1255install_tape() { 1256 typeset _z _bs 1257 1258 # Get the name of the tape device. 1259 get_drive "tape drive" "$MTDEVS" || return 1260 export TAPE=/dev/nr$resp 1261 if [[ ! -c $TAPE ]]; then 1262 echo "$TAPE is not a character special file." 1263 return 1264 fi 1265 1266 # Rewind the tape device. 1267 echo -n "Rewinding $TAPE (mt rewind)..." 1268 mt rewind || return 1269 echo "done." 1270 1271 # Extract the desired files. 1272 while :; do 1273 ask_until "Skip how many files? (or 'done')" 0 1274 [[ $resp = done ]] && return 1275 [[ $resp = +([0-9]) ]] || continue 1276 (( resp < 0 )) && continue 1277 1278 if (( resp > 0 )); then 1279 echo -n "Skipping $resp file(s)..." 1280 mt fsf $resp || return 1281 echo "done." 1282 elif [[ -n $_bs ]]; then 1283 # Dance to start of next file. 1284 mt bsf ; mt fsf 1285 fi 1286 1287 unset _z 1288 ask_yn "Is the file gzipped?" yes 1289 [[ $resp = y ]] && _z=z 1290 1291 # Get the blocksize to use. If the file isn't gzipped then 1292 # default to the 20 x 512 = 10,240 byte tar default. 1293 [[ $_z = z ]] || _bs=10240 1294 ask_until "Blocksize for this file?" "${_bs:-8k}" 1295 [[ $resp = done ]] && return 1296 _bs=$resp 1297 1298 dd if=$TAPE bs=$_bs | tar -M lncp -${_z}xvphf - -C /mnt || \ 1299 return 1300 done 1301} 1302 1303set_timezone() { 1304 typeset _zoneroot=/mnt/usr/share/zoneinfo/ _zonepath 1305 1306 # If the timezone directory structure is not 1307 # available, return immediately. 1308 1309 [[ ! -d $_zoneroot ]] && return 1310 1311 if [[ -L /mnt/etc/localtime ]]; then 1312 TZ=$(ls -l /mnt/etc/localtime 2>/dev/null) 1313 TZ=${TZ#*${_zoneroot#/mnt}} 1314 fi 1315 1316 : ${TZ:=GMT} 1317 1318 while :; do 1319 _zonepath=$_zoneroot 1320 1321 ask "What timezone are you in? ('?' for list)" "$TZ" 1322 1323 if [[ $resp = ? ]]; then 1324 ls -F ${_zonepath} 1325 continue; 1326 fi 1327 1328 _zonepath=${_zonepath}${resp} 1329 1330 while [[ -d $_zonepath ]]; do 1331 ask "What sub-timezone of '${_zonepath#$_zoneroot}' are you in? ('?' for list)" 1332 case $resp in 1333 "") ;; 1334 ?) ls -F $_zonepath ;; 1335 *) _zonepath=$_zonepath/$resp ;; 1336 esac 1337 done 1338 1339 if [[ -f $_zonepath ]]; then 1340 TZ=${_zonepath#$_zoneroot} 1341 echo -n "Setting local timezone to '$TZ'..." 1342 ln -sf /usr/share/zoneinfo/$TZ /mnt/etc/localtime 1343 echo "done." 1344 return 1345 fi 1346 1347 echo -n "'${_zonepath#$_zoneroot}'" 1348 echo " is not a valid timezone on this system." 1349 done 1350} 1351 1352# Check with the user that missing required sets were deliberately skipped. 1353sane_install() { 1354 typeset _s _m 1355 1356 for _s in $SANESETS; do 1357 isin $_s $DEFAULTSETS || continue 1358 ask_yn "'$_s' was not installed.\nAre you *SURE* your $MODE is complete without '$_s'?" 1359 [[ $resp = n ]] && _m="$_m $_s" 1360 done 1361 1362 [[ -n $_m ]] && return 1 1363 return 0 1364} 1365 1366# Ask the user for locations of sets, and then install whatever sets the 1367# user selects from that location. Repeat as many times as the user 1368# needs to get all desired sets. 1369install_sets() { 1370 typeset _d=disk _locs="disk ftp http shttp" 1371 1372 [[ -n $CDDEVS ]] && { _locs="cd $_locs" ; _d=cd ; } 1373 [[ -x /sbin/mount_nfs ]] && _locs="$_locs nfs" 1374 [[ -n $MTDEVS && -x /bin/mt ]] && _locs="$_locs tape" 1375 1376 echo "\nLet's $MODE the sets!" 1377 while :; do 1378 umount -f /mnt2 >/dev/null 2>&1 1379 [[ -z $DEFAULTSETS ]] && _d=done 1380 1381 ask "Location of sets? ($_locs or 'done')" "$_d" 1382 case $resp in 1383 done) sane_install && return ;; 1384 c*|C*) isin "cd" $_locs && install_cdrom ;; 1385 d*|D*) install_disk ;; 1386 f*|F*) isin "ftp" $_locs && install_url ftp ;; 1387 h*|H*) isin "http" $_locs && install_url http ;; 1388 n*|N*) isin "nfs" $_locs && install_nfs ;; 1389 s*|S*) isin "http" $_locs && install_url https ;; 1390 t*|T*) isin "tape" $_locs && install_tape ;; 1391 esac 1392 done 1393} 1394 1395# Create a skeletal but useful /etc/fstab from /tmp/fstab by stripping all 1396# comment lines and dropping all filesystems which 1397# 1398# 1) can't be mounted (no mount_* command is found), 1399# 2) have 'xx' in the option field (usually /altroot), 1400# 3) have 'noauto' in the option field, 1401# 4) are nfs (since name resolution may not be present), 1402# 5) are mfs (breaks install usually). 1403# 1404# In addition, 1405# 1406# 2) mount non-ffs filesystems read only, 1407# 3) prepend '/mnt' to all mount points, 1408# 4) delete any trailing '/' from the mount point (e.g. root), 1409# 5) leave out fs_freq and fs_passno fields. 1410# 1411# If no /etc/fstab is created, do not proceed with install/upgrade. 1412munge_fstab() { 1413 typeset _dev _mp _fstype _opt _rest 1414 1415 while read _dev _mp _fstype _opt _rest; do 1416 # Drop irrelevant lines and filesystems. 1417 [[ $_dev = \#* || \ 1418 $_fstype = nfs || \ 1419 $_fstype = mfs || \ 1420 ! -f /sbin/mount_$_fstype || \ 1421 $_opt = *noauto* || \ 1422 $_opt = *xx* ]] && continue 1423 1424 # Mount non-ffs filesystems read only. 1425 [[ $_fstype = ffs ]] || _opt=$(echo $_opt | sed -e 's/rw/ro/') 1426 1427 # Write fs entry in fstab. 1428 # 1) prepend '/mnt' to the mount point. 1429 # 2) remove a trailing '/' from the mount point (e.g. root). 1430 # 3) leave out fs_freq and fs_passno fields (i.e. $_rest). 1431 echo $_dev /mnt${_mp%/} $_fstype $_opt 1432 1433 done </tmp/fstab >/etc/fstab 1434 1435 # If no /etc/fstab was created, we have nowhere to $MODE to. 1436 if [ ! -s /etc/fstab ]; then 1437 echo "Unable to create valid /etc/fstab." 1438 exit 1439 fi 1440} 1441 1442# Must mount filesystems manually, one at a time, so we can make 1443# sure the mount points exist. 1444mount_fs() { 1445 typeset _async=$1 _dev _mp _fstype _opt _rest 1446 1447 while read _dev _mp _fstype _opt _rest; do 1448 # If not the root filesystem, make sure the mount 1449 # point is present. 1450 [ "$_mp" = "/mnt" ] || mkdir -p $_mp 1451 1452 # Mount the filesystem. If the mount fails, exit. 1453 mount -v -t $_fstype $_async -o $_opt $_dev $_mp && continue 1454 # If it failed, try without async (important for raid) first 1455 mount -v -t $_fstype -o $_opt $_dev $_mp && continue 1456 # In addition to the error message displayed by mount ... 1457 cat <<__EOT 1458 1459FATAL ERROR: Cannot mount filesystems. Double-check your configuration 1460 and restart the $MODE. 1461 1462__EOT 1463 exit 1464 done </etc/fstab 1465 [[ -s /mnt/var/db/host.random ]] && \ 1466 cat /mnt/var/db/host.random >/dev/arandom 1467} 1468 1469# Preen all filesystems in /etc/fstab that have a /sbin/fsck_XXX, 1470# showing individual results, but skipping $ROOTDEV. This was already 1471# fsck'ed successfully. 1472# 1473# Exit if any fsck's fail (but do them all before exiting!). 1474check_fs() { 1475 typeset _dev _mp _fstype _rest _fail 1476 1477 echo "Checking non-root filesystems..." 1478 1479 while read _dev _mp _fstype _rest; do 1480 [ "$_dev" != /dev/"$ROOTDEV" ] || continue 1481 [ -f "/sbin/fsck_$_fstype" ] || continue 1482 # Make sure device exists before fsck'ing it. 1483 _rest=${_dev#/dev/} 1484 makedev ${_rest%[a-p]} || continue 1485 echo -n "fsck -p ${_dev}..." 1486 if ! fsck -fp ${_dev} >/dev/null 2>&1; then 1487 echo "FAILED. You must fsck $_dev manually." 1488 _fail=y 1489 else 1490 echo "OK." 1491 fi 1492 done </etc/fstab 1493 1494 echo "...done." 1495 1496 [ "$_fail" ] && exit 1497} 1498 1499# Extract fully qualified domain name from current hostname. If none is 1500# currently set, use 'my.domain'. 1501get_fqdn() { 1502 typeset _dn 1503 1504 _dn=$(hostname) 1505 _dn=${_dn#$(hostname -s)} 1506 _dn=${_dn#.} 1507 1508 echo "${_dn:=my.domain}" 1509} 1510 1511donetconfig() { 1512 typeset _dn _ns _n 1513 1514 configure_ifs 1515 1516 # As dhclient will populate /etc/resolv.conf, a symbolic link to 1517 # /tmp/resolv.conf.shadow, mv any such file to /tmp/resolv.conf 1518 # so it will eventually be copied to /mnt/etc/resolv.conf and will 1519 # not in the meantime remove the user's ability to choose to use it 1520 # or not, during the rest of the install. 1521 if [ -f /tmp/resolv.conf.shadow ]; then 1522 mv /tmp/resolv.conf.shadow /tmp/resolv.conf 1523 # Get nameserver address(es). Store as a blank separated list. 1524 for _n in $(grep '^nameserver ' /tmp/resolv.conf); do 1525 [[ $_n = nameserver ]] || _ns="$_ns$_n " 1526 done 1527 # Zap trailing space in _ns. 1528 set -- $_ns 1529 _ns=$* 1530 # Get default fully qualified domain name from *first* domain 1531 # given on *last* search or domain statement. 1532 _dn=$(sed -n \ 1533 -e '/^domain[[:space:]][[:space:]]*/{s///;s/\([^[:space:]]*\).*$/\1/;h;}' \ 1534 -e '/^search[[:space:]][[:space:]]*/{s///;s/\([^[:space:]]*\).*$/\1/;h;}' \ 1535 -e '${g;p;}' /tmp/resolv.conf) 1536 fi 1537 1538 # Get/Confirm an IPv4 default route if an IPv4 address was configured. 1539 [[ -n $(ifconfig -a | sed -ne '/[ ]inet .* broadcast /p') ]] && v4_defroute 1540 1541 # Get & apply fully qualified domain name to hostname. 1542 ask "DNS domain name? (e.g. 'bar.com')" "${_dn:=$(get_fqdn)}" 1543 hostname "$(hostname -s).$resp" 1544 1545 # Use a potential IPv4 default route as default nameserver 1546 [[ -n $_ns ]] || _ns=$(route -n show -inet | \ 1547 sed -ne '/^default */{s///; s/ .*//; p;}') 1548 1549 # Get/Confirm nameservers, and construct appropriate resolv.conf. 1550 ask "DNS nameserver? (IP address or 'none')" "${_ns:=none}" 1551 if [[ $resp != none ]]; then 1552 echo '# $MirSecuCron$' >/tmp/resolv.conf 1553 echo "lookup file bind" >>/tmp/resolv.conf 1554 for _ns in $resp; do 1555 echo "nameserver $_ns" >>/tmp/resolv.conf 1556 done 1557 ask_yn "Use the nameserver now?" yes 1558 [[ $resp = y ]] && cp /tmp/resolv.conf /tmp/resolv.conf.shadow 1559 fi 1560 1561 edit_tmp_file hosts 1562 manual_net_cfg 1563} 1564 1565questions() { 1566 [[ -e /mnt/etc/rc.conf.local ]] && mv -f /mnt/etc/rc.conf.local \ 1567 /mnt/etc/rc.conf.local~ 1568 1569 ask_yn "Start sshd(8) by default?" yes 1570 if [[ $resp = n ]]; then 1571 echo "sshd_flags=NO # disabled during install" \ 1572 >>/mnt/etc/rc.conf.local~ 1573 fi 1574 1575 ask_yn "Start ntpd(8) by default?" yes 1576 if [[ $resp = y ]]; then 1577 echo "ntpd_flags= # enabled during install" \ 1578 >>/mnt/etc/rc.conf.local~ 1579 echo "rdate_flags='-nv ntp.mirbsd.org'" >>/mnt/etc/rc.conf.local~ 1580 fi 1581 1582 if [[ -e /mnt/etc/rc.conf.local~ ]]; then 1583 (echo '# $MirSecuCron$'; echo; cat /mnt/etc/rc.conf.local~) \ 1584 >/mnt/etc/rc.conf.local 1585 rm -f /mnt/etc/rc.conf.local~ 1586 fi 1587 1588 if [[ -n $MDXAPERTURE ]]; then 1589 echo 'This setting affects the machdep.allowaperture sysctl.' 1590 echo 'If you respond negatively, you must enable it later in' 1591 echo '/etc/sysctl.conf in order to be able to run XFree86(R).' 1592 if [[ -e /mnt/usr/X11R6/bin/X ]]; then 1593 resp=yes 1594 else 1595 resp=no 1596 fi 1597 ask_yn "Do you expect to run the X Window System?" $resp 1598 if [[ $resp = y ]]; then 1599 sed -e "/^#\(machdep\.allowaperture=${MDXAPERTURE}\)/s//\1 /" \ 1600 /mnt/etc/sysctl.conf >/tmp/sysctl.conf 1601 cp /tmp/sysctl.conf /mnt/etc/sysctl.conf 1602 fi 1603 fi 1604 1605 echo 'The size for the RSA host key can now be selected here. Larger' 1606 echo 'key sizes usually mean more security, but always imply much' 1607 echo 'longer key exchange times (e.g. mail delivery, ssh login), so' 1608 echo 'they are not recommended for old boxen (say, a SPARCstation)' 1609 echo 'or if you have to communicate with them very often; choose a' 1610 echo 'lower size (e.g. 2048) than the default of 4096 then.' 1611 ask_which "size" "should the RSA host key have" \ 1612 "2048 3072 4096 6144 8192" 4096 1613 [[ $resp = done ]] || print "/4096/s//$resp/\nwq" | ed -s /mnt/etc/rc 1614 1615 [[ -z $SERIALDEV ]] && return 1616 ask_yn "Change the default console to $SERIALDEV?" 1617 [[ $resp = n ]] && return 1618 ask_which "speed" "should $SERIALDEV use" "9600 19200 38400 57600 115200" 1619 [[ $resp = done ]] && return 1620 echo '# $MirSecuCron$' >/mnt/boot.cfg 1621 echo "set tty $SERIALDEV\nstty $SERIALDEV $resp" >>/mnt/boot.cfg 1622} 1623 1624finish_up() { 1625 typeset _dev _mp _fstype _rest 1626 1627 # Mount all known swap partitions. This gives systems with little 1628 # memory a better chance at running 'MAKEDEV all'. 1629 if [[ -x /mnt/sbin/swapctl ]]; then 1630 /mnt/sbin/swapctl -a /dev/$SWAPDEV >/dev/null 2>&1 1631 # Can't do chmod && swapctl -A because devices are not yet 1632 # created on install'ed systems. On upgrade'ed system there 1633 # is a small chance the device does not exist on the ramdisk 1634 # and will thus not get mounted. 1635 while read _dev _mp _fstype _rest; do 1636 [[ $_fstype = swap ]] && \ 1637 /mnt/sbin/swapctl -a $_dev >/dev/null 2>&1 1638 done </mnt/etc/fstab 1639 fi 1640 1641 [[ ! -s /mnt/etc/ttys && -s /mnt/etc/ttys.dist ]] && \ 1642 cp /mnt/etc/ttys.dist /mnt/etc/ttys 1643 1644 if grep -qs '^rtsol' /mnt/etc/hostname.*; then 1645 sed -e "/^#\(net\.inet6\.ip6\.accept_rtadv\)/s//\1/" \ 1646 /mnt/etc/sysctl.conf >/tmp/sysctl.conf 1647 cp /tmp/sysctl.conf /mnt/etc/sysctl.conf 1648 fi 1649 1650 echo -n "Making all device nodes..." 1651 cd /mnt/dev 1652 mksh MAKEDEV all 1653 # Make sure any devices we found during probe are created in the 1654 # installed system. 1655 for _dev in $DKDEVS $CDDEVS $MTDEVS; do 1656 mksh MAKEDEV $_dev 1657 done 1658 echo "done." 1659 cd / 1660 1661 if [[ -e $ROOTDISK ]]; then 1662 _dev=$ROOTDISK 1663 else 1664 _dev=/dev/r${ROOTDISK}c 1665 fi 1666 # use extracted mdec if it exists (may be newer) 1667 if [ -e /mnt/usr/mdec/boot ]; then 1668 _prefix=/mnt/usr/mdec 1669 elif [ -e /usr/mdec/boot ]; then 1670 _prefix=/usr/mdec 1671 else 1672 _prefix= 1673 fi 1674 if [[ ! -e $_dev ]]; then 1675 print Cannot install bootblocks to "'$ROOTDISK'". 1676 print You must run installboot manually. 1677 elif [[ -z $_prefix ]]; then 1678 print No boot block prototypes found. 1679 print You must run installboot manually. 1680 else 1681 print Installing boot block... 1682 cat ${_prefix}/boot >/mnt/boot 1683 chmod 0 /mnt/boot 1684 sync; sync; sync 1685 ${_prefix}/installboot -v /mnt/boot ${_prefix}/bootxx $_dev 1686 print done. 1687 fi 1688 1689 [ -x /mnt/$MODE.fixes ] && /mnt/usr/sbin/chroot /mnt /$MODE.fixes 1690 [ -x /mnt/$MODE.site ] && /mnt/usr/sbin/chroot /mnt /$MODE.site 1691 1692 # Pat on the back. 1693 cat <<__EOT 1694 1695CONGRATULATIONS! Your MirBSD $MODE has been successfully completed! 1696To boot the new system, enter halt at the command prompt. Once the 1697system has halted, reset the machine and boot from the disk. 1698 1699Hello there! We from the MirOS project would like to hear from you! 1700If you installed or updated your existing MirOS installation, which 1701architecture, maybe your country, a dmesg and a few words about how 1702you like MirOS. If you don't mind being counted to help us estimate 1703our userbase, mail to <miros-dev@mirbsd.de> - thanks in advance! 1704__EOT 1705 1706 md_congrats 1707} 1708 1709# ####################################################################### 1710# 1711# Initial actions common to both installs and upgrades. 1712# 1713# Some may require machine dependent routines, which may 1714# call functions defined above, so it's safest to put this 1715# code here rather than at the top of the file. 1716# 1717# ####################################################################### 1718 1719ulimit -c 0 1720 1721ROOTDISK= 1722ROOTDEV= 1723 1724VERSION=10 1725 1726# FTPDIR: prefix for SETDIR for ftp/http/https installs 1727FTPDIR="MirOS/" 1728#SETDIR="v${VERSION}/$ARCH" 1729#OBSD="MirOS BSD #$VERSION/$ARCH" 1730SETDIR="current/$ARCH" 1731OBSD="MirOS BSD #$VERSION-current/$ARCH" 1732SERVERLIST=/tmp/serverlist 1733 1734# Do not limit ourselves during installs or upgrades. 1735for _opt in d f l m n p s; do 1736 ulimit -$_opt unlimited 1737done 1738 1739# Scan /var/run/dmesg.boot for interesting devices. 1740DKDEVS=$(scan_dmesg "${MDDKDEVS:-/^r*a*[swi]d[0-9][0-9]* /s/ .*//p}") 1741CDDEVS=$(scan_dmesg "${MDCDDEVS:-/^cd[0-9][0-9]* /s/ .*//p}") 1742MTDEVS=$(scan_dmesg "${MDMTDEVS:-/^[cmsw]t[0-9][0-9]* /s/ .*//p}") 1743SERIALDEV=$(get_serialdev) 1744 1745# Selected sets will be installed in the order they are listed in $THESETS. 1746# Ensure that siteXX.ngz is the *last* set listed so its contents overwrite 1747# the contents of the other sets, not the other way around. Similarly fixes 1748# must be second-to-last. 1749THESETS="bsd bsd.rd $MDSETS" 1750DEFAULTSETS="bsd" 1751for _set in base etc gnu dev ada xbase xetc xfont xserv unfree pkgutl ports \ 1752 source xfree pkgsrc psbsk fixes site; do 1753 [[ $MODE = upgrade && $_set = @(?(x)etc|ports|source|xfree|pkgsrc|psbsk) ]] && continue 1754 THESETS="$THESETS ${_set}${VERSION}.ngz" 1755 isin $_set base etc gnu dev fixes && \ 1756 DEFAULTSETS="$DEFAULTSETS ${_set}${VERSION}.ngz" 1757done 1758# Since etc${VERSION}.ngz is not in DEFAULTSETS for upgrades, it can always be 1759# in SANESETS. 1760SANESETS="bsd base${VERSION}.ngz etc${VERSION}.ngz" 1761 1762# decide upon an editor 1763: ${EDITOR:=ed} 1764[[ -x /usr/bin/vi ]] && EDITOR=vi 1765export EDITOR 1766 1767# umount all filesystems, just in case we are re-running install or upgrade. 1768[[ -f /etc/fstab ]] && umount -avt nomfs 1>/dev/null 2>&1 1769umount -v /mnt 1>/dev/null 2>&1 1770 1771# Introduce ourselves. 1772welcome 1773 1774# Get ROOTDISK, ROOTDEV and SWAPDEV. 1775if [[ $MODE = install && ! -f /etc/fstab ]]; then 1776 cat <<__EOT 1777 1778You will now initialise the disk(s) that MirBSD will use. To enable all 1779available security features you should configure the disk(s) to allow the 1780creation of separate filesystems for /, /tmp, /var, /usr, and /home. 1781 1782__EOT 1783fi 1784 1785set -- $DKDEVS 1786(( $# > 1 )) && _defdsk=done 1787 1788ask_which "disk" "is the root disk" "$DKDEVS" "$_defdsk" 1789[[ $resp = done ]] && exit 1790makedev $resp || exit 1791 1792ROOTDISK=$resp 1793ROOTDEV=${ROOTDISK}a 1794SWAPDEV=${ROOTDISK}b 1795