[Shell / C] Script shell en tant que démon ?

Script shell en tant que démon ? [Shell / C] - Shell/Batch - Programmation

Marsh Posté le 05-10-2006 à 10:51:19    

Bonjour,
 
J’ai écrit un petit script Shell qui envoie des SMS à partir de fichiers placés dans un répertoire. Le script regarde de temps en temps le dossier et traite les fichiers s’il y en a. Comme ce script doit tourner en permanence, je souhaitais le lancer en tant que démon.
 
Après recherches, je n’ai pas trouvé comment faire cela, je ne suis même pas sur que cela soit possible. Les scripts de démarrage placés dans « /etc/init.d » ne semblent fonctionner que pour lancer des applications non binaires.
 
1) Est-ce possible de créer un démon à partir d’un script Shell ?
 
J’avais également pensé utiliser « cron » pour lancer périodiquement mon script, le problème est que l’envoi de SMS (par gnokii) peut prendre du temps et donc il faut que je regarde si mon script est déjà en cours d’exécution. Bref il faut que « cron » appelle un script qui surveille celui qui envoie les SMS et qui l’appelle s’il n’est pas actif. Je n’aime pas trop cette solution et en plus je ne sais pas comment tester si mon script d’envoi est actif (j'ai que "bash" ou "sh" comme nom dans la liste des processus, donc je ne vois pas trop comment être sur de tester le bon; je pourrai tester l'existence du processus « gnokii » mais il se peut aussi que le test se fasse pendant le scan du répertoire ou même entre 2 appels de « gnokii »).
 
2) Cette solution est-elle bonne ? Si oui comment tester l’activité du script d’envoi des SMS (nommage du script ?)
 
Enfin je pensais réécrire le script Shell en C pour pouvoir utilisé la méthode classique de lancement de démons (référencement dans /etc/init.d)
 
3) Est-ce la meilleure solution ?
 
4) Je suis à la ramasse et je m’y prends comme un pied (désolé j’apprends :)) ?
 
Merci pour vos conseils éclairés.
 
Edit: à la limite je pourrai ecrire le PID du shell qui execute mon script d'envoi dans un fichier et que mon script appelé par cron lise ce fichier. Un peu crade non ?

Message cité 1 fois
Message édité par tieuma le 05-10-2006 à 12:26:25
Reply

Marsh Posté le 05-10-2006 à 10:51:19   

Reply

Marsh Posté le 05-10-2006 à 13:48:53    

une solution pas forcément très propre mais facile à mettre en place (en attendant de faire mieux), c'est d'utiliser at :
 
tu ajoutes à la fin de ton script une ligne qui demande la réexécution du script un peu plus tard. genre 'at now + 1 hours < /chemin/vers/ton/script'
la première fois, tu lances le script à la main (ou automatiquement avec /etc/init.d). Ensuite, c'est le script lui-même qui programme sa propre réexécution un peu plus tard.


---------------
TriScale innov
Reply

Marsh Posté le 05-10-2006 à 14:20:43    

Bonjour,
 
A la base le script boucle à l'infini (sans doutes moins propre que ce que tu proposes). Il scan le rep, envoie les sms si il ya des fichiers dedans, attend xx secondes une fois le traitement fini (même chose si le dossier est vide).
 
Mon problème c'est de faire en sorte que mon script tourne en permanence, et qu'il ne meurt pas une fois que j'ai fermé le shell qui l'a lancé.
 
Il faudrait que je puisse le démarrer via un script dans /etc/init.d mais je n'y arrive pas. J'ai essayé avec un script qui ressemble à ça:
 

Code :
  1. case "$1" in
  2.         start)       
  3.         echo -n "Starting $DESC: $NAME"
  4.         sh mon_service & >& /dev/null       
  5.         ;;
  6. ...


 
Mais ça ne fonctionne pas. Quand je lance "/etc/init.d/mon_script start" le bash me renvoie ceci:
 

Code :
  1. -bash: /etc/init.d/mon_script: cannot execute binary file


 
D'où ma question sur la possibilité de lancer un script shell de cette facon (ce qui m'a l'air compromis vu qu'il semble attendre un fichier binaire...).

Message cité 1 fois
Message édité par tieuma le 05-10-2006 à 14:21:12
Reply

