#!/bin/sh

# This script searches for all attached USB storage devices and
# outputs information about the available block devices. Information
# is output for each partition on the device, but if the device has
# no partitions information for the whole device is output instead.
# For each one partition one line is printed with the
# sysfs block device path, the block device node name, the disk partition
# size in 512 byte blocks and the total disk size in 512 byte blocks;
# fields are separate by colons (:).

SYSFS_DRIVER_PATH=/sys/bus/usb/drivers/usb-storage

# Find all the block device links using usb-storage
# NOTE: provide maxdepth to avoid symlink loops from creating an infinite find,
# and do not descend into 'driver' since that gets back links for all devices.
SYSFS_BLINKS="$(find "$SYSFS_DRIVER_PATH" -follow -maxdepth 20 \( -name block -print \) -o \( -name driver -prune \) )"

# Resolve the links to /sys/block names
SYSFS_BLOCK=
for l in $SYSFS_BLINKS; do
    cd "$l" 2>/dev/null || continue
    b="$(pwd -P)"
    if [ -z "$SYSFS_BLOCK" ]; then	
	SYSFS_BLOCK="$b"
    else
	SYSFS_BLOCK="$SYSFS_BLOCK"$'\n'"$b"
    fi
    cd -
done

# Remove duplicate entries by sorting
SYSFS_BLOCK="$(echo "$SYSFS_BLOCK" | sort -u)"

# Print out an entry for each one
for d in $SYSFS_BLOCK; do
    n="$(basename $d)"
    ds="$(< "$d"/size)"
    parts="$(find "$d" -maxdepth 1 -name "${n}[0-9]*" -print)"
    if [ -z "$parts" ]; then
	parts="$d" # No partitions, report whole block device
    fi
    for p in "$parts"; do
	if [ -d "$p" ]; then
	    dev="$(udevinfo -q name -p "${p#/sys}" 2>/dev/null)"
	    [ -n "$dev" ] && dev=/dev/"$dev"
	    ps="$(< "$p"/size)"
	    echo "$p:$dev:$ps:$ds"
	fi
    done
done
