Difference between revisions of "Map Custom Device Entries with udev"

From ArchWiki
Jump to: navigation, search
(1. Get the udev info for your usb device)
(updated for the latest udev)
Line 1: Line 1:
 
[[Category:Hardware]]
 
[[Category:Hardware]]
  
WIP - DibbleTheWrecker
+
This information is basically mirrored from the gentoo wiki with some additional hints. Recently it was updated to reflect changes in udev >= 98 syntax.
  
=== Use udev and hotplug to map multiple nodes to a device===
+
This process allows you to always map a specific device to the same <code>/dev</code> node. This can then be used in <code>fstab</code> to ensure you can always mount the device same device in exactly the same place - which is great for desktop shortcuts!
  
This information is basically mirrored from the gentoo wiki with some additional hints.
+
== Get the udev info for your USB device==
  
This process allows you to always map a specific device to the same /dev node. This can then be used in fstab to ensure you can always mount the device same device in exactly the same place - which is great for desktop shortcuts!
+
Make sure one of your target devices is plugged in and then run the following as root:
 +
udevinfo -a -p `udevinfo -q path -n /dev/sda`
 +
 
 +
This gets the udev device info for the device on <code>/dev/sda</code> - if your device is not mapped to <code>/dev/sda</code> then obviously use the correct mapping. :)
 +
 
 +
You should get some output like this:
 +
<pre>
 +
 
 +
Udevinfo starts with the device specified by the devpath and then
 +
walks up the chain of parent devices. It prints for every device
 +
found, all possible attributes in the udev rules key format.
 +
A rule to match, can be composed by the attributes of the device
 +
and the attributes from one single parent device.
 +
 
 +
  looking at device '/block/sda':
 +
    KERNEL=="sda"
 +
    SUBSYSTEM=="block"
 +
    DRIVER==""
 +
    ATTR{stat}=="      19      111      137      160        0        0        0        0        0      152      160"
 +
    ATTR{size}=="2007040"
 +
    ATTR{removable}=="1"
 +
    ATTR{range}=="16"
 +
    ATTR{dev}=="8:0"
 +
 
 +
  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0':
 +
    KERNELS=="5:0:0:0"
 +
    SUBSYSTEMS=="scsi"
 +
    DRIVERS=="sd"
 +
    ATTRS{ioerr_cnt}=="0x0"
 +
    ATTRS{iodone_cnt}=="0x1c"
 +
    ATTRS{iorequest_cnt}=="0x1c"
 +
    ATTRS{iocounterbits}=="32"
 +
    ATTRS{timeout}=="30"
 +
    ATTRS{state}=="running"
 +
    ATTRS{rev}=="1.20"
 +
    ATTRS{model}=="01GB Tiny      "
 +
    ATTRS{vendor}=="Pretec  "
 +
    ATTRS{scsi_level}=="3"
 +
    ATTRS{type}=="0"
 +
    ATTRS{queue_type}=="none"
 +
    ATTRS{queue_depth}=="1"
 +
    ATTRS{device_blocked}=="0"
 +
    ATTRS{max_sectors}=="240"
 +
 
 +
  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5/1-5:1.0/host5/target5:0:0':
 +
    KERNELS=="target5:0:0"
 +
    SUBSYSTEMS==""
 +
    DRIVERS==""
 +
 
 +
  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5/1-5:1.0/host5':
 +
    KERNELS=="host5"
 +
    SUBSYSTEMS==""
 +
    DRIVERS==""
  
==== 1. Get the udev info for your usb device====
+
  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5/1-5:1.0':
 +
    KERNELS=="1-5:1.0"
 +
    SUBSYSTEMS=="usb"
 +
    DRIVERS=="usb-storage"
 +
    ATTRS{modalias}=="usb:v4146pBA01d0100dc00dsc00dp00ic08isc06ip50"
 +
    ATTRS{bInterfaceProtocol}=="50"
 +
    ATTRS{bInterfaceSubClass}=="06"
 +
    ATTRS{bInterfaceClass}=="08"
 +
    ATTRS{bNumEndpoints}=="03"
 +
    ATTRS{bAlternateSetting}==" 0"
 +
    ATTRS{bInterfaceNumber}=="00"
  
