1 #!/bin/ksh
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 #
  23 # Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
  24 #
  25 # Author:  Jeff Bonwick
  26 #
  27 #       Please report any bugs to bonwick@eng.
  28 #
  29 # How Install works:
  30 #
  31 #       Install performs the following steps:
  32 #
  33 #       1. Get the list of modules, configuration files, and links
  34 #          that are desired.
  35 #
  36 #       2. Create the requested subset of /kernel in Install's temp space
  37 #          (/tmp/Install.username by default.)
  38 #
  39 #       3. Create a tar file (/tmp/Install.username/Install.tar) based on (3).
  40 #
  41 #       4. If -n was specified, exit.  If a target was specified using -T,
  42 #          rcp the tarfile to the target and exit.  If a target was specified
  43 #          using -t, rsh to the target machine and untar the tarfile in the
  44 #          target directory.
  45 #
  46 # If any of these steps fail, Install will give you an error message and,
  47 # in most cases, suggest corrective measures.  Then, you can recover the
  48 # install with "Install -R". (This is not required; it's just faster than
  49 # starting from scratch.)
  50 #
  51 # One final comment:  Unfortunately, tar and I disagree on what
  52 # constitutes a fatal error.  (tar -x will exit 0 even if it can't write
  53 # anything in the current directory.)  Thus, I am reduced to grepping stderr
  54 # for (what I consider) fatal and nonfatal error messages.  If you run into
  55 # a situation where this doesn't behave the way you think it should (either
  56 # an "Install failed" message after a successful install, or an "Install
  57 # complete" message after it bombs), please let me know.
  58 
  59 #
  60 # The CDPATH variable causes ksh's `cd' builtin to emit messages to stdout
  61 # under certain circumstances, which can really screw things up; unset it.
  62 #
  63 unset CDPATH
  64 
  65 INSTALL=`basename $0`
  66 DOT=`pwd`
  67 
  68 TRAILER="Install.$LOGNAME"
  69 INSTALL_STATE=${INSTALL_STATE-$HOME/.Install.state}
  70 export INSTALL_STATE
  71 INSTALL_DIR=${INSTALL_DIR-/tmp/$TRAILER}
  72 if [ "`basename $INSTALL_DIR`" != "$TRAILER" ]; then
  73         INSTALL_DIR="$INSTALL_DIR/$TRAILER"
  74 fi
  75 export INSTALL_DIR
  76 INSTALL_LIB=${INSTALL_LIB-$HOME/LibInstall}
  77 export INSTALL_LIB
  78 INSTALL_RC=${INSTALL_RC-$HOME/.Installrc}
  79 export INSTALL_RC
  80 INSTALL_CP=${INSTALL_CP-"cp -p"}
  81 export INSTALL_CP
  82 INSTALL_RCP=${INSTALL_RCP-"rcp -p"}
  83 export INSTALL_RCP
  84 
  85 STATE=0
  86 
  87 DEFAULT_OPTIONS="-naq"
  88 GLOM=no
  89 GLOMNAME=kernel
  90 IMPL="default"
  91 WANT32="yes"
  92 WANT64="yes"
  93 
  94 modlist=/tmp/modlist$$
  95 # dummy directory for make state files.
  96 modstatedir=/tmp/modstate$$
  97 
  98 trap 'fail "User Interrupt" "You can resume by typing \"$INSTALL -R\""' 1 2 3 15
  99 
 100 function usage {
 101         echo ""
 102         echo $1
 103         echo '
 104 Usage: Install  [ -w workspace ]
 105                 [ -s srcdir (default: usr/src/uts) ]
 106                 [ -k karch (e.g. sun4u; required if not deducible from pwd) ]
 107                 [ -t target (extract tar file on target, e.g. user@machine:/) ]
 108                 [ -T target (copy tar file to target, e.g. user@machine:/tmp) ]
 109                 [ -n (no target, just create tar file in /tmp (default)) ]
 110                 [ -u (install unix only) ]
 111                 [ -m (install modules only) ]
 112                 [ -a (install everything, i.e. unix + modules (default)) ]
 113                 [ -v (verbose output) ]
 114                 [ -V (REALLY verbose output) ]
 115                 [ -q (quiet (default)) ]
 116                 [ -c (clean up (remove temp files) when done (default) ]
 117                 [ -p (preserve temp files -- useful for debugging) ]
 118                 [ -L (library create: put tarfile in $INSTALL_LIB/env.karch) ]
 119                 [ -l lib (library extract: use $INSTALL_LIB/lib as source) ]
 120                 [ -D libdir (default: $HOME/LibInstall) ]
 121                 [ -d tempdir (Install work area (default: /tmp)) ]
 122                 [ -G glomname (put all files under platform/karch/glomname) ]
 123                 [ -i impl (e.g. sunfire; recommended with -G) ]
 124                 [ -x (update /etc/name_to_major et al) ]
 125                 [ -X (do not update /etc/name_to_major et al (default)) ]
 126                 [ -P (update /etc/path_to_inst -- generally not advisable) ]
 127                 [ -h (help -- prints this message) ]
 128                 [ -R (recover a previous Install) ]
 129                 [ -o objdir (object directory - either obj or debug (the default)) ]
 130                 [ -K (do not copy kmdb) ]
 131                 [ -3 32-bit modules only ]
 132                 [ -6 64-bit modules only ]
 133                 [ list of modules to install ]
 134 
 135 For full details:
 136 
 137         man -M /ws/on297-gate/public/docs Install
 138 '
 139         exit 1
 140 }
 141 
 142 #
 143 # Save the current state of Install
 144 #
 145 
 146 function save_state {
 147         rm -f $INSTALL_STATE
 148         (echo "# State of previous Install
 149 TARGET=$TARGET
 150 ENV_PATH=$ENV_PATH
 151 ENV_NAME=$ENV_NAME
 152 KARCH=$KARCH
 153 UTS=$UTS
 154 INSTALL_DIR=$INSTALL_DIR
 155 INSTALL_LIB=$INSTALL_LIB
 156 IMODE=$IMODE
 157 LIBCREATE=$LIBCREATE
 158 LIBSRC=$LIBSRC
 159 VERBOSE=$VERBOSE
 160 CLEANUP=$CLEANUP
 161 GLOM=$GLOM
 162 GLOMNAME=$GLOMNAME
 163 KMDB=$KMDB
 164 files='$files'
 165 STATE=$STATE" >$INSTALL_STATE) || verbose "Warning: cannot save state"
 166 }
 167 
 168 #
 169 # Restore the previous state of Install
 170 #
 171 
 172 function restore_state {
 173         test -s $INSTALL_STATE || fail "Can't find $INSTALL_STATE"
 174         eval "`cat $INSTALL_STATE`"
 175 }
 176 
 177 #
 178 # Install failed -- print error messages and exit 2
 179 #
 180 
 181 function fail {
 182         save_state
 183         #
 184         # We might have gotten here via a trap.  So wait for any
 185         # children (especially "make modlist") to exit before giving
 186         # the error message or cleaning up.
 187         #
 188         wait
 189         while [ $# -gt 0 ]
 190         do
 191                 echo $1
 192                 shift
 193         done
 194         rm -rf $modstatedir
 195         rm -f $modlist
 196         echo "Install failed"
 197         exit 2
 198 }
 199 
 200 #
 201 # Echo a string in verbose mode only
 202 #
 203 
 204 function verbose {
 205         test "$VERBOSE" != "q" && echo $1
 206 }
 207 
 208 #
 209 # hack for tmpfs bug -- remove files gradually
 210 #
 211 
 212 function remove_dir {
 213         test -d $1 || return
 214         local_dot=`pwd`
 215         cd $1
 216         touch foo
 217         rm -f `find . -type f -print`
 218         cd $local_dot
 219         rm -rf $1
 220 }
 221 
 222 #
 223 # Create a directory if it doesn't already exist.
 224 # mkdir will provide an error message, so don't provide an additional
 225 # message.
 226 #
 227 
 228 function tstmkdir {
 229         [ -d $1 ] || mkdir -p $1 || fail
 230 }
 231 
 232 #
 233 # Patch up target directories for glommed kernel.
 234 # usage: fixglom listfile glomname
 235 #
 236 
 237 function fixglom {
 238         nawk \
 239             -v glomname=$2 \
 240             -v karch=$KARCH ' 
 241         $1 == "MOD" || $1 == "SYMLINK" {
 242                 sub(/^platform.*kernel/, "platform/" karch "/" glomname, $4)
 243                 sub(/^kernel/, "platform/" karch "/" glomname, $4)
 244                 sub(/^usr.kernel/, "platform/" karch "/" glomname, $4)
 245                 print
 246         }
 247         $1 == "LINK" {
 248                 sub(/^platform.*kernel/, "platform/" karch "/" glomname, $3)
 249                 sub(/^kernel/, "platform/" karch "/" glomname, $3)
 250                 sub(/^usr.kernel/, "platform/" karch "/" glomname, $3)
 251                 sub(/^platform.*kernel/, "platform/" karch "/" glomname, $5)
 252                 sub(/^kernel/, "platform/" karch "/" glomname, $5)
 253                 sub(/^usr.kernel/, "platform/" karch "/" glomname, $5)
 254                 print
 255         }
 256         $1 == "CONF" {
 257                 sub(/^platform.*kernel/, "platform/" karch "/" glomname, $3)
 258                 sub(/^kernel/, "platform/" karch "/" glomname, $3)
 259                 sub(/^usr.kernel/, "platform/" karch "/" glomname, $3)
 260                 print
 261         }
 262         ' $1 > $1.new
 263         mv $1.new $1
 264 }
 265 
 266 #
 267 # Filter out implementation-specific modules, unless that
 268 # implementation was requested by the user.
 269 # usage: filtimpl listfile implname
 270 #
 271 
 272 function filtimpl {
 273         nawk \
 274             -v impl=$2 '
 275         $1 == "MOD" || $1 == "SYMLINK" {
 276                 if ($6 == "all" || $6 == impl)
 277                         print
 278         }
 279         $1 == "CONF" {
 280                 if ($5 == "all" || $5 == impl)
 281                         print
 282         }
 283         $1 == "LINK" {
 284                 if ($7 == "all" || $7 == impl)
 285                         print
 286         }
 287         ' $1 > $1.new
 288         mv $1.new $1
 289 }
 290 
 291 #
 292 # Filter the module list to match the user's request.
 293 # Usage: filtmod listfile modules
 294 #
 295 function filtmod {
 296         nawk -v reqstring="$2" '
 297         function modmatch(modname) {
 298                 if (reqstring == "All") {
 299                         return (1)
 300                 } else if (reqstring == "Modules") {
 301                         if (modname != "unix" && modname != "genunix")
 302                                 return (1)
 303                 } else {
 304                         if (modname in reqmods)
 305                                 return (1)
 306                 }
 307                 return (0)
 308         }
 309         BEGIN {
 310                 #
 311                 # The split call creates indexes 1, 2, 3, ...  We want
 312                 # the module names as indexes.
 313                 #
 314                 split(reqstring, tmpmods)
 315                 for (i in tmpmods)
 316                         reqmods[tmpmods[i]] = 1
 317         }
 318         $1 == "MOD" {
 319                 if (modmatch($3))
 320                         print
 321         }
 322         $1 == "CONF" {
 323                 if (modmatch($6))
 324                         print
 325         }
 326         $1 == "SYMLINK" {
 327                 if (modmatch($7))
 328                         print
 329         }
 330         $1 == "LINK" {
 331                 if (modmatch($4))
 332                         print
 333         }
 334         ' $1 > $1.new
 335         mv $1.new $1
 336 }
 337 
 338 #
 339 # Unpack the crypto tarball into the given tree, then massage the
 340 # tree so that the binaries are all in objNN or debugNN directories.
 341 #
 342 function unpack_crypto {
 343         typeset tarfile=$1
 344         typeset ctop=$2
 345         [ -d "$ctop" ] || fail "Can't create tree for crypto modules."
 346 
 347         [ "$VERBOSE" = "V" ] && echo "unpacking crypto tarball into $ctop..."
 348         bzcat "$tarfile" | (cd "$ctop"; tar xf -)
 349 
 350         typeset root="$ctop/proto/root_$MACH"
 351         [ $OBJD = obj ] && root="$ctop/proto/root_$MACH-nd"
 352         [ -d "$root" ] || fail "Can't unpack crypto tarball."
 353 
 354         (cd "$root"; for d in platform kernel usr/kernel; do
 355                 [ ! -d $d ] && continue
 356                 find $d -type f -print
 357         done) | while read file; do
 358                 typeset dir=$(dirname "$file")
 359                 typeset base=$(basename "$file")
 360                 typeset type=$(basename "$dir")
 361                 if [ "$type" = amd64 ]; then
 362                         newdir="$dir/${OBJD}64"
 363                 elif [ "$type" = sparcv9 ]; then
 364                         newdir="$dir/${OBJD}64"
 365                 else
 366                         newdir="$dir/${OBJD}32"
 367                 fi
 368                 mkdir -p "$root/$newdir"
 369                 [ "$VERBOSE" = "V" ] && echo "mv $file $newdir"
 370                 mv "$root/$file" "$root/$newdir"
 371         done
 372 }
 373 
 374 #
 375 # usage: fixcrypto listfile ctop
 376 # Massage entries in listfile for crypto modules, so that they point
 377 # into ctop.
 378 #
 379 function fixcrypto {
 380         typeset listfile=$1
 381         typeset ctop=$2
 382 
 383         typeset ccontents=/tmp/crypto-toc$$
 384         find "$ctop" -type f -print > $ccontents
 385         typeset root=root_$MACH
 386         [ "$OBJD" = obj ] && root=root_$MACH-nd
 387 
 388         grep -v ^MOD $listfile > $listfile.no-mod
 389         grep ^MOD $listfile | while read tag srcdir module targdir size impl; do
 390                 #
 391                 # We don't just grep for ${OBJD}$size/$module because
 392                 # there can be generic and platform-dependent versions
 393                 # of a module.
 394                 #
 395                 newsrcfile=$(grep -w $root/$targdir/${OBJD}$size/$module $ccontents)
 396                 if [ -n "$newsrcfile" ]; then
 397                         # srcdir doesn't include final objNN or debugNN
 398                         echo $tag $module $targdir $size $impl \
 399                             $(dirname $(dirname "$newsrcfile"))
 400                 else
 401                         echo $tag $module $targdir $size $impl $srcdir
 402                 fi
 403         done > $listfile.mod
 404         cat $listfile.mod $listfile.no-mod > $listfile
 405 
 406         rm -f $listfile.mod
 407         rm -f $listfile.no-mod
 408         rm -f $ccontents
 409 }
 410 
 411 #
 412 # Copy a module, or create a link, as needed.
 413 #
 414 
 415 function copymod {
 416         case $1 in
 417         MOD)
 418                 targdir=$INSTALL_FILES/$4
 419                 tstmkdir $targdir
 420                 target=$targdir/$3
 421                 verbose "$INSTALL_CP $2/${OBJD}$5/$3 $target"
 422                 $INSTALL_CP $2/${OBJD}$5/$3 $target || \
 423                     fail "can't create $target"
 424                 ;;
 425         SYMLINK)
 426                 targdir=$INSTALL_FILES/$4
 427                 tstmkdir $targdir
 428                 target=$targdir/$5
 429                 rm -f $target
 430                 verbose "ln -s $3 $target"
 431                 ln -s $3 $target || fail "can't create $target"
 432                 ;;
 433         LINK)
 434                 targdir=$INSTALL_FILES/$5
 435                 tstmkdir $targdir
 436                 target=$targdir/$6
 437                 rm -f $target
 438                 verbose "ln $INSTALL_FILES/$3/$4 $target"
 439                 ln $INSTALL_FILES/$3/$4 $target || fail "can't create $target"
 440                 ;;
 441         CONF)
 442                 target=$INSTALL_FILES/$3
 443                 tstmkdir `dirname $target`
 444                 conffile=`basename $3`
 445                 verbose "$INSTALL_CP $4/$conffile $target"
 446                 $INSTALL_CP $4/$conffile $target
 447                 ;;
 448         *)
 449                 fail "unrecognized modlist entry: $*"
 450                 ;;
 451         esac
 452 }
 453 
 454 # Sanity-check the given module list.
 455 function check_modlist {
 456         nawk '
 457         BEGIN {
 458                 nfields["MOD"] = 6
 459                 nfields["CONF"] = 6
 460                 nfields["LINK"] = 7
 461                 nfields["SYMLINK"] = 7
 462         }
 463         {
 464                 # This also catches unknown tags.
 465                 if (nfields[$1] != NF) {
 466                         print "error: invalid modlist record:"
 467                         print $0
 468                         print "expected", nfields[$1], "fields, found", NF
 469                         status=1
 470                 }
 471         }
 472         END {
 473                 exit status
 474         }
 475         ' $1 || fail "Errors in kernel module list"
 476 }
 477 
 478 #
 479 # Copy kernel modules to $INSTALL_DIR
 480 #
 481 
 482 function copy_kernel {
 483 
 484         case $KARCH in
 485                 sun4*)          ISA=sparc;      MACH=sparc      ;;
 486                 i86*)           ISA=intel;      MACH=i386       ;;
 487                 *)              fail "${KARCH}: invalid kernel architecture";;
 488         esac
 489         export MACH
 490 
 491         if [ "$GLOM" = "no" ]; then
 492                 verbose "Source = $UTS, ISA = $ISA, kernel = $KARCH"
 493         else
 494                 verbose "Source = $UTS, ISA = $ISA, kernel = $KARCH, impl = $IMPL"
 495         fi
 496 
 497         test -d $KARCH || fail "${KARCH}: invalid kernel architecture"
 498         test -d $ISA || fail "${ISA}: invalid instruction set architecture"
 499 
 500         tstmkdir $INSTALL_FILES
 501         rm -rf $modstatedir
 502         tstmkdir $modstatedir
 503         export MODSTATE=$modstatedir/state
 504 
 505         #
 506         # Figure out which "make" to use.  dmake is faster than serial
 507         # make, but dmake 7.3 has a bug that causes it to lose log
 508         # output, which means the modlist might be incomplete.
 509         #
 510         make=dmake
 511         dmvers=`$make -version`
 512         if [ $? -ne 0 ]; then
 513                 make=/usr/ccs/bin/make
 514         elif [[ $dmvers = *Distributed?Make?7.3* ]]; then
 515                 unset make
 516                 searchpath="/ws/onnv-tools/SUNWspro/SOS10/bin
 517                         /opt/SUNWspro/SOS10/bin
 518                         /opt/SUNWspro/bin"
 519                 for dmpath in $searchpath; do
 520                         verbose "Trying $dmpath/dmake"
 521                         if [ -x $dmpath/dmake ]; then
 522                                 dmvers=`$dmpath/dmake -version`
 523                                 if [[ $dmvers != *Distributed?Make?7.3* ]]; then
 524                                         make="$dmpath/dmake"
 525                                         break;
 526                                 fi
 527                         fi
 528                 done
 529                 if [ -z $make ]; then
 530                         make=/usr/ccs/bin/make
 531                         echo "Warning: dmake 7.3 doesn't work with Install;" \
 532                                 "using $make"
 533                 fi
 534         fi
 535 
 536         #
 537         # Get a list of all modules, configuration files, and links
 538         # that we might want to install.
 539         #
 540         verbose "Building module list..."
 541         (cd $KARCH; MAKEFLAGS=e $make -K $MODSTATE modlist.karch) | \
 542             egrep "^MOD|^CONF|^LINK|^SYMLINK" > $modlist
 543         [ "$VERBOSE" = "V" ] && cat $modlist
 544         check_modlist $modlist
 545         if [ -n "$ON_CRYPTO_BINS" ]; then
 546                 cryptotar="$ON_CRYPTO_BINS"
 547                 if [ "$OBJD" = obj ]; then
 548                         isa=$(uname -p)
 549                         cryptotar=$(echo "$ON_CRYPTO_BINS" |
 550                             sed -e s/.$isa.tar.bz2/-nd.$isa.tar.bz2/)
 551                 fi
 552                 [ -f "$cryptotar" ] || fail "crypto ($cryptotar) doesn't exist"
 553                 cryptotree=$(mktemp -d /tmp/crypto.XXXXXX)
 554                 [ -n "$cryptotree" ] || fail "can't create tree for crypto"
 555                 unpack_crypto "$cryptotar" "$cryptotree"
 556                 #
 557                 # fixcrypto must come before fixglom, because
 558                 # fixcrypto uses the unglommed path to find things in
 559                 # the unpacked crypto.
 560                 #
 561                 fixcrypto $modlist "$cryptotree"
 562         fi
 563         if [ "$GLOM" = "yes" ]; then
 564                 fixglom $modlist $GLOMNAME
 565                 filtimpl $modlist $IMPL
 566         fi
 567         if [[ -n "$files" && "$files" != All ]]; then
 568                 filtmod $modlist "$files"
 569         fi
 570 
 571         #
 572         # Copy modules and create links.  For architectures with both
 573         # 32- and 64-bit modules, we'll likely have duplicate
 574         # configuration files, so do those after filtering out the
 575         # duplicates.
 576         #
 577         verbose "Copying files to ${INSTALL_FILES}..."
 578 
 579         #
 580         # The IFS is reset to the newline character so we can buffer the
 581         # output of grep without piping it directly to copymod, otherwise
 582         # if fail() is called, then it will deadlock in fail()'s wait call
 583         #
 584         OIFS="$IFS"
 585         IFS="
 586         "
 587         set -- `grep -v "^CONF" $modlist`;
 588         IFS="$OIFS"
 589         for onemod in "$@"; do
 590                 copymod $onemod
 591         done
 592         
 593         OIFS="$IFS"
 594         IFS="
 595         "
 596         set -- `grep "^CONF" $modlist | sort | uniq`;
 597         IFS="$OIFS"
 598         for onemod in "$@"; do
 599                 copymod $onemod
 600         done
 601 
 602         #
 603         # Add the glommed kernel name to the root archive
 604         #
 605         if [[ $GLOM == "yes" ]];
 606         then
 607                 filelist="$INSTALL_FILES/etc/boot/solaris/filelist.ramdisk"
 608                 mkdir -p `dirname $filelist`
 609                 echo "platform/$KARCH/$GLOMNAME" >$filelist
 610         fi
 611 
 612         STATE=1 # all kernel modules copied correctly
 613         save_state
 614 }
 615 
 616 function kmdb_copy {
 617         typeset src="$1"
 618         typeset destdir="$2"
 619 
 620         if [[ ! -d $dest ]] ; then
 621                 [[ "$VERBOSE" != "q" ]] && echo "mkdir -p $destdir"
 622 
 623                 mkdir -p $destdir || fail "failed to create $destdir"
 624         fi
 625 
 626         [[ "$VERBOSE" != "q" ]] && echo "cp $src $destdir"
 627 
 628         cp $src $destdir || fail "failed to copy $src to $destdir"
 629 }
 630 
 631 function kmdb_copy_machkmods {
 632         typeset modbase="$1"
 633         typeset destdir="$2"
 634         typeset dir=
 635         typeset kmod=
 636 
 637         [[ ! -d $modbase ]] && return
 638 
 639         for dir in $(find $modbase -name kmod) ; do
 640                 set -- $(echo $dir |tr '/' ' ')
 641 
 642                 [[ $# -lt 2 ]] && fail "invalid mach kmod dir $dir"
 643 
 644                 shift $(($# - 2))
 645                 kmod=$1
 646 
 647                 [[ ! -f $dir/$kmod ]] && continue
 648 
 649                 kmdb_copy $dir/$kmod $destdir
 650         done
 651 }
 652 
 653 function kmdb_copy_karchkmods {
 654         typeset modbase="$1"
 655         typeset destdir="$2"
 656         typeset bitdir="$3"
 657         typeset dir=
 658         typeset kmod=
 659         typeset karch=
 660 
 661         [[ ! -d $modbase ]] && return
 662 
 663         for dir in $(find $modbase -name kmod) ; do
 664                 set -- $(echo $dir | tr '/' ' ')
 665 
 666                 [[ $# -lt 3 ]] && fail "invalid karch kmod dir $dir"
 667 
 668                 shift $(($# - 3))
 669                 kmod=$1
 670                 bdir=$2
 671 
 672                 [[ $bdir != $bitdir ]] && continue
 673                 [[ ! -f $dir/$1 ]] && continue
 674 
 675                 kmdb_copy $dir/$kmod $destdir
 676         done
 677 }
 678 
 679 function kmdb_copy_kmdbmod {
 680         typeset kmdbpath="$1"
 681         typeset destdir="$2"
 682 
 683         [[ ! -f $kmdbpath ]] && return 1
 684 
 685         kmdb_copy $kmdbpath $destdir
 686 
 687         return 0
 688 }
 689 
 690 function copy_kmdb {
 691         typeset kmdbtgtdir=$INSTALL_FILES/platform/$KARCH/$GLOMNAME/misc
 692         typeset bitdirs=
 693         typeset isadir=
 694         typeset b64srcdir=
 695         typeset b64tgtdir=
 696         typeset b32srcdir=
 697         typeset b32tgtdir=
 698         typeset machdir=
 699         typeset platdir=
 700 
 701         if [[ $KMDB = "no" || ! -d $SRC/cmd/mdb ]] ; then
 702                 # The kmdb copy was suppressed or the workspace doesn't contain
 703                 # the mdb subtree.  Either way, there's nothing to do.
 704                 STATE=2
 705                 save_state
 706                 return
 707         fi
 708 
 709         if [[ $(mach) = "i386" ]] ; then
 710                 isadir="intel"
 711                 b64srcdir="amd64"
 712                 b64tgtdir="amd64"
 713                 b32srcdir="ia32"
 714                 b32tgtdir="."
 715         else
 716                 isadir="sparc"
 717                 b64srcdir="v9"
 718                 b64tgtdir="sparcv9"
 719                 b32srcdir="v7"
 720                 b32tgtdir="."
 721         fi
 722 
 723         typeset foundkmdb=no
 724         typeset kmdbpath=
 725         typeset destdir=
 726 
 727         platdir=$INSTALL_FILES/platform/$KARCH/$GLOMNAME
 728         if [[ $GLOM = "yes" ]] ; then
 729                 machdir=$platdir
 730         else
 731                 machdir=$INSTALL_FILES/kernel
 732         fi
 733 
 734         srctrees=$SRC
 735         if [ -z "$ON_CRYPTO_BINS" ]; then
 736                 echo "Warning: ON_CRYPTO_BINS not set; pre-signed" \
 737                     "crypto not provided."
 738         fi
 739         if [[ $WANT64 = "yes" ]] ; then
 740                 # kmdbmod for sparc and x86 are built and installed
 741                 # in different places
 742                 if [[ $(mach) = "i386" ]] ; then
 743                         kmdbpath=$SRC/cmd/mdb/$isadir/$b64srcdir/kmdb/kmdbmod
 744                         destdir=$machdir/misc/$b64tgtdir
 745                 else
 746                         kmdbpath=$SRC/cmd/mdb/$KARCH/$b64srcdir/kmdb/kmdbmod
 747                         destdir=$platdir/misc/$b64tgtdir
 748                 fi
 749 
 750                 if kmdb_copy_kmdbmod $kmdbpath $destdir ; then
 751                         foundkmdb="yes"
 752 
 753                         for tree in $srctrees; do
 754                                 kmdb_copy_machkmods \
 755                                     $tree/cmd/mdb/$isadir/$b64srcdir \
 756                                     $machdir/kmdb/$b64tgtdir
 757                                 kmdb_copy_karchkmods $tree/cmd/mdb/$KARCH \
 758                                     $platdir/kmdb/$b64tgtdir $b64srcdir
 759                         done
 760                 fi
 761         fi
 762 
 763         if [[ $WANT32 = "yes" ]] ; then
 764                 kmdbpath=$SRC/cmd/mdb/$isadir/$b32srcdir/kmdb/kmdbmod
 765                 destdir=$machdir/misc/$b32tgtdir
 766 
 767                 if kmdb_copy_kmdbmod $kmdbpath $destdir ; then
 768                         foundkmdb="yes"
 769 
 770                         for tree in $srctrees; do
 771                                 kmdb_copy_machkmods \
 772                                     $tree/cmd/mdb/$isadir/$b32srcdir \
 773                                     $machdir/kmdb/$b32tgtdir
 774                                 kmdb_copy_karchkmods $tree/cmd/mdb/$KARCH \
 775                                     $platdir/kmdb/$b32tgtdir $b32srcdir
 776                         done
 777                 fi
 778         fi
 779 
 780         # A kmdb-less workspace isn't fatal, but it is potentially problematic,
 781         # as the changes made to uts may have altered something upon which kmdb
 782         # depends.  We will therefore remind the user that they haven't built it
 783         # yet.
 784         if [[ $foundkmdb != "yes" ]] ; then
 785                 echo "WARNING: kmdb isn't built, and won't be included"
 786         fi
 787 
 788         STATE=2
 789         save_state
 790         return
 791 }
 792 
 793 #
 794 # Make tarfile
 795 #
 796 
 797 function make_tarfile {
 798         echo "Creating tarfile $TARFILE"
 799         test -d $INSTALL_FILES || fail "Can't find $INSTALL_FILES"
 800         cd $INSTALL_FILES
 801         rm -f $TARFILE files
 802 
 803         # We don't want to change the permissions or ownership of pre-existing
 804         # directories on the target machine, so we're going to take care to
 805         # avoid including directories in the tarfile.  On extraction, tar won't
 806         # modify pre-existing directories, and will create non-existent ones as
 807         # the user doing the extraction.
 808         find . ! -type d -print |fgrep -vx './files' >files
 809         tar cf $TARFILE -I files || fail "Couldn't create tarfile $TARFILE"
 810         STATE=3
 811 }
 812 
 813 #
 814 # Routines to copy files to the target machine
 815 #
 816 
 817 function remote_fail {
 818         fail "" "$1" "" \
 819                 "Make sure that $TARGET_MACHINE is up." \
 820 "Check .rhosts in the home directory of user $TARGET_USER on $TARGET_MACHINE." \
 821                 "Check /etc/hosts.equiv, /etc/passwd, and /etc/shadow." \
 822                 "Change permissions on $TARGET_MACHINE as necessary." \
 823                 "Then, use \"$INSTALL -R\" to resume the install." ""
 824 }
 825 
 826 function remote_install {
 827         if [ "$IMODE" = "n" ]; then
 828                 STATE=4
 829                 return 0
 830         fi
 831         test -s $TARFILE || fail "$TARFILE missing or empty"
 832         verbose "Installing system on $TARGET"
 833         test -d $INSTALL_DIR || fail "Can't find $INSTALL_DIR"
 834         cd $INSTALL_DIR
 835         rm -f errors fatal nonfatal
 836         if [ "$IMODE" = "T" ]; then
 837                 EMESG="Can't rcp to $TARGET"
 838                 touch errors
 839                 sh -e${SHV}c "$INSTALL_RCP $TARFILE $TARGET/Install.tar"
 840         else
 841                 EMESG="Can't rsh to $TARGET_MACHINE"
 842                 rsh -l $TARGET_USER $TARGET_MACHINE \
 843                     "(cd $TARGET_DIR; /usr/bin/tar x${V}f -)" \
 844                     <$TARFILE 2>errors
 845         fi
 846         test $? -ne 0 && remote_fail "$EMESG"
 847         cd $INSTALL_DIR
 848         egrep "set time|warning|blocksize" errors >nonfatal
 849         egrep -v "set time|warning|blocksize" errors >fatal
 850         if [ -s fatal ]; then
 851                 echo "Fatal errors from rsh:"
 852                 cat fatal
 853                 remote_fail "Can't install on $TARGET_MACHINE"
 854         fi
 855         if [ -s nonfatal -a "$VERBOSE" != "q" ]; then
 856                 echo "Non-fatal errors from rsh:"
 857                 cat nonfatal
 858         fi
 859         rm -f fatal nonfatal errors
 860         test "$IMODE" = "T" && echo "Files can be extracted on \
 861 $TARGET_MACHINE using 'tar xvf $TARGET_DIR/Install.tar'"
 862         STATE=4
 863 }
 864 
 865 function okexit {
 866         cd /tmp
 867         test "$CLEANUP" = c && remove_dir $INSTALL_DIR
 868         save_state
 869         rm -rf $modstatedir
 870         rm -f $modlist
 871         [ -n "$cryptotree" ] && rm -rf "$cryptotree"
 872         verbose "Install complete"
 873         exit 0
 874 }
 875 
 876 #
 877 # Process options
 878 #
 879 
 880 RCOPTS=""
 881 LIBCREATE="no"
 882 LIBSRC=""
 883 ENV_PATH=$CODEMGR_WS
 884 OBJD="debug"
 885 KMDB="yes"
 886 
 887 test -s $INSTALL_RC && RCOPTS=`cat $INSTALL_RC`
 888 set $INSTALL $DEFAULT_OPTIONS $RCOPTS $*
 889 shift
 890 
 891 while getopts acd:D:G:hi:k:Kl:Lmno:pPqRs:t:T:uvVw:xX36 opt
 892 do
 893         case $opt in
 894             w)  ENV_PATH="$OPTARG"; SRC="$ENV_PATH/usr/src";;
 895             s)  UTS="$OPTARG";;
 896             k)  KARCH="$OPTARG";;
 897           t|T)  TARGET="$OPTARG"; IMODE=$opt; CLEANUP="c";;
 898             n)  TARGET=""; IMODE="n"; CLEANUP="p";;
 899             u)  files="unix genunix";;
 900             m)  files="Modules";;
 901             a)  files="All";;
 902         v|V|q)  VERBOSE=$opt;;
 903           c|p)  CLEANUP=$opt;;
 904             L)  LIBCREATE="yes"; CLEANUP="c";;
 905             l)  LIBSRC="$OPTARG";;
 906             D)  INSTALL_LIB="$OPTARG";;
 907             d)  INSTALL_DIR="$OPTARG/$TRAILER";;
 908             G)  GLOM=yes; GLOMNAME="$OPTARG";;
 909         P|X|x)  echo "-$opt is obsolete; ignored";;
 910             h)  usage "${INSTALL}: installs unix and modules";;
 911             R)  x=$OPTIND; restore_state; OPTIND=$x;;
 912             i)  IMPL="$OPTARG";;
 913             o)  OBJD="$OPTARG";;
 914             K)  KMDB="no";;
 915             3)  WANT64="no";;
 916             6)  WANT32="no";;
 917            \?)  usage "Illegal option";;
 918         esac
 919 done
 920 shift `expr $OPTIND - 1`
 921 
 922 ENV_NAME=`basename $ENV_PATH`
 923 
 924 #
 925 # The rest of the command line is a list of individual files to copy.
 926 # If non-null, this list overrides the -uma options.
 927 #
 928 
 929 if [[ $# -gt 0 ]] ; then
 930         files="$*"
 931         KMDB="no"
 932 fi
 933 
 934 case "$VERBOSE" in
 935         v)      V="v"; SHV="x";;
 936         V)      V="v"; SHV="x"; set -x;;
 937         q)      V=""; SHV="";;
 938 esac
 939 
 940 #
 941 # Create temp directory for Install's files
 942 #
 943 
 944 tstmkdir $INSTALL_DIR
 945 
 946 TARFILE=$INSTALL_DIR/Install.${KARCH}.tar
 947 INSTALL_FILES=$INSTALL_DIR/$KARCH
 948 
 949 #
 950 # Extract the target machine and target directory from a target of the
 951 # form [user@]machine:/dir .
 952 #
 953 
 954 if [ "$IMODE" != "n" ]; then
 955         eval `echo $TARGET | nawk -F':' '{ 
 956                 if (NF != 2 || !length($1) || !length($2))
 957                         print "usage \"Invalid target\""
 958                 m = $1; d = $2
 959                 if ($1 ~ /@/) {
 960                     k = split($1, f, "@");
 961                     if (k != 2 || !length(f[1]) || !length (f[2]))
 962                             print "usage \"Invalid target\""
 963                     u = f[1]; m = f[2]
 964                 }
 965                 print "TARGET_USER=" u ";"
 966                 print "TARGET_MACHINE=" m ";"
 967                 print "TARGET_DIR=" d ";"
 968         }'`
 969         if [ -z "$TARGET_USER" ]; then
 970                 TARGET_USER=$LOGNAME
 971         fi
 972 fi
 973 
 974 #
 975 # Allow the use of library source or target for the install
 976 #
 977 
 978 if [ -n "$LIBSRC" ]; then
 979         LIBSRC="`basename $LIBSRC .tar`.tar"
 980         TARFILE=$INSTALL_LIB/$LIBSRC
 981         test -s $TARFILE || fail "Can't find tarfile $TARFILE"
 982         verbose "Installing from library tarfile $TARFILE"
 983         STATE=3
 984 elif [ "$LIBCREATE" = "yes" ]; then
 985         tstmkdir $INSTALL_LIB
 986         TARFILE="$INSTALL_LIB/${ENV_NAME}.${KARCH}.tar"
 987 fi
 988 
 989 #
 990 # The next few lines allow recovery and activation with -R,
 991 # and library installs with -l.
 992 #
 993 
 994 [[ $STATE -eq 1 ]] && copy_kmdb
 995 [[ $STATE -eq 2 ]] && make_tarfile
 996 [[ $STATE -eq 3 ]] && remote_install
 997 [[ $STATE -eq 4 ]] && okexit
 998 
 999 save_state
