Вопрос или проблема
Я хочу автоматически запускать GUI приложение, когда я подключаю определенное USB устройство.
Когда приложение запускается, оно работает в переднем плане и не должно выполняться с правами root.
Как это сделать?
В моем конкретном случае я хочу запускать Yubico Authenticator, когда я подключаю мой USB FIDO2/TOTP токен безопасности Yubikey.
Прямое использование udev RUN=
не подходит
Прямое использование директивы RUN в правиле udev, например RUN=/opt/yubico-authenticator/authenticator
, не подходит для этой цели.
- RUN блокирует выполнение. Система может/будет завершать долгоживущие процессы через некоторое время. Он предназначен для короткоживущих процессов, таких как выполнение коротких скриптов настройки или подобного.
- Он выполняется с правами root
- У него нет доступа к необходимым переменным окружения, таким как $DISPLAY или $WAYLAND_DISPLAY и аналогичные, и, следовательно, он не может подключиться к сеансу рабочего стола без значительных обходных путей.
Решение
Запуск GUI приложения при подключении устройства может быть достигнут путем комбинирования правила udev с пользовательскими службами systemd. Настройте имена файлов, строки Description=
и ExecStart=
в файле ниже в соответствии с вашими конкретными потребностями.
Пользовательская служба Systemd
Пользовательская служба будет запускаться с использованием ваших обычных прав пользователя в рамках текущей GUI сессии.
- Создайте файл службы systemd
~/.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
, что должно запустить приложение.
Использование udev для запуска службы
Настройте udev на автоматический запуск службы при подключении устройства.
- От имени 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"
- Перезагрузите udev:
sudo systemctl restart udev.service
- Прибыль. Подключите ваше устройство.
Вышеуказанное правило срабатывает на любое 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, необходимым для подключения к текущей сессии пользователя.
- Необходимость выполнения от имени пользователя: Поскольку наше приложение графическое, оно должно работать в контексте обычного пользователя, а не с повышенными привилегиями, чтобы взаимодействовать с текущей рабочей средой.
Пример
Чтобы решить эту задачу, следуйте следующим шагам:
-
Создание пользовательского сервиса 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
Если всё настроено верно, приложение должно запуститься в графической сессии пользователя.
-
Настройка правила 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
-
Практическое применение
Подключите ваш YubiKey к USB-порту. Если правила настроены верно, система автоматически запустит Yubico Authenticator в вашей пользовательской сессии.
Эта конфигурация обеспечивает запуск приложения без необходимости запуска его как root и предоставляет доступ ко всем необходимым переменным окружения, таким как $DISPLAY. Система работает стабильно благодаря механизму systemd, который гарантирует, что приложение запускается только один раз при повторном подключении устройства. Такая практика минимизирует возможные сбои и делает процесс более управляемым.
Подобные настройки могут быть адаптированы для работы с другими устройствами и приложениями, требующими автоматического запуска, изменяя идентификатор производителя и команды запуска в udev-правилах и сервисах systemd. Такие подходы повышают уровень автоматизации и комфорт работы пользователя, не нарушая при этом безопасности системы.