Marsh Posté le 05-10-2006 à 14:42:12    

tieuma a écrit :

Mon problème c'est de faire en sorte que mon script tourne en permanence, et qu'il ne meurt pas une fois que j'ai fermé le shell qui l'a lancé.

tu peux utiliser nohup pour ça.
 
Je ne sais pas trop d'où vient l'erreur dans ton script init.d


---------------
TriScale innov
Reply

Marsh Posté le 05-10-2006 à 15:37:51    

Merci pour nohup, je ne connaissais pas  :whistle:
 
Ca fera l'affaire pour le moment mais il faudra que je trouve une solution pour que mon script init.d fonctionne (les SMS sont utilisés, en partie, pour les alertes nagios critiques :), donc il faut que la commande soit lancée si redemarrage de la machine ou si le processus meurt).
 
Merci en tous cas pour ton aide.


Message édité par tieuma le 05-10-2006 à 15:38:19
Reply

Marsh Posté le 09-10-2006 à 15:13:57    

Je up le sujet car j'ai encore un problème.
 
J'ai réussi à faire executer mon script au démarrage. Le problème est qu'il ne semble pas posseder les mêmes droits que lorsque je le lance en root. Le script appelle "gnokii" qui permet d'envoyer des sms via un gsm nokia. Le gsm est branché sur le port serie dont le fichier descripteur est "ttyS0".
 
Si je lance mon script dans un terminal, l'accès au GSM (au fichier ttyS0) est autorisé. Par contre le script lancé au demarrage se fait jeté.
 
Mon script est lancé au runlevel 5.
 
Une idée ? Merci.

Reply

Marsh Posté le 09-10-2006 à 15:41:02    

A quel moment est lancé ton script ? Tu es sûr que tous les points de  montage /dev/ttyS* ont déjà été créés à cette étape ?
 
Essaie de lancer ton script à la fin du boot (genre priorité 99) pour voir ce que ça donne...


---------------
TriScale innov
Reply

Marsh Posté le 09-10-2006 à 17:50:23    

Bonjour,
 
Finalement gnokii accède bien au fichier ttyS0. Le probleme venait du fait que je n'avais pas spécifié l'emplacelement du binaire gnokii dans mon script shell. Lorsque le script etait appelé lors du passage à init 5, le chemin utilisé etait /usr/bin/gnokii alors qu'en etant deja logué en root le chemin est /usr/local/bin/gnokii.
 
Maintenant j'ai un autre problème  :heink:.
 
Lorsque je lance mon script de démarrage en root (/etc/init.d/smsgateway start & ), tout se passe comme prévu, le sms est envoyé. Si je repasse en init 3 puis en init 5 pour simuler le démarrage, tout se passe normalement, je vois mon processus gnokii se lancer, durer environ 30 et... rien. Pas de sms d'envoyer. Il doit y avoir une erreur pdt l'envoi du sms mais impossible de voir quoique ce soit.
 
Il faut que je redirige le log de gnokii vers un fichier pour savoir ce qui se passe.
 
Edit: apparemment, lorsque gnokii est lancé par mon script lui même lancé au runlevel 5, gnokii perd l'emplacement du fichier de conf et un timeout se produit lors de la recuperation du smsc


Message édité par tieuma le 09-10-2006 à 18:22:28
Reply

Marsh Posté le 09-10-2006 à 22:58:29    

nohup c'est bien, start-stop-daemon c'est mieux.

Reply

Marsh Posté le 10-10-2006 à 10:42:56    

oui, mais il me semble que c'est spécifique à certaines distributions (debian et ses dérivées ?)
 
Je l'ai par exemple sur ma debian perso, mais pas sur la mandrake du boulot. Du coup, je ne savas pas si tieuma y a accès.


---------------
TriScale innov
Reply

Marsh Posté le 10-10-2006 à 10:42:56   

Reply

Marsh Posté le 11-10-2006 à 15:45:26    

C'est bon, j'ai réussi à faire ce que je voulais (enfin presque...). Merci pour vos conseils.

Reply

Marsh Posté le 11-10-2006 à 15:51:23    

nohup

Reply

Marsh Posté le 11-10-2006 à 23:35:37    

