#! /bin/sh
# init fragment for oracleasm
#
# chkconfig: 2345 29 20
# description: Load OracleASM driver at system boot
#
### BEGIN INIT INFO
# Provides: oracleasm
# Required-Start: hwscan
# Should-Start: ypbind
# Required-Stop:
# Default-Start: 2 3 5
# Default-Stop:
# Description: Load OCFS driver at system boot
### END INIT INFO


# Force LC_ALL=C
export LC_ALL=C
 
if [ -f /etc/redhat-release ]
then
. /etc/init.d/functions

init_status()
{
    return 0
}

success_status()
{
    success
    echo
}

failure_status()
{
    failure $1
    echo
}

exit_status()
{
    exit $?
}
elif [ -f /etc/SuSE-release -o -f /etc/UnitedLinux-release ]
then
. /etc/rc.status

init_status()
{
    rc_reset
}

success_status()
{
    /bin/true
    rc_status -v
}

failure_status()
{
    /bin/false
    rc_status -v
}

exit_status()
{
    rc_exit
}
else
init_status()
{
    return 0
}

success_status()
{
    echo "OK"
    return 0
}

failure_status()
{
    echo "Failed"
    return 0
}

exit_status()
{
    exit $?
}
fi

# Source configuration
[ -f /etc/sysconfig/oracleasm ] && . /etc/sysconfig/oracleasm

init_status

KVER="`uname -r`"
MODNAME="oracleasm"

if [ -z "${ORACLE_ASMMANAGER}" ]
then
    ORACLE_ASMMANAGER="/dev/oracleasm"
fi



#
# if_fail()
#
# Evaluates return codes.  If 0, prints "OK", if 1, prints "Failed"
# and exits.  If 2, status is "already done" and nothing is printed.
# The rest of the functions in here all honor this convention.
#
if_fail()
{
    RC="$1"
    REASON="$2"
    if [ "$RC" = "0" ]
    then
        success_status
        return
    elif [ "$RC" = "2" ]
    then
        return
    fi
    failure_status "${REASON}"
    exit 1
}


#
# dev_create()
#
# Create $1
# Returns 0 on success, 1 on error, 2 if it already exists.
#
dev_create()
{
    if [ "$#" -lt "1" -o -z "$1" ]
    then
        echo "dev_create(): Requires an argument" >&2
        return 1
    fi
    DEV="$1"
    if [ -e "$DEV" ]
    then
        if [ -d "$DEV" ]
        then
            return 2
        fi
        echo "dev_create(): File $DEV is not a directory" >&2
        return 1
    fi

    echo -n "Creating $DEV mount point: "
    mkdir "$DEV" 2>/dev/null
    if [ $? != 0 ]
    then
        echo "Unable to create mount point $DEV" >&2
        return 1
    fi
    return 0
}


#
# load_module()
# Load a module
#
# 0 is success, 1 is error, 2 is already loaded
# 
load_module()
{
    if [ "$#" -lt "1" -o -z "$1" ]
    then
        echo "load_module(): Requires an argument" >&2
        return 1
    fi
    MODNAME="$1"

    MODOUT="`awk '$1 ~ /^'$MODNAME'$/{print $1;exit}' < /proc/modules 2>/dev/null`"
    if [ -n "$MODOUT" ]
    then
        return 2
    fi

    echo -n "Loading module \"$MODNAME\": "
    modprobe -s "$MODNAME"
    if [ "$?" != 0 ]
    then
        echo "Unable to load module \"$MODNAME\"" >&2
        return 1
    fi

    return 0
}

#
# unload_module()
# Unload a module
#
# 0 is success, 1 is error, 2 is not loaded
# 
unload_module()
{
    if [ "$#" -lt "1" -o -z "$1" ]
    then
        echo "unload_module(): Requires an argument" >&2
        return 1
    fi
    MODNAME="$1"

    MODOUT="`awk '$1 ~ /^'$MODNAME'$/{print $1,$3;exit}' < /proc/modules 2>/dev/null`"
    if [ -z "$MODOUT" ]
    then
        return 2
    fi
    case "$MODOUT" in
    $MODNAME\ 0)
        ;;
    $MODNAME\ *)
        return 2
        ;;
    *)
        echo -n "Invalid module parsing! "
        return 1
        ;;
    esac

    echo -n "Unloading module \"$MODNAME\": "
    modprobe -rs "$MODNAME"
    if [ "$?" != 0 ]
    then
        echo "Unable to unload module \"$MODNAME\"" >&2
        return 1
    fi

    return 0
}


