Scrivere un servizio che dipende da Xorg


30

Sto cercando di scrivere un servizio a livello di utente per redshift, e deve aspettare fino a quando Xorg è attivo e funzionante. Il mio file di servizio corrente è simile al seguente:

[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

Tuttavia, sembra che tenti di avviarsi prima che Xorg sia attivo e successivamente devo avviare manualmente il servizio. Immagino che sto usando l' After=obiettivo sbagliato . Qualche suggerimento?

Risposte:


20

Ho fatto ricerche su questo e la risposta di Grawity sembra obsoleta. Ora puoi configurare i servizi utente con systemd che viene eseguito con come parte della sessione dell'utente. Possono avere set DISPLAY e XAUTHORITY (attualmente in Arch e Debian Stretch).

Questo ha senso rispetto ai precedenti consigli sull'utilizzo dei file di avvio automatico desktop, poiché ottieni la gestione dei processi proprio come faresti con un'app a livello di sistema (riavvio, ecc.).

I migliori documenti in questo momento è il wiki di Arch; Systemd / utente

Versione TLDR;

  1. Creare il file * .service desiderato in ~/.config/systemd/user/
  2. Esegui systemctl --user enable [service](escludi il suffisso .service)
  3. Opzionalmente eseguire systemctl --user start [service]per iniziare ora
  4. Utilizzare systemctl --user status [service]per verificare come sta andando

Un paio di altri comandi utili.

  • systemctl --user list-unit-files - visualizza tutte le unità utente
  • s ystemctl --user daemon-reload- se si modifica un file .service

-- Dopo...

Ho aggiornato e convertito la maggior parte dei demoni della mia sessione in file systemd .service. Quindi posso aggiungere un paio di note aggiuntive.

Non esisteva un hook predefinito per eseguire i servizi all'accesso, quindi è necessario attivarlo da soli. Lo faccio dal mio file ~ / .xsession.

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

La prima riga importa alcune variabili d'ambiente nella sessione utente di systemd e la seconda dà il via alla destinazione. Il mio file xsession.target;

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

Il mio xbindkeys.service come esempio.

[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 è possibile fornire un file di esempio di esempio e spiegare come consentire all'unità di utilizzare DISPLAY e XAUTHORITY, sarò felice di cambiare la risposta accettata.
mkaito,

@mkaito Lo esaminerò una volta che Debian rilascerà Stretch. Sto eseguendo Debian stable e stavo aspettando fino ad allora per giocarci di più.
John Eikenberry,

@mkaito Su github.com/systemd/systemd/blob/v219/NEWS#L194 dice "È ora disponibile uno scriptlet di sessione X11 che carica $ DISPLAY e $ XAUTHORITY nell'ambiente del demone systemd --user se inizia una sessione. Ciò dovrebbe migliorare la compatibilità con le applicazioni abilitate per X11 eseguite come servizi utente di systemd. "
Jos

Vorrei ancora vedere un file di unità di esempio, solo per chiarire se c'è qualcosa di speciale necessario.
mkaito,

11

Il solito suggerimento è "non". redshiftnon è un servizio a livello di sistema: avrebbe un'istanza separata per ogni sessione e deve sapere come connettersi allo Xorg di quella sessione specifica.

(Xorg non è nemmeno un servizio di sistema - lo è solo il display manager e avvia anche un Xorg separato per ogni sessione. // graphical.targetti dirà quando il display manager è pronto, ma non dice nulla su quando il DM avvia effettivamente il prima o tutte le visualizzazioni).

Basta avviarlo all'avvio con DISPLAY=:0non è sufficiente, poiché non esiste alcuna garanzia che esista esattamente un display in un determinato momento, né che lo sia sempre :0(ad esempio, se Xorg si arresta in modo anomalo lasciando un file di blocco non aggiornato, il successivo verrebbe eseguito :1come penserebbe che :0sia ancora occupato); è inoltre necessario impostare il percorso del XAUTHORITYfile poiché X11 richiede l'autenticazione; e assicurati di essere redshiftriavviato se ti disconnetti e accedi di nuovo.

Quindi come avviarlo? Quasi sempre, l'ambiente desktop ha diversi metodi per avviare i propri servizi di sessione . Vedi un post precedente che descrive già i due soliti; la ~/.xprofilesceneggiatura e il ~/.config/autostart/*.desktopluogo.

Se usi startx , puoi usare ~/.xinitrcper iniziare queste cose. I gestori di finestre indipendenti hanno spesso i propri script di avvio / inizializzazione; ad es. ~/.config/openbox/autostartper Openbox.

La cosa comune a tutti questi metodi è che il programma viene avviato dall'interno della sessione, evitando tutti i problemi sopra elencati.


Mentre redshift non è un servizio a livello di sistema in molti casi, ha senso essere un servizio utente che è esattamente ciò che l'OP sta cercando di fare.
simotek,

5

Ecco cosa ho appena creato come soluzione alternativa al non ancora disponibile graphical-session.target(sul mio sistema Kubuntu 16.04):

  1. Crea un'unità utente pseudo-sistema che porta su graphic -session.target su e giù.

Crea ~/.config/systemd/user/xsession.targetcon i seguenti contenuti:

[Unità]
Descrizione = Xsession attivo e funzionante
BindsTo = graphical-session.target

Informa systemd di questa nuova unità:

$> systemctl --user daemon-reload
  1. Crea script di avvio automatico e spegnimento che controllano xsession.targettramite la meccanica attualmente disponibile del desktop Ubuntu 16.04.

Crea ~/.config/autostart-scripts/xsession.target-login.shcon i seguenti contenuti:

#! / Bin / bash

Se ! systemctl --user is-active xsession.target &> / dev / null
poi
  / bin / systemctl - user import-environment DISPLAY XAUTHORITY
  / bin / systemctl --user avvia xsession.target
fi

Crea ~/.config/plasma-workspace/shutdown/xsession.target-logout.shcon i seguenti contenuti:

#! / Bin / bash

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

Rendi eseguibili gli script:

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

Nota: questi due file sono collocati dove KDE li raccoglierà per l'avvio automatico e l'arresto. I file potrebbero essere collocati altrove per altri ambienti desktop (ad esempio Gnome) - ma non conosco quegli ambienti.

Nota: questa soluzione alternativa non supporta le sessioni multi desktop. Gestisce graphical-session.targetcorrettamente solo fintanto che una sola sessione X11 attiva viene eseguita su una macchina (ma questo è il caso per la maggior parte di noi utenti di Linux).

  1. Crea le tue unità utente di sistema che dipendono da graphical-session.targete farle funzionare in modo pulito durante l'accesso sul desktop.

Come esempio, l'unità di mkaito dovrebbe apparire così:

[Unità]
Descrizione = Redshift
ParteDi = graphical-session.target

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

(Non dimenticare di fare un daemon-reloaddopo aver modificato le tue unità!)

  1. Riavvia il computer, accedi e verifica che le tue unità vengano avviate come previsto
$> systemctl - status dell'utente graphical-session.target
● graphical-session.target - Sessione utente grafica corrente
   Caricato: caricato (/usr/lib/systemd/user/graphical-session.target; statico; preimpostazione fornitore: abilitato)
   Attivo: attivo da Don 2017-01-05 15:08:42 CET; 47min fa
     Documenti: man: systemd.special (7)
$> systemctl - stato utente tua-unità ...

In futuro (sarà Ubuntu 17.04?) La mia soluzione alternativa diventerà obsoleta poiché il sistema gestirà graphical-session.targetcorrettamente se stesso. In quel giorno è sufficiente rimuovere lo script di avvio automatico e spegnimento e anche xsession.target- le tue unità utente personalizzate potrebbero rimanere intatte e funzionare.


So che questo è un vecchio commento, ma puoi anche aggiungere script di avvio / accesso tramite l'app Impostazioni di sistema in Area di lavoro> Avvio e spegnimento> Avvio automatico, se vuoi mettere quegli script in un posto che li ricorderai.
AmbientCyan

2

Questa soluzione fa esattamente quello che chiede l'autore della domanda:

deve attendere che Xorg sia attivo e funzionante

Mentre potrebbero esserci modi migliori per farlo, come già risposto da altri utenti, questo è un altro approccio a questo problema.

È simile al sistema systemd -networkd-wait-online.service che blocca fino a quando non vengono soddisfatti determinati criteri. Altri servizi che dipendono da esso verranno avviati non appena questo servizio viene avviato correttamente o scade.

Secondo il manuale (sezione "File"), X server creerà un socket UNIX /tmp/.X11-unix/Xn(dove nè un numero di visualizzazione).

Monitorando la presenza di questo socket possiamo determinare che il server per un determinato display è stato avviato.

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

Ora abilita x_server_started.servicel'avvio simultaneo con il server X.

Rendere altri servizi (che richiedono l'avvio di X server) per dipendere x_server_started.service

unità dipendente:

[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 il server X si avvia senza problemi, x_server_started.servicesi avvierà quasi immediatamente e systemd procederà all'avvio di tutte le unità che dipendono da x_server_started.service.


Funziona bene. Il servizio extra è un bel tocco. Puoi anche usare ExecStartPre nel tuo servizio di destinazione. Ho dovuto aggiungere un ulteriore "sleep 1" prima di "exit 0", tuttavia sembra che sia stato un po 'troppo veloce per provare a catturare X subito.
TTimo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.