First release candidate.
1 parent e90d281 commit efa585ce18424643798f2967b8af94c946cc615b
@tundra tundra authored on 31 Oct 2013
Showing 1 changed file
View
113
Deconstructing_Linux_udev_Rules.rst
 
Another way to do this is to restart the ``udev`` daemon or reboot to
get the latest rules read in. Note that the daemon restart procedure
is also distro-specific, so you'll have to figure out what works on
your system.
your system. Rebooting is not distro-specific and can always be
accomplished by removing all power sources. This is not a recommended
best practice unless there is loud knocking at the door and
you *really* have to leave fast.
 
 
Our Example Rules
=================
rule below is broken across multiple lines to make it more readable,
but it is all on one line in the actual rules file. It is possible to
break rules across lines but you have to ensure that you follow the
syntax that ``udev`` expects. To keep things from mysteriously
breaking, I typically put the entire rule one one line::
breaking, it is best to put the entire rule one one line::
 
ACTION=="add", KERNEL=="sd*", PROGRAM=="/sbin/scsi_id --whitelisted /dev/$name",
RESULT=="VBOX_HARDDISK_VB5f712327-2bb4be0c", SYMLINK+="my_fine_disk01",
OWNER:="3009", GROUP:="421", MODE:="0600",
the thing that was previously matched*. But, you're not restricted to
this. It's entirely possible to write a rule that operates on
something completely unrelated to the matched condition. For
instance, you could write a rule that says, *reboot the computer
every time my little brother plugs in his favorite thumbdrive*. (This
is, however, considered very bad manners and may get you sent to your
room without dinner.)
every time my little brother plugs in his favorite thumbdrive*. This
is, however, considered Very Bad Manners and may get you sent to your
room without dinner. You may, however, have a career developing
websites for the US government healthcare initiatives.
 
Let's take each rule apart, one key-value pair at a time:
 
 
drive is being *added*. We want to ignore other kernel messages
with ``sd*`` in them when drives are removed or reporting an error.
So, we also include the ``ACTION="add"`` key value pair.
 
Effeectively, this lets us look at every drive being added to the
Effectively, this lets us look at every drive being added to the
system, so we can spot the one we're looking for.
 
- ``PROGRAM=="/sbin/scsi_id --whitelisted /dev/$name"``,
``RESULT=="VBOX_HARDDISK_VB5f712327-2bb4be0c"``
Basically, you have to set ``disk.EnableUUID = "TRUE"``
in your virtual machine's ``.vmx`` file.
 
Why are we bothering with all this? When disks are added and/or
removed from a system, *they are NOT guaranteed to be assigned to
the same device node in* ``/dev/``. Your drive could show up as
``/dev/sdh`` one time and ``/dev/sdx`` the next. This is the
price we pay for having a dynamic device system that allows hot
swapping USB devices on your laptop or live presentation of SAN
storage to a server. We thus have to use something that
*uniquely* identifies the drive every time.
removed from a system, *they are NOT guaranteed to be assigned to the
same device node in* ``/dev/``. Your drive could show up as
``/dev/sdh`` one time and ``/dev/sdx`` the next. This is the price we
pay for having a dynamic device system that allows hot swapping USB
devices on your laptop or live presentation of SAN storage to a
server. We thus have to use something that *uniquely* identifies the
drive every time.
 
Many of the tutorial examples of this on the World Weird Web show this
"uniqueness" test using the major- and minor device numbers. This is
an Officially Bad Idea (tm) because there is no guarantee that the
same device will get the same major/minor device numbers every time.
These numbers are generated by the kernel and are based on the order
of driver/device loading, the next free number available to the
kernel, and the cosmic ray count in Goscratchistan. Only the
``wwid`` (or an equivalent ``UUID``) is guaranteed to be unique, so
that's what we used here.
 
If we got this far, it means that all our matching tests were
successful: we've found the drive we're looking for. Now we can do
what we set out to do in the first place:
means, *"Add another symbolic link to this mountpoint."*
 
The real purpose of this is to provide a *consistent device name*
for software to use when referencing this disk. Say I'm writing
an application. I don't have to know where the disk is mounted.
I just have to always refer to ``/dev/my_fine_disk01`` and let all
this ``udev`` magic do the hard stuff. Remember, it's our job as
Snotty Systems Engineers to relieve Applications Programmers of as
much thinking as possible. Really, it is. Look in the job
description.
an application. We don't have to know where the disk is mounted.
We just have to always refer to ``/dev/my_fine_disk01`` and let
all this ``udev`` magic do the hard stuff. Remember, it's our job
as Snotty Systems Engineers (sm) to relieve Applications Programmers of
as much thinking as possible. Really, it is. Look it up in the
job description.
 