Make sure one of your target devices is plugged in and then run the following as root:
+
  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5':
 +
    KERNELS=="1-5"
 +
    SUBSYSTEMS=="usb"
 +
    DRIVERS=="usb"
 +
    ATTRS{configuration}==""
 +
    ATTRS{serial}=="14AB0000000096"
 +
    ATTRS{product}=="USB Mass Storage Device"
 +
    ATTRS{maxchild}=="0"
 +
    ATTRS{version}==" 2.00"
 +
    ATTRS{devnum}=="7"
 +
    ATTRS{speed}=="480"
 +
    ATTRS{bMaxPacketSize0}=="64"
 +
    ATTRS{bNumConfigurations}=="1"
 +
    ATTRS{bDeviceProtocol}=="00"
 +
    ATTRS{bDeviceSubClass}=="00"
 +
    ATTRS{bDeviceClass}=="00"
 +
    ATTRS{bcdDevice}=="0100"
 +
    ATTRS{idProduct}=="ba01"
 +
    ATTRS{idVendor}=="4146"
 +
    ATTRS{bMaxPower}==" 98mA"
 +
    ATTRS{bmAttributes}=="80"
 +
    ATTRS{bConfigurationValue}=="1"
 +
    ATTRS{bNumInterfaces}==" 1"
  
<pre>udevinfo -a -p `udevinfo -q path -n /dev/sda`
+
  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1':
</pre>
+
    KERNELS=="usb1"
 +
    SUBSYSTEMS=="usb"
 +
    DRIVERS=="usb"
 +
    ATTRS{configuration}==""
 +
    ATTRS{serial}=="0000:00:02.2"
 +
    ATTRS{product}=="EHCI Host Controller"
 +
    ATTRS{manufacturer}=="Linux 2.6.18-ARCH ehci_hcd"
 +
    ATTRS{maxchild}=="6"
 +
    ATTRS{version}==" 2.00"
 +
    ATTRS{devnum}=="1"
 +
    ATTRS{speed}=="480"
 +
    ATTRS{bMaxPacketSize0}=="64"
 +
    ATTRS{bNumConfigurations}=="1"
 +
    ATTRS{bDeviceProtocol}=="01"
 +
    ATTRS{bDeviceSubClass}=="00"
 +
    ATTRS{bDeviceClass}=="09"
 +
    ATTRS{bcdDevice}=="0206"
 +
    ATTRS{idProduct}=="0000"
 +
    ATTRS{idVendor}=="0000"
 +
    ATTRS{bMaxPower}=="  0mA"
 +
    ATTRS{bmAttributes}=="e0"
 +
    ATTRS{bConfigurationValue}=="1"
 +
    ATTRS{bNumInterfaces}==" 1"
  
If this method works for you then just and "| grep SYSFS{serial}" when you get to the next part.
+
  looking at parent device '/devices/pci0000:00/0000:00:02.2':
 +
    KERNELS=="0000:00:02.2"
 +
    SUBSYSTEMS=="pci"
 +
    DRIVERS=="ehci_hcd"
 +
    ATTRS{broken_parity_status}=="0"
 +
    ATTRS{enable}=="1"
 +
    ATTRS{modalias}=="pci:v000010DEd00000068sv00001043sd00000C11bc0Csc03i20"
 +
    ATTRS{local_cpus}=="f"
 +
    ATTRS{irq}=="17"
 +
    ATTRS{class}=="0x0c0320"
 +
    ATTRS{subsystem_device}=="0x0c11"
 +
    ATTRS{subsystem_vendor}=="0x1043"
 +
    ATTRS{device}=="0x0068"
 +
    ATTRS{vendor}=="0x10de"
  
This gets the udev device info for the device on /dev/sda - if your device is not mapped to /dev/sda then obviously use the correct mapping :)
+
  looking at parent device '/devices/pci0000:00':
 +
    KERNELS=="pci0000:00"
 +
    SUBSYSTEMS==""
 +
    DRIVERS==""
  
You should get some output like this:
+
</pre>
  
<pre>
+
Bit too much information!  The only bit of this you actaully need is the <code>ATTRS<serial}</code> part - so now you know what the above command does just grep out the bit you want in future cases:
udevinfo starts with the device the node belongs to and then walks up the
 