Tout le monde a donné pas mal d'infos. Je vais essayer de résumer
 

tieuma a écrit :

1) Est-ce possible de créer un démon à partir d’un script Shell ?


Un démon c'est grosso-modo un programme qui tourne à l'infini et qui fait des trucs. Rien ne t'empêche de faire un "while true" dans un script et lancer ce script d'une façon ou d'une autre. Ce sera un démon.
 

tieuma a écrit :

J’avais également pensé utiliser « cron » pour lancer périodiquement mon script, le problème est que l’envoi de SMS (par gnokii) peut prendre du temps et donc il faut que je regarde si mon script est déjà en cours d’exécution. Bref il faut que « cron » appelle un script qui surveille celui qui envoie les SMS et qui l’appelle s’il n’est pas actif. Je n’aime pas trop cette solution et en plus je ne sais pas comment tester si mon script d’envoi est actif (j'ai que "bash" ou "sh" comme nom dans la liste des processus, donc je ne vois pas trop comment être sur de tester le bon; je pourrai tester l'existence du processus « gnokii » mais il se peut aussi que le test se fasse pendant le scan du répertoire ou même entre 2 appels de « gnokii »).
 
2) Cette solution est-elle bonne ? Si oui comment tester l’activité du script d’envoi des SMS (nommage du script ?)
Edit: à la limite je pourrai ecrire le PID du shell qui execute mon script d'envoi dans un fichier et que mon script appelé par cron lise ce fichier. Un peu crade non ?


Dans l'absolu, rien n'empêche un programme de s'exécuter plusieurs fois en parallèle. Donc même si l'envoi du SMS prend du temps, rien n'interdit à priori de relancer une 2° instance du programme, celui-ci envoyant lui-aussi le SMS... sauf si le programme utilise une ressource unique de façon exclusive. Mais t'as raison, faire un 2° script pour détecter que le premier n'a pas déjà été lancé c'est un peu beaucoup sale.
En général, quand on veut faire un script exclusif, on lui fait créer un fichier particulier (dans "/tmp" par exemple) et détruire le fichier à la fin d'exécution. Et on place au début du script un test vérifiant si le fichier n'existe pas déjà. Ainsi si le programme est lancé 2 fois, la 2° instance détectant que le fichier existe déjà refuse de continuer.
 

tieuma a écrit :

Enfin je pensais réécrire le script Shell en C pour pouvoir utilisé la méthode classique de lancement de démons (référencement dans /etc/init.d)
 
3) Est-ce la meilleure solution ?


Rien n'interdit de mettre dans "/etc/rc.d/init.d" un script shell. Mais si t'as envie de l'écrire en C...
 

tieuma a écrit :

désolé j’apprends :)) ?


pas un pb. Le répertoire "/etc/rc.d/init.d" est conçu de façon bien précise. On lui place en "vrac" tous les scripts/programmes. Puis on va placer dans le répertoire "/etc/rc.d/rcN.d" ("N" étant le niveau de démarrage de la machine compris entre 0 et 6) un lien symbolique relié au script de "init.d". Cela permet
1) de relier le programme à plusieurs niveaux (on place un lien dans chaque "rcN.d" voulu)
2) malgré le fait que ce code puisse être appelé dans plusieurs niveaux, il n'y a qu'un seul source (si on veut le modifier par exemple)
 
Le nom du script est libre. En revanche, le nom du lien doit impérativement commencer par "S" ou "K". Au démarrage de la machine, le programme init balaye tous les "S" (comme "Start" ) de son niveau et les lance séquentiellement en y passant le mot "start". Et lors de l'arrêt, il exécute séquentiellement tous les "K" (comme "Kill" ) en y passant le paramètre "stop". A toi de faire en sorte que ton script/programme C prenne en compte ces 2 paramètres...
 
Et sinon, "nohup" signifie "nohang up" (pas de "main levée" ) et indique au shell de ne pas tuer le processus au cas où son père viendrait à mourir (comportement par défaut). Il est d'usage de l'associer au caractère "&" afin de pouvoir continuer à travailler pendant que le processus tourne.

Message cité 1 fois
Message édité par Sve@r le 11-10-2006 à 23:41:02

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 11-10-2006 à 23:52:21    

