"Fossies" - the Fresh Open Source Software Archive

Member "lmon-1.2/lmon.pl" (19 May 2005, 7613 Bytes) of package /linux/privat/old/lmon-1.2.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "lmon.pl" see the Fossies "Dox" file reference documentation.

    1 #! /usr/bin/perl -T
    2 # LMon 1.2, anders@bsdconsulting.no, 2005-05-19
    3 # External requirements: Mail::Sendmail, File::Tail.
    4 
    5 package LMon;
    6 use Fcntl;
    7 use Getopt::Std;
    8 use POSIX;
    9 use strict;
   10 use Mail::Sendmail;
   11 use File::Tail;
   12 use FindBin qw($Bin);
   13 $ENV{PATH} = "/sbin:/bin:/usr/sbin:/usr/bin";
   14 $ENV{ENV} = "";
   15 
   16 # --configuration ---
   17 $LMon::mailservers = ['smtp1.tld.com', 'smtp2.tld.com'];
   18 $LMon::recipients = "user\@tld.com";
   19 $LMon::from = "user\@tld.com";
   20 # How many lines to read initially from log:
   21 $LMon::lines = 0;
   22 # How many lines to read initially from log if rotated:
   23 $LMon::resetlines = -1;
   24 # For lines/resetlines, 0 = only read new lines, -1 = read everything.
   25 # How long to wait before checking log buffer:
   26 $LMon::waitsecs = 5;
   27 # How long to wait before checking log buffer after a mail is sent:
   28 $LMon::waitsecsnext = 3600;
   29 # Max buffer lines, set to 0 for unlimited (otherwise drop lines from the top):
   30 $LMon::maxbuffer = 50;
   31 # --- end configuration ---
   32 
   33 # Copyright (c) 2005, Anders Nordby <anders@bsdconsulting.no>
   34 # All rights reserved.
   35 # 
   36 # Redistribution and use in source and binary forms, with or without
   37 # modification, are permitted provided that the following conditions are met:
   38 # 
   39 # * Redistributions of source code must retain the above copyright notice, this
   40 # list of conditions and the following disclaimer.
   41 # 
   42 # * Redistributions in binary form must reproduce the above copyright notice,
   43 # this list of conditions and the following disclaimer in the documentation
   44 # and/or other materials provided with the distribution.
   45 # 
   46 # * Neither the name of BSD Consulting nor the names of its contributors may
   47 # be used to endorse or promote products derived from this software without
   48 # specific prior written permission.
   49 # 
   50 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   51 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   52 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   53 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
   54 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   55 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   56 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   57 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   58 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   59 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   60 
   61 @LMon::reglist = ();
   62 @LMon::logbuffer = ();
   63 $LMon::logfile = ();
   64 $LMon::logbuffertruncated = 0;
   65 $LMon::fnok = '([-\w\.\_]+)';
   66 
   67 use vars qw { $opt_f $opt_p $opt_r $opt_n $opt_s $opt_i $opt_t $opt_F $opt_b $opt_m $opt_d };
   68 
   69 # Untaint $Bin if OK
   70 if ($Bin =~ /$LMon::fnok/) {
   71     $Bin = $1;
   72 }
   73 
   74 sub usage {
   75     print "Usage: lmon.pl -r <rule file> -f <log file> [-t <recipients>] [-p <pid file>]\n";
   76     print "[-n <log name (for alerts)>] [-s <system name (for alerts)]\n";
   77     print "[-i (include mode: alert on rule hits instead of misses) [-F <from mailaddress>]\n";
   78     print "[-m <mail server(s)>] [-d (detach)]\n";
   79 }
   80 if ($#ARGV < 0) { usage; exit(0); }
   81 getopts('r:f:t:p:n:s:F:b:im:d');
   82 if ($opt_t) {
   83     $LMon::recipients = $opt_t;
   84 }
   85 if ($opt_b) {
   86     $LMon::maxbuffer = $opt_b;
   87 }
   88 
   89 my $line = "";
   90 
   91 if ($opt_s) {
   92     $LMon::sysname = $opt_s;
   93 } else {
   94     $LMon::sysname = (POSIX::uname)[1];
   95 }
   96 if (!$LMon::from) {
   97     $LMon::from = "hostmaster\@$LMon::sysname";
   98 } elsif($opt_F) {
   99     $LMon::from = $opt_F;
  100 }
  101 
  102 
  103 if ($opt_i) {
  104     $LMon::alertstr = "LMon: interesting data in";
  105 } else {
  106     $LMon::alertstr = "LMon: unrecognized data in";
  107 }
  108 
  109 if ($opt_m) {
  110     @LMon::mailserverstxt = split(/ /, $opt_m);
  111     $LMon::mailservers = \@LMon::mailserverstxt;
  112     for (my $i = 0; $i <= $#LMon::mailserverstxt; $i++) {
  113         if ($LMon::mailserverstxt[$i] =~ /^([\s\w\.-_]+)$/) {
  114             # untaint mailserver
  115             $LMon::mailserverstxt[$i] = $1;
  116         } else {
  117             print "Bad data $opt_m in option -m.\n";
  118             exit(1);
  119         }
  120     }
  121     $Mail::Sendmail::mailcfg{'smtp'} = \@LMon::mailserverstxt;
  122 } else {
  123     $Mail::Sendmail::mailcfg{'smtp'} = $LMon::mailservers;
  124 }
  125 
  126 sub errusage {
  127     my $msg = $_[0];
  128     print "$msg\n\n";
  129     usage;
  130     exit(1);
  131 }
  132 
  133 sub sender {
  134     my $text = "$_[0]";
  135     my $subject = "$_[1]";
  136 
  137     for my $recipient (split /([ \s,;])/, $LMon::recipients) {
  138         my %mail = ( To      => "$recipient",
  139                  From    => "$LMon::from",
  140                  Message => "$text",
  141                  Subject => "$subject"
  142         );
  143 
  144     sendmail(%mail);
  145     }
  146 }
  147 
  148 sub isinteresting {
  149     my $str = $_[0];
  150     chomp($str);
  151     my $substr;
  152 
  153     if ($opt_i) {
  154         for (my $i = 0; $i <= $#LMon::reglist; $i++) {
  155             if (substr($LMon::reglist[$i], 0, 1) eq '!') {
  156                 $substr = substr($LMon::reglist[$i], 1);
  157                 if ($str !~ /$substr/) { return(1); }
  158             } else {
  159                 if ($str =~ /$LMon::reglist[$i]/) { return(1); }
  160             }
  161         }
  162         return(0);
  163     } else {
  164         for (my $i = 0; $i <= $#LMon::reglist; $i++) {
  165             if (substr($LMon::reglist[$i], 0, 1) eq '!') {
  166                 $substr = substr($LMon::reglist[$i], 1);
  167                 if ($str !~ /$substr/) { return(0); }
  168             } else {
  169                 if ($str =~ /$LMon::reglist[$i]/) { return(0); }
  170             }
  171         }
  172         return(1);
  173     }
  174 }
  175 
  176 sub sendbuffer {
  177     if($LMon::logbuffertruncated != 0) {
  178         unshift(@LMon::logbuffer, "\n");
  179         unshift(@LMon::logbuffer, "from the top of the file.\n");
  180         unshift(@LMon::logbuffer, "ERROR: Log buffer got full at $LMon::maxbuffer lines. Data has been dropped\n");
  181         $LMon::logbuffertruncated = 0;
  182     }
  183     if ($opt_n) {
  184         sender(join("", @LMon::logbuffer), "$LMon::alertstr $opt_n on $LMon::sysname");
  185     } else {
  186         sender(join("", @LMon::logbuffer), "$LMon::alertstr $opt_f on $LMon::sysname");
  187     }
  188 }
  189 
  190 sub checkbuffer {
  191     if ($#LMon::logbuffer != -1) {
  192         sendbuffer;
  193         @LMon::logbuffer = ();
  194         alarm($LMon::waitsecsnext);
  195     } else {
  196         alarm($LMon::waitsecs);
  197     }
  198 }
  199 
  200 sub fixpidfilename {
  201     if ($opt_p =~ /^([-\w\.\/]+)$/) {
  202         # untaint PID filename
  203         $opt_p = $1;
  204     } else {
  205         print "Bad data $opt_p in option -p.\n";
  206         exit(1);
  207     }
  208 }
  209 
  210 sub writepid {
  211     fixpidfilename;
  212     if (sysopen(PID, $opt_p, O_WRONLY|O_CREAT)) {
  213         print PID "$$\n";
  214     } else {
  215         errusage("ERROR: Could not write pid file.");
  216     }
  217     close(PID);
  218 }
  219 
  220 sub readconf {
  221     sysopen(CONF, $opt_r, O_RDONLY);
  222     @LMon::reglist = ();
  223     my $line = 0;
  224     while (<CONF>) {
  225         my $rule = $_;
  226         $line++;
  227 
  228         next if ($rule =~ /^(#|$)/);
  229         chomp($rule);
  230 
  231         eval { if (/$rule/) {} };
  232         if ($@) {
  233             print STDERR "ABORT, syntax/regexp error on line $line in $opt_r.\n";
  234             print STDERR "Details:\n\n";
  235             print STDERR $@;
  236             close(CONF);
  237             exit(1);
  238         }
  239 
  240         push(@LMon::reglist, $rule);
  241     }
  242     close(CONF);
  243 }
  244 
  245 if (!$opt_f) {
  246     errusage("ERROR: No file to monitor specified, use -f.");
  247 } elsif(! -f $opt_f) {
  248     errusage("ERROR: Logfile $opt_f does not exist/is not a file.");
  249 }
  250 if (!$opt_r) {
  251     errusage("ERROR: No rule file specified, use -r.");
  252 } elsif(! -f $opt_r) {
  253     errusage("ERROR: Rule file $opt_r does not exist/is not a file.");
  254 }
  255 readconf;
  256 if ($opt_d) {
  257     # Detach from controlling terminal
  258     exit 0 if (fork);
  259     chdir($Bin);
  260     close(STDERR);
  261     close(STDOUT);
  262     close(STDIN);
  263     POSIX::setsid;
  264 }
  265 writepid;
  266 
  267 $SIG{ALRM} = sub { checkbuffer; };
  268 alarm($LMon::waitsecs);
  269 
  270 #$LMon::logfile = File::Tail->new($opt_f);
  271 $LMon::logfile = File::Tail->new(name=>$opt_f, maxinterval=>30, interval=>10, tail=>$LMon::lines, reset_tail=>$LMon::resetlines, errmode=>"return");
  272 
  273 while(defined($line=$LMon::logfile->read)) {
  274     if (isinteresting($line)) {
  275         if (($#LMon::logbuffer+1) >= $LMon::maxbuffer && $LMon::maxbuffer != 0) {
  276             if ($LMon::logbuffertruncated == 0) {
  277                 $LMon::logbuffertruncated = 1;
  278             }
  279             shift(@LMon::logbuffer);
  280             push(@LMon::logbuffer, $line);
  281         } else {
  282             push(@LMon::logbuffer, $line);
  283         }
  284     }
  285 }