.. NOTE:: Why use a symlink? Why not just rename the mountpoint.
It *is* possible to do this with ``udev`` with the
``NAME+=...`` key-value construct. I prefer not to do
``NAME+=...`` key-value construct. It's best not to do
this because you lose visibility into the underlying
device name when you do this.
 
It's handy to know that the actual device name is, say,
``sdk``. For example, ejecting SAN-attached storage
requires you to sent things to
requires you to send things to
``/sys/block/sdk/device/delete``. If you overwrite
``/dev/sdk`` with ``my_fine_disk01``, it's not
immediately clear what the underlying device actually
is. A symbolic link covers both bases.
Here the use of the ``+=`` operator means something different. It
means, *"I am the final rule in this matter. No subsequent rule
can change this setting."* That's how we prevent rules that are
read after us (ones with higher numbers in their name) from
overriding what we want. For example, on at least one system
I worked on, using ``GROUP=`` got overriden by a later
default filesystem rule that always reset group ownership to
overriding what we want. For example, we've seen instances of
systems using ``GROUP=`` that then got overriden by a later
default filesystem rule. This then reset group ownership to
``disk``. Using ``:=`` instead, fixed this.
 
One other thing here: Notice the use of numeric values for ``UID``
and ``GID``. You *could* use the actual user- and group names
 
"But why", you may ask, "are you using the ``RUN==`` construct?
Isn't that what ``PROGRAM==`` does?" Not exactly, Grasshopper.
``PROGRAM==`` *always* runs regardless of prior matching.
``RUN==`` *only* runs if all prior matching has been succesful.
``RUN==`` *only* runs if all prior matching has been successful.
 
Why is that important here? Say we boot the system, and the
kernel discovers drives ``/dev/sdh, /dev/sdi,`` and ``/dev/sdj``
and let's suppose that the first one has the matching ``wwid``.
With ``RUN==`` the raw character device will only be created when
the full set of matching occurs - i.e., When the kernel reports
the addition of ``/dev/sdh``. But if you use ``PROGRAM==``, the
raw device will be associated *every time the kernel reports a new
``/dev/sd*``. The last one to be reported will "win". In this
``/dev/sd*``*. The last one to be reported will "win". In this
case, that means ``/dev/raw/raw1`` will be associated with
``/dev/sdj`` - not what we want here. Do NOT email me asking how
I figured this out. It wasn't fun.
``/dev/sdj`` - not what we want here.
 
 
With that under our belts, the second rule should be pretty
simple to understand:
we just did that at the end of the previous rule.
 
- ``SYMLINK+="rmy_fine_disk01"``
 
Let's symlink ``/dev/raw/raw1`` to ``/dev/rmy_fine_disk01``. The
DBAs can then configure their database engines to look for the
Let's symlink ``/dev/raw/raw1`` to ``/dev/rmy_fine_disk01``.
It is a time honored ``Unix`` convention that the raw device
name be the same as the actual device with an ``r`` prepended
to it. You don't have to do this, but if you don't, people
will hate youu, your dog will probably run away, and your
ex-wife will show up again ... and no one wants that.
 
The DBAs can then configure their database engines to look for the
symlink name and never worry about what the underlying node
mapping is for the raw device. Just as with Applications
Programmers, we Snotty Systems Engineers are required - by law -
to make things as easy as possible for DBAs. Again, I refer you
to the job description.
Programmers, we Snotty Systems Engineers (sm) are required - by law -
to make things as easy as possible for DBAs. Again, you are
referred to the job description.
 
 
- ``OWNER:="3009", GROUP:="421", MODE:="0600``
 
would be a matter of changing the unique ID for the ``RESULT`` field
of the first rule. You'd also have to change any references to
``my_fine_disk01`` and ``raw1``.
 
You'll also have to change the rules above to the program used to
check for a unique ``wwid`` or ``UUID`` on your particular distro.
 
If you want to know the current state of what raw devices exist
do this::
 
raw -qa
device, use this, substituting your device for ``/dev/sdd`` ::
 
udevadm info --query=all --name /dev/sdd 2>&1| less
 
The output of this command can be helful in figuring out just which
The output of this command can be helpful in figuring out just which
attributes and values you need to get to a running rule.
 
Finally, you can test your rules to see what is matching, again
substituting for ``/block/sdd``::
 
Document Revision Information
=============================
 
``$Id: Deconstructing_Linux_udev_Rules.rst,v 1.112 2013/11/01 02:17:08 tundra Exp $``
``$Id: Deconstructing_Linux_udev_Rules.rst,v 1.113 2013/11/01 02:53:07 tundra Exp $``
 
You can find the latest version of this document at:
 
http://www.tundraware.com/TechnicalNotes/Deconstructing-Linux-udev-Rules