device chain, to print for every device found, all possibly useful attributes
 
in the udev key format.
 
Only attributes within one device section may be used together in one rule,
 
to match the device for which the node will be created.
 
  
device '/sys/block/sda/sda1' has major:minor 8:1
+
udevinfo -a -p `udevinfo -q path -n /dev/sda` | grep ATTRS{serial}
  looking at class device '/sys/block/sda/sda1':
 
    SYSFS{dev}="8:1"
 
    SYSFS{size}="499195"
 
    SYSFS{start}="4"
 
    SYSFS{stat}="      84      84      202      202"
 
  
follow the class device's "device"
+
output:
  looking at the device chain at '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0':
 
    BUS="scsi"
 
    ID="0:0:0:0"
 
    SYSFS{detach_state}="0"
 
    SYSFS{device_blocked}="0"
 
    SYSFS{max_sectors}="240"
 
    SYSFS{model}="disgo          "
 
    SYSFS{queue_depth}="1"
 
    SYSFS{rev}="4.70"
 
    SYSFS{scsi_level}="3"
 
    SYSFS{state}="running"
 
    SYSFS{timeout}="30"
 
    SYSFS{type}="0"
 
    SYSFS{vendor}="        "
 
  
  looking at the device chain at '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1:1.0/host0/target0:0:0':
+
     ATTRS{serial}=="14AB0000000096"
     BUS=""
+
     ATTRS{serial}=="0000:00:02.2"
    ID="target0:0:0"
 
     SYSFS{detach_state}="0"
 
  
  looking at the device chain at '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1:1.0/host0':
+
Hmm, two serials. Which one to use?
    BUS=""
 
    ID="host0"
 
    SYSFS{detach_state}="0"
 
  
  looking at the device chain at '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1:1.0':
+
udevinfo -a -p `udevinfo -q path -n /dev/sda` | grep ATTRS{product}
    BUS="usb"
 
    ID="1-1:1.0"
 
    SYSFS{bAlternateSetting}=" 0"
 
    SYSFS{bInterfaceClass}="08"
 
    SYSFS{bInterfaceNumber}="00"
 
    SYSFS{bInterfaceProtocol}="50"
 
    SYSFS{bInterfaceSubClass}="06"
 
    SYSFS{bNumEndpoints}="02"
 
    SYSFS{detach_state}="0"
 
  
  looking at the device chain at '/sys/devices/pci0000:00/0000:00:1d.0/usb1/1-1':
+
and we get
    BUS="usb"
 
    ID="1-1"
 
    SYSFS{bConfigurationValue}="1"
 
    SYSFS{bDeviceClass}="00"
 
    SYSFS{bDeviceProtocol}="00"
 
    SYSFS{bDeviceSubClass}="00"
 
    SYSFS{bMaxPower}="178mA"
 
    SYSFS{bNumConfigurations}="1"
 
    SYSFS{bNumInterfaces}=" 1"
 
    SYSFS{bcdDevice}="0200"
 
    SYSFS{bmAttributes}="80"
 
    SYSFS{detach_state}="0"
 
    SYSFS{devnum}="2"
 
    SYSFS{idProduct}="0012"
 
    SYSFS{idVendor}="08ec"
 
    SYSFS{manufacturer}="M-Sys"
 
    SYSFS{maxchild}="0"
 
    SYSFS{product}="disgo"
 
    SYSFS{serial}="1730C13B18000B84"
 
    SYSFS{speed}="12"
 
    SYSFS{version}=" 2.00"
 
  
  looking at the device chain at '/sys/devices/pci0000:00/0000:00:1d.0/usb1':
+
     ATTRS{product}=="USB Mass Storage Device"
     BUS="usb"
