Escrevendo um serviço que depende do Xorg


30

Estou tentando escrever um serviço no nível do usuário redshifte ele precisa esperar até que o Xorg esteja em funcionamento. 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 da instalação do Xorg, e eu tenho que iniciar o serviço manualmente posteriormente. Acho que estou usando o After=alvo errado . Alguma dica?

Respostas:


20

Eu estive pesquisando isso e a resposta do grawity parece desatualizada. Agora você pode configurar os serviços do usuário com systemd que são executados como parte da sessão do usuário. Eles podem ter DISPLAY e XAUTHORITY definidos (atualmente no Arch e Debian Stretch).

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

Os melhores documentos agora são o wiki do Arch; Systemd / Usuário

Versão TLDR;

  1. Crie o arquivo * .service desejado em ~/.config/systemd/user/
  2. Executar systemctl --user enable [service](excluir sufixo .service)
  3. Opcionalmente, execute systemctl --user start [service]para começar agora
  4. Use systemctl --user status [service]para verificar como está indo

Alguns outros comandos úteis.

  • systemctl --user list-unit-files - visualizar todas as unidades de usuário
  • s ystemctl --user daemon-reload- se você editar um arquivo .service

-- Mais tarde...

Atualizei e converti a maioria dos meus daemons de sessão em arquivos systemd .service. Para adicionar algumas notas adicionais.

Não havia gancho padrão para executar os serviços no logon, portanto, você deve acioná-lo. Eu faço isso no 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

2
Se você pode fornecer um exemplo de arquivo de unidade e explicar como a unidade pode usar DISPLAY e XAUTHORITY, ficarei feliz em mudar a resposta aceita.
Mkaito 27/09/16

@mkaito Vou analisar isso assim que o Debian lançar o Stretch. Estou executando o Debian stable e estava esperando até então para jogar mais com ele.
John Eikenberry 25/02

@mkaito No github.com/systemd/systemd/blob/v219/NEWS#L194, ele diz "Agora é enviado um scriptlet de sessão X11 que carrega $ DISPLAY e $ XAUTHORITY no ambiente do daemon systemd --user se uma sessão começar. Isso deve melhorar a compatibilidade com aplicativos habilitados para X11, executados como serviços de usuário systemd. "
Josch

Eu ainda gostaria de ver um exemplo de arquivo de unidade, apenas para esclarecer se é necessário algo especial.
Mkaito 11/0418

11

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

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

Apenas iniciá-lo na inicialização DISPLAY=:0não é suficiente, pois não há garantia de que exista exatamente uma tela a qualquer momento, nem que seja sempre :0(por exemplo, se o Xorg travar deixando um arquivo de bloqueio obsoleto, o próximo será executado :1como pensaria que :0ainda está ocupado); você também precisa definir o caminho para o seu XAUTHORITYarquivo, pois o X11 exige autenticação; e verifique se redshifté reiniciado se você sair e efetuar login novamente.

