60 votes

Écrire un service qui dépend de Xorg

J'essaie d'écrire un service au niveau de l'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 en place, et je dois ensuite démarrer manuellement le service. Je suppose que je n'utilise pas le bon After= cible. Des indices ?

50voto

user42807 Points 11

J'ai fait des recherches à ce sujet et la réponse de Grawity semble dépassée. Vous pouvez maintenant configurer des services utilisateur avec systemd qui s'exécutent dans le cadre de la session de l'utilisateur. Ils peuvent avoir DISPLAY et XAUTHORITY (actuellement dans Arch, Debian Stretch+ et Ubuntu).

Cela est plus logique que les recommandations précédentes d'utiliser des fichiers de démarrage automatique du bureau, car vous obtenez une gestion des processus comme vous le feriez avec une application au niveau du système (redémarrage, etc.).

La meilleure documentation à l'heure actuelle est le wiki d'Arch ; Systemd/Utilisateur

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. En option, exécuter systemctl --user start [service] pour commencer maintenant
  4. Utilisation systemctl --user status [service] pour vérifier son état de santé

Quelques autres commandes utiles.

  • systemctl --user list-unit-files - Voir toutes les unités d'utilisateurs
  • systemctl --user daemon-reload - si vous modifiez un fichier .service

-- Plus tard...

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

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

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

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

[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

11voto

James Mertz Points 390

Le conseil habituel est de ne pas le faire. redshift n'est pas un service à l'échelle du système - il y aurait une instance distincte pour le service chaque session et il doit savoir comment se connecter au Xorg de cette session spécifique.

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

Il suffit de le lancer au démarrage avec DISPLAY=:0 n'est pas suffisante, car il n'y a aucune garantie qu'il y ait exactement un affichage à un moment donné, ni qu'il soit toujours :0 (par exemple, si Xorg se plante en laissant un fichier de verrouillage périmé, le prochain s'exécutera à :1 comme il le penserait :0 est toujours occupé) ; vous devez également définir le chemin d'accès à votre fichier XAUTHORITY car X11 exige une authentification ; et assurez-vous que redshift est redémarré si vous vous déconnectez et vous reconnectez.

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

Si vous utilisez startx vous pouvez utiliser ~/.xinitrc pour commencer ce genre de choses. Les gestionnaires de fenêtres autonomes ont souvent leurs propres scripts de démarrage/init scripts ; par ex. ~/.config/openbox/autostart pour Openbox.

Le point commun à toutes ces méthodes est que le programme est lancé à partir de à l'intérieur la session, ce qui permet d'éviter tous les problèmes énumérés ci-dessus.

6voto

VL-80 Points 4415

Cette solution répond exactement à la demande de l'auteur de la question :

il doit attendre que Xorg soit opérationnel

Bien qu'il puisse y avoir de meilleures façons de procéder, comme l'ont déjà fait d'autres utilisateurs, il s'agit d'une autre approche de ce problème.

Elle est similaire à la fonction systemd-networkd-wait-online.service qui se bloque jusqu'à ce que certains critères soient remplis. Les autres services qui en dépendent seront lancés dès que ce service aura démarré avec succès ou se sera arrêté.

Selon la 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

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

  # Adjust timeout according to your needs
  if [ $SECONDS -gt 15 ]
  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

Maintenant, activez x_server_started.service pour démarrer en même temps que le serveur X.

Faire dépendre les autres services (qui ont besoin du serveur X pour être démarrés) 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 message x_server_started.service démarrera presque immédiatement et systemd procédera au démarrage de toutes les unités qui dépendent de x_server_started.service .

0voto

Sur "/usr/lib/systemd/ utilisateur " placer un service qui comprend

[Service]
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/<user>/.Xauthority

Si cela ne suffit pas, faites un script qui attend que le gestionnaire de fenêtres soit en place :

waitSuccess () {
    local command="${*}"

    while ! ${command} &> /dev/null; do
        sleep 0.5
    done
}

waitSuccess "xprop -root -notype _NET_SUPPORTING_WM_CHECK | grep --silent true"

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X