# Using udev rules to mount camera and get serial

## Arthanis

Hi all. I have the following problem: I have this hardware that is a camera that export the SD content as mass storage. For now, what I need is to detect when the device is plugged and run a C program passing the serial and the device locations as parameters.

These are the data Im able to gather using 

```
udevadm info  --query=name --name=/dev/sdc --attribute-walk

```

 looking at device '/devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1:1.0/host156/target156:0:0/156:0:0:0/block/sdc':

    KERNEL=="sdc"

    SUBSYSTEM=="block"

    DRIVER==""

    ATTR{range}=="16"

    ATTR{ext_range}=="256"

    ATTR{removable}=="1"

    ATTR{ro}=="0"

    ATTR{size}=="15269888"

    ATTR{alignment_offset}=="0"

    ATTR{discard_alignment}=="0"

    ATTR{capability}=="51"

    ATTR{stat}=="      87       15      816       72        0        0        0        0        0       72       72"

    ATTR{inflight}=="       0        0"

    ATTR{events}=="media_change"

    ATTR{events_async}==""

    ATTR{events_poll_msecs}=="-1"

  looking at parent device '/devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1:1.0/host156/target156:0:0/156:0:0:0':

    KERNELS=="156:0:0:0"

    SUBSYSTEMS=="scsi"

    DRIVERS=="sd"

    ATTRS{device_blocked}=="0"

    ATTRS{type}=="0"

    ATTRS{scsi_level}=="3"

    ATTRS{vendor}=="Linux   "

    ATTRS{model}=="File-Stor Gadget"

    ATTRS{rev}=="0316"

    ATTRS{state}=="running"

    ATTRS{timeout}=="30"

    ATTRS{iocounterbits}=="32"

    ATTRS{iorequest_cnt}=="0xe0"

    ATTRS{iodone_cnt}=="0xe0"

    ATTRS{ioerr_cnt}=="0x1"

    ATTRS{evt_media_change}=="0"

    ATTRS{queue_depth}=="1"

    ATTRS{queue_type}=="none"

    ATTRS{max_sectors}=="240"

  looking at parent device '/devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1:1.0/host156/target156:0:0':

    KERNELS=="target156:0:0"

    SUBSYSTEMS=="scsi"

    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1:1.0/host156':

    KERNELS=="host156"

    SUBSYSTEMS=="scsi"

    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1:1.0':

    KERNELS=="1-1:1.0"

    SUBSYSTEMS=="usb"

    DRIVERS=="usb-storage"

    ATTRS{bInterfaceNumber}=="00"

    ATTRS{bAlternateSetting}==" 0"

    ATTRS{bNumEndpoints}=="02"

    ATTRS{bInterfaceClass}=="08"

    ATTRS{bInterfaceSubClass}=="06"

    ATTRS{bInterfaceProtocol}=="50"

    ATTRS{supports_autosuspend}=="1"

    ATTRS{interface}=="Mass Storage"

  looking at parent device '/devices/pci0000:00/0000:00:04.1/usb1/1-1':

    KERNELS=="1-1"

    SUBSYSTEMS=="usb"

    DRIVERS=="usb"

    ATTRS{configuration}=="Self-powered"

    ATTRS{bNumInterfaces}==" 1"

    ATTRS{bConfigurationValue}=="1"

    ATTRS{bmAttributes}=="c0"

    ATTRS{bMaxPower}=="  2mA"

    ATTRS{urbnum}=="568"

    ATTRS{idVendor}=="0525"

    ATTRS{idProduct}=="a4a5"

    ATTRS{bcdDevice}=="0316"

    ATTRS{bDeviceClass}=="00"

    ATTRS{bDeviceSubClass}=="00"

    ATTRS{bDeviceProtocol}=="00"

    ATTRS{bNumConfigurations}=="1"

    ATTRS{bMaxPacketSize0}=="64"

    ATTRS{speed}=="480"

    ATTRS{busnum}=="1"

    ATTRS{devnum}=="6"

    ATTRS{devpath}=="1"

    ATTRS{version}==" 2.00"

    ATTRS{maxchild}=="0"

    ATTRS{quirks}=="0x0"

    ATTRS{avoid_reset_quirk}=="0"

    ATTRS{authorized}=="1"

    ATTRS{manufacturer}=="Linux 2.6.18_pro500-davinci_evm-arm_v5t_le with musb_hdrc"

    ATTRS{product}=="File-backed Storage Gadget"

    ATTRS{serial}=="3238204E6F76"

  looking at parent device '/devices/pci0000:00/0000:00:04.1/usb1':

    KERNELS=="usb1"

    SUBSYSTEMS=="usb"

    DRIVERS=="usb"

    ATTRS{configuration}==""

    ATTRS{bNumInterfaces}==" 1"

    ATTRS{bConfigurationValue}=="1"

    ATTRS{bmAttributes}=="e0"

    ATTRS{bMaxPower}=="  0mA"

    ATTRS{urbnum}=="2956"

    ATTRS{idVendor}=="1d6b"

    ATTRS{idProduct}=="0002"

    ATTRS{bcdDevice}=="0303"

    ATTRS{bDeviceClass}=="09"

    ATTRS{bDeviceSubClass}=="00"

    ATTRS{bDeviceProtocol}=="00"

    ATTRS{bNumConfigurations}=="1"

    ATTRS{bMaxPacketSize0}=="64"

    ATTRS{speed}=="480"

    ATTRS{busnum}=="1"

    ATTRS{devnum}=="1"

    ATTRS{devpath}=="0"

    ATTRS{version}==" 2.00"

    ATTRS{maxchild}=="6"

    ATTRS{quirks}=="0x0"

    ATTRS{avoid_reset_quirk}=="0"

    ATTRS{authorized}=="1"

    ATTRS{manufacturer}=="Linux 3.3.8-gentoo ehci_hcd"

    ATTRS{product}=="EHCI Host Controller"

    ATTRS{serial}=="0000:00:04.1"

    ATTRS{authorized_default}=="1"

  looking at parent device '/devices/pci0000:00/0000:00:04.1':

    KERNELS=="0000:00:04.1"

    SUBSYSTEMS=="pci"

    DRIVERS=="ehci_hcd"

    ATTRS{vendor}=="0x10de"

    ATTRS{device}=="0x0d9d"

    ATTRS{subsystem_vendor}=="0x10de"

    ATTRS{subsystem_device}=="0xcb89"

    ATTRS{class}=="0x0c0320"

    ATTRS{irq}=="19"

    ATTRS{local_cpus}=="3"

    ATTRS{local_cpulist}=="0-1"

    ATTRS{dma_mask_bits}=="32"

    ATTRS{consistent_dma_mask_bits}=="32"

    ATTRS{enable}=="1"

    ATTRS{broken_parity_status}=="0"

    ATTRS{msi_bus}==""

    ATTRS{companion}==""

    ATTRS{uframe_periodic_max}=="100"

  looking at parent device '/devices/pci0000:00':

    KERNELS=="pci0000:00"

    SUBSYSTEMS==""

    DRIVERS==""

