#!/usr/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos71S src/bos/usr/sbin/rpm_share/rpm_share.sh 1.5.2.1 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2005,2014 
# 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 

# @(#)64      1.5.2.1  src/bos/usr/sbin/rpm_share/rpm_share.sh, cmdcorral, bos71S, s2014_32A5 7/30/14 18:27:45

check_space()
{
   typeset ERROR='eval perror 87; return 1'
   typeset SNODE       # source node
   typeset TNODE       # target node
   typeset FLIST="$1"  # file install list
   typeset DLIST="$2"  # dir install list
   typeset RC=0
   typeset SUM=0
   typeset SIZE=0
   typeset MINSIZE=16

   [[ -z $FLIST || -z $DLIST ]] && $ERROR
   check_file $FLIST || $ERROR
   check_file $DLIST || $ERROR

   # Do the files.
   while read SNODE; do

      TNODE=${RPM_INST_ROOT}${SNODE}

      if [[ -L $SNODE && ! -L $TNODE ]]; then
         (( SUM = $SUM + $MINSIZE ))
         continue
      fi

      # If the target node exists AND is closed, subtract its space.
      if [[ -f $TNODE ]]; then
         isfopen $TNODE
         if [[ $? -eq 0 ]]; then
            SIZE=$(getfsize "$TNODE") || $ERROR
            (( SUM = $SUM - $SIZE ))
         fi
      fi

      SIZE=$(getfsize "$SNODE") || $ERROR
      (( SUM = $SUM + $SIZE ))

   done < $FLIST

   # Do the dirs
   while read SNODE; do
      TNODE=${RPM_INST_ROOT}${SNODE}
      [[ -d $SNODE && ! -d $TNODE ]] && (( SUM = $SUM + $MINSIZE ))
   done < $DLIST

   # Finalize the SUM, add a small buffer
   [[ $SUM -le 0 ]] && SUM=$MINSIZE
   addbuf SUM 5 $MINSIZE || $ERROR

   # Check the space.
   ck_exp_fs "$RPM_INST_ROOT" "$SUM" || $ERROR 

   return 0

}  # end of check_space()

remove_files()
{
   typeset ERROR='eval pmerror "remove_files()"; return 1'
   typeset NODE
   typeset RIR_NODE
   typeset CUR_LIST="$1"  # current list
   typeset KEEP_LIST="$2" # keep list
   typeset RC=0

   [[ -z $KEEP_LIST || -z $CUR_LIST ]] && $ERROR
   check_file $KEEP_LIST || $ERROR
   check_file $CUR_LIST || $ERROR

   while read RIR_NODE; do

      [[ ! -f $RIR_NODE && ! -L $RIR_NODE ]] && continue

      NODE=${RIR_NODE#*$RPM_INST_ROOT}

      RC=$(inlistf "$NODE" "$KEEP_LIST") || $ERROR

      case $RC in
         1) # in the RPM databse, do nothing
            : ;;
         0) # Not in the RPM database, remove
            $RM -f ${RIR_NODE} >/dev/null 2>&1 ;;
         *) $ERROR ;;
      esac

   done < $CUR_LIST

   return 0

}  # end of remove_files()

remove_dirs()
{
   typeset ERROR='eval pmerror "remove_dirs()"; return 1'
   typeset NODE
   typeset RIR_NODE
   typeset CUR_LIST="$1"  # current list
   typeset KEEP_LIST="$2" # keep list
   typeset RC=0

   [[ -z $KEEP_LIST || -z $CUR_LIST ]] && $ERROR
   check_file $KEEP_LIST || $ERROR
   check_file $CUR_LIST || $ERROR

   while read RIR_NODE; do

      [[ ! -d $RIR_NODE || "$RIR_NODE" = "$RPM_INST_ROOT" ]] && continue

      NODE=${RIR_NODE#*$RPM_INST_ROOT}

      RC=$(inlistf "$NODE" "$KEEP_LIST") || $ERROR

      case $RC in
         1) # in the RPM databse, do nothing
            : ;;
         0) # Not in the RPM database, remove
            $RMDIR ${RIR_NODE} >/dev/null 2>&1 ;;
         *) $ERROR ;;
      esac

   done < $CUR_LIST

   return 0

}  # end of remove_dirs()

RPM_RC_EXIT()
{
   cleanup
   exit "$RPM_RC"

}  # end of RPM_RC_EXIT()

FAIL()
{
   cleanup
   exit 1

}  # end of FAIL()

cleanup()
{
   [[ -d $WORKDIR ]] && $RM -rf $WORKDIR

}  # end of cleanup()

