#!/bin/bash
# 
# Return a disk to the operating system
#


# Force LC_ALL=C
export LC_ALL=C
 
USAGE="[-l <manager>] [-v] [-f] <label>|<device> <new_label>"

exec 3>/dev/null

help=
verbose=
version=
usage=
force=
restore=

while case "$#" in 0) break ;; esac
do
    case "$1" in
    -l|--manager)
        case "$#" in 1) usage=t; break ;; esac
        shift
        ORACLE_ASMMANAGER="$1"
        ;;
    -f|--force)
        force=t
        ;;
    -r|--restore)
        restore=t
        force=t
        ;;
    -v|--verbose)
        verbose=t
        exec 3>&2
        ;;
    -V|--version)
        version=t
        ;;
    -h|--help)
        help=t
        ;;
    -*)
        usage=t
        ;;
    *)
        break
        ;;
    esac
    shift
done


# Load configuration
. oracleasm-Xshlib

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

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



relabel_disk()
{
    if [ "$#" != "2" -o -z "$1" -o -z "$2" ]
    then
        die "relabel_disk(): Requires an argument"
    fi

    OLD="$1"
    NEW="$2"

    old_path="$(asm_disk_path "${ORACLE_ASMMANAGER}" "${OLD}")"
    new_path="$(asm_disk_path "${ORACLE_ASMMANAGER}" "${NEW}")"

    INFO="$(oracleasm-read-label "${old_path}" 2>&3)"
    ERRNO=$?
    if [ -z "$INFO" ]
    then
        case "$ERRNO" in
        250|237)
            # ENXIO or ENODEV means its a bad device, we should remove
            # the disk!
            oracleasm-clean-disk -l "${ORACLE_ASMMANAGER}" "${OLD}" 2>&3
            if [ $? != 0 ]
            then
                echo "Unable to remove stale ASM disk \"${OLD}\"" | asm_log 1
            fi
            ;;
        *)
            ;;
        esac
        echo "Unable to open ASM disk \"${OLD}\"" | asm_log 1
        exit 1
    fi    

    LABEL="$(echo "$INFO" | cut -f1 -d:)"
    case "$LABEL" in
    "$OLD")
        old_dispos="old"
        error=

        echo -n "Instantiating disk \"${NEW}\": "
        oracleasm-instantiate-disk -l "${ORACLE_ASMMANAGER}" \
            "${old_path}" "${NEW}" 2>&3
        if [ $? != 0 ]
        then
            echo "failed"
            echo "Unable to instantiate disk \"${NEW}\"" | asm_log 1
            exit 1
        fi

        perm_disk "${new_path}"
        if [ $? = 1 ]
        then
            echo "failed"
            echo "Unable to change ownership of disk \"${NEW}\"" | asm_log 1
            exit 1
        fi
        echo "done"

        echo -n "Writing disk header: "
        oracleasm-write-label -f "${old_path}" "${NEW}" 2>&1 | asm_log 2
        if [ ${PIPESTATUS[0]} != 0 ]
        then
            oracleasm-clean-disk -l "${ORACLE_ASMMANAGER}" "${NEW}" 2>&3
            echo "failed"
            echo "Unable to label disk \"${NEW}\"" | asm_log 1
            exit 1
        fi
        echo "done"
        ;;
    "$NEW")
        old_dispos="stale"
        error="Disk \"${OLD}\" already labeled for \"${NEW}\""
        ;;
    *)
        old_dispos="$stale"
        error "Disk \"${OLD}\" isn't labeled \"${OLD}\""
        ;;
    esac

    echo -n "Removing ${old_dispos} ASM disk \"${OLD}\": "
    oracleasm-clean-disk -l "${ORACLE_ASMMANAGER}" "${OLD}" 2>&3
    if [ $? != 0 ]
    then
        echo "failed"
        echo "Unable to remove ${old_dispos} ASM disk \"${OLD}\"" | asm_log 1
        exit 1
    fi
    echo "done"

    if [ -n "$error" ]
    then
        echo "$error" | asm_log 1
        exit 1
    fi

    return 0
}

