#!/usr/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is not an automatically generated prolog. 
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2005 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 

Version="1.1"

PATH="/usr/bin:/etc:/usr/sbin:/sbin"
export PATH=$PATH

USAGE="usage: chjava -b <path_to_package> -p <java_path_suffix> [-l <LPP_name_suffix>] [-q] 
ex: chjava -b /tmp/images/Java131.rte.bin -p A -l _A  
    This will create a package with an LPP name of Java131_A.rte.bin that installs to /usr/java131A .
ex: chjava -b \"/tmp/images/Java13*\" -p A   
ex: chjava -b \"Java131.rte.bin Java14.sdk\" -p A   

usage: chjava -b <path_to_package> -P <path_to_replace_usr> [-p <java_path_suffix>] -l <LPP_name_suffix>) [-q] 
ex: chjava -b /tmp/images/Java131.rte.bin -P /alt/previous -p alt -l _A  
    This will create a package with an LPP name of Java131_A.rte.bin that 
    installs to /alt/previous/java131alt . 

-b : Specifies the path to the install or update packages to alter. 
-l : Specifies the suffix to add to the original LPP name when creating the 
     new package.
-p : Specifies the suffix to add to the original /usr/java<version> install path 
     when creating the new package. 
     Also specifies the suffix to add to the original LPP name if the -l flag
     isn't specified.
-P : Specifies the path to replace /usr with in the install image for 
     files /usr/java* .  
     We highly recommend not using this flag for security issues, 
     installp spacing expansion issues, and file tracking issues. 
-q : Specifies to suppress informational messages and to only print the summary. \n"




P_FLAG_WARNING="
_______________________________________________________________________________
We highly recommend against using the P flag due to the following issues: 
1) Replacing /usr/java* with <other directory structure>/java* can open your 
system up to security exposures since the java install image does not own 
the /usr directory and therefore does not set the permissions correctly for 
the replacement directory. 
The replacement directory structure could also not work correctly if the 
permissions are too restrictive.
2) Installp auto expansion of filesystem size may not work correctly due to 
switching some files out of the /usr directory.
3) The created directory that replaces /usr will not be removed if the
fileset is uninstalled.

Directory structure replacing /usr should have the same permissions and 
ownership as /usr.  Also there should be sufficient space available in 
/usr and the replacement directory to install the fileset.
_______________________________________________________________________________\n\n"



TRUE=0
FALSE=1
OWD=`pwd`


# Default settings
quiet=$FALSE
breakAfterReplace=$FALSE
packageList=""
pathToPackage=""
oldLppName=""
newLppName=""
pathNameArg=""
oldPath=""
newPath=""
workdir="./"
tempOsummary=""
tempNsummary=""
Osummary=""
Nsummary=""
packageType="update"
licenseFileset=$FALSE
msgFileset=$FALSE
javaFileset=$FALSE
pathUsrArg=""
rc=0



######################################
# Functions
######################################


function _print
   {
   if [[ $quiet = $FALSE ]] then
      print "$*"
   fi
   }
   
# 
# add by RWL
#
function _cleanupPackage
{

  _print "chjava: interupted by cltr-c, cleaning up : ${_workdir}${_package}_temp"
  cd ${OLDPWD}
  rm -rf ${_workdir}${_package}_temp

  exit 1
}



