#!/bin/sh

set -eu

SCRIPT_NAME=`basename "$0"`

errecho() {
   echo "$@" >&2
}

usage() {
    echo "\
Usage: $SCRIPT_NAME [options]

Libasan interceptors switching tool.
When switching:
   - changes library which libasan.so symlink points to
   - modifies /ASAN_OPTIONS
   - backups (or restores) original libasan

Options:
    -h, --help                    - display this help and exit
    -c, --current                 - show currently set ASan library
    -s, --set libasan|libasansi   - set ASan library"
}

errusage() {
   usage >&2
}

check_file() {
    if [ ! -f "$1" ]; then
        errecho "$1: no such file"
        exit 1
    fi
}

init_libdir() {
    if `rpm -q --quiet libasan`; then
        LIBDIR=`rpm -ql libasan | grep '/libasan\.so$' | xargs dirname`
        check_file "${LIBDIR}/libasan.so"
    else
        errecho "libasan package is not installed"
        exit 1
    fi
}

show_current_lib() {
    basename `readlink -f "${LIBDIR}/libasan.so"` | cut -d. -f1
}

remount_rootfs() {
    mount -o remount,rw /
}

set_lib() {
    local NEW_LIB="$1"
    local OLD_LIB=`show_current_lib`
    if [[ "$NEW_LIB" == "$OLD_LIB" ]]; then
        echo "$NEW_LIB is already set"
        exit 0
    fi

    case "$NEW_LIB" in
        libasan)
            echo 'Set libasan'

            # check presence of backups
            check_file /ASAN_OPTIONS.BACKUP
            check_file "${LIBDIR}/libasan.so.6.0.0.backup"

            remount_rootfs

            # restore ASan library
            mv "${LIBDIR}/libasan.so.6.0.0.backup" "${LIBDIR}/libasan.so.6.0.0"
            chsmack -a _ "${LIBDIR}/libasan.so.6.0.0"

            # restore ASan options
            mv /ASAN_OPTIONS.BACKUP /ASAN_OPTIONS
            chsmack -a _ /ASAN_OPTIONS
            ;;
        libasansi)
            echo 'Set libasansi'

            # check presence of original files
            check_file /ASAN_OPTIONS
            check_file "${LIBDIR}/libasan.so.6.0.0"

            remount_rootfs

            # create backup
            cp "${LIBDIR}/libasan.so.6.0.0" "${LIBDIR}/libasan.so.6.0.0.backup"
            cp /ASAN_OPTIONS /ASAN_OPTIONS.BACKUP

            # change ASan options
            echo "`cat /ASAN_OPTIONS`:enable_interceptors=0" > /ASAN_OPTIONS
            chsmack -a _ /ASAN_OPTIONS

            # change ASan library
            ln -sf "${LIBDIR}/libasansi.so" "${LIBDIR}/libasan.so.6.0.0"
            chsmack -a _ "${LIBDIR}/libasan.so.6.0.0"
            ;;
        *)
            errecho "Incorrect libname: $NEW_LIB"
            errusage
            exit 1
            ;;
    esac
}

if [ `id -u` -ne 0 ]; then
   echo "This script must be run as root"
   exit 1
fi

# parsing arguments
while [ "$#" -gt 0 ]; do
    KEY="$1"
    case "$KEY" in
        -h|--help)
            usage
            exit 0
            ;;
        -c|--current)
            init_libdir
            show_current_lib
            exit 0
            ;;
        -s|--set)
            if [ "$#" -ne 2 ]; then
                errusage
                exit 1
            fi
            NEW_LIB="$2"
            init_libdir
            set_lib "$NEW_LIB"
            exit 0
            ;;
        *)
            errecho "Incorrect argument: $KEY"
            errusage
            exit 1
    esac
done

errusage
exit 1
