LINUX.ORG.RU

Уведомление при подключении/отключении устройства

 


1

2

Всем привет.

У меня Mint 13 MATE, хочу получать уведомления, когда я подключаю/отключаю устройства.

Первым делом попробовал udev-notify, но к сожалению он почти не заработал: «почти» - потому что работает первую минуту-две (показывает толковые уведомления), но потом, если я подключу или отключу что-нибудь, то падает так:

Traceback (most recent call last):
  File "./udev-notify.py", line 319, in <module>
    notification.show()
glib.GError: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name :1.1061 was not provided by any .service files

Победить это так и не получилось, поэтому написал багрепорт и снес.

Тогда попробовал добавить правило udev для всех устройств: добавил новый файл /etc/udev/rules.d/notify.rules:

ACTION=="add",    RUN+="/bin/bash /path/to/device_plug.sh"
ACTION=="remove", RUN+="/bin/bash /path/to/device_unplug.sh"

И два скрипта:

device_plug.sh :

#!/bin/bash

export DISPLAY=":0"
notify-send "device plugged"

/usr/bin/play -q /path/to/plug_sound.wav &

device_unplug.sh :

#!/bin/bash

export DISPLAY=":0"
notify-send "device unplugged"

/usr/bin/play -q /path/to/unplug_sound.wav &

Кое-как заработало, но плохо:

  • Когда я подключаю устройство, срабатывает несколько уведомлений. Например, FTDI usb2com порождает 4 уведомления, а флешка - больше 15. Если посмотреть вывод lsusb, то и usb2com, и флешка считаются одним устройством. Как бы настроить правило udev, чтобы уведомление тоже было только одно?
  • Не нашел как в правиле udev можно выцепить название подключенного устройства, чтобы показать его в уведомлении. В идеале было бы просто передать параметр для вызываемого с помощью RUN+="..." скрипта, но как выцепить название устройства? Ожидал, что можно указать что-то вроде ${DEV_TITLE}, ничего подобного не нагуглил.

Вот так. Если кто знает, как решить какую-нибудь из этих двух проблем - подскажите пожалста. Или если есть вообще другой способ реализовать подобные уведомления - тоже подскажите.

ничего подобного не нагуглил.

man udev, в самом конце:

$kernel, %k The kernel name for this device.

ACTION=="add",    RUN+="/path/to/device_plug.sh %k"
mky ★★★★★ ()
Ответ на: комментарий от mky

Спасибо, но как мне получить из этого kernel name красивое название, которое отображается в lsusb?

Когда я подключаю девайс, получаю 4 уведомления со следующими kernel name:

5-2
5-2:1.0
ttyUSB1
ttyUSB1

Но в lsusb оно отображается так:

Bus 005 Device 032: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC

Пробовал

$ lsusb -s 5-2:1.0
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
- не то, еще пробовал
$ lsusb -D ttyUSB1
Cannot open ttyUSB1
$ lsusb -D /dev/ttyUSB1
Cannot open /dev/ttyUSB1

Еще можно в udev подставить %p (path to device), получим что-то вроде этого:

/devices/pci0000:00/0000:00:1d.0/usb5/5-2/5-2:1.0/ttyUSB1/tty/ttyUSB1