Sve@r a écrit :

Le nom du script est libre. En revanche, le nom du lien doit impérativement commencer par "S" ou "K". Au démarrage de la machine, le programme init balaye tous les "S" (comme "Start" ) de son niveau et les lance séquentiellement en y passant le mot "start". Et lors de l'arrêt, il exécute séquentiellement tous les "K" (comme "Kill" ) en y passant le paramètre "stop". A toi de faire en sorte que ton script/programme C prenne en compte ces 2 paramètres...


T'es sûr de ton coup :??:
 
il me semblait que ça marchait plutôt comme ça : à chaque état du système correspond un runlevel particulier (genre 2 pour le boot normal, 0 pour l'arrêt, etc.). Quand on entre dans un runlevel, le processus init exécute tous les scripts en K avec l'argument stop et les scripts en S avec l'argument start. Mais il me semble qu'on peut avoir des K lors du démarrage et vice-versa.


---------------
TriScale innov
Reply

Marsh Posté le 12-10-2006 à 00:35:48    

franceso a écrit :

T'es sûr de ton coup :??:
 
il me semblait que ça marchait plutôt comme ça : à chaque état du système correspond un runlevel particulier (genre 2 pour le boot normal, 0 pour l'arrêt, etc.). Quand on entre dans un runlevel, le processus init exécute tous les scripts en K avec l'argument stop et les scripts en S avec l'argument start. Mais il me semble qu'on peut avoir des K lors du démarrage et vice-versa.


 
Euh... c'est pas ce qu'on m'a appris... et j'ai jamais vérifié ta théorie.
Pour moi, les scripts "K" sont lancés quand on quitte un niveau. C'est un truc à voir...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 12-10-2006 à 04:17:12    

Le système d'init varie beaucoup d'une distrib à l'autre.

Reply

Marsh Posté le 12-10-2006 à 12:06:00    

Bonjour,
 
J'ai effectivement utilisé un script dans /etc/init.d pour lancer mon demon. Y a juste un dernier truc qui me chiffone, dans mon script de démarrage, dans la cas de l'argument stop, le code n'est pas exécuté jusqu'au bout, qd je tue mon processus, le script s'acheve (alors que je voulais mettre un petit "Arret du service truc" dans un fichier de log" ). C'est pas très grave mais ce n'est pas l'execution normale donc ca me travaille qd meme :).
 
Edit: j'en profite comme y a un peu de monde pour reposer uen question qui n'a rien à avoir...
 
Mon gnokii part carrément en vrille: en gros si j'écris un SMS de 160 caractères il mouline comme un âne (il recoit pas de ack du GSM). Bon je me dis c'est soit le cable, soit mon install de Gnokii soit le GSM. Maitnenant si j'écris un message composé uniquement de 160 fois le même caractère (2 a la limite ca passe aussi) le SMS est envoyé...
 
La limite pour un message composé de caractères différents semble etre autour de 77 caractères.
 
Bref ca me parait tres tres bizzare...

Message cité 1 fois
Message édité par tieuma le 12-10-2006 à 15:00:19
Reply

Marsh Posté le 12-10-2006 à 15:45:33    

tieuma a écrit :

Y a juste un dernier truc qui me chiffone, dans mon script de démarrage, dans la cas de l'argument stop, le code n'est pas exécuté jusqu'au bout, qd je tue mon processus, le script s'acheve (alors que je voulais mettre un petit "Arret du service truc" dans un fichier de log" )

Comment tu fais pour tuer ton processus ?  (c'est pas un pkill ou assimilé, quand même ?)


---------------
TriScale innov
Reply

Marsh Posté le 12-10-2006 à 16:18:07    

Je me suis inspiré du script présent ici : http://guide.andesi.org/html/kservices.html (section 3)


Message édité par tieuma le 12-10-2006 à 16:18:25
Reply

Marsh Posté le 12-10-2006 à 17:14:33    

ok, c'est bien ce qu'il me semblait : le processus est tué grâce à un killall (qui tue sauvagement tous les processus portant le même nom).
 
Je suppose que tu as donné à ton script de lancement le même nom que ton démon. Du coup, avec le killall, ton script de lancement se suicide en même temps qu'il tue le démon. (enfin, ce n'est qu'une hypothèse, mais il se pourrait bien que ce soit ça).
 
La méthode killall est un peu brutale. Tu ferais peut-être bien de stocker le pid de ton démon au démarrage (par exemple dans un fichier), et de tuer uniquement ce processus là avec ton script d'arrêt.


---------------
TriScale innov
Reply

Marsh Posté le 12-10-2006 à 17:47:31    

franceso a écrit :

Tu ferais peut-être bien de stocker le pid de ton démon au démarrage (par exemple dans un fichier), et de tuer uniquement ce processus là avec ton script d'arrêt.


D'ou l'interet de start-stop-daemon ou l'equivalent sur ta distrib, qui prend soin de tout ca.

Reply

Marsh Posté le 12-10-2006 à 17:55:55    

Non je me suis inspiré mais j'ai pas fait ca comme un bourrin :). Je recupère effectivement le PID de mon processus et je le tue ensuite. D'où mon étonnement de voir mon script mourir  :heink:

Reply

Marsh Posté le 12-10-2006 à 18:10:01    

tieuma a écrit :

Non je me suis inspiré mais j'ai pas fait ca comme un bourrin :). Je recupère effectivement le PID de mon processus et je le tue ensuite. D'où mon étonnement de voir mon script mourir  :heink:


tu peux poster ton script ? Comme ça on évitera les suppositions ;)
 
EDIT: c'est quoi ta distrib ? Comme dit matafan, si tu disposes de start-stop-daemon il vaut mieux l'utiliser.


Message édité par franceso le 12-10-2006 à 18:10:42

---------------
TriScale innov
Reply

Marsh Posté le 13-10-2006 à 10:09:38    

Code :
  1. # actions pour arreter le service
  2.     stop)
  3.         echo `date` >> $LOG
  4.         echo "Arret du service : $DESC ($NAME)" >> $LOG
  5.         # test si le processus est actif
  6.         if [ -z "$(ps ax | grep sh | grep smsgateway)" ]
  7.         then
  8.                 echo "smsgateway n'est pas actif" >> $LOG
  9.         else
  10.                 PID=`ps ax | grep sh | grep smsgateway | awk '{print $1}'`
  11.                 killall -9 gnokii 2>> $LOG
  12.                 kill $PID 2>> $LOG
  13.         fi
  14.         echo "."
  15.         ;;


 
Je fais un double grep car effectivement j'ai appelé mon script de demarrage du meme nom que mon script "demon". La distrib c'est une Suse 10.0, start-stop-daemon est installé, j'avais essayé de l'utiliser mais un truc ne m'avait pas plu :P

Message cité 1 fois
Message édité par tieuma le 13-10-2006 à 10:16:26
Reply

Marsh Posté le 13-10-2006 à 15:24:20    

tieuma a écrit :

Code :
  1. # actions pour arreter le service
  2.     stop)
  3.         echo `date` >> $LOG
  4.         echo "Arret du service : $DESC ($NAME)" >> $LOG
  5.         # test si le processus est actif
  6.         if [ -z "$(ps ax | grep sh | grep smsgateway)" ]
  7.         then
  8.                 echo "smsgateway n'est pas actif" >> $LOG
  9.         else
  10.                 PID=`ps ax | grep sh | grep smsgateway | awk '{print $1}'`
  11.                 killall -9 gnokii 2>> $LOG
  12.                 kill $PID 2>> $LOG
  13.         fi
  14.         echo "."
  15.         ;;