So, I made some udev rules that should have done the trick(/etc/udev/rules.d/10-my_awesome_rule.rules):

```
SUBSYSTEM=="block", SUBSYSTEMS=="usb", ACTION=="add", ATTRS{serial}=="3238204E6F76", SYMLINK+="camera_%k", RUN+="/usr/local/sbin/my_c_program a camera_%k %s{serial}"
```

The %k stands for the device name on /dev (i.e /dev/sdd) and %s{serial} stands for the ATTRS{serial} given by udev

The C program is writing the parameters in a file so I can see the output, so when I plug only the right device (which contains the rule serial "3238204E6F76") it does runs the C program and create the /dev/camera_sdd symlink, so the matching rule is working.

For example, if I plug the camera and udev detects it as /dev/sdc, then the output would be: 

```
a camera_sdc 3238204E6F76
```

My problem is that although I can get the %k parameter, %s{serial} returns me a NULL value. Looking at the hierarquical data udev gives me (read above) I noticed that I can get any data using %s{attribute} (i.e %s{size}, %s{range}, etc) as long as it is in the current device node (subsystem block):

looking at device '/devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1:1.0/host156/target156:0:0/156:0:0:0/block/sdc':

    KERNEL=="sdc"

    SUBSYSTEM=="block"

    DRIVER==""

    ATTR{range}=="16"

    ATTR{ext_range}=="256"

    ATTR{removable}=="1"

    ATTR{ro}=="0"

    ATTR{size}=="15269888"

    ATTR{alignment_offset}=="0"

    ATTR{discard_alignment}=="0"

    ATTR{capability}=="51"

    ATTR{stat}=="      87       15      816       72        0        0        0        0        0       72       72"

    ATTR{inflight}=="       0        0"

    ATTR{events}=="media_change"

    ATTR{events_async}==""

    ATTR{events_poll_msecs}=="-1"