relabel_device()
{
    if [ "$#" != "2" -o -z "$1" -o -z "$2" ]
    then
        die "relabel_device(): Requires an argument"
    fi

    DEV="$1"
    NEW="$2"

    new_path="$(asm_disk_path "${ORACLE_ASMMANAGER}" "${NEW}")"

    INFO="$(oracleasm-read-label "${DEV}" 2>&3)"
    ERRNO=$?
    if [ -z "$INFO" ]
    then
        if [ "$ERRNO" = 0 ]
        then
            echo "Device \"${DEV}\" is not labeled for ASM" | asm_log 1
            exit 1
        else
            echo "Unable to read device \"${DEV}\"" | asm_log 1
            exit 1
        fi
    fi    

    OLD="$(echo "$INFO" | cut -f1 -d:)"
    if [ "${OLD}" = "${NEW}" ]
    then
        echo "Device \"${DEV}\" is already labeled \"${NEW}\"" | asm_log 1
        exit 1
    elif [ -n "$OLD" ]
    then
        old_path="$(asm_disk_path "${ORACLE_ASMMANAGER}" "${OLD}")"
        dev_major_minor="$(get_dev "$DEV")"
        old_major_minor="$(get_dev "$old_path")"
        if [ -n "$dev_major_minor" -a "$dev_major_minor" = "$old_major_minor" ]
        then
            echo -n "Removing old ASM disk \"${OLD}\": "
            oracleasm-clean-disk -l "${ORACLE_ASMMANAGER}" "${OLD}" 2>&3
            if [ $? != 0 ]
            then
                echo "failed"
                echo "Unable to remove ${old_dispos} ASM disk \"${OLD}\"" | asm_log 1
                exit 1
            fi
            echo "done"
        fi
    fi

    echo -n "Writing disk header: "
    oracleasm-write-label -f "${DEV}" "${NEW}" 2>&1 | asm_log 2
    if [ ${PIPESTATUS[0]} != 0 ]
    then
    	oracleasm-instantiate-disk -l "${ORACLE_ASMMANAGER}" "${DEV}" \
        	"${OLD}" 2>&3
        echo "failed"
        echo "Unable to label device \"${DEV}\"" | asm_log 1
        exit 1
    fi
    echo "done"

    echo -n "Instantiating disk \"${NEW}\": "
    oracleasm-instantiate-disk -l "${ORACLE_ASMMANAGER}" "${DEV}" \
        "${NEW}" 2>&3
    if [ $? != 0 ]
    then
        echo "failed"
        echo "Unable to instantiate disk \"${NEW}\"" | asm_log 1
        exit 1
    fi

    perm_disk "${new_path}"
    if [ $? = 1 ]
    then
        echo "failed"
        echo "Unable to change ownership of disk \"${NEW}\"" | asm_log 1
        exit 1
    fi
    echo "done"

    return 0
}

restore_device()
{
    if [ "$#" != "2" -o -z "$1" -o -z "$2" ]
    then
        die "restore_device(): Requires an argument"
    fi

    DEV="$1"
    NEW="$2"

    new_path="$(asm_disk_path "${ORACLE_ASMMANAGER}" "${NEW}")"

    INFO="$(oracleasm-read-label -r "${DEV}" 2>&3)"
    ERRNO=$?
    if [ -z "$INFO" ]
    then
        if [ "$ERRNO" = 0 ]
        then
            echo "Device \"${DEV}\" is not labeled for ASM" | asm_log 1
            exit 1
        else
            echo "Unable to read device \"${DEV}\"" | asm_log 1
            exit 1
        fi
    fi
    echo -n "Writing disk header: "
    oracleasm-write-label -f "${DEV}" "${NEW}" 2>&1 | asm_log 2
    if [ ${PIPESTATUS[0]} != 0 ]
    then
        oracleasm-instantiate-disk -l "${ORACLE_ASMMANAGER}" "${DEV}" \
                "${OLD}" 2>&3
        echo "failed"
        echo "Unable to label device \"${DEV}\"" | asm_log 1
        exit 1
    fi
    echo "done"

    echo -n "Instantiating disk \"${NEW}\": "
    oracleasm-instantiate-disk -l "${ORACLE_ASMMANAGER}" "${DEV}" \
        "${NEW}" 2>&3
    if [ $? != 0 ]
    then
        echo "failed"
        echo "Unable to instantiate disk \"${NEW}\"" | asm_log 1
        exit 1
    fi

    perm_disk "${new_path}"
    if [ $? = 1 ]
    then
        echo "failed"
        echo "Unable to change ownership of disk \"${NEW}\"" | asm_log 1
        exit 1
    fi
    echo "done"

    return 0
}

if [ $# != 2 -o -z "$1" -o -z "$2" ]
then
    usage
fi

OLD="$1"
shift
case "$OLD" in
*/*)
    ;;
*)
    OLD="$(upper_disk "$OLD")"
    if [ -z "$OLD" ]
    then
        exit 1
    fi
    ;;
esac

NEW="$(upper_disk "$1")"
shift
if [ -z "$NEW" ]
then
    exit 1
fi

if [ "$force" != "t" ]
then
    cat <<EOCAT
WARNING: Changing the label of an disk marked for ASM is a very dangerous
         operation.  If this is really what you mean to do, you must
         ensure that all Oracle and ASM instances have ceased using
         this disk.  Otherwise, you may LOSE DATA.

If you are really sure you wish to change the label and are sure that
all of your Oracle and ASM instances have ceased using the disk,
rerun this command with the '-f' option.
EOCAT
    exit 1
fi

if [ "$restore" = "t" ]
then
    restore_device "$OLD" "$NEW"
    exit 0
fi

case "$OLD" in
"$NEW")
    echo "New label is identical to the old one" | asm_log 1
    exit 1
    ;;
*/*)
    relabel_device "$OLD" "$NEW"
    ;;
*)
    relabel_disk "$OLD" "$NEW"
    ;;
esac

exit 0
