Rev 1040 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
######################################################################### Copyright (C) 2011 Vix-ERG Limited, All rights reserved## Module name : pl# Compiler(s) : Perl## Description : Start up the package blat system## Usage : blat 'tag' opr args##......................................................................#require 5.008_002;use strict;use warnings;use Getopt::Long; # Option processinguse Pod::Usage; # Required for help supportuse POSIX qw(setsid strftime);use POSIX ":sys_wait_h";use File::Basename;use File::Spec::Functions qw(rel2abs);use Cwd;use FindBin; # Determine the current directoryuse lib "$FindBin::Bin/lib"; # Allow local librariesuse Utils;use StdLogger; # Log to sdtoutuse Logger; # Log to file## Globals#my $rootDir = $FindBin::Bin;my $configFile = "/blat.conf";my $configPath = "${rootDir}/config${configFile}";my $logger = StdLogger->new();my %children;my %dead;my $conf;my $mtimeConfig = 0;## Options#my $opt_help = 0;my $opt_verbose = 0;my $opt_daemonise = 1;my $opt_config;my $opt_basedir = $rootDir;my $opt_pid;## Describe configuration parameters#my %cdata = ('.ignore' => {'env\.(.+)' => 'envVars', 'path\.(.+)' => 'envPath'},'pidfile' => {'mandatory' => 0 , 'fmt' => 'vfile'},'logfile' => {'mandatory' => 1 , 'fmt' => 'vfile'},'logfile.size' => {'default' => '1M' , 'fmt' => 'size'},'logfile.count' => {'default' => 9 , 'fmt' => 'int'},'config' => {'mandatory' => 1 , 'fmt' => 'dir'},'verbose' => {'default' => 0 , 'fmt' => 'int'},'configpoll' => {'default' => 10 , 'fmt' => 'period'},);#-------------------------------------------------------------------------------# Function : Mainline Entry Point## Description :## Inputs :#my $result = GetOptions ("help|h:+" => \$opt_help,"manual:3" => \$opt_help,"verbose:+" => \$opt_verbose,"daemon!" => \$opt_daemonise,"config=s" => \$opt_config,"dir=s" => \$opt_basedir,"pid=s" => \$opt_pid,);## UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!### Process help and manual options#pod2usage(-verbose => 0, -message => "dpkg_blat") if ($opt_help == 1 || ! $result || $#ARGV >= 0);pod2usage(-verbose => 1) if ($opt_help == 2 );pod2usage(-verbose => 2) if ($opt_help > 2);## Process options#chdir ($opt_basedir) || die ("Cannot 'cd' to $opt_basedir: $!\n");print "Current Directory: ", getcwd() , "\n";if ( $opt_config ){$configPath = rel2abs( $opt_config );my($filename, $directories, $suffix) = fileparse($configPath);$configFile = '/' . $filename;}#-------------------------------------------------------------------------------# Read in the basic configurationreadConfig();## Only one instance#die "No PID file provided or configured" unless ( $conf->{pidfile} );Utils::checkpid($conf);## Daemonise myself# Even if the users says no-daemon we still partially daemonise ourselves#$logger->logmsg('Daemonizing...');## Comment out the redirection lines to assist in debugging#if ( $opt_daemonise ){my $msg = 'Can\'t read /dev/null:';open STDIN, '>/dev/null' or $logger->err("$msg $!");open STDOUT, '>/dev/null' or $logger->err("$msg $!");open STDERR, '>/dev/null' or $logger->err("$msg $!");}defined (my $pid = fork) or $logger->err("Can't fork: $!");exit if $pid;setsid or $logger->err("Can't start a new session: $!");$logger->logmsg('Writing pid');Utils::writepid($conf);$logger->logmsg('Daemonizing completed');## Locate and start up new transfer targets#sighandlers($conf);while ( 1 ){readConfig();## Process all the configured transfer targets#for my $target ( glob($conf->{'config'} . '/*.conf') ){## Ignore my own config file#next if ( $target =~ m~$configFile~ );## Known entries are tested# If the child is dead, then it will be restarted#if ( exists $children{$target} ){my $pid = $children{$target}{pid};next unless ( exists $dead{$pid} );delete $dead{$pid};delete $children{$target};}## Fork then exec#$logger->logmsg("Starting $target");defined (my $pid = fork) or $logger->err("Can't fork: $!");if ( $pid ){## Parent process. Save PID for dead child testing#$children{$target}{pid} = $pid;next;}## Child process at this point## setsid or $logger->err("Can't start a new session: $!");$logger->logmsg("Started $target");exec 'perl',"$rootDir/blatDaemon.pl", $target or $logger->err ("Can't exec");}## What a bit and try again#sleep $conf->{'configpoll'};## Reap child processes# Remember the dead ones - they will be restarted##...my $kid;do {if ( ($kid = waitpid(-1, WNOHANG)) > 0 ){$dead{$kid} = 1;$logger->logmsg("Child Process terminated: $kid");}} while ( $kid > 0 );}#-------------------------------------------------------------------------------# Function : readConfig## Description : Re read the config file if it modification time has changed# Not much happens if the cinfig is re-read# Only a few of the attributes are used## Inputs : Nothing## Returns : Nothing#sub readConfig{my ($mtime) = Utils::mtime($configPath);if ( $mtimeConfig != $mtime ){$logger->logmsg("Reading config file: $configPath");$mtimeConfig = $mtime;my $errors;($conf, $errors) = Utils::readconf ( $configPath, \%cdata );if ( scalar @{$errors} > 0 ){warn "$_\n" foreach (@{$errors});die ("Config contained errors\n");}## Reset some information# Create a new logger#$logger = Logger->new($conf);$conf->{logger} = $logger;$logger->verbose("Log Levl: $conf->{verbose}");## Some command line options will override config#$conf->{pidfile} = $opt_pid if ( defined $opt_pid );$conf->{verbose} = $opt_verbose if ( $opt_verbose > 0 );## Scan the configuration and export specified environment values# Simplfies the process of passing data to children#while (my($key, $data) = each ( %{$conf->{envVars}} )){$ENV{$key} = $data;$logger->verbose("Env: $key -> $data");}# Extend the pathmy @extraPath;while (my($key, $data) = each ( %{$conf->{envPath}} )){push @extraPath, $data;$logger->verbose("Path: $key -> $data");}if ( @extraPath ){$ENV{PATH} = join( ':', $ENV{PATH} , @extraPath );}$logger->verbose("PATH: $ENV{PATH}");}}#-------------------------------------------------------------------------------# Function : sighandlers## Description : Install signal handlers## Inputs : $conf - System config## Returns : Nothing#sub sighandlers{my $conf = shift;my $logger = $conf->{logger};$SIG{TERM} = sub {# On shutdown$logger->logmsg('Received SIGTERM. Shutting down....' );foreach my $entry ( keys %children ){my $pid = $children{$entry}{pid};$logger->logmsg('Terminate child: ' . $pid);kill 15, $pid;}unlink $conf->{'pidfile'} if -f $conf->{'pidfile'};exit 0;};$SIG{HUP} = sub {# On logrotate$logger->logmsg('Received SIGHUP.');$logger->rotatelog();foreach my $entry ( keys %children ){my $pid = $children{$entry}{pid};$logger->logmsg('Signal HUP to child: ' . $pid);kill 1, $pid;}};}