#!/bin/sh
# Copyright 2022 Northern.tech AS
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

set -e

CONFIG=${TEST_CONFIG:-/var/lib/mender-configure/device-config.json}
APPLY_DIR=${TEST_APPLY_DIR:-/usr/lib/mender-configure/apply-device-config.d}
DEFAULT_PERMISSIONS="0600"

STATE="$1"
FILES="$2"

# Primarily used by tests, but can be enabled by anyone.
QUIET=${QUIET:-0}

BACKUP="$FILES/tmp/device-config-backup.json"

# create the configuration directory if it doesn't exist
CONFIG_DIR=$(dirname "$CONFIG")
if ! [ -d "$CONFIG_DIR" ]; then
    mkdir -p "$CONFIG_DIR"
fi

safe_copy() {
    if [ -n "$3" ]; then
        echo "safe_copy can only handle one file copy at a time" 1>&2
        exit 2
    fi
    touch "$2".tmp
    chmod $DEFAULT_PERMISSIONS "$2".tmp
    cat "$1" > "$2".tmp
    sync "$2".tmp
    mv "$2".tmp "$2"
    sync "$(dirname "$2")"
}

apply_scripts() {
    global_return_code=0
    for script in "$APPLY_DIR"/*; do
        if [ "$script" = "$APPLY_DIR/*" ]; then
            # No files present, glob failed and returned verbatim '*'.
            exit 0
        fi

        if [ "$QUIET" = 0 ]; then
            echo "Executing $script"
        fi
        return_code=0
        "$script" "$CONFIG" || return_code=$?
        if [ $return_code -ne 0 ]; then
            # Set the overall return code, but prioritize real errors over
            # "reboot return code" (20).
            if [ $return_code -ne 20 ] || [ $global_return_code -eq 0 ]; then
                global_return_code=$return_code
            fi
            echo "Script \"$script\" returned exit code $return_code." 1>&2
        fi
    done

    return $global_return_code
}

case "$STATE" in

    --apply-only)
        # Special mode when called during startup.
        apply_scripts
        ;;

    SupportsRollback)
        echo "Yes"
        ;;

    ArtifactInstall)
        if [ -e "$CONFIG" ]; then
            safe_copy "$CONFIG" "$BACKUP"
        else
            touch "$FILES/tmp/no-original"
            sync "$FILES/tmp/no-original"
            sync "$FILES/tmp"
        fi
        safe_copy "$FILES/header/meta-data" "$CONFIG"
        RET=0
        apply_scripts || RET=$?
        if [ $RET -eq 20 ]; then
            touch "$FILES/tmp/needs-reboot"
            sync "$FILES/tmp/needs-reboot"
            sync "$FILES/tmp"
            exit 0
        else
            exit $RET
        fi
        ;;

    NeedsArtifactReboot)
        if [ -e "$FILES/tmp/needs-reboot" ]; then
            echo "Automatic"
        else
            echo "No"
        fi
        ;;

    ArtifactRollback)
        if [ -e "$FILES/tmp/no-original" ]; then
            # There was no preexisting configuration. Nothing to restore.
            rm -f "$CONFIG"
            sync "$(dirname "$CONFIG")"
            exit 0
        elif ! [ -e "$BACKUP" ]; then
            # The update was interrupted before we could make a backup: Nothing
            # to do.
            exit 0
        fi
        safe_copy "$BACKUP" "$CONFIG"
        RET=0
        apply_scripts || RET=$?
        if [ $RET -eq 20 ]; then
            touch "$FILES/tmp/needs-reboot"
            sync "$FILES/tmp/needs-reboot"
            sync "$FILES/tmp"
            exit 0
        else
            exit $RET
        fi
        ;;

esac

exit 0

