#!/bin/bash
# Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
#
# Stop SGD services
#

if [ -f $TTAMSG/common -a -f $TTAMSG/tta_stop ]; then
  . $TTAMSG/common
  . $TTAMSG/tta_stop
else
  echo "Unable to open message file: $TTAMSG/tta_stop"
  exit 1
fi

N=""
C=""
if echo -n | grep n > /dev/null
then
  C="\c"
else
  N="-n"
fi
case "$MACHINEARCH" in
i3li*|ppli*) N="$N -e" ;;
esac
_ss_headlines="--------------------------------------------------------------------------"


case "$trace" in x|X) set -x;; esac

# cd to the directory containing this script, so that we can use
# relative pathnames
ttacommand=$0
case "$ttacommand" in
/*) cd `dirname $ttacommand`
    ;;
*)  fullpath=`pwd`/$ttacommand
    cd `dirname $fullpath`
esac


# Where are we relative to top of tta tree?
top=.
for _i in 0 1 2 3 4 5 6 7 8 9; do
    [ -d $top/bin/java -a -x $top/bin/tarantella ] && break
    [ -f $top/etc/passwd ] && { top=.; break; }
    top=../$top
done


cwd=`pwd`
cd "$top"
installdir=`pwd`
cd "$cwd"

# Get ${prvusr} and ${prvgrp}
GetPrivUsrGrp()
{
    cat $installdir/var/serverconfig/global/array.properties 2>/dev/null | awk -F= \
	'BEGIN { u="ttasys"; wu="ttaserv"; g="ttaserv" }
	$1 == "tarantella.config.array.privilegeduser" { u = $2 }
	$1 == "tarantella.config.array.webserveruser" { wu = $2 }
	$1 == "tarantella.config.array.privilegedgroup" { g = $2 }
	END { print u " " wu " " g }'
}
_privusrgrp=`GetPrivUsrGrp`
privusr=`expr "$_privusrgrp" : '\([^ ]*\) .*'`
webservusr=`expr "$_privusrgrp" : '.* \([^ ]*\) .*'`
privgrp=`expr "$_privusrgrp" : '.* \([^ ]*\)$'`




### Constants ###

SUBSVC_SGD=sgd
SUBSVC_CDM=cdm
SUBSVC_WEBSERVER=webserver

EXIT_SUCCESS=0
EXIT_INVALID_USAGE=1
EXIT_PROMPT_REJECTED=2



### Local functions ###

# $1 - exit code
function ExitUsage()
{
    echo "${lf_usage}" 1>&2
    exit $1
}


function ExitInvalidUsage()
{
    echo "${l_invalid_arg1}$1${l_invalid_arg2}" 1>&2
    echo "${sf_usage}" 1>&2
    exit ${EXIT_INVALID_USAGE}
}


# Stamp the "stopped" file with the current date and time.
function Stamp()
{
    # Touch the stop file with the current time.
    ( umask 077 ; date > "${TTADATADIR}/info/stopped"; chown ${privusr}:${privgrp} "${TTADATADIR}/info/stopped" )
    [ -n "${PRODUCT_LSBSCRIPTNAME}" -a -f /var/lock/subsys/${PRODUCT_LSBSCRIPTNAME} ] && rm -f /var/lock/subsys/${PRODUCT_LSBSCRIPTNAME}
}


# Parse and validate the command line arguments.
# Accepted syntaxes:
#     1) tarantella stop [--force] [--yes]
#     2) tarantella stop --help
# Deprecated syntaxes:
#     3) tarantella stop [--kill] [--quiet] [--http | --https] [--servlet]
#     4) tarantella stop sgd [--kill] [--quiet]
#     5) tarantella stop webserver [--http | --https] [--servlet]
#     6) tarantella stop cdm
# Internal syntaxes (to be removed):
#     7) tarantella stop --restart --quiet
#
# Input parameters:
#     $@  Command line parameters
# Output globals:
#     opt_subservice  the subservice to restart (sgd, webserver) [deprecated] or#                     empty (both)
#     opt_help        true iff --help is specified
#     opt_force       true iff --force is specified
#     opt_yes         true iff --yes is specified
#     opt_kill        true iff --kill is specified
#     opt_quiet       true iff --quiet is specified
#     opt_http        "--http" iff --http specified, else empty [deprecated]
#     opt_https       "--https" iff --https specified, else empty [deprecated]
#     opt_servlet     "--servlet" iff --servlet specified, else empty
#                     [deprecated]
#     opt_restart     true iff --restart specified
#
# Returns: An exit code
#     EXIT_SUCCESS              on success
#     EXIT_INVALID_USAGE        if a syntax error is encountered
#
function ParseOptions()
{
    opt_subservice=
    opt_help=false
    opt_force=false
    opt_yes=false
    opt_kill=false
    opt_quiet=false
    opt_http=
    opt_https=
    opt_servlet=
    opt_restart=false

    case "$1" in
        # all subservices are deprecated
        ${SUBSVC_SGD}|${SUBSVC_WEBSERVER})
            opt_subservice="$1"
            shift
            ;;
    esac

    while [ $# -gt 0 ]
    do
        case "$1" in
            --help)
                opt_help=true
                return $EXIT_SUCCESS
                ;;
            --force)
                opt_force=true
                ;;
            --yes)
                opt_yes=true
                ;;
            --kill)
                opt_kill=true
                ;;
            --quiet)
                opt_quiet=true
                ;;
            --http)
                opt_http="$1"
                ;;
            --https)
                opt_https="$1"
                ;;
            --servlet)
                opt_servlet="$1"
                ;;
            --restart)
                opt_restart=true
                ;;
            *)
                return $EXIT_INVALID_USAGE
                ;;
        esac
        shift
    done

    # Check valid syntaxes

    local have_webopt=false
    [ -n "${opt_http}" -o -n "${opt_https}" -o -n "${opt_servlet}" ] &&
       have_webopt=true

    local have_deprecated=false
    (${have_webopt} || ${opt_kill} || ${opt_quiet}) && have_deprecated=true
    local have_nondeprecated=false
    (${opt_force} || ${opt_yes}) && have_nondeprecated=true

    # --http, --https, --servlet (deprecated) only valid if starting webserver
    ${have_webopt} &&
        [ -n "${opt_subservice}" -a \
          "${opt_subservice}" != ${SUBSVC_WEBSERVER} ] &&
            return ${EXIT_INVALID_USAGE}

    # --kill and --quiet (deprecated) only valid if starting sgd
    (${opt_kill} || ${opt_quiet}) &&
        [ -n "${opt_subservice}" -a "${opt_subservice}" != ${SUBSVC_SGD} ] &&
            return ${EXIT_INVALID_USAGE}

    # --http and --https are mutually exclusive
    [ -n "${opt_http}" -a -n "${opt_https}" ] &&
        return ${EXIT_INVALID_USAGE}

    # --force, --yes (non-deprecated) only valid with no subservice
    [ -n "${opt_subservice}" ] && (${opt_force} || ${opt_yes}) &&
        return ${EXIT_INVALID_USAGE}

    # Deprecated options can't be used with non-deprecated
    ${have_deprecated} && ${have_nondeprecated} &&
        return ${EXIT_INVALID_USAGE}

    # The internal --restart syntax can only be used with --quiet
    ${opt_restart} && [ $# -gt 1 ] && ! ${opt_quiet} &&
        return ${EXIT_INVALID_USAGE}

    # tarantella stop cdm is handled by the top-level tarantella script

    return ${EXIT_SUCCESS}
}


function GetProcessInfo()
{
    case "$SCOARCH" in
        i3li*)
            processInfo=`ps ajx 2>/dev/null | awk '$2=="'"$1"'"{print}'` ;;
        *)
            processInfo=`ps -fp$1 2>/dev/null | awk '$2=="'"$1"'"{print}'`
            [ -z "$processInfo" ] &&
                processInfo=`ps -ajx 2>/dev/null | awk '$2=="'"$1"'"{print}'`
    esac
    echo "$processInfo"
}


# Kill processes.
# Kills the processes listed in $3 by sending the TERM signal. If that fails,
# then optionally, the KILL signal is sent. The pid file $2 is deleted after the
# processes have been terminated
# Input parameters:
#     $1  Process name
#     $2  pid file
#     $3  Process ids
# Global parameters:
#     opt_quiet  true iff output should be suppressed
#     tryhard    Iff not empty, send SIGKILL if process does not exit on
#                SIGTERM.
function KillIt()
{
    local name="$1"; shift
    local file="$1"; shift
    local processids="$*"
    
    if ! ${opt_quiet}
    then
        echo "$name pid=$processids"
    fi
    for pid in $processids
    do
        count=10
        while [ $count -gt 0 ]
        do
            processInfo=`GetProcessInfo $pid`
            if [ -n "$processInfo" ]
            then
                kill $pid
                count=`expr $count - 1`
                sleep 1
            else
                if ! ${quiet}
                then
                    echo "${stop_success}$name"
                fi
                break
            fi
        done
        if [ $count -eq 0 ]
        then
            if [ ! -z "$tryhard" ]
            then
                kill -9 $pid
                sleep 1
                processInfo=`GetProcessInfo $pid`
            fi
            if ! ${opt_quiet} && [ -n "$processInfo" ]
            then
                echo "${stop_failed}$name (PID=$pid)"
            fi
        fi
    done
    rm -f "$file"

    Stamp
}


# Kill miscellaneous helper proccesses that don't exit with the JServer.
# Kills the ttaprintfifo, tier2loadprobe and, optionally, the ttalaunchhelper
# processes.
# Input globals:
#     TTADIR      The SGD installation path.
#     TTADATADIR  The SGD data subdirectory path.
# Input parameters:
#     $1  true iff we should kill the ttalaunchhelper process
function KillHelpers()
{
    # Kill the ttaprintfifo process, as on some platforms it may not get killed
    # by the JServer correctly.
    local printfifofile
    for printfifofile in `ls -d ${TTADATADIR}/info/PrintFifo* 2>/dev/null`
    do
        local printfifoPid=`expr "$printfifofile" : "${TTADATADIR}/info/PrintFifo\(.*\)"`
        tryhard=t
        KillIt printfifo $printfifofile $printfifoPid >/dev/null
        tryhard=
    done

    # Kill the Tier2 load probe explicitly, as sometimes it takes a while to
    # notice that we've gone
    local PROBE_FILE="${TTADATADIR}/info/tier2loadprobe.pid"

    if [ -f "$PROBE_FILE" ]
    then
        local PROBE_PID="`tail -1 ${PROBE_FILE} | sed -e 's/ //'`"
        if [ -n "$PROBE_PID" ]
        then
            tryhard=t
            KillIt tier2loadprobe "${PROBE_FILE}" $PROBE_PID >/dev/null
            tryhard=
        fi
    fi

    if [ "$1" = true ]
    then
        # Kill the ttalaunchhelper process
        local LaunchHelperInfoFile="${TTADATADIR}/info/launchhelperinfo"
        if [ -f "${LaunchHelperInfoFile}" ]
        then
            local LaunchHelperPid=`awk '{print $1}' <${LaunchHelperInfoFile}`
            [ -n "${LaunchHelperPid}" ] &&
                KillIt ttalaunchhelper \
                       "${LaunchHelperInfoFile}" \
                       ${LaunchHelperPid} >/dev/null
            rm -f "${LaunchHelperInfoFile}"
        fi
    fi

    # disable TTA printer
    ${TTADIR}/bin/scripts/lpdisable >/dev/null 2>&1
}


# Send kill signal to any SSL daemon processes
# Input globals:
#     TTADATADIR  The SGD data directory path.
function KillSSLDaemons() 
{
    local ssldaemonsfile="${TTADATADIR}/info/ssldaemons.pid"
    if [ -f "${ssldaemonsfile}" ]
    then
        [ -x "/usr/bin/nawk" ] && AWK="nawk" || AWK="awk"
        local pids=`${AWK} -f getrunningpids.awk "${ssldaemonsfile}"`
        # Ensure all the processes are stopped
        KillIt "ttassl" "${ssldaemonsfile}" "${pids}" > /dev/null
    fi
}


# Prompts the user to stop the SGD server if there are running sessions.
# Input globals:
#     TTADIR            The SGD installation directory.
#     stop_shouldistop  Confirmation prompt message for user.
#     answer            Message indicating accepted user responses (yes/no).
#     a_case_yes        The accepted prefix for an affimrative response (y).
# Returns:
#     0  The user has confirmed stop, or no sessions running.
#     1  There are sessions running and the user has rejected the stop.
function Prompt()
{
    local ttastatus="`${TTADIR}/bin/tarantella status --server \`${TTADIR}/bin/scripts/getconfig --peerdns\` | egrep '(Webtop|Emulator)  *sessions  *\([^0]'`"
    if [ -n "${ttastatus}" ]
    then
        local answer=no
[ -z "${i18n_yes}" ] && i18n_yes="${a_yes}"
[ -z "${i18n_no}" ] && i18n_no="${a_no}"
[ -z "${i18n_case_yes}" ] && i18n_case_yes="${a_case_yes}"
[ -z "${i18n_case_no}" ] && i18n_case_no="${a_case_no}"
[ -z "${i18n_s_yes}" ] && i18n_s_yes="${s_yes}"
[ -z "${i18n_s_no}" ] && i18n_s_no="${s_no}"
[ "${stop_shouldistop}" != "NOPROMPT" ] && echo "${stop_shouldistop}"
echo # blank line between prompt and question
_valid=false
while [ $_valid = false ]
do
  echo $N "${q_stop_shouldistop} [$answer] $C"
  read _answer
  if [ -z "$_answer" ]
  then
    _answer="$answer"   # default
  fi
  case "$_answer" in
    [${i18n_case_yes}]* )
	    _answer=$i18n_s_yes
	    _valid=true
	    ;;
    [${i18n_case_no}]* )
	    _answer=$i18n_s_no
	    _valid=true
	    ;;
  esac
done
answer="$_answer"

        case "${answer}" in
            [${a_case_yes}]*)
                ;;
            *)
                return 1
        esac
    fi
    return 0
}



### Main ###

# Process command line options

ParseOptions "$@" || ExitInvalidUsage
${opt_help} && ExitUsage ${EXIT_SUCCESS}

# Alias deprecated options to non-deprecated ones
${opt_kill}  && { opt_force=true; opt_yes=true; }
unset opt_kill
${opt_quiet} && { opt_yes=true; }

# Which services do we want to stop?
stop_webserver=false
[ "${opt_subservice}" = $SUBSVC_WEBSERVER -o -z "${opt_subservice}" ] &&
    stop_webserver=true;
stop_core=false
[ "${opt_subservice}" = $SUBSVC_SGD -o -z "${opt_subservice}" ] &&
    stop_core=true;

# Make sure that they are running as root

u="`LANG=C LC_ALL=C id | sed 's/.*uid=\([0-9][0-9]*\).*/\1/'`"
if [ "$u" = "0" ]
then
  : # all is okay
