Subversion Repositories DevTools

Rev

Rev 7387 | Rev 7396 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1040 dpurdie 1
#! /usr/bin/perl
2
########################################################################
3
# Copyright (C) 2011 Vix-ERG Limited, All rights reserved
4
#
5
# Module name   : pl
6
# Compiler(s)   : Perl
7
#
8
# Description   : Start up the package blat system
9
#
10
# Usage         : blat 'tag' opr args
11
#
12
#......................................................................#
13
 
14
require 5.008_002;
15
use strict;
16
use warnings;
17
 
18
use Getopt::Long;                               # Option processing
19
use Pod::Usage;                                 # Required for help support
20
 
21
use POSIX qw(setsid strftime);
22
use POSIX ":sys_wait_h";
23
use File::Basename;
24
use File::Spec::Functions qw(rel2abs);
25
use Cwd;
26
 
27
use FindBin;                                    # Determine the current directory
28
use lib "$FindBin::Bin/lib";                    # Allow local libraries
29
 
30
use Utils;
31
use StdLogger;                                  # Log to sdtout
32
use Logger;                                     # Log to file
33
 
34
#
35
#   Globals
36
#
37
my $rootDir = $FindBin::Bin;
38
my $configFile = "/blat.cfg";
39
my $configPath = "${rootDir}/config${configFile}";
40
my $logger = StdLogger->new();
41
my %children;
42
my %dead;
43
my $conf;
44
my $mtimeConfig = 0;
45
 
46
#
47
#   Options
48
#
49
my $opt_help = 0;
50
my $opt_verbose = 0;
51
my $opt_nodaemonise = 0;
52
my $opt_config;
53
my $opt_basedir = $rootDir;
54
my $opt_pid;
55
 
56
#
57
#   Describe configuration parameters
58
#
59
my %cdata = (
60
    '.ignore'         => {'env\.(.+)'   => 'envVars', 'path\.(.+)'   => 'envPath'},
61
    'pidfile'         => {'mandatory' => 0    , 'fmt' => 'vfile'},
62
    'logfile'         => {'mandatory' => 1    , 'fmt' => 'vfile'},
63
    'logfile.size'    => {'default'   => '1M' , 'fmt' => 'size'},
64
    'logfile.count'   => {'default'   => 9    , 'fmt' => 'int'},
65
    'config'          => {'mandatory' => 1    , 'fmt' => 'dir'},
66
    'verbose'         => {'default'   => 0    , 'fmt' => 'int'},
67
    'configpoll'      => {'default'   => 10   , 'fmt' => 'period'},
68
);
69
 
70
#-------------------------------------------------------------------------------
71
# Function        : Mainline Entry Point
72
#
73
# Description     :
74
#
75
# Inputs          :
76
#
77
my $result = GetOptions (
78
                "help|h:+"      => \$opt_help,
79
                "manual:3"      => \$opt_help,
80
                "verbose:+"     => \$opt_verbose,
81
                "D"             => \$opt_nodaemonise,
82
                "config=s"      => \$opt_config,
83
                "dir=s"         => \$opt_basedir,
84
                "pid=s"         => \$opt_pid,
85
                );
86
 
87
                #
88
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
89
                #
90
 
