Get /dev/sd?? from USB hotplug

Linux howto's, compile information, information on whatever we learned on working with linux, MACOs and - of course - Products of the big evil....
Post Reply
User avatar
^rooker
Site Admin
Posts: 1483
Joined: Fri Aug 29, 2003 8:39 pm

Get /dev/sd?? from USB hotplug

Post 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.
Last edited by ^rooker on Sat Jan 08, 2005 5:09 pm, edited 2 times in total.
User avatar
^rooker
Site Admin
Posts: 1483
Joined: Fri Aug 29, 2003 8:39 pm

[Step 1] - Prepare the input

Post 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);


}
Last edited by ^rooker on Sat Jan 08, 2005 4:54 pm, edited 1 time in total.
User avatar
^rooker
Site Admin
Posts: 1483
Joined: Fri Aug 29, 2003 8:39 pm

[Step 2] - Find the SCSI HostID

Post 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);
			}
		}
	}
}
User avatar
^rooker
Site Admin
Posts: 1483
Joined: Fri Aug 29, 2003 8:39 pm

[Step 3] - From HostID to device position

Post 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.
}
User avatar
^rooker
Site Admin
Posts: 1483
Joined: Fri Aug 29, 2003 8:39 pm

[Step 4] - Summary and how-to-call-it

Post 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.
Post Reply