USB storage hotplug code.

    * From: Konstantin Riabitsev 
    * To: rhl-devel-list redhat com
    * Subject: USB storage hotplug code.
    * Date: 12 Aug 2003 10:43:22 -0400

Hey, all:

I thought I'd share this little bit of code that I've written to handle
usb-pen/thumbdrive devices that seem to be pretty popular these days
(certainly beats floppies). It is pretty simplistic and will work in 99%
of cases, by my estimates. 

Benefits:
1. Automatically create /dev/diskonkey pointing to the correct device.
2. Automatically create /mnt/diskonkey if missing.
3. Automatically add fstab entries if missing.
4. Automatically set ownership to the console user (if anyone is logged
in -- if not, then the ownership will be set by the /mnt/diskonkey* rule
in /etc/security/console.perms).

Drawbacks:
1. Currently only supports one thumbdrive device at a time, though
support for more should be easy to add (I only have one to play with.
:)).
2. No way to tell nautilus to re-read /etc/fstab to add diskonkey to the
list of mountable devices in rightclick->disks (they claim it's fixed in
the newer version of nautilus, but that doesn't help. Currently sending
killall -$(anysignal) nautilus will kill it, though theoretically a -HUP
should tell it to reread the config). A workaround -- tell your users to
plug in the device before they log in.
3. If partition info changes on the device, then things go screwey, as
devlabel gets confused (e.g. someone deletes /dev/sda1 and decides to
use the entire /dev/sda device instead). This rarely, if ever, happens.
4. This hasn't been overly extensively tested.

Installation instructions are in the file itself. I would love to hear
any feedback on this.

Regards,
-- 
Konstantin ("Icon") Riabitsev
Duke Physics Sysadmin, RHCE

#!/bin/bash
#
# This code is free software covered by GNU GPL license version 2 or above.
# Please refer to http://www.gnu.org/ for the full license text.
#
# Some code lifted from usb-mount by Michael Hamilton's usb-mount (LGPL)
# see http://users.actrix.co.nz/michael/usbmount.html
#
# INSTALL
# -------
# Put this in /etc/hotplug/usb/diskonkey
# Then look in /etc/hotplug/usb.distmap, and copy all usb-storage entries
# into /etc/hotplug/usb.usermap, substituting "usb-storage" for "diskonkey".
# Otherwise this code is only run during the kernel module invocation/removal
# (at least in my tests), which defeats the purpose.
#
# TODO
# ----
# Handle more than one diskonkey device at one time (e.g. /dev/diskonkey1
# and /mnt/diskonkey1), etc. The biggest problem here is the handling in 
# devlabel, which I haven't yet tried.
#
# AUTHOR and SUPPORT
# ------------------
# Konstantin Riabitsev, .
# Send any problem reports to my email address at the moment.
#

SYMLINKDEV=/dev/diskonkey
MOUNTPOINT=/mnt/diskonkey
DEVLABEL=/sbin/devlabel
DEVLABELCONFIG=/etc/sysconfig/devlabel
IAM=$0

##
# Functions lifted near-verbatim from usb-mount code.
#
function allAttachedScsiUsb {
    find /proc/scsi/ -path '/proc/scsi/usb-storage*' -type f | xargs grep -l 'Attached: Yes'
}
function scsiDevFromScsiUsb {
    echo $1 | awk -F"[-/]" '{ n=$(NF-1);  print "/dev/sd" substr("abcdefghijklmnopqrstuvwxyz", n+1, 1) }'
}

if [ "${ACTION}" = "add" ] && [ -f "${DEVICE}" ]; then
    ##
    # lifted from usbcam code.
    #
    if [ -f /var/run/console.lock ]; then
        CONSOLEOWNER=`cat /var/run/console.lock`
    elif [ -f /var/lock/console.lock ]; then
        CONSOLEOWNER=`cat /var/lock/console.lock`
    else
        CONSOLEOWNER=
    fi
    for procEntry in $(allAttachedScsiUsb); do
        scsiDev=$(scsiDevFromScsiUsb $procEntry)
        # Some bug with usb-storage?
        # partitions are not in /proc/partitions until they are accessed
        # somehow.
        /sbin/fdisk -l $scsiDev >/dev/null
        ##
        # Most devices have partitioning info, so the data would be on
        # /dev/sd?1. However, some stupider ones don't have any partitioning
        # and use the entire device for data storage. This tries to 
        # guess semi-intelligently if we have a /dev/sd?1 and if not, then
        # it uses the entire device and hopes for the better.
        #
        if grep -q `basename $scsiDev`1 /proc/partitions; then
            part="$scsiDev""1"
        else
            part=$scsiDev
        fi
        ##
        # Change ownership of the partition to the console user so they can
        # mount it.
        #
        if [ ! -z "$CONSOLEOWNER" ]; then
            chown $CONSOLEOWNER:disk $part
        fi
        ##
        # This checks if we already have this UUID defined with devlabel.
        # If not, it then adds the device to the list.
        #
        prodid=`$DEVLABEL printid -d $part`
        if ! grep -q $prodid $DEVLABELCONFIG; then
            # cross our fingers and hope it works
            $DEVLABEL add -d $part -s $SYMLINKDEV 2>/dev/null
        fi
        ##
        # Check if the mount point exists and create if it doesn't.
        #
        if [ ! -e $MOUNTPOINT ]; then
            mkdir -p $MOUNTPOINT
        fi
        ##
        # Take care of /etc/fstab so mounting is easy.
        #
        if ! grep -q "^$SYMLINKDEV" /etc/fstab; then
            # Add an fstab entry
            echo -e \
                "$SYMLINKDEV\t\t$MOUNTPOINT\t\tauto\tnoauto,owner,kudzu 0 0" \
                >> /etc/fstab
        fi
    done
    if [ ! -z "$REMOVER" ]; then
        ##
        # Make sure this script is triggered on device removal.
        #
        mkdir -p `dirname $REMOVER`
        ln -s $IAM $REMOVER
    fi
elif [ "${ACTION}" = "remove" ]; then
    ##
    # If the device is mounted, unmount it cleanly.
    #
    if grep -q "$MOUNTPOINT" /etc/mtab; then
        # unmount cleanly
        umount -l $MOUNTPOINT
    fi
    ##
    # Remove it from /etc/fstab if it's there.
    #
    if grep -q "^$SYMLINKDEV" /etc/fstab; then
        grep -v "^$SYMLINKDEV" /etc/fstab > /etc/.fstab.new
        mv -f /etc/.fstab.new /etc/fstab
    fi
fi