#!/usr/bin/env bash
# shellcheck disable=SC1004

# saptune update helper script
# upd_helper is called by post script of saptune package installation to
# update the SAP Note name changes between SLE12 and SLE15 in the
# configuration files, saved state files or in the name of the configuration
# files
# only called in postinstallation, if it is a package update
# NOT called, if it is an initial package installation

# upd_helper v1tov2pi
# upd_helper v1tov2pt
# upd_helper sle12to15pt
# upd_helper cleanup
# upd_helper staging

if [ "$1" == "" ]; then
    echo "ERROR: missing argument"
    exit 1
else
    upd_opt="$1"
fi

SAPTUNE_SYSCONFIG=/etc/sysconfig/saptune
CUSTOM_TUNED_CONF=/etc/tuned/saptune/tuned.conf

OVERRIDEDIR=/etc/saptune/override
OLD_SAVEDSTATEDIR=/var/lib/saptune/saved_state
SAVEDSTATEDIR=/run/saptune/saved_state
OLD_PARAMETERSTATEDIR=/var/lib/saptune/parameter
PARAMETERSTATEDIR=/run/saptune/parameter
SECTIONSTATEDIR=/run/saptune/sections

WORKINGAREA=/var/lib/saptune/working
STAGINGAREA=/var/lib/saptune/staging
PACKAGEAREA=/usr/share/saptune

NOTEDIR=/usr/share/saptune/notes
NOTES2CHANGE_12to15="1984787,2578899 2205917,2684254"
NOTES2DELETE_15="1557506 1275776"

set_sysconfig_version() {
    # add or change SAPTUNE_VERSION string in /etc/sysconfig/saptune to "1"
    if (grep "SAPTUNE_VERSION[[:space:]]*=" $SAPTUNE_SYSCONFIG >/dev/null 2>&1); then
        sed -i 's/SAPTUNE_VERSION="[23]"/SAPTUNE_VERSION="1"/' $SAPTUNE_SYSCONFIG
    else
        echo "missing SAPTUNE_VERSION string in /etc/sysconfig/saptune. Appending ..."
        echo -e "## Type:    string\n## Default: \"3\"\n#\n# Version of saptune\nSAPTUNE_VERSION=\"1\"\n" >> $SAPTUNE_SYSCONFIG
    fi
}

create_tuned_conf() {
    # add 'old' cpu section to tuned.conf for compatibility reasons
    # if a custom tuned.conf file exists, do nothing.
    if [ ! -f $CUSTOM_TUNED_CONF ]; then
        echo "create custom file '$CUSTOM_TUNED_CONF' for compatibility support of saptune version 1"
        echo "see man saptune(8) and saptune-migrate(7) for more information"
        mkdir -p /etc/tuned/saptune
        cp /usr/lib/tuned/saptune/tuned.conf $CUSTOM_TUNED_CONF
	# add description
	sed -i '/^\[main\]/i\
#\
# for compatibility support of saptune version 1 the tuned config script\
# /usr/lib/tuned/saptune/tuned.conf is copied to /etc/tuned/saptune/tuned.conf\
# during the saptune package update from rpm version 1* to version 3*\
# ATTENTION: saptune version 3 (SAPTUNE_VERSION=3 in /etc/sysconfig/saptune)\
# does not use tuned service any longer\
# Please migrate to saptune version 3 as soon as possible\
#\
' $CUSTOM_TUNED_CONF
        # add cpu section
        sed -i '/^\[script\]/i\
[cpu]\
#cpu section added by saptune package installation during package update from version1 to version2\
#stv1tov2#\
governor=performance\
energy_perf_bias=performance\
min_perf_pct=100\
force_latency = 70\
' $CUSTOM_TUNED_CONF
        # use absolute pathname for script
        sed -i 's%script.sh%/usr/lib/tuned/saptune/script.sh%' $CUSTOM_TUNED_CONF
    fi
}