91
#
92
#   Process help and manual options
93
#
94
pod2usage(-verbose => 0, -message => "dpkg_blat") if ($opt_help == 1 || ! $result || $#ARGV >= 0);
95
pod2usage(-verbose => 1) if ($opt_help == 2 );
96
pod2usage(-verbose => 2) if ($opt_help > 2);
97
 
98
#
99
#   Process options
100
#
101
chdir ($opt_basedir) || die ("Cannot 'cd' to $opt_basedir: $!\n");
102
print "Current Directory: ", getcwd() , "\n";
103
 
104
if ( $opt_config )
105
{
106
    $configPath = rel2abs( $opt_config );
107
    my($filename, $directories, $suffix) = fileparse($configPath);
108
    $configFile = '/' . $filename;
109
}
110
 
111
#-------------------------------------------------------------------------------
112
#   Read in the basic configuration
113
readConfig();
114
 
115
#
116
#   Only one instance
117
#
118
die "No PID file provided or configured" unless ( $conf->{pidfile} );
119
Utils::checkpid($conf);
120
 
121
#
122
#   Daemonise myself
123
#
124
unless ( $opt_nodaemonise )
125
{
126
    $logger->logmsg('Daemonizing...');
127
 
128
    my $msg = 'Can\'t read /dev/null:';
129
    open STDIN, '>/dev/null' or $logger->err("$msg $!");
130
    open STDOUT, '>/dev/null' or $logger->err("$msg $!");
131
    open STDERR, '>/dev/null' or $logger->err("$msg $!");
132
    defined (my $pid = fork) or $logger->err("Can't fork: $!");
133
    exit if $pid;
5398 dpurdie 134
 
1040 dpurdie 135
    setsid or $logger->err("Can't start a new session: $!");
136
    $logger->logmsg('Writing pid');
137
}
138
 
139
#
140
#   Locate and start up new transfer targets
141
#
142
Utils::writepid($conf);
143
sighandlers($conf);
144
while ( 1 )
145
{
146
    readConfig();
147
 
148
    #
149
    #   Process all the configured transfer targets
150
    #
151
    for my $target ( glob($conf->{'config'} . '/*.conf') )
152
    {
153
        #
154
        #   Known entries are tested
155
        #   If the child is dead, then it will be restarted
156
        #
157
        if ( exists $children{$target} )
158
        {
159
            my $pid = $children{$target}{pid};
160
            next unless ( exists $dead{$pid} );
161
            delete $dead{$pid};
162
            delete $children{$target};
163
        }
164
 
165
        #
166
        #   Fork then exec
167
        #
168
        $logger->logmsg("Starting $target");
5398 dpurdie 169
        defined (my $pid = fork) or $logger->err("Can't fork: $!");
1040 dpurdie 170
        if ( $pid )
171
        {
172
            #
173
            #   Parent process. Save PID for dead child testing
174
            #
175
            $children{$target}{pid} = $pid;
5398 dpurdie 176
            next;
1040 dpurdie 177
        }
178
 
179
        #
180
        #   Child process at this point
181
        #
182
#        setsid or $logger->err("Can't start a new session: $!");
183
        $logger->logmsg("Started $target");
7387 dpurdie 184
 
7389 dpurdie 185
        my $daemon = ( $target =~ m~/tarZip~) ? "$rootDir/blatTarZip.pl" : "$rootDir/blatDaemon.pl";
7387 dpurdie 186
        exec 'perl',$daemon, $target or $logger->err ("Can't exec $daemon");
1040 dpurdie 187
    }
188
 
189
    #
190
    #   What a bit and try again
191
    #
192
    sleep $conf->{'configpoll'};
193
 
194
    #
195
    #   Reap child processes
196
    #   Remember the dead ones - they will be restarted
197
    #
198
    #...
199
    my $kid;
200
    do {
201
        if ( ($kid = waitpid(-1, WNOHANG)) > 0 )
202
        {
203
            $dead{$kid} = 1;
204
            $logger->logmsg("Child Process terminated: $kid");
205
        }
206
    } while ( $kid > 0 );
207
}
208
 
209
#-------------------------------------------------------------------------------
210
# Function        : readConfig
211
#
212
# Description     : Re read the config file if it modification time has changed
3847 dpurdie 213
#                   Not much happens if the config is re-read
1040 dpurdie 214
#                   Only a few of the attributes are used
215
#
216
# Inputs          : Nothing
217
#
218
# Returns         : Nothing
219
#
220
sub readConfig
221
{
222
    my ($mtime) = Utils::mtime($configPath);
223
    if ( $mtimeConfig != $mtime )
224
    {
225
        $logger->logmsg("Reading config file: $configPath");
226
        $mtimeConfig = $mtime;
227
        my $errors;
228
        ($conf, $errors) = Utils::readconf ( $configPath, \%cdata );
229
        if ( scalar @{$errors} > 0 )
230
        {
231
            warn "$_\n" foreach (@{$errors});
232
            die ("Config contained errors\n");
233
        }
234
 
235
        #
236
        #   Reset some information
237
        #   Create a new logger
238
        #
239
        $logger = Logger->new($conf);
240
        $conf->{logger} = $logger;
241
        $logger->verbose("Log Levl: $conf->{verbose}");
242
 
243
        #
244
        #   Some command line options will override config
245
        #
246
        $conf->{pidfile} = $opt_pid if ( defined $opt_pid );
247
        $conf->{verbose} = $opt_verbose if ( $opt_verbose > 0 );
248
 
249
        #
250
        #   Scan the configuration and export specified environment values
251
        #   Simplfies the process of passing data to children
252
        #
253
        while (my($key, $data) = each ( %{$conf->{envVars}} ))
254
        {
255
            $ENV{$key} = $data;
256
            $logger->verbose("Env: $key -> $data");
257
 
258
        }
259
 
260
        #   Extend the path
261
        my @extraPath;
262
        while (my($key, $data) = each ( %{$conf->{envPath}} ))
263
        {
264
            push @extraPath, $data;
265
            $logger->verbose("Path: $key -> $data");
266
 
267
        }
268
        if ( @extraPath )
269
        {
270
            $ENV{PATH} = join( ':', $ENV{PATH} , @extraPath );
271
        }
272
        $logger->verbose("PATH: $ENV{PATH}");
273
    }
274
}
275
 
276
 
277
 
278
#-------------------------------------------------------------------------------
279
# Function        : sighandlers
280
#
281
# Description     : Install signal handlers
282
#
283
# Inputs          : $conf           - System config
284
#
285
# Returns         : Nothing
286
#
287
sub sighandlers
288
{
5398 dpurdie 289
    my $conf = shift;
290
    my $logger = $conf->{logger};
1040 dpurdie 291
 
5398 dpurdie 292
    $SIG{TERM} = sub {
293
        # On shutdown
294
        $logger->logmsg('Received SIGTERM. Shutting down....' );
1040 dpurdie 295
        foreach my $entry ( keys %children )
296
        {
297
            my $pid = $children{$entry}{pid};
5398 dpurdie 298
            $logger->logmsg('Terminate child: ' . $pid);
1040 dpurdie 299
            kill 15, $pid;
300
        }
301
 
5398 dpurdie 302
        unlink $conf->{'pidfile'} if -f $conf->{'pidfile'};
303
        exit 0;
304
    };
1040 dpurdie 305
 
5398 dpurdie 306
    $SIG{HUP} = sub {
307
        # On logrotate
308
        $logger->logmsg('Received SIGHUP.');
309
        $logger->rotatelog();
1040 dpurdie 310
        foreach my $entry ( keys %children )
311
        {
312
            my $pid = $children{$entry}{pid};
5398 dpurdie 313
            $logger->logmsg('Signal HUP to child: ' . $pid);
1040 dpurdie 314
            kill 1, $pid;
315
        }
5398 dpurdie 316
    };
3847 dpurdie 317
 
5398 dpurdie 318
    $SIG{USR1} = sub {
319
        # On Force Archive Sync
320
        $logger->logmsg('Received SIGUSR1.');
3847 dpurdie 321
        foreach my $entry ( keys %children )
322
        {
323
            my $pid = $children{$entry}{pid};
5398 dpurdie 324
            $logger->logmsg('Signal USR1 to child: ' . $pid);
3847 dpurdie 325
            kill 'USR1', $pid;
326
        }
5398 dpurdie 327
    };
1040 dpurdie 328
}
329