Но, опять-таки, как по этому пути получить красивое название устройства, которое отображается в lsusb? В системе путь /sys/devices/pci0000:00/0000:00:1d.0/usb5/5-2/5-2:1.0/ttyUSB1/tty/ttyUSB1 существует, но имени устройства я там не нашел =(

dimonomid ()
Ответ на: комментарий от dimonomid

Нашел, что можно получить инфу о конкретном устройстве вот так: lsusb -D /dev/bus/usb/005/032 - выдаст информацию об этом устройстве:

Bus 005 Device 032: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC

но проблема в том, что вот этот номер Device 032 - это не физический номер устройства, а типа логический, или х3: если я вытащу устройство и вставлю его обратно, то номер увеличится. А udev мне возвращает всегда один и тот же номер: /devices/pci0000:00/0000:00:1d.0/usb5/5-2

Как мне их связать? =(

dimonomid ()
Ответ на: комментарий от dimonomid

У usb-устройства есть два идентификатора — производитель и продукт. В вашем случае ID 0403:6001. lsusb содержит в себе базу данных, которая сопоставляет численные значения текстовой строке. В приницпе, можно взять этот файл из исходников lsusb, он там простой в текстовом виде.

В ядре, в общем случае, нет строки «Future Technology Devices International, Ltd FT232 USB-Serial», то есть, можно в исходниках ядра найти драйвер, который отвечает за 0403:6001, почитать там комментарии, что-то выяснить... Но, драйвер в ядре и lsusb в общем случае никак не связаны, в ядре устройство может поддерживаться, а lsusb про него ещё не знает (старая версия) и наоборот.

Посмотрите, какие переменные среды выставляет udev для скрипта (выполните в скрипте команду set). Вроде как выставляется ID_VENDOR и ID_PRODUCT, но я точно не уверен. Но, в общем, udev может сообщить скрипту эти самы идентификаторы. А далее, либо из скрипта делать ″lsusb -d 0403:6001″, либо вытащить данные из исходников lsusb (usbutils).

/sys/devices/pci0000:00/0000:00:1d.0/usb5/5-2/5-2:1.0/ttyUSB1/tty/ttyUSB1

Названия устройства там и нет. Вот здесь вот /sys/devices/pci0000:00/0000:00:1d.0/usb5/5-2/devnum будет лежать этот самый логический номер, который выводи lsusb (Device 032).

mky ★★★★★ ()

Написать в рулесах что-то типа

SUBSYSTEM==«usb», RUN+=«/path/to/script»

В скрипте смотреть $MODALIAS Там будет что-то типа usb:vABCDp1234*ip01 - прям вплоть до конкретного интерфейса USB девайса.

Имеет смысл смотреть $ACTION в том же скрипте, а не писать 2 разных для add и remove

Stanson ★★★★★ ()
Ответ на: комментарий от mky

lsusb содержит в себе базу данных

Обычно в /usr/share/hwdata/usb.ids, обновляется из сети при помощи /usr/sbin/update-usbids.sh.

bormant ★★★★★ ()
Ответ на: комментарий от mky

mky, большое спасибо за информацию! Нашел, что можно передать vid и pid в скрипт так:

ACTION=="add", RUN+="/path/to/script $attr{idVendor} $attr{idProduct}"

и это работает, но вот если у меня воткнуто два одинаковых устройства (например, у меня несколько этих usb2com адаптеров), то lsusb -d 0403:6001 выдаст инфу о всех этих подключенных устройствах, а не только об одном - некрасиво.

Потом нашел, что можно таким же образом передать busnum и devnum: $attr{busnum} и $attr{devnum} соответственно.

К сожалению, эти вещи не передаются при отключении устройства (передаются только при подключении). А вот device_path передается. Так что, видимо, придется в текстовый файл при подключении писать device_path и соответствующее название, и потом при отключении grep-ать по этому device_path, чтобы показать название.

Щас буду пробовать.

dimonomid ()
Ответ на: комментарий от Stanson

Stanson, спасибо. Насчет $ACTION в скрипте - пожалуй, так и сделаю, действительно.

dimonomid ()
Ответ на: комментарий от bormant

bormant, спасибо, посмотрел файлик - действительно, хренова туча девайсов. А ведь наверняка есть какой-то готовый инструмент для получения названия устройства по его vid:pid? Как я уже писал выше, lsusb -d 0403:6001 выдает инфу по всем подключенным совпадающим устройствам (что логично), но мне-то нужно просто показать название по vid:pid. Как это лучше сделать? Тогда можно будет даже не париться с busnum и devnum.

dimonomid ()

Уф, кажется, альфа готова. =)

При подключении/отключении устройств срабатывает уведомление: звук и всплывающая фиговина (с помощью libnotify). Все даже можно настроить из конф. файла (вкл/выкл всплывающую фиговину, вкл/выкл звук, сами звуки)

Если у кого есть настроение, потестируйте и покритикуйте. Это мой почти первый скрипт на bash, так что я пока не владею «best practices», и буду рад здоровой критике.

Вот сам скрипт: тынц.

Установка (тестировал на Linux Mint 13) :

  • скачайте архив и распакуйте его куда-нибудь (в принципе, можно просто скопипастить скрипт, но в архиве, например, уже есть звуки для подключения/отключения устройства);
  • создайте файл /etc/udev/rules.d/my-udev-notify.rules следующего содержания: (не забудьте поправить пути к вашему my-udev-notify.sh!)
    
    ACTION=="add",    RUN+="/bin/bash /path/to/my-udev-notify.sh -a add    -p '%p' -b '$attr{busnum}' -d '$attr{devnum}'"
    ACTION=="remove", RUN+="/bin/bash /path/to/my-udev-notify.sh -a remove -p '%p' -b '$attr{devnum}' -d '$attr{devnum}'"
    
    

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

Или просто ребутнитесь, чтобы он подцепил все девайсы. НО: во время первого ребута будет много уведомлений! Это одна из «known issues». Если кто-нибудь знает, как я из bash скрипта могу проверить, загрузилась система или еще нет, поделитесь. Подключенные девайсы хранятся в определенном файле (по умолчанию /var/tmp/udev-notify-devices ), и если после выключения компа вы никаких устройств не добавляли и не убавляли, то во время следующего ребута уведомлений уже не будет.

Hope somebody enjoy it.

dimonomid ()
Ответ на: комментарий от dimonomid

Пробовал на Kubuntu 14 - не работает. Делал по инструкции, но ваш скрипт не подхватывается. Из него можно хоть всё поудалять - разницы нет. Выполняется какой-то стандартный скрипт, а где он найти не могу. Мужик, напиши в личку и вместе попробуем разобраться.

TuxLinuxMan ()
#!/usr/bin/python3
import socket

#linux/netlink.h
NETLINK_KOBJECT_UEVENT=15

soc=socket.socket(socket.AF_NETLINK,socket.SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)
soc.bind((0,1))
while 1:
  msg=dict(i.split('=')for i in soc.recv(4096).decode().split('\0')[1:-1])

  dev=msg.get('DEVNAME')
  if not(msg['ACTION']=='add'and dev and msg.get('PRODUCT')in['46d/c018/4301','749/1000/105']):
    continue

  что_нужно()
anonymous ()
Ответ на: комментарий от TuxLinuxMan

Привет. Блин, лор не отправляет письма-уведомления об ответах, а я сюда редко захожу, так что извиняй что так долго не отвечал - не видел.

Кстати, где тут личка я тоже не смог бегло найти. Так что пишу сюда: ну как, не решил проблему? Я недавно поставил Mint 17.1, все отлично работает. На Ubuntu 14.04 у коллеги тоже работало.

В общем, напиши как обстановка.

dimonomid ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.