Escrevendo um serviço que depende do Xorg

18

Eu estou tentando escrever um serviço de nível de usuário para redshift , e ele precisa esperar até que o Xorg esteja funcionando. Meu arquivo de serviço atual é assim:

[Unit]
Description=Redshift
After=graphical.target

[Service]
Environment=DISPLAY=:0
ExecStart=/bin/redshift -l 28:-13 -t 5300:3300 -b 0.80:0.91 -m randr
Restart=always

[Install]
WantedBy=default.target

No entanto, parece que ele tenta iniciar antes do Xorg, e eu tenho que iniciar manualmente o serviço depois. Eu acho que estou usando o alvo After= errado. Alguma dica?

    
por mkaito 28.05.2014 / 16:22

4 respostas

7

Eu venho pesquisando isso e a resposta da 'grewity' parece desatualizada. Agora você pode configurar serviços do usuário com o systemd que é executado como parte da sessão do usuário. Eles podem ter o conjunto DISPLAY e XAUTHORITY (atualmente em Arch e Debian Stretch).

Isso faz sentido em relação às recomendações anteriores de uso de arquivos de autostart da área de trabalho, já que você obtém o gerenciamento de processos da mesma forma que faria com um aplicativo no nível do sistema (reiniciar, etc).

Os melhores documentos agora são os wiki do Arch; Systemd / User

Versão do TLDR;

  1. Crie o arquivo desejado * .service em ~ / .config / systemd / user /
  2. Executar 'systemctl --user enable [service]' (excluir sufixo .service)
  3. Opcionalmente, execute 'systemctl --user start [service]' para iniciar agora
  4. Use 'systemctl - status do usuário [serviço]' para verificar como está sendo feito

Alguns outros comandos úteis.

  • 'systemctl - user-list-unit-files' - exibir todos os blocos de usuários
  • 'systemctl --user daemon-reload' - se você editar um arquivo .service

- Mais tarde ...

Eu fiz o upgrade e convertei a maioria dos daemons da minha sessão para os arquivos systemd .service. Então eu posso adicionar algumas notas adicionais.

Não havia gancho padrão para executar os serviços no login, portanto você deve acioná-lo por conta própria. Eu faço isso do meu arquivo ~ / .xsession.

systemctl --user import-environment PATH DBUS_SESSION_BUS_ADDRESS
systemctl --no-block --user start xsession.target

A primeira linha importa algumas variáveis de ambiente para a sessão do usuário systemd e a segunda inicia o destino. Meu arquivo xsession.target;

[Unit]
Description=Xsession running
BindsTo=graphical-session.target

Meu xbindkeys.service como um exemplo.

[Unit]
Description=xbindkeys
PartOf=graphical-session.target

[Service]
ExecStart=/usr/bin/xbindkeys -n -f ${HOME}/projects/dotfiles/.xbindkeysrc
Restart=always

[Install]
WantedBy=xsession.target
    
por 27.09.2016 / 20:03
10

A dica usual é "não". redshift não é um serviço de todo o sistema - teria uma instância separada para cada sessão , e precisa saber como se conectar ao Xorg daquela sessão específica.

