Subversion Repositories DevTools

Rev

Rev 3847 | Rev 7387 | 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");
184
        exec 'perl',"$rootDir/blatDaemon.pl", $target or $logger->err ("Can't exec");
185
    }
186
 
187
    #
188
    #   What a bit and try again
189
    #
190
    sleep $conf->{'configpoll'};
191
 
192
    #
193
    #   Reap child processes
194
    #   Remember the dead ones - they will be restarted
195
    #
196
    #...
197
    my $kid;
198
    do {
199
        if ( ($kid = waitpid(-1, WNOHANG)) > 0 )
200
        {
201
            $dead{$kid} = 1;
202
            $logger->logmsg("Child Process terminated: $kid");
203
        }
204
    } while ( $kid > 0 );
205
}
206
 
207
#-------------------------------------------------------------------------------
208
# Function        : readConfig
209
#
210
# Description     : Re read the config file if it modification time has changed
3847 dpurdie 211
#                   Not much happens if the config is re-read
1040 dpurdie 212
#                   Only a few of the attributes are used
213
#
214
# Inputs          : Nothing
215
#
216
# Returns         : Nothing
217
#
218
sub readConfig
219
{
220
    my ($mtime) = Utils::mtime($configPath);
221
    if ( $mtimeConfig != $mtime )
222
    {
223
        $logger->logmsg("Reading config file: $configPath");
224
        $mtimeConfig = $mtime;
225
        my $errors;
226
        ($conf, $errors) = Utils::readconf ( $configPath, \%cdata );
227
        if ( scalar @{$errors} > 0 )
228
        {
229
            warn "$_\n" foreach (@{$errors});
230
            die ("Config contained errors\n");
231
        }
232
 
233
        #
234
        #   Reset some information
235
        #   Create a new logger
236
        #
237
        $logger = Logger->new($conf);
238
        $conf->{logger} = $logger;
239
        $logger->verbose("Log Levl: $conf->{verbose}");
240
 
241
        #
242
        #   Some command line options will override config
243
        #
244
        $conf->{pidfile} = $opt_pid if ( defined $opt_pid );
245
        $conf->{verbose} = $opt_verbose if ( $opt_verbose > 0 );
246
 
247
        #
248
        #   Scan the configuration and export specified environment values
249
        #   Simplfies the process of passing data to children
250
        #
251
        while (my($key, $data) = each ( %{$conf->{envVars}} ))
252
        {
253
            $ENV{$key} = $data;
254
            $logger->verbose("Env: $key -> $data");
255
 
256
        }
257
 
258
        #   Extend the path
259
        my @extraPath;
260
        while (my($key, $data) = each ( %{$conf->{envPath}} ))
261
        {
262
            push @extraPath, $data;
263
            $logger->verbose("Path: $key -> $data");
264
 
265
        }
266
        if ( @extraPath )
267
        {
268
            $ENV{PATH} = join( ':', $ENV{PATH} , @extraPath );
269
        }
270
        $logger->verbose("PATH: $ENV{PATH}");
271
    }
272
}
273
 
274
 
275
 
276
#-------------------------------------------------------------------------------
277
# Function        : sighandlers
278
#
279
# Description     : Install signal handlers
280
#
281
# Inputs          : $conf           - System config
282
#
283
# Returns         : Nothing
284
#
285
sub sighandlers
286
{
5398 dpurdie 287
    my $conf = shift;
288
    my $logger = $conf->{logger};
1040 dpurdie 289
 
5398 dpurdie 290
    $SIG{TERM} = sub {
291
        # On shutdown
292
        $logger->logmsg('Received SIGTERM. Shutting down....' );
1040 dpurdie 293
        foreach my $entry ( keys %children )
294
        {
295
            my $pid = $children{$entry}{pid};
5398 dpurdie 296
            $logger->logmsg('Terminate child: ' . $pid);
1040 dpurdie 297
            kill 15, $pid;
298
        }
299
 
5398 dpurdie 300
        unlink $conf->{'pidfile'} if -f $conf->{'pidfile'};
301
        exit 0;
302
    };
1040 dpurdie 303
 
5398 dpurdie 304
    $SIG{HUP} = sub {
305
        # On logrotate
306
        $logger->logmsg('Received SIGHUP.');
307
        $logger->rotatelog();
1040 dpurdie 308
        foreach my $entry ( keys %children )
309
        {
310
            my $pid = $children{$entry}{pid};
5398 dpurdie 311
            $logger->logmsg('Signal HUP to child: ' . $pid);
1040 dpurdie 312
            kill 1, $pid;
313
        }
5398 dpurdie 314
    };
3847 dpurdie 315
 
5398 dpurdie 316
    $SIG{USR1} = sub {
317
        # On Force Archive Sync
318
        $logger->logmsg('Received SIGUSR1.');
3847 dpurdie 319
        foreach my $entry ( keys %children )
320
        {
321
            my $pid = $children{$entry}{pid};
5398 dpurdie 322
            $logger->logmsg('Signal USR1 to child: ' . $pid);
3847 dpurdie 323
            kill 'USR1', $pid;
324
        }
5398 dpurdie 325
    };
1040 dpurdie 326
}
327