Bon, déjà "echo `date`" se remplace avantageusement par "date". Il en va de même pour toute autre commande mise en sous-exécution de la commande "echo"...
Ensuite, je connais pas "killall" mais si l'argument "-9" a la même signification que pour kill, pourquoi utiliser le signal 9 (fait pour les cas extrèmes) ?
killall -15 devrait être plus propre puisque le signal "15" demande au processus de se terminer => le processus finit ce qu'il faisait, ferme les fichiers, finalise les écritures en attente et se termine...
 

tieuma a écrit :

La distrib c'est une Suse 10.0, start-stop-daemon est installé, j'avais essayé de l'utiliser mais un truc ne m'avait pas plu :P


Oui, la Suse est assez économique car elle ne s'use que quand on s'en sert :lol:

Message cité 1 fois
Message édité par Sve@r le 13-10-2006 à 15:24:59

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 13-10-2006 à 16:16:25    

t'as vérifié que ton double grep te donnait bien le bon pid ?


---------------
TriScale innov
Reply

Marsh Posté le 13-10-2006 à 16:34:47    

Sve@r a écrit :

Bon, déjà "echo `date`" se remplace avantageusement par "date". Il en va de même pour toute autre commande mise en sous-exécution de la commande "echo"...
Ensuite, je connais pas "killall" mais si l'argument "-9" a la même signification que pour kill, pourquoi utiliser le signal 9 (fait pour les cas extrèmes) ?
killall -15 devrait être plus propre puisque le signal "15" demande au processus de se terminer => le processus finit ce qu'il faisait, ferme les fichiers, finalise les écritures en attente et se termine...
 
 
Oui, la Suse est assez économique car elle ne s'use que quand on s'en sert :lol:


 
Pas con pour le "echo" :P
 
