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++; &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 = ; close(FD); my @PIDS; while (1) { foreach my $line (@cronlines) { next if ($line =~ m/^#/); my $runpid = fork(); if ($runpid == 0) { &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) { &Run(); } } }