get_back_extra_ASE_BOBJ() {
    # check for extra files needed for the v1tov2 migration
    # get back custom note definition files for BOBJ and/or ASE
    # needed for migration, if customer had applied these notes
    if [ -f /etc/saptune/extra/SAP_BOBJ_n2c.conf ]; then
        mv /etc/saptune/extra/SAP_BOBJ_n2c.conf /etc/saptune/extra/SAP_BOBJ-SAP_Business_OBJects.conf || :
    fi
    if [ -f /etc/saptune/extra/SAP_ASE_n2c.conf ]; then
        mv /etc/saptune/extra/SAP_ASE_n2c.conf /etc/saptune/extra/SAP_ASE-SAP_Adaptive_Server_Enterprise.conf || :
    fi
}

change_note_names() {
    OIFS=$IFS
    for notepair in $NOTES2CHANGE_12to15; do
        IFS=","
        # shellcheck disable=SC2086
        set -- $notepair
        oldNote=$1
        newNote=$2
        IFS=$OIFS
        if [ ! -f ${NOTEDIR}/"${oldNote}" ] && [ -f ${NOTEDIR}/"${newNote}" ]; then
            # the old note definition name is NOT available, but the new one
            # so update from SLE12 to SLE15
            # change config

            # 1. change variable TUNE_FOR_NOTES and NOTE_APPLY_ORDER in /etc/sysconfig/saptune
            # " ${oldNote} " or " ${oldNote}\"" or "\"${oldNote}\""
            # srch_pat="[ \"]${oldNote}[ \"]"
            srch_pat1="[ ]${oldNote}[ ]"
            new_pat1=" ${newNote} "
            if grep "$srch_pat1" $SAPTUNE_SYSCONFIG >/dev/null 2>&1; then
                echo "### changing old, SLE12 specific Note name '$oldNote' to the new, SLE15 Note name '$newNote'"
                sed -i "s/$srch_pat1/$new_pat1/g" $SAPTUNE_SYSCONFIG
            fi
            srch_pat2=" ${oldNote}\""
            new_pat2=" ${newNote}\""
            if grep "$srch_pat2" $SAPTUNE_SYSCONFIG >/dev/null 2>&1; then
                echo "### changing old, SLE12 specific Note name '$oldNote' to the new, SLE15 Note name '$newNote'"
                sed -i "s/$srch_pat2/$new_pat2/g" $SAPTUNE_SYSCONFIG
            fi
            srch_pat3="\"${oldNote} "
            new_pat3="\"${newNote} "
            if grep "$srch_pat3" $SAPTUNE_SYSCONFIG >/dev/null 2>&1; then
                echo "### changing old, SLE12 specific Note name '$oldNote' to the new, SLE15 Note name '$newNote'"
                sed -i "s/$srch_pat3/$new_pat3/g" $SAPTUNE_SYSCONFIG
            fi
            srch_pat4="\"${oldNote}\""
            new_pat4="\"${newNote}\""
            if grep "$srch_pat4" $SAPTUNE_SYSCONFIG >/dev/null 2>&1; then
                echo "### changing old, SLE12 specific Note name '$oldNote' to the new, SLE15 Note name '$newNote'"
                sed -i "s/$srch_pat4/$new_pat4/g" $SAPTUNE_SYSCONFIG
            fi

            # 2. check existence of override file and change name
            if [ -f ${OVERRIDEDIR}/"$oldNote" ]; then
                echo "### mv old override filename '${OVERRIDEDIR}/$oldNote' to new filename '${OVERRIDEDIR}/$newNote'"
                echo "WARNING: the header information in section [version] will NOT be adapted. So it will show the old SAP Note name and the related information"
                mv ${OVERRIDEDIR}/"$oldNote" ${OVERRIDEDIR}/"$newNote"
            fi

            # 3. check existence of saved_state file and change name
            if [ -f ${SAVEDSTATEDIR}/"$oldNote" ]; then
                echo "### mv old saved state file to the new name"
                mv ${SAVEDSTATEDIR}/"$oldNote" ${SAVEDSTATEDIR}/"$newNote"
            fi

            # 4. check, if old note name is available in any parameter saved state file
            srch_pat="\"${oldNote}\""
            new_pat="\"${newNote}\""
            if grep "$srch_pat" "${PARAMETERSTATEDIR}"/* >/dev/null 2>&1; then
                echo "### changing the parameter saved state files"
            fi
            for pfile in "${PARAMETERSTATEDIR}"/*; do
                if grep "$srch_pat" "$pfile" >/dev/null 2>&1; then
                    sed -i "s/$srch_pat/$new_pat/g" "$pfile"
                fi
            done

            # 5. check existence of section state file and change name
            if [ -f ${SECTIONSTATEDIR}/"$oldNote".sections ]; then
                echo "### mv old section state file to the new name"
                mv ${SECTIONSTATEDIR}/"$oldNote".sections ${SECTIONSTATEDIR}/"$newNote".sections
            fi
        #else
            # if both note files are available - not possible, rpm should cover
            # if both note files NOT available - not possible, rpm should cover
            # if oldNote is available, but newNote not
            #    still on SLE12, no update from 12 to 15, so nothing to do
        fi
    done
}

delete_notes() {
    for delnote in $NOTES2DELETE_15; do
        if [ ! -f ${NOTEDIR}/"${delnote}" ]; then
            # 1. delete Note from variable TUNE_FOR_NOTES and NOTE_APPLY_ORDER in /etc/sysconfig/saptune
            # " ${delnote} " or " ${delnote}\"" or "\"${delnote}\""
            # srch_pat="[ \"]${delnote}[ \"]"
            srch_pat1="[ ]${delnote}[ ]"
            del_pat1=" "
            if grep "$srch_pat1" $SAPTUNE_SYSCONFIG >/dev/null 2>&1; then
                echo "### removing old, SLE12 specific Note name '$delnote' from $SAPTUNE_SYSCONFIG"
                sed -i "s/$srch_pat1/$del_pat1/g" $SAPTUNE_SYSCONFIG
            fi
            srch_pat2=" ${delnote}\""
            del_pat2="\""
            if grep "$srch_pat2" $SAPTUNE_SYSCONFIG >/dev/null 2>&1; then
                echo "### removing old, SLE12 specific Note name '$delnote' from $SAPTUNE_SYSCONFIG"
                sed -i "s/$srch_pat2/$del_pat2/g" $SAPTUNE_SYSCONFIG
            fi
            srch_pat3="\"${delnote} "
            del_pat3="\""
            if grep "$srch_pat3" $SAPTUNE_SYSCONFIG >/dev/null 2>&1; then
                echo "### removing old, SLE12 specific Note name '$delnote' from $SAPTUNE_SYSCONFIG"
                sed -i "s/$srch_pat3/$del_pat3/g" $SAPTUNE_SYSCONFIG
            fi
            srch_pat4="\"${delnote}\""
            del_pat4="\"\""
            if grep "$srch_pat4" $SAPTUNE_SYSCONFIG >/dev/null 2>&1; then
                echo "### removing old, SLE12 specific Note name '$delnote' from $SAPTUNE_SYSCONFIG"
                sed -i "s/$srch_pat4/$del_pat4/g" $SAPTUNE_SYSCONFIG
            fi

            # 2. check existence of override file and print a WARNING
            if [ -f ${OVERRIDEDIR}/"$delnote" ]; then
                echo "WARNING: override file '${OVERRIDEDIR}/$delnote' exists, but Note definition is no longer supported."
                echo "Please check and remove superfluous file"
            fi

            # 3. check existence of saved_state file and remove file
            # normally shouldn't be available
            if [ -f ${SAVEDSTATEDIR}/"$delnote" ]; then
                echo "WARNING: old saved state file '${SAVEDSTATEDIR}/$delnote' found, removing superfluous file."
                rm ${SAVEDSTATEDIR}/"$delnote"
            fi

            # 4. check existence of sections state file and remove file
            # normally shouldn't be available
            if [ -f ${SECTIONSTATEDIR}/"$delnote".sections ]; then
                echo "WARNING: old sections state file '${SECTIONSTATEDIR}/${delnote}.sections' found, removing superfluous file."
                rm ${SECTIONSTATEDIR}/"$delnote".sections
            fi
        fi
    done
}

adjust_workingarea() {
    # called from the postinstall script of saptune to adjust the working area
    # during a major release update (like 12 to 15)
    # only needed, if staging is active. If not, postinstall of package is
    # updating the working area
    upd12to15="false"
    OIFS=$IFS
    for notepair in $NOTES2CHANGE_12to15; do
        IFS=","
        # shellcheck disable=SC2086
        set -- $notepair
        oldNote=$1
        newNote=$2
        IFS=$OIFS
        if [ ! -f ${NOTEDIR}/"${oldNote}" ] && [ -f ${NOTEDIR}/"${newNote}" ]; then
            # the old note definition name is NOT available, but the new one
            # so update from SLE12 to SLE15
            if [ -n "${oldNote}" ] && [ -f ${WORKINGAREA}/notes/"${oldNote}" ]; then
                echo "### removing old sle12 note '${oldNote}' from working area"
                rm -rf ${WORKINGAREA}/notes/${oldNote}
            fi
            if [ -n "${newNote}" ] && [ ! -f ${WORKINGAREA}/notes/"${newNote}" ]; then
                echo "### adding new sle15 note '${newNote}' from package area to working area"
                cp ${NOTEDIR}/"${newNote}" ${WORKINGAREA}/notes
            fi

            # adjust solution files
            for wsol in ${WORKINGAREA}/sols/*; do
                srch_pat1="[[:space:]]${oldNote}[[:space:]]"
                new_pat1=" ${newNote} "
                if grep "$srch_pat1" $wsol >/dev/null 2>&1; then
                    echo "### changing old, SLE12 specific Note name '$oldNote' to the new, SLE15 Note name '$newNote' in solution '$wsol'"
                    sed -i "s/$srch_pat1/$new_pat1/g" $wsol
                fi
                srch_pat2="[[:space:]]${oldNote}$"
                new_pat2=" ${newNote}"
                if grep "$srch_pat2" $wsol >/dev/null 2>&1; then
                    echo "### changing old, SLE12 specific Note name '$oldNote' to the new, SLE15 Note name '$newNote' in solution '$wsol'"
                    sed -i "s/$srch_pat2/$new_pat2/g" $wsol
                fi
                srch_pat3="^${oldNote}[[:space:]]"
                new_pat3="${newNote} "
                if grep "$srch_pat3" $wsol >/dev/null 2>&1; then
                    echo "### changing old, SLE12 specific Note name '$oldNote' to the new, SLE15 Note name '$newNote' in solution '$wsol'"
                    sed -i "s/$srch_pat3/$new_pat3/g" $wsol
                fi
            done
        fi
    done

    for delnote in $NOTES2DELETE_15; do
        if [ ! -f ${NOTEDIR}/"${delnote}" ]; then
            if [ -n "${delnote}" ] && [ -f ${WORKINGAREA}/notes/"${delnote}" ]; then
                echo "### removing no longer supported note '${delnote}' from working area"
                rm -rf ${WORKINGAREA}/notes/${delnote}
            fi
            # adjust solution files - not needed yet
        fi
    done
}

cleanup_savestates() {
    # cleanup older, no longer handled savedState files
    param_filelist="/var/lib/saptune/parameter/IO_SCHEDULER_sr* /var/lib/saptune/parameter/IO_SCHEDULER_dm-*"
    for i in $param_filelist ; do
        [ -f "$i" ] && rm -f "$i"
    done
    sle_vers=$(sed -n "s%.*baseversion>\(.*\)</base.*%\1%p" /etc/products.d/baseproduct)
    [[ $sle_vers != 12 ]] && rm -f /var/lib/saptune/parameter/UserTasksMax
    [[ $sle_vers != 12 ]] && rm -f /etc/systemd/logind.conf.d/saptune-UserTasksMax.conf

    # move saved state files to /run
    if [ ! -d /run/saptune ]; then
        mkdir -p /run/saptune
    fi
    if [ -d "$OLD_PARAMETERSTATEDIR" ]; then
        mv "$OLD_PARAMETERSTATEDIR" "$PARAMETERSTATEDIR"
    fi
    if [ -d "$OLD_SAVEDSTATEDIR" ]; then
        mv "$OLD_SAVEDSTATEDIR" "$SAVEDSTATEDIR"
    fi
}

copy_packednotes2staging() {
    # called from the postinstall script of saptune to handle the staging area
    # check for changed or new notes
    for pnote in ${PACKAGEAREA}/notes/*; do
        note=${pnote##*/}
        if [ -f ${WORKINGAREA}/notes/${note} ]; then
            md5_packed_note=$(/usr/bin/md5sum $pnote | awk '{print $1}')
            md5_working_note=$(/usr/bin/md5sum ${WORKINGAREA}/notes/${note} | awk '{print $1}')
            # check for unchanged notes
            if [ "$md5_packed_note" == "$md5_working_note" ]; then
                # ignore unchanged notes
                continue
            fi
            # check for changed notes
            if [ "$md5_packed_note" != "$md5_working_note" ]; then
                # copy changed note from package area to staging area
                cp $pnote ${STAGINGAREA}/latest
            fi
        else
            # found new note
            # copy new note from package area to staging area
            cp $pnote ${STAGINGAREA}/latest
        fi
    done
    # check for deleted notes
    # available in working area but not in package area
    for wnote in ${WORKINGAREA}/notes/*; do
        note=${wnote##*/}
        if [ ! -f ${PACKAGEAREA}/notes/${note} ]; then
            # note deleted in the current installed package
            # create a note file in staging area, which only contains the
            # version information of the 'old' note
            # as a flag for a later removal from the working area
            grep '# .*VERSION=.*DATE=.*NAME=".*"' ${wnote} > ${STAGINGAREA}/latest/${note}
        fi
    done
    # check for changed or new solutions
    for psol in ${PACKAGEAREA}/sols/*; do
        sol=${psol##*/}
        if [ -f ${WORKINGAREA}/sols/${sol} ]; then
            md5_packed_sol=$(/usr/bin/md5sum $psol | awk '{print $1}')
            md5_working_sol=$(/usr/bin/md5sum ${WORKINGAREA}/sols/${sol} | awk '{print $1}')
            # check for unchanged solutions
            if [ "$md5_packed_sol" == "$md5_working_sol" ]; then
                # ignore unchanged solution
                continue
            fi
            # check for changed solutions
            if [ "$md5_packed_sol" != "$md5_working_sol" ]; then
                # copy changed solution from package area to staging area
                cp $psol ${STAGINGAREA}/latest
            fi
        else
            # found new solution
            # copy new solution from package area to staging area
            cp $psol ${STAGINGAREA}/latest
        fi
    done
    # check for deleted solutions
    # available in working area but not in package area
    for wsol in ${WORKINGAREA}/sols/*; do
        sol=${wsol##*/}
        if [ ! -f ${PACKAGEAREA}/sols/${sole} ]; then
            # solution deleted in the current installed package
            # create a solution file in staging area, which only contains the
            # version information of the 'old' solution
            # as a flag for a later removal from the working area
            grep '# .*VERSION=.*DATE=.*NAME=".*"' ${wsol} > ${STAGINGAREA}/latest/${sol}
        fi
    done
}

case "$upd_opt" in
v1tov2pi)
    # called from the postinstall script of saptune, if installation was an
    # update from saptune version 1 to version 2/3
    set_sysconfig_version
    create_tuned_conf
    ;;
v1tov2pt)
    # called from the posttrans script of saptune, if installation was an
    # update from saptune version 1 to version 2/3
    get_back_extra_ASE_BOBJ
    ;;
sle12to15pt)
    # called from the posttrans script of saptune, if installation was an
    # update from saptune version 2/3 to version 2/3
    change_note_names
    delete_notes
    staging=$(grep ^STAGING= /etc/sysconfig/saptune | awk -F '"' '{ print $2 }')
    if [ "$staging" == "true" ]; then
        adjust_workingarea
    fi
    ;;
cleanup)
    # called from the postinstall script of saptune to clean up some leftover
    # files from older saptune operations
    cleanup_savestates
    ;;
staging)
    # called from the postinstall script of saptune to handle the staging area
    copy_packednotes2staging
    ;;
esac
