#   Copyright (c) 1986, 1987 AT&T
#   All Rights Reserved

#   THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
#   The copyright notice above does not evidence any
#   actual or intended publication of such source code.

#ident  "@(#)tapepkg    1.1.2.3"

# Script to install/remove multiple packages from SCSI tape.

#menu# install/remove packages from SCSI tape.
#help#
#help# Tapepkg will allow you to install or remove software packages from
#help# SCSI tape.  You will be asked to select the tape drive to be
#help# used and which packages you wish to install (remove) from the tape
#help# (the tape is first scanned to determine which packages are
#help# contained on it).
#help#
#help# After selecting the packages to be installed (removed), the packages
#help# are then read from the tape and installed (removed).
#help#
#help# Any packages requiring user interaction will require input at the
#help# time of installation.

PATH=$PATH:/usr/lbin
export PATH
set -u
export INSTTAPE
INSTTAPE=
TMPNODE=
EC=1                    # Default exit condition is ERROR
ALL=
REBOOT=0                # Default is not re-boot required.
P4NAME=
LOCK=/tmp/tapelock$$
FILE=/usr/tmp/INSTCMD$$ # file to hold installation/removal commands
                       # (list of files to be installed/removed)
trap 'cleanup' 0 1 2 3 15
> $FILE                 # Zero file
echo "                   \n\n\nColumbia MCC tape load procedure\n\n"

cleanup () {
   # /tmp/$$* catches $$INSTALL
   rm -f $FILE ${FILE}.ed $LOCK /tmp/$$* /usr/tmp/pkglist $TMPNODE ${TMPNODE}n 2>/dev/null
   exit $EC
}


display_1 () {
echo "\nFine. Please keep in mind that the following SMSCRC software packages"
echo "require operator intervention, even though you have requested that"
echo "default responses be used."
echo ""
echo "                       0015AA 10Base5 Network Interface"
echo "                       0015DA SNA/3270 Emulator"
echo "                       0015DA BSC/3270 Emulator"
echo ""
echo "If any of the above packages are contained on your load tape, they"
echo "will require you to provide hardware configuration information."
}
##  Check to see if setup has been run on the machine
if [ -s /etc/rc2.d/S00firstcheck ]
then
  echo "The procedure \"setup\" has not been run on this machine."
  echo "Please run this procedure to initialize the system date and time"
  echo "before attempting to load software.\n\n"
  echo "Procedure aborted.\n"
  exit 1
fi
## Determine how many Prelude packages have been loaded.
if [ -f /usr/options/pre-* ]
then
  PRE1=`ls /usr/options/pre-*|wc|cut -c1-7`
else
  PRE1=""
fi

if ls /tmp/tapelock* 2>/dev/null 1>&2
   then echo "\n\n\07
       NOTICE:  Only one person at a time may install/remove packages
                from SCSI tape.

                Someone else is using this command at this time-
                Try again later.\n\n"
       cleanup
   else /usr/bin/id > $LOCK            # Set up lock file
fi

# make sure that partition 4 can be referenced by "devnm / | sed s/s0/s4/"
root=`/etc/devnm / | sed 's/ .*//'`
case $root in
*d0s0)
       P4NAME=`echo $root | sed s/s0/s4/`
       break
       ;;
*mir000)
       /etc/scsi/mirror `echo $root | sed s/dsk/rdsk/` | \
               grep '^Disk' >/tmp/$$mirror

       P4NAME=`
       while read aline
       do
               set -- $aline

               if [ "$3" = ":" ]
               then
                       root=\`echo $4 | sed 's/rdsk/dsk/; s/d0s0/d0s4/'\`
               else
                       root=\`echo $5 | sed 's/rdsk/dsk/; s/d0s0/d0s4/'\`
               fi

               if [ ! -b $root -o \`expr $root : '.*d0s4$'\` -eq 0 ]
               then
                       continue
               fi

               if dd if=$root count=1 >/dev/null 2>/tmp/$$dd
               then
                       echo "1+0 records in\n1+0 records out" >/tmp/$$echo
                       if cmp -s /tmp/$$echo /tmp/$$dd
                       then
                               echo $root
                               break
                       fi

               fi
       done < /tmp/$$mirror`

       if [ -z "$P4NAME" ]
       then
               echo ERROR: $0 cannot locate partition 4 on the root device.
               cleanup
       fi

       break
       ;;
