web-dev-qa-db-fra.com

Ecrire un service qui dépend de Xorg

J'essaie d'écrire un service de niveau utilisateur pour redshift et il doit attendre que Xorg soit opérationnel. Mon fichier de service actuel ressemble à ceci:

[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

Cependant, il semble qu'il tente de démarrer avant que Xorg ne soit opérationnel et je dois ensuite démarrer le service manuellement. Je suppose que j'utilise la mauvaise cible After=. Des allusions?

23
mkaito

J'ai étudié cela et la réponse de Grawity semble obsolète. Vous pouvez maintenant configurer les services utilisateur avec systemd qui s’exécute avec la session de l’utilisateur. Ils peuvent avoir les options DISPLAY et XAUTHORITY (actuellement dans Arch et Debian Stretch).

Cela a du sens par rapport aux recommandations précédentes consistant à utiliser des fichiers à démarrage automatique sur le bureau, car vous bénéficiez d'une gestion des processus identique à celle d'une application système (redémarrage, etc.).

Le meilleur documentaire actuellement est le wiki Arch; Systemd/User

Version TLDR;

  1. Créer le fichier * .service souhaité dans ~/.config/systemd/user/
  2. Exécuter systemctl --user enable [service] (exclure le suffixe .service)
  3. Exécutez éventuellement systemctl --user start [service] pour commencer maintenant
  4. Utilisez systemctl --user status [service] pour vérifier comment ça se passe

Quelques autres commandes utiles.

  • systemctl --user list-unit-files - voir toutes les unités utilisateur
  • systemctl --user daemon-reload - si vous éditez un fichier .service

-- Plus tard...

J'ai mis à niveau et converti la plupart de mes démons de session en fichiers systemd .service. Je peux donc ajouter quelques notes supplémentaires.

Il n'y avait pas de hook par défaut pour exécuter les services lors de la connexion, vous devez donc le déclencher vous-même. Je le fais à partir de mon fichier ~/.xsession.

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

La première ligne importe certaines variables d’environnement dans la session utilisateur systemd et la seconde lance la cible. Mon fichier xsession.target;

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

Mon xbindkeys.service à titre d'exemple.

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

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

[Install]
WantedBy=xsession.target
16
John Eikenberry

L'indice habituel est "ne pas". redshift n'est pas un service à l'échelle du système - il aurait une instance distincte pour chaque session , et il a besoin de savoir comment se connecter à Xorg de cette session.

(Xorg n'est pas non plus un service système - seul le gestionnaire d'affichage l'est, et il lance également un Xorg distinct pour chaque session. // graphical.target vous indiquera quand le gestionnaire d'affichage est prêt, mais cela ne dit rien sur le moment où le DM commence réellement le premier ou tous les affichages.)

Il ne suffit pas de le démarrer au démarrage avec DISPLAY=:0, car rien ne garantit qu’il y ait exactement un affichage à la fois, ni qu’il reste toujours :0 (par exemple, si Xorg se bloque en laissant un fichier de verrouillage obsolète, le prochain s'exécutera à :1 car il penserait que :0 est toujours occupé); vous devez également définir le chemin d'accès à votre fichier XAUTHORITY, car X11 requiert une authentification; et assurez-vous que redshift est redémarré si vous vous déconnectez et vous reconnectez.

Alors, comment le démarrer? L'environnement de bureau dispose presque toujours de plusieurs méthodes pour démarrer ses propres services de session . Voir un article plus ancien qui décrit déjà les deux messages habituels; le script ~/.xprofile et l'emplacement ~/.config/autostart/*.desktop.

Si vous utilisez startx , vous pouvez utiliser ~/.xinitrc pour démarrer de telles choses. Les gestionnaires de fenêtres autonomes ont souvent leurs propres scripts de démarrage/init. par exemple. ~/.config/openbox/autostart pour Openbox.

Le point commun à toutes ces méthodes est que le programme est lancé à partir de dans la session, ce qui évite tous les problèmes énumérés ci-dessus.

11
grawity

Voici ce que je viens de créer comme solution de contournement au graphical-session.target pas encore disponible (Sur mon système Kubuntu 16.04):

  1. Créez une pseudo unité d'utilisateur systemd qui déplace le graphical-session.target vers le haut et le bas.

Créez ~/.config/systemd/user/xsession.target avec le contenu suivant:

 [Unité] 
 Description = Xsession en marche 
 BindsTo = graphical-session.target 

Parlez de cette nouvelle unité à systemd:

$> systemctl --user daemon-reload
  1. Créez des scripts de démarrage automatique et d'arrêt qui contrôlent le xsession.target via les mécanismes actuellement disponibles du bureau Ubuntu 16.04.

Créez ~/.config/autostart-scripts/xsession.target-login.sh avec le contenu suivant:

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

Créez ~/.config/plasma-workspace/shutdown/xsession.target-logout.sh avec le contenu suivant:

#!/bin/bash 
 
 si systemctl --user est actif xsession.target &> /dev/null
then
/bin/systemctl - arrêt utilisateur xsession.target 
 fi 

Rendre les scripts exécutables:

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

Remarque: ces deux fichiers sont placés à l'emplacement où KDE les récupérera pour un démarrage automatique et un arrêt. Les fichiers peuvent être placés ailleurs pour d'autres environnements de bureau (par exemple, Gnome), mais je ne connais pas ces environnements.

Remarque: Cette solution de contournement ne prend pas en charge les sessions multi-postes de travail. Il ne gère correctement le graphical-session.target que si une seule session X11 active est exécutée sur une machine (mais c'est le cas pour la plupart des utilisateurs de Linux nous-mêmes).

  1. Créez vos propres unités utilisateur systemd qui dépendent de graphical-session.target et faites-les fonctionner correctement tout en étant connecté à votre bureau.

Comme exemple, l'unité de @ mkaito devrait ressembler à ceci:

[Unité] 
 Description = Redshift 
 PartOf = graphical-session.target 
 
 [Service] 
 ExecStart =/bin/redshift -l 28 : -13 -t 5300: 3300 -b 0,80: 0,91 m randr 
 Redémarrer = toujours 

(N'oubliez pas de faire un daemon-reload après avoir modifié vos unités!)

  1. Redémarrez votre ordinateur, connectez-vous et vérifiez que vos unités sont démarrées comme prévu
 $> systemctl - statut de l'utilisateur graphical-session.target 
 ● graphical-session.target - Session graphique actuelle 
 Loaded: chargé (/ usr/lib/systemd/user /graphical-session.target; statique; préréglage du vendeur: activé) 
 Actif: actif depuis Don 2017-01-05 15:08:42 CET; Il y a 47 minutes 
 Docs: man: systemd.special (7) 
 $> Systemctl - statut de l'utilisateur your-unit ... 

À un moment donné (ce sera Ubuntu 17.04?), Ma solution de contournement devient obsolète, car le système gérera le graphical-session.target correctement. À cette date, supprimez simplement le script de démarrage automatique et d'arrêt ainsi que le xsession.target - vos unités utilisateur personnalisées peuvent rester intactes et fonctionner.

4
gue

Cette solution fait exactement ce que l'auteur de la question demande:

il doit attendre que Xorg soit opérationnel

Bien qu'il puisse y avoir de meilleures façons de le faire, comme d'autres utilisateurs l'ont déjà répondu, c'est une autre approche de ce problème.

Il est similaire au service systemd systemd-networkd-wait-online.service qui bloque jusqu'à ce que certains critères soient remplis. Les autres services qui en dépendent seront lancés dès que ce service démarrera avec succès ou expirera.

Selon le manuel (section "Fichiers"), le serveur X crée un socket UNIX /tmp/.X11-unix/Xn (où n est un numéro d'affichage).

En surveillant la présence de ce socket, nous pouvons déterminer que le serveur pour un affichage particulier a démarré.

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

Activez maintenant x_server_started.service pour démarrer en même temps avec le serveur X.

Faire en sorte que les autres services (nécessitant le démarrage du serveur X) dépendent de x_server_started.service

unité dépendante:

[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

Si le serveur X démarre sans problème, le x_server_started.service démarre presque immédiatement et systemd démarrera toutes les unités dépendantes de x_server_started.service.

2
VL-80