[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 );
-}