#!/lib/klibc/bin/sh
# $Id: udev.get_unique_drive_id.sh 274 2005-04-18 06:34:27Z hare $
#set -x

# this script should provide the disk id 

# example for all:
# for i in `find /sys/block -name dev` ;do DEVPATH="`echo $i | sed -e 's@^/sys\|/dev@@g'`" $0 ; done

PATH=/lib/klibc/bin:/bin:/sbin #/usr:/usr/sbin:/usr/bin:/sbin:/bin
SYSFS=/sys
export PATH
RESULT=1
# required variables from the kernel
DEVPATH=$DEVPATH
# optional variables from the kernel
PHYSDEVPATH=$PHYSDEVPATH
SUBSYSTEM=$SUBSYSTEM
#
OPWD="`pwd`"
# Check for 'pwd -P'
if $(pwd -P > /dev/null 2>&1); then
    pwd_cmd="pwd -P"
else
    pwd_cmd="pwd"
fi
# Check for udevinfo
if [ -x /usr/bin/udevinfo ] ; then
	UDEVINFO=/usr/bin/udevinfo
elif [ -x /sbin/udevinfo.static ] ; then
	UDEVINFO=/sbin/udevinfo.static
elif [ -x /sbin/udevinfo ] ; then
	UDEVINFO=/sbin/udevinfo
fi

full_sysfs_class_path=
full_sysfs_device_path=
is_partition=false
disk_id=

get_scsi_type () {
    local type

    read type < $1/type
    case "$type" in
	0)
	    # Direct-access device
	    devtype=disk
	    ;;
	1)
	    # Sequential access device
	    devtype=tape
	    ;;
	2)
	    # Printer device
	    devtype=printer
	    ;;
	3)
	    # Processor device
	    devtype=scanner
	    ;;
	4)
	    # Write-once device
	    devtype=cd
	    ;;
	5)
	    # CD-ROM device
	    devtype=cd
	    ;;
	6)
	    # Scanner device
	    devtype=scanner
	    ;;
	7)
            # Optical memory device
	    devtype=disk
	    ;;
	8)
	    # Medium changer devices
	    devtype=generic
	    ;;
	9)
	    # Communications device
	    devtype=generic
	    ;;
	10|11)
	    # Graphic arts pre-press device
	    devtype=generic
	    ;;
	12)
	    # Storage array controller
	    devtype=generic
	    ;;
	13)
	    # Enclosure service device
	    devtype=generic
	    ;;
	14)
	    # Simplified direct-access device
	    devtype=generic
	    ;;
	15)
	    # Optical card reader/writer device
	    devtype=generic;
	    ;;
	*)
	    devtype=generic;
	    ;;
    esac

    echo $devtype
}

if [ -z "$DEVPATH" -a -z "$1" ] ; then
	exit 1
