#!/usr/bin/bash

export MALLOC_ARENA_MAX=2

add_library_path() {
    location="$1"
    if [ ! "x$location" = "x" ] ; then
        if [ ! "$location" = "/usr" ] ; then
            libdir="$location/lib"
            libdir64="$location/lib64"
            if [ -d "$libdir64" ] ; then
                if [ "x$LD_LIBRARY_PATH" = "x" ]; then
                    LD_LIBRARY_PATH="$libdir64"
                else
                    LD_LIBRARY_PATH="$libdir64:$LD_LIBRARY_PATH"
                fi
            fi
            if [ -d "$libdir" ] ; then
                if [ "x$LD_LIBRARY_PATH" = "x" ]; then
                    LD_LIBRARY_PATH="$libdir"
                else
                    LD_LIBRARY_PATH="$libdir:$LD_LIBRARY_PATH"
                fi
            fi
        fi
    fi
}

prog=arched
RUN=yes

send_systemd_notify() {
    # return if no systemd-notify found
    type systemd-notify >/dev/null 2>&1 || return
    systemd-notify "$@"
}

log_failure_msg() {
    send_systemd_notify --status "Error: $@"
    echo $@
}

# sysconfig files
if [ -r /etc/sysconfig/nordugrid ]; then
    . /etc/sysconfig/nordugrid
elif [ -r /etc/default/nordugrid ]; then
    . /etc/default/nordugrid
fi
if [ -r /etc/sysconfig/arc-arex ]; then
    . /etc/sysconfig/arc-arex
elif [ -r /etc/default/arc-arex ]; then
    . /etc/default/arc-arex
fi

# GLOBUS_LOCATION
GLOBUS_LOCATION=${GLOBUS_LOCATION:-/usr}
if [ -n "$GLOBUS_LOCATION" ]; then
    if [ ! -d "$GLOBUS_LOCATION" ]; then
        log_failure_msg "GLOBUS_LOCATION ($GLOBUS_LOCATION) not found"
        exit 1
    fi
    export GLOBUS_LOCATION
fi

# ARC_LOCATION
ARC_LOCATION=${ARC_LOCATION:-/usr}
if [ ! -d "$ARC_LOCATION" ]; then
    log_failure_msg "ARC_LOCATION ($ARC_LOCATION) not found"
    exit 1
fi
export ARC_LOCATION

# VOMS_LOCATION
VOMS_LOCATION=${VOMS_LOCATION:-@DEFAULT_VOMS_LOCATION@}

# Prepare environment for executing various tools and main application

add_library_path "$VOMS_LOCATION"
add_library_path "$GLOBUS_LOCATION"
if [ "x$LD_LIBRARY_PATH" = "x" ]; then
    LD_LIBRARY_PATH=$ARC_LOCATION/lib64:$ARC_LOCATION/lib6464
else
    LD_LIBRARY_PATH=$ARC_LOCATION/lib64:$ARC_LOCATION/lib6464:$LD_LIBRARY_PATH
fi
export LD_LIBRARY_PATH

testconfigblock() {
    $ARC_LOCATION/libexec/arc/arcconfig-parser --runconfig "$1" --load -b "$2" 2>/dev/null 1>&2
    if [ $? -eq 0 ] ; then
        echo 'true'
    else
        echo 'false'
    fi
}

readorigconfigvar() {
    value=`$ARC_LOCATION/libexec/arc/arcconfig-parser --config "$1" -b "$3" -o "$2" 2>/dev/null`
    if [ $? -eq 0 ] ; then
        echo "$value"
        exit 0
    else
        exit 1
    fi
}

readconfigvar() {
    fname="$1"
    optname="$2"
    blocks=""
    while [ ! -z "$3" ] ; do
        blocks="$blocks -b $3"
        shift
    done
    value=`$ARC_LOCATION/libexec/arc/arcconfig-parser --runconfig "$fname" --load $blocks -o "$optname" 2>/dev/null`
    if [ $? -eq 0 ] ; then
        echo "$value"
        exit 0
    else
        exit 1
    fi
}

# ARC_CONFIG
if [ "x$ARC_CONFIG" = "x" ]; then
    if [ -r $ARC_LOCATION/etc/arc.conf ]; then
        ARC_CONFIG=$ARC_LOCATION/etc/arc.conf
    elif [ -r /etc/arc.conf ]; then
        ARC_CONFIG=/etc/arc.conf
    fi
fi

# PID file
PID_FILE=`readorigconfigvar "$ARC_CONFIG" pidfile arex`
if [ "x$PID_FILE" = "x" ]; then
    # Missing default value for pidfile means no service block is present
    log_failure_msg "ARC configuration is missing [arex] block"
    exit 1
fi

if [ "$1" = "--getpidfile" ] ; then
    echo $PID_FILE
    exit 0
fi

ARC_RUNTIME_CONFIG=`echo "$PID_FILE" | sed 's#\([^\./]*\)\.[^\./]*$#\1#'`
ARC_RUNTIME_CONFIG="${ARC_RUNTIME_CONFIG}.cfg"


