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


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

exec 3>/dev/null

help=
verbose=
version=
usage=
force=
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
        ;;
    -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}\"" >&2
            fi
            ;;
        *)
            ;;
        esac
        die "Unable to open ASM disk \"${OLD}\""
    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"
            die "Unable to instantiate disk \"${NEW}\""
        fi

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

        echo -n "Writing disk header: "
        oracleasm-write-label -f "${old_path}" "${NEW}" 2>&3
        if [ $? != 0 ]
        then
            oracleasm-clean-disk -l "${ORACLE_ASMMANAGER}" "${NEW}" 2>&3
            echo "failed"
            die "Unable to label disk \"${NEW}\""
        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"
        die "Unable to remove ${old_dispos} ASM disk \"${OLD}\""
    fi
    echo "done"

    if [ -n "$error" ]
    then
        die "$error"
    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
            die "Device \"${DEV}\" is not labeled for ASM"
        else
            die "Unable to read device \"${DEV}\""
        fi
    fi    

    OLD="$(echo "$INFO" | cut -f1 -d:)"
    if [ "${OLD}" = "${NEW}" ]
    then
        die "Device \"${DEV}\" is already labeled \"${NEW}\""
    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"
                die "Unable to remove ${old_dispos} ASM disk \"${OLD}\""
            fi
            echo "done"
        fi
    fi

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

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

    perm_disk "${new_path}"
    if [ $? = 1 ]
    then
        echo "failed"
        die "Unable to change ownership of disk \"${NEW}\""
    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

case "$OLD" in
"$NEW")
    die "New label is identical to the old one"
    ;;
*/*)
    relabel_device "$OLD" "$NEW"
    ;;
*)
    relabel_disk "$OLD" "$NEW"
    ;;
esac

exit 0
