#!/usr/bin/bash
#
# Copyright (c) 2006, 2025, Oracle and/or its affiliates.
#
# Scan disks to find any ASM disks and perhaps fix their ownership.
#

# Force LC_ALL=C
export LC_ALL=C

USAGE="[-s] [[-o <order_pattern>] ...] [[-x <exclude_pattern>] ...] [[-D <scan_directories>] ...] [-v] [<device> ...]"

exec 3>/dev/null

help=
verbose=
version=
usage=
SCANARGS=
scanonly=
while case "$#" in 0) break ;; esac
do
    case "$1" in
    -o|--scanorder)
        case "$#" in 1) usage=t; break ;; esac
        shift
        SCANARGS="${SCANARGS} -o $1"
        ;;
    -x|--scanexclude)
        case "$#" in 1) usage=t; break ;; esac
        shift
        SCANARGS="${SCANARGS} -x $1"
        ;;
    -D|--scan_directories)
        case "$#" in 1) usage=t; break ;; esac
        shift
        SCANARGS="${SCANARGS} -D $1"
        ;;
    -s|--scanonly)
        scanonly=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
check_oracleasm_config

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

if [ $(echo $UID) != 0 ]
then
    echo "This operation requires root privileges. Please run as root"
    exit 1
fi

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

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

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

for d in ${ORACLEASM_SCAN_DIRECTORIES}
do
    SCANARGS="${SCANARGS} -D $d"
done

to_scan()
{
    if [ $# -gt 0 ]
    then
        for d in "$@"
        do
            echo "$d"
        done
    else
        oracleasm-scan-partitions ${SCANARGS} 2>&3
    fi
}

#
# If we reload the partition table, udev may take time to (re-)create
# the device file.  Thus, we must try a few times on ENOENT.
#
# This is a backoff of four tries:
#
# try1
# sleep 1
# try2
# sleep 3
# try3
# sleep 5
# try4
# fail
#
# We do not retry if --scanonly was specified
#
try_read()
{
    dev="$1"

    delay=1
    rc=0
    info=
    while :
    do
        oracleasm-read-label "$dev"
        rc=$?

        [ "$scanonly" = "t" ] && break

        #
        # oracleasm-read-label returns -errno, but return codes are positive
        # eight-bit values.  So -ENOENT (-2) is 254.
        #
        [ $rc != 254 ] && break

        [ $delay -gt 5 ] && break
        sleep $delay
        delay="$(expr $delay + 2)"
    done

    return $rc
}

if [ -z "$scanonly" ]
then
    echo -n "Reloading disk partitions: "
    if [ "$ORACLEASM_DRIVER_SUPPORTED" = "true" ]
    then
	to_scan "$@" | oracleasm-reload-partitions 2>&3
	echo "done"
        oracleasm-dropdisks -v 2>&3
    else
	echo "done"
	# To keep compatibiity with v2 messages just print
	# the message about Cleaning ASM disks.
	echo "Cleaning any stale ASM disks..."
    fi
fi

#
# For v3 interface, scan and add ASM disks to iofilter map.
#
if [ "$ORACLEASM_DRIVER_SUPPORTED" = "false" ]
then
    # Remove any existing BPF filter map.
    rm -rf ${ORACLEASM_IOFILTER_MAP_PATH}
    # Recreate the BPF filter map.
    iofilter_init
    if [ $? = 1 ]
    then
        echo "Failed to set up iofilter map" | asm_log 1
        exit 1
    fi
    # get list of ASM disks and add them to iofilter map
    echo "Scanning system for ASM disks..." | asm_log 1
    oracleasm-listdisks 2>&3 | while read LINE
    do
	iofilter_map_add "${LINE}" | asm_log 2
	if [ $? != 0 ]
	then
            echo "Failed to add disk \"${LABEL}\" to iofilter map" | \
		asm_log 1
	fi
        perm_disk "${LINE}" 2>&3
        if [ $? = 1 ]
        then
            echo "Unable to fix permissions on ASM disk \"$LINE\"" | asm_log 1
            exit 1
        fi
    done
    exit 0
fi

echo "Scanning system for ASM disks..." | asm_log 1

to_scan "$@" | while read dev
    do
        INFO="$(try_read "$dev" 2>&3)"
        if [ $? != 0 ]
        then
            continue
        fi
        if [ -z "$INFO" ]
        then
            continue
        fi

        LABEL="$(echo "$INFO" | cut -f1 -d:)"
        if [ -z "$LABEL" ]
        then
            continue
        fi

        if oracleasm-querydisk "${LABEL}" 1>&3 2>&3
        then
                continue
        fi

        echo "Instantiating disk \"${LABEL}\""
        oracleasm-instantiate-disk "${dev}" "${LABEL}" 2>&3
        if [ $? != 0 ]
        then
            echo "Unable to instantiate disk \"${LABEL}\"" | asm_log 1
        fi
    done

oracleasm-listdisks 2>&3 | while read LINE
    do
        perm_disk "${LINE}" 2>&3
        if [ $? = 1 ]
        then
            echo "Unable to fix permissions on ASM disk \"$LINE\"" | asm_log 1
            exit 1
        fi
    done

exit 0