else
  echo "You must be root to run this program"
  exit 15
fi


# Prompt for confirmation, if required

if ! ${opt_yes} && ${stop_core} && ! Prompt
then
    echo "${stop_serverinuse}"
    exit ${EXIT_PROMPT_REJECTED}
fi

# Stop the webserver, unless we are doing a (deprecated) warm restart

if ! ${opt_restart} && ${stop_webserver}
then
    [ -n "${opt_http}" -o -n "${opt_https}" ] && websserver_stop_opts="--http"
    websserver_stop_opts="${websserver_stop_opts} ${opt_servlet}"
    ${TTADIR}/bin/scripts/webserver .stop ${websserver_stop_opts}
fi
# Bail if we're only stopping the webserver
[ "${opt_subservice}" = $SUBSVC_WEBSERVER ] && exit 0

# Stop the core services

# If this is not a forced stop, we send a message the server asking it to exit
if ! ${opt_force}
then
    ${opt_restart} && tclrestart="--restart"
    # NB. Promrpt in proper_stop is no longer used. --quiet always specified.
    ./run_tclscript proper_stop ${tclrestart} --quiet
    err=$?
    if [ "$err" != "1" ]
    then
        ! ${opt_quiet} && echo "${stop_stopmsg}"
        # stop the cdm if it is installed, and this isn't a restart
        if ! ${opt_restart} && [ -x $TTADIR/bin/scripts/stop_cdm ]
        then
            "${TTADIR}/bin/scripts/stop_cdm" --quiet
        fi

        ${opt_restart} && kill_launchhelpers=false || kill_launchhelpers=true
        KillHelpers ${kill_launchhelpers}
        Stamp
    fi
    KillSSLDaemons
    exit $err
