#!/bin/bash
##
## Run Apache Tomcat
## Copyright (c) 2020-2024 SATOH Fumiyasu @ OSSTech Corp., Japan
##
## SPDX-License-Identifier: GPL-3.0
##

set -u

if [[ -n ${JOURNAL_STREAM-} || $PPID -eq 1 ]]; then
  PNAME=""
else
  PNAME="$0"
fi

TRUE='@(true|yes|on)'

run() {
  if [[ -n ${TOMCAT_RUN_INFO-set} ]]; then
    echo "${PNAME:+$PNAME: }INFO: Run: $*" >&2
  fi
  "$@"
}

run_or_die() {
  run "$@" || exit $?
}

info() {
  echo "${PNAME:+$PNAME: }INFO: $1" >&2
}

warn() {
  echo "${PNAME:+$PNAME: }WARNING: $1" >&2
}

error() {
  echo "${PNAME:+$PNAME: }ERROR: $1" >&2
  exit ${2-1}
}

debug() {
  sed "s#^#${PNAME:+$PNAME: }DEBUG: #" >&2
}

## ======================================================================

tomcat_sysconf_dir="${TOMCAT_SYSCONF_DIR:-/opt/osstech/etc/tomcat}"

tomcat_conf="${TOMCAT_CONF:-$tomcat_sysconf_dir/tomcat.conf}"
tomcat_conf_dir="${TOMCAT_CONF_DIR:-$tomcat_sysconf_dir/tomcat.conf.d}"

## ======================================================================

LANG="${JAVA_LANG:-en_US.UTF-8}"
LC_MESSAGES="${JAVA_LC_MESSAGES:-en_US.UTF-8}"
HOME=

: ${CATALINA_HOME:='/opt/osstech/share/tomcat'}
: ${CATALINA_BASE:='/opt/osstech/var/lib/tomcat'}
: ${CATALINA_OPTS:=''}
: ${TOMCAT_USER:='tomcat'}
: ${TOMCAT_UMASK:=0027}

: ${JAVA_HOME:='/usr/lib/jvm/jre-11-openjdk'}
: ${JAVA_GC:='G1GC'}
: ${JAVA_METASPACESIZE:='256M'}
: ${JAVA_OPTS:=''}
: ${JAVA_TOOL_OPTIONS:=''}
: ${_JAVA_OPTIONS:=''}

: ${JPDA:='false'}
: ${JPDA_TRANSPORT:='dt_socket'}
: ${JPDA_ADDRESS:='8000'}
: ${JPDA_SUSPEND:='n'}
: ${LOGGING_MANAGER:='-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager'}
: ${LOGGING_CONFIG:=''}
: ${SECURITY_MANAGER:='false'}

## ----------------------------------------------------------------------

${TOMCAT_RUN_PRE:+run_or_die source "$TOMCAT_RUN_PRE"}

if [[ -f $tomcat_conf ]]; then
  source "$tomcat_conf" || error "Failed to source the config file: $tomcat_conf" $?
fi