#
# mount_device()
# Mount the /dev/oracleasm filesystem
#
# 0 is success, 1 is error, 2 is already mounted
#
mount_device()
{
    if [ -z "$ORACLE_ASMMANAGER" ]
    then
        echo "mount_device(): No device specified!" >&2
        return 1
    fi
    ORACLE_ASMMANAGERSEARCH="`echo "$ORACLE_ASMMANAGER" | sed -e 's/\//\\\\\//g'`"
    MOUNTOUT="`awk '$2 ~ /^'$ORACLE_ASMMANAGERSEARCH'$/{print $2; exit}' < /proc/mounts 2>/dev/null`"

    if [ -n "$MOUNTOUT" ]
    then
        return 2
    fi

    echo -n "Mounting ASMlib driver filesystem: "
    mount $OPTS -t oracleasmfs oracleasmfs $ORACLE_ASMMANAGER
    if [ $? != 0 ]
    then
        echo "Unable to mount ASMlib driver filesystem" >&2
        return 1
    fi

    for i in ${ORACLE_ASMMANAGER}/.[a-z]*
    do
        if [ "$i" = ${ORACLE_ASMMANAGER}'/.[a-z]*' ]
        then
            break
        fi
        perm_disk "$i"
        if [ $? = 1 ]
        then
            echo "Unable to fix ASM driver permissions" >&2
            return 1
        fi
    done
        
    perm_disk ${ORACLE_ASMMANAGER}/iid
    if [ $? = 1 ]
    then
        echo "Unable to fix ASM driver permissions" >&2
        return 1
    fi

    chmod 0770 ${ORACLE_ASMMANAGER}/iid
    if [ $? = 1 ]
    then
        echo "Unable to fix ASM driver permissions" >&2
        return 1
    fi


    return 0
}


#
# unmount_device()
# Unmount the /dev/oracleasm filesystem
#
# 0 is success, 1 is error, 2 is not mounted
#
unmount_device()
{
    if [ -z "$ORACLE_ASMMANAGER" ]
    then
        echo "mount_device(): No device specified!" >&2
        return 1
    fi
    ORACLE_ASMMANAGERSEARCH="`echo "$ORACLE_ASMMANAGER" | sed -e 's/\//\\\\\//g'`"
    MOUNTOUT="`awk '$2 ~ /^'$ORACLE_ASMMANAGERSEARCH'$/{print $2; exit}' < /proc/mounts 2>/dev/null`"

    if [ -z "$MOUNTOUT" ]
    then
        return 2
    fi

    echo -n "Unmounting ASMlib driver filesystem: "
    umount $ORACLE_ASMMANAGER
    if [ $? != 0 ]
    then
        echo "Unable to unmount ASMlib driver filesystem" >&2
        return 1
    fi

    return 0
}


#
# write_sysconfig()
#
# Writes the system configuration out
#
write_sysconfig()
{
    echo -n "Writing Oracle ASM library driver configuration: "
    cat >/etc/sysconfig/oracleasm <<EOF
#
# This is a configuration file for automatic loading of the Oracle
# Automatic Storage Management library kernel driver.  It is generated
# By running /etc/init.d/oracleasm configure.  Please use that method
# to modify this file
#

# ORACLEASM_ENABELED: 'true' means to load the driver on boot.
ORACLEASM_ENABLED=${ORACLEASM_ENABLED:-false}

# ORACLEASM_UID: Default user owning the $ORACLE_ASMMANAGER mount point.
ORACLEASM_UID=${ORACLEASM_UID}

# ORACLEASM_GID: Default group owning the $ORACLE_ASMMANAGER mount point.
ORACLEASM_GID=${ORACLEASM_GID}

# ORACLEASM_SCANBOOT: 'true' means fix disk perms on boot
ORACLEASM_SCANBOOT=${ORACLEASM_SCANBOOT}

# ORACLEASM_CLEARBOOT: 'true' means clean old disk perms on boot
ORACLEASM_CLEARBOOT=${ORACLEASM_CLEARBOOT}

# ORACLEASM_SCANORDER: Matching patterns to order disk scanning
ORACLEASM_SCANORDER=${ORACLEASM_SCANORDER}

# ORACLEASM_SCANEXCLUDE: Matching patterns to exclude disks from scan
ORACLEASM_SCANEXCLUDE=${ORACLEASM_SCANEXCLUDE}

EOF

    if [ $? != 0 ]
    then
        return 1
    fi
    return 0
}


