#!/bin/bash
#
# Download the latest Oracle ASMLib driver for a given kernel.
#
# This script uses the list files generated and placed on the 
# Oracle Technology Network.  The files have a specific format:
#
# <package_name><space><version><space><revision><space><architecture><space><url>
#
# If the format changes, this script must be modified to parse a new format.
#
# This only supports RPM-based distributions right now.
#

# Force LC_ALL=C
export LC_ALL=C
 
# Base for the OracleASM software
ORACLEASM_URL="http://www.oracle.com/technology/software/tech/linux/asmlib"

# Detected distribution vendor
VENDOR=rhel6

USAGE="[-n] [-d] [<kernel_version>]"

exec 3>/dev/null

help=
verbose=
version=
usage=
dry_run=
download_only=
kernel_version=
while case "$#" in 0) break ;; esac
do
    case "$1" in
    -n|--dry-run)
        dry_run=t
        ;;
    -d|--download-only)
        download_only=t
        ;;
    -v|--verbose)
        verbose=-v
        exec 3>&2
        ;;
    -V|--version)
        version=t
        ;;
    -h|--help)
        help=t
        ;;
    -*)
        usage=t
        ;;
    *)
        if [ -z "$kernel_version" ]
        then
            kernel_version="$1"
        else
            usage=t
        fi
        ;;
    esac
    shift
done

# Load configuration
. oracleasm-Xshlib

if [ "$help" = "t" -o "$usage" = "t" ]
then
    usage
fi

if [ "$version" = "t" ]
then
    version
fi

if [ -z "$VENDOR" ]
then
    die "Driver update unsupported for unknown vendor"
fi   

ORACLEASM_UPDATE_METHOD=
UPDATE_CONFIG=
if [ -n "${ORACLEASM_CONFIG}" ]
then
    UPDATE_CONFIG="$(dirname ${ORACLEASM_CONFIG})/oracleasm-update"
    if [ -f "${UPDATE_CONFIG}" -a -r "${UPDATE_CONFIG}" ]
    then
        . "${UPDATE_CONFIG}"
    fi
fi

#
# List of supported fetch methods.  A method must have check_<method>() and
# get_<method>() defined.
#
GET_METHODS="curl wget lynx"

# Cache the updater configuration
write_update_config()
{
    [ -z "${UPDATE_CONFIG}" ] && return

    cat >"${UPDATE_CONFIG}" 2>&3 <<EOF
#
# This is a configuration file for the Oracle ASMlib updater.
# It is generated by the updater, and it's really just a cache.  You
# shouldn't modify it.
#

# ORACLEASM_UPDATE_METHOD is the updater function used to grab a URL
ORACLEASM_UPDATE_METHOD="${ORACLEASM_UPDATE_METHOD}"

EOF

    if [ $? != 0 ]
    then
        die "Unable to save updater cache"
    fi

    return
}

check_curl()
{
    TYPE="$(type -p curl)"
    [ $? != 0 ] && return 1
    [ -z "$TYPE" ] && return 1

    return 0
}

