Bonjour,
Je fais suite à un topic sur le forum Linux ( https://www.jeuxvideo.com/forums/1-38-7705220-1-0-1-0-relancement-automatique-service.htm )
Je cherche à coder un programme en C qui permette de lancer un service, et qui soit en charge de relancer ce même service en cas de plantage par seg fault.
Sur le précédent topic, on m'a conseillé d'utiliser wait() pour gérer ca.
Pour l'instant j'ai ca :
void main(void)
{
int sts;
int val;
sts=fork();
if (sts == 0) {
val = execve("/usr/sbin/myService",NULL,NULL);
printf("value returned : %d\n",val);
}
wait(&sts);
printf("IOP\n");
}
d'après le man :
"execve() does not return on success, and the text, data, bss, and stack of the calling process are overwritten by that of the program loaded.
"
Du coup si cela ne retourne rien, cela veut dire que c'est bloquant ? C'est ce que je croyais, mais en fait non apparemment.
du coup dans mon programme (enfin, le début...) , le service est bien lancé, mais le programme se termine sans que je puisse monitorer le service, ce qui est gênant.
Je ne comprends pas sur quoi doit porter une boucle dans le main...
Merci
exec ce n'est pas comme ca que ca marche.
quand tu fais exec, le system desalloue toute la memoire, decharge le code du programme, charge le code du programme que tu veux lancer et appel main().
exec REMPLACE le processus courant par le programme que tu cherche a lancer. Donc l'appel a exec ne retourne jamais. SAUF si l'appel a exec echoue.
ah, c'est effectivement la partie du man que je n'étais pas sur d'avoir compris
Je suis obligé d'utiliser exec n'est-ce pas ? Ou y-a-t-il une alternative ![]()
il faut utiliser exec
typiquement ce que tu fais est:
begin:
fork()
if (jesuislefils)
{
exec(...)
}
else
{
//je suis le pere
if (!systemshutdown)
goto begin;
}
ok je vois.
Mais, comment est-ce que je peux traiter cette condition : "if (!systemshutdown) " ![]()
Si je récupère le pid du service, je peux utiliser un waitpid à la limite , non ![]()
Par contre, cela demande de récupérer le pid du service, ce que je ne peux faire qu'après le lancement du service donc après le "exec". Or je perds la main une fois que le exec est exécuté....
ce que je veux dire par systemshutdown, c'est que tu peux vouloir explicitement ne pas relance le programme.
c'est pour ca que tu fork avant. C'est le pere qui fait ca. pas le fils.
ah oui effectivement, j'avais mal interprété...
Mais après le exec, je perds le fils (dans le sens je ne maîtrise plus son exécution) non ?
Donc c'est bel et bien dans le père que je dois gérer le relancement non ?
et le seul moyen serait avec un waitpid ?
apres exec, le fils devient le service que tu cherches a relancer.
Tu peux utiliser waitpid pour savoir quand le service se termine.
Tu dois meme pouvoir obtenir le code de retour du service et determiner si il s'est terminer parceque c'est fini ou parcequ'il a crasher.
Voila ce que j'ai fait : http://pastebin.com/giBGSaTB
Il se trouve que j'ai un problème avec waitpid, car il ne bloque pas dans mon programme (il semble que waitpid retourne tout de suite quelquechose alors que mon service tourne avec le pid que j'ai récupéré avant.)
Voici la sortie du programme ci après.
Ca boucle alors que cela ne devrait pas il me semble...et donc évidemment quand le exec se lance une deuxième fois, cela renvoit une erreur.
$ sudo ./mergesort
PID:12139 IOPIOP
myService already running on /var/run/myService/myService.ctl.
PID:12139 IOPIOP
myService already running on /var/run/myService/myService.ctl.
PID:12139 IOPIOP
myService already running on /var/run/myService/myService.ctl.
PID:12139 IOPIOP
myService already running on /var/run/myService/myService.ctl.
C'est quoi ce service si c'est pas indiscret ?
Puet etre que le programme que tu lance n'est en fait qu'un wrapper qui lance le vrai process. Du coup, tu detecte la mort du wrapper...
Dans ce cas, tu peuyx vouloir attendre de ne plus avoir de fils du tout. regarde le code de retour de wait et le errno ECHILD dans le manuel.
c'est pas indiscret, il s'agit d'asteriks.
Le code de retour de wait est -1 ce qui est plutot mauvais signe^^
PID:21677
PID:21677 - ECHILD:10 - i:-1
le ps donne ca à des moments différents pendant que la boucle tourne : http://pastebin.com/RywqHLUx
Du coup ![]()
ton appel à waitpid ne vas pas du tout. le premier argument doit être le pid du processus à attendre (donc ta variable sts et non pas une variable pid que tu initialise à 0) puis le second argument est une variable qui recevra le statut du processus lorsqu'il va être mort.
Par ailleurs, je n'arrive pas à le retrouver mais je crois qu'il existe un utilitaire système assez standard pour faire ce genre de chose que tu pourrais vouloir utiliser.
dnob, je ne connais que start-stop-daemon. et ca ne relance pas automatiquement sur un crash.
Cependant, maintenant que tu le mentionnes, ca m'etonne que ca n'existe pas.
dnob
pid est modifié dans le scanf deux lignes au dessus de waitpid.
Si vous avez le nom d'un tel utilitaire, je prends bien sur, mais j'aimerai également savoir pourquoi cela ne fonctionne pas dans mon programme...
on peut utiliser des goto en C ? :D
bien sur qu'on peut utiliser des goto en C... C'est assez utile pour la gestion d'erreur d'ailleurs. Bien que dans ce cas la, une boucle est plus approprie.
on m'a toujours dit qu'utiliser un goto était une espèce d'abomination en C, je ne sais pas trop pourquoi, je trouve ca assez propre dans certains cas, mais du coup je ne les utilise pas. Cela dit, j'ai pas fait beaucoup de C.
Bon, je ne comprends toujours pas.
Je lance mon programme
- il lance le service
- le waitpid retourne une erreur
- ca boucle avec 2 erreurs : lancement du service impossible (normal car il a déjà été lancé une fois) + erreur du waitpid.
Si je laisse tourner ce programme, en parallèle je peux me connecter à la console du service, qui fonctionne. Si je fais un kill -9 sur le pid indiqué par mon programme, ca tue bien mon service.... Donc je ne comprends rien ![]()
si waitpid renvoie une erreur (i.e. -1) regarde quelle est l'erreur. la variable errno (qui est défini dans errno.h) prend une certaines valeur que tu peux passer aux fonction strerror et Cie pour avoir un message d'erreur explicatif sur ton problème. Regardes le et si ça ne te suffit pas, donne le nous, ça nous aidera à comprendre ce qui ne vas pas.
Celà dit, dans le processus père, fork renvoie le pid du processus fils. Est-ce qu'il correspond avec le pid que tu récupère par ton fscanf (que, honnêtement, je ne comprend pas).
parce que, avec waitpid, je ne suis pas sûr du tout que tu as le droit d'attendre un processus dont tu n'es pas le père, y compris si son père à lui est mort entre temps (pareil avec wait, contrairement à ce qu'a écrit godrik plus haut, si je ne me trompe pas trop).
dans ma memoire de mes cours de systeme. Il me semble que quand le pere d'un processus meurt, , le grand pere devient le pere. Mais ca pourrait ne pas etre standard, ou etre completemenet faux.