#
# configure_ask()
#
# Ask configuration questions, setting the shell vars.
#
configure_ask()
{
    cat <<EOF
Configuring the Oracle ASM library driver.

This will configure the on-boot properties of the Oracle ASM library
driver.  The following questions will determine whether the driver is
loaded on boot and what permissions it will have.  The current values
will be shown in brackets ('[]').  Hitting <ENTER> without typing an
answer will keep that current value.  Ctrl-C will abort.

EOF

    while :
    do
        echo -n "Default user to own the driver interface [$ORACLEASM_UID]: "
        read LINE
        case "$LINE" in
        "")
            break
            ;;
        *[^a-zA-Z0-9]*)
            echo "Invalid user: $LINE" >&2
            ;;
        *)
            ORACLEASM_UID=$LINE
            break
            ;;
        esac
    done

    while :
    do
        echo -n "Default group to own the driver interface [$ORACLEASM_GID]: "
        read LINE
        case "$LINE" in
        "")
            break
            ;;
        *[^a-zA-Z0-9]*)
            echo "Invalid group: $LINE" >&2
            ;;
        *)
            ORACLEASM_GID=$LINE
            break
            ;;
        esac
    done

    while :
    do
        if [ "$ORACLEASM_ENABLED" = "true" ]
        then
            CUR=y
        else
            CUR=n
        fi
        echo -n "Start Oracle ASM library driver on boot (y/n) [$CUR]: "
        read LINE
        case "$LINE" in
        "")
            break
            ;;
        y|Y)
            ORACLEASM_ENABLED=true
            break
            ;;
        n|N)
            ORACLEASM_ENABLED=false
            break
            ;;
        *)
            echo "Invalid response: $LINE" >&2
            ;;
        esac
    done

    while :
    do
        if [ -z "$ORACLEASM_SCANBOOT" ]
        then
            ORACLEASM_SCANBOOT=true
        fi
        if [ "${ORACLEASM_SCANBOOT}" = "true" ]
        then
            CUR=y
        else
            CUR=n
        fi
        echo -n "Fix permissions of Oracle ASM disks on boot (y/n) [$CUR]: "
        read LINE
        case "$LINE" in
        "")
            break
            ;;
        y|Y)
            ORACLEASM_SCANBOOT=true
            break
            ;;
        n|N)
            ORACLEASM_SCANBOOT=false
            break
            ;;
        *)
            echo "Invalid response: $LINE" >&2
            ;;
        esac
    done
}