set_time_token()
{

   typeset ERROR='eval pmerror "set_time_token()"; return 1'

   TIMETOKEN=${WORKDIR}/timetoken.$$.${RANDOM}
   > $TIMETOKEN || $ERROR
   check_file $TIMETOKEN || $ERROR

############################################################
## Next, make sure the dates are reasonable by 
## 1) Check that the current TIMETOKEN is not older
##    than RPM_PACKAGES (dates messed up)
## 2) Test the rpm database lock.
## 3) Correct #2 if necessary.
############################################################

   # If the dates are reasonable, we are done
   [[ $TIMETOKEN -nt $RPM_PACKAGES ]] && return 0

   # Is another rpm install running?
   $RRPM -qa >/dev/null || $ERROR 
  
   # Make the time correction.
   $TOUCH $RPM_PACKAGES $TIMETOKEN || $ERROR 
 
   return 0

}  # end of set_time_token()

update_inst_root()
{
   typeset ERROR='eval pmerror "update_inst_root()"; return 1'
   typeset NODE
   typeset RIR_NODE # RPM inst_root node
   typeset RC=0

############################################################
## Data files. 
############################################################

   export  OACLFILE=${WORKDIR}/oaclfile.$$.${RANDOM}
   typeset RPM_DB_LIST=${WORKDIR}/rpm_db_list.$$.${RANDOM}
   typeset RIR_FILES=${WORKDIR}/rir_files.$$.${RANDOM}
   typeset RIR_DIRS=${WORKDIR}/rir_dirs.$$.${RANDOM}
   typeset FILE_ILIST=${WORKDIR}/fileilist.$$.${RANDOM} 
   typeset DIR_ILIST=${WORKDIR}/dirilist.$$.${RANDOM} 

   $RM -f $RPM_DB_LIST $RIR_FILES $RIR_DIRS $OACLFILE \
          $FILE_ILIST $DIR_ILIST

############################################################   
## Ensure that $RPM_INST_ROOT exists and set the OACLFILE
## file variable.
############################################################

   if [[ ! -d $RPM_INST_ROOT ]]; then
      $MKDIR -m 700 $RPM_INST_ROOT || $ERROR
   fi

############################################################   
## If inurid has run we do not need to save any files.
## To be safe we also blast the entire directory.
############################################################

   $INURID -q >/dev/null 2>&1
   if [[ $? -eq 1 ]]; then
      $RM -rf $RPM_INST_ROOT/*
      $TOUCH $RPM_INST_ROOT_INV
      return 0
   fi

############################################################
## Invalidate the current inventory list.
############################################################\

   $RM -f $RPM_INST_ROOT_INV

############################################################
## Create the rpm inst_root list.
############################################################

   get_rpm_inst_root_list > $RPM_DB_LIST || $ERROR

############################################################
## Create the list of RPM inst_root files.
############################################################

   $FIND $RPM_INST_ROOT -xdev -type f -o -type l > $RIR_FILES || $ERROR
 
############################################################
## Create the list of RPM inst_root dirs.
############################################################

   $FIND $RPM_INST_ROOT -xdev -type d -o -type l > $RIR_DIRS || $ERROR
   revflines $RIR_DIRS || $ERROR

############################################################
## Now remove anyhing in $RPM_INST_ROOT that is no longer
## in the RPM database.
############################################################

   remove_files "$RIR_FILES" "$RPM_DB_LIST" || $ERROR
   remove_dirs "$RIR_DIRS" "$RPM_DB_LIST" || $ERROR
 
############################################################
## Create the file and directory install lists.
############################################################

   > $FILE_ILIST || $ERROR
   > $DIR_ILIST  || $ERROR

   while read NODE; do
     
      RIR_NODE=${RPM_INST_ROOT}${NODE}

      if [[ -d $NODE && ! -d $RIR_NODE ]]; then
         echo "$NODE" >> $DIR_ILIST || $ERROR
         continue 
      fi

      if [[ -f $NODE ]]; then
         if [[ ! -f $RIR_NODE || $NODE -nt $RIR_NODE ]]; then
            echo "$NODE" >> $FILE_ILIST || $ERROR
            continue 
         fi
      fi

   done < $RPM_DB_LIST

############################################################
## Make sure we have enough space to do the copy.
############################################################

   check_space "$FILE_ILIST" "$DIR_ILIST" || $ERROR

############################################################
## Lets update the directories first.
############################################################

   while read NODE; do
      update_dir "$NODE" || $ERROR
   done < $DIR_ILIST

############################################################
## Finally, update the files.
############################################################

   while read NODE; do
      update_file "$NODE" || $ERROR
   done < $FILE_ILIST

############################################################
## Update RPM_INST_ROOT_INV with the latest data
############################################################

   check_fdup_space $RPM_DB_LIST 20 $RPM_INST_ROOT || $ERROR
   $CP $RPM_DB_LIST $RPM_INST_ROOT_INV || $ERROR

   $RM -f $RPM_DB_LIST $RIR_FILES $RIR_DIRS $OACLFILE \
          $FILE_ILIST $DIR_ILIST
 
   return 0

}  # end of update_inst_root()

update_dir()
{
   typeset ERROR='eval pmerror "update_dir()"; return 1'
   typeset ORIGDIR="$1" # original dir (to be copied)
   typeset NEWDIR       # new dir (to be created)
   typeset PORIGDIR     # parent dir of ORIGDIR 
   typeset PNEWDIR      # parent dir of NEWDIR 

   # Check input parameters.
   [[ -n $ORIGDIR ]]  || $ERROR
   NEWDIR=${RPM_INST_ROOT}${ORIGDIR}
   [[ -d "$NEWDIR" ]] && return 0 # no work to do
   check_dir $ORIGDIR || $ERROR 

############################################################
## Establish the parent dirs.
############################################################

   PORIGDIR=$(getpdir $ORIGDIR) || $ERROR
   check_dir ${PORIGDIR} || $ERROR
   PNEWDIR=${RPM_INST_ROOT}${PORIGDIR}

############################################################
## Does the new parent dir exist ? If yes, we are ready to
## do the update. If not, create it via recursive call.
## Note: ksh does not support more than 128 levels of 
## recursion.
############################################################

   if [[ ! -d "$PNEWDIR" ]]; then
      # create the parent directory
      update_dir "$PORIGDIR" || $ERROR 
   fi

   # create the new dir
   if [[ -L "$ORIGDIR" ]]; then
      $RM -f $NEWDIR 
      $CP -fph $ORIGDIR $NEWDIR || $ERROR
   else
      $MKDIR $NEWDIR || $ERROR
   fi

   # update the new dir's ownership and ACLs
   update_operms "$ORIGDIR" "$NEWDIR" || $ERROR
 
   return 0

}  # end of update_dir()

update_file()
{
   typeset ERROR='eval pmerror "update_file()"; return 1'
   typeset ORIGFILE="$1"  # original file (to be copied)
   typeset NEWFILE        # new file (to be created)
   typeset PORIGDIR       # parent dir of orig file

   # Check input parameters.
   [[ -z $ORIGFILE ]] && $ERROR
   NEWFILE=${RPM_INST_ROOT}${ORIGFILE}
   check_file "$ORIGFILE" || $ERROR

############################################################
## Establish the parent dirs.
############################################################

   PORIGDIR=$(getpdir $ORIGFILE) || $ERROR
   check_dir ${PORIGDIR} || $ERROR
   PNEWDIR=${RPM_INST_ROOT}${PORIGDIR}

############################################################
## If the new parent dir does not exist, create it.
############################################################

   if [[ ! -d "$PNEWDIR" ]]; then
      # create the parent directory
      update_dir "$PORIGDIR" || $ERROR
   fi

############################################################
## Copy the file and update ownership + ACLs
############################################################

   # Do the copy
   [[ -L $NEWFILE ]] && $RM -f $NEWFILE
   $CP -fph "$ORIGFILE" "$NEWFILE" || $ERROR

   # Update ownership + ACLs
   update_operms "$ORIGFILE" "$NEWFILE" || $ERROR

   return 0

}  # end of update_file()

########################################################################
## main MAIN Main
########################################################################

# Unset potential trouble makers
unset BASH_ENV
unset CDPATH
unset ENV
unset IFS

unalias -a
export PLATFORM=AIX
export WORKDIR=""
export TIMETOKEN=""
export OACLFILE=""
export RPM_RC=0
export EXP_REQUESTED=0
export BASELIB=/usr/lib/instl/baselib_sh
export USER_POSIXLY_CORRECT="$POSIXLY_CORRECT"    
export SYNCROOT=/usr/sbin/syncroot
export INURID=/usr/lib/instl/inurid

[[ -n $INUBOSTYPE ]] && EXP_REQUESTED=1

# Set a trap to cleanup all temp files. 
trap 'cleanup' EXIT
trap 'FAIL' 1 2 3 4 5 6 7 8 10 11 12 13 14 15 18 30 31 
   
. $BASELIB || exit 1

if [[ -n "$RPM_SHARE_DEBUG" ]]; then
   set -x
   typeset F
   for F in $(typeset +f); do typeset -ft $F; done
fi

# Initialize CISAL methods
init_baselib "rpm_share" || FAIL

# Check for minimal work space
ck_exp_fs ${WORKDIR} 1024 || FAIL 
ck_exp_fs ${OPTFS} 2048 || FAIL

# Sync only? 
if [[ -n $RPM_SHARE_SYNCNOW ]]; then
   update_inst_root || FAIL
   cleanup
   exit 0
fi 

# Set the time token.
set_time_token || FAIL

# Turn off posix enforcement activated by init_baselib(), 
# unless the user asked for it.
[[ -z $USER_POSIXLY_CORRECT ]] && unset POSIXLY_CORRECT

# Execute the rpm command
$RRPM "$@" 
RPM_RC=$? 

############################################################
## Did a change to the rpm database take place? If it did
## not, we are done.
############################################################

[[ $TIMETOKEN -nt $RPM_PACKAGES ]] && RPM_RC_EXIT 

############################################################
## Update $RPM_INST_ROOT root with any changes.
############################################################
 
update_inst_root || FAIL

RPM_RC_EXIT 
