[vhffs-dev] [1593] moved cron_scheduler into vhffs_cron, added daemonizing of vhffs_cron, fixed path for shells

[ Thread Index | Date Index | More vhffs.org/vhffs-dev Archives ]


Revision: 1593
Author:   gradator
Date:     2010-04-10 03:13:43 +0200 (Sat, 10 Apr 2010)
Log Message:
-----------
moved cron_scheduler into vhffs_cron, added daemonizing of vhffs_cron, fixed path for shells

Modified Paths:
--------------
    trunk/Makefile.am
    trunk/configure.ac
    trunk/vhffs-robots/Makefile.am

Added Paths:
-----------
    trunk/vhffs-cron/
    trunk/vhffs-cron/src/
    trunk/vhffs-cron/src/vhffscron.pl

Removed Paths:
-------------
    trunk/vhffs-robots/src/cron_scheduler.pl

Modified: trunk/Makefile.am
===================================================================
--- trunk/Makefile.am	2010-04-09 23:38:28 UTC (rev 1592)
+++ trunk/Makefile.am	2010-04-10 01:13:43 UTC (rev 1593)
@@ -3,15 +3,16 @@
 SITE_CONFIG_FILE = @CONFDIR@/vhffs.conf
 
 DISTCHECK_CONFIGURE_FLAGS = --enable-extra --enable-panel \
-	--enable-public --enable-listengine --enable-robots --enable-backend \
-	--enable-compat --enable-jabber --enable-tools --enable-vhffs-fs
+	--enable-public --enable-listengine --enable-cron --enable-robots \
+	--enable-backend --enable-compat --enable-jabber --enable-tools \
+	--enable-vhffs-fs
 
 if INSTALL_VHFFS_FS 
   SUB_VHFFS_FS=vhffs-fs
 endif
 
 SUBDIRS = $(SUB_VHFFS_FS) vhffs-api vhffs-packages vhffs-backend vhffs-doc vhffs-compat vhffs-intl vhffs-jabber vhffs-listengine \
-	vhffs-panel vhffs-public vhffs-robots vhffs-shells vhffs-themes vhffs-tools vhffs-irc vhffs-autokill \
+	vhffs-cron vhffs-panel vhffs-public vhffs-robots vhffs-shells vhffs-themes vhffs-tools vhffs-irc vhffs-autokill \
 	vhffs-forum vhffs-fssync vhffs-mw vhffs-stsmon
 
 EXTRA_DIST = config.rpath m4/ChangeLog

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2010-04-09 23:38:28 UTC (rev 1592)
+++ trunk/configure.ac	2010-04-10 01:13:43 UTC (rev 1593)
@@ -41,14 +41,18 @@
 	AC_HELP_STRING([--with-shell-path=path],
 		[Complete path for tux shell and falseshell(/bin)]),
 	SHELLDIR=$withval,
-	SHELLDIR=${prefix}/bin
+	if test "x$prefix" = "x/usr"; then
+		SHELLDIR=/bin
+	else
+		SHELLDIR=${prefix}/bin
+	fi
 )
 AC_SUBST(SHELLDIR)
 
 dnl Where to store tools
 AC_ARG_WITH(tools-path,
 	AC_HELP_STRING([--with-tools-path=path],
-		[Complete path for tools (executables) (/usr/local/bin)]),
+		[Complete path for tools (executables) (/usr/bin)]),
 	TOOLSDIR=$withval,
 	TOOLSDIR=${prefix}/bin
 )
@@ -136,6 +140,15 @@
 )
 AC_SUBST(LEDIR)
 
