Как автоматически запускать графическое приложение при подключении USB-устройства?

Вопрос или проблема

Я хочу автоматически запускать GUI приложение, когда я подключаю определенное USB устройство.
Когда приложение запускается, оно работает в переднем плане и не должно выполняться с правами root.

Как это сделать?

В моем конкретном случае я хочу запускать Yubico Authenticator, когда я подключаю мой USB FIDO2/TOTP токен безопасности Yubikey.

Прямое использование udev RUN= не подходит

Прямое использование директивы RUN в правиле udev, например RUN=/opt/yubico-authenticator/authenticator, не подходит для этой цели.

  1. RUN блокирует выполнение. Система может/будет завершать долгоживущие процессы через некоторое время. Он предназначен для короткоживущих процессов, таких как выполнение коротких скриптов настройки или подобного.
  2. Он выполняется с правами root
  3. У него нет доступа к необходимым переменным окружения, таким как $DISPLAY или $WAYLAND_DISPLAY и аналогичные, и, следовательно, он не может подключиться к сеансу рабочего стола без значительных обходных путей.

Решение

Запуск GUI приложения при подключении устройства может быть достигнут путем комбинирования правила udev с пользовательскими службами systemd. Настройте имена файлов, строки Description= и ExecStart= в файле ниже в соответствии с вашими конкретными потребностями.

Пользовательская служба Systemd

Пользовательская служба будет запускаться с использованием ваших обычных прав пользователя в рамках текущей GUI сессии.

  1. Создайте файл службы systemd ~/.local/share/systemd/user/yubico-authenticator.service, который запускает приложение:
[Unit]
Description=Запускает Yubico-Authenticator

[Service]
Type=simple
ExecStart=/opt/yubico-authenticator/authenticator
  1. Перезагрузите файлы служб systemd: выполните systemctl --user daemon-reload
  2. Проверьте: выполните systemctl --user start yubico-authenticator.service, что должно запустить приложение.

Использование udev для запуска службы

Настройте udev на автоматический запуск службы при подключении устройства.

  1. От имени root создайте файл правил udev /etc/udev/rules.d/10-yubikey.rules со следующим содержимым:
#Yubico USB TOTP/FIDO2 токены
SUBSYSTEM=="usb", ATTRS{idVendor}=="1050", ACTION=="add", ENV{SYSTEMD_USER_WANTS}+="yubico-authenticator.service", TAG+="systemd"
  1. Перезагрузите udev: sudo systemctl restart udev.service
  2. Прибыль. Подключите ваше устройство.

Вышеуказанное правило срабатывает на любое USB устройство от производителя 0x1050, который является Yubico. Через ENV{SYSTEMD_USER_WANTS} оно говорит systemd запустить пользовательскую службу с именем yubico-authenticator.service, которое должно совпадать с именем файла ранее созданного файла службы.

Поскольку оно указывает systemd, что устройство хочет, чтобы служба была запущена, а не чтобы исполняемый файл запускался при каждом подключении, systemd запускает только один экземпляр максимум. Первое подключение запускает службу, а последующие отключения и повторные подключения устройства, или подключение нескольких устройств не порождают дополнительных экземпляров.

Ответ или решение

Автоматический запуск графического приложения при подключении USB-устройства — это задача, которая может быть решена с помощью совмещения правил udev и пользовательских сервисов systemd. Давайте подробно рассмотрим процесс решения этой задачи на примере запуска Yubico Authenticator при подключении YubiKey.

Теория

Основная идея состоит в использовании правила udev и пользовательского сервиса systemd для запуска приложения в контексте текущей пользовательской сессии. udev ответственен за мониторинг событий на устройствах, а systemd обеспечивает управление сервисами, предлагая гибкие средства для их настройки и запуска.

При этом важно понять, почему некоторые подходы непригодны для нашей задачи:

  • RUN в udev-правилах: Директива RUN предполагала бы выполнение команды или скрипта при срабатывании udev-события, но её использование ограничено. Такие задания блокируют выполнение до завершения процесса и запускаются с правами root, что небезопасно для графических приложений. Кроме того, они не имеют доступа к переменным окружения, таким как $DISPLAY, необходимым для подключения к текущей сессии пользователя.
  • Необходимость выполнения от имени пользователя: Поскольку наше приложение графическое, оно должно работать в контексте обычного пользователя, а не с повышенными привилегиями, чтобы взаимодействовать с текущей рабочей средой.

Пример

Чтобы решить эту задачу, следуйте следующим шагам:

  1. Создание пользовательского сервиса systemd

    Первый шаг — создать пользовательский сервис, который будет запускать Yubico Authenticator. Для этого создайте файл ~/.local/share/systemd/user/yubico-authenticator.service со следующим содержимым:

    [Unit]
    Description=Запуск Yubico Authenticator
    
    [Service]
    Type=simple
    ExecStart=/opt/yubico-authenticator/authenticator

    Перезагрузите пользовательские сервисы systemd с помощью команды:

    systemctl --user daemon-reload

    Проверьте, что сервис может быть запущен вручную:

    systemctl --user start yubico-authenticator.service

    Если всё настроено верно, приложение должно запуститься в графической сессии пользователя.

  2. Настройка правила udev

    Следующий шаг — создание правила udev, которое будет срабатывать при подключении устройства YubiKey. Создайте файл /etc/udev/rules.d/10-yubikey.rules с таким содержимым:

    # Yubico USB TOTP/FIDO2 tokens
    SUBSYSTEM=="usb", ATTRS{idVendor}=="1050", ACTION=="add", ENV{SYSTEMD_USER_WANTS}+="yubico-authenticator.service", TAG+="systemd"

    В этом правиле ATTRS{idVendor}=="1050" определяется производителем устройства — Yubico. При добавлении (подключении) устройства с таким идентификатором, запускается указанный пользовательский сервис.

    Для применения новых правил необходимо перезапустить udev:

    sudo systemctl restart udev.service
  3. Практическое применение

    Подключите ваш YubiKey к USB-порту. Если правила настроены верно, система автоматически запустит Yubico Authenticator в вашей пользовательской сессии.

Эта конфигурация обеспечивает запуск приложения без необходимости запуска его как root и предоставляет доступ ко всем необходимым переменным окружения, таким как $DISPLAY. Система работает стабильно благодаря механизму systemd, который гарантирует, что приложение запускается только один раз при повторном подключении устройства. Такая практика минимизирует возможные сбои и делает процесс более управляемым.

Подобные настройки могут быть адаптированы для работы с другими устройствами и приложениями, требующими автоматического запуска, изменяя идентификатор производителя и команды запуска в udev-правилах и сервисах systemd. Такие подходы повышают уровень автоматизации и комфорт работы пользователя, не нарушая при этом безопасности системы.

Оцените материал
Добавить комментарий

Капча загружается...