Home

Escrito por Helio Loureiro
Acessos: 7712

No sistema de agendamento de tarefas, o cron, existe a possibilidade de controle de acesso pelos arquivos /etc/cron.allow/etc/cron.deny.  Existindo somente o /etc/cron.allow no sistema, o usuário deverá ter seu login incluso nesse arquivo para fazer uso do cron.  Do contrário será brindando com uma mensagem semelhante a essa:

You (helio) are not allowed to use this program (crontab)
See crontab(1) for more information

Nos ambientes de telecomunicações, onde muitos dos sistemas operacionais em uso são Solaris, ex-Sun e agora da Oracle, esses vêm com essa forma de controle do cron habilitada por padrão.

Isso aumenta a segurança do sistema, mas também torna alguns trabalhos simples mais difíceis, principalmente quando é necessário ter agendamento de trabalho.  Claro que isso poderia ser resolvido com ajuda de um bom administrador de sistemas, o sysadmin, e conhecimento em Unix, mas isso parece estar se tornando cada vez mais raro nesses dias.

Então criei o mycrond, um daemon escrito em perl, para rodar periodicamente como o crond do sistema.  A sintaxe não é perfeita e tem alguns furos, como não aceitar "*/5" para tarefas a cada 5 intervalos, mas utiliza uma sintaxe que somente Solaris aceita como, por exemplo para tarefas agendadas para cada 5 minutos, utilizar "0,5,10,15,20,25,30,35,40,45,50,55".  O restante é parecido com o uso normal da crontab.

Não é 100% perfeito, pois acabei deixando a análise de sintaxe incompleta para todos os valores de data, mas funciona perfeitamente como daemon, não morrendo ao sair do sistema, e é capaz de analisar e rodar formas mais simples da crontab.



O conteúdo do programa é o seguinte:

#! /usr/bin/perl
# $Id: mycrond 29 2011-06-22 20:42:35Z helio $
# Date: Wed Jun 22 12:37:00 BRT 2011
# Author: Helio Loureiro
# Description: an user level alternative to system crond.
#

 
my $ROOTDIR = "/home/helio/AUDIT";
 
exit(0); # Edit $ROOTDIR settings and comment this exit.

my $CRONFILE = $ROOTDIR."/etc/crontab";
my $PIDFILE = $ROOTDIR."/var/run/mycrond.pid";
 
$SIG{CHLD} = 'IGNORE'; #avoid zombies, or they can eat your brain

### Starting in daemon mode
&Daemonize();
 
 
sub CheckDir() {
  my $dir = $_[0];
  if ( ! -d "$dir" ) {
    system("mkdir -p $dir");
  }
}
 
sub ParseCronLine() {
  my $cron = $_[0];
  chomp($cron);
 
  my @params = split(/ /, $cron);
  my $r_minute = $params[0];
  my $r_hour = $params[1];
  my $r_day = $params[2];
  my $r_month = $params[3];
  my $r_dow = $params[4];
  my $command = $params[5]; 
 
  for (my $x = 6; $x < @params; $x++) {
    $command .= " ".$params[$x];
  }
 
  my ($second, $minute, $hour, $dayOfMonth, $month, $year, $dayOfWeek, 
  $dayOfYear, $daylightSavings) = localtime();
  $year += 1900;
  $month++;
 
  ### Day of week requires some more work
  if ($r_dow != '*') {
    if ($r_dow != $dayOfWeek) {
      return 0;
    }
  }
 
  if ($r_month != '*') {
    $run_status = 0;
    @months = split(/,/, $r_month);
    foreach $m (@months) {
      if ($m == $month) {
        $run_status++ ;
      }
    }
    return if (! $run_status);
  }
 
  if ($r_day != '*') {
    $run_status = 0;
    @days = split(/,/, $r_day);
    foreach $d (@days) {
      if ($d == $dayOfMonth) {
        $run_status++ ;
      }
    }
    return if (! $run_status);
  }
 
  if ($r_minute != '*') {
    $run_status = 0;
    @minutes = split(/,/, $r_minute);
    foreach $m (@minutes) {
      if ($m == $minute) {
        $run_status++ ;
      }
    }
    return if (! $run_status);
  }
 
  if ($r_hour != '*') {
    $run_status = 0;
    @hours = split(/,/, $r_hour);
    foreach $h (@hours) {
      if ($h == $hour) {
        $run_status++ ;
      }  
    }
    return if (! $run_status);
  }
 
  # If it is ok, then run your command
  if (defined($DEBUG)){
    print "Running: $command\n";
  }
  exec "$command" or exit(1);
  exit(0);
 
}
 
sub Run() {
  ### Saving process PID
  my $pid = getppid();
  $pid++;
 
  &amp;CheckDir($ROOTDIR."/var/run");
  open(PID, ">$PIDFILE") or die "Impossible to create $PIDFILE: $!\n";
  print PID $pid."\n";
  close(PID);
 
  open(FD, $CRONFILE) or die "Impossible to read crontab: $!\n";
  my @cronlines = <fd>;
  close(FD);
  my @PIDS;
  while (1) {
    foreach my $line (@cronlines) {
      next if ($line =~ m/^#/);
      my $runpid = fork();
      if ($runpid == 0) {
        &amp;ParseCronLine($line);
        exit(0);
      }
      if ($runpid > 0) {
        push(@PIDS, $runpid);
      }
    }
    sleep(60);
  }
 
}
 
sub Daemonize() {
  # Change to /
  chdir("/");
 
  my $pid = fork(); #first fork
  
  if ($pid > 0) { #Parent exists
    exit(0);
  }
 
  if ($pid == 0) { # Son forks again
  
    my $pid2 = fork();
 
    if ($pid2 > 0) {
      exit(0);
    }
 
    if ($pid2 == 0) {
      &amp;Run();
    }
 
  }
}
</fd>
Categoria: