#!/bin/sh
#
# Component : ChorusOS patch
# Module    : patchit.sh
# Sypnosis  : primary script to launch when patching a ChorusOS
#
# Copyright (c) 1998 by Sun Microsystems, Inc.
# All rights reserved.
#
# ident	"@(#)patchit.sh	1.0	98/09/12 SMI"
#



######################################################################
#
# FUNCTIONS
#
######################################################################

    #
    # SPY
    #    Display a spy message
    #
SPY() {
   echo "Spying $1"
}

    #
    # ERROR
    #     Displays a message and exit 1
    #
ERROR() {
  echo " ** ERROR : $1"
  exit 1
}

    #
    # flush
    #    Black magic, to work around a bug in cygwin32.
    #
flush() {
    if [ "${OS}" = "win32" -a "${DISABLE_CYGWIN32_READ_WORKAROUND}" = "" ]; then
	exec <&2
    fi
}

    # 
    # usage
    #    Displays the script usage and exit 1
    #
usage() {
	PROGNAME=`basename $0`
	echo "USAGE:\n\t${PROGNAME} [ -F ]\n" >&2
	echo "\t\t-F\tForce the patch application\n" >&2
	exit 1
}

    #
    # ask_ok
    #    asks a question and wait y or n
    #    default is y.
    #    if reply = y, return 0
    #    if reply = n, return 1
    #
ask_ok() {
    flush
    while [ "true" ]; do
	${ECHO_N} "$1 [y] "
	read answer
	if [ -z "${answer}" ]; then
	    break
	fi
	if [ "${answer}" = "y" ]; then
	    break
	fi
	if [ "${answer}" != "n" ]; then
	    echo "Please answer y or n"
	    continue;
	fi
	return 1
    done
    return 0
}

    #
    # ask_nok
    #    asks a question and wait y or n
    #        default is n.
    #        if reply = y, return 0
    #        if reply = n, return 1
    #
ask_nok() {
    flush
    while [ "true" ]; do
	${ECHO_N} "$1 [n] "
	read answer
	if [ -z "${answer}" ]; then
	    break
	fi
	if [ "${answer}" = "n" ]; then
	    break
	fi
	if [ "${answer}" != "y" ]; then
	    echo "Please answer y or n"
	    continue;
	fi
	return 0
    done
    return 1
}

    #
    # check_path
    #      Check the value of a path by verifying it's contents 
    #      point to a readable file.
    #      Exit from program if the readable file is not present.
    #
check_path ()
{
  VARIABLE="$1"
  if [ -z "$2" ]; then
    DESCRIPTION=""
 else
    DESCRIPTION="as $2"
  fi
  if [ ! -z "$3" ]; then
    XFILE="$3"
  else
    XFILE=""
  fi

  if [ -z "${XFILE}" ]; then
	if [ -d "${VARIABLE}" ] ; then
		echo "Using ${VARIABLE} ${DESCRIPTION}"
	else
		ERROR "${VARIABLE} is not a directory."
	fi
  else
	if [ -r "${VARIABLE}/${XFILE}" ] ; then
		echo "Using ${VARIABLE} ${DESCRIPTION}"
	else
		ERROR "${VARIABLE}/${XFILE} is not readable."
	fi
  fi
}


    #
    # check_file
    #      Check if the file is readable.
    #      Exit from program if the readable file is not present.
    #
check_file ()
{
  XFILE="$1"
  DESCRIPTION="$2"

  if [ ! -r "${XFILE}" ] ; then
    if [ -z "${DESCRIPTION}" ]; then
      ERROR "${XFILE} does not exist."
    else
      ERROR "${DESCRIPTION}" 
    fi
  fi
}

    #
    # getpath
    #      Ask a path
    #      If no answer is given, return the default path
    #
getpath () {
    flush
    $ECHO_N "$1 [$2] " >&2
    read answer
    if [ -z "${answer}" ]; then
        echo "$2"
    else
        echo "${answer}"
    fi
}


    #
    # make_patch_profile
    #      Create the profile data
    #      Save in it all _CHORUSOS_XXXX variables
    #
make_patch_profile () {
	
chmod u+w "${PATCH_DIR}/etc/patch.env"
if [ $? != 0 ]; then
  ERROR "Can not edit the environment file."
fi

cat <<EOF > "${PATCH_DIR}/etc/patch.env"
#      Patch information

_CHORUSOS_PATCH_ID="${_CHORUSOS_PATCH_ID}"
_CHORUSOS_PARTNUMBER="${_CHORUSOS_PARTNUMBER}"
_CHORUSOS_HOST="${_CHORUSOS_HOST}"
_CHORUSOS_HOST_NICKNAME="${_CHORUSOS_HOST_NICKNAME}"
_CHORUSOS_RELEASE="${_CHORUSOS_RELEASE}"
_CHORUSOS_TARGET="${_CHORUSOS_TARGET}"
_CHORUSOS_BANNER="${_CHORUSOS_BANNER}"
_CHORUSOS_PATCHES_DIR="${_CHORUSOS_PATCHES_DIR}"
_CHORUSOS_PATCH_DATE="${_CHORUSOS_PATCH_DATE}"
_CHORUSOS_PATCH_LASTOP="`date`"

EOF
}


    #
    # default_profile_values
    #      Set the profile variables with the default values
    #
default_profile_values () {
_CHORUSOS_PATCH_ID="${_CHORUSOS_PATCH_ID:-123456}"
_CHORUSOS_PARTNUMBER="${_CHORUSOS_PARTNUMBER:-CLX320-AAAA}"
_CHORUSOS_HOST="${_CHORUSOS_HOST:-SPARC/Solaris}"
_CHORUSOS_HOST_NICKNAME="${_CHORUSOS_HOST_NICKNAME:-'solaris'}"
_CHORUSOS_RELEASE="${_CHORUSOS_RELEASE:-'3.2'}"
_CHORUSOS_TARGET="${_CHORUSOS_TARGET:-Intel x86}"
_CHORUSOS_BANNER="${_CHORUSOS_BANNER:-ChorusOS r3.2 Binary for Intel x86 on SPARC/Solaris host}"
_CHORUSOS_PATCHES_DIR=`echo "${_CHORUSOS_PATCHES_DIR:-'/ChorusOS/patches'}" | \
			sed "s=^/ChorusOS/patches$=${LAUNCH_DIR}/patches="`
_CHORUSOS_PATCH_DATE="${_CHORUSOS_PATCH_DATE:-`date`}"
_CHORUSOS_PATCH_LASTOP="${_CHORUSOS_PATCH_LASTOP:-`date`}"

}

	
    #
    # remove_current_patch
    #      Remove the current patch if needed
    #
remove_current_patch() {
    UNSUBPATCHIT="${CURRENT_PATCH_DIR}/bin/unsubpatchit.sh"
    check_file "$UNSUBPATCHIT" "Unable to find ${UNSUBPATCHIT}"
    LIST=`ls ${CURRENT_PATCH_DIR}/*/subpatch.env`
    if [ ! $? = 0 ]; then
	echo "WARNING: Nothing to do"
    else
	for p in "${LIST}"
	do
	    # Launch of subscript
	    if  sh "${UNSUBPATCHIT}" -E "${p}"; then
		echo "${UNSUBPATCHIT} -E ${p} applied."
            else
                 ERROR "Unable to apply ${UNSUBPATCHIT} on ${p}\nThe previous patch can not be removed\n"
            fi
	done
	rm -rf "${_CHORUSOS_PATCHES_DIR}/current"
        echo "\nThe previous patch has been removed.\n"
    fi
}


    #
    # host_specific
    #      Find the OS
    #
host_specific () {
  # Find the host type
  UNAME=`uname`
  if [ "${UNAME}" = "Linux" ]; then
    OS=linux
  elif [ "${UNAME}" = "SunOS" ]; then
    case `uname -r` in
	4.*) OS=sunos;;
	5.*) OS=solaris;;
    esac;
  elif [ "${UNAME}" = "UNIX_SV" ]; then
    OS=unixware
  elif [ "${UNAME}" = "HP-UX" ]; then
    OS=hpux
  elif [ "${UNAME}" = "CYGWIN32/NT" ]; then
    OS=win32
  elif [ "${UNAME}" = "CYGWIN32_NT" ]; then
    OS=win32
  fi

  if [ -z "${OS}" ]; then
    ERROR "I have not been able to determine your host type. Sorry..."
  fi

  # Host specifics
  case "${OS}" in
    linux)	ECHO_N="echo -n";
		;;
    sunos)	ECHO_N="echo -n";
		;;
    solaris)	ECHO_N="printf %s";
		;;
    unixware)	ECHO_N="echo -n";
		;;
    svr4)	ECHO_N="echo -n";
		;;
    hpux)      	ECHO_N="printf %s";
		;;
    win32)	ECHO_N="printf %s";
		;;
  esac
}

    #
    # check_os
    #      Verify if the subpatch can be applied on this OS
    #
