Page 1 of 1
Get /dev/sd?? from USB hotplug
Posted: Sat Jan 08, 2005 4:42 pm
by ^rooker
[PROBLEM]
Under Linux kernel 2.4, the
USB-hotplug suite provides some parameters to use in shell scripts when writing your own code for add/remove of USB devices.
In case of USB-sticks (usb-storage module), it is necessary to know which device file has been assigned in order to mount it automatically.
...now this is, where my quest started:
I found out that under kernel 2.4, there seems to be no 'nice' way to get from what you need from the variables that
hotplug provides, and that everyone else seems to simply add a static entry in their fstab.
[SOLUTION]
Hotplug passes the variable $PRODUCT which contains "vendorId/productId/something". I now wrote a perl script which takes only these IDs and uses /proc/scsi/usb-storage* and /proc/scsi/scsi to find out which /dev/sd?? we want.
The next follow-ups contain the interesting parts of my script.
[Step 1] - Prepare the input
Posted: Sat Jan 08, 2005 4:51 pm
by ^rooker
Splits $PRODUCT in product_id and vendor_id and fills them with leading zeros:
Code: Select all
sub prepare_ids {
my ( $product ) = @_;
$product = uc($product);
($vendor, $prod_id) = $product =~ /([0-9A-F]+)\/([0-9A-F]+)\/[0-9A-F]+/;
# prefix IDs with zeros, then take the 4 rightmost chars:
$vendor = substr("0000$vendor", -4);
$prod_id = substr("0000$prod_id", -4);
}
[Step 2] - Find the SCSI HostID
Posted: Sat Jan 08, 2005 4:52 pm
by ^rooker
Compares the GUID field in /proc/scsi/usb-storage-* with the IDs of our stick and if one of the entries matches, remembers its Host-ID:
Code: Select all
sub product_to_scsi {
my ($scsi_procdir) = "/proc/scsi";
my ($dirmask) = "usb-storage-[0-9]";
my (@scsi_dirs, @scsi_infos, @scsi_info);
my ($e1, $e2, $line, $prod_id1, $prod_id2);
my ($match, $hostid);
# List all scsi dirs for usb-storages:
@scsi_dirs = read_dir($scsi_procdir, $dirmask);
foreach $e1 ( @scsi_dirs ) {
@scsi_infos = read_dir("$scsi_procdir/$e1", "[0-9]");
foreach $e2 ( @scsi_infos ) {
@scsi_info = read_file("$scsi_procdir/$e1/$e2");
$match = 0; # Assume that this scsi-entry is NOT what we want
foreach $line (@scsi_info) {
$line = uc($line);
# Check if current entry is attached or not:
if ($line =~ /ATTACHED: NO/) { $match = 0 }; # NOT our device, if not attached.
if ($line =~ /HOST SCSI([0-9]+):.*/) { $hostid = $1 }; # Read SCSI hostid.
# Parse GUID entry in scsi listing, and if it matches our IDs = remember match!
if ($line =~ /GUID: ($vendor)($prod_id)([0-9A-F]{16})/) { $match = 1; }
}
if($match == 1) {
$hostid += 0; # convert string to number
push(@host_ids, $hostid);
}
}
}
}
[Step 3] - From HostID to device position
Posted: Sat Jan 08, 2005 4:57 pm
by ^rooker
Now this is the final step.
/proc/scsi/scsi stores where each Host (by ID) has its devices on the bus.
Code: Select all
sub get_scsi_position {
my ( @host_ids ) = @_;
my ( $scsi_info ) = "/proc/scsi/scsi";
my ( @scsi_info, $line, $hostid, $scsi_dev );
my ( $chan, $id, $lun);
@scsi_info = read_file($scsi_info);
foreach $line (@scsi_info) {
$line = uc($line);
foreach $hostid (@host_ids) {
($chan, $id, $lun) = $line =~ /HOST: SCSI$hostid CHANNEL: ([0-9]{2}) ID: ([0-9]{2}) LUN: ([0-9]{2})/;
if ($lun) {
$lun += 1; # convert to number (and ++).
$scsi_dev = substr($aleph, $hostid, 1);
$scsi_dev = "sd$scsi_dev$lun";
print "$scsi_dev ";
}
}
}
if ($scsi_dev) { print "\n"; } # make sure the output has its own line.
}
[Step 4] - Summary and how-to-call-it
Posted: Sat Jan 08, 2005 5:08 pm
by ^rooker
After putting all those perl parts together, the output will contain something like this:
"sda1 sda2" (multiple partitions on one stick)
"sdc1 sda1" (two sticks with same IDs connected simultaneously)
---------------------------------
When using hotplug, simply add your stick(s) to the /etc/hotplug/usb.usermap file and use it to call a bash script which then uses the info from my program to mount the stick wherever you want it.