CHECK_SIZE=false
CHECK_MODEL=false
CHECK_VENDOR=false
CHECK_UUID=false
CHECK_WWN=false
CHECK_HCTL=false
CHECK_SERIAL=false


# URL/Percent decode a text
function urldecode() {
    local encoded="${1//+/ }"
    printf '%b' "${encoded//%/\x}"
}


# Lowercase and url decode the values
function normalize() {
    echo `urldecode "${1,,}"`
}


function _exec_lsblk() {
    lsblk -Pbio $2 /dev/$1 | head -n 1 | grep -Po "(?<=^$2=).*" | tr "\"" " "
}


# Get the block device size in GiB
function get_size() {
    echo $(( (512 * $(cat /sys/block/$1/size) ) / 2**30))
}


function get_model() {
    local file
    file=/sys/block/$1/device/model
    if [ -f $file ]; then
        normalize "$(cat $file)"
    fi
}


function get_vendor() {
    local file
    file=/sys/block/$1/device/vendor
    if [ -f $file ]; then
        normalize "$(cat $file)"
    fi
}


function get_wwn() {
    normalize "$(_exec_lsblk "$1" WWN)"
}


function get_serial() {
    normalize "$(_exec_lsblk "$1" SERIAL)"
}


# Parse all the hints from the Kernel cmdline and set the CHECK_*
# variables
function parse_hints() {
    IFS=',' read -ra H <<< "$ROOT_DEVICE"
    for i in "${H[@]}"; do
        case "$i" in
                size=*)
                    CHECK_SIZE="${i#size=}"
                ;;
                model=*)
                    CHECK_MODEL=`normalize "${i#model=}"`
                ;;
                vendor=*)
                    CHECK_VENDOR=`normalize "${i#vendor=}"`
                ;;
                wwn=*)
                    CHECK_WWN=`normalize "${i#wwn=}"`
                ;;
                serial=*)
                    CHECK_SERIAL=`normalize "${i#serial=}"`
                ;;
                *)
                ;;
        esac
    done
}


function get_root_device() {
    # Parse the hints
    parse_hints

    for DEV in /sys/block/* ; do
        DEV_NAME=${DEV##*/}
        DEV_PATH=/dev/$DEV_NAME

        # Ignore loop and ram devices
        [[ $DEV_NAME = *loop* || $DEV_NAME = *ram* ]] && continue || :

        # Find out if it's a CDROM
        TYPE=/sys/block/$DEV_NAME/device/type
        [[ -f $TYPE ]] && (( $(cat "$TYPE") == 5 )) && continue || :

        [[ $CHECK_SIZE != false && $(get_size "$DEV_NAME") != $CHECK_SIZE ]] && continue || :
        [[ $CHECK_MODEL != false && $(get_model "$DEV_NAME") != $CHECK_MODEL ]] && continue || :
        [[ $CHECK_VENDOR != false && $(get_vendor "$DEV_NAME") != $CHECK_VENDOR ]] && continue || :
        [[ $CHECK_SERIAL != false && $(get_serial "$DEV_NAME") != $CHECK_SERIAL ]] && continue || :
        [[ $CHECK_WWN != false && $(get_wwn "$DEV_NAME") != $CHECK_WWN ]] && continue || :

        # A device that matches all hints was found
        echo "$DEV_PATH"
        break
    done
}