+
     ATTRS{product}=="EHCI Host Controller"
    ID="usb1"
 
    SYSFS{bConfigurationValue}="1"
 
    SYSFS{bDeviceClass}="09"
 
    SYSFS{bDeviceProtocol}="00"
 
    SYSFS{bDeviceSubClass}="00"
 
     SYSFS{bMaxPower}="  0mA"
 
    SYSFS{bNumConfigurations}="1"
 
    SYSFS{bNumInterfaces}=" 1"
 
    SYSFS{bcdDevice}="0206"
 
    SYSFS{bmAttributes}="c0"
 
    SYSFS{detach_state}="0"
 
    SYSFS{devnum}="1"
 
    SYSFS{idProduct}="0000"
 
    SYSFS{idVendor}="0000"
 
    SYSFS{manufacturer}="Linux 2.6.10-ARCH uhci_hcd"
 
    SYSFS{maxchild}="2"
 
    SYSFS{product}="Intel Corp. 82801CA/CAM USB (Hub #1)"
 
    SYSFS{serial}="0000:00:1d.0"
 
    SYSFS{speed}="12"
 
    SYSFS{version}=" 1.10"
 
  
  looking at the device chain at '/sys/devices/pci0000:00/0000:00:1d.0':
+
So, we need to use first serial.
    BUS="pci"
 
    ID="0000:00:1d.0"
 
    SYSFS{class}="0x0c0300"
 
    SYSFS{detach_state}="0"
 
    SYSFS{device}="0x2482"
 
    SYSFS{irq}="11"
 
    SYSFS{local_cpus}="1"
 
    SYSFS{subsystem_device}="0x4541"
 
    SYSFS{subsystem_vendor}="0x8086"
 
    SYSFS{vendor}="0x8086"
 
  
  looking at the device chain at '/sys/devices/pci0000:00':
 
    BUS=""
 
    ID="pci0000:00"
 
    SYSFS{detach_state}="0"
 
</pre>
 
  
Bit too much information!  The only bit of this you actaully need is the =SYSFS{serial}= part - so now you know what the above command does just grep out the bit you want in future cases:
+
== Create a udev rule==
  
<pre>udevinfo -a -p `udevinfo -q path -n /dev/sda` | grep SYSFS{serial}
+
You then use the <code>ATTRS{serial}</code> in a udev rule as follows:
</pre>
 
  
==== 2. Create a udev rule====
+
Note: The convention for Arch Linux is to place custom rules into <code>code]/etc/udev/rules.d/00.rules</code>
 +
You may, however create a file with a different name. Just remember that udev processes these files in alphabetical order.
  
You then use the SYSFS{serial} in a udev rule as follows:
+
BUS=="usb", ATTRS{serial}=="14AB0000000096", KERNEL=="sd?1",    NAME="%k", SYMLINK="usbdrive", GROUP="storage"
  
Note: The convention for Arch Linux is to place custom rules into /etc/udev/rules.d/00.rules
 
  
<pre>BUS=="usb", SYSFS{serial}=="0402170100000020EB5D00000000000", KERNEL=="sd?1", NAME="%k", SYMLINK="usbdrive", GROUP="storage"
+
=== 3. Create an fstab entry and mount point===
</pre>
 
  
==== 3. Create an fstab entry and mount point====
+
Create a directory:
  
Create a directory: mkdir /mnt/usbdrive
+
  mkdir /mnt/usbdrive
  
In your /etc/fstab, create an entry like this:
+
In your <code>/etc/fstab</code>, create an entry like this:
  
<pre>
+
/dev/usbdrive    /mnt/usbdrive    vfat noauto,user,noexec,nodev,nosuid    0 0
/dev/usbdrive    /mnt/usbdrive    vfat noauto,user,noexec,nodev,nosuid    0 0
 
</pre>
 
  
Now root or any user who belongs to the "storage" group can mount the usb stick by simply doing
+
Now root or any user who belongs to the <code>storage</code> group can mount the USB stick by simply doing
mount /mnt/usbdrive
 
  
Btw, all the last 3 additional mount options are meant to increase your system's security, e.g. they will prevent you running an executable file directly from the usb drive.
+
mount /mnt/usbdrive
  
Check if /etc/group contains an entry called "storage".
+
BTW, all the last 3 additional mount options are meant to increase your system's security, e.g. they will prevent you running an executable file directly from the USB drive.
  
If it does not, simply do a "groupadd storage"
+
To allow non-root users to acces to USB stick do
 +
gpasswd -a user1 storage
 +