(o Xorg também não é um serviço de sistema - apenas o gerenciador de exibição é, e também lança um Xorg separado para cada sessão. // graphical.target avisa quando o gerenciador de exibição é pronto, mas não diz nada sobre quando o DM realmente inicia o primeiro - ou todos - os displays.)

Apenas iniciá-lo na inicialização com DISPLAY=:0 não é suficiente, pois não há garantia de que exista exatamente uma exibição em um determinado momento, nem que seja sempre :0 (por exemplo, se o Xorg travar deixando um lockfile obsoleto , o próximo seria executado em :1 , como seria de esperar :0 ainda está ocupado); você também precisa definir o caminho para o seu arquivo XAUTHORITY , pois o X11 requer autenticação; e certifique-se de que redshift seja reiniciado se você efetuar logout & faça o login novamente.

Então, como começar? Quase sempre, o ambiente de desktop tem vários métodos para iniciar seus próprios serviços de sessão . Veja uma postagem antiga que já descreve as duas mais usuais; o script ~/.xprofile e a localização ~/.config/autostart/*.desktop .

Se você usar startx , poderá usar ~/.xinitrc para iniciar tais coisas. Os gerenciadores de janelas independentes geralmente possuem seus próprios scripts de inicialização / inicialização; por exemplo. ~/.config/openbox/autostart para o Openbox.

O que é comum a todos esses métodos é que o programa é iniciado a partir de dentro da sessão - evitando todos os problemas listados acima.

    
por 28.05.2014 / 21:27
4

Aqui está o que acabei de criar como solução alternativa para o ainda não disponível graphical-session.target (no meu sistema Kubuntu 16.04):

  1. Crie uma unidade de usuário do pseudo systemd que traga o graphical-session.target para cima e para baixo.

Crie ~/.config/systemd/user/xsession.target com os seguintes conteúdos:

[Unit]
Description = Xsession up and running
BindsTo=graphical-session.target

Diga ao systemd sobre essa nova unidade:

$> systemctl --user daemon-reload
  1. Crie autostart e scripts de desligamento , que controlam o xsession.target através da mecânica atualmente disponível da área de trabalho do Ubuntu 16.04.

Crie ~/.config/autostart-scripts/xsession.target-login.sh com os seguintes conteúdos:

#!/bin/bash

if ! systemctl --user is-active xsession.target &> /dev/null
then
  /bin/systemctl --user import-environment DISPLAY XAUTHORITY
  /bin/systemctl --user start xsession.target
fi

Crie ~/.config/plasma-workspace/shutdown/xsession.target-logout.sh com os seguintes conteúdos:

#!/bin/bash

if systemctl --user is-active xsession.target &> /dev/null
then
  /bin/systemctl --user stop xsession.target
fi

Torne os scripts executáveis:

$> chmod +x ~/.config/autostart-scripts/xsession.target-login.sh
$> chmod +x ~/.config/plasma-workspace/shutdown/xsession.target-logout.sh

Nota: esses dois arquivos são colocados onde o KDE os selecionará para início automático e desligamento. Os arquivos podem ser colocados em outro lugar para outros ambientes de área de trabalho (por exemplo, Gnome), mas não sei sobre esses ambientes.

Observação: essa solução alternativa não oferece suporte a várias sessões de área de trabalho. Ele lida apenas com o graphical-session.target corretamente, desde que apenas uma sessão X11 ativa seja executada em uma máquina (mas esse é o caso para a maioria dos usuários do Linux).

  1. Crie suas próprias unidades de usuário systemd , que dependem de graphical-session.target e execute-as de forma limpa enquanto estiver conectado à sua área de trabalho.

Como exemplo, a unidade do @mkaito deve ficar assim:

[Unit]
Description=Redshift
PartOf=graphical-session.target

[Service]
ExecStart=/bin/redshift -l 28:-13 -t 5300:3300 -b 0.80:0.91 -m randr
Restart=always

(Não se esqueça de fazer um daemon-reload após editar suas unidades!)

  1. Reinicie sua máquina, faça o login e verifique se suas unidades foram iniciadas conforme o esperado
$> systemctl --user status graphical-session.target
● graphical-session.target - Current graphical user session
   Loaded: loaded (/usr/lib/systemd/user/graphical-session.target; static; vendor preset: enabled)
   Active: active since Don 2017-01-05 15:08:42 CET; 47min ago
     Docs: man:systemd.special(7)
$> systemctl --user status your-unit...

Em algum dia futuro (será o Ubuntu 17.04?), minha solução alternativa se tornará obsoleta, já que o sistema manipulará o graphical-session.target corretamente. Nesse dia, basta remover o script de início automático e encerramento e também o xsession.target - suas unidades de usuário personalizadas podem permanecer intactas e funcionar.

    
por 05.01.2017 / 15:53
1

Esta solução faz exatamente o que o autor da pergunta faz:

it needs to wait until Xorg is up and running

Embora possa haver maneiras melhores de fazer isso, como já foi respondido por outros usuários, essa é outra abordagem para esse problema.

É semelhante ao systemd-networkd-wait-online do systemd. service que bloqueia até que certos critérios sejam atendidos. Outros serviços que dependem dele serão lançados assim que o serviço for iniciado ou expirar.

Pelo manual (seção "Arquivos"), o servidor X criará um soquete UNIX /tmp/.X11-unix/Xn ( onde n é um número de exibição).

Ao monitorar a presença deste soquete, podemos determinar que o servidor para uma determinada exibição foi iniciado.

confirm_x_started.sh :

#!/bin/bash
COUNTER=0

while [ 1 ]
do
  # Check whether or not socket exists
  if [ -S /tmp/.X11-unix/X0 ]
  then
    exit 0
  fi

  ((++COUNTER))

  if [ $COUNTER -gt 20 ]
  then
    exit 1
  fi

  sleep 0.5
done

x_server_started.service :

[Unit]
Description=Monitor X server start

[Service]
Type=oneshot
ExecStart=/path/to/confirm_x_started.sh

[Install]
WantedBy=example.target

Agora, ative o x_server_started.service para iniciar ao mesmo tempo com o servidor X.

Faça outros serviços (que precisam que o servidor X seja iniciado) para depender de x_server_started.service

unidade dependente:

[Unit]
Description=Service that needs to have the X server started
Requires=x_server_started.service
After=x_server_started.service

[Service]
ExecStart=/path/to/binary

[Install]
WantedBy=example.target

Se o servidor X for iniciado sem um problema, o x_server_started.service será iniciado quase imediatamente e o systemd continuará a iniciar todas as unidades que dependem do x_server_started.service .

    
por 23.08.2018 / 01:45

Tags