Então, como começar? Quase sempre, o ambiente da área de trabalho possui vários métodos para iniciar seus próprios serviços de sessão . Veja uma postagem antiga que já descreve as duas usuais; o ~/.xprofilescript e a ~/.config/autostart/*.desktoplocalização.

Se você usa o startx , pode usar ~/.xinitrcpara iniciar essas coisas. Os gerenciadores de janelas independentes geralmente têm seus próprios scripts de inicialização / inicialização; por exemplo, ~/.config/openbox/autostartpara o Openbox.

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


Embora o redshift não seja um serviço para todo o sistema, em muitos casos, faz sentido ser um serviço para o usuário, exatamente o que o OP está tentando fazer.
Simotek 27/0618

5

Aqui está o que eu criei 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 pseudo-systemd que traga a graphical-session.target para cima e para baixo.

Crie ~/.config/systemd/user/xsession.targetcom o seguinte conteúdo:

[Unidade]
Descrição = Xsession em funcionamento
BindsTo = graphical-session.target

Informe o systemd sobre esta nova unidade:

$> systemctl --user daemon-reload
  1. Crie scripts de início automático e desligamento, que controlam a xsession.targetmecânica atualmente disponível na área de trabalho Ubuntu 16.04.

Crie ~/.config/autostart-scripts/xsession.target-login.shcom o seguinte conteúdo:

#! / bin / bash

E se ! systemctl --user está ativo xsession.target &> / dev / null
então
  / bin / systemctl --user import-environment DISPLAY XAUTHORITY
  / bin / systemctl --user start xsession.target
fi

Crie ~/.config/plasma-workspace/shutdown/xsession.target-logout.shcom o seguinte conteúdo:

#! / bin / bash

se systemctl --user estiver ativo xsession.target &> / dev / null
então
  / 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 buscará para inicialização automática e desligamento. Os arquivos podem ser colocados em outro lugar para outros ambientes de desktop (por exemplo, Gnome) - mas eu não conheço esses ambientes.

Nota: Esta solução alternativa não oferece suporte a sessões com várias áreas de trabalho. Ele lida apenas com o graphical-session.targetcorreto, desde que apenas uma sessão X11 ativa seja executada em uma máquina (mas esse é o caso da maioria de nós, usuários do Linux).

  1. Crie suas próprias unidades de usuário do sistema, das quais dependem graphical-session.targete que sejam executadas de maneira limpa enquanto estão logadas na área de trabalho.

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

[Unidade]
Descrição = Redshift
PartOf = graphic-session.target

[Serviço]
ExecStart = / bin / redshift -l 28: -13 -t 5300: 3300 -b 0,80: 0,91 -m randr
Reiniciar = sempre

(Não esqueça de fazer daemon-reloaddepois de editar suas unidades!)

  1. Reinicie sua máquina, faça o login e verifique se suas unidades são iniciadas conforme o esperado
$> systemctl --user status graphic-session.target
● graphical-session.target - Sessão gráfica atual do usuário
   Carregado: carregado (/usr/lib/systemd/user/graphical-session.target; estático; predefinição de fornecedor: ativada)
   Ativo: ativo desde Don 2017-01-05 15:08:42 CET; 47min atrás
     Documentos: man: systemd.special (7)
$> systemctl - status do usuário sua unidade ...

Em algum dia futuro (será o Ubuntu 17.04?), Minha solução alternativa se tornará obsoleta, pois o sistema manipulará o processo graphical-session.targetcorretamente. Nesse dia, remova o script de inicialização automática e desligamento e também as xsession.targetsuas unidades de usuário personalizadas podem permanecer intocadas e funcionar.


Sei que esse é um comentário antigo, mas você também pode adicionar scripts de inicialização / login através do aplicativo Configurações do sistema em Área de trabalho> Inicialização e desligamento> Início automático, se você quiser colocar esses scripts em um local, lembrará deles.
AmbientCyan

2

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

ele precisa esperar até que o Xorg esteja em funcionamento

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

É semelhante ao systemd -networkd-wait-online.service do systemd, 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 com sucesso ou atingir o tempo limite.

De acordo com o 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 desse soquete, podemos determinar que o servidor para uma exibição específica foi iniciada.

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, habilite x_server_started.servicepara iniciar ao mesmo tempo com o servidor X.

Faça com que outros serviços (que precisam do servidor X sejam iniciados) dependam 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 problemas, o sistema x_server_started.serviceiniciará quase imediatamente e o systemd continuará a iniciar todas as unidades que dependem x_server_started.service.


Isso funciona bem. O serviço extra é um toque agradável. Você também pode usar o ExecStartPre no seu serviço de destino. Eu tive que adicionar um 'sono 1' extra antes da 'saída 0', porém, parece que foi um pouco rápido demais para tentar pegar o X imediatamente.
TTimo 8/08
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.