J'ai un processus serveur de longue durée dans une session d'écran sur mon serveur Linux. C'est un peu instable (et malheureusement pas mon logiciel donc je ne peux pas résoudre ce problème!), Je veux donc script un redémarrage nocturne du processus pour aider à la stabilité. La seule façon de le faire faire un arrêt gracieux est d'aller au processus d'écran, de basculer vers la fenêtre dans laquelle il s'exécute et d'entrer la chaîne "stop" sur sa console de contrôle.
Y a-t-il des contorsions de redirection intelligentes que je peux faire pour faire un cronjob envoyer cette commande d'arrêt à une heure fixe chaque jour?
Cette réponse ne résout pas le problème, mais elle est laissée ici car plus de 30 personnes l'ont trouvée utile, sinon je l'aurais supprimée il y a longtemps.
Écrire à /proc/*pid of the program*/fd/0
. Le sous-répertoire fd
contient les descripteurs de tous les fichiers ouverts et le descripteur de fichier 0
est l'entrée standard (1 est stdout et 2 est stderr).
Vous pouvez l'utiliser pour générer des messages sur le tty sur lequel un programme s'exécute, bien qu'il ne vous permette pas d'écrire dans le programme lui-même.
Terminal 1:
[ciupicri@hermes ~]$ cat
shows on the tty but bypasses cat
Terminal 2:
[ciupicri@hermes ~]$ pidof cat
7417
[ciupicri@hermes ~]$ echo "shows on the tty but bypasses cat" > /proc/7417/fd/0
Démarrez le serveur comme ceci:
# screen -d -m -S ServerFault tr a-z A-Z # replace with your server
( écran démarre en mode détaché, donc si vous voulez voir ce qui se passe, lancez:
# screen -r ServerFault
Contrôlez le serveur comme ceci:
# screen -S ServerFault -p 0 -X stuff "stop^M"
# screen -S ServerFault -p 0 -X stuff "start^M"
# screen -S ServerFault -p 0 -X stuff "^D" # send EOF
(cette réponse est basée sur envoi de texte à un écran détaché depuis le Unix et Linux site frère)
Explication des paramètres:
-d -m Start screen in "detached" mode. This creates a new session but doesn't attach to it. This is useful for system startup scripts. -S sessionname When creating a new session, this option can be used to specify a meaningful name for the session. -r [pid.tty.Host] -r sessionowner/[pid.tty.Host] resumes a detached screen session. -p number_or_name|-|=|+ Preselect a window. This is useful when you want to reattach to a specific window or you want to send a command via the "-X" option to a specific window. -X Send the specified command to a running screen session e.g. stuff.
stuff [chaîne]
Stuff the string string in the input buffer of the current window. This is like the "paste" command but with much less overhead. Without a parameter, screen will Prompt for a string to stuff.
Démarrez le serveur comme ceci:
# tmux new-session -d -s ServerFault 'tr a-z A-Z' # replace with your server
tmux démarrera en mode détaché, donc si vous voulez voir ce qui se passe, lancez:
# tmux attach-session -t ServerFault
Contrôlez le serveur comme ceci:
# tmux send-keys -t ServerFault -l stop
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault -l start
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault C-d # send EOF
Explication des paramètres:
new-session [-AdDP] [-c start-directory] [-F format] [-n window-name] [-s session-name] [-t target-session] [-x width] [-y height] [Shell-command] Create a new session with name session-name. The new session is attached to the current terminal unless -d is given. window-name and Shell-command are the name of and Shell command to execute in the initial window. If -d is used, -x and -y specify the size of the initial window (80 by 24 if not given). send-keys [-lR] [-t target-pane] key ... (alias: send) Send a key or keys to a window. Each argument key is the name of the key (such as `C-a' or `npage' ) to send; if the string is not recognised as a key, it is sent as a series of characters. The -l flag disables key name lookup and sends the keys literally.
Essayez ceci pour commencer:
# screen
# cd /path/to/wd
# mkfifo cmd
# my_cmd <cmd
C-A d
Et cela pour tuer:
# cd /path/to/wd
# echo "stop" > cmd
# rm cmd
Il est possible d'envoyer du texte d'entrée à un processus en cours d'exécution sans exécuter l'utilitaire screen
ou tout autre utilitaire sophistiqué. Et cela peut être fait en envoyant ce texte d'entrée au "fichier" d'entrée standard du processus /proc/PID#/fd/0
.
Cependant, le texte d'entrée doit être envoyé d'une manière spéciale pour être lu par le processus. L'envoi du texte d'entrée via la méthode de fichier ordinaire write
ne provoquera pas la réception du texte par le processus. En effet, cela ne s'ajoutera qu'à ce "fichier", mais ne déclenchera pas le processus de lecture des octets.
Pour déclencher le processus de lecture des octets, il est nécessaire d'effectuer une opération IOCTL
de type TIOCSTI
pour chaque octet à envoyer. Cela placera l'octet dans la file d'attente d'entrée standard du processus.
Ceci est discuté ici avec quelques exemples en C, Perl et Python:
-
Donc, pour répondre à la question initiale posée il y a près de 9 ans, le travail cron devrait exécuter un petit script/programme utilitaire similaire aux exemples que les gens ont écrits pour cette autre question, qui enverrait la chaîne "stop\n" à ce processus serveur dans la question, en envoyant chacun des 5 octets via une opération IOCTL
de type TIOCSTI
.
Bien sûr, cela ne fonctionnera que sur les systèmes qui prennent en charge le type d'opération TIOCSTI
IOCTL
(comme Linux), et uniquement à partir du compte utilisateur root
, car ces "fichiers" sous /proc/
appartiennent à root
.
Comme je ne peux pas commenter la réponse la plus acceptée de Cristian Ciupitu (de 2010), je dois mettre cela dans une réponse séparée:
Cette question a déjà été résolue dans ce fil: https://stackoverflow.com/questions/5374255/how-to-write-data-to-existing-processs-stdin-from-external-process
En bref:
Vous devez démarrer votre processus avec un canal pour stdin qui ne se bloque ni ne se ferme lors de l'écriture de l'entrée actuelle. Cela peut être mis en œuvre par une simple boucle sans fin qui sera dirigée vers le processus en question:
$ (while [ 1 ]; do sleep 1; done) | yourProgramToStart
Je peux confirmer que c'est différent de la manière de Krissi d'ouvrir un tuyau qui ne fonctionnait pas dans mon cas. La solution indiquée a plutôt fonctionné.
Vous pouvez ensuite écrire dans le fichier .../fd/0 du processus pour lui envoyer des instructions. Le seul inconvénient est que vous devez également terminer le processus bash qui exécute la boucle sans fin après l'arrêt du serveur.