#!/bin/bash
# Copyright (c) 2019 Huawei Technologies Co., Ltd. All rights reserved.
# This script reads options and runs ExaGear.

EXAGEAR_ROOT_DIR="$(dirname "$(realpath "${BASH_SOURCE}")")"/..
EXAGEAR_ROOT_DIR="$(realpath "${EXAGEAR_ROOT_DIR}")"

. ${EXAGEAR_CORE_CONF}
. ${EXAGEAR_GUEST_CONF}

# Number of reserved FDs (must be >= kHifdReserve)
RESERVED_FD_COUNT=8
REQUIRED_FD_LIMIT=$((EXAGEAR_FD_HARD_LIMIT + RESERVED_FD_COUNT))
if [ `ulimit -Hn` -lt $REQUIRED_FD_LIMIT ] # Limit is too low
then
    if ! ulimit -Hn $REQUIRED_FD_LIMIT 2>/dev/null # Try to rise it
    then
        # Reserved FDs + leave some minimum (16) FDs for guest
        if [ `ulimit -Hn` -lt $((RESERVED_FD_COUNT + 16)) ]
        then
            echo "Error: open files limit (nofile) must be >= $((RESERVED_FD_COUNT + 16))"
            exit 1
        fi

        # Failed to rise, reduce guest FD limit
        EXAGEAR_FD_HARD_LIMIT=$((`ulimit -Hn` - RESERVED_FD_COUNT))
    fi
fi

. ${EXAGEAR_ROOT_DIR}/bin/ubt-make-opt-cmdline

IMAGE_DIR=${EXAGEAR_ROOT_DIR}/images/${EXAGEAR_GUEST_IMAGE_NAME}
VPATHS_LIST="${IMAGE_DIR}/.exagear/vpaths-list"
OPATHS_LIST="${IMAGE_DIR}/.exagear/opaths-list"
UTMP_LIST="${IMAGE_DIR}/.exagear/utmp-list"

if [ "${EXAGEAR_USE_OPT}" == "y" ]
then
    if [ ! -z "${EXAGEAR_OPT_SOCKET}" -a \( -z "${EXAGEAR_IN_CONTAINER}" -o "${EXAGEAR_IN_CONTAINER}" == "n" \) ]
    then
        if [ ! -S "${EXAGEAR_OPT_SOCKET}" ]
        then
            echo "ExaGear optimizer socket ${EXAGEAR_OPT_SOCKET} doesn't exist! Enable optimizer service or disable optimizer in config."
            exit 1
        fi
    else
        if [ ! -f "${EXAGEAR_OPT_BINARY}" ]
        then
            echo "ExaGear optimizer binary ${EXAGEAR_OPT_BINARY} doesn't exist! Reinstall ExaGear or disable optimizer in config."
            exit 1
        fi
    fi
fi

if ${EXAGEAR_ROOT_DIR}/bin/exagear-manage binfmt_misc ${EXAGEAR_GUEST_ARCH_NAME} status
then
    SUGID_EXEC_METHOD="--use-binfmt-misc"
fi

C=''
for i in "$@"; do
    i="${i//\\/\\\\}"
    C="$C \"${i//\"/\\\"}\""
done
CMDLINE_OPTS=`exagear_make_opt_cmdline`


if [ `cat /proc/sys/kernel/perf_event_paranoid` -ge 3 ]
then
    echo "Failed to start exagear. /proc/sys/kernel/perf_event_paranoid == $(cat /proc/sys/kernel/perf_event_paranoid) but it must be <= 2."
    exit 1
fi

if [ "${EXAGEAR_IN_CONTAINER}" == "y" ]
then
    # In this mode we make flat rootfs by combining guest image and parts of host rootfs
    # using bwrap and run UBT in resulting container.

    if ! command -v bwrap 2>&1 >/dev/null; then
        echo -e "\nBubblewrap (bwrap) is required to run ExaGear in container mode."
        echo "Please install Bubblewrap package."
        exit 1
    fi

    EXAGEAR_UBT_BINARY=`realpath "${EXAGEAR_UBT_BINARY}"`
    EXAGEAR_BIN_PATH=`dirname "${EXAGEAR_UBT_BINARY}"`
    EXAGEAR_RUN_PATH=`dirname "${EXAGEAR_OPT_SOCKET}"`

    EXAGEAR_CONT_BIN="/.exagear/bin"
    EXAGEAR_CONT_RUN="/.exagear/run"

    if [ ! -e "${IMAGE_DIR}${EXAGEAR_CONT_BIN}" ]; then
        echo -e "\nDirectory ${IMAGE_DIR}${EXAGEAR_CONT_BIN} doesn't exist, probably you're using old guest image."
        echo "Please create ${IMAGE_DIR}${EXAGEAR_CONT_BIN} or install latest guest image."
        exit 1
    fi
    if [ ! -e "${IMAGE_DIR}${EXAGEAR_CONT_RUN}" ]; then
        echo -e "\nDirectory ${IMAGE_DIR}${EXAGEAR_CONT_RUN} doesn't exist, probably you're using old guest image."
        echo "Please create ${IMAGE_DIR}${EXAGEAR_CONT_RUN} or install latest guest image."
        exit 1
    fi

    # Path to main UBT binary in rootfs
    EXAGEAR_UBT_BINARY="${EXAGEAR_CONT_BIN}/`basename ${EXAGEAR_UBT_BINARY}`"

    CMDLINE_OPTS=$(sed "s#${EXAGEAR_BIN_PATH}#${EXAGEAR_CONT_BIN}#g" <<< ${CMDLINE_OPTS})
    CMDLINE_OPTS=$(sed "s#${EXAGEAR_RUN_PATH}#${EXAGEAR_CONT_RUN}#g" <<< ${CMDLINE_OPTS})

    # Bind guest image as rootfs
    BIND_ARGS="--bind ${IMAGE_DIR} /"
    # Bind ExaGear's 'bin' dir to ${EXAGEAR_CONT_BIN}
    BIND_ARGS+=" --ro-bind ${EXAGEAR_BIN_PATH} ${EXAGEAR_CONT_BIN}"
    BIND_ARGS+=" --ro-bind ${EXAGEAR_RUN_PATH} ${EXAGEAR_CONT_RUN}"

    # Bind everything from vpaths_list to rootfs
    while read p
    do
    if [ -e "$p" ]; then
        # /dev/ will be mounted separately below
        if [ "$p" != "/dev/" ]; then
            BIND_ARGS+=" --bind $p $p"
        fi
    fi
    done < ${VPATHS_LIST}

    # Make bwrap command, add /proc and /dev mounts
    BWRAP_PREFIX="bwrap ${BIND_ARGS} --proc /proc --dev-bind /dev /dev -- "

    CMDLINE_OPTS+=" --vfs-kind host-first"

    # Run UBT in container
    exec ${BWRAP_PREFIX} ${EXAGEAR_UBT_BINARY} ${CMDLINE_OPTS} -- /bin/bash -c  "${C}"
fi

exec ${EXAGEAR_UBT_BINARY} --path-prefix ${IMAGE_DIR} --utmp-paths-list ${UTMP_LIST} --vpaths-list ${VPATHS_LIST} --opaths-list ${OPATHS_LIST} ${SUGID_EXEC_METHOD} ${CMDLINE_OPTS} -- \
/bin/bash -c  "${C}"