Sinon le killall est pas nécessaire de ttes manieres, j'ai qu'un gnokii lancé à la fois. Et même qd j'en ai pas, mon script se fait dégager qd meme.
 
Sinon pour la Suse, j'ai pas choisi :). J'aurai pas pris ca mais je suis pas assez savant en linux pour bien voir la différence avec d'autres distrib (enfin je sais qd même que je préfere apt au gestionnaire de package de Suse :P).
 
@ francesco: oui j'avais vérifié en lançant la commande "à la mano"
 

Code :
  1. bigbrother:/opt/smsgateway # ps ax | grep smsgateway
  2. 30245 ?        S      0:00 /sbin/sh /opt/smsgateway/smsgateway
  3. 30247 ?        Ss     0:00 startpar -f -- smsgateway
  4. 9464 pts/3    R+     0:00 grep smsgateway
  5. bigbrother:/opt/smsgateway # ps ax | grep sh | grep smsgateway
  6. 30245 ?        S      0:00 /sbin/sh /opt/smsgateway/smsgateway


 
le PID de mon service est < à celui du script de démarrage, la mort de mon procsessus "service" semble entrainer la mort de mon script...

Message cité 1 fois
Message édité par tieuma le 13-10-2006 à 16:42:58
Reply

Marsh Posté le 13-10-2006 à 16:54:29    

tieuma a écrit :

le PID de mon service est < à celui du script de démarrage


C'est ça qui m'étonne le plus... En même temps, c'est peut-être du à la méthode de fonctionnement de startpar (que je ne connaissais pas)
 
As-tu vérifié avec un pstree (ou autre truc du genre) s'il y a filiation entre ton service et ton script de démarrage (et si oui, dans quel sens) ?
 


---------------
TriScale innov
Reply

Marsh Posté le 13-10-2006 à 17:22:08    

franceso a écrit :

C'est ça qui m'étonne le plus... En même temps, c'est peut-être du à la méthode de fonctionnement de startpar (que je ne connaissais pas)
 
As-tu vérifié avec un pstree (ou autre truc du genre) s'il y a filiation entre ton service et ton script de démarrage (et si oui, dans quel sens) ?


 
Voila le pstree:
 
     |-sh---sleep
     |-smbd---2*[smbd]
     |-sshd-+-2*[sshd---bash]
     |      `-sshd---bash---pstree
     |-startpar
     |-syslog-ng
     `-udevd
 
-sh--sleep c'est mon service
 
Donc pas de lien a priori.


Message édité par tieuma le 13-10-2006 à 17:22:52
Reply

Marsh Posté le 13-10-2006 à 20:34:27    

OK, dans ce cas je vois vraiment pas ce qui pourrait tuer ton script d'init lorsque le démon meurt. :??: Désolé...


---------------
TriScale innov
Reply

Marsh Posté le 16-10-2006 à 15:41:35    

Pas très grave, ce qui m'embête plus c'est mon appli GSM pas foutue d'envoyer des SMS de 160 caractères  :(  
 
 (forum.hardware.fr/hardwarefr/O [...] 0018-1.htm)


Message édité par tieuma le 08-11-2006 à 17:35:09
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed