отладка правил udev

Столкнулся тут с задачей: нужно было написать правило для udev, такое, чтобы стартовали программы (какие, сейчас не важно) при подключении измерительной карты к прибор. Соответственно, при отключении карты от прибора программы должны прибиваться.

Когда дело дошло до отладки, я обнаружил, что куда-то делся udev-monitor,
который раньше позволял мониторить появление и удаление устройств. Позже оказалось, что никуда он не пропал, а стал по-другому называться.
Теперь, чтобы запустить мониторинг нужно использовать:

$ udevadm monitor --udev

И будет счастье! ;)
Но ещё не полное. Ведь при отладке приходится убивать разъём и делать много телодвижений, вынимая и вставляя карту. Этого можно избежать, поскольку добавление устройства происходит после так называемого binding-а драйвера и подходящего к нему устройства. А для инициирования binding-a можно использовать маленький трюк.
Он заключается в следующем. Определяем, к какому драйверу подходит устройство, hotplug которого мы отлаживаем. «Подходящесть» драйвера к устройству определяется их именами
(см. сюда). Далее для симуляции выдёргивания/вставления устройства выполняем unbinding, а потом binding:

$ echo -n device_name > /sys/.../drivers/driver_name/unbind

После этой команды устройство пропадёт из системы. Будет выполнено правило
«remove» udev’ом.

$ echo -n device_name > /sys/.../drivers/driver_name/bind

После этой команды устройство cнова появится в системе. Будет выполнено правило «add» udev’ом.

Вот и всё.
А отлаживать происходящее в скриптах можно обычной связкой logger + syslogd.
И будет счастье ;)

Ну и ещё один трюк, в актуальности которого я, правда, сомневаюсь. Есть такая команда

$ udevadm test,

которая позволяет симулировать появление/пропадание устройства. Её плюс в том, что она пишет, какие программы и скрипты запускает udev! Чтобы устранить сомнения насчёт того, выполняется ли вообще скрипт. Меня смутило только предупреждение в man’e относительно этой команды. А вообще она мне помогла :)

5 комментариев

  1. kurtis:

    Вы бы реальный пример привели, а то не совсем понятно что именно значит device_name, где его искать, и многоточие в путях вводит в уныние.
    А так спасибо, если честно то не знал о программной возможности переподключить устройство.

    • Павел Курочкин:

      Да, согласен. Всё не так очевидно ;) Нужно понимать, как работает binding устройств и драйверов в ядре. Вот небольшая инструкция, которая может помочь.

      У меня есть девайс arm-usb-ocd (отладчик). Подключаю его к компу по usb при запущенном udev monitore. Вот, что вижу в мониторе:


      UDEV [1281595359.479667] add /devices/pci0000:00/0000:00:1d.0/usb2/usb_device/usbdev2.1 (usb_device)
      UDEV [1281595359.521175] add /devices/pci0000:00/0000:00:1d.0/usb2/2-0:1.0 (usb)
      UDEV [1281595359.523495] add /devices/pci0000:00/0000:00:1d.0/usb2/2-0:1.0/usb_endpoint/usbdev2.1_ep81 (usb_endpoint)
      UDEV [1281595359.879303] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2 (usb)
      UDEV [1281595359.896482] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/usb_endpoint/usbdev2.123_ep00 (usb_endpoint)
      UDEV [1281595359.915017] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0 (usb)
      UDEV [1281595359.927947] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1 (usb)
      UDEV [1281595359.929630] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/usb_endpoint/usbdev2.123_ep81 (usb_endpoint)
      UDEV [1281595359.932820] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/usb_endpoint/usbdev2.123_ep02 (usb_endpoint)
      UDEV [1281595359.936218] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1/ttyUSB0 (usb-serial)
      UDEV [1281595359.942481] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1/usb_endpoint/usbdev2.123_ep83 (usb_endpoint)
      UDEV [1281595359.945976] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1/usb_endpoint/usbdev2.123_ep04 (usb_endpoint)
      UDEV [1281595359.968245] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/usb_device/usbdev2.123 (usb_device)
      UDEV [1281595359.982977] add /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1/ttyUSB0/tty/ttyUSB0 (tty)

      Нахожу там usb_device. К пути, который приведён в выводе udev monitor’a прибавляем приставку /sys. Получается:


      /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-2/usb_device/usbdev2.123

      Этот путь — это каталог, в котором:


      $ ls /sys/devices/pci0000:00/0000:00:1d.0/usb2/usb_device/usbdev2.1
      dev device power subsystem uevent

      device — это symlink, который в себе содержит symlink на driver, к которому он приаттачен. Нужно запомнить, куда указывает этот симлинк, поскольку после уделения устройства драйвер по описанному алгоритму найти уже невозможно ;) В каталоге этого драйвера вот что:


      $ ls /sys/devices/pci0000:00/0000:00:1d.0/usb2/usb_device/usbdev2.1/device/driver/
      2-2 bind module uevent unbind usb1 usb2 usb3 usb4 usb5

      Так вот, чтобы отключить устройство, нужно выполнить (под root’ом)


      echo -n usb2 > /sys/devices/pci0000:00/0000:00:1d.0/usb2/usb_device/usbdev2.1/device/driver/unbind

      В udev monitor’e будет видно, что происходит «remove»:


      UDEV [1281595305.680487] remove /devices/pci0000:00/0000:00:1d.0/usb2/usb_device/usbdev2.1 (usb_device)
      UDEV [1281595305.684690] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-0:1.0/usb_endpoint/usbdev2.1_ep81 (usb_endpoint)
      UDEV [1281595305.687069] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/usb_endpoint/usbdev2.122_ep81 (usb_endpoint)
      UDEV [1281595305.689200] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/usb_endpoint/usbdev2.122_ep02 (usb_endpoint)
      UDEV [1281595305.692701] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0 (usb)
      UDEV [1281595305.694901] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1/usb_endpoint/usbdev2.122_ep83 (usb_endpoint)
      UDEV [1281595305.697029] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1/usb_endpoint/usbdev2.122_ep04 (usb_endpoint)
      UDEV [1281595305.703166] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/usb_endpoint/usbdev2.122_ep00 (usb_endpoint)
      UDEV [1281595305.706028] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-0:1.0 (usb)
      UDEV [1281595305.710336] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/usb_device/usbdev2.122 (usb_device)
      UDEV [1281595305.733922] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1/ttyUSB0/tty/ttyUSB0 (tty)
      UDEV [1281595305.739520] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1/ttyUSB0 (usb-serial)
      UDEV [1281595305.742798] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.1 (usb)
      UDEV [1281595305.746287] remove /devices/pci0000:00/0000:00:1d.0/usb2/2-2 (usb)

      Чтобы вернуть в систему устройство, нужно выполнить echo -n «usb2» в bind того драйвера, путь которого был сохранён (см. выше).
      В моём случае:


      $ echo -n usb2 > /sys/bus/usb/drivers/usb/bind

      Дальше смотрим в udev monitor.
      ;)

    • Павел Курочкин:

      обнаружил тут такую штуку.
      в ядре 2.6.35 у device’а появился атрибут remove

      запись «1» в этот атрибут равносильная unbind ;)
      так что driver искать не обязательно

  2. kurtis:

    Спасибо!))

    • Павел Курочкин:

      рад был помочь!
      оч. приятно, что мои труды кому-то пригодились ;)