+dnl Cron
+AC_ARG_WITH(cron-path,
+	AC_HELP_STRING([--with-cron-path=path],
+		[Complete path for cron daemon (/usr/lib/vhffs/cron)]),
+	CRONDIR=$withval,
+	CRONDIR=${prefix}/lib/vhffs/cron
+)
+AC_SUBST(CRONDIR)
+
 dnl IRC bot
 AC_ARG_WITH(irc-bot-path,
 	AC_HELP_STRING([--with-irc-bot-path=path],
@@ -219,6 +232,14 @@
 
 AM_CONDITIONAL(INSTALL_LISTENGINE, test "$enable_listengine" = yes)
 
+dnl Install cron daemon or not ?
+AC_ARG_ENABLE(cron,
+    AC_HELP_STRING([--enable-cron],
+        [Enable cron daemon installation [default=yes]]),
+        enable_cron=$enableval, enable_cron=yes)
+
+AM_CONDITIONAL(INSTALL_CRON, test "$enable_cron" = yes)
+
 dnl Install robots or not ?
 AC_ARG_ENABLE(robots,
     AC_HELP_STRING([--enable-robots],
@@ -349,6 +370,8 @@
 	vhffs-jabber/Makefile
 	vhffs-listengine/Makefile
 	vhffs-listengine/src/Makefile
+	vhffs-cron/Makefile
+	vhffs-cron/src/Makefile
 	vhffs-mw/Makefile
 	vhffs-packages/Makefile
 	vhffs-panel/Makefile

Copied: trunk/vhffs-cron/src/vhffscron.pl (from rev 1592, trunk/vhffs-robots/src/cron_scheduler.pl)
===================================================================
--- trunk/vhffs-cron/src/vhffscron.pl	                        (rev 0)
+++ trunk/vhffs-cron/src/vhffscron.pl	2010-04-10 01:13:43 UTC (rev 1593)
@@ -0,0 +1,374 @@
+#!%PERL%
+# Copyright (c) vhffs project and its contributors
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without 
+# modification, are permitted provided that the following conditions 
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright 
+#   notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in 
+#   the documentation and/or other materials provided with the 
+#   distribution.
+#3. Neither the name of vhffs nor the names of its contributors 
+#   may be used to endorse or promote products derived from this 
+#   software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
+#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+# POSSIBILITY OF SUCH DAMAGE.
+
+use strict;
+use utf8;
+use POSIX;
+use Fcntl ':mode';
+use IO::Handle;
+use IO::Select;
+use BSD::Resource;
+use English;
+use Cwd 'chdir';
+#use Data::Dumper;
+
+use constant
+{
+	STATUS_CREATED => 0,
+	STATUS_RUNNING => 1,
+	STATUS_KILLED => 2,
+
+	FAIL_TO_RUN_PROCESS_EXIT_CODE => 136,
+};
+
+use lib '%VHFFS_LIB_DIR%';
+use Vhffs::Main;
+use Vhffs::Services::Cron;
+use Vhffs::Robots::Cron;
+use Vhffs::Functions;
+
+#select(STDOUT);
+#$| = 1;
+
+my $vhffs = init Vhffs::Main;
+exit 1 unless defined $vhffs;
+
+my $cronconf = $vhffs->get_config->get_service('cron');
+unless( defined $cronconf ) {
+	print 'Please add VHFFS configuration for this module'."\n";
+	exit 1;
+}
+
+# daemonize if there is an argument
+if( $#ARGV >= 0 ) {
+	close STDOUT;
+	close STDIN;
+	close STDERR;
+	exit 0 if defined fork();
+}
+
+my $chroot = $cronconf->{'chroot'};
+my $limits = $cronconf->{'limits'};
+my $rlimits = BSD::Resource::get_rlimits();
+my $mailcronfrom = $cronconf->{'mail_from'};
+my $maxexectime = $cronconf->{'max_execution_time'};
+my $nice = $cronconf->{'nice'};
+
+my %jobs;
+my %fd2jobs;
+my $read_set = new IO::Select();
+my $prevrun = 0;
+
+while(1)  {
+
+	if( time() - $prevrun > int(rand 10)+5 )  {
+
+		# new jobs ?
+		my $crons = Vhffs::Robots::Cron::get_runnable_jobs( $vhffs );
+		foreach my $c ( @{$crons} )  {
+			if( exists $jobs{ $c->get_cron_id } )  {
+				print scalar localtime().'    ! '.$c->get_cron_id.' '.$c->get_cronpath."\n";
+			}
+			else {
+				new_job( $c );
+			}
+		}
+
+		# stalled jobs ?
+		$crons = Vhffs::Robots::Cron::get_stalled_jobs( $vhffs , $maxexectime + 60 );
+		foreach my $c ( @{$crons} )  {
+			$c->quick_reset();
+			print scalar localtime().'    * '.$c->get_cron_id.' '.$c->get_cronpath."\n";
+		}
+
+		$prevrun = time();
+	}
+
+	foreach ( keys %jobs )  {
+		my $job = $jobs{$_};
+
+		if( $job->{'status'} == STATUS_CREATED )  {
+			run_job( $job ) if( time() > $job->{'runat'} );
+			next;
+		}
+
+		if ( $job->{'status'} == STATUS_RUNNING )  {
+			if( defined $maxexectime  &&  $maxexectime > 0  &&  time() - $job->{'startedat'} > $maxexectime ) {
+				kill 9, $job->{'pid'};
+				$job->{'status'} = STATUS_KILLED;
+				next;
+			}
+		}
+
+		next if defined $job->{'pipe'};
+
+		my $pid = waitpid( $job->{'pid'}, POSIX::WNOHANG );
+		my $returnvalue = $? >> 8;
+		next if $pid != $job->{'pid'};
+
+		my $cron = $job->{'cron'};
+		
+		$job->{'output'} .= "\n------KILLED------\n" if( $job->{'status'} == STATUS_KILLED );
+			
+		if( defined $job->{'output'}  &&  $job->{'output'} ne '' )  {
+			
+			my $body = 'Exit value: '. $returnvalue."\n\n";
+			$body .= 'WARNING: This process was killed because it were still running after more than '.$maxexectime.' seconds'."\n\n" if( $job->{'status'} == STATUS_KILLED );
+			$body .= "\n--- Environment ---\n\n".$job->{'env'}."\n\n--- Stdout and stderr output ---\n\n".$job->{'output'}."\n";
+			sendmail_cron( $cron , $body );
+		}
+
+		my $nextinterval = $cron->get_interval;
+		$nextinterval = 600 if $returnvalue == FAIL_TO_RUN_PROCESS_EXIT_CODE;
+		$cron->quick_set_nextrundate( time() + $nextinterval );
+		$cron->quick_set_lastrun( $job->{'createdat'} , $returnvalue );
+		$cron->quick_dec_running();
+		destroy_job( $job );
+	}
+
+	my ($rh_set) = IO::Select->select($read_set, undef, undef, 1);
+	foreach my $rh (@$rh_set) {
+		my $job = $fd2jobs{$rh->fileno};
+		my $cron = $job->{'cron'};
+		my $buf = <$rh>;
+		if($buf) {
+			if( $job->{'inheaders'} )  {
+				if( (my $data) = ( $buf =~ /^ENV:(.*)$/ ) ) {
+					$job->{'env'} .= $data."\n";
+				}
+				elsif( $buf =~ /^$/ )  {
+					$job->{'inheaders'} = 0;
+				}
+			}
+			else  {
+				$job->{'output'} .= $buf;
+			}
+		}
+		else {
+			delete $fd2jobs{ $rh->fileno };
+			$read_set->remove( $rh );
+			close( $rh );
+			$job->{'pipe'} = undef;
+		}
+	}
+
+	#print 'Jobs: '.join(' ', sort { $a <=> $b } keys %jobs)."\n";
+	#print 'Fd2Jobs: '.join(' ', sort { $a <=> $b } keys %fd2jobs)."\n";
+}
+
+exit 0;
+
+
+sub new_job
+{
+	my $cron = shift;
+	my $cron_id = $cron->get_cron_id;
+
+	$jobs{$cron_id}{'cron'} = $cron;
+	$jobs{$cron_id}{'pid'} = undef;
+	$jobs{$cron_id}{'pipe'} = undef;
+	$jobs{$cron_id}{'output'} = undef;
+	$jobs{$cron_id}{'env'} = '';
+	$jobs{$cron_id}{'inheaders'} = 1;
+	$jobs{$cron_id}{'createdat'} = time();
+	$jobs{$cron_id}{'runat'} = $jobs{$cron_id}{'createdat'} + int(rand 4) +2;
+	$jobs{$cron_id}{'startedat'} = undef;
+	$jobs{$cron_id}{'status'} = STATUS_CREATED;
+	$cron->quick_set_nextrundate( $jobs{$cron_id}{'runat'} );  # so that we know when the process will/has be/been started in nextrundate
+	$cron->quick_inc_running();
+
+	print scalar localtime().'    + '.$cron_id.' '.$cron->get_cronpath."\n";
+	return $jobs{$cron_id};
+}
+
+
+sub run_job
+{
+	my $job = shift;
+	my $cron = $job->{'cron'};
+	my $cron_id = $cron->get_cron_id;
+
+	my $running = $cron->quick_get_running();
+	return 1 unless defined $running;
+	if( $running > 1 )  {
+		print scalar localtime().'    x '.$cron_id.' '.$cron->get_cronpath."\n";
+		$cron->quick_dec_running();
+		destroy_job( $job );
+		return 1;
+	}
+	elsif( $running < 0 )  {
+		#this should not happen, set running to 0 and abort
+		$cron->quick_set_running( 0 );
+		destroy_job( $job );
+		return 1;
+	}
+	print scalar localtime().'    > '.$cron_id.' '.$cron->get_cronpath."\n";
+
+	my $par = new IO::Handle->new();
+	my $son = new IO::Handle->new();
+	
+	unless( pipe( $par, $son ) )  {
+		print "pipe() failed\n";
+		destroy_job( $job );
+		return 1;
+	}
+
+	my $pid = fork();
+	unless( defined $pid )  {
+		print "fork() failed\n";
+		close $par;
+		close $son;
+		destroy_job( $job );
+		return 1;
+	}
+
+	if ($pid) {
+
+		# I am the parent
+		close $son;
+
+		$jobs{$cron_id}{'pid'} = $pid;
+		$jobs{$cron_id}{'pipe'} = $par;
+		$jobs{$cron_id}{'startedat'} = time();
+		$jobs{$cron_id}{'status'} = STATUS_RUNNING;
+		$fd2jobs{$par->fileno} = $jobs{$cron_id};
+		$read_set->add($par);
+		return 0;
+
+	}
+	elsif($pid == 0)  {
+
+		# I am the child
+		close $par;
+		$son->autoflush(1);
+
+		close STDOUT;
+		open STDOUT, '>&'.$son->fileno;
+		STDOUT->autoflush(1);
+
+		close STDERR;
+		open STDERR, '>&'.$son->fileno;
+		STDERR->autoflush(1);
+
+		foreach my $resource ( keys %{$limits} )  {
+			my ( $soft , $hard ) = ( $limits->{$resource} =~ /^\s*([\d\w]+)\s+([\d\w]+)\s*$/ );
+
+			$resource = $rlimits->{$resource};
+			$soft = eval $soft;   # we get a string, we have to convert it to the
+			$hard = eval $hard;   # integer constant if needed ( RLIM_INFINITY and such )
+
+			BSD::Resource::setrlimit( $resource , $soft, $hard ) if defined $resource and defined $soft and defined $hard;
+		}
+
+		POSIX::nice $nice;
+		%ENV = ();
+
+		chroot $chroot if defined $chroot;
+
+		my ($username,undef,undef,undef,undef,undef,undef,$homedir,undef,undef) = getpwuid( $cron->get_owner_uid );
+		$ENV{'PATH'} = '/usr/bin:/bin';
+		$ENV{'HOME'} = $homedir;
+		$ENV{'LOGNAME'} = $username;
+		chdir $homedir;
+
+		foreach (sort keys(%ENV)) {
+			print $son 'ENV:'.$_.'='.$ENV{$_}."\n";
+		}
+		print $son "\n";
+
+		if( $ENV{'PWD'} ne $homedir ) {
+			print $son "CRITICAL: Cannot chdir() to home directory\n";
+			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
+		}
+
+		$GID = $EGID = $cron->get_owner_gid.' '.$cron->get_owner_gid;
+		$UID = $EUID = $cron->get_owner_uid;
+		unless( POSIX::getuid() == $cron->get_owner_uid && POSIX::getgid() == $cron->get_owner_gid ) {
+			print $son "CRITICAL: Error while setting UID and GID\n";
+			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
+		}
+
+		my $cronpath = $cron->get_cronpath;
+
+		unless( -f $cronpath && -x $cronpath )  {
+			print $son "CRITICAL: The path is neither a regular file nor an executable\n";
+			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
+		}
+
+		my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($cronpath);
+
+		unless( $gid == $cron->get_owner_gid )  {
+			print $son "CRITICAL: GID of file don't match the owner GID of this object in the VHFFS database\n";
+			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
+		}
+
+		unless( $uid == $cron->get_owner_uid )  {
+			print $son "CRITICAL: UID of file don't match the owner UID of this object in the VHFFS database\n";
+			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
+		}
+
+		if( $mode & S_IWOTH )  {
+			print $son "CRITICAL: File is writeable by others, I am not going to execute that\n";
+			exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
+		}		
+
+		exec $cron->get_cronpath;		
+		exit 1;
+	}
+}
+
+
+sub destroy_job
+{
+	my $job = shift;
+	my $cron = $job->{'cron'};
+	my $cron_id = $cron->get_cron_id;
+
+	print scalar localtime().'    - '.$cron->get_cron_id.' '.$cron->get_cronpath."\n";
+	delete $jobs{$cron_id};
+
+	my $pipe = $job->{'pipe'};
+	if( defined $pipe )  {
+		delete $fd2jobs{ $pipe->fileno };
+		$read_set->remove($pipe);
+		close($pipe);
+	}
+}
+
+
+sub sendmail_cron
+{
+	my $cron = shift;
+	my $body = shift;
+	return undef unless( defined $cron->get_reportmail  &&  $cron->get_reportmail ne '' );
+	my $subject = 'VHFFS Cron '.$cron->get_cronpath;
+	Vhffs::Functions::send_mail( $vhffs , $mailcronfrom , $cron->get_reportmail , $vhffs->get_config->get_mailtag , $subject , $body );
+}

Modified: trunk/vhffs-robots/Makefile.am
===================================================================
--- trunk/vhffs-robots/Makefile.am	2010-04-09 23:38:28 UTC (rev 1592)
+++ trunk/vhffs-robots/Makefile.am	2010-04-10 01:13:43 UTC (rev 1593)
@@ -74,8 +74,7 @@
 	src/web_delete.pl \
 	src/web_stats.pl \
 	src/cron_create.pl \
-	src/cron_delete.pl \
-	src/cron_scheduler.pl
+	src/cron_delete.pl
 
 # Define the substitution we need to point perl script at correct location
 do_sed = $(SED) --in-place \

Deleted: trunk/vhffs-robots/src/cron_scheduler.pl
===================================================================
--- trunk/vhffs-robots/src/cron_scheduler.pl	2010-04-09 23:38:28 UTC (rev 1592)
+++ trunk/vhffs-robots/src/cron_scheduler.pl	2010-04-10 01:13:43 UTC (rev 1593)
@@ -1,361 +0,0 @@
-#!%PERL%
-# Copyright (c) vhffs project and its contributors
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without 
-# modification, are permitted provided that the following conditions 
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright 
-#   notice, this list of conditions and the following disclaimer.
-#2. Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in 
-#   the documentation and/or other materials provided with the 
-#   distribution.
-#3. Neither the name of vhffs nor the names of its contributors 
-#   may be used to endorse or promote products derived from this 
-#   software without specific prior written permission.
-#
-#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
-#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
-#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
-#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
-#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
-#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
-#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
-# POSSIBILITY OF SUCH DAMAGE.
-
-use strict;
-use utf8;
-use POSIX;
-use Fcntl ':mode';
-use IO::Handle;
-use IO::Select;
-use BSD::Resource;
-use English;
-use Cwd 'chdir';
-#use Data::Dumper;
-
-use constant
-{
-	STATUS_CREATED => 0,
-	STATUS_RUNNING => 1,
-	STATUS_KILLED => 2,
-
-	FAIL_TO_RUN_PROCESS_EXIT_CODE => 136,
-};
-
-use lib '%VHFFS_LIB_DIR%';
-use Vhffs::Main;
-use Vhffs::Services::Cron;
-use Vhffs::Robots::Cron;
-use Vhffs::Functions;
-
-#select(STDOUT);
-#$| = 1;
-
-my $vhffs = init Vhffs::Main;
-exit 1 unless defined $vhffs;
-
-my $cronconf = $vhffs->get_config->get_service('cron');
-my $chroot = $cronconf->{'chroot'};
-my $limits = $cronconf->{'limits'};
-my $rlimits = BSD::Resource::get_rlimits();
-my $mailcronfrom = $cronconf->{'mail_from'};
-my $maxexectime = $cronconf->{'max_execution_time'};
-my $nice = $cronconf->{'nice'};
-
-my %jobs;
-my %fd2jobs;
-my $read_set = new IO::Select();
-my $prevrun = 0;
-
-while(1)  {
-
-	if( time() - $prevrun > int(rand 10)+5 )  {
-
-		# new jobs ?
-		my $crons = Vhffs::Robots::Cron::get_runnable_jobs( $vhffs );
-		foreach my $c ( @{$crons} )  {
-			if( exists $jobs{ $c->get_cron_id } )  {
-				print scalar localtime().'    ! '.$c->get_cron_id.' '.$c->get_cronpath."\n";
-			}
-			else {
-				new_job( $c );
-			}
-		}
-
-		# stalled jobs ?
-		$crons = Vhffs::Robots::Cron::get_stalled_jobs( $vhffs , $maxexectime + 60 );
-		foreach my $c ( @{$crons} )  {
-			$c->quick_reset();
-			print scalar localtime().'    * '.$c->get_cron_id.' '.$c->get_cronpath."\n";
-		}
-
-		$prevrun = time();
-	}
-
-	foreach ( keys %jobs )  {
-		my $job = $jobs{$_};
-
-		if( $job->{'status'} == STATUS_CREATED )  {
-			run_job( $job ) if( time() > $job->{'runat'} );
-			next;
-		}
-
-		if ( $job->{'status'} == STATUS_RUNNING )  {
-			if( defined $maxexectime  &&  $maxexectime > 0  &&  time() - $job->{'startedat'} > $maxexectime ) {
-				kill 9, $job->{'pid'};
-				$job->{'status'} = STATUS_KILLED;
-				next;
-			}
-		}
-
-		next if defined $job->{'pipe'};
-
-		my $pid = waitpid( $job->{'pid'}, POSIX::WNOHANG );
-		my $returnvalue = $? >> 8;
-		next if $pid != $job->{'pid'};
-
-		my $cron = $job->{'cron'};
-		
-		$job->{'output'} .= "\n------KILLED------\n" if( $job->{'status'} == STATUS_KILLED );
-			
-		if( defined $job->{'output'}  &&  $job->{'output'} ne '' )  {
-			
-			my $body = 'Exit value: '. $returnvalue."\n\n";
-			$body .= 'WARNING: This process was killed because it were still running after more than '.$maxexectime.' seconds'."\n\n" if( $job->{'status'} == STATUS_KILLED );
-			$body .= "\n--- Environment ---\n\n".$job->{'env'}."\n\n--- Stdout and stderr output ---\n\n".$job->{'output'}."\n";
-			sendmail_cron( $cron , $body );
-		}
-
-		my $nextinterval = $cron->get_interval;
-		$nextinterval = 600 if $returnvalue == FAIL_TO_RUN_PROCESS_EXIT_CODE;
-		$cron->quick_set_nextrundate( time() + $nextinterval );
-		$cron->quick_set_lastrun( $job->{'createdat'} , $returnvalue );
-		$cron->quick_dec_running();
-		destroy_job( $job );
-	}
-
-	my ($rh_set) = IO::Select->select($read_set, undef, undef, 1);
-	foreach my $rh (@$rh_set) {
-		my $job = $fd2jobs{$rh->fileno};
-		my $cron = $job->{'cron'};
-		my $buf = <$rh>;
-		if($buf) {
-			if( $job->{'inheaders'} )  {
-				if( (my $data) = ( $buf =~ /^ENV:(.*)$/ ) ) {
-					$job->{'env'} .= $data."\n";
-				}
-				elsif( $buf =~ /^$/ )  {
-					$job->{'inheaders'} = 0;
-				}
-			}
-			else  {
-				$job->{'output'} .= $buf;
-			}
-		}
-		else {
-			delete $fd2jobs{ $rh->fileno };
-			$read_set->remove( $rh );
-			close( $rh );
-			$job->{'pipe'} = undef;
-		}
-	}
-
-	#print 'Jobs: '.join(' ', sort { $a <=> $b } keys %jobs)."\n";
-	#print 'Fd2Jobs: '.join(' ', sort { $a <=> $b } keys %fd2jobs)."\n";
-}
-
-exit 0;
-
-
-sub new_job
-{
-	my $cron = shift;
-	my $cron_id = $cron->get_cron_id;
-
-	$jobs{$cron_id}{'cron'} = $cron;
-	$jobs{$cron_id}{'pid'} = undef;
-	$jobs{$cron_id}{'pipe'} = undef;
-	$jobs{$cron_id}{'output'} = undef;
-	$jobs{$cron_id}{'env'} = '';
-	$jobs{$cron_id}{'inheaders'} = 1;
-	$jobs{$cron_id}{'createdat'} = time();
-	$jobs{$cron_id}{'runat'} = $jobs{$cron_id}{'createdat'} + int(rand 4) +2;
-	$jobs{$cron_id}{'startedat'} = undef;
-	$jobs{$cron_id}{'status'} = STATUS_CREATED;
-	$cron->quick_set_nextrundate( $jobs{$cron_id}{'runat'} );  # so that we know when the process will/has be/been started in nextrundate
-	$cron->quick_inc_running();
-
-	print scalar localtime().'    + '.$cron_id.' '.$cron->get_cronpath."\n";
-	return $jobs{$cron_id};
-}
-
-
-sub run_job
-{
-	my $job = shift;
-	my $cron = $job->{'cron'};
-	my $cron_id = $cron->get_cron_id;
-
-	my $running = $cron->quick_get_running();
-	return 1 unless defined $running;
-	if( $running > 1 )  {
-		print scalar localtime().'    x '.$cron_id.' '.$cron->get_cronpath."\n";
-		$cron->quick_dec_running();
-		destroy_job( $job );
-		return 1;
-	}
-	elsif( $running < 0 )  {
-		#this should not happen, set running to 0 and abort
-		$cron->quick_set_running( 0 );
-		destroy_job( $job );
-		return 1;
-	}
-	print scalar localtime().'    > '.$cron_id.' '.$cron->get_cronpath."\n";
-
-	my $par = new IO::Handle->new();
-	my $son = new IO::Handle->new();
-	
-	unless( pipe( $par, $son ) )  {
-		print "pipe() failed\n";
-		destroy_job( $job );
-		return 1;
-	}
-
-	my $pid = fork();
-	unless( defined $pid )  {
-		print "fork() failed\n";
-		close $par;
-		close $son;
-		destroy_job( $job );
-		return 1;
-	}
-
-	if ($pid) {
-
-		# I am the parent
-		close $son;
-
-		$jobs{$cron_id}{'pid'} = $pid;
-		$jobs{$cron_id}{'pipe'} = $par;
-		$jobs{$cron_id}{'startedat'} = time();
-		$jobs{$cron_id}{'status'} = STATUS_RUNNING;
-		$fd2jobs{$par->fileno} = $jobs{$cron_id};
-		$read_set->add($par);
-		return 0;
-
-	}
-	elsif($pid == 0)  {
-
-		# I am the child
-		close $par;
-		$son->autoflush(1);
-
-		close STDOUT;
-		open STDOUT, '>&'.$son->fileno;
-		STDOUT->autoflush(1);
-
-		close STDERR;
-		open STDERR, '>&'.$son->fileno;
-		STDERR->autoflush(1);
-
-		foreach my $resource ( keys %{$limits} )  {
-			my ( $soft , $hard ) = ( $limits->{$resource} =~ /^\s*([\d\w]+)\s+([\d\w]+)\s*$/ );
-
-			$resource = $rlimits->{$resource};
-			$soft = eval $soft;   # we get a string, we have to convert it to the
-			$hard = eval $hard;   # integer constant if needed ( RLIM_INFINITY and such )
-
-			BSD::Resource::setrlimit( $resource , $soft, $hard ) if defined $resource and defined $soft and defined $hard;
-		}
-
-		POSIX::nice $nice;
-		%ENV = ();
-
-		chroot $chroot if defined $chroot;
-
-		my ($username,undef,undef,undef,undef,undef,undef,$homedir,undef,undef) = getpwuid( $cron->get_owner_uid );
-		$ENV{'PATH'} = '/usr/bin:/bin';
-		$ENV{'HOME'} = $homedir;
-		$ENV{'LOGNAME'} = $username;
-		chdir $homedir;
-
-		foreach (sort keys(%ENV)) {
-			print $son 'ENV:'.$_.'='.$ENV{$_}."\n";
-		}
-		print $son "\n";
-
-		if( $ENV{'PWD'} ne $homedir ) {
-			print $son "CRITICAL: Cannot chdir() to home directory\n";
-			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
-		}
-
-		$GID = $EGID = $cron->get_owner_gid.' '.$cron->get_owner_gid;
-		$UID = $EUID = $cron->get_owner_uid;
-		unless( POSIX::getuid() == $cron->get_owner_uid && POSIX::getgid() == $cron->get_owner_gid ) {
-			print $son "CRITICAL: Error while setting UID and GID\n";
-			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
-		}
-
-		my $cronpath = $cron->get_cronpath;
-
-		unless( -f $cronpath && -x $cronpath )  {
-			print $son "CRITICAL: The path is neither a regular file nor an executable\n";
-			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
-		}
-
-		my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($cronpath);
-
-		unless( $gid == $cron->get_owner_gid )  {
-			print $son "CRITICAL: GID of file don't match the owner GID of this object in the VHFFS database\n";
-			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
-		}
-
-		unless( $uid == $cron->get_owner_uid )  {
-			print $son "CRITICAL: UID of file don't match the owner UID of this object in the VHFFS database\n";
-			_exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
-		}
-
-		if( $mode & S_IWOTH )  {
-			print $son "CRITICAL: File is writeable by others, I am not going to execute that\n";
-			exit(FAIL_TO_RUN_PROCESS_EXIT_CODE);
-		}		
-
-		exec $cron->get_cronpath;		
-		exit 1;
-	}
-}
-
-
-sub destroy_job
-{
-	my $job = shift;
-	my $cron = $job->{'cron'};
-	my $cron_id = $cron->get_cron_id;
-
-	print scalar localtime().'    - '.$cron->get_cron_id.' '.$cron->get_cronpath."\n";
-	delete $jobs{$cron_id};
-
-	my $pipe = $job->{'pipe'};
-	if( defined $pipe )  {
-		delete $fd2jobs{ $pipe->fileno };
-		$read_set->remove($pipe);
-		close($pipe);
-	}
-}
-
-
-sub sendmail_cron
-{
-	my $cron = shift;
-	my $body = shift;
-	return undef unless( defined $cron->get_reportmail  &&  $cron->get_reportmail ne '' );
-	my $subject = 'VHFFS Cron '.$cron->get_cronpath;
-	Vhffs::Functions::send_mail( $vhffs , $mailcronfrom , $cron->get_reportmail , $vhffs->get_config->get_mailtag , $subject , $body );
-}


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/