for conf in "$tomcat_conf_dir"/*.conf; do
  if [[ -f $conf ]]; then
    source "$conf" || error "Failed to source the config file: $conf" $?
  fi
done

## ----------------------------------------------------------------------

: ${HOME:="$CATALINA_BASE/data"}
: ${CATALINA_TMPDIR:="$CATALINA_BASE/temp"}
: ${CATALINA_OUT:="$CATALINA_BASE/logs/catalina.out"}
: ${JRE_HOME:="$JAVA_HOME"}
: ${JAVA:="$JRE_HOME/bin/java"}
: ${JPDA_OPTS:="-agentlib:jdwp=transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,suspend=$JPDA_SUSPEND"}

## Backward compatibility with the old tomcat-instance script
if [[ -n ${HEAPSIZE-} && -z ${JAVA_HEAPSIZE-} ]]; then
  JAVA_HEAPSIZE="$HEAPSIZE"
fi

if [[ -z ${JAVA_HEAPSIZE-} ]]; then
  if [[ -f /proc/meminfo ]]; then
    memsize=$(($(sed -E -n 's/^MemTotal: *([0-9]+) kB$/\1/p' /proc/meminfo) / 1024))
    if [[ -n $memsize && $memsize -ge 4096 ]]; then
      JAVA_HEAPSIZE="$((${memsize} * ${JAVA_HEAPSIZE_RATIO:-50} / 100))M"
    fi
  fi
  if [[ -z ${JAVA_HEAPSIZE-} ]]; then
    JAVA_HEAPSIZE='2048M'
  fi
elif [[ $JAVA_HEAPSIZE == *% ]]; then
    JAVA_RAM_PERCENTAGE="${JAVA_HEAPSIZE%\%}"
    JAVA_HEAPSIZE=
fi

if [[ -z ${TOMCAT_GROUP-} && -n $TOMCAT_USER ]]; then
  TOMCAT_GROUP=$(id -gn "$TOMCAT_USER") \
  || error "Failed to detect the primary group of the user: $user" $? \
  ;
fi

CLASSPATH="${CLASSPATH:+$CLASSPATH:}$CATALINA_HOME/bin/bootstrap.jar"
if [[ -f $CATALINA_BASE/bin/tomcat-juli.jar ]]; then
  CLASSPATH="$CLASSPATH:$CATALINA_BASE/bin/tomcat-juli.jar"
else
  CLASSPATH="$CLASSPATH:$CATALINA_HOME/bin/tomcat-juli.jar"
fi

## FIXME: Rename to LOGGING_PROPERTIES? See Fedora tomcat-*
if [[ -z $LOGGING_CONFIG ]]; then
  if [[ -f $CATALINA_BASE/conf/logging.properties ]]; then
    LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties"
  else
    LOGGING_CONFIG="-Dnop"
  fi
fi

## ----------------------------------------------------------------------

TOMCAT_RUN_ARGS=(
  ${TOMCAT_NO_RUN:+true}
  ${TOMCAT_NICE:+nice -n "$TOMCAT_NICE"}
  ${TOMCAT_IONICE:+ionice ${TOMCAT_IONICE_CLASS:+-c "$TOMCAT_IONICE_CLASS"} -n "$TOMCAT_IONICE"}
  env
    -
    LANG="$LANG"
    ${LC_MESSAGES:+LC_MESSAGES="$LC_MESSAGES"}
    ${TZ:+TZ="$TZ"}
    ${PATH:+PATH="$PATH"}
    HOME="$HOME"
    ${JAVA_HOME:+JAVA_HOME="$JAVA_HOME"}
    ${JAVA_TOOL_OPTIONS:+JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS"}
    ${_JAVA_OPTIONS:+_JAVA_OPTIONS="$_JAVA_OPTIONS"}
)

if [[ -n $TOMCAT_USER ]]; then
  uid=$(id -u)
  if [[ $uid -eq 0 ]]; then
    tomcat_uid=$(/usr/bin/id -u "$TOMCAT_USER") \
    || error "Failed to detect the UID of the user: $TOMCAT_USER" $?
    tomcat_gid=$(/usr/bin/id -g "$TOMCAT_GROUP") \
    || error "Failed to detect the GID of the group: $TOMCAT_GROUP" $?
    TOMCAT_RUN_ARGS+=(
      setpriv
	--no-new-privs
	--reuid "$tomcat_uid"
	--regid "$tomcat_gid"
	--clear-groups
      --
    )
  elif [[ $uid != $TOMCAT_USER && $(id -un) != $TOMCAT_USER ]]; then
    error "Cannot switch to user: $TOMCAT_USER"
  fi
fi

TOMCAT_RUN_ARGS+=(
  ${TOMCAT_WRAPPER_COMMAND:+"$TOMCAT_WRAPPER_COMMAND" ${TOMCAT_WRAPPER_OPTIONS-}}
  "$JAVA"
    -Djava.awt.headless=true
    -Djava.security.egd=file:/dev/urandom
    -Djdk.tls.ephemeralDHKeySize=2048
    -XX:-MaxFDLimit
    -XX:+Use"$JAVA_GC"
    -XX:MetaspaceSize="$JAVA_METASPACESIZE"
    ${JAVA_HEAPSIZE:+-Xms"$JAVA_HEAPSIZE"}
    ${JAVA_HEAPSIZE:+-Xmx"$JAVA_HEAPSIZE"}
    ${JAVA_RAM_PERCENTAGE:+-XX:InitialRAMPercentage="$JAVA_RAM_PERCENTAGE"}
    ${JAVA_RAM_PERCENTAGE:+-XX:MaxRAMPercentage="$JAVA_RAM_PERCENTAGE"}
    -classpath "$CLASSPATH"
    -Dcatalina.home="$CATALINA_HOME"
    -Dcatalina.base="$CATALINA_BASE"
    -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
    -Djava.io.tmpdir="$CATALINA_TMPDIR"
    -Dorg.apache.catalina.security.SecurityListener.UMASK="$TOMCAT_UMASK"
    -Duser.home="$HOME"
    "$LOGGING_MANAGER"
    "$LOGGING_CONFIG"
    ${JAVA_OPTS-}
    ${CATALINA_OPTS-}
)

if [[ $JPDA == $TRUE ]]; then
  TOMCAT_RUN_ARGS+=("$JPDA_OPTS")
fi

if [[ $SECURITY_MANAGER == $TRUE ]]; then
  TOMCAT_RUN_ARGS+=(
    -Djava.security.manager
    -Djava.security.policy=="$CATALINA_BASE/conf/catalina.policy"
  )
fi

TOMCAT_RUN_ARGS+=(
    org.apache.catalina.startup.Bootstrap
    start
)

## ======================================================================

run_or_die umask "$TOMCAT_UMASK"
run_or_die cd "${TOMCAT_WORKINGDIR:-$HOME}"

## Seconds
${TOMCAT_LIMIT_CPU:+run_or_die ulimit -t "$TOMCAT_LIMIT_CPU"}
## Bytes
${TOMCAT_LIMIT_FSIZE:+run_or_die ulimit -f "$TOMCAT_LIMIT_FSIZE"}
## Bytes
${TOMCAT_LIMIT_DATA:+run_or_die ulimit -d "$TOMCAT_LIMIT_DATA"}
## Bytes
${TOMCAT_LIMIT_STACK:+run_or_die ulimit -s "$TOMCAT_LIMIT_STACK"}
## Bytes
${TOMCAT_LIMIT_CORE:+run_or_die ulimit -c "$TOMCAT_LIMIT_CORE"}
## Bytes
${TOMCAT_LIMIT_RSS:+run_or_die ulimit -m "$TOMCAT_LIMIT_RSS"}
## Number of File
${TOMCAT_LIMIT_NOFILE:+run_or_die ulimit -n "$TOMCAT_LIMIT_NOFILE"}
## Bytes
${TOMCAT_LIMIT_AS:+run_or_die ulimit -v "$TOMCAT_LIMIT_AS"}
## Number of Processes
${TOMCAT_LIMIT_NPROC:+run_or_die ulimit -u "$TOMCAT_LIMIT_NPROC"}
## Bytes
${TOMCAT_LIMIT_MEMLOCK:+run_or_die ulimit -l "$TOMCAT_LIMIT_MEMLOCK"}
## Number of Locks
${TOMCAT_LIMIT_LOCKS:+run_or_die ulimit -x "$TOMCAT_LIMIT_LOCKS"}
## Number of Queued Signals
${TOMCAT_LIMIT_SIGPENDING:+run_or_die ulimit -i "$TOMCAT_LIMIT_SIGPENDING"}
## Bytes
${TOMCAT_LIMIT_MSGQUEUE:+run_or_die ulimit -q "$TOMCAT_LIMIT_MSGQUEUE"}
## Nice Level
${TOMCAT_LIMIT_NICE:+run_or_die ulimit -e "$TOMCAT_LIMIT_NICE"}
## Realtime Priority
${TOMCAT_LIMIT_RTPRIO:+run_or_die ulimit -r "$TOMCAT_LIMIT_RTPRIO"}

${TOMCAT_RUN_POST:+run_or_die source "$TOMCAT_RUN_POST"}

if [[ -n ${TOMCAT_RUN_DEBUG-} ]]; then
  { umask; pwd; ulimit -a; env; } |debug
fi

## ----------------------------------------------------------------------

java_ver=$("$JAVA" -version 2>&1|sed -n '1s/^[^"]*"\([^"]*\)".*/\1/p')

info "Java version:    $java_ver"
info "JAVA:            $JAVA"
info "JAVA_HOME:       $JAVA_HOME"
info "JRE_HOME:        $JRE_HOME"
info "CLASSPATH:       $CLASSPATH"
info "CATALINA_HOME:   $CATALINA_HOME"
info "CATALINA_BASE:   $CATALINA_BASE"
info "CATALINA_OUT:    $CATALINA_OUT"
info "CATALINA_TMPDIR: $CATALINA_TMPDIR"
info "HOME:            $HOME"

if [[ ! -d $JAVA_HOME ]]; then
  error "Java home directory not found: $JAVA_HOME"
fi
if [[ ! -f $JAVA || ! -x $JAVA ]]; then
  error "Java command not found: $JAVA"
fi

## ----------------------------------------------------------------------

run_or_die exec "${TOMCAT_RUN_ARGS[@]}" >>"$CATALINA_OUT" 2>&1