get_curl()
{
    if [ $# != 2 ]
    then
        die "Invalid number of arguments to get_curl()"
    fi

    URL="$1"
    FILE="$2"

    curl -L -C - -o "$FILE" "$URL"
    return $?
}

check_wget()
{
    TYPE="$(type -p wget)"
    [ $? != 0 ] && return 1
    [ -z "$TYPE" ] && return 1

    return 0
}

get_wget()
{
    if [ $# != 2 ]
    then
        die "Invalid number of arguments to get_wget()"
    fi

    URL="$1"
    FILE="$2"

    wget -c -O "$FILE" "$URL"
    return $?
}

check_lynx()
{
    TYPE="$(type -p lynx)"
    [ $? != 0 ] && return 1
    [ -z "$TYPE" ] && return 1

    return 0
}

get_lynx()
{
    if [ $# != 2 ]
    then
        die "Invalid number of arguments to get_lynx()"
    fi

    URL="$1"
    FILE="$2"

    lynx -source "$URL" 1>"$FILE"
    return $?
}

which_method()
{
    for m in $GET_METHODS
    do
        echo -n "Checking for $m: " >&3
        check_$m 1>/dev/null 2>&1
        if [ $? = 0 ]
        then
            echo "found" >&3
            echo $m
            break
        else
            echo "not found" >&3
        fi
    done
}

get_method()
{
    if [ $# != 2 ]
    then
        die "Invalid number of arguments to get_method()"
    fi

    echo "Downloading $1" >&3
    get_${ORACLEASM_UPDATE_METHOD} "$1" "$2" 1>&3 2>&1
    if [ $? != 0 ]
    then
        die "Unable to retrieve $1"
    else
        echo "Saved as $2" >&3
    fi
}


#
# Now let's actually do something
#

#
# Check our downloader.  If we haven't had one before, configure it.
# If we have, test that it still works.
#
if [ -z "$ORACLEASM_UPDATE_METHOD" ] || ! check_$ORACLEASM_UPDATE_METHOD 1>/dev/null 2>&1
then
    ORACLEASM_UPDATE_METHOD="$(which_method)"
    if [ -z "$ORACLEASM_UPDATE_METHOD" ]
    then
        die "No download program found"
    fi
    write_update_config
fi


#
# Ok, we're about to set up some temporary files, so we need to trap
# exits and remove them.  All temporary files go in $WORKDIR, and they
# must be listed in $WORKFILES.
#
WORKFILES=
WORKDIR=
trap "exitcode=\$?; (rm -f \$WORKFILES 2>/dev/null; rmdir \$WORKDIR 2>/dev/null) && exit \$exitcode" 0
trap "rm -f \$WORKFILES 2>/dev/null; rmdir \$WORKDIR 2>/dev/null" 1 2 13 15

WORKDIR="$(mktemp -d "${TMPDIR:-/tmp}/oracleasm.XXXXXX" 2>/dev/null)"
if [ -z "$WORKDIR" -o ! -d "$WORKDIR" ]
then
    die "Unable to create temporary directory"
fi

#
# Let's set up our distribution's package list
#
LISTURL="${ORACLEASM_URL}/${VENDOR}.list"
LISTFILE="${WORKDIR}/${VENDOR}.list"

#
# If this returns, the distribution list will be in $LISTFILE
#
WORKFILES="$WORKFILES $LISTFILE"
get_method "$LISTURL" "$LISTFILE"

#
# OracleASM driver packages are always named
# "oracleasm-<kernel_version>", where <kernel_version> is the output
# of `uname -r`.  So, let's get our driver package name to use later.
#
if [ -z "$kernel_version" ]
then
    kernel_version="$(uname -r)"
fi
if [ ! -d "/lib/modules/${kernel_version}" ] || ! rpm -qf "/lib/modules/${kernel_version}" 1>/dev/null 2>&1
then
    die "Kernel ${kernel_version} is not installed"
fi

kernel_arch="$(rpm -qf "/lib/modules/${kernel_version}" --qf "%{ARCH}" 2>&3)"
if [ $? != 0 -o -z "$kernel_arch" ]
then
    die "Unable to determine kernel package architecture"
fi

echo -e "Kernel:\t\t$kernel_version $kernel_arch"

DRIVER_NAME="oracleasm-${kernel_version:-$(uname -r)}"
echo -e "Driver name:\t$DRIVER_NAME"
DRIVER_INFO="$(awk '$1 ~ /^'"$DRIVER_NAME"'$/ && $4 ~ /^'"$kernel_arch"'$/{print $0; exit}' "$LISTFILE" 2>&3)"
if [ -z "$DRIVER_INFO" ]
then
    die "Driver for kernel ${kernel_version} does not exist"
fi

DRIVER_URL="$(echo "$DRIVER_INFO" | cut -d" " -f5)"
DRIVER_FILE="${WORKDIR}/$(basename "$DRIVER_URL")"
echo -e "Latest version:\t$(basename "$DRIVER_URL")"

WORKFILES="$WORKFILES $DRIVER_FILE"
if [ -z "$dry_run" ]
then
    get_method "$DRIVER_URL" "$DRIVER_FILE"
fi

if [ "$download_only" = "t" ]
then
    if [ -z "$dry_run" ]
    then
        /bin/mv -f "$DRIVER_FILE" ./ 2>&3
        [ $? != 0 ] && die "Unable to download driver"
    fi

    echo "Driver downloaded successfully"
    exit 0
fi

echo "Installing driver... "
if [ -z "$dry_run" ]
then
    rpm -Uvh "$DRIVER_FILE"
    if [ $? != 0 ]
    then
        die "Driver not installed"
    fi
fi

echo "Driver installed successfully"

exit 0