function _breakdownPackage
   {
   typeset _pathToPackage=$1
   
   typeset _package=${_pathToPackage##*/}
   typeset _workdir=`pwd`"/"
   
   # Restore package
   trap "_cleanupPackage ${_workdir}${_package}_temp" 2		# added by RWL
   _print "chjava: Breaking down package named:${_package} in directory ${_workdir}${_package}_temp ."
   _print "\n"
   
   rm -rf ${_package}_temp > /dev/null 2>&1
   mkdir ${_package}_temp   
   cd ${_package}_temp
   
   output=`restore -xvqf ../${_package} 2>&1`
   _rc=$?
   _print "$output"
   _print "\n"
   
   if [[ $_rc != 0 ]] then
      print "chjava: restore of package failed."
      exit 1
   fi
   
   # ar the liblpp.a files
   _print "chjava: - Breaking down the liblpp.a files into seperate packaging files."
   
   liblpps=`find . -name liblpp.a`   
   
   for liblpp in $liblpps
      do
      liblpp=${liblpp#./}
      _dir=${liblpp%liblpp.a}

      _print "chjava: - Breaking down ${_workdir}${_package}_temp/${liblpp} into ${_workdir}${_package}_temp/${_dir}temp"

      cd $_dir
      mkdir temp
      cd temp

      output=`ar -xv ../liblpp.a`
      _rc=$?
      _print "$output"
      _print "\n"
   
      if [[ $_rc != 0 ]] then
         print "chjava: ar of ${_workdir}${_package}_temp/${liblpp} failed."
         exit 1
      fi
      
      cd ${_workdir}${_package}_temp
      done

   cd ${_workdir}
   _print "chjava: Breaking down of package was successful.\n\n"
   }





function _modifyFilename
   {
   typeset _file=$1
   typeset _oldName=$2
   typeset _newName=$3

   typeset dir=${_file%/*}"/"
   typeset newfile=${_file##*/}
   newfile=` echo "${newfile}" | sed "s:$_oldName:$_newName:g" `
   if [[ ${_file} = ${dir}${newfile} ]] then
      return
   fi
   _print "mv ${_file} ${dir}${newfile}"
   output=`mv ${_file} ${dir}${newfile} 2>&1`
   _rc=$?
   if [[ $_rc != 0 ]] then
      print "chjava: Modifying filename failed."
      exit 1
   fi
   _print "$output"
   }




function _modifyFile
   {
   typeset _file=$1
   typeset _oldContent=$2
   typeset _newContent=$3

   _print "sed \"s:$_oldContent:$_newContent:g\" ${_file} > ${_file}.new ; mv -f ${_file}.new ${_file}"
   output=`sed "s:$_oldContent:$_newContent:g" ${_file} > ${_file}.new ; mv -f ${_file}.new ${_file}`
   _rc=$?
   if [[ $_rc != 0 ]] then
      print "chjava: Modifying file failed."
      exit 1
   fi
   _print "$output"
   }


function _modifyFileExceptLAR
   {
   typeset _file=$1
   typeset _oldContent=$2
   typeset _newContent=$3

#   _print "sed \"s:$_oldContent:$_newContent:g\" ${_file} > ${_file}.new ; mv ${_file}.new ${_file}"
#   output=`sed "s:$_oldContent:$_newContent:g" ${_file} > ${_file}.new ; mv ${_file}.new ${_file}`

   _print "awk '\$0 !~ /^LAR/ {gsub(\"${_oldContent}\",\"${_newContent}\", \$0); }; {print}' ${_file} > ${_file}.new ; mv -f ${_file}.new ${_file}"
   output=`awk '\$0 !~ /^LAR/ {gsub("'${_oldContent}'","'${_newContent}'", \$0); }; {print}' ${_file} > ${_file}.new ; mv -f ${_file}.new ${_file}`
   _rc=$?
   if [[ $_rc != 0 ]] then
      print "chjava: Modifying file failed."
      exit 1
   fi
   _print "$output"
   }




function _depth
   {
   typeset _path=$1
   
   _Depth=0 
   _path=${_path#/}
   _path=${_path%/}
   typeset _dir=""
   OIFS=$IFS
   IFS="/"
   for _dir in $_path
      do
      (( _Depth = _Depth + 1 ))
      done 
   IFS=$OIFS
   return $_Depth
   }




function _modifyPackage
   {
   typeset _pathToPackage=$1
   typeset _lppNameArg=$2
   typeset _packageType=$3
   typeset _pathNameArg=$4
   typeset _pathUsrArg=$5

   typeset _package=${_pathToPackage##*/}
   typeset _workdir=`pwd`"/"
   
   # Modify package
   tempOsummary="${tempOsummary}Original package: ${_package} \n"
   _print "chjava: Modifying package named:${_package} in directory ${_workdir}${_package}_temp ."
   _print "\n"

   # Create old and new LPP names and path names
   filenames="${_workdir}${_package}_temp/usr/lpp/Java*"
   files=`find $filenames -prune`
   for file in $files
      do
      typeset _oldLppName=${file##*/}
      _oldLppName=${_oldLppName%%.*}
      break
      done
   typeset _newLppName=${_oldLppName}${_lppNameArg}

   filenames="${_workdir}${_package}_temp/usr/java*"
   files=`find $filenames -prune`
   for file in $files
      do
      typeset _oldPath="/usr/"${file##*/}
      break
      done
   typeset _newPath=${_oldPath}${_pathNameArg}
   if [[ $_pathUsrArg != "" ]] then
      _newPath=`echo "$_newPath" | sed "s:/usr/:$_pathUsrArg:g" `
   fi
   tempOsummary="${tempOsummary}Original path: ${_oldPath} \n"
   tempNsummary="${tempNsummary}New      path: ${_newPath} \n"
   _newPath=""	# Reset so to not use this value from here as set

   # Modify fileset name directories
   if [[ $_packageType = "update" ]] then
      filenames="${_workdir}${_package}_temp/usr/lpp/*${_oldLppName}*"
      files=`find $filenames -prune`
      for file in $files
         do
         _modifyFilename $file ${_oldLppName} ${_newLppName}
         done
   fi

   if [[ $_packageType = "install" ]] then
      filenames="${_workdir}${_package}_temp/usr/lpp/*${_oldLppName}*"
   else
      filenames="${_workdir}${_package}_temp/usr/lpp/*/*${_oldLppName}*"
   fi
   files=`find $filenames -prune`
   for file in $files
      do
      _modifyFilename $file ${_oldLppName} ${_newLppName}
      done

   # Modify packaging file names
   if [[ $_packageType = "install" ]] then
      filenames="${_workdir}${_package}_temp/usr/lpp/*/temp/*${_oldLppName}*"
   else
      filenames="${_workdir}${_package}_temp/usr/lpp/*/*/*/temp/*${_oldLppName}*"
   fi
   files=`find $filenames -prune`
   for file in $files
      do
      _modifyFilename $file ${_oldLppName} ${_newLppName}
      done

   # Get previous fileset names from lpp_name
   typeset _num=0
   typeset filesets=`awk '/^Java/ {print $1}' ${_workdir}${_package}_temp/lpp_name`  
   for file in $filesets
      do
      (( _num = _num + 1 ))
      tempOsummary="${tempOsummary}Original fileset${_num}: ${file##*/} \n"
      done

   # Modify content of .inventory files, productid, and size files lpp_name from _oldLppName to _newLppName
   if [[ $_packageType = "install" ]] then
      filenames="${_workdir}${_package}_temp/usr/lpp/*/temp/productid"
   else
      filenames="${_workdir}${_package}_temp/usr/lpp/*/*/*/temp/productid"
   fi
   files=`find $filenames `
   for file in $files
      do
      _modifyFile $file ${_oldLppName} ${_newLppName}
      done

   if [[ $_packageType = "install" ]] then
      filenames="${_workdir}${_package}_temp/usr/lpp/*/temp/*.inventory"
   else
      filenames="${_workdir}${_package}_temp/usr/lpp/*/*/*/temp/*.inventory"
   fi
   files=`find $filenames `
   for file in $files
      do
      _modifyFile $file ${_oldLppName} ${_newLppName}
      done

   if [[ $_packageType = "install" ]] then
      filenames="${_workdir}${_package}_temp/usr/lpp/*/temp/*.size"
   else
      filenames="${_workdir}${_package}_temp/usr/lpp/*/*/*/temp/*.size"
   fi
   files=`find $filenames `
   for file in $files
      do
      _modifyFile $file ${_oldLppName} ${_newLppName}
      done

   filenames="${_workdir}${_package}_temp/lpp_name"
   files=`find $filenames `
   for file in $files
      do
      _modifyFileExceptLAR $file ${_oldLppName} ${_newLppName}
      done

   # Get new fileset names from lpp_name
   typeset _num=0
   typeset filesets=`awk '/^Java/ {print $1}' ${_workdir}${_package}_temp/lpp_name`  
   for file in $filesets
      do
      (( _num = _num + 1 ))
      tempNsummary="${tempNsummary}New      fileset${_num}: ${file##*/} \n"
      done
   

   #
   # Modify files for path suffix if specified
   if [[ $_pathNameArg != "" ]] then
   
      _newPath=${_oldPath}${_pathNameArg}
      # Modify content of packaging files from _oldPath to _newPath 
      if [[ $_packageType = "install" ]] then
         filenames="${_workdir}${_package}_temp/usr/lpp/*/temp/*"
      else
         filenames="${_workdir}${_package}_temp/usr/lpp/*/*/*/temp/*"
      fi
      files=`find $filenames `
      for file in $files
         do
         _modifyFile $file ${_oldPath} ${_newPath}
         done
      filenames="${_workdir}${_package}_temp/lpp_name"
      files=`find $filenames `
      for file in $files
         do
         _modifyFile $file ${_oldPath} ${_newPath}
         done

      # Modify directory names from _oldPath to _newPath
      file="${_workdir}${_package}_temp${_oldPath}"
      typeset old=${_oldPath##*/}
      typeset new=${_newPath##*/}
      _modifyFilename $file ${old} ${new}

   fi # end modify for path suffix


   #
   # Modify /usr directory to another directory if specified
   if [[ $_pathUsrArg != "" ]] then

      # Create replacement directory (Rdir) in packaging structure
      _print "mkdir -p ${_workdir}${_package}_temp${_pathUsrArg}"
      output=`mkdir -p ${_workdir}${_package}_temp${_pathUsrArg} 2>&1`
      _rc=$?
      if [[ $_rc != 0 ]] then
         print "chjava: Creating directory failed."
         exit 1
      fi
      _print "$output"
      
      # Move /usr/java* files to Rdir
      filenames="${_workdir}${_package}_temp/usr/java*"
      files=`find $filenames -prune`
      for file in $files
         do
         _print "mv ${file} ${_workdir}${_package}_temp${_pathUsrArg}"
         output=`mv ${file} ${_workdir}${_package}_temp${_pathUsrArg} 2>&1`
         _rc=$?
         if [[ $_rc != 0 ]] then
            print "chjava: Moving usr/java* to ${_pathUsrArg} failed."
            exit 1
         fi
         _print "$output"
         done

      # Modify content of packaging files from /usr/java* to Rdir
      if [[ $_packageType = "install" ]] then
         filenames="${_workdir}${_package}_temp/usr/lpp/*/temp/*"
      else
         filenames="${_workdir}${_package}_temp/usr/lpp/*/*/*/temp/*"
      fi
      files=`find $filenames `
      for file in $files
         do
         _modifyFile $file "/usr/java" "${_pathUsrArg}java"
         done
      filenames="${_workdir}${_package}_temp/lpp_name"
      files=`find $filenames `
      for file in $files
         do
         _modifyFile $file "/usr/java" "${_pathUsrArg}java"
         done
   fi # end modify /usr

   _print "\n"
   }
   
   
   
   
function _rebuildPackage
   {
   typeset _pathToPackage=$1
   typeset _packageType=$2
   typeset _lppNameArg=$3
   
   typeset _package=${_pathToPackage##*/}
   typeset _workdir=`pwd`"/"
   
   #  package
   _print "chjava: Rebuilding package from directory ${_workdir}${_package}_temp ."
   _print "\n"
   
   if [[ $_packageType = "install" ]] then
      filenames="${_workdir}${_package}_temp/usr/lpp/*/temp"
   else
      filenames="${_workdir}${_package}_temp/usr/lpp/*/*/*/temp"
   fi
   files=`find $filenames -prune`

   _print "chjava: - rebuilding liblpp.a files."
   for file in $files
      do
      cd $file
      
      _print 'rm -f ../liblpp.a'
      output=`rm -f ../liblpp.a`
      _rc=$?
      _print "$output"
      _print "\n"
   
      if [[ $_rc != 0 ]] then
         print "chjava: rm of ${file}/../liblpp.a failed."
         exit 1
      fi

      _print 'ar -vq ../liblpp.a *'
      output=`ar -vq ../liblpp.a * 2>&1`
      _rc=$?
      _print "$output"
      _print "\n"
   
      if [[ $_rc != 0 ]] then
         print "chjava: ar of ${file}/../liblpp.a failed."
         exit 1
      fi

      cd ../
      rm -rf temp
      done

   typeset preDot=${_package%%\.*}
   typeset postDot=${_package#*\.}   
   if (( ${#preDot} == ${#package} )) then 
      # No dot found in package name
      typeset bff=${_package}${_lppNameArg}
   else
      typeset bff=${preDot}${_lppNameArg}"."${postDot}
   fi
 
   _print "chjava: - building package "
   cd ${_workdir}${_package}_temp
   _print "find . -print | backup -ivqpf ../$bff"
   output=`find . -print | backup -ivqpf ../$bff`
   _rc=$?
   _print "$output"
   _print "\n"
   if [[ $_rc != 0 ]] then
      print "chjava: backup failed."
      exit 1
   fi
   tempNsummary="New      package: ${bff} \n${tempNsummary}"
   
   cd ${_workdir}
   output=`rm -rf ${_workdir}${_package}_temp`
   trap "" 2			# added by RWL
   }
   
   
   
   


######################################
# Main
######################################


#
# Examine passed in args
#
validCommand=$FALSE
bflag=$FALSE
lflag=$FALSE
pflag=$FALSE
Pflag=$FALSE

while getopts :qBvb:l:p:P: arguments
   do
   case $arguments in 
      q)  quiet=$TRUE;;
      B)  breakAfterReplace=$TRUE;;
      b)  packageList=$OPTARG
          bflag=$TRUE;;
      l)  lppNameArg=$OPTARG
          lflag=$TRUE;;
      p)  pathNameArg=$OPTARG
          pflag=$TRUE;;
      P)  pathUsrArg=$OPTARG
          Pflag=$TRUE;;
      v)  print "Version $Version"
	  exit 0;;
      :)  print "$USAGE"
	  exit 99;;
      \?) print "$USAGE"
	  exit 99;;
   esac
   done
(( switchPositions = OPTIND - 1 ))
shift $switchPositions

# Use p flag value as l flag value if not specified
if [[ $lflag = $FALSE ]] && [[ $pflag = $TRUE ]] then
   lppNameArg=$pathNameArg
   lflag=$TRUE
fi

if [[ $bflag = $TRUE ]] && [[ $pflag = $TRUE ]] then
   validCommand=$TRUE
fi

if [[ $bflag = $TRUE ]] && [[ $Pflag = $TRUE ]] && [[ $lflag = $TRUE ]] then
   validCommand=$TRUE
fi

if [[ $validCommand = $FALSE ]] then
   print "$USAGE"
   exit 99
fi

if [[ $lppNameArg = */* ]] || [[ $pathNameArg = */* ]] then 
   print "chjava: Suffix arguments cannot contain the \"/\" character. \n"
   exit 1
fi

# Add a slash at beginning and end if not there
if [[ $Pflag = $TRUE ]] then
   if [[ $pathUsrArg != /* ]] then
      pathUsrArg="/${pathUsrArg}"
   fi
   if [[ $pathUsrArg != */ ]] then
      pathUsrArg="${pathUsrArg}/"
   fi

   if [[ $pathUsrArg = "/usr/" ]] then
      print "$USAGE"
      exit 99
   fi
fi


packages=`ls ${packageList}`
if [[ $packages = "" ]] then
   print "chjava: package ${packageList} could not be accessed. \n"
   exit 1
fi   

for pathToPackage in `ls ${packageList}`
   do
   packageType="update"
   licenseFileset=$FALSE
   msgFileset=$FALSE
   javaFileset=$FALSE
   tempOsummary=""
   tempNsummary=""
   
   # Check for package existance and type
   if [[ ! -f $pathToPackage ]] then
      print "chjava: package ${pathToPackage} could not be accessed or is not a regular file. \n"
      exit 1
   fi
   output=`file ${pathToPackage} | grep 'backup/restore' > /dev/null`
   _rc=$?
   if [[ $_rc != 0 ]] then
      print "chjava:package ${pathToPackage} is not a backup/restore file type. \n"
      exit 1
   fi

   if [[ $pathToPackage != "" ]] then
      workdir="${pathToPackage%/*}/"
   fi
   
   if [[ "${pathToPackage}/" = $workdir ]] then
      workdir="./"
   fi
   
   # Check package
   cd $workdir
   workdir=`pwd`"/"
   package=${pathToPackage##*/}
   if [[ -d $pathToPackage ]] then
      print "chjava: package passed in with b flag must be a file."
      exit 1
   fi
   pathToPackage=${workdir}${package}
   
   
   #
   # Break down package
   #
   _breakdownPackage $pathToPackage 
   
   
   # Find type of package install or update
   # and whether this is a license or msg fileset
   while read -r line
      do
      num=0
      for part in $line
         do
         (( num = num + 1 ))
         if (( num == 3 )) then
            if [[ $part = "I" ]] then
               packageType="install"
	    fi
   	 fi
         if (( num == 4 )) then
            if [[ $part = *license* ]] then
               licenseFileset=$TRUE
	       javaFileset=$TRUE
	    fi
            if [[ $part = *msg* ]] then
               msgFileset=$TRUE
	       javaFileset=$TRUE
	    fi
            break 2
   	 fi
         done
      done < ${workdir}${package}_temp/lpp_name
   _print "chjava: package passed in is an ${packageType} type package."

   output=`find ${workdir}${package}_temp/usr/java* >/dev/null 2>&1`
   _rc=$?
   if [[ $_rc = 0 ]] then
      javaFileset=$TRUE
   fi
   
   if [[ $licenseFileset = $TRUE ]] || [[ $msgFileset = $TRUE ]] || [[ $javaFileset = $FALSE ]] then
      output=`rm -rf ${workdir}${package}_temp`
      tempOsummary="Original package: ${package} \n"
      if [[ $licenseFileset = $TRUE ]] then
         tempNsummary="New      package: UNCHANGED license fileset.\n"
      fi
      if [[ $msgFileset = $TRUE ]] then
         tempNsummary="New      package: UNCHANGED message fileset.\n"
      fi
      if [[ $javaFileset = $FALSE ]] then
         tempNsummary="New      package: UNCHANGED non-java fileset.\n"
      fi
   else
      _modifyPackage $pathToPackage $lppNameArg $packageType "$pathNameArg" "$pathUsrArg"
      if [[ $breakAfterReplace = $TRUE ]] then
         exit $rc
      fi   
   
      #
      # Rebuild package
      #
      _rebuildPackage $pathToPackage $packageType $lppNameArg
   fi

Osummary="${Osummary}${tempOsummary}"
Osummary="${Osummary}__________________________________________________\n"
Nsummary="${Nsummary}${tempNsummary}"
Nsummary="${Nsummary}\n"
done

if [[ $rc = "0" ]] then
   if [[ $Pflag = $TRUE ]] then
      print "$P_FLAG_WARNING"
   fi
   
   print "chjava: Summary:"
   o_text=$Osummary
   n_text=$Nsummary
   while [[ ${#o_text} > 0 ]]
      do
      text="${o_text%%\\n*}"
      print "$text"
      o_text=${o_text#*\\n}
      
      text="${n_text%%\\n*}"
      print "$text"
      n_text=${n_text#*\\n}
      done
   print "\n\n"
   print "chjava: Success"
else
   print "chjava: Failed"
fi
return $rc

cd $OWD > /dev/null


