1#!/bin/sh 2# $NetBSD: install.sub,v 1.66 2024/05/11 06:31:59 andvar 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 35MACHINE= # filled by distrib/miniroot/list 36export MACHINE 37VERSION=100 # updated by distrib/miniroot/list 38export VERSION 39RELEASE=10.0 # updated by distrib/miniroot/list 40export RELEASE 41 42ALLSETS="base comp etc games man misc modules rescue text" # default install sets 43UPGRSETS="base comp games man misc modules rescue text" # default upgrade sets 44THESETS= # one of the above 45 46local_sets_dir="" # Path searched for sets by install_sets 47 # on the local filesystems 48 49# decide upon an editor 50if [ -z "$EDITOR" ]; then 51 if [ -x /usr/bin/vi ]; then 52 EDITOR=vi 53 else 54 EDITOR=ed 55 fi 56fi 57 58getresp() { 59 read resp 60 if [ -z "$resp" ]; then 61 resp=$1 62 fi 63} 64 65isin() { 66# test the first argument against the remaining ones, return success on a match 67 _a=$1; shift 68 while [ $# != 0 ]; do 69 if [ "$_a" = "$1" ]; then return 0; fi 70 shift 71 done 72 return 1 73} 74 75rmel() { 76# remove first argument from list formed by the remaining arguments 77 local _a 78 79 _a=$1; shift 80 while [ $# != 0 ]; do 81 if [ "$_a" != "$1" ]; then 82 echo "$1"; 83 fi 84 shift 85 done 86} 87 88cutword () { 89# read a line of data, return Nth element. 90 local _a 91 local _n 92 local _oifs 93 94 # optional field separator 95 _oifs="$IFS" 96 case "$1" in 97 -t?*) IFS=${1#-t}; shift;; 98 esac 99 100 _n=$1 101 read _a; set -- $_a 102 IFS="$_oifs" 103 if [ "$1" = "" ]; then return; fi 104 eval echo \$$_n 105} 106 107cutlast () { 108# read a line of data, return last element. Equiv. of awk '{print $NF}'. 109 local _a 110 local _oifs 111 112 # optional field separator 113 _oifs="$IFS" 114 case "$1" in 115 -t?*) IFS=${1#-t}; shift;; 116 esac 117 118 read _a; set -- $_a 119 IFS="$_oifs" 120 if [ "$1" = "" ]; then return; fi 121 eval echo '"${'"$#"'}"' 122} 123 124firstchar () { 125# return first character of argument 126 local _a 127 _a=$1 128 while [ ${#_a} != 1 ]; do 129 _a=${_a%?} 130 done 131 echo $_a 132} 133 134basename () { 135 local _oifs 136 if [ "$1" = "" ]; then return; fi 137 _oifs="$IFS" 138 IFS="/" 139 set -- $1 140 IFS="$_oifs" 141 eval echo '"${'"$#"'}"' 142} 143 144dir_has_sets() { 145 # return true when the directory $1 contains a set for $2...$n 146 local _dir 147 local _file 148 149 _dir=$1; shift 150 for _file in $* 151 do 152 if [ -f $_dir/${_file}.tar.gz ]; then 153 return 0 154 fi 155 # Try for stupid msdos convention 156 if [ -f $_dir/${_file}.tgz ]; then 157 return 0 158 fi 159 # Try for uncompressed files 160 if [ -f $_dir/${_file}.tar ]; then 161 return 0 162 fi 163 # Try for split files 164 if [ -f $_dir/${_file}${VERSION}.aa ]; then 165 return 0 166 fi 167 done 168 return 1 169} 170 171twiddle() { 172# spin the propeller so we don't get bored 173 while : ; do 174 sleep 1; echo -n "/"; 175 sleep 1; echo -n "-"; 176 sleep 1; echo -n "\\"; 177 sleep 1; echo -n "|"; 178 done > /dev/tty & echo $! 179} 180 181get_localdir() { 182 # $1 is relative mountpoint 183 local _mp 184 local _dir 185 186 _mp=$1 187 _dir= 188 while : ; do 189 if [ -n "$_mp" ]; then 190 cat << __get_localdir_1 191Note: your filesystems are mounted under the temporary mount point \"$_mp\". 192The pathname you are requested to enter below should NOT include the \"$_mp\" 193prefix. 194__get_localdir_1 195 fi 196 echo -n "Enter the pathname where the sets are stored [$_dir] " 197 getresp "$_dir" 198 _dir=$resp 199 200 # Allow break-out with empty response 201 if [ -z "$_dir" ]; then 202 echo -n "Are you sure you don't want to set the pathname? [n] " 203 getresp "n" 204 case "$resp" in 205 y*|Y*) 206 break 207 ;; 208 *) 209 continue 210 ;; 211 esac 212 fi 213 214 if dir_has_sets "$_mp/$_dir" $THESETS 215 then 216 local_sets_dir="$_mp/$_dir" 217 break 218 else 219 cat << __get_localdir_2 220The directory \"$_mp/$_dir\" does not exist, or does not hold any of the 221upgrade sets. 222__get_localdir_2 223 echo -n "Re-enter pathname? [y] " 224 getresp "y" 225 case "$resp" in 226 y*|Y*) 227 ;; 228 *) 229 local_sets_dir="" 230 break 231 ;; 232 esac 233 fi 234 done 235} 236 237getrootdisk() { 238 cat << \__getrootdisk_1 239 240The installation program needs to know which disk to consider 241the root disk. Note the unit number may be different than 242the unit number you used in the standalone installation 243program. 244 245Available disks are: 246 247__getrootdisk_1 248 _DKDEVS=$(md_get_diskdevs) 249 echo "$_DKDEVS" 250 echo "" 251 echo -n "Which disk is the root disk? " 252 getresp "" 253 if isin $resp $_DKDEVS ; then 254 ROOTDISK="$resp" 255 else 256 echo "" 257 echo "The disk $resp does not exist." 258 ROOTDISK="" 259 fi 260} 261 262labelmoredisks() { 263 cat << \__labelmoredisks_1 264 265You may label the following disks: 266 267__labelmoredisks_1 268 echo "$_DKDEVS" 269 echo "" 270 echo -n "Label which disk? [done] " 271 getresp "done" 272 case "$resp" in 273 "done") 274 ;; 275 276 *) 277 if isin $resp $_DKDEVS ; then 278 md_labeldisk $resp 279 else 280 echo "" 281 echo "The disk $resp does not exist." 282 fi 283 ;; 284 esac 285} 286 287addhostent() { 288 # $1 - IP address 289 # $2 - symbolic name 290 291 local fqdn 292 293 # Create an entry in the hosts table. If no host table 294 # exists, create one. If the IP address already exists, 295 # replace its entry. 296 if [ ! -f /tmp/hosts ]; then 297 echo "127.0.0.1 localhost" > /tmp/hosts 298 fi 299 300 sed "/^$1 /d" < /tmp/hosts > /tmp/hosts.new 301 mv /tmp/hosts.new /tmp/hosts 302 303 if [ -n "${FQDN}" ]; then 304 fqdn=$2.$FQDN 305 fi 306 echo "$1 $2 $fqdn" >> /tmp/hosts 307} 308 309addifconfig() { 310 # $1 - interface name 311 # $2 - interface symbolic name 312 # $3 - interface IP address 313 # $4 - interface netmask 314 # $5 - (optional) interface link-layer medium, preceded by "media ", else "" 315 # $6 - (optional) interface link-layer directives 316 local _m 317 318 # Create a ifconfig.* file for the interface. 319 echo "inet $2 netmask $4 $5 $6" > /tmp/ifconfig.$1 320 321 addhostent $3 $2 322} 323 324configurenetwork() { 325 local _ifsdone 326 local _ifs 327 328# _IFS=$(md_get_ifdevs) 329 _IFS=$(ifconfig -l | sed ' 330 s/lo0// 331 s/ppp[0-9]//g 332 s/sl[0-9]//g 333 s/tun[0-9]//g') 334 335 _ifsdone="" 336 resp="" # force at least one iteration 337 while [ "${resp}" != "done" ]; do 338 cat << \__configurenetwork_1 339 340You may configure the following network interfaces (the interfaces 341marked with [X] have been successfully configured): 342 343__configurenetwork_1 344 345 for _ifs in $_IFS; do 346 if isin $_ifs $_ifsdone ; then 347 echo -n "[X] " 348 else 349 echo -n " " 350 fi 351 echo $_ifs 352 done 353 echo "" 354 echo -n "Configure which interface? [done] " 355 getresp "done" 356 case "$resp" in 357 "done") 358 ;; 359 *) 360 _ifs=$resp 361 if isin $_ifs $_IFS ; then 362 if configure_ifs $_ifs ; then 363 _ifsdone="$_ifs $_ifsdone" 364 fi 365 else 366 echo "Invalid response: \"$resp\" is not in list" 367 fi 368 ;; 369 esac 370 done 371} 372 373configure_ifs() { 374 375 local _up 376 local _interface_name 377 local _interface_ip 378 local _interface_mask 379 local _interface_symname 380 local _interface_extra 381 local _interface_mediumtype 382 local _interface_supported_media 383 local _m 384 local _t 385 386 _interface_name=$1 387 _up=DOWN 388 if isin $_interface_name $(ifconfig -l -u); then 389 _up=UP 390 fi 391 392 _interface_supported_media=$(ifconfig -m $_interface_name | sed -n ' 393 /^[ ]*media autoselect/d 394 4,$s/[ ]*media //p') 395 396 # get current "media" "ip" and "netmask" ("broadcast") 397 _t=$(ifconfig $_interface_name | sed -n ' 398 s/^[ ]*media: [^ ]* \([^ ][^ ]*\).*/\1/p') 399 400 if [ "$_t" != "manual" ] && [ "$_t" != "media:" ] && [ "$_t" != "autoselect" ]; 401 then 402 _interface_mediumtype=$1 403 fi 404 405 set -- $(ifconfig $_interface_name | sed -n ' 406 /^[ ]*inet /{ 407 s/inet// 408 s,/[0-9]*,, 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 [ -z "${resp}" ]; 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 [ -z "${resp}" ]; 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 [ -z "${resp}" ]; 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 [ "${resp:-none}" != "none" ]; 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 [ "${resp:-none}" != "none" ]; 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 if [ -f /mnt/etc/defaults/rc.conf ]; then 518 . /mnt/etc/defaults/rc.conf 519 fi 520 . /mnt/etc/rc.conf 521 522 if [ "$net_interfaces" != NO ]; then 523 if [ "$auto_ifconfig" = YES ]; then 524 tmp="$(ifconfig -l)" 525 else 526 tmp="$net_interfaces" 527 fi 528 echo -n "configuring network interfaces:" 529 for i in $tmp; do 530 eval $(echo 'args=$ifconfig_'$i) 531 if [ -n "$args" ]; then 532 echo -n " $i" 533 ifconfig $i $args 534 elif [ -f /mnt/etc/ifconfig.$i ]; then 535 echo -n " $i" 536 (while read args; do 537 ifconfig $i $args 538 done) < /mnt/etc/ifconfig.$i 539 elif [ "$auto_ifconfig" != YES ]; then 540 echo 541 echo -n "/mnt/etc/ifconfig.$i missing" 542 echo -n "& ifconfig_$i not set" 543 echo "; interface $i can't be configured" 544 fi 545 done 546 echo "." 547 fi 548) 549else 550( 551 tmp="$IFS" 552 IFS="$IFS." 553 set -- $(echo /mnt/etc/hostname*) 554 IFS=$tmp 555 unset tmp 556 557 while [ $# -ge 2 ] ; do 558 shift # get rid of "hostname" 559 ( 560 read af name mask bcaddr extras 561 read dt dtaddr 562 563 if [ -z "$name" ]; then 564 echo "/etc/hostname.$1: invalid network configuration file" 565 exit 566 fi 567 568 cmd="ifconfig $1 $af $name " 569 if [ "${dt}" = "dest" ]; then cmd="$cmd $dtaddr"; fi 570 if [ -n "$mask" ]; then cmd="$cmd netmask $mask"; fi 571 if [ "${bcaddr:-NONE}" != "NONE" ]; then 572 cmd="$cmd broadcast $bcaddr"; 573 fi 574 cmd="$cmd $extras" 575 576 $cmd 577 ) < /mnt/etc/hostname.$1 578 shift 579 done 580) 581fi 582 583 # set the address for the loopback interface 584 ifconfig lo0 inet localhost 585 586 # use loopback, not the wire 587 route add $hostname localhost 588 589 # /etc/mygate, if it exists, contains the name of my gateway host 590 # that name must be in /etc/hosts. 591 if [ -f /mnt/etc/mygate ]; then 592 route delete default > /dev/null 2>&1 593 route add default $(cat /mnt/etc/mygate) 594 fi 595 596 # enable the resolver, if appropriate. 597 if [ -f /mnt/etc/resolv.conf ]; then 598 _resolver_enabled="TRUE" 599 cp /mnt/etc/resolv.conf /tmp/resolv.conf.shadow 600 fi 601 602 # Display results... 603 echo "Network interface configuration:" 604 ifconfig -a 605 606 echo "" 607 608 if [ "${_resolver_enabled:-FALSE}" = "TRUE" ]; then 609 echo "Resolver enabled." 610 else 611 echo "Resolver not enabled." 612 fi 613 614 return 0 615} 616 617install_ftp() { 618 local _f 619 local _sets 620 local _next 621 622 # Build a script to extract valid files from a list 623 # of filenames on stdin. 624 # XXX : Can we use this on more places? Leo. 625 626 echo "#!/bin/sh" > /tmp/fname_filter.sh 627 echo "while read line; do" >> /tmp/fname_filter.sh 628 echo " case \$line in" >> /tmp/fname_filter.sh 629 for _f in $THESETS; do 630 echo " $_f.tar.gz|$_f.tgz|$_f.tar|$_f.${VERSION}.aa)" \ 631 >> /tmp/fname_filter.sh 632 echo ' echo -n "$line ";;' \ 633 >> /tmp/fname_filter.sh 634 done 635 echo " *) ;;" >> /tmp/fname_filter.sh 636 echo " esac" >> /tmp/fname_filter.sh 637 echo "done" >> /tmp/fname_filter.sh 638 639 # Get several parameters from the user, and create 640 # a shell script that directs the appropriate 641 # commands into ftp. 642 cat << \__install_ftp_1 643 644This is an automated ftp-based installation process. You will be asked 645several questions. The correct set of commands will be placed in a script 646that will be fed to ftp(1). 647 648__install_ftp_1 649 # Get server IP address 650 resp="" # force one iteration 651 while [ -z "${resp}" ]; do 652 echo -n "Server IP? [${_ftp_server_ip}] " 653 getresp "${_ftp_server_ip}" 654 _ftp_server_ip=$resp 655 done 656 657 # Get login name 658 resp="" # force one iteration 659 while [ -z "${resp}" ]; do 660 echo -n "Login? [${_ftp_server_login}] " 661 getresp "${_ftp_server_login}" 662 _ftp_server_login=$resp 663 done 664 665 # Get password 666 resp="" # force one iteration 667 while [ -z "${resp}" ]; do 668 echo -n "Password? " 669 stty -echo 670 getresp "" 671 echo "" 672 stty echo 673 _ftp_server_password=$resp 674 done 675 676 cat << \__install_ftp_2 677 678You will be asked to enter the name of the directory that contains the 679installation sets. When you enter a '?' you will see a listing of the 680current directory on the server. 681__install_ftp_2 682 echo "" 683 echo "The default installation directory in the official ftp server is:" 684 echo "/pub/NetBSD/NetBSD-${RELEASE}/${MACHINE}/binary/sets" 685 686 _sets="" 687 while [ -z "$_sets" ] 688 do 689 resp="" # force one iteration 690 while [ -z "${resp}" ]; do 691 echo -n "Server directory? [${_ftp_server_dir}] " 692 getresp "${_ftp_server_dir}" 693 if [ -z "$resp" ] && [ -z "$_ftp_server_dir" ]; then 694 resp="" 695 fi 696 done 697 if [ $resp != '?' ]; then 698 _ftp_server_dir=$resp 699 fi 700 701 # Build the basics of an ftp-script... 702 echo "#!/bin/sh" > /tmp/ftp-script.sh 703 echo "cd /mnt" >> /tmp/ftp-script.sh 704 echo "ftp -e -i -n $_ftp_server_ip << \__end_commands" >> \ 705 /tmp/ftp-script.sh 706 echo "user $_ftp_server_login $_ftp_server_password" >> \ 707 /tmp/ftp-script.sh 708 echo "bin" >> /tmp/ftp-script.sh 709 echo "cd $_ftp_server_dir" >> /tmp/ftp-script.sh 710 711 # Make a copy of this script that lists the directory 712 # contents, and use that to determine the files to get. 713 cat /tmp/ftp-script.sh > /tmp/ftp-dir.sh 714 echo "nlist" >> /tmp/ftp-dir.sh 715 echo "quit" >> /tmp/ftp-dir.sh 716 echo "__end_commands" >> /tmp/ftp-dir.sh 717 718 if [ $resp = '?' ]; then 719 sh /tmp/ftp-dir.sh 720 else 721 _sets=$(sh /tmp/ftp-dir.sh | sort -u | sh /tmp/fname_filter.sh) 722 fi 723 done 724 rm -f /tmp/ftp-dir.sh /tmp/fname_filter.sh 725 rm -f /tmp/ftp-script.sh 726 727 # Prepare ftp-fetch script to fetch binary sets 728 _download_dir=INSTALL 729 _ftp_opts="" 730 _ftp_url="ftp://$_ftp_server_login:$_ftp_server_password@$_ftp_server_ip$_ftp_server_dir/" 731 echo "#!/bin/sh" > /tmp/ftp-fetch.sh 732 echo "cd /mnt" >> /tmp/ftp-fetch.sh 733 echo "mkdir -p $_download_dir" >> /tmp/ftp-fetch.sh 734 735 while : ; do 736 echo "The following sets are available for extraction:" 737 echo "(marked sets are already on the extraction list)" 738 echo "" 739 740 _next="" 741 for _f in $_sets ; do 742 if isin $_f $_setsdone; then 743 echo -n "[X] " 744 _next="" 745 else 746 echo -n " " 747 if [ -z "$_next" ]; then _next=$_f; fi 748 fi 749 echo $_f 750 done 751 echo "" 752 753 # Get name of the file and add extraction command 754 # to the ftp-fetch script. 755 if [ -z "$_next" ]; then resp=n; else resp=y; fi 756 echo -n "Continue to add filenames [$resp]? " 757 getresp "$resp" 758 if [ "$resp" = "n" ]; then 759 break 760 fi 761 762 echo -n "File name [$_next]? " 763 getresp "$_next" 764 if isin $resp $_sets; then 765 echo "echo Fetching $resp:" >> \ 766 /tmp/ftp-fetch.sh 767 echo "ftp ${_ftp_opts} -o $_download_dir/$resp ${_ftp_url}$resp" >> \ 768 /tmp/ftp-fetch.sh 769 echo "echo Extracting $resp:" >> \ 770 /tmp/ftp-fetch.sh 771 echo "pax -zr${verbose_flag}pe -f $_download_dir/$resp" >> \ 772 /tmp/ftp-fetch.sh 773 echo "rm -f $_download_dir/$resp" >> \ 774 /tmp/ftp-fetch.sh 775 _setsdone="$resp $_setsdone" 776 else 777 echo "You entered an invalid filename." 778 echo "" 779 fi 780 done 781 782 sh /tmp/ftp-fetch.sh 783 rm -f /tmp/ftp-fetch.sh 784 echo "Extraction complete." 785} 786 787install_from_mounted_fs() { 788 # $1 - directory containing installation sets 789 local _filename 790 local _sets 791 local _next 792 local _all 793 local _f 794 local _dirname 795 796 _dirname=$1 797 _sets="" 798 799 if ! dir_has_sets ${_dirname} $THESETS 800 then 801 802 echo "" 803 echo "The directory at the mount point, \"${_dirname}\", contains: " 804 echo "" 805 ls -F ${_dirname} 806 echo "" 807 echo "Enter the subdirectory relative to the mountpoint, that" 808 echo -n "contains the savesets: [try this directory] " 809 getresp "" 810 if [ -n "${resp}" ]; then 811 _dirname=${_dirname}/$resp 812 fi 813 814 while ! dir_has_sets ${_dirname} $THESETS; do 815 echo "" 816 echo -n "There are no NetBSD install sets available in " 817 echo "\"${_dirname}\"." 818 echo "\"${_dirname}\" contains: " 819 echo "" 820 ls -F ${_dirname} 821 echo "" 822 echo -n "Enter subdirectory: [try other install media] " 823 getresp "" 824 if [ -z "${resp}" ]; then 825 return 826 fi 827 if [ ! -d ${_dirname}/${resp} ]; then 828 echo "\"${resp}\" is no directory; try again." 829 else 830 _dirname=${_dirname}/$resp 831 fi 832 done 833 fi 834 835 for _f in $THESETS ; do 836 if [ -f ${_dirname}/${_f}.tar.gz ]; then 837 _sets="$_sets ${_f}.tar.gz" 838 elif [ -f ${_dirname}/${_f}.tgz ]; then 839 _sets="$_sets ${_f}.tgz" 840 elif [ -f ${_dirname}/${_f}.tar ]; then 841 _sets="$_sets ${_f}.tar" 842 elif [ -f ${_dirname}/${_f}${VERSION}.aa ]; then 843 _sets="$_sets ${_f}${VERSION}" 844 fi 845 done 846 847 while : ; do 848 echo "The following sets are available for extraction:" 849 echo "(marked sets have already been extracted)" 850 echo "" 851 852 _next="" 853 _all="" 854 for _f in $_sets ; do 855 if isin $_f $_setsdone; then 856 echo -n "[X] " 857 _next="" 858 else 859 echo -n " " 860 if [ -z "$_next" ]; then 861 _next=$_f; 862 fi 863 _all="$_all $_f" 864 fi 865 echo $_f 866 done 867 echo "" 868 869 # Get the name of the file. 870 if [ -z "$_next" ]; then 871 resp=n 872 else 873 resp=y 874 fi 875 echo -n "Continue extraction [$resp]?" 876 getresp "$resp" 877 if [ "$resp" = "n" ]; then 878 break 879 fi 880 881 echo -n "File name(s) (or "all") [$_next]? " 882 getresp "$_next" 883 if [ "x$resp" = xall ]; then 884 resp="$_all" 885 fi 886 887 for _f in $resp; do 888 _filename="/${_dirname}/$_f" 889 890 # Ensure file exists 891 if [ ! -f $_filename ]; then 892 if [ -f ${_filename}.aa ]; then 893 _filename=${_filename}.\?\? 894 else 895 echo "File $_filename does not exist. Check to make" 896 echo "sure you entered the information properly." 897 continue 2 898 fi 899 fi 900 901 # Extract file 902 echo "Extracting the $_f set:" 903 case "$_filename" in 904 *.tar) 905 (cd /mnt; pax -r${verbose_flag}pe < $_filename) 906 ;; 907 *) 908 cat $_filename | \ 909 (cd /mnt; pax -zr${verbose_flag}pe) 910 ;; 911 esac 912 echo "Extraction complete." 913 _setsdone="$_f $_setsdone" 914 done 915 916 done 917} 918 919install_cdrom() { 920 local _drive 921 local _partition_range 922 local _partition 923 local _fstype 924 local _directory 925 926 # Get the cdrom device info 927 cat << \__install_cdrom_1 928 929The following CD-ROM devices are installed on your system; please select 930the CD-ROM device containing the partition with the installation sets: 931 932__install_cdrom_1 933 _CDDEVS=$(md_get_cddevs) 934 echo "$_CDDEVS" 935 echo "" 936 echo -n "Which is the CD-ROM with the installation media? [abort] " 937 getresp "abort" 938 case "$resp" in 939 abort) 940 echo "Aborting." 941 return 942 ;; 943 944 *) 945 if isin $resp $_CDDEVS ; then 946 _drive=$resp 947 else 948 echo "" 949 echo "The CD-ROM $resp does not exist." 950 echo "Aborting." 951 return 952 fi 953 ;; 954 esac 955 956 # Get partition 957 _partition_range=$(md_get_partition_range) 958 resp="" # force one iteration 959 while [ -z "${resp}" ]; do 960 echo -n "Partition? [a] " 961 getresp "a" 962 case "$resp" in 963 $_partition_range) 964 _partition=$resp 965 ;; 966 967 *) 968 echo "Invalid response: $resp" 969 resp="" # force loop to repeat 970 ;; 971 esac 972 done 973 974 # Ask for filesystem type 975 cat << \__install_cdrom_2 976 977There are two CD-ROM filesystem types currently supported by this program: 978 1) ISO-9660 (cd9660) 979 2) Berkeley Fast Filesystem (ffs) 980 981__install_cdrom_2 982 resp="" # force one iteration 983 while [ -z "${resp}" ]; do 984 echo -n "Which filesystem type? [cd9660] " 985 getresp "cd9660" 986 case "$resp" in 987 cd9660|ffs) 988 _fstype=$resp 989 ;; 990 991 *) 992 echo "Invalid response: $resp" 993 resp="" # force loop to repeat 994 ;; 995 esac 996 done 997 998 # Mount the CD-ROM 999 if ! mount -t ${_fstype} -o ro \ 1000 /dev/${_drive}${_partition} /mnt2 ; then 1001 echo "Cannot mount CD-ROM drive. Aborting." 1002 return 1003 fi 1004 1005 install_from_mounted_fs /mnt2 1006 umount -f /mnt2 > /dev/null 2>&1 1007} 1008 1009mount_a_disk() { 1010 # Mount a disk on /mnt2. The set of disk devices to choose from 1011 # is $_DKDEVS. 1012 # returns 0 on failure. 1013 1014 local _drive 1015 local _partition_range 1016 local _partition 1017 local _fstype 1018 local _fsopts 1019 local _directory 1020 local _md_fstype 1021 local _md_fsopts 1022 1023 getresp "abort" 1024 case "$resp" in 1025 abort) 1026 echo "Aborting." 1027 return 0 1028 ;; 1029 1030 *) 1031 if isin $resp $_DKDEVS ; then 1032 _drive=$resp 1033 else 1034 echo "" 1035 echo "The disk $resp does not exist." 1036 echo "Aborting." 1037 return 0 1038 fi 1039 ;; 1040 esac 1041 1042 # Get partition 1043 _partition_range=$(md_get_partition_range) 1044 resp="" # force one iteration 1045 while [ -z "${resp}" ]; do 1046 echo -n "Partition? [d] " 1047 getresp "d" 1048 case "$resp" in 1049 $_partition_range) 1050 _partition=$resp 1051 ;; 1052 1053 *) 1054 echo "Invalid response: $resp" 1055 resp="" # force loop to repeat 1056 ;; 1057 esac 1058 done 1059 1060 # Ask for filesystem type 1061 cat << \__mount_a_disk_2 1062 1063The following filesystem types are supported: 1064 1) ffs 1065 2) cd9660 1066__mount_a_disk_2 1067 _md_fstype=$(md_native_fstype) 1068 _md_fsopts=$(md_native_fsopts) 1069 if [ -n "$_md_fstype" ]; then 1070 echo " 3) $_md_fstype" 1071 else 1072 _md_fstype="_undefined_" 1073 fi 1074 resp="" # force one iteration 1075 while [ -z "${resp}" ]; do 1076 echo -n "Which filesystem type? [ffs] " 1077 getresp "ffs" 1078 case "$resp" in 1079 ffs|cd9660) 1080 _fstype=$resp 1081 _fsopts="ro" 1082 ;; 1083 $_md_fstype) 1084 _fstype=$resp 1085 _fsopts=$_md_fsopts 1086 ;; 1087 *) 1088 echo "Invalid response: $resp" 1089 resp="" # force loop to repeat 1090 ;; 1091 esac 1092 done 1093 1094 # Mount the disk 1095 if ! mount -t ${_fstype} -o $_fsopts \ 1096 /dev/${_drive}${_partition} /mnt2 ; then 1097 echo "Cannot mount disk. Aborting." 1098 return 0 1099 fi 1100 return 1 1101} 1102 1103install_disk() { 1104 local _directory 1105 1106 cat << \__install_disk_1 1107 1108Ok, lets install from a disk. The file-system the install sets on may 1109already mounted, or we might have to mount the filesystem to get to it. 1110 1111__install_disk_1 1112 1113 echo -n "Is the file-system with the install sets already mounted? [n] " 1114 getresp "n" 1115 case $resp in 1116 y*|Y*) 1117 echo "What mount point are the sets located in? [] " 1118 getresp "" 1119 if [ -d "$resp" ]; then 1120 install_from_mounted_fs $resp 1121 else 1122 echo "$resp: Not a directory, aborting..." 1123 fi 1124 return 1125 ;; 1126 *) 1127 ;; 1128 esac 1129 1130 cat << \__install_disk_2 1131 1132The following disk devices are installed on your system; please select 1133the disk device containing the partition with the installation sets: 1134 1135__install_disk_2 1136 _DKDEVS=$(md_get_diskdevs) 1137 echo "$_DKDEVS" 1138 echo "" 1139 echo -n "Which is the disk with the installation sets? [abort] " 1140 1141 if mount_a_disk ; then 1142 return 1143 fi 1144 1145 install_from_mounted_fs /mnt2 1146 umount -f /mnt2 > /dev/null 2>&1 1147} 1148 1149install_nfs() { 1150 # Get the IP address of the server 1151 resp="" # force one iteration 1152 while [ -z "${resp}" ]; do 1153 echo -n "Server IP address? [${_nfs_server_ip}] " 1154 getresp "${_nfs_server_ip}" 1155 done 1156 _nfs_server_ip=$resp 1157 1158 # Get server path to mount 1159 resp="" # force one iteration 1160 while [ -z "${resp}" ]; do 1161 echo -n "Filesystem on server to mount? [${_nfs_server_path}] " 1162 getresp "${_nfs_server_path}" 1163 done 1164 _nfs_server_path=$resp 1165 1166 # Check mount_nfs(8) options 1167 echo "Use small NFS transfers (needed when server or client" 1168 echo -n "has a slow network card)? [n] " 1169 getresp "n" 1170 case "$resp" in 1171 y*|Y*) 1172 _nfs_tcp="-r 1024 -w 1024" 1173 ;; 1174 1175 *) 1176 _nfs_tcp="" 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 [ -z "${resp}" ]; 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 [ -z "${resp}" ]; 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 [ "${_nskip}" != "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 [ -z "${resp}" ]; 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 immediately. 1291 # 1292 if [ ! -e /usr/share/zoneinfo ] && [ ! -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 [ -z "$TZ" ]; 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 [ -n "${local_sets_dir}" ]; then 1393 install_from_mounted_fs ${local_sets_dir} 1394 if [ -n "$_setsdone" ]; 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 [ -z "${resp}" ]; 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 [ "${_yup}" = "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 [ "$_mp" != "/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 displayed by mount 1510 exit 1 1511 fi 1512 done ) < $_fstab 1513 1514 if [ "$?" != "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}" ] || ! [ -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 "Unmounting 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 1607mi_mount_kernfs() { 1608 # Make sure kernfs is mounted. 1609 if [ ! -d /kern ] || [ ! -e /kern/msgbuf ]; then 1610 mkdir /kern > /dev/null 2>&1 1611 /sbin/mount_kernfs /kern /kern 1612 fi 1613} 1614 1615mi_filter_msgbuf() { 1616 # Remove timestamps, sort. 1617 sed -e 's/^\[[0-9. ]*\] //' < /kern/msgbuf | sort -u 1618} 1619 1620mi_filter_dmesg() { 1621 # Remove timestamps, sort. 1622 dmesg | awk '{ h=$0; gsub("^[[0-9. ]*] ", "", h); print h; }' \ 1623 | sort -u 1624} 1625