#!/bin/bash

emitDiagnostic()
{
   if [[ -n "${RSESSION_DIAGNOSTICS_ENABLED}" ]]; then
      echo "[$(date)] $1" >> $RSESSION_DIAGNOSTICS_FILE
   fi
}

getDiagnosticSessionOptions()
{
   if [[ -n "${RSESSION_DIAGNOSTICS_ENABLED}" ]]; then
      # load libSegFault and redirect its backtrace output to our diagnostics file
      echo "env SEGFAULT_SIGNALS='abrt segv' SEGFAULT_OUTPUT_NAME=$RSESSION_SEGFAULT_FILE LD_PRELOAD=$RSESSION_DIAGNOSTICS_LIBSEGFAULT"
   else
      echo ""
   fi
}

getDiagnosticSessionLdd()
{
   if [[ -n "${RSESSION_DIAGNOSTICS_ENABLED}" ]]; then
      echo "echo -e \"[$(date)] ---- ldd output ----\n[$(date)] $(ldd $(dirname ${BASH_SOURCE[0]})/rsession)\" $(getDiagnosticSessionRedirection) &&"
   else
      echo ""
   fi
}

getDiagnosticSessionStraceEnabled()
{
   if [[ -z "${RSESSION_DIAGNOSTICS_STRACE_ENABLED}" ]]; then
      echo "strace not enabled for this diagnostics report"
   elif command -v strace &> /dev/null; then
      echo "strace enabled for this diagnostics report"
      echo "strace report location: $RSESSION_STRACE_FILE"
      echo ""
   else
      echo "strace is not installed; cannot generate strace diagnostics"
   fi
}

getDiagnosticSessionStrace()
{
   if [[ -z "${RSESSION_DIAGNOSTICS_STRACE_ENABLED}" ]]; then
      echo ""
   elif command -v strace &> /dev/null; then
      echo "strace -fttTy -o $RSESSION_STRACE_FILE"
   else
      echo ""
   fi
}

getDiagnosticSessionRedirection()
{
   if [[ -n "${RSESSION_DIAGNOSTICS_ENABLED}" ]]; then
      echo "|& tee -a $RSESSION_DIAGNOSTICS_FILE"
   else
      echo ""
   fi
}

getDiagnosticsPrintenv()
{
   if [[ -n "${RSESSION_DIAGNOSTICS_ENABLED}" ]]; then
      echo "echo -e \"[$(date)] ---- launching rsession process ----\n[$(date)] ---- final env ----\n[$(date)] $(printenv)\" $(getDiagnosticSessionRedirection) &&"
   else
      echo ""
   fi
}

findLibSegFault()
{
   # if the libsegfault location has not explicitly been set
   # try to find it in common distribution locations
   if [[ -z "${RSESSION_DIAGNOSTICS_LIBSEGFAULT}" ]]; then
      if [[ -e /lib/x86_64-linux-gnu/libSegFault.so ]]; then
         RSESSION_DIAGNOSTICS_LIBSEGFAULT=/lib/x86_64-linux-gnu/libSegFault.so
      elif [[ -e /lib/i386-linux-gnu/libSegFault.so ]]; then
         RSESSION_DIAGNOSTICS_LIBSEGFAULT=/lib/i386-linux-gnu/libSegFault.so
      elif [[ -e /lib64/libSegFault.so ]]; then
         RSESSION_DIAGNOSTICS_LIBSEGFAULT=/lib64/libSegFault.so
      elif [[ -e /lib/libSegFault.so ]]; then
         RSESSION_DIAGNOSTICS_LIBSEGFAULT=/lib/libSegFault.so
      fi
   fi
}

# initialize log file path
: ${RSESSION_DIAGNOSTICS_FILE:=/tmp/rsession-diagnostics.log}
RSESSION_STRACE_FILE="$RSESSION_DIAGNOSTICS_FILE.strace"
RSESSION_SEGFAULT_FILE="$RSESSION_DIAGNOSTICS_FILE.segfault"


findLibSegFault

# dump user information
emitDiagnostic "---- user ---- "
emitDiagnostic "$(whoami)"

# dump initial environment
emitDiagnostic "---- init env ----"
emitDiagnostic "$(printenv)"