fi
if [ -z "$DEVPATH" ] ; then
	case "$1" in
		$SYSFS/*)
		DEVPATH="${1#$SYSFS}"
		;;
		*)
		DEVPATH=$1
		;;
	esac
fi

if [ ! -d $SYSFS$DEVPATH ] ; then
	exit 1
fi
if [ ! -f $SYSFS$DEVPATH/dev ] ; then
	exit 1
fi


if [ -z "$SUBSYSTEM" ] ; then
	case "$DEVPATH" in
		/block/*)
			SUBSYSTEM=block
			;;
		/class/*)
			SUBSYSTEM="${DEVPATH#/class/}"
			SUBSYSTEM="${SUBSYSTEM%%/*}"
			;;
		*)
			exit 1
			;;
	esac
fi

#
##
#


case "$SUBSYSTEM" in
	scsi_generic)
	if [ ! -d $SYSFS$DEVPATH/device/block ] ; then
		exit 1
	fi
	if [ -z "$PHYSDEVPATH" ] ; then
		cd $SYSFS$DEVPATH/device/block || exit 1
		PHYSDEVPATH="`$pwd_cmd`"
		cd "$OPWD"
		PHYSDEVPATH="${PHYSDEVPATH#$SYSFS}"
	fi
	;;
	block)
	if [ -f $SYSFS$DEVPATH/range -a -L $SYSFS$DEVPATH/device ] ; then
		read major_minor < $SYSFS$DEVPATH/dev
		cd $SYSFS$DEVPATH/device
		fulldevpath="`$pwd_cmd`"
		if [ -d block ]; then
		    cd block
		    fullblockpath="`$pwd_cmd`"
		fi
		blockdevpath=$DEVPATH
		cd "$OPWD"
	else
		if [ ! -L $SYSFS$DEVPATH/../device -a ! -f $SYSFS$DEVPATH/../range ] ; then
			exit 1
		fi
		read major_minor < $SYSFS$DEVPATH/../dev
		cd $SYSFS$DEVPATH/../device
		fulldevpath="`$pwd_cmd`"
		if [ -d block ]; then
		    cd block
		    fullblockpath="`$pwd_cmd`"
		fi
		blockdevpath=${DEVPATH%/*}
		cd "$OPWD"
		SUBSYSTEM=partition
	fi
	;;
	usb)
		cd $SYSFS$DEVPATH/device || exit 1
		PHYSDEVPATH="`$pwd_cmd`"
		cd "$OPWD"
		PHYSDEVPATH="${PHYSDEVPATH#$SYSFS}"
	;;
esac

major=${major_minor%%:*}
minor=${major_minor##*:}
mynode=/dev/shm/diskid_tmpnode.$major.$minor.$$
devtype="generic"

#
#
handle_partition() {
    # look for a partition number
    dp="`echo $DEVPATH | sed -e 's@^.*[^0-9]@@'`"
    suffix="p${dp}"

    set -- $($UDEVINFO -q symlink -p $blockdevpath)
    symlink_num=$#
    while [ $# -gt 0 ] ; do
	sym=$1
	case "$sym" in
		*[0-9])
                        suffix="p${dp}"
			;;
		*)
		        suffix="${dp}"
			;;
	esac
	echo -n "${sym}${suffix} "
	shift
    done
    echo ""
    if [ $symlink_num -gt 0 ]; then
	    return 0
    else
	    return 1
    fi
}

#
#
handle_block () {
    case "$fulldevpath" in
	# USB devices are mapped onto SCSI
	*/usb[0-9]*/*)
            # Use the attributes from sysfs instead of doing a full-blown
            # INQUIRY as USB is notoriously slow and buggy
            if [ -f $fulldevpath/model ]; then
		read m < $fulldevpath/model
		model="`echo $m | sed -e 's@ @_@g;s@/@.@g'`"
	    fi
	    if [ -f $fulldevpath/vendor ]; then
		read v < $fulldevpath/vendor
		vendor="`echo $v | sed -e 's@ @_@g;s@/@.@g'`"
	    fi
	    if [ -f $fulldevpath/type ] ; then
		devtype="`get_scsi_type $fulldevpath`"
	    fi
	    if [ -z "$vendor" -o -z "$model" ]; then
		# No vendor or model attribute. 
		cil="${fulldevpath##*/}"
		cil="${cil#*:}"
		controller_dev=$fulldevpath
		while [ ! -z "$controller_dev" ] ; do
			case "$controller_dev" in
				*/host[0-9]*)
				controller_dev="${controller_dev%/*}"
				;;
				*) break ;;
			esac
		done
		: controller_dev $controller_dev
		#
		# Try to get the USB serial number
		serial=
		if [ -f $controller_dev/../serial ] ; then
		    serial="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789]@@g' < $controller_dev/../serial`"
		    : serial XXX_${serial}_XXX
		    devtype=disk
		    disk_id="$serial"
		    serial="`echo $serial | sed -e 's@[ 0]\{1,\}@@g'`"
		fi
		if [ -z "$serial" ] ; then
		    # no serial, broken device
		    # has eventually binary junk in vpd
		    identifier=
		    if [ -f $controller_dev/../product ] ; then
			product="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789]@@g' < $controller_dev/../product`"
		    fi
		    if [ -f $controller_dev/../manufacturer ] ; then
			manufacturer="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789]@@g' < $controller_dev/../manufacturer`"
		    fi
		    if [ -z "$product" -o -z "$manufacturer" ] ; then
			read idvendor < $controller_dev/../idVendor
			read idproduct < $controller_dev/../idProduct
			identifier="0x${idvendor}-0x${idproduct}"
		    else
			identifier="${manufacturer}-${product}"
		    fi
		    devtype=disk
		    disk_id="${identifier}"
		fi
	    else
		disk_id="$vendor-$model"
	    fi
	    ;;
	# ide-scsi is CD only
	*/ide*/*/host*/*)
		: skip ide-scsi: $fulldevpath
		return 1
		;;
	*/iscsi/*)
	        # iSCSI disks
	        : looking at iSCSI $fulldevpath
	        p="`echo $fulldevpath |  sed -e 's@/iscsi/[0-9]\{1,\}:@/@'`"
		cil="`echo $p |  sed -e 's@^.*/@@'`"
		if [ -r /sys/class/scsi_host/iscsi/print_info ]; then
		    while read bus tgt lun ip port target; do
			if [ -n "$bus" -a "$bus" != "#" ]; then
			    if [ "${bus}:${tgt}:${lun}" = "$cil" ]; then
				disk_id="iscsi-$target-$lun"
			    fi
			fi
		    done < /sys/class/scsi_host/iscsi/print_info
		fi
		if [ "$disk_id" ]; then
		    RESULT=0
		    devtype=disk
		else
		    RESULT=1
		fi
	;;
	# scsi devices
	# firewire sbp2 has a GUID, but it may provide the serial of the disk
	*/host[0-9]*/[0-9]*:[0-9]*:[0-9]*:[0-9]*)
		# check for ieee1394 sbp2 
		# do not call scsi_id for firewire disks, it may hang
		if [ -f $fulldevpath/ieee1394_id ] ; then
			return 1
		fi
		: looking at scsi $fulldevpath
		disk_id="`scsi_id -gs $DEVPATH`"
		if [ $? -ne 0 ]; then
		    # Not all SCSI devices support EVPD. Fallback to
		    # model_vendor for those cases
		    read model < $fulldevpath/model
		    read vendor < $fulldevpath/vendor
		    disk_id="${vendor}_${model}"
		fi
		: disk_id XXX${disk_id}XXX
 
		case "$disk_id" in
			*Linux\ ATA-SCSI\ simulator)
			disk_id="`scsi_id  -p 0x80 -gs $DEVPATH`"
			: STATA disk_id XXX${disk_id}XXX
			;;
			*)
			;;
		esac
		# removes also leading and trailing whitespaces
		disk_id="`echo $disk_id | sed -e 's@ \+@_@g'`"
		if [ -f $fulldevpath/type ] ; then
		    devtype="`get_scsi_type $fulldevpath`"
		fi
	;;
	# ide devices
	*/ide[0-9]/[0-9].[0-9]*|*/ide[0-9][0-9]/[0-9][0-9].[0-9]*)
		
		: looking at ide $fulldevpath
		rm -f $mynode
		/bin/mknod -m 600 $mynode b $major $minor 2> /dev/null
		if [ $? -eq 0 -a -b $mynode ]; then
		    disk_id="`ata_identify $mynode`"
		    if [ $? -ne 0 ]; then
			disk_id=
		    fi
		    rm -f $mynode
		fi
		if [ -f /proc/ide/${fullblockpath##*/}/media ]; then
		    read media < /proc/ide/${fullblockpath##*/}/media
		    case "$media" in
			disk)
			    devtype=disk
			    ;;
			cdrom)
			    devtype=cd
			    ;;
			tape)
			    devtype=tape
			    ;;
			floppy)
			    devtype=disk
			    ;;
			*)
			    devtype=generic
			    ;;
		    esac
		fi
	;;
	*/css0/*)
	        # S/390 DASDs
		: looking at dasd $fulldevpath
		rm -f $mynode
		mknod -m 600 $mynode b $major $minor
	        disk_id="`/sbin/dasdview -j -f $mynode`"
		if [ ! $? ]; then
		    disk_id=
		else
		    disk_id=${disk_id%% *}
		    devtype=disk
		fi
		rm -f $mynode
	;;
	*)
		: $fulldevpath not handled
		return 1
	;;
    esac
# done
return 0
}

handle_usb() {
	if [ -f $SYSFS$PHYSDEVPATH/model ]; then
		read m < $SYSFS$PHYSDEVPATH/model
		model="`echo $m | sed -e 's@ @_@g;s@/@.@g'`"
	fi
	if [ -f $SYSFS$PHYSDEVPATH/vendor ]; then
		read v < $SYSFS$PHYSDEVPATH/vendor
		vendor="`echo $v | sed -e 's@ @_@g;s@/@.@g'`"
	fi
	if [ -z "$vendor" -o -z "$model" ]; then
		# No vendor or model attribute. 
		# Try to get the USB serial number
		serial=
		if [ -f $SYSFS$PHYSDEVPATH/../serial ] ; then
		    serial="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789]@@g' < $SYSFS$PHYSDEVPATH/../serial`"
		    : serial XXX_${serial}_XXX
		    usblpid="$serial"
		    serial="`echo $serial | sed -e 's@[ 0]\{1,\}@@g'`"
		fi
		if [ -z "$serial" ] ; then
		    # no serial, broken device
		    # has eventually binary junk in vpd
		    identifier=
		    if [ -f $SYSFS$PHYSDEVPATH/../product ] ; then
			product="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789]@@g' < $SYSFS$PHYSDEVPATH/../product`"
		    fi
		    if [ -f $SYSFS$PHYSDEVPATH/../manufacturer ] ; then
			manufacturer="`sed -e 's@^[ -]\{1,\}\|[ -]\{1,\}$@@g;s@[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789]@@g' < $fulldevpath/../manufacturer`"
		    fi
		    if [ -z "$product" -o -z "$manufacturer" ] ; then
			read idvendor < $SYSFS$PHYSDEVPATH/../idVendor
			read idproduct < $SYSFS$PHYSDEVPATH/../idProduct
			identifier="0x${idvendor}-0x${idproduct}"
		    else
			identifier="${manufacturer}-${product}"
		    fi
		    usblpid="${identifier}"
		fi
	else
		usblpid="$vendor-$model"
	fi
return 0
}

case "$SUBSYSTEM" in
	block)
	if ! handle_block; then
	    : not handled
	    exit 1
	fi

	if [ -z "$disk_id" -o "$devtype" = "generic" ]; then
	    : not handled
	    exit 1
	fi

	# Reset CDROM devices for backwards compability
	# if [ "$devtype" = "cd" ]; then
	#    devtype=disk
	# fi

	if [ ! -z "$disk_id" ] ; then
		echo "$devtype/by-id/$disk_id"
	fi
	RESULT=0
	;;
        partition)

	if [ -z "$UDEVINFO" ] ; then
		: not handled
		exit 1
	fi

	if ! handle_partition; then
		: not handled
		exit 1
	fi
	RESULT=0
	;;
	scsi_generic)
	if ! handle_block; then
	    : not handled
	    exit 1
	fi

	if [ -z "$disk_id" ]; then
	    : not handled
	    exit 1
	else
	    echo "generic/by-id/$disk_id"
	fi
	RESULT=0
	;;
	usb)
	if ! handle_usb; then
	    : not handled
	    exit 1
	fi
	echo "printer/by-id/usb-printer-$usblpid"
	RESULT=0
	;;
	*)
	RESULT=1
	;;
esac
exit $RESULT
