#!/bin/sh
set -eu
# bees systemd wrapper
# See README.Debian for details
#
# Copyright 2021 Alexander Gerasiov <a@gerasiov.net>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


DEBUG=${DEBUG:-0}
SCRIPT_NAME=$(basename "$0")

# Prints usage
usage() {
    echo "$SCRIPT_NAME: bees systemd runner" >&2
    echo "prepares environment for bees daemon" >&2
    echo "Usage:" >&2
    echo "$SCRIPT_NAME [--verbose] <instance>" >&2
    echo "  <instance>    - daemon instance (filesystem uuid in common)" >&2
}

debug() {
    [ "$DEBUG" -eq 1 ] && echo "$SCRIPT_NAME: $*" >&2
    return 0
}

error() {
    echo "$SCRIPT_NAME: $*" >&2
    return 0
}

# Parse args
# Input - all scripts positional params
# Output:
#   DEBUG
argparse() {
    local TEMP
    local PARSE_ERROR
    PARSE_ERROR=0

    TEMP=$(getopt -o v --long verbose,help --name "$0" -- "$@") || PARSE_ERROR=$?
    eval set -- "$TEMP"

    while true; do
        case "$1" in
        --help)
            usage
            exit 0
            ;;
        -v|--verbose)
            DEBUG=1
            shift
            ;;
        --)
            shift
            break
            ;;
        *)
            error "Unknown option: $1"
            PARSE_ERROR=1
            ;;
        esac
    done

    if [ $# -ge 1 ]; then
        INSTANCE="$1"
        shift
    else
        error "uuid/disk not set."
        PARSE_ERROR=1
    fi

    if [ $# -ne 0 ]; then
        error "Unsupported parameters: $*"
        PARSE_ERROR=1
    fi

    if [ $PARSE_ERROR -ne 0 ]; then
        usage
        exit 1
    fi
    return 0
}

argparse "$@"

# default variable
# had to move it here to allow `bees-runner --help` to work without $RUNTIME_DIRECTORY
DEFAULT_ROOT="$RUNTIME_DIRECTORY/mount"
DEFAULT_BEESHOME="$DEFAULT_ROOT/.beeshome"
DEFAULT_VERBOSITY=5
DEFAULT_DAEMON_OPTIONS="--no-timestamps"
DEFAULT_DB_SIZE=1G

CONFIG_DIR="/etc/bees"
BEES_EXECUTABLE="/sbin/bees"


source_config() {
    local CONFIG_FILE="$1"

    if [ -e "$CONFIG_FILE" ]; then
        debug "$CONFIG_FILE exists, sourcing it..."
        . "$CONFIG_FILE"
    fi
    return 0
}

check_vars() {
    : "$INSTANCE"
    : "${UUID:=$INSTANCE}"
    : "${BEESHOME:=$DEFAULT_BEESHOME}"
    : "${ROOT:=$DEFAULT_ROOT}"
    : "${DB_SIZE:=$DEFAULT_DB_SIZE}"
    : "${VERBOSITY:=$DEFAULT_VERBOSITY}"
    : "${DAEMON_OPTIONS:=$DEFAULT_DAEMON_OPTIONS}"

    debug "INSTANCE=$INSTANCE"
    debug "UUID=$UUID"
    debug "BEESHOME=$BEESHOME"
    debug "ROOT=$ROOT"
    debug "DB_SIZE=$DB_SIZE"
    debug "VERBOSITY=$VERBOSITY"
    debug "DAEMON_OPTIONS=$DAEMON_OPTIONS"

    return 0
}

get_device() {
    local DEVICE=$(blkid --uuid "$UUID")
    if [ -z "$DEVICE" ]; then
        error "Could not find device with uuid $UUID."
        return 1
    fi
    local FS_TYPE=$(blkid --match-tag TYPE --output value "$DEVICE")
    if [ "$FS_TYPE" != "btrfs" ]; then
        error "Device $DEVICE fs type is $FS_TYPE but not btrfs."
        return 1
    fi
    echo "$DEVICE"
    return 0
}

check_root_mountpoint() {
    if [ "$ROOT" = "$DEFAULT_ROOT" ]; then
        mountpoint -q "$ROOT" && umount "$ROOT"
        DEVICE=$(get_device)
        mkdir -p "$ROOT"
        mount -t btrfs --make-private -osubvolid=5 "$DEVICE" "$ROOT"
    fi
    return 0
}

check_beeshome() {
    if [ "$BEESHOME" = "$DEFAULT_BEESHOME" ]; then
        if [ ! -d "$BEESHOME" ]; then
            btrfs subvolume create "$BEESHOME"
        elif ! btrfs subvolume show "$BEESHOME" > /dev/null; then
            error "$BEESHOME is not a subvolume"
            return 1
        fi
    else
        debug "BEESHOME is overridden in config"
        mkdir -p "$BEESHOME"
    fi
    return 0
}

check_database() {
    local DATABASE="$BEESHOME/beeshash.dat"
    touch "$DATABASE"
    local ORIG_SIZE=$(stat --format=%s "$DATABASE")
    truncate -s "$DB_SIZE" "$DATABASE"
    local NEW_SIZE=$(stat --format=%s "$DATABASE")
    if [ "$ORIG_SIZE" != "$NEW_SIZE" ]; then
        debug "Database size changed, removing crawler state file."
        rm -f "$BEESHOME/beescrawl.dat"
    fi
    return 0
}

exec_bees() {
    export BEESHOME
    export BEESSTATUS
    exec "$BEES_EXECUTABLE" $DAEMON_OPTIONS -v "$VERBOSITY" "$ROOT"
}

argparse "$@"
source_config "$CONFIG_DIR/bees.conf"
source_config "$CONFIG_DIR/$INSTANCE.conf"
check_vars
check_root_mountpoint
check_beeshome
check_database

exec_bees