# load rsession-profile script from all XDG dirs
configDirs="$XDG_CONFIG_DIRS:/etc"
origIFS=$IFS
IFS=':'; read -ra configDirList <<< "$configDirs"
for configDir in "${configDirList[@]}"
do
   if test -e "$configDir/rstudio/rsession-profile"
   then
      . "$configDir/rstudio/rsession-profile"
      emitDiagnostic "---- sourced $configDir/rstudio/rsession-profile ----"
      break
   fi
done
IFS=$origIFS

# load rsession-profile script from RStudio-specific config dir
if test -e "$RSTUDIO_CONFIG_DIR/rsession-profile"
then
    . "$RSTUDIO_CONFIG_DIR/rsession-profile"
    emitDiagnostic "---- sourced $RSTUDIO_CONFIG_DIR/rsession-profile ----"
fi

# load module if specified
if [[ -n "${RSTUDIO_R_MODULE}" ]]; then
   # on some systems, /etc/profile contains important path munging utilities
   # that are required for modules to work, so they need to be imported
   if test -e /etc/profile
   then
      source /etc/profile
      emitDiagnostic "---- sourced /etc/profile ----"
   fi

   # load the modules init script - this defaults to ~/.bashrc if no modules-bin-path
   # was specified in rserver.conf - it is assumed that modules are loaded into the shell
   # via ~/.bashrc in most cases - note that on some systems (like Ubuntu), bashrc is a
   # no-op if run non-interactively, which this script is
   #
   # expand the module script path as it can contain ~ paths
   RSTUDIO_R_MODULE_SCRIPT="${RSTUDIO_R_MODULE_SCRIPT/#\~/$HOME}"
   if test -e "${RSTUDIO_R_MODULE_SCRIPT}"
   then
      source "${RSTUDIO_R_MODULE_SCRIPT}"
      emitDiagnostic "---- sourced ${RSTUDIO_R_MODULE_SCRIPT} ----"
   fi

   module load "${RSTUDIO_R_MODULE}"
   emitDiagnostic "---- loaded module $RSTUDIO_R_MODULE ----"
fi

# source prelaunch script if specified
if [[ -n "${RSTUDIO_R_PRELAUNCH_SCRIPT}" ]]; then
   # expand the prelaunch script as it is possible it could point
   # to an aliased home path
   RSTUDIO_R_PRELAUNCH_SCRIPT="${RSTUDIO_R_PRELAUNCH_SCRIPT/#\~/$HOME}"
   if test -e "${RSTUDIO_R_PRELAUNCH_SCRIPT}"
   then
      source "${RSTUDIO_R_PRELAUNCH_SCRIPT}"
      emitDiagnostic "---- sourced prelaunch script $RSTUDIO_R_PRELAUNCH_SCRIPT ----"
   fi
fi

# session arguments
# escape backslashes in arguments to pass safely to bash below
RSESSION_ARGS="${@//\\/\\\\}"
emitDiagnostic "---- session args ----"
emitDiagnostic "$RSESSION_EXEC_COMMAND + $RSESSION_ARGS"

# dump boot env
emitDiagnostic "---- boot env ----"
emitDiagnostic "$(printenv)"

emitDiagnostic "---- strace ----"
emitDiagnostic "$(getDiagnosticSessionStraceEnabled)"

WWW_REUSE_PORTS="--www-reuse-ports 0"

while true
do
   # run the session
  /bin/bash --login $RSESSION_PROFILE_OPTIONS -c "$(getDiagnosticsPrintenv) $RSESSION_EXEC_COMMAND $(getDiagnosticSessionLdd) $(getDiagnosticSessionOptions) $RSESSION_EXEC_COMMAND $(getDiagnosticSessionStrace) $(dirname ${BASH_SOURCE[0]})/rsession $RSESSION_ARGS $WWW_REUSE_PORTS" $(getDiagnosticSessionRedirection)

  # keep running the session if we are told to continue for suspend and restart
  RSESSION_EXIT_CODE=$?
  if [ "$RSESSION_EXIT_CODE" -ne "102" ]; then
     break
  fi

  emitDiagnostic "---- Launcher session exited with code 102 - restarting ----"

  # make sure when the session restarts it grabs the same bound ports
  WWW_REUSE_PORTS="--www-reuse-ports 1"
done

# dump the session return code and end time
emitDiagnostic "---- exit code ----"
emitDiagnostic "${RSESSION_EXIT_CODE}"

exit ${RSESSION_EXIT_CODE}