fi

# Force quit the core services by killing processes


echo "$stop_killintro"

# stop the cdm if it is installed
if [ -x $TTADIR/bin/scripts/stop_cdm ]
then
    $TTADIR/bin/scripts/stop_cdm --quiet --kill
fi

${opt_restart} && kill_launchhelpers=false || kill_launchhelpers=true
KillHelpers ${kill_launchhelpers}

# Kill the AuxServer
auxserverfile="${TTADATADIR}/info/auxserver.pid"
if [ ! -f "${auxserverfile}" ]
then
    ! ${opt_quiet} && echo "${stop_already}${auxservername}"
else
    auxserverPid=`cat ${auxserverfile}`
    KillIt "${auxservername}" "${auxserverfile}" ${auxserverPid}
fi

# Kill the JServer
jserverfile="${TTADATADIR}/info/jserver.pid"
if [ ! -f "${jserverfile}" ]
then
    ! ${opt_quiet} && echo "${stop_already}${jservername}"
else
    jserverPid=`cat $jserverfile`
    KillIt "${jservername}" "${jserverfile}" $jserverPid
fi

# Kill any remaining SSL daemons
KillSSLDaemons



getChildrenOfPid() 
{
## Warning - the following code is Linux specific.  (And if 
## /proc/<pid>/exe changes, will break)
## PS: It was changed. And it did break. [Fitz 605468]
ppid="$1"
exepattern="$2"
exclpattern="$3"
childrenpids=""
# Get children of ppid
ALLCHILDPIDS=`echo "$ps_output" | grep "^ *$ppid " | awk '{ print $2 }'`

if [ -z "$exepattern" ] ; then 
    childrenpids="$ALLCHILDPIDS" 
else 
    if [ ! -z "$ALLCHILDPIDS" ] ; then 
	for p in $ALLCHILDPIDS ; do
	    # is the executable one we worry about?
	    if [ -n "`find /proc/$p -name exe -lname \"$exepattern\" 2>/dev/null | sort | sed 1q`" ] ; then
		# yes 
                if [ -z "$exclpattern" ]; then
                    childrenpids="$childrenpids $p"
                else
                    check=`ps --noheading --pid $p -ww -o args | egrep -- "$exclpattern"`
                    [ -z "$check" ] && childrenpids="$childrenpids $p"
                fi
	    fi
	done
    fi
fi
echo $childrenpids
}