*)
       echo ERROR: $0 cannot determine the root device.  A \"devnm /\" should
       echo have responded with either /dev/dsk/c\?t\?d0s0 or /dev/dsk/mir000.
       cleanup
       ;;
esac

diskumount () {
#       perform a umount, complain if it doesn't work

   msg=`/etc/umount ${ddrive} 2>&1`
   case "${msg}" in
       '' ) echo "\n\n";;
       *' busy' )
           echo >&2 "
           The file system is \"busy\" which means that either some command
           is using files under it or someone is logged in and currently
           in a directory within the file system."
           cleanup
           ;;
       *' not mounted' ) ;;
       * ) admerr $0 "/etc/umount got '${msg}'"
           cleanup;;
   esac
}

tinstall () {
# Tape install/remove version of sysadm installpkg/removepkg
#
   trap 'EC=0; cleanup' 1 2 15
   maxtry=5

   ddrive=$P4NAME

   while true
   do
       if readpkg ${INSTTAPE:?}
               then :
               else echo "Package read FAILED."
               cleanup
       fi

       fulllabel=`disklabel -y $$ ${ddrive}`
       fsname=
       label=
       eval `labelfsname "${fulllabel}"`
       if [ "$label" = $1 ]
           then break  # Found it!
           else maxtry=`expr $maxtry - 1`
               echo "\nTape out of sync: Looking for $1, read $label"
               if [ "$maxtry" = 0 ]
                   then echo "Could not recover...\n\n"
                       rewind
                       cleanup
                   else echo "Trying to re-sync the tape..."
               fi
       fi
   done
   case "${fsname}" in
           instal | install )
               trap 'trap "" 1 2; cd /; diskumount; cleanup' 0
               /etc/umount ${ddrive} 2>/dev/null
               chmod 700 /install
               if /etc/mount ${ddrive} /install -r
                   then : # OK
                   else cleanup
               fi
               ;;
           * )
               echo >&2 '
   This removable medium is not labeled properly and will not work.'
               cleanup
               ;;
   esac

   trap 'trap "" 1 2; cd /; diskumount; cleanup' 0
   cd /tmp

   case $INSTRM in
   install) if [ ! -r /install/install/INSTALL ]
               then
               admerr $0 'Improperly built software removable medium.'
               diskumount
               cleanup
           fi
           if [  $DEFINS = default -a -s /install/install/DINSTALL ]
           then
              cp /install/install/DINSTALL $$INSTALL
           else
              cp /install/install/INSTALL $$INSTALL
           fi;;

   remove)  if [ ! -r /install/install/UNINSTALL ]
               then
               echo >&2 '      This package will not remove itself.
               Consult the instructions that came with the medium.'
               diskumount
               return   # On to next package in list...
           fi
           cp /install/install/UNINSTALL $$INSTALL;;

   *)          echo "ERROR in tinstall/INSTRM case."
               cleanup
               ;;
   esac

   chmod +x $$INSTALL

   trap '' 1 2         # Block interrupts
   if [ "$INSTRM" = install -a -r /etc/coredirs -a  ! -f $$installpkg ]
   then
       #       A problem in cpio makes it change the modes and
       #       ownership of directories it did not create.  This trick
       #       records and later restores the existing values.  The
       #       directories to be protected are listed in /etc/coredirs.
       cpio -o </etc/coredirs >$$installpkg 2>/dev/null
   fi
   /tmp/$$INSTALL ${ddrive} /install  || echo \
       'WARNING: Installation/removal may not have completed properly.'
   if [ "$INSTRM" = install -a -f $$installpkg ]
   then
       #       Restore the directory modes and ownerships.
       cpio -id <$$installpkg >/dev/null 2>&1
   fi
   rm -f $$INSTALL
   diskumount
   trap 'cleanup' 0 1 2
}

rewind () {
# Shell to rewind tape
# removes the "n" at the end of the device name
# If tape is at BOT, reads until first FILE Mark, then rewinds.

   if=`echo ${INSTTAPE:?}  | sed 's/n$//'`

   dd if=$if of=/dev/null bs=1 count=1 2>/dev/null     # initiate rewind
   dd if=$if of=/dev/null bs=1 count=1 2>/dev/null     # wait for rewind to complete
}

