http://www.dreamincode.net/forums/showtopic20020.htm Using udev to manage hardware Why? The first question is, why would you write a tutorial on using udev? Aren't there enough out there already?! I'd say yes, but in order for me to REALLY start getting the idea and writing my own rules, it required me to read almost all of them, and piece together the good parts of each one. I thought I could bring together what I had going on, and then possibly share what I had figured out. The second question is, why would I need to learn to write custom udev rules? Well, take, for instance, my standard desktop system. I've got a card reader that reads 5,195,638,923,579,823 different types of cards (that's a slight exaggeration...), my iPod which has it's own dock, my digital camera, my 6 different thumb drives, and my pocket hard drive. These all mount as /dev/sda, /dev/sdb, /dev/sdc... and so on, all depending on the order I plug them in at. This makes my /etc/fstab super messy, and a little unwieldy. It would be nice if my SD card reader always appeared as /dev/sdcardreader and I could mount accordingly there, etc. Prerequisites The /dev directory in your linux installation is a list of nodes, and each node corresponds with a piece of hardware on your system. So say you want to read input from the mouse, you'd just read input from /dev/input/mice Originally the /dev directory stored EVERY SINGLE node that the kernel could possibly know about. This meant that if you used a full kernel with everything enabled, you could have a node for a device you have never even heard of, much less own. This made a bloated and rather lethargic. Along came devfs, which was a little smart. It populated /dev only with hardware it could find on the system. This meant that if you didn't plug in a mouse, you'd have no /dev/input/mice This was a much better approach because you only had the hardware that was relevant to your system. However, there were still many architectural problems that hadn't been thoroughly thought out fully before implementation, and so as the system grew, the pain was felt. Enter udev. udev's idea cleared up some of the problems with devfs, including better kernel management (as of kernel 2.6.x), and the implementation of sysfs, which is found at /sys Using sysfs, udev knows about information plugged into your. sysfs can be thought of as a “middle layer” of sorts. When a device is plugged into a system, sysfs provides udev with extensive information about that hardware. Name Schemes and udev Rule Writing I have a server I'm running that has a SCSI IDE controller in it. It then has two 74GB hard drives that are mirrored using software mirroring. udev automatically has some of the most generic of rules written in for you already. For instance, for all of my storage devices, udev puts a node record in /dev/disk. To see what udev has found, I just do ls -lR /dev/disk, and it returns this: CODE
drwxr-xr-x 2 root root 160 2006-10-19 13:27 by-id/ drwxr-xr-x 2 root root 180 2006-10-19 13:27 by-path/ drwxr-xr-x 2 root root 60 2006-10-19 13:27 by-uuid/ /dev/disk/by-id: total 0 lrwxrwxrwx 1 root root 9 2006-10-19 13:27 scsi-20e09e00019ecd40e -> ../../sdb lrwxrwxrwx 1 root root 10 2006-10-19 13:27 scsi-20e09e00019ecd40e-part1 -> ../../sdb1 lrwxrwxrwx 1 root root 10 2006-10-19 13:27 scsi-20e09e00019ecd40e-part2 -> ../../sdb2 lrwxrwxrwx 1 root root 9 2006-10-19 13:27 scsi-20e09e00019ecd44c -> ../../sda lrwxrwxrwx 1 root root 10 2006-10-19 13:27 scsi-20e09e00019ecd44c-part1 -> ../../sda1 lrwxrwxrwx 1 root root 10 2006-10-19 13:27 scsi-20e09e00019ecd44c-part2 -> ../../sda2 /dev/disk/by-path: total 0 lrwxrwxrwx 1 root root 9 2006-10-19 13:27 pci-0000:00:0c.0-scsi-0:0:0:0 -> ../../sda lrwxrwxrwx 1 root root 10 2006-10-19 13:27 pci-0000:00:0c.0-scsi-0:0:0:0-part1 -> ../../sda1 lrwxrwxrwx 1 root root 10 2006-10-19 13:27 pci-0000:00:0c.0-scsi-0:0:0:0-part2 -> ../../sda2 lrwxrwxrwx 1 root root 9 2006-10-19 13:27 pci-0000:00:0c.0-scsi-0:0:1:0 -> ../../sdb lrwxrwxrwx 1 root root 10 2006-10-19 13:27 pci-0000:00:0c.0-scsi-0:0:1:0-part1 -> ../../sdb1 lrwxrwxrwx 1 root root 10 2006-10-19 13:27 pci-0000:00:0c.0-scsi-0:0:1:0-part2 -> ../../sdb2 lrwxrwxrwx 1 root root 10 2006-10-19 13:27 pci-0000:00:0c.1-scsi-0:0:6:0 -> ../../scd0 /dev/disk/by-uuid: total 0 lrwxrwxrwx 1 root root 9 2006-10-19 13:27 6aae5be6-6003-4def-8837-9a6ea3489d5e -> ../../md0 So in /dev/disk are three folders, by-id, by-path, and by-uuid. by-id and by-path both show me the scsi drives by their path or id (big surprise!), but by-uuid doesn't show the drives, but the RAID array they are actually in. I can then reference those drives by any of those address provided there (although RAID arrays are a special case, and you only want to write and read to the array). Notice, however, that these nodes are actually just symlinks to the real node address. This way, if /dev/sda and /dev/sdb are switched on boot one time (for some unknown reason) I can still access the drive by it's id (although a RAID array is still not a perfect example) udev usually stores the default rules in /etc/udev/rules.d/50-udev.rules (this may differ on your distribution). Look over this file. There are lots of examples of rules in here, you may find that the rule you want to write is already there is some form or another. However, if you want to write your own rules, remember two things: (1) The rules are parsed in “lexical” order, meaning they are ordered by the number at the beginning, and that they must end in .rules It is suggested that you create an /etc/udev/rules.d/10-local.rules and put all your local rules in there. This way, your local rules are parsed before the default rules at 50-udev.rules The syntax of rules is quite simple. They use a key-value system, and each is separated by commas. They usually have at least one match key and one assignment key. This means one _expression_ to match a device on, and then one one _expression_ that tells udev what to do with it. Match keys can be one of the following:
CODE
KERNEL==”sdb”, SYMLINK+=”home” Or say we want to easily access our cdrom drive: CODE
KERNEL==”hdc”, SYMLINK+=”cdrom cdrom0” Now we can get to the cdrom drive from /dev/hdc, /dev/cdrom, or /dev/cdrom0 Isn't that great? Usually, it's a good idea to symlink instead of actually renaming the device in /dev Getting sysfs Involved Now, this is all fine and dandy, but guess what? My multicard reader seems to always mount the different card slots as different sdX interfaces. So I can't just symlink /dev/sdc with /dev/cfcard Wouldn't it be nice if we could just look at the model, or manufacturer or something? Well guess what? You can, with sysfs attributes! sysfs allows you to look at model, size, manufacturer, product information, and a whole lote more (although I don't use anything other than that). Now I can have udev check out the actual device a little more and symlink it based on more than just where the kernel stuck it. However, how can I find the exact information sysfs knows about my device? Easy! udevinfo gives you all the information you need. Start with the following commands: CODE
# find /sys -name sda /sys/block/sda # udevinfo /sys/block/sda 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}==" 14123 2902 256324 72040 52085 250203 2498104 4701412 0 540648 4773452" ATTR{size}=="17930694" ATTR{removable}=="0" ATTR{range}=="16" ATTR{dev}=="8:0" looking at parent device '/devices/pci0000:00/0000:00:0c.0/host0/target0:0:0/0:0:0:0': KERNELS=="0:0:0:0" SUBSYSTEMS=="scsi" DRIVERS=="sd" ATTRS{ioerr_cnt}=="0x1" ATTRS{iodone_cnt}=="0x102bc" ATTRS{iorequest_cnt}=="0x102bc" ATTRS{iocounterbits}=="32" ATTRS{timeout}=="30" ATTRS{state}=="running" ATTRS{rev}=="0200" ATTRS{model}=="ATLAS_V__9_WLS " ATTRS{vendor}=="QUANTUM " ATTRS{scsi_level}=="4" ATTRS{type}=="0" ATTRS{queue_type}=="ordered" ATTRS{queue_depth}=="8" ATTRS{device_blocked}=="0" looking at parent device '/devices/pci0000:00/0000:00:0c.0/host0/target0:0:0': KERNELS=="target0:0:0" SUBSYSTEMS=="" DRIVERS=="" looking at parent device '/devices/pci0000:00/0000:00:0c.0/host0': KERNELS=="host0" SUBSYSTEMS=="" DRIVERS=="" looking at parent device '/devices/pci0000:00/0000:00:0c.0': KERNELS=="0000:00:0c.0" SUBSYSTEMS=="pci" DRIVERS=="aic7xxx" ATTRS{broken_parity_status}=="0" ATTRS{modalias}=="pci:v00009005d0000005Fsv00009004sd00000053bc01sc00i00" ATTRS{local_cpus}=="1" ATTRS{irq}=="169" ATTRS{class}=="0x010000" ATTRS{subsystem_device}=="0x0053" ATTRS{subsystem_vendor}=="0x9004" ATTRS{device}=="0x005f" ATTRS{vendor}=="0x9005" looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS=="" That's more than enough information about my scsi hard drive in my server. Now I have sysfs specified items that I can use to refer to this drive in my udev rules. So, let's say I want to symlink this hard drive to /dev/backup, because I want to mount it ONLY when it's time to run a backup, and I'll use a script to handle the mount and unmount. So I'm going to create a rule that looks like this: CODE
17930694
SUBSYSTEM==”block”, SYSFS{size}==”17930694”, SYSFS{model}==”ATLAS_V__9_WLS”,SYMLINK+=”backup” Now, I just restart udev with /etc/init.d/udev restart, and the drive will be all ready for me. Permissions Let's take the last rule we wrote and modify it. I only want the group “backup” to be able to read and write to it. In fact, I'll even give the user “backup” ownership to it, as cron will run the script as user “backup” of group “backup” The completed rule would look like this: CODE
17930694
SUBSYSTEM==”block”, SYSFS{size}==”17930694”, SYSFS{model}==”ATLAS_V__9_WLS”,SYMLINK+=”backup”, GROUP=”backup”, OWNER=”backup” And if I wanted to just chmod it on load, I could just do this: CODE
17930694
SUBSYSTEM==”block”, SYSFS{size}==”17930694”, SYSFS{model}==”ATLAS_V__9_WLS”,SYMLINK+=”backup”, MODE=”0666” We've only skimmed the surface of udev in this howto. There are environment interactions, and external program manipulations you can learn about, but this howto is long enough. Have fun writing your new udev rules. |