gpasswd -a user2 storage
  
Then edit /etc/group to make the new storage group entry look like this:
 
<pre>
 
storage:x:102:user1,user2
 
</pre>
 
user1 and user2 are the names of the non-root users you wish to have access to the usb stick.
 
  
==== 4. Restart udev====
+
== Restart udev==
 
Only if really needed, you may restart udev like this. As root, run those 3 commands:
 
Only if really needed, you may restart udev like this. As root, run those 3 commands:
<pre>
+
/etc/./start_udev
/etc/./start_udev
+
mount /dev/pts
mount /dev/pts
+
mount /dev/shm
mount /dev/shm
 
</pre>
 
  
==== 5. Examples====
 
  
Here are some examples from my system.  My devices sometimes mount on sda or sda1 so I have two rules for each - this is a work around for device not found problems. The sda node is also needed for disk-level activities e.g. fdisk /dev/sda.
+
== Examples==
  
Note: The convention for Arch Linux is to place custom rules into /etc/udev/rules.d/00.rules
+
Here are some examples from my system.  My devices sometimes mount on <code>sda</code> or <code>sda1</code> so I have two rules for each - this is a work around for device not found problems. The sda node is also needed for disk-level activities e.g. <code>fdisk /dev/sda</code>.
  
This always maps my disgo USB pen to /dev/usbpen which i then map in fstab to mount on /mnt/usbpen
+
This always maps my disgo USB pen to <code>/dev/usbpen</code> which I then map in fstab to mount on <code>/mnt/usbpen</code>
  
 
  # Symlink USB pen
 
  # Symlink USB pen
  BUS=="usb", SYSFS{serial}=="1730C13B18000B84", KERNEL=="sd?", NAME="%k", SYMLINK+="usbpen", GROUP="storage"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd?", NAME="%k", SYMLINK+="usbpen", GROUP="storage"
  BUS=="usb", SYSFS{serial}=="1730C13B18000B84", KERNEL=="sd?1", NAME="%k", SYMLINK+="usbpen", GROUP="storage"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd?1", NAME="%k", SYMLINK+="usbpen", GROUP="storage"
  
If you have a device with with multiple partitions, the following example maps the device to /dev/usbdisk, and partitions 1,2,3,etc to usbdisk1, usbdisk2, usbdisk3, etc
+
If you have a device with with multiple partitions, the following example maps the device to <code>/dev/usbdisk</code>, and partitions 1, 2, 3 etc. to <code>/dev/usbdisk1</code>, <code>/dev/usbdisk2</code>, <code>/dev/usbdisk3</code> etc.
  
 
  # Symlink multi-part device
 
  # Symlink multi-part device
  BUS=="usb", SYSFS{serial}=="1730C13B18000B84", KERNEL=="sd?", NAME="%k", SYMLINK+="usbdisk", GROUP="storage"
+
  SUSSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd?", NAME="%k", SYMLINK+="usbdisk", GROUP="storage"
  BUS=="usb", SYSFS{serial}=="1730C13B18000B84", KERNEL=="sd?[1-9]", NAME="%k", SYMLINK+="usbdisk%n", GROUP="storage"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd?[1-9]", NAME="%k", SYMLINK+="usbdisk%n", GROUP="storage"
  
 
These rules are equivalent to the following one:
 
These rules are equivalent to the following one:
  
 
  # Symlink multi-part device
 
  # Symlink multi-part device
  BUS=="usb", SYSFS{serial}=="1730C13B18000B84", KERNEL=="sd*", NAME="%k", SYMLINK+="usbdisk%n", GROUP="storage"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd*", NAME="%k", SYMLINK+="usbdisk%n", GROUP="storage"
  
You can also omit the NAME and GROUP statements, so that the defaults from udev.rules are used. So the shortest and simplest solution would be adding this rule:
+
You can also omit the NAME and GROUP statements, so that the defaults from <code>udev.rules</code> are used. So the shortest and simplest solution would be adding this rule:
  
 
  # Symlink multi-part device
 
  # Symlink multi-part device
  BUS=="usb", SYSFS{serial}=="1730C13B18000B84", KERNEL=="sd*", SYMLINK+="usbdisk%n"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd*", SYMLINK+="usbdisk%n"
  
