X-Git-Url: http://git.ipfire.org/?p=people%2Fstevee%2Fguardian.git;a=blobdiff_plain;f=guardian;h=7b4c23fae7b86c7e2d5b1ea7a726a23b03baf2f9;hp=cf759b04821511c5394567dadf0e28f1e3522d81;hb=0b1fe0462fe0e7837228129f6c1d89e64a5ab720;hpb=3111df627870b496ce35c30192098db316a64da4 diff --git a/guardian b/guardian index cf759b0..7b4c23f 100644 --- a/guardian +++ b/guardian @@ -29,11 +29,17 @@ use Time::HiRes qw[ time sleep ]; require Guardian::Base; require Guardian::Config; +require Guardian::Daemon; +require Guardian::Events; +require Guardian::Logger; require Guardian::Parser; require Guardian::Socket; use warnings; +# Disable warnings of unjoinded threads when stopping guardian. +no warnings 'threads'; + # Define version. my $version ="2.0"; @@ -61,22 +67,54 @@ if (defined($cmdargs{"help"})) { exit; } +# Check if another instance of guardian is allready running. +if (&Guardian::Daemon::IsRunning()) { + die "Another instance of Guardian is allready running...\n"; +} + # Read-in the configuration file and store the settings. # Push the may be given config file argument. my %mainsettings = &Guardian::Config::UseConfig($cmdargs{"config"}); -# Shared hash between the main process and all threads. It will store all +# Initialize Logger. +my $logger = Guardian::Logger->Init(%mainsettings); +$logger->Log("debug", "Logger successfully initialized..."); + +# Add the logger object to the mainsettings for passing +# it to the modules. +$mainsettings{Logger} = $logger; + +# Redirect perls "die" messages to the logger before exiting. +$SIG{__DIE__} = sub { $logger->Log("err", "@_"); }; + +# Initialize the event handler. +my $events = Guardian::Events->Init(%mainsettings); + +# Hash to store the currently monitored files and their configured +# parsers. +my %monitored_files = (); + +# Shared hash between the main process and all threads. It will store the # monitored files and their current file position. -my %monitored_files :shared = (); +my %file_positions :shared = (); # Create the main queue. It is used to store and process all events which are # reported and enqueued by the worker threads. -my $queue :shared = new Thread::Queue or die "Could not create new, empty queue. $!\n";; +my $queue :shared = new Thread::Queue or die "Could not create new, empty queue. $!";; # Array to store all currently running worker objects. # (Does not include the socket thread) my @running_workers; +# Check if guardian should be daemonized or keep in the foreground. +unless (defined($cmdargs{"foreground"})) { + # Fork into background. + &Guardian::Daemon::Daemonize(); +} else { + # Write PID (process-id). + &Guardian::Daemon::WritePID(); +} + # Call Init function to initzialize guardian. &Init(); @@ -91,12 +129,21 @@ while(1) { # Grab the data of the top enqueued event. my $event = $queue->peek(); - print "Got event: $event\n"; + # Log processed event. + $logger->Log("debug", "QUEUE - Processed event: $event"); + + # Send event data to the events parser to determine + # if any action is required. + $events->CheckAction($event); # Drop processed event from queue. $queue->dequeue(); } + # Call RemoveBlocks routine from the Events module to check + # if items from the block list can be dropped. + $events->RemoveBlocks(); + # Sleep 10ms to reduce the load of the main process. sleep(0.01); } @@ -144,18 +191,25 @@ sub Init () { sub Worker ($) { my $file = $_[0]; + # Obtain the parser name which should be used to parser any + # messages of this file. + my $parser = $monitored_files{$file}; + # Signal handler to kill worker. $SIG{'KILL'} = sub { threads->exit(); }; # Create inotify watcher. - my $watcher = new Linux::Inotify2 or die "Could not use inotify. $!\n"; + my $watcher = new Linux::Inotify2 or die "Could not use inotify. $!"; # Monitor the specified file. - $watcher->watch("$file", IN_MODIFY) or die "Could not monitor $file. $!\n"; + $watcher->watch("$file", IN_MODIFY) or die "Could not monitor $file. $!"; # Switch watcher into non-blocking mode. $watcher->blocking(0); + # Log successfully spawned worker. + $logger->Log("debug", "Spawned worker thread for: $file"); + # Infinite loop. while(1) { # Check for any events and perform them, if there @@ -164,10 +218,10 @@ sub Worker ($) { my @message = (); # Obtain fileposition from hash. - my $fileposition = $monitored_files{$file}; + my $fileposition = $file_positions{$file}; # Open the file. - open (FILE, $file) or die "Could not open $file. $!\n"; + open (FILE, $file) or die "Could not open $file. $!"; # Seek to the last known position. seek (FILE, $fileposition, 0); @@ -183,10 +237,10 @@ sub Worker ($) { { # Lock shared hash. - lock(%monitored_files); + lock(%file_positions); # Update fileposition. - $monitored_files{$file} = tell(FILE); + $file_positions{$file} = tell(FILE); } # Close file. @@ -194,7 +248,7 @@ sub Worker ($) { # Send filename and message to the parser, # which will return if an action has to be performed. - my @action = &Guardian::Parser::Parser("$file", @message); + my @action = &Guardian::Parser::Parser("$parser", @message); # Send the action to the main process and put it into # the queue. @@ -227,6 +281,9 @@ sub Socket () { # Create the Server socket by calling the responsible function. my $server = &Guardian::Socket::Server(); + # Log successfull creation of socket. + $logger->Log("debug", "Listening to Socket..."); + # Accept incomming connections from the socket. while (my $connection = $server->accept()) { # Autoflush the socket after the data @@ -238,6 +295,9 @@ sub Socket () { # Remove any newlines. chomp($message); + # Log recieved socket command. + $logger->Log("debug", "Socket - Recieved message: $message"); + # Send the recieved data message to the # socket parser. my $action = &Guardian::Socket::Message_Parser($message); @@ -265,6 +325,7 @@ sub SignalHandler { $SIG{INT} = \&Shutdown; $SIG{TERM} = \&Shutdown; $SIG{QUIT} = \&Shutdown; + $SIG{HUP} = \&Reload; } # @@ -275,9 +336,13 @@ sub SignalHandler { ## be added to the array of running workers. # sub StartWorkers () { + # Init/Update hash which contains the cursor position of EOF. + %file_positions = &Guardian::Base::FilePositions(\%monitored_files, \%file_positions); + # Loop through the hash which contains the monitored files and start # a worker thread for each single one. foreach my $file (keys %monitored_files) { + $logger->Log("debug", "Starting worker thread for $file"); # Create worker thread for the file. push @running_workers, threads->create(\&Worker,$file); } @@ -294,8 +359,42 @@ sub StopWorkers () { foreach my $worker (@running_workers) { # Send the worker the "KILL" signal and detach the # thread so perl can do an automatically clean-up. - $worker->kill('KILL')->detach(); + $worker->kill('KILL'); } + $logger->Log("debug", "All workers are stopped now..."); +} + +# +## Reload function. +# +## This function will get called if the signal handler recieves a "SIGHUP" signal, +## or the reload command will be sent via socket connection. It is responsible for +## reloading all configure options and stopping/starting the worker threads. +# +sub Reload () { + # Log reload. + $logger->Log("info", "Reload configuration..."); + + # Stop all running workers. + &StopWorkers(); + + # Re-read configuration file. + %mainsettings = &Guardian::Config::UseConfig($cmdargs{"config"}); + + # Update Logger settings. + $logger = Guardian::Logger->Init(%mainsettings); + + # Update logger object in mainsettings hash. + $mainsettings{Logger} = $logger; + + # Update ignore list. + &Guardian::Events::GenerateIgnoreList($mainsettings{IgnoreFile}); + + # Re-generate hash of monitored files. + %monitored_files = &Guardian::Base::GenerateMonitoredFiles(\%mainsettings, \%monitored_files); + + # Restart the worker threads. + &StartWorkers(); } # @@ -305,12 +404,26 @@ sub StopWorkers () { ## by the signal handler when recieving INT (2), QUIT (3) and TERM (15) signals. # sub Shutdown () { + # Log shutdown. + $logger->Log("info", "Shutting down..."); + # Stop all workers. &StopWorkers(); # Remove socket file on exit. &Guardian::Socket::RemoveSocketFile(); + # Remove pid file on exit. + &Guardian::Daemon::RemovePIDFile(); + + # Sleep for one second to give perl some + # time to proper clean up everything before + # exiting. + sleep(1); + + # Log good bye message. + $logger->Log("debug", "Good Bye!"); + # Exit guardian. exit; }