#
# upper_disk()
# Make a disk name uppercase
#
upper_disk()
{
    case "$1" in
    */*)
        # Don't upper pathnames
        echo "$1"
        ;;
    *)
        echo "$1" | tr '[a-z]' '[A-Z]'
        ;;
    esac
}


#
# make_disk()
# Creates an ASM disk.
#
# Returns 0 on success, 1 on error, 2 on already marked.
#
make_disk()
{
    if [ "$#" -lt "2" -o -z "$1" -o -z "$2" ]
    then
        echo "make_disk(): Requires two arguments" >&2
        return 1
    fi
    LABEL="$1"
    DISKNAME="$2"
    if [ ! -z "$3" ]
    then
        MARK="-a mark=$3"
    fi

    OUTPUT="`asmtool -C -l "${ORACLE_ASMMANAGER}" -n "${LABEL}" -s "${DISKNAME}" $MARK 2>&1`"
    if [ $? != 0 ]
    then
        echo -n "Marking disk \"$DISKNAME\" as an ASM disk: "
	echo "$OUTPUT"
        return 1
    fi
    case "$OUTPUT" in
    *is\ marked*)
        return 2
        ;;
    *)
        ;;
    esac
    echo -n "Marking disk \"$DISKNAME\" as an ASM disk: "
    return 0
}


#
# relabel_disk()
# Relabels an ASM disk.
#
# Returns 0 on success, 1 on error.
#
relabel_disk()
{
    if [ "$#" -lt "2" -o -z "$1" -o -z "$2" ]
    then
        echo "relabel_disk(): Requires two arguments" >&2
        return 1
    fi
    OLDDISK="$1"
    NEWLABEL="$2"
    FORCE="$3"

    if [ -z "$FORCE" ]
    then
        REDIR=''
    else
        REDIR='2>&1'
    fi
    OUTPUT="`asmtool -H -l "${ORACLE_ASMMANAGER}" -n "${OLDDISK}" -a "label=${NEWLABEL}" $FORCE $REDIR`"
    if [ $? != 0 ]
    then
        if [ -z "$FORCE" ]
        then
            echo "If you really wish to change the label, rerun with the force-renamedisk command." >&2
        fi
        echo -n "Renaming disk \"$OLDDISK\" to \"$NEWLABEL\": "
        return 1
    fi
    echo -n "Renaming disk \"$OLDDISK\" to \"$NEWLABEL\": "
    return 0
}


#
# remove_disk()
# Removes the  ASM disk.
#
# Returns 0 on success, 1 on error, 2 on not there.
#
remove_disk()
{
    if [ "$#" -lt "1" -o -z "$1" ]
    then
        echo "remove_disk(): Requires an argument" >&2
        return 1
    fi
    DISKNAME="$1"
   
    OUTPUT="`asmtool -D -l "${ORACLE_ASMMANAGER}" -n "${DISKNAME}" 2>&1`"
    if [ $? != 0 ]
    then
        echo -n "Removing ASM disk \"$DISKNAME\": "
        return 1
    fi
    case "$OUTPUT" in
    *not\ marked*)
        return 2
        ;;
    *)
        ;;
    esac
    echo -n "Removing ASM disk \"$DISKNAME\": "
    return 0
}


#
# check_disk()
# Check if the disk is an ASM disk
#
check_disk()
{
    if [ "$#" -lt "1" -o -z "$1" ]
    then
        echo "check_disk(): Requires an argument" >&2
        return 1
    fi
    DISKNAME="$1"

    asmtool -I -l "$ORACLE_ASMMANAGER" -n "$DISKNAME" -a label 2>&1| sed -e 's/^asmtool: //'
}


#
# perm_disk()
# Set the appropriate permissions on a disk.
#
# Returns 0 on success, 1 on error, 2 on already correct
#
perm_disk()
{
    if [ "$#" -lt "1" -o -z "$1" ]
    then
        echo "perm_disk(): Requires an argument" >&2
        return 1
    fi
    DISKNAME="$1"

    OUTPUT="`ls -ld "${DISKNAME}" 2>/dev/null`"
    if [ $? != 0 ]
    then
        echo -n "Checking ownership of disk \"${DISKNAME}\": "
        return 1
    fi
    OUID="`echo "$OUTPUT" | awk '{print $3}'`"
    OGID="`echo "$OUTPUT" | awk '{print $4}'`"

    if [ "$OUID" = "${ORACLEASM_UID:-root}" -a "$OGID" = "${ORACLEASM_GID:-root}" ]
    then
        return 2
    fi

    chown "${ORACLEASM_UID:-root}:${ORACLEASM_GID:-root}" "$DISKNAME"
    if [ $? != 0 ]
    then
        return 1
    fi

    chmod 0660 "$DISKNAME"
    if [ $? != 0 ]
    then
        return 1
    fi

    return 0
}




#
# scan_disks()
# Scan disks to find any ASM disks and perhaps fix their ownership.
#
# Returns 0 on success, 1 on error, 2 on disabled.
#
scan_disks()
{
    if [ "$ORACLEASM_SCANBOOT" != "true" ]
    then
        return 2
    fi

    echo -n "Scanning system for ASM disks: "
    RC=0

    SCANARGS=
    for d in ${ORACLEASM_SCANORDER}
    do
        SCANARGS="${SCANARGS} -s $d"
    done

    for d in ${ORACLEASM_SCANEXCLUDE}
    do
        SCANARGS="${SCANARGS} -x $d"
    done

    OUTPUT="`asmscan -l "${ORACLE_ASMMANAGER}" ${SCANARGS} 2>/dev/null`"
    if [ $? != 0 ]
    then
        return 1
    fi

    ls -1 "${ORACLE_ASMMANAGER}/disks" | while read LINE
        do
            perm_disk "${ORACLE_ASMMANAGER}/disks/${LINE}"
            if [ $? = 1 ]
            then
                echo "Unable to fix permissions on ASM disk \"$LINE\"" >&2
                return 1
            fi
        done

    return 0
}

configure()
{
    configure_ask
    write_sysconfig
    if_fail $? "Unable to write the driver configuration"
}


scandisks()
{
    scan_disks
    if_fail "$?" "Unable to scan for ASM disks"
}


start()
{
    dev_create "${ORACLE_ASMMANAGER}"
    if_fail "$?" "Unable to create ${ORACLE_ASMMANAGER}"

    if [ "$ORACLEASM_ENABLED" != "true" ]
    then
        exit 0
    fi

    load_module "${MODNAME}"
    if_fail "$?" "Unable to load the ASMlib driver module"

    mount_device
    if_fail "$?" "Unable to mount the ASMlib driver filesystem"

    scandisks
}


stop()
{
    unmount_device
    if_fail "$?" "Unable to unmount the ASMlib driver filesystem"

    unload_module oracleasm
    if_fail "$?" "Unable to unload the ASM library driver"
}



case "$1" in
    start)
        start
	;;
	
    status)
        echo -n $"Checking if ASM is loaded: "
	grep '^oracleasm ' /proc/modules >/dev/null 2>&1
        if_fail $?

        echo -n $"Checking if $ORACLE_ASMMANAGER is mounted: "
        ORACLE_ASMMANAGERSEARCH="`echo $ORACLE_ASMMANAGER | sed -e 's/\//\\\\\//g'`"
        grep "^oracleasmfs $ORACLE_ASMMANAGERSEARCH oracleasmfs" /proc/mounts >/dev/null 2>&1
        if_fail $?

        exit 0
        ;;

    configure)
        configure
        if [ "$ORACLEASM_ENABLED" = "true" ]
        then
            start
        else
            stop
        fi
        ;;

    enable)
        ORACLEASM_ENABLED=true
        write_sysconfig
        if_fail $? "Unable to write the driver configuration"
        start
        ;;

    disable)
        ORACLEASM_ENABLED=false
        write_sysconfig
        if_fail $? "Unable to write the driver configuration"
        stop
        ;;

    createdisk)
        if [ -z "$2" -o -z "$3" ]
        then
            echo "Action \"createdisk\" requires two arguments" >&2
            exit 1
        fi
        UPDISK="`upper_disk "$2"`"
        make_disk "$UPDISK" "$3"
        if [ $? = 1 ]
        then
            if_fail 1 "Unable to create disk \"$UPDISK\""
        fi
        perm_disk "${ORACLE_ASMMANAGER}/disks/$UPDISK"
        if_fail $? "Unable to change ownership of disk \"$UPDISK\""
        ;;

    deletedisk)
        if [ -z "$2" ]
        then
            echo "Action \"deletedisk\" requires an argument" >&2
            exit 1
        fi
        UPDISK="`upper_disk "$2"`"
        remove_disk "$UPDISK"
        if_fail $? "Unable to delete disk \"$UPDISK\""
        ;;

    renamedisk)
        if [ -z "$2" -o -z "$3" ]
        then
            echo "Action \"renamedisk\" requires two arguments" >&2
            exit 1
        fi
        OLDDISK="$2"
        NEWDISK="`upper_disk "$3"`"
        relabel_disk "$OLDDISK" "$NEWDISK"
        # We know this will error via asmtool
        if_fail 1 "Unable to rename disk \"$OLDDISK\"" >&2
        ;;
    
    force-renamedisk)
        if [ -z "$2" -o -z "$3" ]
        then
            echo "Action \"renamedisk\" requires two arguments" >&2
            exit 1
        fi
        OLDDISK="$2"
        NEWDISK="`upper_disk "$3"`"
        relabel_disk "$OLDDISK" "$NEWDISK" "-a force=yes"
        if [ $? = 1 ]
        then
            if_fail 1 "Unable to rename disk \"$OLDDISK\"" >&2
        fi
        perm_disk "${ORACLE_ASMMANAGER}/disks/$NEWDISK"
        if_fail $? "Unable to change ownership of disk \"$NEWDISK\""
        ;;

    listdisks)
	if [ -d "${ORACLE_ASMMANAGER}/disks/" ]
        then
            ls -1 "${ORACLE_ASMMANAGER}/disks/"
        fi
        ;;

    querydisk)
        if [ -z "$2" ]
        then
            echo "Action \"querydisk\" requires an argument" >&2
            exit 1
        fi
	shift
	for d in "$@"
        do
	    case "$d" in
            */*)
                check_disk "$d"
                ;;
            *)
                UPDISK="`upper_disk "$d"`"
                check_disk "$UPDISK"
                ;;
            esac
        done
        ;;

    scandisks)
        scandisks
        ;;

    stop)
        stop
        ;;

    restart)
        stop
        start
	;;

    *)
	echo "Usage: $0 {start|stop|restart|enable|disable|configure|createdisk|deletedisk|querydisk|listdisks|scandisks|status}"
        exit 1
esac

exit 0