This always maps our Olympus digicam to /dev/usbcam which i then map in fstab to mount on /mnt/usbcam
+
This always maps our Olympus digicam to <code>/dev/usbcam</code> which I then map in fstab to mount on <code>/mnt/usbcam</code>
  
 
  # Symlink USB camera
 
  # Symlink USB camera
  BUS=="usb", SYSFS{serial}=="000207532049", KERNEL=="sd?", NAME="%k", SYMLINK+="usbcam", GROUP="storage"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="000207532049", KERNEL=="sd?", NAME="%k", SYMLINK+="usbcam", GROUP="storage"
  BUS=="usb", SYSFS{serial}=="000207532049", KERNEL=="sd?1", NAME="%k", SYMLINK+="usbcam", GROUP="storage"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="000207532049", KERNEL=="sd?1", NAME="%k", SYMLINK+="usbcam", GROUP="storage"
  
And this maps my Packard Bell MP3 player to /dev/mp3player
+
And this maps my Packard Bell MP3 player to <code>/dev/mp3player</code>
  
 
  # Symlink MP3 player
 
  # Symlink MP3 player
  BUS=="usb", SYSFS{serial}=="0002F5CF72C9C691", KERNEL=="sd?", NAME="%k", SYMLINK+="mp3player", GROUP="storage"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="0002F5CF72C9C691", KERNEL=="sd?", NAME="%k", SYMLINK+="mp3player", GROUP="storage"
  BUS=="usb", SYSFS{serial}=="0002F5CF72C9C691", KERNEL=="sd?1", NAME="%k", SYMLINK+="mp3player", GROUP="storage"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="0002F5CF72C9C691", KERNEL=="sd?1", NAME="%k", SYMLINK+="mp3player", GROUP="storage"
  
To map your own usb key to /dev/mykey and all of other keys to /dev/otherkey
+
To map your own usb key to <code>/dev/mykey</code> and all of other keys to <code>/dev/otherkey</code>
  
 
  # Symlink USB keys
 
  # Symlink USB keys
  BUS=="usb", SYSFS{serial}=="insert serial key", KERNEL=="sd?1", NAME="%k", SYMLINK+="mykey"
+
  SUBSYSTEMS=="usb", ATTRS{serial}=="insert serial key", KERNEL=="sd?1", NAME="%k", SYMLINK+="mykey"
  BUS=="usb", KERNEL=="sd?1", NAME="%k", SYMLINK+="otherkey"
+
  SUBSYSTEMS=="usb", KERNEL=="sd?1", NAME="%k", SYMLINK+="otherkey"
  
 
Note the order of the lines. Since all the usb keys should create the /dev/sd<a||b> node, udev will first check if it is your own usb key, defined with the serial number. But if you plug another key witch you don't know the serial number, it will create a node too, with a generic name "otherkey". That rule should be the last one your rules file.
 
Note the order of the lines. Since all the usb keys should create the /dev/sd<a||b> node, udev will first check if it is your own usb key, defined with the serial number. But if you plug another key witch you don't know the serial number, it will create a node too, with a generic name "otherkey". That rule should be the last one your rules file.

Revision as of 12:40, 2 October 2006


This information is basically mirrored from the gentoo wiki with some additional hints. Recently it was updated to reflect changes in udev >= 98 syntax.

This process allows you to always map a specific device to the same /dev node. This can then be used in fstab to ensure you can always mount the device same device in exactly the same place - which is great for desktop shortcuts!

Get the udev info for your USB device

Make sure one of your target devices is plugged in and then run the following as root:

udevinfo -a -p `udevinfo -q path -n /dev/sda`

This gets the udev device info for the device on /dev/sda - if your device is not mapped to /dev/sda then obviously use the correct mapping. :)

You should get some output like this:


