L’écriture de données sur stderr fait que le programme se ferme après que le programme soit devenu un démon

Veuillez regarder ce code. Il fonctionne en CentOS6 64 bits.

#include int main(int argc, char **argv) { fprintf(stderr, "output 1\n"); printf("output 2\n"); fflush(stdout); system("echo abc"); fprintf(stderr, "output 3\n "); printf("output 4\n"); fflush(stdout); daemon(0, 1); fprintf(stderr, "output 5\n"); printf("output 6\n"); fflush(stdout); system("echo abc"); fprintf(stderr, "output 7\n"); printf("output 8\n"); fflush(stdout); } 

Si je le lance, je verrai ces messages:

 output 1 output 2 abc output 3 output 4 output 5 output 6 abc output 7 output 8 

Si j’utilise ssh pour me connecter et l’exécuter, je verrai les mêmes résultats.

Cependant, si j’utilise le nom binary comme paramètre de ssh et que je l’exécute, le programme se fermera lors de l’écriture des données sur stderr après avoir appelé le démon (0, 1). Supposons que le nom binary soit myapp. je cours

 ssh localhost myapp 

Et je ne verrai que ces messages:

 output 1 output 2 abc output 3 output 4 output 5 output 6 abc 

Quelqu’un sait-il pourquoi? selon le débogage, le programme ne quitte qu’après avoir fait trois choses:

  1. Appeler le démon (0, 1).
  2. Appelez le système pour exécuter une autre application ou une commande bash.
  3. Ecrivez quelque chose à stderr.

Merci beaucoup!

Si vous exécutez cette commande depuis un shell, vous voyez probablement une nouvelle invite de shell entre la sortie 4 et la sortie 5 (cela serait plus visible si des alarmes se trouvaient entre les lignes de sortie).

Cela est dû au fait que l’appel système daemon() provoque la division du programme en deux processus indépendants. Ceci est appelé un “fork”, et peut être contrôlé un peu plus étroitement en utilisant l’appel système fork() . Après le fork, les deux processus gardent des pointeurs vers les descripteurs de fichiers ouverts: stdin, stdout et stderr. Selon le “démon man 3”, le processus parent appelle exit() après le fork.

Lorsque vous appelez votre exécutable à partir de SSH, la session SSH exécute un processus. Il bloque un enfant et le processus principal se termine. SSH voit que la commande que vous avez émise est terminée et ferme la connexion SSH. Cela ferme stdout et stderr. Malheureusement, votre processus enfant a encore du travail à faire, mais il ne peut pas écrire sur le fichier stderr partagé car ce descripteur de fichier a été fermé. Si vous imprimiez d’autres informations de débogage, telles que les valeurs fprintf() appels à printf() et à fprintf() , vous verriez qu’il n’était pas capable d’écrire dans les descripteurs de fichiers fermés.

Si, au lieu d’imprimer sur stderr, vous imprimiez dans un fichier journal (ce que font la plupart des démons), vous verrez que le processus enfant continuera à s’exécuter en arrière-plan et à écrire comme prévu.

Si vous aviez choisi d’utiliser fork() au lieu de daemon() , le parent pourrait attendre que l’enfant se termine. Vous feriez cela avec pid_t waitpid(pid_t pid, int *stat_loc, int options); .

Vous pourriez également vouloir examiner les signaux envoyés entre le parent et l’enfant. Lorsqu’un processus enfant meurt, il enverra SIGCHILD au parent. Si vous souhaitez la notification inverse, vous pouvez en configurer une (sous Linux uniquement) en utilisant prctl(PR_SET_PDEATHSIG, SIGHUP); , de sorte que le parent envoie un SIGHUP à l’enfant.