removeSurplusJVMs() 
{
# this will kill any instances of our JVM whose parent is init.
case "$SCOARCH" in
    i3li*|ppli*)
	## cache the output of ps, as it may be called several times, and can
	## be slow.
	ps_output=`ps --no-heading -ax -o ppid,pid 2>/dev/null`
	
	PIDSTOKILL=""
	PPIDS=`getChildrenOfPid 1 "$TTABINDIR/j*" "-classpath[ :]*$TTADIR/webserver"`
	while [ ! -z "$PPIDS" ] ; do
	    CHILDPIDS=""
	    PIDSTOKILL="$PIDSTOKILL $PPIDS"
	    for pp in $PPIDS ; do 
		CHILDPIDS="$CHILDPIDS `getChildrenOfPid $pp`"
	    done
	    PPIDS="$CHILDPIDS"
	done
	if [ ! -z "$PIDSTOKILL" ] ; then 
	    for p in $PIDSTOKILL ; do 
		if [ -d /proc/$p ] ; then 
		    kill $p 2>/dev/null
		    # give it time to exit
		    sleep 1
		    if [ -d /proc/$p ]; then
			kill -9 $p 2>/dev/null
			echo -n "(Using SIGKILL)"
		    fi
		echo "Killed pid $p (surplus JVM thread)"
		fi
	    done
	fi
	;;
esac
}


removeSurplusJVMs

exit 0