Udevinfo starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/block/sda':
    KERNEL=="sda"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{stat}=="      19      111      137      160        0        0        0        0        0      152      160"
    ATTR{size}=="2007040"
    ATTR{removable}=="1"
    ATTR{range}=="16"
    ATTR{dev}=="8:0"

  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0':
    KERNELS=="5:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{ioerr_cnt}=="0x0"
    ATTRS{iodone_cnt}=="0x1c"
    ATTRS{iorequest_cnt}=="0x1c"
    ATTRS{iocounterbits}=="32"
    ATTRS{timeout}=="30"
    ATTRS{state}=="running"
    ATTRS{rev}=="1.20"
    ATTRS{model}=="01GB Tiny       "
    ATTRS{vendor}=="Pretec  "
    ATTRS{scsi_level}=="3"
    ATTRS{type}=="0"
    ATTRS{queue_type}=="none"
    ATTRS{queue_depth}=="1"
    ATTRS{device_blocked}=="0"
    ATTRS{max_sectors}=="240"

  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5/1-5:1.0/host5/target5:0:0':
    KERNELS=="target5:0:0"
    SUBSYSTEMS==""
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5/1-5:1.0/host5':
    KERNELS=="host5"
    SUBSYSTEMS==""
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5/1-5:1.0':
    KERNELS=="1-5:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb-storage"
    ATTRS{modalias}=="usb:v4146pBA01d0100dc00dsc00dp00ic08isc06ip50"
    ATTRS{bInterfaceProtocol}=="50"
    ATTRS{bInterfaceSubClass}=="06"
    ATTRS{bInterfaceClass}=="08"
    ATTRS{bNumEndpoints}=="03"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceNumber}=="00"

  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1/1-5':
    KERNELS=="1-5"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ATTRS{serial}=="14AB0000000096"
    ATTRS{product}=="USB Mass Storage Device"
    ATTRS{maxchild}=="0"
    ATTRS{version}==" 2.00"
    ATTRS{devnum}=="7"
    ATTRS{speed}=="480"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bcdDevice}=="0100"
    ATTRS{idProduct}=="ba01"
    ATTRS{idVendor}=="4146"
    ATTRS{bMaxPower}==" 98mA"
    ATTRS{bmAttributes}=="80"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bNumInterfaces}==" 1"

  looking at parent device '/devices/pci0000:00/0000:00:02.2/usb1':
    KERNELS=="usb1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ATTRS{serial}=="0000:00:02.2"
    ATTRS{product}=="EHCI Host Controller"
    ATTRS{manufacturer}=="Linux 2.6.18-ARCH ehci_hcd"
    ATTRS{maxchild}=="6"
    ATTRS{version}==" 2.00"
    ATTRS{devnum}=="1"
    ATTRS{speed}=="480"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceClass}=="09"
    ATTRS{bcdDevice}=="0206"
    ATTRS{idProduct}=="0000"
    ATTRS{idVendor}=="0000"
    ATTRS{bMaxPower}=="  0mA"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bNumInterfaces}==" 1"

  looking at parent device '/devices/pci0000:00/0000:00:02.2':
    KERNELS=="0000:00:02.2"
    SUBSYSTEMS=="pci"
    DRIVERS=="ehci_hcd"
    ATTRS{broken_parity_status}=="0"
    ATTRS{enable}=="1"
    ATTRS{modalias}=="pci:v000010DEd00000068sv00001043sd00000C11bc0Csc03i20"
    ATTRS{local_cpus}=="f"
    ATTRS{irq}=="17"
    ATTRS{class}=="0x0c0320"
    ATTRS{subsystem_device}=="0x0c11"
    ATTRS{subsystem_vendor}=="0x1043"
    ATTRS{device}=="0x0068"
    ATTRS{vendor}=="0x10de"

  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""

Bit too much information! The only bit of this you actaully need is the ATTRS<serial} part - so now you know what the above command does just grep out the bit you want in future cases:

udevinfo -a -p `udevinfo -q path -n /dev/sda` | grep ATTRS{serial}

output:

   ATTRS{serial}=="14AB0000000096"
   ATTRS{serial}=="0000:00:02.2"

Hmm, two serials. Which one to use?

udevinfo -a -p `udevinfo -q path -n /dev/sda` | grep ATTRS{product}

and we get

   ATTRS{product}=="USB Mass Storage Device"
   ATTRS{product}=="EHCI Host Controller"

So, we need to use first serial.


Create a udev rule

You then use the ATTRS{serial} in a udev rule as follows:

