Запуск системных сервисов, использующих сеанс D-Bus в автономной системе
Мне нужна помощь в запуске служб, которые обмениваются данными через сеанс (не системный) D-Bus в системе безголового Linux Ключ в том, что никто не войдет в систему без наушников.
До сих пор я был в состоянии запустить демон D-Bus и проверить связь по D-Bus от имени пользователя ("otheruser"), который не вошел в систему, в трех разных терминалах:
В первом терминале я запускаю демон D-Bus для "другого пользователя":
$ sudo -u otheruser dbus-daemon --session --print-address 1
unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48
Во втором терминале я запускаю приложение сервера D-Bus, используя приведенный выше ответ DBUS_SESSION_BUS_ADDRESS:
$ sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" /usr/bin/my-dbus-service
Затем в третьем терминале я могу проверить соединение:
$ sudo -u otheruser DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-a5cU7r4IHc,guid=6c0a9bbfd02f5f68da0fe32f5a5e0a48" gdbus introspect --session --dest com.mycompany.myappname --object-path /com/mycompany/interface
Но я хочу запустить серверное приложение D-Bus, а также несколько клиентских сервисов D-Bus через systemd. Как запустить сеанс D-Bus через systemd, чтобы его переменная среды DBUS_SESSION_BUS_ADDRESS была передана на сервер D-Bus и в клиентские службы для "otheruser"?
Одним из возможных решений может быть перенаправление вывода dbus-daemon в "somefile", а затем установить DBUS_SESSION_BUS_ADDRESS=$(cat somefile) перед запуском сервера и клиентов D-Bus. Это просто кажется мне немного неловким; особенно потому, что я знаю, что есть некоторая магия с директивой "Busname" в служебном файле systemd для системных соединений D-Bus. Как правильно запустить службы systemd для "otheruser", чтобы эти службы systemd могли взаимодействовать с сеансным интерфейсом D-Bus?
1 ответ
Вам нужно несколько вещей, чтобы сделать эту работу.
- Включите пользовательские службы для запуска во время загрузки без входа пользователя в систему (задержка systemd).
- Файл сокета systemd для указания сокета D-Bus, который должен выделить systemd.
- Служба systemd для запуска сеансной шины D-Bus, которая запускает, а затем устанавливает переменную DBUS_SESSION_BUS_ADDRESS для других системных служб.
- Убедитесь, что ваш systemd
my-dbus-client.service
файлы имеютType=dbus
или зависит отdbus.socket
чтобы убедиться, что они выделяют сокет шины сеанса dbus и запускают службу сеанса dbus, если она еще не запущена.
Во-первых, чтобы службы Systemd для данного пользователя запускались во время загрузки без входа в систему, вам нужно включить задержку пользователя systemd - это нужно сделать только один раз как пользователь root при настройке, чтобы включить его для пользователя:
# loginctl enable-linger otheruser
Далее, если вы работаете в системе на основе Debian, для следующих двух шагов вы можете просто установить пакет dbus-user-session:
# apt-get install dbus-user-session
Если вы используете какой-то другой дистрибутив, хотите сделать это вручную или просто хотите понять, как он работает, продолжайте. В противном случае пропустите создание dbus.service
а также dbus.socket
,
Создать файл /usr/lib/systemd/user/dbus.socket
(обратите внимание, что в некоторых дистрибутивах каталог пользователя может находиться под /lib
вместо /usr/lib
) со следующим содержанием:
[Unit]
Description=D-Bus User Message Bus Socket
[Socket]
ListenStream=%t/bus
ExecStartPost=-/bin/systemctl --user set-environment DBUS_SESSION_BUS_ADDRESS=unix:path=%t/bus
[Install]
WantedBy=sockets.target
Also=dbus.service
Распространение DBUS_SESSION_BUS_ADDRESS
ко всем услугам, которые были вашей главной заботой, адресованы ExecPostStart
строка ниже - все последующие сервисы будут иметь этот набор.
%t
заменяется на XDG_RUNTIME_DIR
- временный каталог в /run
созданный systemd специально для пользовательского сеанса, который вы можете заполнить файлы. Если вы хотите создать этот сокет где-то еще, нет причин, по которым вы не можете. Просто убедитесь, что он где-то временный или очищен при перезагрузке / завершении сеанса.
У меня были некоторые проблемы, когда я пытался сделать сокет dbus unix абстрактным - systemd, похоже, не нравилась форма unix:abstract=
или же @
префикс по какой-то причине.
Теперь создайте файл /usr/lib/systemd/user/dbus.service
со следующим содержанием:
[Unit]
Description=D-Bus User Message Bus
Requires=dbus.socket
[Service]
ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
[Install]
Also=dbus.socket
За кулисами systemd происходит немного магии, чтобы передать уже созданный сокет unix демону dbus. Systemd использует информацию из dbus.socket
создать сокет, и его файловый дескриптор устанавливается в переменной окружения LISTEN_FDS
, который передается в dbus-daemon
, Специальные опции, перечисленные выше, заставляют dbus-daemon использовать переданный файловый дескриптор вместо создания нового. Это позволяет клиентам dbus запускаться параллельно с запуском dbus-демона, не беспокоясь о том, что сокет не существует.
Наконец, создайте свои собственные пользовательские службы systemd, убедившись, что вы либо установили тип Type=dbus
, задавать BusName=
на имя одного из имен службы dbus, которое будет зарегистрировано этой службой, или убедившись, Requires=dbus.socket
указан в разделе "Единица измерения". Вот пример:
[Unit]
Description=Config Server Startup
[Service]
Type=dbus
BusName=com.example.app.configuree
ExecStart=/opt/example/app/configuration_server
Restart=on-failure
[Install]
WantedBy=default.target
Вы можете разместить их в одном из нескольких мест: $HOME/.config/systemd/user
- /usr/lib/systemd/user
Включите ваши услуги с systemctl --user enable <service name>
и перезагрузите, и все должно работать.
Рекомендации:
man loginctl
задержатьсяman pam_systemd
для информации XDG_RUNTIME_DIRman systemd.service
для Type=dbus, BusName= и неявной зависимости от dbus.socketman sd_listen_fds
для получения информации о переменной среды LISTEN_FDS- https://wiki.archlinux.org/index.php/Systemd/User - общая информация о пользовательских сеансах systemd