Search code examples
linuxscriptingusblibusbudev

Run script after all udev rules are through and device is completely initialized


I am attempting to read information from a usb device after it is attached.

The information I require are accessed through two APIs: v4l2 and libusb. Both are used through a script that is correctly called as the v4l2 part executes are expected.

SUBSYSTEM=="usb", ATTRS{idVendor}=="199a", GROUP="video", MODE="0666", TAG+="uaccess", TAG+="udev-acl"

ACTION=="add", SUBSYSTEM=="video4linux", \
               ATTRS{idVendor}=="199a" \
               RUN+="/usr/bin/camera-infos-wrapper %s{serial}"

When I run the script manually all steps are executed correctly. I have a wrapper around the script to set additional environment variables.

#!/usr/bin/env bash

export DISPLAY=":0"
export XAUTHORITY=/home/user/.Xauthority

# sleep 3 <- does not work
# sleep 4 <- works

# ensure debug output is logged
exec 1> >(logger -s -t $(basename $0)) 2>&1

/usr/bin/tcam-index-camera $1

When I sleep for 3 seconds libusb is unable to correctly open the device. Sleeping for 4 seconds allows correct access. Since this has to run on more than on PC I would prefer a more robust solution.

Is there any way to run the script after all udev rules are through and the device is completely initialized?


Solution

  • The way to go seems to be systemd.

    The systemd unit [email protected]

    [Unit]
    Description=My service
    
    After=dev-ident%i.device
    Wants=dev-ident%i.device
    
    [Service]
    Type=forking
    ExecStart=/usr/bin/script %i
    

    Note the '@' in the file name. It is important as it is required for arguments.

    The udev rule looks like:

    ACTION=="add", SUBSYSTEM=="video4linux", \
                   ATTRS{idVendor}=="<vendor id>", \
                   TAG+="systemd", \
                   SYMLINK+="ident%s{serial}", \
                   ENV{SYSTEMD_WANTS}="camera-index@%s{serial}.service"
    
    

    The systemd unit waits until the symlink is created and executes the script after that.