case `askx -q " Do you wish to install or remove packages?\n" \
       -c "install remove quit i r q"` in
       install|i)      INSTRM=install;;
       remove|r)       INSTRM=remove;;
       quit|q)         EC=0; cleanup;;
esac
DEFINS=nodefault
if [ $INSTRM = "install" ]
then
  case `askx -q " Do you wish to use default responses for the software packages?\n" \
       -c "yes no quit y n q"` in
       yes|y)  DEFINS=default;;
       no|n)   DEFINS=nodefault;;
       quit|q) EC=0; cleanup;;
  esac
fi
export DEFINS

if [  $DEFINS = default ]
then
  display_1
fi

echo "\n"
INSTTAPE=`selectdevice -q \
"Select the tape drive to use:" -c $$ /dev/rSA qtape`

echo "\07
Insert the removable medium for the package(s) you want to $INSTRM
into the `basename $INSTTAPE` drive.
Press <RETURN> when ready.  Type  q  to quit. \c"
read a
echo
if [ "$a" = q ]
   then EC=0; cleanup
fi

# Take the sysadm name and transform it into the /dev/rmt
# name with the no-rewind option
inode=`ls -i $INSTTAPE | cut -c1-6`
newname=`ls -i /dev/rmt | grep "$inode" 2>/dev/null | cut -c7-`
if [ -z "$newname" ]
   then echo "ERROR: cannot determine /dev/rmt name from SA name."
   cleanup
fi
# is87-23107 & is87-21901
# Make tape software operate with any tape device
TMPNODE=/tmp/${newname}
ls -og /dev/rmt/${newname}n | \
       (
       IFS=",$IFS"
       read perm links major minor otherstuff
       /etc/mknod $TMPNODE c $major 0
       /etc/mknod ${TMPNODE}n c $major 1
       )
INSTTAPE=${TMPNODE}n
#

# Remove package list and try to read it from the tape...
rm -f /usr/tmp/pkglist 2>/dev/null
cd /usr/tmp; cpio -ic \*pkglist < $INSTTAPE >/dev/null 2>&1
if [ $? = 1 ]
then echo "\n\n\
       The medium may not be properly inserted.
       Re-insert the medium and try again.\n\n"
       cleanup
fi
if [ ! -f /usr/tmp/pkglist ]
   then # read of pkglist from tape failed...  rewind and try again.
   rewind
   dd if=$INSTTAPE of=/dev/null bs=9k 2>/dev/null      # Skip file
   dd if=$INSTTAPE of=/dev/null bs=9k 2>/dev/null      # Skip file
   cpio -ic \*pkglist < $INSTTAPE >/dev/null 2>&1
   if [ ! -f /usr/tmp/pkglist ]
       then echo "\07\nRead of tape package header FAILED.\n"; cleanup
   fi
fi

NPKGS=`cat /usr/tmp/pkglist | wc -l`
> $FILE
for pkg in `cat /usr/tmp/pkglist`
do
   echo $pkg | sed 's/=/ /g' |
   sed 's/.*%\(.*\)%\(.*\)%\(.*\)%.*$/skip \1  # \2 # RB=\3/' >> $FILE
done

