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.servicedo systemd% sejamType=dbusou dependam da unidadedbus.socketpara 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 loginctlpara atrasar -
man pam_systemdpara informações de XDG_RUNTIME_DIR -
man systemd.servicepara Type = dbus, BusName = e dependência implícita em dbus.socket -
man sd_listen_fdspara informações sobre a variável de ambiente LISTEN_FDS - link - informações gerais sobre sessões de usuários do systemd