1#!/bin/sh 2# $NetBSD: install.sub,v 1.43 2002/06/12 09:10:02 bouyer Exp $ 3# 4# Copyright (c) 1996 The NetBSD Foundation, Inc. 5# All rights reserved. 6# 7# This code is derived from software contributed to The NetBSD Foundation 8# by Jason R. Thorpe. 9# 10# Redistribution and use in source and binary forms, with or without 11# modification, are permitted provided that the following conditions 12# are met: 13# 1. Redistributions of source code must retain the above copyright 14# notice, this list of conditions and the following disclaimer. 15# 2. Redistributions in binary form must reproduce the above copyright 16# notice, this list of conditions and the following disclaimer in the 17# documentation and/or other materials provided with the distribution. 18# 3. All advertising materials mentioning features or use of this software 19# must display the following acknowledgement: 20# This product includes software developed by the NetBSD 21# Foundation, Inc. and its contributors. 22# 4. Neither the name of The NetBSD Foundation nor the names of its 23# contributors may be used to endorse or promote products derived 24# from this software without specific prior written permission. 25# 26# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36# POSSIBILITY OF SUCH DAMAGE. 37# 38 39# NetBSD installation/upgrade script - common subroutines. 40 41ROOTDISK="" # filled in below 42VERSION= # filled in automatically (see list) 43export VERSION 44 45ALLSETS="base comp etc games man misc text" # default install sets 46UPGRSETS="base comp games man misc text" # default upgrade sets 47THESETS= # one of the above 48 49local_sets_dir="" # Path searched for sets by install_sets 50 # on the local filesystems 51 52# decide upon an editor 53if [ X$EDITOR = X ]; then 54 if [ -x /usr/bin/vi ]; then 55 EDITOR=vi 56 else 57 EDITOR=ed 58 fi 59fi 60 61getresp() { 62 read resp 63 if [ "X$resp" = "X" ]; then 64 resp=$1 65 fi 66} 67 68isin() { 69# test the first argument against the remaining ones, return succes on a match 70 _a=$1; shift 71 while [ $# != 0 ]; do 72 if [ "$_a" = "$1" ]; then return 0; fi 73 shift 74 done 75 return 1 76} 77 78rmel() { 79# remove first argument from list formed by the remaining arguments 80 local _a 81 82 _a=$1; shift 83 while [ $# != 0 ]; do 84 if [ "$_a" != "$1" ]; then 85 echo "$1"; 86 fi 87 shift 88 done 89} 90 91cutword () { 92# read a line of data, return Nth element. 93 local _a 94 local _n 95 local _oifs 96 97 # optional field separator 98 _oifs="$IFS" 99 case "$1" in 100 -t?*) IFS=${1#-t}; shift;; 101 esac 102 103 _n=$1 104 read _a; set -- $_a 105 IFS="$_oifs" 106 if [ "$1" = "" ]; then return; fi 107 eval echo \$$_n 108} 109 110cutlast () { 111# read a line of data, return last element. Equiv. of awk '{print $NF}'. 112 local _a 113 local _oifs 114 115 # optional field separator 116 _oifs="$IFS" 117 case "$1" in 118 -t?*) IFS=${1#-t}; shift;; 119 esac 120 121 read _a; set -- $_a 122 IFS="$_oifs" 123 if [ "$1" = "" ]; then return; fi 124 while [ "$#" -gt 10 ]; do shift 10; done 125 eval echo \$$# 126} 127 128firstchar () { 129# return first character of argument 130 local _a 131 _a=$1 132 while [ ${#_a} != 1 ]; do 133 _a=${_a%?} 134 done 135 echo $_a 136} 137 138basename () { 139 local _oifs 140 if [ "$1" = "" ]; then return; fi 141 _oifs="$IFS" 142 IFS="/" 143 set -- $1 144 IFS="$_oifs" 145 while [ "$#" -gt 10 ]; do shift 10; done 146 eval echo \$$# 147} 148 149dir_has_sets() { 150 # return true when the directory $1 contains a set for $2...$n 151 local _dir 152 local _file 153 154 _dir=$1; shift 155 for _file in $* 156 do 157 if [ -f $_dir/${_file}.tar.gz ]; then 158 return 0 159 fi 160 # Try for stupid msdos convention 161 if [ -f $_dir/${_file}.tgz ]; then 162 return 0 163 fi 164 # Try for uncompressed files 165 if [ -f $_dir/${_file}.tar ]; then 166 return 0 167 fi 168 # Try for split files 169 if [ -f $_dir/${_file}${VERSION}.aa ]; then 170 return 0 171 fi 172 done 173 return 1 174} 175 176twiddle() { 177# spin the propeller so we don't get bored 178 while : ; do 179 sleep 1; echo -n "/"; 180 sleep 1; echo -n "-"; 181 sleep 1; echo -n "\\"; 182 sleep 1; echo -n "|"; 183 done > /dev/tty & echo $! 184} 185 186get_localdir() { 187 # $1 is relative mountpoint 188 local _mp 189 local _dir 190 191 _mp=$1 192 _dir= 193 while : ; do 194 if [ X$_mp != X ]; then 195 cat << __get_localdir_1 196Note: your filesystems are mounted under the temporary mount point \"$_mp\". 197The pathname you are requested to enter below should NOT include the \"$_mp\" 198prefix. 199__get_localdir_1 200 fi 201 echo -n "Enter the pathname where the sets are stored [$_dir] " 202 getresp "$_dir" 203 _dir=$resp 204 205 # Allow break-out with empty response 206 if [ -z "$_dir" ]; then 207 echo -n "Are you sure you don't want to set the pathname? [n] " 208 getresp "n" 209 case "$resp" in 210 y*|Y*) 211 break 212 ;; 213 *) 214 continue 215 ;; 216 esac 217 fi 218 219 if dir_has_sets "$_mp/$_dir" $THESETS 220 then 221 local_sets_dir="$_mp/$_dir" 222 break 223 else 224 cat << __get_localdir_2 225The directory \"$_mp/$_dir\" does not exist, or does not hold any of the 226upgrade sets. 227__get_localdir_2 228 echo -n "Re-enter pathname? [y] " 229 getresp "y" 230 case "$resp" in 231 y*|Y*) 232 ;; 233 *) 234 local_sets_dir="" 235 break 236 ;; 237 esac 238 fi 239 done 240} 241 242getrootdisk() { 243 cat << \__getrootdisk_1 244 245The installation program needs to know which disk to consider 246the root disk. Note the unit number may be different than 247the unit number you used in the standalone installation 248program. 249 250Available disks are: 251 252__getrootdisk_1 253 _DKDEVS=`md_get_diskdevs` 254 echo "$_DKDEVS" 255 echo "" 256 echo -n "Which disk is the root disk? " 257 getresp "" 258 if isin $resp $_DKDEVS ; then 259 ROOTDISK="$resp" 260 else 261 echo "" 262 echo "The disk $resp does not exist." 263 ROOTDISK="" 264 fi 265} 266 267labelmoredisks() { 268 cat << \__labelmoredisks_1 269 270You may label the following disks: 271 272__labelmoredisks_1 273 echo "$_DKDEVS" 274 echo "" 275 echo -n "Label which disk? [done] " 276 getresp "done" 277 case "$resp" in 278 "done") 279 ;; 280 281 *) 282 if isin $resp $_DKDEVS ; then 283 md_labeldisk $resp 284 else 285 echo "" 286 echo "The disk $resp does not exist." 287 fi 288 ;; 289 esac 290} 291 292addhostent() { 293 # $1 - IP address 294 # $2 - symbolic name 295 296 local fqdn 297 298 # Create an entry in the hosts table. If no host table 299 # exists, create one. If the IP address already exists, 300 # replace it's entry. 301 if [ ! -f /tmp/hosts ]; then 302 echo "127.0.0.1 localhost" > /tmp/hosts 303 fi 304 305 sed "/^$1 /d" < /tmp/hosts > /tmp/hosts.new 306 mv /tmp/hosts.new /tmp/hosts 307 308 if [ X${FQDN} != X ]; then 309 fqdn=$2.$FQDN 310 fi 311 echo "$1 $2 $fqdn" >> /tmp/hosts 312} 313 314addifconfig() { 315 # $1 - interface name 316 # $2 - interface symbolic name 317 # $3 - interface IP address 318 # $4 - interface netmask 319 # $5 - (optional) interface link-layer medium, preceded by "media ", else "" 320 # $6 - (optional) interface link-layer directives 321 local _m 322 323 # Create a ifconfig.* file for the interface. 324 echo "inet $2 netmask $4 $5 $6" > /tmp/ifconfig.$1 325 326 addhostent $3 $2 327} 328 329configurenetwork() { 330 local _ifsdone 331 local _ifs 332 333# _IFS=`md_get_ifdevs` 334 _IFS=`ifconfig -l | sed ' 335 s/lo0// 336 s/ppp[0-9]//g 337 s/sl[0-9]//g 338 s/tun[0-9]//g'` 339 340 _ifsdone="" 341 resp="" # force at least one iteration 342 while [ "X${resp}" != X"done" ]; do 343 cat << \__configurenetwork_1 344 345You may configure the following network interfaces (the interfaces 346marked with [X] have been successfully configured): 347 348__configurenetwork_1 349 350 for _ifs in $_IFS; do 351 if isin $_ifs $_ifsdone ; then 352 echo -n "[X] " 353 else 354 echo -n " " 355 fi 356 echo $_ifs 357 done 358 echo "" 359 echo -n "Configure which interface? [done] " 360 getresp "done" 361 case "$resp" in 362 "done") 363 ;; 364 *) 365 _ifs=$resp 366 if isin $_ifs $_IFS ; then 367 if configure_ifs $_ifs ; then 368 _ifsdone="$_ifs $_ifsdone" 369 fi 370 else 371 echo "Invalid response: \"$resp\" is not in list" 372 fi 373 ;; 374 esac 375 done 376} 377 378configure_ifs() { 379 380 local _up 381 local _interface_name 382 local _interface_ip 383 local _interface_mask 384 local _interface_symname 385 local _interface_extra 386 local _interface_mediumtype 387 local _interface_supported_media 388 local _m 389 local _t 390 391 _interface_name=$1 392 _up=DOWN 393 if isin $_interface_name `ifconfig -l -u` ; then 394 _up=UP 395 fi 396 397 _interface_supported_media=`ifconfig -m $_interface_name | sed -n ' 398 /^[ ]*media autoselect/d 399 4,$s/[ ]*media //p'` 400 401 # get current "media" "ip" and "netmask" ("broadcast") 402 _t=`ifconfig $_interface_name | sed -n ' 403 s/^[ ]*media: [^ ]* \([^ ][^ ]*\).*/\1/p'` 404 405 if [ "$_t" != "manual" -a "$_t" != "media:" -a "$_t" != "autoselect" ]; 406 then 407 _interface_mediumtype=$1 408 fi 409 410 set -- `ifconfig $_interface_name | sed -n ' 411 /^[ ]*inet/{ 412 s/inet// 413 s/--> [0-9.][0-9.]*// 414 s/netmask// 415 s/broadcast// 416 p;}'` 417 418 _interface_ip=$1 419 _interface_mask=$2 420 421 # Get IP address 422 resp="" # force one iteration 423 while [ "X${resp}" = X"" ]; do 424 echo -n "IP address? [$_interface_ip] " 425 getresp "$_interface_ip" 426 _interface_ip=$resp 427 done 428 429 # Get symbolic name 430 resp="" # force one iteration 431 while [ "X${resp}" = X"" ]; do 432 echo -n "Symbolic (host) name? " 433 getresp "" 434 _interface_symname=$resp 435 done 436 437 # Get netmask 438 resp="" # force one iteration 439 while [ "X${resp}" = X"" ]; do 440 echo -n "Netmask? [$_interface_mask] " 441 getresp "$_interface_mask" 442 _interface_mask=$resp 443 done 444 445 echo "Your network interface might require explicit selection" 446 echo "of the type of network medium attached. Supported media:" 447 echo "$_interface_supported_media" 448 echo -n "Additional media type arguments (none)? [$_interface_mediumtype] " 449 getresp "$_interface_mediumtype" 450 _m="" 451 if [ "X${resp}" != X"" -a "X${resp}" != Xnone ]; then 452 _interface_mediumtype=$resp 453 _m="media ${resp}" 454 fi 455 456 457 echo "Your network interface might require additional link-layer" 458 echo "directives (like \`link0'). If this is the case you can enter" 459 echo "these at the next prompt." 460 echo "" 461 echo -n "Additional link-layer arguments (none)? [$_interface_extra] " 462 getresp "$_interface_extra" 463 if [ "X${resp}" != X"" -a "X${resp}" != Xnone ]; then 464 _interface_extra=$resp 465 fi 466 467 # Configure the interface. If it 468 # succeeds, add it to the permanent 469 # network configuration info. 470 if [ $_up != "UP" ]; then 471 ifconfig ${_interface_name} down 472 if ifconfig ${_interface_name} inet \ 473 ${_interface_ip} \ 474 netmask ${_interface_mask} \ 475 ${_interface_extra} ${_m} up ; then 476 addifconfig \ 477 "${_interface_name}" \ 478 "${_interface_symname}" \ 479 "${_interface_ip}" \ 480 "${_interface_mask}" \ 481 "${_m}" \ 482 "${_interface_extra}" 483 return 0 484 fi 485 else 486 echo "Interface ${_interface_name} is already active." 487 echo "Just saving configuration on new root filesystem." 488 addifconfig \ 489 "${_interface_name}" \ 490 "${_interface_symname}" \ 491 "${_interface_ip}" \ 492 "${_interface_mask}" \ 493 "${_m}" \ 494 "${_interface_extra}" 495 fi 496 return 1 497} 498 499# Much of this is gratuitously stolen from /etc/rc.d/network. 500enable_network() { 501 502 # Set up the hostname. 503 if [ -f /mnt/etc/myname ]; then 504 hostname=`cat /mnt/etc/myname` 505 elif [ -f /mnt/etc/rc.conf ];then 506 hostname=`sh -c '. /mnt/etc/rc.conf ; echo $hostname'` 507 else 508 echo "ERROR: no /etc/myname!" 509 return 1 510 fi 511 if [ -z "$hostname" ];then 512 echo "ERROR: hostname not set in /etc/myname or /etc/rc.conf!" 513 return 1 514 fi 515 hostname $hostname 516 517 # configure all the interfaces which we know about. 518if [ -f /mnt/etc/rc.conf ]; then 519( 520 # assume network interface configuration style 1.2D and up 521 if [ -f /mnt/etc/defaults/rc.conf ]; then 522 . /mnt/etc/defaults/rc.conf 523 fi 524 . /mnt/etc/rc.conf 525 526 if [ "$net_interfaces" != NO ]; then 527 if [ "$auto_ifconfig" = YES ]; then 528 tmp="`ifconfig -l`" 529 else 530 tmp="$net_interfaces" 531 fi 532 echo -n "configuring network interfaces:" 533 for i in $tmp; do 534 eval `echo 'args=$ifconfig_'$i` 535 if [ ! -z "$args" ]; then 536 echo -n " $i" 537 ifconfig $i $args 538 elif [ -f /mnt/etc/ifconfig.$i ]; then 539 echo -n " $i" 540 (while read args; do 541 ifconfig $i $args 542 done) < /mnt/etc/ifconfig.$i 543 elif [ "$auto_ifconfig" != YES ]; then 544 echo 545 echo -n "/mnt/etc/ifconfig.$i missing" 546 echo -n "& ifconfig_$i not set" 547 echo "; interface $i can't be configured" 548 fi 549 done 550 echo "." 551 fi 552) 553else 554( 555 tmp="$IFS" 556 IFS="$IFS." 557 set -- `echo /mnt/etc/hostname*` 558 IFS=$tmp 559 unset tmp 560 561 while [ $# -ge 2 ] ; do 562 shift # get rid of "hostname" 563 ( 564 read af name mask bcaddr extras 565 read dt dtaddr 566 567 if [ ! -n "$name" ]; then 568 echo "/etc/hostname.$1: invalid network configuration file" 569 exit 570 fi 571 572 cmd="ifconfig $1 $af $name " 573 if [ "${dt}" = "dest" ]; then cmd="$cmd $dtaddr"; fi 574 if [ -n "$mask" ]; then cmd="$cmd netmask $mask"; fi 575 if [ -n "$bcaddr" -a "X$bcaddr" != "XNONE" ]; then 576 cmd="$cmd broadcast $bcaddr"; 577 fi 578 cmd="$cmd $extras" 579 580 $cmd 581 ) < /mnt/etc/hostname.$1 582 shift 583 done 584) 585fi 586 587 # set the address for the loopback interface 588 ifconfig lo0 inet localhost 589 590 # use loopback, not the wire 591 route add $hostname localhost 592 593 # /etc/mygate, if it exists, contains the name of my gateway host 594 # that name must be in /etc/hosts. 595 if [ -f /mnt/etc/mygate ]; then 596 route delete default > /dev/null 2>&1 597 route add default `cat /mnt/etc/mygate` 598 fi 599 600 # enable the resolver, if appropriate. 601 if [ -f /mnt/etc/resolv.conf ]; then 602 _resolver_enabled="TRUE" 603 cp /mnt/etc/resolv.conf /tmp/resolv.conf.shadow 604 fi 605 606 # Display results... 607 echo "Network interface configuration:" 608 ifconfig -a 609 610 echo "" 611 612 if [ "X${_resolver_enabled}" = X"TRUE" ]; then 613 netstat -r 614 echo "" 615 echo "Resolver enabled." 616 else 617 netstat -rn 618 echo "" 619 echo "Resolver not enabled." 620 fi 621 622 return 0 623} 624 625install_ftp() { 626 local _f 627 local _sets 628 local _next 629 630 # Build a script to extract valid files from a list 631 # of filenames on stdin. 632 # XXX : Can we use this on more places? Leo. 633 634 echo "#!/bin/sh" > /tmp/fname_filter.sh 635 echo "while read line; do" >> /tmp/fname_filter.sh 636 echo " case \$line in" >> /tmp/fname_filter.sh 637 for _f in $THESETS; do 638 echo " $_f.tar.gz|$_f.tgz|$_f.tar|$_f.${VERSION}.aa)" \ 639 >> /tmp/fname_filter.sh 640 echo ' echo -n "$line ";;' \ 641 >> /tmp/fname_filter.sh 642 done 643 echo " *) ;;" >> /tmp/fname_filter.sh 644 echo " esac" >> /tmp/fname_filter.sh 645 echo "done" >> /tmp/fname_filter.sh 646 647 # Get several parameters from the user, and create 648 # a shell script that directs the appropriate 649 # commands into ftp. 650 cat << \__install_ftp_1 651 652This is an automated ftp-based installation process. You will be asked 653several questions. The correct set of commands will be placed in a script 654that will be fed to ftp(1). 655 656__install_ftp_1 657 # Get server IP address 658 resp="" # force one iteration 659 while [ "X${resp}" = X"" ]; do 660 echo -n "Server IP? [${_ftp_server_ip}] " 661 getresp "${_ftp_server_ip}" 662 _ftp_server_ip=$resp 663 done 664 665 # Get login name 666 resp="" # force one iteration 667 while [ "X${resp}" = X"" ]; do 668 echo -n "Login? [${_ftp_server_login}] " 669 getresp "${_ftp_server_login}" 670 _ftp_server_login=$resp 671 done 672 673 # Get password 674 resp="" # force one iteration 675 while [ "X${resp}" = X"" ]; do 676 echo -n "Password? " 677 stty -echo 678 getresp "" 679 echo "" 680 stty echo 681 _ftp_server_password=$resp 682 done 683 684 cat << \__install_ftp_2 685 686You will be asked to enter the name of the directory that contains the 687installation sets. When you enter a '?' you will see a listing of the 688current directory on the server. 689__install_ftp_2 690 _sets="" 691 while [ -z "$_sets" ] 692 do 693 resp="" # force one iteration 694 while [ "X${resp}" = X"" ]; do 695 echo -n "Server directory? [${_ftp_server_dir}] " 696 getresp "${_ftp_server_dir}" 697 if [ "X$resp" = 'X?' -a -z "$_ftp_server_dir" ]; then 698 resp="" 699 fi 700 done 701 if [ $resp != '?' ]; then 702 _ftp_server_dir=$resp 703 fi 704 705 # Build the basics of an ftp-script... 706 echo "#!/bin/sh" > /tmp/ftp-script.sh 707 echo "cd /mnt" >> /tmp/ftp-script.sh 708 echo "ftp -e -i -n $_ftp_server_ip << \__end_commands" >> \ 709 /tmp/ftp-script.sh 710 echo "user $_ftp_server_login $_ftp_server_password" >> \ 711 /tmp/ftp-script.sh 712 echo "bin" >> /tmp/ftp-script.sh 713 echo "cd $_ftp_server_dir" >> /tmp/ftp-script.sh 714 715 # Make a copy of this script that lists the directory 716 # contents, and use that to determine the files to get. 717 cat /tmp/ftp-script.sh > /tmp/ftp-dir.sh 718 echo "nlist" >> /tmp/ftp-dir.sh 719 echo "quit" >> /tmp/ftp-dir.sh 720 echo "__end_commands" >> /tmp/ftp-dir.sh 721 722 if [ $resp = '?' ]; then 723 sh /tmp/ftp-dir.sh 724 else 725 _sets=`sh /tmp/ftp-dir.sh | sh /tmp/fname_filter.sh` 726 fi 727 done 728 rm -f /tmp/ftp-dir.sh /tmp/fname_filter.sh 729 730 while : ; do 731 echo "The following sets are available for extraction:" 732 echo "(marked sets are already on the extraction list)" 733 echo "" 734 735 _next="" 736 for _f in $_sets ; do 737 if isin $_f $_setsdone; then 738 echo -n "[X] " 739 _next="" 740 else 741 echo -n " " 742 if [ -z "$_next" ]; then _next=$_f; fi 743 fi 744 echo $_f 745 done 746 echo "" 747 748 # Get name of the file and add extraction command 749 # to the ftp-script. 750 if [ "X$_next" = "X" ]; then resp=n; else resp=y; fi 751 echo -n "Continue to add filenames [$resp]? " 752 getresp "$resp" 753 if [ "$resp" = "n" ]; then 754 break 755 fi 756 757 echo -n "File name [$_next]? " 758 getresp "$_next" 759 if isin $resp $_sets; then 760 echo "get $resp |\"pax -zr${verbose_flag}pe\"" >> \ 761 /tmp/ftp-script.sh 762 _setsdone="$resp $_setsdone" 763 else 764 echo "You entered an invalid filename." 765 echo "" 766 fi 767 done 768 769 echo "quit" >> /tmp/ftp-script.sh 770 echo "__end_commands" >> /tmp/ftp-script.sh 771 772 sh /tmp/ftp-script.sh 773 rm -f /tmp/ftp-script.sh 774 echo "Extraction complete." 775} 776 777install_from_mounted_fs() { 778 # $1 - directory containing installation sets 779 local _filename 780 local _sets 781 local _next 782 local _all 783 local _f 784 local _dirname 785 786 _dirname=$1 787 _sets="" 788 789 if ! dir_has_sets ${_dirname} $THESETS 790 then 791 792 echo "" 793 echo "The directory at the mount point, \"${_dirname}\", contains: " 794 echo "" 795 ls -F ${_dirname} 796 echo "" 797 echo "Enter the subdirectory relative to the mountpoint, that" 798 echo -n "contains the savesets: [try this directory] " 799 getresp "" 800 if [ "X${resp}" != "X" ]; then 801 _dirname=${_dirname}/$resp 802 fi 803 804 while ! dir_has_sets ${_dirname} $THESETS; do 805 echo "" 806 echo -n "There are no NetBSD install sets available in " 807 echo "\"${_dirname}\"." 808 echo "\"${_dirname}\" contains: " 809 echo "" 810 ls -F ${_dirname} 811 echo "" 812 echo -n "Enter subdirectory: [try other install media] " 813 getresp "" 814 if [ "X${resp}" = "X" ]; then 815 return 816 fi 817 if [ ! -d ${_dirname}/${resp} ]; then 818 echo "\"${resp}\" is no directory; try again." 819 else 820 _dirname=${_dirname}/$resp 821 fi 822 done 823 fi 824 825 for _f in $THESETS ; do 826 if [ -f ${_dirname}/${_f}.tar.gz ]; then 827 _sets="$_sets ${_f}.tar.gz" 828 elif [ -f ${_dirname}/${_f}.tgz ]; then 829 _sets="$_sets ${_f}.tgz" 830 elif [ -f ${_dirname}/${_f}.tar ]; then 831 _sets="$_sets ${_f}.tar" 832 elif [ -f ${_dirname}/${_f}${VERSION}.aa ]; then 833 _sets="$_sets ${_f}${VERSION}" 834 fi 835 done 836 837 while : ; do 838 echo "The following sets are available for extraction:" 839 echo "(marked sets have already been extracted)" 840 echo "" 841 842 _next="" 843 _all="" 844 for _f in $_sets ; do 845 if isin $_f $_setsdone; then 846 echo -n "[X] " 847 _next="" 848 else 849 echo -n " " 850 if [ -z "$_next" ]; then 851 _next=$_f; 852 fi 853 _all="$_all $_f" 854 fi 855 echo $_f 856 done 857 echo "" 858 859 # Get the name of the file. 860 if [ "X$_next" = "X" ]; then 861 resp=n 862 else 863 resp=y 864 fi 865 echo -n "Continue extraction [$resp]?" 866 getresp "$resp" 867 if [ "$resp" = "n" ]; then 868 break 869 fi 870 871 echo -n "File name(s) (or "all") [$_next]? " 872 getresp "$_next" 873 if [ "x$resp" = xall ]; then 874 resp="$_all" 875 fi 876 877 for _f in $resp; do 878 _filename="/${_dirname}/$_f" 879 880 # Ensure file exists 881 if [ ! -f $_filename ]; then 882 if [ -f ${_filename}.aa ]; then 883 _filename=${_filename}.\?\? 884 else 885 echo "File $_filename does not exist. Check to make" 886 echo "sure you entered the information properly." 887 continue 2 888 fi 889 fi 890 891 # Extract file 892 echo "Extracting the $_f set:" 893 case "$_filename" in 894 *.tar) 895 (cd /mnt; pax -r${verbose_flag}pe < $_filename) 896 ;; 897 *) 898 cat $_filename | \ 899 (cd /mnt; pax -zr${verbose_flag}pe) 900 ;; 901 esac 902 echo "Extraction complete." 903 _setsdone="$_f $_setsdone" 904 done 905 906 done 907} 908 909install_cdrom() { 910 local _drive 911 local _partition_range 912 local _partition 913 local _fstype 914 local _directory 915 916 # Get the cdrom device info 917 cat << \__install_cdrom_1 918 919The following CD-ROM devices are installed on your system; please select 920the CD-ROM device containing the partition with the installation sets: 921 922__install_cdrom_1 923 _CDDEVS=`md_get_cddevs` 924 echo "$_CDDEVS" 925 echo "" 926 echo -n "Which is the CD-ROM with the installation media? [abort] " 927 getresp "abort" 928 case "$resp" in 929 abort) 930 echo "Aborting." 931 return 932 ;; 933 934 *) 935 if isin $resp $_CDDEVS ; then 936 _drive=$resp 937 else 938 echo "" 939 echo "The CD-ROM $resp does not exist." 940 echo "Aborting." 941 return 942 fi 943 ;; 944 esac 945 946 # Get partition 947 _partition_range=`md_get_partition_range` 948 resp="" # force one iteration 949 while [ "X${resp}" = X"" ]; do 950 echo -n "Partition? [a] " 951 getresp "a" 952 case "$resp" in 953 $_partition_range) 954 _partition=$resp 955 ;; 956 957 *) 958 echo "Invalid response: $resp" 959 resp="" # force loop to repeat 960 ;; 961 esac 962 done 963 964 # Ask for filesystem type 965 cat << \__install_cdrom_2 966 967There are two CD-ROM filesystem types currently supported by this program: 968 1) ISO-9660 (cd9660) 969 2) Berkeley Fast Filesystem (ffs) 970 971__install_cdrom_2 972 resp="" # force one iteration 973 while [ "X${resp}" = X"" ]; do 974 echo -n "Which filesystem type? [cd9660] " 975 getresp "cd9660" 976 case "$resp" in 977 cd9660|ffs) 978 _fstype=$resp 979 ;; 980 981 *) 982 echo "Invalid response: $resp" 983 resp="" # force loop to repeat 984 ;; 985 esac 986 done 987 988 # Mount the CD-ROM 989 if ! mount -t ${_fstype} -o ro \ 990 /dev/${_drive}${_partition} /mnt2 ; then 991 echo "Cannot mount CD-ROM drive. Aborting." 992 return 993 fi 994 995 install_from_mounted_fs /mnt2 996 umount -f /mnt2 > /dev/null 2>&1 997} 998 999mount_a_disk() { 1000 # Mount a disk on /mnt2. The set of disk devices to choose from 1001 # is $_DKDEVS. 1002 # returns 0 on failure. 1003 1004 local _drive 1005 local _partition_range 1006 local _partition 1007 local _fstype 1008 local _fsopts 1009 local _directory 1010 local _md_fstype 1011 local _md_fsopts 1012 1013 getresp "abort" 1014 case "$resp" in 1015 abort) 1016 echo "Aborting." 1017 return 0 1018 ;; 1019 1020 *) 1021 if isin $resp $_DKDEVS ; then 1022 _drive=$resp 1023 else 1024 echo "" 1025 echo "The disk $resp does not exist." 1026 echo "Aborting." 1027 return 0 1028 fi 1029 ;; 1030 esac 1031 1032 # Get partition 1033 _partition_range=`md_get_partition_range` 1034 resp="" # force one iteration 1035 while [ "X${resp}" = X"" ]; do 1036 echo -n "Partition? [d] " 1037 getresp "d" 1038 case "$resp" in 1039 $_partition_range) 1040 _partition=$resp 1041 ;; 1042 1043 *) 1044 echo "Invalid response: $resp" 1045 resp="" # force loop to repeat 1046 ;; 1047 esac 1048 done 1049 1050 # Ask for filesystem type 1051 cat << \__mount_a_disk_2 1052 1053The following filesystem types are supported: 1054 1) ffs 1055__mount_a_disk_2 1056 _md_fstype=`md_native_fstype` 1057 _md_fsopts=`md_native_fsopts` 1058 if [ ! -z "$_md_fstype" ]; then 1059 echo " 2) $_md_fstype" 1060 else 1061 _md_fstype="_undefined_" 1062 fi 1063 resp="" # force one iteration 1064 while [ "X${resp}" = X"" ]; do 1065 echo -n "Which filesystem type? [ffs] " 1066 getresp "ffs" 1067 case "$resp" in 1068 ffs) 1069 _fstype=$resp 1070 _fsopts="ro" 1071 ;; 1072 $_md_fstype) 1073 _fstype=$resp 1074 _fsopts=$_md_fsopts 1075 ;; 1076 *) 1077 echo "Invalid response: $resp" 1078 resp="" # force loop to repeat 1079 ;; 1080 esac 1081 done 1082 1083 # Mount the disk 1084 if ! mount -t ${_fstype} -o $_fsopts \ 1085 /dev/${_drive}${_partition} /mnt2 ; then 1086 echo "Cannot mount disk. Aborting." 1087 return 0 1088 fi 1089 return 1 1090} 1091 1092install_disk() { 1093 local _directory 1094 1095 cat << \__install_disk_1 1096 1097Ok, lets install from a disk. The file-system the install sets on may 1098already mounted, or we might have to mount the filesystem to get to it. 1099 1100__install_disk_1 1101 1102 echo -n "Is the file-system with the install sets already mounted? [n] " 1103 getresp "n" 1104 case $resp in 1105 y*|Y*) 1106 echo "What mount point are the sets located in? [] " 1107 getresp "" 1108 if [ -d "$resp" ]; then 1109 install_from_mounted_fs $resp 1110 else 1111 echo "$resp: Not a directory, aborting..." 1112 fi 1113 return 1114 ;; 1115 *) 1116 ;; 1117 esac 1118 1119 cat << \__install_disk_2 1120 1121The following disk devices are installed on your system; please select 1122the disk device containing the partition with the installation sets: 1123 1124__install_disk_2 1125 _DKDEVS=`md_get_diskdevs` 1126 echo "$_DKDEVS" 1127 echo "" 1128 echo -n "Which is the disk with the installation sets? [abort] " 1129 1130 if mount_a_disk ; then 1131 return 1132 fi 1133 1134 install_from_mounted_fs /mnt2 1135 umount -f /mnt2 > /dev/null 2>&1 1136} 1137 1138install_nfs() { 1139 # Get the IP address of the server 1140 resp="" # force one iteration 1141 while [ "X${resp}" = X"" ]; do 1142 echo -n "Server IP address? [${_nfs_server_ip}] " 1143 getresp "${_nfs_server_ip}" 1144 done 1145 _nfs_server_ip=$resp 1146 1147 # Get server path to mount 1148 resp="" # force one iteration 1149 while [ "X${resp}" = X"" ]; do 1150 echo -n "Filesystem on server to mount? [${_nfs_server_path}] " 1151 getresp "${_nfs_server_path}" 1152 done 1153 _nfs_server_path=$resp 1154 1155 # Determine use of TCP 1156 echo -n "Use TCP transport (only works with capable NFS server)? [n] " 1157 getresp "n" 1158 case "$resp" in 1159 y*|Y*) 1160 _nfs_tcp="-T" 1161 ;; 1162 1163 *) 1164 echo -n "Use small NFS transfers (needed when server " 1165 echo "or client" 1166 echo -n "has a slow network card)? [n] " 1167 getresp "n" 1168 case "$resp" in 1169 y*|Y*) 1170 _nfs_tcp="-r 1024 -w 1024" 1171 ;; 1172 1173 *) 1174 _nfs_tcp="" 1175 ;; 1176 esac 1177 ;; 1178 esac 1179 1180 # Mount the server 1181 mkdir /mnt2 > /dev/null 2>&1 1182 if ! mount_nfs $_nfs_tcp ${_nfs_server_ip}:${_nfs_server_path} \ 1183 /mnt2 ; then 1184 echo "Cannot mount NFS server. Aborting." 1185 return 1186 fi 1187 1188 install_from_mounted_fs /mnt2 1189 umount -f /mnt2 > /dev/null 2>&1 1190} 1191 1192install_tape() { 1193 local _xcmd 1194 1195 # Get the name of the tape from the user. 1196 cat << \__install_tape_1 1197 1198The installation program needs to know which tape device to use. Make 1199sure you use a "no rewind on close" device. 1200 1201__install_tape_1 1202 _tape=`basename $TAPE` 1203 resp="" # force one iteration 1204 while [ "X${resp}" = X"" ]; do 1205 echo -n "Name of tape device? [${_tape}]" 1206 getresp "${_tape}" 1207 done 1208 _tape=`basename $resp` 1209 TAPE="/dev/${_tape}" 1210 if [ ! -c $TAPE ]; then 1211 echo "$TAPE does not exist or is not a character special file." 1212 echo "Aborting." 1213 return 1214 fi 1215 export TAPE 1216 1217 # Rewind the tape device 1218 echo -n "Rewinding tape..." 1219 if ! mt rewind ; then 1220 echo "$TAPE may not be attached to the system or may not be" 1221 echo "a tape device. Aborting." 1222 return 1223 fi 1224 echo "done." 1225 1226 # Get the file number 1227 resp="" # force one iteration 1228 while [ "X${resp}" = X"" ]; do 1229 echo -n "File number? " 1230 getresp "" 1231 case "$resp" in 1232 [1-9]*) 1233 _nskip=`expr $resp - 1` 1234 ;; 1235 1236 *) 1237 echo "Invalid file number ${resp}." 1238 resp="" # fore loop to repeat 1239 ;; 1240 esac 1241 done 1242 1243 # Skip to correct file. 1244 echo -n "Skipping to source file..." 1245 if [ "X${_nskip}" != X"0" ]; then 1246 if ! mt fsf $_nskip ; then 1247 echo "Could not skip $_nskip files. Aborting." 1248 return 1249 fi 1250 fi 1251 echo "done." 1252 1253 cat << \__install_tape_2 1254 1255There are 2 different ways the file can be stored on tape: 1256 1257 1) an image of a gzipped tar file 1258 2) a standard tar image 1259 1260__install_tape_2 1261 resp="" # force one iteration 1262 while [ "X${resp}" = X"" ]; do 1263 echo -n "Which way is it? [1] " 1264 getresp "1" 1265 case "$resp" in 1266 1) 1267 _xcmd="pax -zr${verbose_flag}pe" 1268 ;; 1269 1270 2) 1271 _xcmd="pax -r${verbose_flag}pe" 1272 ;; 1273 1274 *) 1275 echo "Invalid response: $resp." 1276 resp="" # force loop to repeat 1277 ;; 1278 esac 1279 ( cd /mnt; dd if=$TAPE | $_xcmd ) 1280 done 1281 echo "Extraction complete." 1282} 1283 1284get_timezone() { 1285 local _a 1286 local _zonepath 1287 1288 # 1289 # If the zoneinfo is not on the installation medium or on the 1290 # installed filesystem, set TZ to GMT and return immediatly. 1291 # 1292 if [ ! -e /usr/share/zoneinfo -a ! -e /mnt/usr/share/zoneinfo ]; then 1293 TZ=GMT 1294 return 1295 fi 1296 if [ ! -d /usr/share/zoneinfo ]; then 1297 _zonepath=/mnt 1298 else 1299 _zonepath="" 1300 fi 1301 1302cat << \__get_timezone_1 1303 1304Select a time zone for your location. Timezones are represented on the 1305system by a directory structure rooted in "/usr/share/zoneinfo". Most 1306timezones can be selected by entering a token like "MET" or "GMT-6". 1307Other zones are grouped by continent, with detailed zone information 1308separated by a slash ("/"), e.g. "US/Pacific". 1309 1310To get a listing of what's available in /usr/share/zoneinfo, enter "?" 1311at the prompts below. 1312 1313__get_timezone_1 1314 if [ X$TZ = X ]; then 1315 TZ=`ls -l /mnt/etc/localtime 2>/dev/null | cutlast` 1316 TZ=${TZ#/usr/share/zoneinfo/} 1317 fi 1318 while :; do 1319 echo -n "What timezone are you in [\`?' for list] [$TZ]? " 1320 getresp "$TZ" 1321 case "$resp" in 1322 "") 1323 echo "Timezone defaults to GMT" 1324 TZ="GMT" 1325 break; 1326 ;; 1327 "?") 1328 ls ${_zonepath}/usr/share/zoneinfo 1329 ;; 1330 *) 1331 _a=$resp 1332 while [ -d ${_zonepath}/usr/share/zoneinfo/$_a ]; do 1333 echo -n "There are several timezones available" 1334 echo " within zone '$_a'" 1335 echo -n "Select a sub-timezone [\`?' for list]: " 1336 getresp "" 1337 case "$resp" in 1338 "?") ls ${_zonepath}/usr/share/zoneinfo/$_a ;; 1339 *) _a=${_a}/${resp} 1340 if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then 1341 break; 1342 fi 1343 ;; 1344 esac 1345 done 1346 if [ -f ${_zonepath}/usr/share/zoneinfo/$_a ]; then 1347 TZ="$_a" 1348 echo "You have selected timezone \"$_a\"". 1349 break 2 1350 fi 1351 echo "'/usr/share/zoneinfo/$_a' is not a valid timezone on this system." 1352 ;; 1353 esac 1354 done 1355} 1356 1357install_sets() 1358{ 1359 local _yup 1360 _yup="FALSE" 1361 1362 # Ask the user which media to load the distribution from. 1363 # Ask the user if they want verbose extraction. They might not want 1364 # it on, eg, SPARC frame buffer console. 1365 cat << \__install_sets_1 1366 1367It is now time to extract the installation sets onto the hard disk. 1368Make sure the sets are either on a local device (i.e. tape, CD-ROM) or on a 1369network server. 1370 1371Would you like to see each file listed during extraction (verbose) mode? 1372On some console hardware, such as serial consoles and Sun frame buffers, 1373this can extend the total extraction time. 1374__install_sets_1 1375 echo -n "Use verbose listing for extractions? [y] " 1376 getresp "y" 1377 case "$resp" in 1378 y*|Y*) 1379 verbose_flag=v 1380 ;; 1381 *) 1382 echo "Not using verbose listing." 1383 verbose_flag="" 1384 ;; 1385 esac 1386 1387 if [ -d ${Default_sets_dir:-/dev/null} ]; then 1388 if dir_has_sets $Default_sets_dir $THESETS; then 1389 local_sets_dir=$Default_sets_dir 1390 fi 1391 fi 1392 if [ "X$local_sets_dir" != "X" ]; then 1393 install_from_mounted_fs ${local_sets_dir} 1394 if [ X"$_setsdone" != X ]; then 1395 _yup="TRUE" 1396 fi 1397 fi 1398 1399 # Go on prodding for alternate locations 1400 resp="" # force at least one iteration 1401 while [ X"${resp}" = X ]; do 1402 # If _yup is not FALSE, it means that we extracted sets above. 1403 # If that's the case, bypass the menu the first time. 1404 if [ X"$_yup" = X"FALSE" ]; then 1405 echo -n "Install from (f)tp, (t)ape, (C)D-ROM, (N)FS" 1406 echo -n " or local (d)isk? " 1407 getresp "" 1408 case "$resp" in 1409 d*|D*) 1410 install_disk 1411 ;; 1412 f*|F*) 1413 install_ftp 1414 ;; 1415 t*|T*) 1416 install_tape 1417 ;; 1418 c*|C*) 1419 install_cdrom 1420 ;; 1421 n*|N*) 1422 install_nfs 1423 ;; 1424 *) 1425 echo "Invalid response: $resp" 1426 resp="" 1427 ;; 1428 esac 1429 else 1430 _yup="FALSE" # So we'll ask next time 1431 fi 1432 1433 # Give the user the opportunity to extract more sets. They 1434 # don't necessarily have to come from the same media. 1435 echo "" 1436 echo -n "Extract more sets? [n] " 1437 getresp "n" 1438 case "$resp" in 1439 y*|Y*) 1440 # Force loop to repeat 1441 resp="" 1442 ;; 1443 1444 *) 1445 ;; 1446 esac 1447 done 1448} 1449 1450munge_fstab() 1451{ 1452 local _fstab 1453 local _fstab_shadow 1454 local _dev 1455 local _mp 1456 local _fstype 1457 local _rest 1458 1459 # Now that the 'real' fstab is configured, we munge it into a 'shadow' 1460 # fstab which we'll use for mounting and unmounting all of the target 1461 # filesystems relative to /mnt. Mount all filesystems. 1462 _fstab=$1 1463 _fstab_shadow=$2 1464 ( while read _dev _mp _fstype _rest; do 1465 # Skip comment lines 1466 case "$_dev" in 1467 \#*) continue;; 1468 *) ;; 1469 esac 1470 # and some filesystem types (like there are swap,kernfs,...) 1471 case "$_fstype" in 1472 ffs|ufs|nfs) ;; 1473 *) continue;; 1474 esac 1475 if [ "$_mp" = "/" ]; then 1476 echo $_dev /mnt $_fstype $_rest 1477 else 1478 echo $_dev /mnt$_mp $_fstype $_rest 1479 fi 1480 done ) < $_fstab > $_fstab_shadow 1481} 1482 1483mount_fs() 1484{ 1485 # Must mount filesystems manually, one at a time, so we can make 1486 # sure the mount points exist. 1487 # $1 is a file in fstab format 1488 local _fstab 1489 1490 _fstab=$1 1491 1492 ( while read line; do 1493 set -- $line 1494 _dev=$1 1495 _mp=$2 1496 _fstype=$3 1497 _opt=$4 1498 1499 # If not the root filesystem, make sure the mount 1500 # point is present. 1501 if [ "X{$_mp}" != X"/mnt" ]; then 1502 mkdir -p $_mp 1503 fi 1504 1505 # Mount the filesystem. If the mount fails, exit 1506 # with an error condition to tell the outer 1507 # later to bail. 1508 if ! mount -v -t $_fstype -o async -o $_opt $_dev $_mp ; then 1509 # error message displated by mount 1510 exit 1 1511 fi 1512 done ) < $_fstab 1513 1514 if [ "X${?}" != X"0" ]; then 1515 cat << \__mount_filesystems_1 1516 1517FATAL ERROR: Cannot mount filesystems. Double-check your configuration 1518and restart the installation process. 1519__mount_filesystems_1 1520 exit 1521 fi 1522} 1523 1524unmount_fs() 1525{ 1526 # Unmount all filesystems and check their integrity. 1527 # Usage: [-fast] <fstab file> 1528 local _fast 1529 local _fstab 1530 local _pid 1531 1532 if [ "$1" = "-fast" ]; then 1533 _fast=1 1534 _fstab=$2 1535 else 1536 _fast=0 1537 _fstab=$1 1538 fi 1539 1540 if [ ! \( -f $_fstab -a -s $_fstab \) ]; then 1541 echo "fstab empty" > /dev/tty 1542 return 1543 fi 1544 1545 if [ $_fast = 0 ]; then 1546 echo -n "Syncing disks..." 1547 _pid=`twiddle` 1548 sync; sleep 4; sync; sleep 2; sync; sleep 2 1549 kill $_pid 1550 echo "done." 1551 fi 1552 1553 ( 1554 _devs="" 1555 _mps="" 1556 # maintain reverse order 1557 while read line; do 1558 set -- $line 1559 _devs="$1 ${_devs}" 1560 _mps="$2 ${_mps}" 1561 done 1562 echo -n "Umounting filesystems... " 1563 for _mp in ${_mps}; do 1564 echo -n "${_mp} " 1565 umount ${_mp} 1566 done 1567 echo "Done." 1568 1569 if [ $_fast = 0 ]; then 1570 exit 1571 fi 1572 echo "Checking filesystem integrity..." 1573 for _dev in ${_devs}; do 1574 echo "${_dev}" 1575 fsck -f ${_dev} 1576 done 1577 echo "Done." 1578 ) < $_fstab 1579} 1580 1581check_fs() 1582{ 1583 # Check filesystem integrity. 1584 # $1 is a file in fstab format 1585 local _fstab 1586 1587 _fstab=$1 1588 1589 ( 1590 _devs="" 1591 _mps="" 1592 while read line; do 1593 set -- $line 1594 _devs="$1 ${_devs}" 1595 _mps="$2 ${_mps}" 1596 done 1597 1598 echo "Checking filesystem integrity..." 1599 for _dev in ${_devs}; do 1600 echo "${_dev}" 1601 fsck -f ${_dev} 1602 done 1603 echo "Done." 1604 ) < $_fstab 1605} 1606