Você precisa de várias coisas para fazer isso funcionar.
- Permitir que os serviços do usuário sejam executados no momento da inicialização sem o login do usuário (systemd linger).
- Um arquivo de soquete systemd para especificar o soquete D-Bus para o systemd alocar.
- Um serviço do systemd para iniciar o barramento de sessão do D-Bus que é iniciado e, em seguida, define a variável de env DBUS_SESSION_BUS_ADDRESS para outros serviços do systemd.
- Assegure-se de que seus arquivos
my-dbus-client.service
do systemd% sejamType=dbus
ou dependam da unidadedbus.socket
para garantir que eles aloquem o soquete do barramento da sessão dbus e iniciem o serviço da sessão dbus se ele ainda não tiver sido iniciado.
Primeiro, para fazer com que os serviços do Systemd para um determinado usuário iniciem no tempo de inicialização sem login, é necessário ativar o usuário systemd remanescente - isso só precisa ser feito uma vez como root ao configurá-lo para um usuário:
# loginctl enable-linger otheruser
Em seguida, se você estiver em um sistema baseado no Debian, para as próximas duas etapas, você pode simplesmente instalar o pacote pacote dbus-user-session:
# apt-get install dbus-user-session
Se você estiver usando alguma outra distribuição, faça isso manualmente ou apenas queira entender como ela funciona. Caso contrário, pule a criação de dbus.service
e dbus.socket
.
Crie o arquivo /usr/lib/systemd/user/dbus.socket
(note que em algumas distribuições o diretório do usuário pode estar em /lib
em vez de /usr/lib
) com o seguinte conteúdo:
[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
A propagação de DBUS_SESSION_BUS_ADDRESS
para todos os serviços, que era sua principal preocupação, é tratada pela linha ExecPostStart
abaixo - todos os serviços a seguir terão esse conjunto.
%t
é substituído pelo XDG_RUNTIME_DIR
- um diretório transitório em /run
criado pelo systemd específico da sessão do usuário que você pode preencher os arquivos. Se você deseja criar este soquete em outro lugar, não há motivo para você não poder. Apenas certifique-se de que esteja em algum lugar transitório ou que seja limpo na reinicialização / desmontagem da sessão.
Eu tive alguns problemas tentando tornar o soquete unix dbus um resumo - o systemd parecia não gostar do prefixo unix:abstract=
or @
por algum motivo.
Agora crie o arquivo /usr/lib/systemd/user/dbus.service
com o seguinte conteúdo:
[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
Existe um pouco de mágica que acontece aqui nos bastidores pelo systemd para passar o socket unix já criado para o dbus-daemon. O Systemd usa as informações de dbus.socket
para criar o soquete e seu descritor de arquivo é definido na variável de ambiente LISTEN_FDS
, que é passada para o dbus-daemon
. Opções especiais listadas acima fazem o dbus-daemon usar o descritor de arquivo passado em vez de criar um novo. Isso permite que os clientes dbus iniciem paralelamente ao dbus-daemon, iniciando sem preocupações de que o socket não exista.
Por fim, crie seus próprios serviços de usuário do systemd, certificando-se de definir o tipo como Type=dbus
, definir BusName=
como o nome de um dos nomes de serviço dbus que serão registrados por esse serviço ou Certifique-se de que Requires=dbus.socket
esteja especificado na seção Unidade.
Aqui está um exemplo:
[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
Você pode colocá-los em um dos vários lugares:
- $HOME/.config/systemd/user
- /usr/lib/systemd/user
Ative seus serviços com systemctl --user enable <service name>
e reinicialize e tudo deve funcionar.
Referências:
-
man loginctl
para atrasar -
man pam_systemd
para informações de XDG_RUNTIME_DIR -
man systemd.service
para Type = dbus, BusName = e dependência implícita em dbus.socket -
man sd_listen_fds
para informações sobre a variável de ambiente LISTEN_FDS - link - informações gerais sobre sessões de usuários do systemd