while true
do
   INVALID=false
   > ${FILE}.ed
   echo "\n\nPackages available:\n"
   cat /usr/tmp/pkglist | sed 's/%.*$//' | pr -2tn5w80 | sed 's/=/ /g'

   echo "\n\07Enter selection(s) to $INSTRM [all help quit]: \c"
   read a
   if [ ! "$a" ]
       then echo >&2 "\n\07You must enter something."
       a=help
   fi
   for i in $a
   do
       case $i in
           [1-9] | [0-9][0-9])
                   # Normal number
                   if [ "$i" -gt "$NPKGS" ]
                       then echo >&2 "\n\07Choice ($i) out of range."
                       INVALID=true; break
                   fi
                   echo "${i}s/skip[^#]*#/tinstall/" >> ${FILE}.ed
                   ;;

           [1-9]-[1-9] |\
           [1-9]-[0-9][0-9] |\
           [0-9][0-9]-[0-9][0-9])
                   # Range
                   eval `echo $i | sed 's/\(.*\)-\(.*\)$/start=\1 end=\2/'`
                   if [ "$start" -gt "$end" ]
                       then echo >&2 "\n\07Invalid range: $i"
                       INVALID=true; break
                   fi
                   if [ "$end" -gt "$NPKGS" ]
                       then echo >&2 "\n\07Invalid range: $i"
                       INVALID=true; break
                   fi
                   j=$start
                   while [ "$j" -le "$end" ]
                   do
                       echo "${j}s/skip[^#]*#/tinstall/" >> ${FILE}.ed
                       j=`expr $j + 1`
                   done
                   ;;

           all|ALL)    # all choices
                   j=1
                   while [ "$j" -le "$NPKGS" ]
                   do
                       echo "${j}s/skip[^#]*#/tinstall/" >> ${FILE}.ed
                       j=`expr $j + 1`
                   done
                   ;;

           q|quit|Q|QUIT)
                   echo "\n\n\07QUIT- Nothing ${INSTRM}ed.\n"
                   EC=0; cleanup
                   ;;
           h|help|H|HELP|?)
                   echo "\n\n\
Enter the number(s) of the packages you wish to install/remove.
You may enter:
       o numbers seperated by spaces (eg. 1 4 10)
       o ranges of numbers (eg. 4-9)
       o combinations of numbers and ranges (eg. 1 3 10-15)
       o all - $INSTRM all packages
       o quit - do not $INSTRM anything

Enter <CR> to continue: \c"
                   read a
                   INVALID=true; break
                   ;;

           *)  echo >&2 "\n\07Invalid input: $i"
                   INVALID=true; break
                   ;;
       esac
   done
   if [ "$INVALID" = false ]
       then break
   fi
done
echo "\$a\nskip rope\n.\n\$\n?^tinstall?ka\n'a,\$s/^skip/delete/\ng/^delete/d\nw\nq" >> ${FILE}.ed
cat ${FILE}.ed | ed - $FILE >/dev/null 2>&1

echo "rewind" >> $FILE  # Rewind tape when done installing/removing

echo "\n\nSelection complete--- ${INSTRM}pkg starting.\n\n"

# Execute the file containing commands for installation/removal...
$FILE

if grep "tinstall.*RB=2" $FILE > /dev/null 2>&1
   then REBOOT=2
   elif grep "tinstall.*RB=1" $FILE > /dev/null 2>&1
       then REBOOT=1
       else REBOOT=0
fi

case $REBOOT in
0)      #No re-boot necessary
       ;;
1)      #init 6 required
       echo "\n\nExecute \"cd /; shutdown -i6 -g0 -y\" and"
       echo "wait for the \"Console Login:\" prompt."
       ;;
2)      #init 0 required on removepkg, init 6 on installpkg
       if [ "$INSTRM" = install ]
       then
           echo "\n\nExecute \"cd /; shutdown -i6 -g0 -y\" and"
           echo "wait for the \"Console Login:\" prompt."
       else
           echo "You have requested the removal of a package that"
           echo "contains a hardware device.  If the removal of the"
           echo "software has completed successfully, you now need"
           echo "to remove associated the hardware."
           echo "\n\nExecute \"cd /; shutdown -i0 -g0 -y\" and"
           echo "wait for the machine to power down- then remove the"
           echo "hardware."
       fi
       ;;
*)      echo "An error has occured within the $0 command."
       cleanup
       ;;
esac
## Determine how many Prelude packages have been loaded during this session
##
if [ -f /usr/options/pre-* ]
then
  PRE2=`ls /usr/options/pre-*|wc|cut -c1-7` > /dev/null 2>&1
else
  PRE2=""
fi
##
## Execute pradmin to rebuild the Prelude menus if Prelude packages have been
## loaded during this session
if [  $DEFINS = default -a "$PRE1" != "$PRE2" ]
then
echo "\nRebuilding Prelude menu for newly installed Prelude software."
/usr/bin/pradmin <<-EOFX >/dev/null 2>&1
in
q
EOFX
fi

echo "\07\n\nThe ${INSTRM}pkg from SCSI tape has completed-\
\nYou may remove the tape after the rewind is complete.\n\n"

EC=0; cleanup