check_os() {
  # Check the host is the expected one
  if [ "${OS}" != "${_CHORUSOS_HOST_NICKNAME}" ]; then
    ERROR "This install script must be run on a ${_CHORUSOS_HOST_NICKNAME} OS. Sorry"
  fi
}

    #
    # hereify
    #      Make all specified paths absolute
    #
HERE=`pwd`
hereify() {
  if [ -z "$1" ]; then
    return
  fi
  if echo "$1" | grep -v "^/" >/dev/null 2>&1; then
    if [ "$1" = "." ]; then
      echo "${HERE}"
    else
      echo "${HERE}/$1"
    fi
  else
    echo "$1"
  fi
}

##############################################################################
#
# BANNERS
#
##############################################################################

BANNER_PATCHIT() {
cat <<EOF

+----------------------------- ChorusOS Patchit -----------------------------+

EOF
}

BANNER_ENV() {
cat <<EOF

----- Finding patch environment -----

EOF
}

BANNER_COPY() {
cat <<EOF

----- Copy the patch files -----

EOF
}

BANNER_UNARCHIVE() {
cat <<EOF

----- Unarchive the patch files -----

EOF
}

BANNER_PREVIOUS_PATCH() {
cat <<EOF

----- Uninstall previous patch -----

EOF
}

BANNER_PATCHING() {
cat <<EOF

----- Applying patches -----

EOF
}

BANNER_END() {
cat <<EOF

----- The patch ${_CHORUSOS_PATCH_ID} has been successfully applied. -----

+----------------------------- ChorusOS Patchit -----------------------------+
EOF
}

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


host_specific

# Store the current directory
LAUNCH_DIR=`pwd`
export LAUNCH_DIR

# Test the current directory
$ECHO_N $$ > test.$$
if [ `cat test.$$` != $$ ]; then
  $ECHO_N "The current directory is not writable"
  $ECHO_N "Run ${LAUNCH_DIR}/patchit.sh from a writable directory"
  exit 1
fi
rm -f test.$$

# Log output and errors here
PATCH_OUTFILE="${LAUNCH_DIR}/patchit.out"

# Rename the old log
[ -f "${PATCH_OUTFILE}" ] && mv "${PATCH_OUTFILE}" "${PATCH_OUTFILE}.old"

(
DISABLE_CYGWIN32_READ_WORKAROUND=TRUE
export DISABLE_CYGWIN32_READ_WORKAROUND

BANNER_PATCHIT

# Analyze the parameters
FORCE_OPT=""
while getopts "F" opt
do
	case "${opt}" in

	F) FORCE_OPT="-F" ;;

	*) usage ;;

	esac
done
shift `expr ${OPTIND} - 1`


BANNER_ENV


# Retrieve FTP directory
FTP=`dirname $0`
FTP=`hereify "${FTP}"`
FTP=`getpath "Install ChorusOS patch from ?" "${FTP}"`
FTP=`hereify "${FTP}"`
if [ ! -d "${FTP}" ]; then
  ERROR "Cannot access ${FTP}"
fi

# Verify if cix is present in the same directory than patchid.sh
check_path "${FTP}" "patch delivery directory" bin/cix

# Load environments if any
if [ -f "${FTP}/etc/patch.env" ]; then
	. "${FTP}/etc/patch.env"
else
    ERROR "No environment file for this patch"
fi

# Create default values if needed
default_profile_values

# Verify the OS
check_os

# Ask a place PATCH_DIR in order to unarchive patchs
# Retrieve FTP directory
_CHORUSOS_PATCHES_DIR=`getpath "Install ChorusOS patch in ?" "${_CHORUSOS_PATCHES_DIR}"`
_CHORUSOS_PATCHES_DIR=`hereify "${_CHORUSOS_PATCHES_DIR}"`
PATCH_DIR="${_CHORUSOS_PATCHES_DIR}/${_CHORUSOS_PATCH_ID}"
CURRENT_PATCH_DIR="${_CHORUSOS_PATCHES_DIR}/current"
PATCH_BIN_DIR="${PATCH_DIR}/bin"
CIX="${PATCH_BIN_DIR}/cix"
UNSUBPATCHIT="${PATCH_BIN_DIR}/unsubpatchit.sh"
SUBPATCHIT="${PATCH_BIN_DIR}/subpatchit.sh"
PATCH_ETC_DIR="${PATCH_DIR}/etc"