1000 
1001 cd $DOT
1002 DOTDOT=`cd ..; pwd`
1003 
1004 #
1005 # Try to be smart: if DOTDOT ends in uts, then infer UTS and KARCH from DOT
1006 # Otherwise, if SRC is set, infer UTS = $SRC/uts.
1007 #
1008 
1009 if [ "`basename $DOTDOT`" = "uts" ]; then
1010         UTS=$DOTDOT
1011         KARCH=`basename $DOT`
1012         if [ ! -n "$SRC" ]; then
1013                 SRC=`dirname $DOTDOT`
1014                 verbose "Setting SRC to $SRC"
1015         fi
1016         export SRC
1017 fi
1018 
1019 if [ -z "$UTS" -a -n "$SRC" ]; then
1020         UTS="${SRC}/uts"
1021         test -n "$KARCH" || fail "no karch specified (e.g. -k sun4u)"
1022 fi
1023 
1024 if [ "$LIBCREATE" = "yes" ]; then
1025         TARFILE=$INSTALL_LIB/${ENV_NAME}.${KARCH}.tar
1026 else
1027         TARFILE=$INSTALL_DIR/Install.${KARCH}.tar
1028 fi
1029 INSTALL_FILES=$INSTALL_DIR/$KARCH
1030 save_state
1031 
1032 cd $DOT
1033 test -z "$UTS" && fail 'Cannot find kernel sources -- $SRC not set'
1034 test -d "$UTS" || fail "${UTS}: no such directory"
1035 
1036 #
1037 # Convert UTS into an absolute path.
1038 #
1039 
1040 cd $UTS
1041 UTS=`pwd`
1042 
1043 test "`basename $UTS`" = "uts" || \
1044         verbose "Warning: source path $UTS doesn't end in 'uts'"
1045 
1046 remove_dir $INSTALL_DIR/$KARCH
1047 rm -f $TARFILE
1048 
1049 copy_kernel     # sets STATE=1 if successful
1050 copy_kmdb       # sets STATE=2 if successful
1051 make_tarfile    # sets STATE=3 if successful
1052 remote_install  # sets STATE=4 if successful
1053 
1054 okexit