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