if [ "${PATCH_DIR}" != "${FTP}" ]
then
    # Create the _CHORUSOS_PATCHES_DIR for courtesy
    mkdir -p "${_CHORUSOS_PATCHES_DIR}"
    check_path "${_CHORUSOS_PATCHES_DIR}" "ChorusOS patches directory." 

    if [ -d "${CURRENT_PATCH_DIR}" ]; then
	# Remove the current patch
	remove_current_patch
    else
	echo "There is no patch to remove\n"
    fi

    BANNER_COPY

    # Create and/or remove PATCH_DIR if needed
    if [ -d "${PATCH_DIR}" ]; then
	echo "Warning : ${PATCH_DIR} already exits.\n"
	if ask_ok "Remove ${PATCH_DIR}"; then
	    rm -rf "${PATCH_DIR}"
	    echo "          ${PATCH_DIR} is removed."
	fi
    fi
    mkdir "${PATCH_DIR}"
    if [ ! -d "${PATCH_DIR}" ]; then
	ERROR "Unable to create ${PATCH_DIR} patch directory"
    fi

    # Copy of the uninstall script
    cp "${FTP}/patchit.sh"       "${PATCH_DIR}"
    cp "${FTP}/bin/unpatchit.sh" "${PATCH_DIR}"
    chmod a+x ${PATCH_DIR}/*.sh
    check_file "${PATCH_DIR}/unpatchit.sh" "Unable to copy unpatchit.sh in ${PATCH_DIR}"
    check_file "${PATCH_DIR}/patchit.sh" "Unable to copy patchit.sh in ${PATCH_DIR}"

    # Copy cix
    mkdir "${PATCH_BIN_DIR}"
    if [ ! -d "${PATCH_BIN_DIR}" ]; then
	ERROR "Unable to create ${PATCH_BIN_DIR} patch directory"
    fi
    cp "${FTP}/bin/cix"             "${PATCH_BIN_DIR}"
    cp "${FTP}/bin/subpatchit.sh"   "${PATCH_BIN_DIR}"
    cp "${FTP}/bin/unsubpatchit.sh" "${PATCH_BIN_DIR}"
    check_file "${PATCH_BIN_DIR}/cix" "Unable to copy cix in ${PATCH_BIN_DIR}"
    chmod a+x ${PATCH_BIN_DIR}/*

    # Copy patch.env if any
    mkdir "${PATCH_ETC_DIR}"
    if [ ! -d "${PATCH_ETC_DIR}" ]; then
	ERROR "Unable to create ${PATCH_ETC_DIR} patch directory"
    fi
    cp ${FTP}/etc/* "${PATCH_ETC_DIR}"
    chmod a+r ${PATCH_ETC_DIR}/*

    BANNER_UNARCHIVE

    # Unarchive packets
    for a in `ls ${FTP}/archives/*`
    do
	# Launch of cix
	AA=`basename "${a}"`
	if "${CIX}" -t "${PATCH_DIR}/${AA}" -a "${a}"; then
	    echo "${PATCH_DIR}/${AA} unarchived."
	else
	    ERROR "Unable to unarchive ${a}"
	fi
    done
fi

BANNER_PATCHING

# Find subscripts environment files
LIST=`ls ${PATCH_DIR}/P*/subpatch.env`
if [ ! $? = 0 ]; then
  ERROR "WARNING: Nothing to apply in this patch"
fi

# Launch subscripts
for p in "${LIST}"
do
    # Launch of subscript
    if  sh "${SUBPATCHIT}" ${FORCE_OPT} -E "${p}" ; then
	echo "${SUBPATCHIT} on ${p} applied."
    else
	ERROR "Unable to apply ${SUBPATCHIT} on ${p}"
    fi
done

# Creating the `current` symbolic name to ${PATCH_DIR}
ln -s "${PATCH_DIR}" "${_CHORUSOS_PATCHES_DIR}/current"

# Save new environment
make_patch_profile

# Come back
cd "${LAUNCH_DIR}"

BANNER_END "${_CHORUSOS_PATCH_ID}"

) 2>&1 | tee /dev/tty > "${PATCH_OUTFILE}" 2>&1

# EOF
