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