Manière «correcte» d'exécuter le script shell en tant que démon

20

J'écris un script shell que j'aimerais exécuter en tant que démon au démarrage sans utiliser d'outils externes comme daemontools ou daemonize .


Linux Daemon Writing HOWTO

Selon le Linux Daemon Writing HOWTO , un démon approprié a les caractéristiques suivantes:

  • fourches du processus parent
  • ferme tous les descripteurs de fichiers ( par exemple, stdin, stdout, stderr)
  • ouvre les journaux pour l'écriture (si configuré)
  • change le répertoire de travail en un répertoire persistant (généralement /)
  • réinitialise le masque du mode fichier (umask)
  • crée un identifiant de session unique (SID)

Présentation de daemonize

L' introduction de daemonize va plus loin, déclarant qu'un démon typique aussi:

  • se dissocie de son terminal de commande (s'il y en a un) et ignore tous les signaux du terminal
  • se dissocie de son groupe de processus
  • poignées SIGCLD

Comment puis-je faire tout cela dans un sh, dashou bashscript avec des outils Linux communs seulement?

Le script devrait pouvoir fonctionner sur autant de distributions que possible sans logiciel supplémentaire, bien que Debian soit notre objectif principal.


REMARQUE: Je sais qu'il existe de nombreuses réponses sur le réseau StackExchange recommandant l'utilisation de nohupou setsid, mais aucune de ces méthodes ne répond à toutes les exigences ci-dessus.


EDIT: La page de manuel daemon (7) donne également quelques pointeurs, bien qu'il semble y avoir des différences entre les SysVdémons de style ancien et les plus systemdrécents. Étant donné que la compatibilité avec une variété de distributions est importante, veuillez vous assurer que la réponse indique clairement toute différence.


user339676
la source
1
La « bonne » façon de concevoir votre propre script shell est de faire faire sa propre exploitation forestière, de fournir une méthode pour le lancement comme un démon, etc. Des choses comme daemonet les autres sont pour l' exécution arbitraire des scripts shell avec aucune disposition pour l' exécution en un démon. Puisque vous êtes l'auteur et que vous contrôlez entièrement la façon dont ce script est écrit, faites en sorte qu'il puisse simplement être lancé à partir d'un fichier unitaire systemd ou d'un script rc.d. Vous avez spécifié « approprié »!
Rich

Réponses:

16

En utilisant systemd, vous devriez pouvoir exécuter un script en tant que démon en créant une unité simple. Il existe de nombreuses options différentes que vous pouvez ajouter, mais c'est aussi simple que possible.

Disons que vous avez un script /usr/bin/mydaemon.

#!/bin/sh

while true; do
  date;
  sleep 60;
done

Vous créez une unité /etc/systemd/system/mydaemon.service.

[Unit]
Description=My daemon

[Service]
ExecStart=/usr/bin/mydaemon
Restart=on-failure

[Install]
WantedBy=multi-user.target 

Pour démarrer le démon que vous exécutez

systemctl start mydaemon.service 

Pour démarrer au démarrage, vous l'activez

systemctl enable mydaemon.service

Si sur un système basé sur systemd, ce que la majorité des distributions Linux sont aujourd'hui, ce n'est pas vraiment un outil externe. Le négatif serait que cela ne fonctionnera pas partout cependant.

johnramsden
la source
3
Bien que j'aime l'approche systemd, le PO a dit "pas d'outils externes". Il existe des distributions Linux qui n'ont pas encore systemd, ou vous permettent de choisir entre systemd et autre chose, par exemple OpenRC.
Cristian Ciupitu
5
Pour les distributions qui utilisent systemd, systemdn'est pas plus un "outil externe" que bash.
Alexander
7

Il me manque probablement quelque chose ici; pourquoi ne serait-il pas nohupapproprié? Bien sûr, cela ne suffit pas seul , mais le compléter semble simple.

#!/bin/bash

if [ "$1" = "DAEMON" ]; then
    # is this necessary? Add other signals at will (TTIN TTOU INT STOP TSTP)
    trap '' INT
    cd /tmp
    shift
    ### daemonized section ######
    for i in $( seq 1 10 ); do
        date
        sleep 5
    done
    #### end of daemonized section ####
    exit 0
fi

export PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
umask 022
# You can add nice and ionice before nohup but they might not be installed
nohup setsid $0 DAEMON $* 2>/var/log/mydaemon.err >/var/log/mydaemon.log &

D'aussi loin que je puisse voir:

  • la sortie est correctement redirigée (utilisez / dev / null si nécessaire)
  • le umask est hérité
  • stdin meurt à la fin du script parent cependant
  • le script daemon.sh est reparent à init(ou systemd)

J'ai le sentiment fort que je manque l'évidence. Downvote, mais dites-moi ce que c'est :-)

LSerni
la source
2
J'étais sur le point de suggérer quelque chose de très similaire. J'utilise nohupavec &et la redirection d'E / S pour lancer plusieurs Cutilitaires non- démon avec peut-être la sécurité supplémentaire d'envelopper votre nohupcommande à l'intérieur d'un su -c "nohup ... &" -s /bin/bash systemUserpour exécuter le démon en tant qu'utilisateur non privilégié.
111 ---
4

La screencommande Linux contenue dans la plupart des distributions peut démonifier un script shell. Je l'utilise souvent. Voici un exemple rapide pour démarrer, répertorier et quitter une session d'écran détachée ...

# screen -dmS Session_Name  bash -c "while true; do date; sleep 60; done"

# screen -ls
There are screens on:
        8534.Session_Name       (04/04/2018 08:46:27 PM)        (Detached)

# screen -S Session_Name -X quit
S.Haran
la source
2
screenne désamorce pas le script shell. Il suffit de les exécuter dans un terminal distingué et peut se détacher de ce terminal (comme débrancher le clavier du PC) sans fermer la session. Ainsi, le programme s'exécutant dans un terminal détaché s'exécute en arrière-plan. Par conséquent, détachez le programme de passe en arrière-plan.
Yurij Goncharuk