c59f674a84e1bea6f2d2bfd77d70f13e8d087f08
7 use POSIX
qw(setsid setuid setgid
);
8 use POSIX
":sys_wait_h";
22 #For each process, uid and gid to set after fork
27 #Number of launch, for each daemon
29 my %ratio_launch_prio;
37 &debug_msg
("got SIGHUP\n");
42 #Read Configuration and init global vars
45 my $config = new Config
::General
( -file
=>"$file",
46 -AllowMultiOptions
=>"yes",
47 -LowerCaseNames
=>"yes",);
48 %conf = $config->getall;
49 &debug_msg
(Dumper
(\
%conf));
55 print STDERR
$text unless ($debug == 0);
65 $confile="$path/muxdaemon.conf";
67 print STDERR
"Error : unable to get working directory, $!\n";
73 if ( not getopts
('dhf:', \
%opts) or $opts{'h'}) {
74 print STDERR
"\nThis is mail processing Daemon :\n",
75 "-h - this help message\n",
76 "-f <file> - use <file> as config file\n",
82 if (-r
"$opts{'f'}") {
83 print STDERR
"Using $opts{'f'} as config file\n";
84 &read_conf
("$opts{'f'}");
86 print STDERR
"$opts{'f'} : not a valid config file\n";
90 print STDERR
"Using $confile as config file\n";
92 &read_conf
("$confile");
94 print STDERR
"No valid configuration file found, aborting\n";
100 print STDERR
"Running in debug mode ...\n";
107 #init useful variables for scheduler
109 foreach my $arg (keys %{$conf{'client'}}){
111 $ratio_launch_prio{$arg} = 0;
112 $last_schedule{$arg} = 0;
116 #check configuration file
118 &debug_msg
("Salut\n");
119 print STDERR
"Checking configuration file for wrong user/groups, schedules, ....\n";
120 foreach my $arg (keys %{$conf{'client'}}){
121 #La conf du client courant
122 my %hash = %{$conf{'client'}{$arg}};
123 if ($hash{'run_as_user'}) {
124 my $id = getpwnam($hash{'run_as_user'});
126 $conf{'client'}{$arg}{'uid'} = $id;
128 print STDERR
" Error, user $hash{'run_as_user'} does not exist, please check...\n";
132 if ($hash{'run_as_group'}){
133 my $id = getgrnam("$hash{'run_as_group'}");
135 $conf{'client'}{$arg}{'gid'} = $id;
137 print STDERR
" Error, group $hash{'run_as_group'} does not exist, please check...\n";
141 if ($hash{'allow_many'} eq "yes" and $hash{'min_schedule'}){
142 print STDERR
" Error, allow_many and min_schedule defined for $arg\n";
149 #make the program run in daemon mode
151 print STDERR
"Forking ... \n";
152 chdir '/' or die "Can't chdir to /: $!";
153 open STDIN, '/dev/null
' or die "Can't
read /dev/null
: $!";
154 open STDOUT, '>>/dev/null' or die "Can
't write to /dev/null: $!";
155 if ($conf{'error_log
'}){
156 open STDERR, ">>$conf{'error_log
'}" or die "Can't
write to
$conf{'error_log'}: $!";
158 open STDERR, '>>/dev/null' or die "Can
't write to /dev/null: $!";
160 defined(my $pid = fork) or die "Can't
fork: $!";
162 setsid or die "Can
't start a new session: $!";
164 &debug_msg("Daemon started\n");
168 #returns current load or any good value
171 if (open(LOAD, '</proc/loadavg
')) {
173 ($load) = ($line =~ m/(\d+\.\d+)/);
179 #Return the list of client for which max_load is => ld
181 sub get_possible_client(#){
185 foreach my $arg (keys %{$conf{'client
'}}){
186 my %hash = %{$conf{'client
'}{$arg}};
187 if ($hash{'max_load
'} >= $ld){
195 #Return the client that should be executed according to priorities
197 # Refaire avec calcul du min de launches/prio !
200 my @possible_client = @{$ref};
201 #List des proc executes assez souvent
205 foreach my $arg (@possible_client) {
206 if ($ratio_launch_prio{$arg} < $min_ratio or $min_ratio == -1){
207 $min_ratio=$ratio_launch_prio{$arg};
213 #Update ratio for him
214 $launches{$client}++;
215 $ratio_launch_prio{$client}=$launches{$client}/$conf{'client
'}{$client}{'priority
'};
218 &debug_msg("No client runnable in get_next\n");
224 #Elimine les clients présent dans la liste qui sont en cours d'éxécution et
225 #qui n'ont pas le allow_many (pour pas les éxécuter deux fois)
226 #Elimine aussi les clients qui ont terminé depuis moins que min_schedule
227 sub trim_possible_client
(#){
232 foreach my $arg (@
$ref){
233 if (${${$conf{'client'}}{$arg}}{'allow_many'} eq "no"){
235 if ((time - $last_schedule{$arg}) >= ${${$conf{'client'}}{$arg}}{'min_schedule'}){
236 push(@out_list,$arg) unless grep($_ eq $arg, values %running);
239 push(@out_list,$arg);
247 sub change_uid_gid
(#){
249 if ($conf{'client'}{$client}{'gid'}){
250 &debug_msg
("Changing gid to $conf{'client'}{$client}{'gid'} for $client ...");
251 # $( = $conf{'client'}{$client}{'gid'};
252 # $) = $conf{'client'}{$client}{'gid'};
253 if (POSIX
::setgid
($conf{'client'}{$client}{'gid'})){
254 &debug_msg
("done\n");
256 &debug_msg
("error, $!\n");
260 if ($conf{'client'}{$client}{'uid'}){
261 &debug_msg
("Changing uid to $conf{'client'}{$client}{'uid'} for $client ...");
262 # $< = $conf{'client'}{$client}{'uid'};
263 # $> = $conf{'client'}{$client}{'uid'};
264 if (POSIX
::setuid
($conf{'client'}{$client}{'uid'})){
265 &debug_msg
("done\n");
267 &debug_msg
("error, $!\n");
274 #Sends mail on the input of the command (pipe)
276 # TODO check that the child has properly finished before moving
280 &debug_msg
("run $conf{'client'}{$client}{'command'} with file $fich for $client\n");
283 die "cannot fork $!";
284 } elsif ($pid == 0) {
286 if (open(STDIN
, '<', $fich)) {
287 &change_uid_gid
($client);
288 &debug_msg
("sending output to $conf{'client'}{$client}{'command'} with file $fich for $client $fich openned\n");
289 exec $conf{'client'}{$client}{'command'} or die "exec error $!";
291 die "Error opening $fich : $!\n";
296 &debug_msg
("sending output to $conf{'client'}{$client}{'command'} with file $fich for $client done\n");
297 # return true if the program exited normaly
298 return ($?
>> 8) == 0;
304 my %hash = %{$conf{'client'}{$client}};
305 if ($hash{'mbox'} =~ /\/$/) { #ok, maildir format
308 my $path = $hash{'mbox'};
309 $path =~ s/\/$//igo; # suppress the final /
310 &debug_msg
("Sending datas for $hash{'mbox'}\n");
312 if (opendir MAILDIR
, "$path/new") {
313 my $nb_left = $hash{'nb_mails'};
314 while (my $fich = readdir MAILDIR
) {
316 next if ($fich eq "." or $fich eq "..");
317 # read the dir until the max number of mail is done
318 &debug_msg
("nb_left : $nb_left\n");
319 last if ($nb_left-- == 0);
320 &debug_msg
("File : $fich\n");
321 # if add_to_cmdline is true, add to the list
322 if ($hash{'add_to_cmdline'}) {
325 # else run the command for each file
326 if (&send_data
($client, "$path/new/$fich")) {
330 &debug_msg
("Done file : $fich, $?\n");
334 print STDERR
"Error opening $path/new : $!\n";
336 # if add_to_cmdline is true and there are files to treat,
338 if ($hash{'add_to_cmdline'} and scalar @args > 0) {
339 chdir "$path/new" or die "Cannot chdir to $path/new : $!";
340 &debug_msg
("run $hash{'command'} with files @args for $client\n");
341 my @cmd = split(/ /, $hash{'command'});
343 &debug_msg
("@cmd\n");
346 die "cannot fork $!";
347 } elsif ($pid == 0) {
349 &change_uid_gid
($client);
350 exec @cmd or die "exec error $!";
354 my $status = $?
>> 8;
356 # if the command didn't fail, mark the files to be moved
361 # if there is files to move, moves them
362 foreach my $fich (@tomove) {
363 &debug_msg
("$path/new/$fich -> $path/cur/$fich ... ");
364 if (rename("$path/new/$fich", "$path/cur/$fich")){
367 print STDERR
"Error moving $path/new/$fich, keeped : $!\n";
371 &debug_msg
("Mbox format not yet supported.\n");
380 &change_uid_gid
($client);
381 #Launch the command of a simple client
382 &debug_msg
("Son $client, launching $conf{'client'}{$client}{'command'}\n");
383 exec($conf{'client'}{$client}{'command'});
394 if ($reload_conf == 1){
395 #We have to load conf again
397 &debug_msg
("Reloading configuration .... \n");
398 &debug_msg
(" Waiting all child to terminate ...");
399 while ((my $kid=wait) != -1){
401 delete($running{$kid});
403 &debug_msg
("done\n");
404 &debug_msg
(" Restarting ...");
407 &debug_msg
("done\n");
411 if ($nchild >= $conf{'max_client'}){
412 #We have to wait for one child (Blocking)"
413 &debug_msg
("Waiting for childs to terminate\n");
416 &debug_msg
("Kid=$kid est mort, c'était un $running{$kid}\n");
418 delete($running{$kid});
421 #Rip child terminated
422 &debug_msg
("Checking dead childs....\n");
423 while ( (my $kid = waitpid(-1, WNOHANG
)) > 0 ){
424 &debug_msg
("Kid=$kid est mort, c'était un $running{$kid}\n");
426 delete($running{$kid});
429 #Look for a client to execute
431 &debug_msg
("Load = $ld, processing\n");
432 my $possible_client = &get_possible_client
($ld);
433 my @list = @
{$possible_client};
434 &debug_msg
("Avant Trim : \n");
435 &debug_msg
(Dumper
($possible_client));
436 $possible_client = &trim_possible_client
($possible_client);
437 &debug_msg
("Après Trim : \n");
438 &debug_msg
(Dumper
($possible_client));
439 my $client = &get_next
($possible_client);
441 &debug_msg
("$client was chosen, launching\n");
442 $last_schedule{$client} = time ;
445 print STDERR
"cannot fork: $!\n";
446 } elsif ($pid != 0) {
447 #Pere, on marque qu'on l'a lancé
448 $running{$pid} = $client;
450 &debug_msg
("$client launched as PID $pid\n");
451 &debug_msg
(Dumper
(\
%running));
452 &debug_msg
(Dumper
(\
%launches));
455 if ($conf{'client'}{$client}{'mbox'}) {
456 #We have to send data ourselves
457 &list_files
($client);
459 #We only have to execute a command
465 &debug_msg
("No client runable\n");
466 sleep($conf{'sleep_poll'});
468 sleep($conf{'active_poll'});
479 $SIG{HUP
}=\
&sigHUP_handler
;