dimanche 10 février 2019

Device management using Udev

Introduction

udev is a device manager running as a daemon "udevd". It captures devices events sent by the kernel to userspace.
After receiving an event from the kernel, udev creates an entry in /dev directory for the device (In fact, the job of udev is to dynamically populate this folder).

udev general concepts

One can monitor events related to devices in 2 steps :
  • Launch udev monitor in order to catch events received by udev :
    $ udevadm monitor
    
  • Insert a device (I'm going to test using my USB stick).
The above steps are summarized in the picture below :

Removing the usb stick yields :

udev rules

Users may customize the behavior of udev, for example :
  • Change the name of device driver file in /dev or simply create symbolic links.
  • Execute a program when some event related to a device is triggered (for example call a program to copy pictures when my phone is inserted to my computer).
However, in order to set a custom behaviour, one must understand the concept of udev rules.

udev rules

Rules instructs udev for what to do when certain condition (or conditions) becomes valid (for instance : when usb stick which has PID=0x000f and VID=0x1234 is inserted).
  • Rules are typically stored in "/etc/udev/rules.d/" folder and carry the extension ".rules".
  • Rules are named using number-rulename.rules convention, so 10-usbstick.rules or 99-formatunknownusb.rules can be valid udev rule names (most often, numbers are choosed between 10 and 99).
  • udev rules are parsed in lexical order.

When udev starts, it parses /etc/udev/rules.d/ folder and builds udev rules table. Upon receiving an event, udev goes through it's rule table looking for rules to apply.

udev rule syntax

A rule is made up from 2 blocks, a matching condition and an action :

  • Matching condition : tells udev when to execute a rule.
  • Action : instructs udev what to do when matching condition is satisfied.

Udev matching conditions

Conditions are defined using the following keywords :
  • ACTION : can have values : add (when device in inserted), remove(when device is removed) or change(when device changed state.).
  • KERNEL : name of device as reported by the kernel.
  • SUBSYSTEM : name of subsystem containing the device (in /sys).
  • ATTR : device attributes like size, product id (PID), vendor id (VID), etc, ...

A udev rule example for my usb stick is shown below :

ACTION=="add", KERNEL=="sdb1", ATTR{size}=="126859264"

We can notice that == was used to test the condition, other compactors are also possible like: !=.

Remark : one should not confuse ACTION keyword with udev actions.

We are going to learn later how to find valid matching expression for any device.

udev actions

Conditions are defined using the following keywords :
  • NAME : the name of the device file driver in /dev (If not specified, udev uses default name as provided by kernel).
  • SYMLINK : creates symbolic links to device file driver in /dev.

An example that matches my usb stick :

ACTION=="add", KERNEL=="sdb1", ATTR{size}=="126859264", NAME="myfiledrive", SYMLINK+="myfiledrive-0, myfiledrive-1"

udev special commands

Find device matching conditions

One can use udev to list all matching conditions of a certain device as follow :
$ udevadm info -a -p $(udevadm info -q path -n /dev/file_driver_name)

Testing the above command on my usb stick yields :

The output can be broken into 2 parts :

  • Device part (looking at device in previous picture): gives all possible matching conditions for the device (those are enough for most usage).
  • Parents part (looking at parent in previous picture): gives matching conditions for device's parent.

We can mix both of parts together to target a specific device.

Test and debug udev rules

Errors are common when making udev rules (udev does not show errors and ignores the rule from which errors originate), one can enable udev's debugging functionality to track udev's activity :

We can see clearly that our rule has been loaded correctly (try making a syntax error in the rule, you will see a bench of errors).

Examples

Example-1 : Adding Symlink to /dev

  • Add a udev rules to /etc/udev/rules.d/ :

    Note : One must reload udev using $ sudo udevadm control --reload rules using to force udev to take into account the newly created rule.

  • Insert a usb stick and check file entries in /dev :
    Now, programs can interact with your usb stick using myfiledriver-0 or myfiledriver-1 (as they are symbolic links to sdb1).

Example-2 : Formatting unauthorized usb stick

  • Create an eraser bash script (wipe.sh) :
    #!/bin/bash
    
    dd if=/dev/zero of=/dev/sdb1 bs=1k count=2048
    
  • Add executable permission rights to eraser script :
    $ chmod 777 wipe.sh
    
  • Add udev rule :
    # Customize usb stick driver file name
    ACTION=="add", KERNEL=="sdb1", ATTR{size}=="126859264", SYMLINK+="myfiledrive-0 myfiledrive-1", RUN+="/home/jugurtha/wiper/wipe.sh"
    

    The above command will format a usb stick with the corresponding matching creteria.

  • It is important to note that : ATTR{size}!="126859264" can be used to match all devices that are different from Matching condition.