But not in the parent node (in this case, subsystem usb, which contains the serial I want):

looking at parent device '/devices/pci0000:00/0000:00:04.1/usb1/1-1':

    KERNELS=="1-1"

    SUBSYSTEMS=="usb"

    DRIVERS=="usb"

    ATTRS{configuration}=="Self-powered"

    ATTRS{bNumInterfaces}==" 1"

    ATTRS{bConfigurationValue}=="1"

    ATTRS{bmAttributes}=="c0"

    ATTRS{bMaxPower}=="  2mA"

    ATTRS{urbnum}=="568"

    ATTRS{idVendor}=="0525"

    ATTRS{idProduct}=="a4a5"

    ATTRS{bcdDevice}=="0316"

    ATTRS{bDeviceClass}=="00"

    ATTRS{bDeviceSubClass}=="00"

    ATTRS{bDeviceProtocol}=="00"

    ATTRS{bNumConfigurations}=="1"

    ATTRS{bMaxPacketSize0}=="64"

    ATTRS{speed}=="480"

    ATTRS{busnum}=="1"

    ATTRS{devnum}=="6"

    ATTRS{devpath}=="1"

    ATTRS{version}==" 2.00"

    ATTRS{maxchild}=="0"

    ATTRS{quirks}=="0x0"

    ATTRS{avoid_reset_quirk}=="0"

    ATTRS{authorized}=="1"

    ATTRS{manufacturer}=="Linux 2.6.18_pro500-davinci_evm-arm_v5t_le with musb_hdrc"

    ATTRS{product}=="File-backed Storage Gadget"

    ATTRS{serial}=="3238204E6F76"

Anything from above like %s{serial}, %s{product} or %s{authorized} returns me NULL, which is weird, since acording to the udev man (http://linux.die.net/man/7/udev), if %s isn't in the current node, it will search through the parents until the attribute is matched:

 *Quote:*   

> $attr{file}, %s{file}
> 
>     The value of a sysfs attribute found at the device, where all keys of the rule have matched. If the matching device does not have such an attribute, follow the chain of parent devices and use the value of the first attribute that matches. If the attribute is a symlink, the last element of the symlink target is returned as the value.

 

Also I read in an Ubuntu forum that at some point, they had a fixed bug in their version of udev that seems to be exactly my problem:

https://bugs.launchpad.net/ubuntu/+source/udev/+bug/348513

Is it possible that "our" udev doesn't contain this patch? Im using udev from the stable tree:

```

macbook # eix -I udev

[I] sys-fs/udev

     Available versions:  ~141-r1 ~146-r1^t ~149 ~151-r4 ~164-r2 171-r9 ~171-r10 ~195^t ~196-r1^t ~197^t **9999^t {{acl action_modeswitch build debug (+)devfs-compat doc edd (-)extras floppy gudev hwdb introspection keymap +kmod old-hd-rules +openrc +rule_generator selinux static-libs test}}

    Installed versions:  171-r9(05:46:38 AM 11/20/2012)(gudev hwdb rule_generator -action_modeswitch -build -debug -edd -extras -floppy -introspection -keymap -selinux -test)

```

If I'm doing something wrong can anyone give me some pointers? And if this is indeed a confirmed bug still in the current udev build, what would be the better workaround? Thanks in advance.

----------

## PaulBredbury

 *Quote:*   

> Is it possible that "our" udev doesn't contain this patch?

 

You already have the source code - should only take a couple of minutes to determine this yourself  :Wink: 

After a superficial read - can't you just match on:

```
KERNEL=="sd?", ATTRS{serial}=="3238204E6F76"
```

Edit: I suppose not. Probably your C program has to call udev to walk up the device hierarchy itself.

----------

## Arthanis

Still, wouldn't it be great if the ubuntu patch was incorporated in the gentoo udev?

----------

## PaulBredbury

That won't happen simply by idly mentioning it here - use the Gentoo bugzilla.

----------

## jrussia

The Ubuntu patch didn't fix ATTRS walking up the tree, it changed the man page to match the actual behavior of the udev rule -- http://git.kernel.org/?p=linux/hotplug/udev.git;a=commitdiff;h=83184d008ba23724fd30996440534c0633a0d0aa

----------