mkdir_for_user() {
    dirpath="$1"
    username="$2"
    groupname="$3"

    if [ ! -d "$dirpath" ] ; then
        mkdir -p "$dirpath"
        if [ ! -z "$username" ] ; then
            if [ ! -z "$groupname" ] ; then
                chown "$username:$groupname" "$dirpath"
            else
                chown "$username" "$dirpath"
            fi
        fi
    fi
}

mkfile_for_user() {
    filepath="$1"
    username="$2"
    groupname="$3"

    if [ ! -f "$filepath" ] ; then
        touch "$filepath"
    fi
    if [ ! -z "$username" ] ; then
        if [ ! -z "$groupname" ] ; then
            chown "$username:$groupname" "$filepath"
        else
            chown "$username" "$filepath"
        fi
    fi
}

prepare() {

    CMD="$ARC_LOCATION/sbin/$prog"
    if [ ! -x "$CMD" ]; then
        log_failure_msg "Missing $CMD executable"
        exit 1
    fi

    if [ ! -r "$ARC_CONFIG" ]; then
        log_failure_msg "ARC configuration not found (usually /etc/arc.conf)"
        exit 1
    fi

    # Pre-process configuration
    $ARC_LOCATION/libexec/arc/arcconfig-parser --config "$ARC_CONFIG" --runconfig "$ARC_RUNTIME_CONFIG" --save 2>/dev/null
    if [ $? -ne 0 ] ; then
        log_failure_msg "ARC configuration processing failed"
        exit 1
    fi

    # Creating configuration file of arched
    # Reading following information from config file:
    #  Log file
    #  Debug level
    #  User name
    #  ...

    LOGFILE=`readconfigvar "$ARC_RUNTIME_CONFIG" logfile arex`
    LOGLEVEL=`readconfigvar "$ARC_RUNTIME_CONFIG" loglevel arex`
    WATCHDOG=`readconfigvar "$ARC_RUNTIME_CONFIG" watchdog arex`
    USERNAME=`readconfigvar "$ARC_RUNTIME_CONFIG" user arex`
    GRIDTMPDIR=`readconfigvar "$ARC_RUNTIME_CONFIG" tmpdir arex`
    GROUPNAME=`echo "$USERNAME" | sed 's/^[^:]*//;s/^://'`
    USERNAME=`echo "$USERNAME" | sed 's/:.*//'`
    X509_USER_CERT=`readconfigvar "$ARC_RUNTIME_CONFIG" x509_host_cert common`
    X509_USER_KEY=`readconfigvar "$ARC_RUNTIME_CONFIG" x509_host_key common`
    X509_CERT_POLICY=`readconfigvar "$ARC_RUNTIME_CONFIG" x509_cert_policy common`
    if [ "$X509_CERT_POLICY" = 'any' ] ; then
        X509_CERT_DIR=`readconfigvar "$ARC_RUNTIME_CONFIG" x509_cert_dir common`
    elif [ "$X509_CERT_POLICY" = 'grid' ] ; then
        X509_CERT_DIR=`readconfigvar "$ARC_RUNTIME_CONFIG" x509_cert_dir common`
    else
        X509_CERT_DIR=""
        X509_CERT_POLICY='system'
    fi
    GLOBUS_TCP_PORT_RANGE=`readconfigvar "$ARC_RUNTIME_CONFIG" globus_tcp_port_range arex/data-staging`
    GLOBUS_UDP_PORT_RANGE=`readconfigvar "$ARC_RUNTIME_CONFIG" globus_udp_port_range arex/data-staging`
    HOSTNAME=`readconfigvar "$ARC_RUNTIME_CONFIG" hostname common`
    SERVICEMAIL=`readconfigvar "$ARC_RUNTIME_CONFIG" mail arex`
    # CONTROLDIR=`readconfigvar "$ARC_RUNTIME_CONFIG" controldir arex`
    # It is easier to handle root user through empty value.
    if [ "$USERNAME" = "root" ] ; then
        USERNAME=""
    fi
    if [ "$GROUPNAME" = "root" ] ; then
        GROUPNAME=""
    fi

    # Exporting collected variables
    export X509_USER_CERT
    export X509_USER_KEY
    export X509_CERT_DIR
    export X509_CERT_POLICY
    export GLOBUS_TCP_PORT_RANGE
    export GLOBUS_UDP_PORT_RANGE
    export HOSTNAME
    if [ ! -z "$GRIDTMPDIR" ] ; then export TMPDIR="$GRIDTMPDIR" ; fi

    # Web Service configuration
    arex_endpoint=""
    arex_mount_point=""
    ws_present=`testconfigblock "$ARC_RUNTIME_CONFIG" arex/ws`
    arex_present=`testconfigblock "$ARC_RUNTIME_CONFIG" arex/ws/jobs`
    if [ "$ws_present" = 'true' ] ; then
        WSLOGFILE=`readconfigvar "$ARC_RUNTIME_CONFIG" logfile arex/ws`
        arex_mount_point=`readconfigvar "$ARC_RUNTIME_CONFIG" wsurl arex/ws`
        arex_endpoint="<arex:endpoint>$arex_mount_point</arex:endpoint>"
    fi

    service_mail=""
    if [ ! -z "$SERVICEMAIL" ] ; then
        service_mail="<serviceMail>$SERVICEMAIL</serviceMail>"
    fi

    AREX_CONFIG=`mktemp -t arex.xml.XXXXXX`
    if [ -z "$AREX_CONFIG" ] ; then
        log_failure_msg "Failed to create temporary file"
        exit 1
    fi

    CMD="$CMD -c $AREX_CONFIG"

    case "$LOGLEVEL" in 
        0) LOGLEVEL="FATAL" ;;
        1) LOGLEVEL="ERROR" ;;
        2) LOGLEVEL="WARNING" ;;
        3) LOGLEVEL="INFO" ;;
        4) LOGLEVEL="VERBOSE" ;;
        5) LOGLEVEL="DEBUG" ;;
        *) LOGLEVEL="INFO" ;;
    esac

    mkdir_for_user `dirname "$LOGFILE"` "$USERNAME" "$GROUPNAME"
    mkfile_for_user "$LOGFILE" "$USERNAME" "$GROUPNAME"

    if [ "$WATCHDOG" = "yes" ] ; then
        WATCHDOG="true"
    else
        WATCHDOG="false"
    fi
    if [ ! -z "$USERNAME" ] ; then
        CMD="$CMD -u $USERNAME"
    fi
    if [ ! -z "$GROUPNAME" ] ; then
        CMD="$CMD -g $GROUPNAME"
    fi

    AREXCFG="\
<?xml version=\"1.0\"?>
<ArcConfig
  xmlns=\"http://www.nordugrid.org/schemas/ArcConfig/2007\"
  xmlns:arex=\"http://www.nordugrid.org/schemas/a-rex/Config\">
  <Server>
    <PidFile>$PID_FILE</PidFile>
    <Logger>
      <File>$LOGFILE</File>
      <Level>$LOGLEVEL</Level>
    </Logger>
    <Watchdog>$WATCHDOG</Watchdog>
  </Server>
  <ModuleManager>
    <Path>$ARC_LOCATION/lib64/arc/</Path>
  </ModuleManager>
  <Plugins><Name>arex</Name></Plugins>
  <Chain>
    <Service name=\"a-rex\" id=\"a-rex\">
      $service_mail
      $arex_endpoint
      <arex:gmconfig>$ARC_RUNTIME_CONFIG</arex:gmconfig>
    </Service>
  </Chain>
