Citation: http://possiblelossofprecision.net/?p=343
INTRO
UDEV is a service/package that detects new devices connected to the linux server and launches predefined scripts and also makes them accessible through /dev. In the old days people had to use “mknod DEVICENAME [b,c,p] MAJOR# MINOR#” (ex: “mknod /dev/random b 12 5” or “mknod /dev/ttyS0 c 4 64” or “mknod /dev/nicedisk b 45 0” or “mknod /dev/sda b 8 0” or “mknod /dev/sda1 b 8 1” or “mknod /dev/sda2 b 8 2” or “mknod /dev/sdb b 8 16” or “mknod /dev/sdb1 b 8 17” – notice the device name can be anything, such /dev/nicedisk. notice the major number stays the same for similar devices as they use the same drives. Also notice that there are b[block], c[character], or p[fifo] type of devices that can be made) to associate a new device to its major number (which represented a unique identifier that tied a certain device to a driver) and minor number (which sub-categorized the device within the driver). For example: The major number 8 is used for “sd” devices and the minor numbers represent the drive letter and partition – you can see that if you run “cat /proc/partitions“. There was a newer system then mknod which udev built from called mdev. mdev was a device discovery tool which had to be manually ran like this “mdev -s“. Well udev is like “mdev -s” except it runs when it detects a new device. udevadm can be used to gather lots of information about a device. udev can also use all of this information when it detects a device to do certain things, such as make a symlink of sda that looks like this “/dev/0:7200 –> /dev/sda” meaning “port 1. rpm 7200” and sdb can be “/dev/5:5600 –> /dev/sdb” meaning meaning “port 6 rpm 5600″ – this is just an example of how useful udev can be, for example a linux admin can reference up a drive based on slot number or rpm.
SIDENOTE: With mknod, how did one know what major and minor number to associate to a device? Well one can use previous similar devices to figure out the pattern such as based on the above info I can predict that since sda is b,8,0 and sda1 is b,8,1 then I can assume sda3 is b,8,3 (TIP: for making the pattern connection use “cat /proc/partitions” for storage block devices). Now if you dont have anything to make a pattern out of, then just use the LANANA LINUX DEVICE LIST (administred by Alan Cox – one of the main linux beards). You can find the latest copy online (http://www.lanana.org/docs/device-list/devices-2.6+.txt) or in the linux kernle source code under the folder Documentation/devices.txt
SIDENOTE: History timeline, first it was mknod, then mdev, then udev
UDEVADM SECTION 1: EXAMPLES
GET DEVICE SYS PATH
To gather info about a device using udevadm you need to know the path of the device. To get the path of the device find it in /sys/devices or use “udevadm info -q path -n DEV_PATH”
Example1: sda & sdb
udevadm info -q path -n /dev/sda # or you can omit the /dev prefix udevadm info -q path -n sda /devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
udevadm info -q path -n /dev/sdb # or you can omit the /dev prefix udevadm info -q path -n sdb /devices/pci0000:00/0000:00:1f.2/ata2/host1/target1:0:0/1:0:0:0/block/sdb
Imagine a prefix of /sys for each of those devices paths.
sda is really /sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
sdb is really /sys/devices/pci0000:00/0000:00:1f.2/ata2/host1/target1:0:0/1:0:0:0/block/sdb
GET DEVICE INFO
Now to get info about the device (udev info) do this: “udevadm info -a -p DEV_SYS_PATH”
Example2: for sda
udevadm info -a -p /sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda # or write it without the /sys prefix (same result) udevadm info -a -p /devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
See output below. sdb will have similar output
COMBINE THE TWO
You can can combine both results like this: “udevadm info -a -p `udevadm info -q path -n DEV_PATH`” or instead of back ticks command substitution use dollar-sign-parenthesis substitution, “udevadm info -a -p $(udevadm info -q path -n DEV_PATH)”
Example3: sda
udevadm info -a -p $(udevadm info -q path -n sda) # or to get same answer: udevadm info -a -p $(udevadm info -q path -n /dev/sda) # or to get same answer: udevadm info -a -p `udevadm info -q path -n sda` # or to get same answer: udevadm info -a -p `udevadm info -q path -n /dev/sda`
All of the above will provide the same output seen at the bottom
TO GET ALL OUTPUT
Now what if we wanted to poll every device in /dev, then use this script:
for i in /dev/*; do echo "######## ${i} #########"; echo; udevadm info -a -p `udevadm info -q path -n "${i}"` | grep .; echo; echo; done;
SIDENOTE: the i will equal /dev/sda and /dev/sdb and so on.
SIDENOTE: the | grep . removes those extra new lines you see at the bottom. Then the echo; echo; just adds a good seperator between the devices for easier viewing
SIDENOTE: I didnt include my own system output so that you didnt get too much info. Just run it on your own system to check it out.
SDA DEVICE INFO OUTPUT
# udevadm info -a -p $(udevadm info -q path -n sda) Udevadm info 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 '/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda': KERNEL=="sda" SUBSYSTEM=="block" DRIVER=="" ATTR{ro}=="0" ATTR{size}=="1953525168" ATTR{stat}==" 1799945 769925 214302484 36182890 542669 6772016 119502568 39048627 0 10411312 75937287" ATTR{range}=="16" ATTR{discard_alignment}=="0" ATTR{events}=="" ATTR{ext_range}=="256" ATTR{events_poll_msecs}=="-1" ATTR{alignment_offset}=="0" ATTR{inflight}==" 0 0" ATTR{removable}=="0" ATTR{capability}=="50" ATTR{events_async}=="" looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0': KERNELS=="0:0:0:0" SUBSYSTEMS=="scsi" DRIVERS=="sd" ATTRS{rev}=="SN06" ATTRS{type}=="0" ATTRS{scsi_level}=="6" ATTRS{model}=="ST31000340NS " ATTRS{state}=="running" ATTRS{queue_type}=="simple" ATTRS{iodone_cnt}=="0x25ea38" ATTRS{iorequest_cnt}=="0x265658" ATTRS{queue_ramp_up_period}=="120000" ATTRS{evt_capacity_change_reported}=="0" ATTRS{timeout}=="30" ATTRS{evt_media_change}=="0" ATTRS{ioerr_cnt}=="0x11b0" ATTRS{queue_depth}=="31" ATTRS{vendor}=="ATA " ATTRS{evt_soft_threshold_reached}=="0" ATTRS{device_blocked}=="0" ATTRS{evt_mode_parameter_change_reported}=="0" ATTRS{evt_lun_change_reported}=="0" ATTRS{evt_inquiry_change_reported}=="0" ATTRS{iocounterbits}=="32" ATTRS{vpd_pg80}=="" ATTRS{vpd_pg83}=="" ATTRS{eh_timeout}=="10" looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0': KERNELS=="target0:0:0" SUBSYSTEMS=="scsi" DRIVERS=="" looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1/host0': KERNELS=="host0" SUBSYSTEMS=="scsi" DRIVERS=="" looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1': KERNELS=="ata1" SUBSYSTEMS=="" DRIVERS=="" looking at parent device '/devices/pci0000:00/0000:00:1f.2': KERNELS=="0000:00:1f.2" SUBSYSTEMS=="pci" DRIVERS=="ahci" ATTRS{irq}=="41" ATTRS{subsystem_vendor}=="0x8086" ATTRS{broken_parity_status}=="0" ATTRS{class}=="0x010601" ATTRS{consistent_dma_mask_bits}=="64" ATTRS{dma_mask_bits}=="64" ATTRS{local_cpus}=="ff" ATTRS{device}=="0x2821" ATTRS{enable}=="1" ATTRS{msi_bus}=="" ATTRS{local_cpulist}=="0-7" ATTRS{vendor}=="0x8086" ATTRS{subsystem_device}=="0x2821" ATTRS{d3cold_allowed}=="1" looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS==""
UDEVADM SECTION 2: Deeper Dive
Lets dive deeper into udevadm info arguments, and maybe we can unlock more things.
Checkout the –help of “udevadm info”, to make sense of the options
# udevadm info --help Usage: udevadm info OPTIONS --query=<type> query device information: * name name of device node * symlink pointing to node * path sys device path * property the device properties * all all values --path=<syspath> sys device path used for query or attribute walk --name=<name> node or symlink name used for query or attribute walk --root prepend dev directory to path names --attribute-walk print all key matches while walking along the chain of parent devices --device-id-of-file=<file> print major:minor of device containing this file --export export key/value pairs --export-prefix export the key name with a prefix --export-db export the content of the udev database --cleanup-db cleanup the udev database --help
Each of those can also be used by single letters:
-q for query, -n for name, -a for attribute walk (get all attributes), -p for path
So check this out, we can actually get the device path by doing this (as seen above):
udevadm info -q path -n sda
Meaning: udevadm-info query(get) the path of device named sda. In other words: Udevadm-info please show us the path of the device sda.
Or you can get all of the query-able information like this:
udevadm info -q all -n sda
You can also get all of the query-able information by path:
udevadm info -q all -p /devices/pci0000:00/0000:00:01.1/0000:02:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/block/sda
Or you can get every attribute by path or name* (see CORRECTION TO SECTION 1 below)
Get all Attributes by device sys path:
udevadm info -a -p /devices/pci0000:00/0000:00:01.1/0000:02:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/block/sda
Get all Attributes by device name:
udevadm info -a -n sda
* CORRECTION TO SECTION 1: I said you cant get all attribute by using the name (such as sda) and that you needed to know the path (such as /devices/pci0000:00/0000:00:01.1/0000:02:00.0/host0/port-0:0/end_device-0:0/target0:0:0/0:0:0:0/block/sda). But that is in correct. PS: I only said that we are limited to get all attributes if we quote the full devices’s sys path because the citation I quoted said that, but I tested it myself and the message of the author was incorrect.
So that means instead of using this to get all the attributes of sda:
udevadm info -a -p $(udevadm info -q path -n sda)
We can use this simpler one:
udevadm info -a -n sda
And to get the attributes of every device:
for i in /dev/*; do echo "######## ${i} #########"; echo; udevadm info -a -n ${i} | grep .; echo; echo; done;
NOTE: getting all of the attributes, udevadm does an “attribute walk” through all of the sys files
UDEVADM TEST
You can use udevadm test “sys path of device” to get even more information. The above just shows all of the attributes with udevadm info -a (–attribute). Or it shows all of the queriable information with udevadm info -q (–query). However there is also env variables for each device. Which can be used when device rules are made. For example the ID_CHANNEL env variable of a device tells you the slot number.
TIP: /sys/block/ has symlinks to all of the /sys/devices paths are useful
Like this:
# ls -l /sys/block total 0 lrwxrwxrwx 1 root root 0 Mar 18 21:19 loop0 -> ../devices/virtual/block/loop0 lrwxrwxrwx 1 root root 0 Mar 18 21:19 loop1 -> ../devices/virtual/block/loop1 lrwxrwxrwx 1 root root 0 Mar 18 21:19 loop2 -> ../devices/virtual/block/loop2 lrwxrwxrwx 1 root root 0 Mar 18 21:19 loop3 -> ../devices/virtual/block/loop3 lrwxrwxrwx 1 root root 0 Mar 18 21:19 loop4 -> ../devices/virtual/block/loop4 lrwxrwxrwx 1 root root 0 Mar 18 21:19 loop5 -> ../devices/virtual/block/loop5 lrwxrwxrwx 1 root root 0 Mar 18 21:19 loop6 -> ../devices/virtual/block/loop6 lrwxrwxrwx 1 root root 0 Mar 18 21:19 loop7 -> ../devices/virtual/block/loop7 lrwxrwxrwx 1 root root 0 Mar 18 21:13 md0 -> ../devices/virtual/block/md0 lrwxrwxrwx 1 root root 0 Mar 18 21:13 md1 -> ../devices/virtual/block/md1 lrwxrwxrwx 1 root root 0 Mar 18 21:13 md127 -> ../devices/virtual/block/md127 lrwxrwxrwx 1 root root 0 Mar 16 14:44 sda -> ../devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda lrwxrwxrwx 1 root root 0 Mar 16 14:44 sdb -> ../devices/pci0000:00/0000:00:1f.2/ata2/host1/target1:0:0/1:0:0:0/block/sdb lrwxrwxrwx 1 root root 0 Mar 16 14:44 sdc -> ../devices/pci0000:00/0000:00:1f.2/ata3/host2/target2:0:0/2:0:0:0/block/sdc lrwxrwxrwx 1 root root 0 Mar 16 14:44 sdd -> ../devices/pci0000:00/0000:00:1f.2/ata4/host3/target3:0:0/3:0:0:0/block/sdd lrwxrwxrwx 1 root root 0 Mar 16 14:42 sde -> ../devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/host6/target6:0:0/6:0:0:0/block/sde
Check out the output of these 3 identical commands:
udevadm test /sys/block/sda udevadm test /sys/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda udevadm test /devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
Output:
# This just the bottom part of the output which shows the ENV variables: DEVLINKS=/dev/disk/by-id/ata-ST3000DM001-1CH166_W1F28168 /dev/disk/by-id/scsi-SATA_ST3000DM001-1CH_W1F28168 /dev/disk/by-id/wwn-0x5000c5005e43ed87 /dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 /dev/disk/internal/0:3:ST3000DM001-1CH166:W1F28168:CC24:7200 DEVNAME=/dev/sdd DEVPATH=/devices/pci0000:00/0000:00:1f.2/ata4/host3/target3:0:0/3:0:0:0/block/sdd DEVTYPE=disk ID_ATA=1 ID_ATA_DOWNLOAD_MICROCODE=1 ID_ATA_FEATURE_SET_APM=1 ID_ATA_FEATURE_SET_APM_CURRENT_VALUE=254 ID_ATA_FEATURE_SET_APM_ENABLED=1 ID_ATA_FEATURE_SET_HPA=1 ID_ATA_FEATURE_SET_HPA_ENABLED=1 ID_ATA_FEATURE_SET_PM=1 ID_ATA_FEATURE_SET_PM_ENABLED=1 ID_ATA_FEATURE_SET_SECURITY=1 ID_ATA_FEATURE_SET_SECURITY_ENABLED=0 ID_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN=334 ID_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN=334 ID_ATA_FEATURE_SET_SECURITY_FROZEN=1 ID_ATA_FEATURE_SET_SMART=1 ID_ATA_FEATURE_SET_SMART_ENABLED=1 ID_ATA_ROTATION_RATE_RPM=7200 ID_ATA_SATA=1 ID_ATA_SATA_SIGNAL_RATE_GEN1=1 ID_ATA_SATA_SIGNAL_RATE_GEN2=1 ID_ATA_WRITE_CACHE=1 ID_ATA_WRITE_CACHE_ENABLED=1 ID_BUS=ata ID_CHANNEL=0:3 ID_MODEL=ST3000DM001-1CH166 ID_MODEL_ENC=ST3000DM001-1CH166\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20 ID_PART_TABLE_TYPE=gpt ID_PATH=pci-0000:00:1f.2-scsi-0:0:0:0 ID_PATH_TAG=pci-0000_00_1f_2-scsi-0_0_0_0 ID_REVISION=CC24 ID_SCSI_COMPAT=SATA_ST3000DM001-1CH_W1F28168 ID_SERIAL=ST3000DM001-1CH166_W1F28168 ID_SERIAL_SHORT=W1F28168 ID_TYPE=disk ID_WWN=0x5000c5005e43ed87 ID_WWN_WITH_EXTENSION=0x5000c5005e43ed87 MAJOR=8 MINOR=48 SUBSYSTEM=block TAGS=:systemd: UDEV_LOG=6 USEC_INITIALIZED=196460535692
NOTE: all of these variables seen in “udevadm test” and “udevadm info” can be used while making rules. Checkout these rules.
Here is an example of a rule that looks at the drives and makes a symlink for it in /dev/disk/internal which has the channel (so it has the slot number), model number, serial number, firmware version of the drive, and rpm of the drive
### 1 rule per line ### # cat /etc/udev/rules.d/99-disk-chan.rules ENV{DEVTYPE}=="disk", ENV{ID_CHANNEL}=="?*", SYMLINK+="disk/internal/$env{ID_CHANNEL}:$env{ID_MODEL}:$env{ID_SERIAL_SHORT}:$env{ID_REVISION}:$env{ID_ATA_ROTATION_RATE_RPM}" ### note that rules should be 1 per line, however you can extend them like this, with a hanging line ### # cat /etc/udev/rules.d/99-disk-chan.rules ENV{DEVTYPE}=="disk", ENV{ID_CHANNEL}=="?*", \ SYMLINK+="disk/internal/$env{ID_CHANNEL}:$env{ID_MODEL}:$env{ID_SERIAL_SHORT}:$env{ID_REVISION}:$env{ID_ATA_ROTATION_RATE_RPM}" ### same rule, just no spaces on the hanging line. ### # cat /etc/udev/rules.d/99-disk-chan.rules ENV{DEVTYPE}=="disk", ENV{ID_CHANNEL}=="?*", \ SYMLINK+="disk/internal/$env{ID_CHANNEL}:$env{ID_MODEL}:$env{ID_SERIAL_SHORT}:$env{ID_REVISION}:$env{ID_ATA_ROTATION_RATE_RPM}"<span style="font-family: Lato, sans-serif; font-size: 16px; line-height: 1.5; background-color: #ffffff;"> </span>
That rule looks for a device that is a “disk” and has an ID_CHANNEL of anything (“?*” means it just cant be empty – usb drives dont have ID_CHANNEL so they dont appear here. ID_CHANNEL is output like this 0:3 where 3 is the slot number, just add 1 and it will 4). If the ID_CHANNEL doesnt exist then this rule is skipped and a symlink is not made. The Symlink that is made if the device is a disk and has the variable ID_CHANNEL will be of the format disk/internal/stuff. meaning that it will go in the /dev/disk/internal folder (udev will auto make the folder /dev/disk/internal). The “stuff” will be ID_CHANNEL:ID_MODEL:ID_SERIAL_SHORT:ID_REVISION:ID_ATA_ROTATION_RATE_RPM. Notice all of these variables are shown with “udevadm test /sys/block/sd*”.
Example of this rules /dev’s results:
# ls -lisah /dev/disk/internal/ total 0 99 0 drwxrwxrwx 2 root root 160 Mar 18 21:19 . 98 0 drwxrwxrwx 5 root root 100 Mar 18 21:17 .. 2091 0 lrwxrwxrwx 1 root root 9 Mar 16 14:44 0:0 -> ../../sda 1540 0 lrwxrwxrwx 1 root root 9 Mar 18 21:20 0:0:WDC_WD30EFRX-68EUZN1:WD-WMC4N0479141:80.00A08:5400 -> ../../sda 2092 0 lrwxrwxrwx 1 root root 9 Mar 16 14:44 0:1 -> ../../sdb 100 0 lrwxrwxrwx 1 root root 9 Mar 16 14:44 0:2 -> ../../sdc 101 0 lrwxrwxrwx 1 root root 9 Mar 16 14:44 0:3 -> ../../sdd ### So we know that sda is in slot 0+1, meaning slot1 ### sdb is in slot 2, sdc is in slot 3, sdd is in slot 4
SIDENOTE: this rule exists on the new ReadyNAS OS6 units. I dont recommend editing them without risk of hurting your warranty. However now you know how to see which /dev/sd* letter ties to which slot. Simply look at “ls -lisah /dev/disk/internal” and add 1 to the second number to get the slot number.
NOTE: if you edit any rules (dont do so on the ReadyNAS or else might hurt). Reset them like this and check out the /dev folder:
udevadm control --reload-rules; udevadm trigger;
There is some HTML in line #12.
Fixed. Thanks for your help.