Sous Linux, j'ai developpé un programme qui en gère plusieurs autres en
se forkant.
Voilà le principe:
Dans une table de hachage, se trouvent toutes les commandes à lancer.
Pour chaque commande à lancer:
il se forke, récupère le PID du fil, puis passe au suivant, etc...
Le fils va alors lancer la commande grâce à exec, de manière à ne pas
ouvrir de shell supplémentaires, et permettre au père de conserver le
PID comme étant celui de la commande à gérer.
Chaque commande est lancée, gràce à exec, avec une redirection de STDOUT
et STDERR vers un fichier de log.
Et c'est là ou le bas blesse....
En réalité, je récupère toutes les sorties standard sur le programme
père, se qui génère, vous vous en doutez bien, un flux d'informations
colossal.
Je n'ai pas la maitrise des programmes lancés, je ne peux pas les faire
"imprimer" dans un log autrement qu'en redirigeant la sortie standard.
Y aurait-il un moyen ?
Voici mon script:
#========================================================================
#!/usr/bin/perl -w
use strict;
use warnings;
use Config;
use POSIX ":sys_wait_h";
$0="MASTER";
defined $Config{sig_name} || die "No sigs?";
my $i=0;
my @signame=();
foreach (split(' ', $Config{sig_name})) {
$signame[$i] = $_;
$i++;
}
my %cmd=(
"PROC0" => "perl programme.pl fichier1 > fichier1.log 2>&1",
"PROC1" => "perl programme.pl fichier2 > fichier2.log 2>&1",
"PROC2" => "perl programme.pl fichier3 > fichier3.log 2>&1",
"PROC3" => "perl programme.pl fichier4 > fichier4.log 2>&1"
);
my @pid=();
my $cloture=0;
my %Kid=();
my %Dik=();
my %tosend = %cmd;
while(1) {
foreach my $process (sort keys %tosend){
my $pid = fork();
unless (defined($pid)){
&logmsg(__LINE__,"Fork impossible - $! \n");
exit 1;
}
if ($pid == 0){
delete $tosend{$process};
$0="PROC_$process";
print "FILS --> $process : Lancement commande
$cmd{$process} ....\n";
exec split/\s+/, $cmd{$process} ;
exit;
}
else {
delete $tosend{$process};
$0="MASTER";
print "PERE: Nouveau Fils: PID N°$pid\n";
$Dik{$pid} = $process;
$Kid{$process}=$pid;
}
sleep 3;
}
sleep 3;
last unless (keys %Kid); # s'il n'y a plus de fils à gérer, Bye
}
print "Terminé\n";
exit;
sub REAPER {
my $child;
my $numsignal;
while (($child = waitpid(-1,WNOHANG)) > 0) {
print "REAPER: child=$child \[$Dik{$child}\] renvoi $?\n";
$numsignal = $? & 127;
print "REAPER: child=$child \[$Dik{$child}\] recv signal
signame[$numsignal]($numsignal)\n";
unless ($cloture){
if ($numsignal > 1){ # Voir les n° en gestion ==> à une cloture
print "Programme relancement de $Dik{$child} ...\n";
$tosend{$Dik{$child}} = $cmd{$Dik{$child}};
}
}
}
$SIG{CHLD} = \&REAPER; # still loathe sysV
}
$SIG{CHLD} = \&REAPER;
$SIG{INT} = sub { &KILL_ALL("INT")};
$SIG{HUP} = sub { &KILL_ALL("HUP")};
$SIG{ABRT} = sub { &KILL_ALL("ABRT")};
$SIG{TERM} = sub { &KILL_ALL("TERM")};
$SIG{QUIT} = sub { &KILL_ALL("QUIT")};
sub KILL_ALL {
print "PERE RECU ".$_[0]."\n";
print "Killing all son\n";
$cloture=1; # permet d'empêcher le relancement
foreach (sort {$b cmp $a} keys %Kid){
print "Sending TERM(15) to $_ => pid n° $Kid{$_}\n";
kill 15, $Kid{$_};
}
exit 0;
}
#========================================================================
Cela me permet d'avoir ceci (gràce à la commande ps axf):
Tu ne peux pas faire une redirection avec exec : là, tu es en train d'appeler le script programme.pl (soit dit en passant, l'extension recommandée est .plx) avec comme arguments fichier1, >, fichier1.log et 2>&1. Les redirections à base de > sont interprétées par un shell ; si tu veux te passer de shell, ce qui est une bonne idée, il faut les faire toi-même, avec un open sur STDOUT.
Sébastien Cottalorda wrote in message
<44f6e9ea$0$31459$626a54ce@news.free.fr>:
Tu ne peux pas faire une redirection avec exec : là, tu es en train
d'appeler le script programme.pl (soit dit en passant, l'extension
recommandée est .plx) avec comme arguments fichier1, >, fichier1.log et
2>&1. Les redirections à base de > sont interprétées par un shell ; si tu
veux te passer de shell, ce qui est une bonne idée, il faut les faire
toi-même, avec un open sur STDOUT.
Tu ne peux pas faire une redirection avec exec : là, tu es en train d'appeler le script programme.pl (soit dit en passant, l'extension recommandée est .plx) avec comme arguments fichier1, >, fichier1.log et 2>&1. Les redirections à base de > sont interprétées par un shell ; si tu veux te passer de shell, ce qui est une bonne idée, il faut les faire toi-même, avec un open sur STDOUT.
Sébastien Cottalorda
Sébastien Cottalorda wrote in message <44f6e9ea$0$31459$:
Tu ne peux pas faire une redirection avec exec : là, tu es en train d'appeler le script programme.pl (soit dit en passant, l'extension recommandée est .plx) avec comme arguments fichier1, >, fichier1.log et 2>&1. ça marche quand même comme cela, mais ce n'est pas là mon problème.
Les redirections à base de > sont interprétées par un shell ; si tu veux te passer de shell, ce qui est une bonne idée, il faut les faire toi-même, avec un open sur STDOUT.
dans mon exemple, cela se traduira par quoi ? Je n'ai pas très bien compris, ai-je un moyen "externe", en gros, à partir du programme que j'ai envoyé, d'intercepter, chaqua flux STDOUT ?
j'ai eu beau remplacer l'exec par un:
unless (open (FH, "$cmd |")){ die "Problemen"; } while ($my $ligne=<FH>){ print "Intercepté>> $lignen"; } close(FH);
j'ai même essayé avec un open2, mais je n'ai rien de rien.....
mais cela ne marche pas non plus. En fait cela crée un fils au fils, ce qui n'est pas ce que je recherche.
Sébastien Cottalorda wrote in message
<44f6e9ea$0$31459$626a54ce@news.free.fr>:
Tu ne peux pas faire une redirection avec exec : là, tu es en train
d'appeler le script programme.pl (soit dit en passant, l'extension
recommandée est .plx) avec comme arguments fichier1, >, fichier1.log et
2>&1.
ça marche quand même comme cela, mais ce n'est pas là mon problème.
Les redirections à base de > sont interprétées par un shell ; si tu
veux te passer de shell, ce qui est une bonne idée, il faut les faire
toi-même, avec un open sur STDOUT.
dans mon exemple, cela se traduira par quoi ?
Je n'ai pas très bien compris, ai-je un moyen "externe", en gros, à
partir du programme que j'ai envoyé, d'intercepter, chaqua flux STDOUT ?
j'ai eu beau remplacer l'exec par un:
unless (open (FH, "$cmd |")){
die "Problemen";
}
while ($my $ligne=<FH>){
print "Intercepté>> $lignen";
}
close(FH);
j'ai même essayé avec un open2, mais je n'ai rien de rien.....
mais cela ne marche pas non plus.
En fait cela crée un fils au fils, ce qui n'est pas ce que je recherche.
Tu ne peux pas faire une redirection avec exec : là, tu es en train d'appeler le script programme.pl (soit dit en passant, l'extension recommandée est .plx) avec comme arguments fichier1, >, fichier1.log et 2>&1. ça marche quand même comme cela, mais ce n'est pas là mon problème.
Les redirections à base de > sont interprétées par un shell ; si tu veux te passer de shell, ce qui est une bonne idée, il faut les faire toi-même, avec un open sur STDOUT.
dans mon exemple, cela se traduira par quoi ? Je n'ai pas très bien compris, ai-je un moyen "externe", en gros, à partir du programme que j'ai envoyé, d'intercepter, chaqua flux STDOUT ?
j'ai eu beau remplacer l'exec par un:
unless (open (FH, "$cmd |")){ die "Problemen"; } while ($my $ligne=<FH>){ print "Intercepté>> $lignen"; } close(FH);
j'ai même essayé avec un open2, mais je n'ai rien de rien.....
mais cela ne marche pas non plus. En fait cela crée un fils au fils, ce qui n'est pas ce que je recherche.
Nicolas George
Sébastien Cottalorda wrote in message <44f7d3fc$0$31419$:
ça marche quand même comme cela, mais ce n'est pas là mon problème.
Probablement que les programmes lancés ignorent leurs arguments supplémentaires.
dans mon exemple, cela se traduira par quoi ?
Il faut reprendre un peu la structure du programme, parce que les structures de données ne sont pas bien adaptées.
Je n'ai pas très bien compris, ai-je un moyen "externe", en gros, à partir du programme que j'ai envoyé, d'intercepter, chaqua flux STDOUT ?
Il ne faut pas faire :
exec "foo", "bar", ">", "baz", "2>&1";
(c'est ce qu'il y a dans ton programme, déguisé par un split) mais :
open STDOUT, ">", "bar"; open STDERR, ">&STDOUT"; exec "foo", "bar";
Avec bien sûr tous les tests d'erreur qui s'imposent.
Sébastien Cottalorda wrote in message
<44f7d3fc$0$31419$626a54ce@news.free.fr>:
ça marche quand même comme cela, mais ce n'est pas là mon problème.
Probablement que les programmes lancés ignorent leurs arguments
supplémentaires.
dans mon exemple, cela se traduira par quoi ?
Il faut reprendre un peu la structure du programme, parce que les structures
de données ne sont pas bien adaptées.
Je n'ai pas très bien compris, ai-je un moyen "externe", en gros, à
partir du programme que j'ai envoyé, d'intercepter, chaqua flux STDOUT ?
Il ne faut pas faire :
exec "foo", "bar", ">", "baz", "2>&1";
(c'est ce qu'il y a dans ton programme, déguisé par un split) mais :
open STDOUT, ">", "bar";
open STDERR, ">&STDOUT";
exec "foo", "bar";
Avec bien sûr tous les tests d'erreur qui s'imposent.