Note: The convention for Arch Linux is to place custom rules into code]/etc/udev/rules.d/00.rules You may, however create a file with a different name. Just remember that udev processes these files in alphabetical order.

BUS=="usb", ATTRS{serial}=="14AB0000000096", KERNEL=="sd?1",    NAME="%k", SYMLINK="usbdrive", GROUP="storage"


3. Create an fstab entry and mount point

Create a directory:

 mkdir /mnt/usbdrive

In your /etc/fstab, create an entry like this:

/dev/usbdrive    /mnt/usbdrive    vfat noauto,user,noexec,nodev,nosuid    0 0

Now root or any user who belongs to the storage group can mount the USB stick by simply doing

mount /mnt/usbdrive

BTW, all the last 3 additional mount options are meant to increase your system's security, e.g. they will prevent you running an executable file directly from the USB drive.

To allow non-root users to acces to USB stick do

gpasswd -a user1 storage
gpasswd -a user2 storage


Restart udev

Only if really needed, you may restart udev like this. As root, run those 3 commands:

/etc/./start_udev
mount /dev/pts
mount /dev/shm


Examples

Here are some examples from my system. My devices sometimes mount on sda or sda1 so I have two rules for each - this is a work around for device not found problems. The sda node is also needed for disk-level activities e.g. fdisk /dev/sda.

This always maps my disgo USB pen to /dev/usbpen which I then map in fstab to mount on /mnt/usbpen

# Symlink USB pen
SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd?", NAME="%k", SYMLINK+="usbpen", GROUP="storage"
SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd?1", NAME="%k", SYMLINK+="usbpen", GROUP="storage"

If you have a device with with multiple partitions, the following example maps the device to /dev/usbdisk, and partitions 1, 2, 3 etc. to /dev/usbdisk1, /dev/usbdisk2, /dev/usbdisk3 etc.

# Symlink multi-part device
SUSSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd?", NAME="%k", SYMLINK+="usbdisk", GROUP="storage"
SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd?[1-9]", NAME="%k", SYMLINK+="usbdisk%n", GROUP="storage"

These rules are equivalent to the following one:

# Symlink multi-part device
SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd*", NAME="%k", SYMLINK+="usbdisk%n", GROUP="storage"

You can also omit the NAME and GROUP statements, so that the defaults from udev.rules are used. So the shortest and simplest solution would be adding this rule:

# Symlink multi-part device
SUBSYSTEMS=="usb", ATTRS{serial}=="1730C13B18000B84", KERNEL=="sd*", SYMLINK+="usbdisk%n"

This always maps our Olympus digicam to /dev/usbcam which I then map in fstab to mount on /mnt/usbcam

# Symlink USB camera
SUBSYSTEMS=="usb", ATTRS{serial}=="000207532049", KERNEL=="sd?", NAME="%k", SYMLINK+="usbcam", GROUP="storage"
SUBSYSTEMS=="usb", ATTRS{serial}=="000207532049", KERNEL=="sd?1", NAME="%k", SYMLINK+="usbcam", GROUP="storage"

And this maps my Packard Bell MP3 player to /dev/mp3player

# Symlink MP3 player
SUBSYSTEMS=="usb", ATTRS{serial}=="0002F5CF72C9C691", KERNEL=="sd?", NAME="%k", SYMLINK+="mp3player", GROUP="storage"
SUBSYSTEMS=="usb", ATTRS{serial}=="0002F5CF72C9C691", KERNEL=="sd?1", NAME="%k", SYMLINK+="mp3player", GROUP="storage"

To map your own usb key to /dev/mykey and all of other keys to /dev/otherkey

# Symlink USB keys
SUBSYSTEMS=="usb", ATTRS{serial}=="insert serial key", KERNEL=="sd?1", NAME="%k", SYMLINK+="mykey"
SUBSYSTEMS=="usb", KERNEL=="sd?1", NAME="%k", SYMLINK+="otherkey"

Note the order of the lines. Since all the usb keys should create the /dev/sd<a||b> node, udev will first check if it is your own usb key, defined with the serial number. But if you plug another key witch you don't know the serial number, it will create a node too, with a generic name "otherkey". That rule should be the last one your rules file.