</ArcConfig>
"

    echo "$AREXCFG" > "$AREX_CONFIG"

    # setup logfile in case it is not there yet
    if [ ! -z "$USERNAME" ] ; then
        if [ ! -z "$GROUPNAME" ] ; then
            [ -f $AREX_CONFIG ] && chown "$USERNAME:$GROUPNAME" "$AREX_CONFIG"
        else
            [ -f $AREX_CONFIG ] && chown "$USERNAME" "$AREX_CONFIG"
        fi
    fi

    # prepare to collect crash information
    COREDIR=`dirname "${LOGFILE}"`/arccore
    mkdir_for_user "${COREDIR}" "$USERNAME" "$GROUPNAME"
    cd "${COREDIR}"
    ulimit -c unlimited
}

validate() {
    CHECK_CMD=$ARC_LOCATION/sbin/arcctl
    if [ ! -x $CHECK_CMD ]; then
        log_failure_msg "Could not find or execute arcctl tool"
        return 1
    fi
    eval "$CHECK_CMD $@ --config $ARC_CONFIG service verify"
    RETVAL=$?
    return $RETVAL
}

if [ "$RUN" != "yes" ] ; then
    echo "a-rex disabled, please adjust the configuration to your needs "
    echo "and then set RUN to 'yes' in /etc/default/a-rex to enable it."
    exit 0
fi

prepare

echo "Validating A-REX setup..." >> "$LOGFILE"
validate >> "$LOGFILE" 2>&1
RETVAL=$?
if [ $RETVAL != 0 ]; then
    # Run validator again to print errors to stdout
    validate -d ERROR
    log_failure_msg "Configuration validation failed"
    exit 1
fi

# if [ -z "$CONTROLDIR" ] ;  then
#     log_failure_msg "Missing controldir in A-REX configuration"
#     exit 1
# fi
# "$ARC_LOCATION/share/arc/update-controldir" "$CONTROLDIR" >> "$LOGFILE"
# if [ $? -ne 0 ]; then
#     log_failure_msg "Failed to update A-REX control dir"
#     exit 1
# fi

# Raise limit on number of file descriptors to max
hlimit=`ulimit -H -n`
if [ ! -z "$hlimit" ] ; then
  ulimit -S -n "$hlimit" 2>/dev/null
fi

now=`date '+[%Y:%m:%d %H:%M:%S]' 2>/dev/null`
echo "$now Starting A-REX service executable..." >> "$LOGFILE"
exec $CMD "$@"
