From c6bc020851a3604554b2035560fa9f6b3aa5cf2b Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Tue, 21 Mar 2006 17:54:32 +0000 Subject: [PATCH] Neu dazu --- LogRotate/StateFile.pm | 362 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 LogRotate/StateFile.pm diff --git a/LogRotate/StateFile.pm b/LogRotate/StateFile.pm new file mode 100644 index 0000000..2f1bbc0 --- /dev/null +++ b/LogRotate/StateFile.pm @@ -0,0 +1,362 @@ +package LogRotate::StateFile; + +# $Id$ +# $URL$ + +=head1 NAME + +B - Logrotate Statusdatei Modul + +=head1 SYNOPSIS + + my $statefile = new LogRotate::StateFile(); + + $statefile->verbose(2); + $statefile->file('/var/lib/logrotate.status'); + + if ( $statefile->check() ) { ... + + $last_rotated_files = $statefile->read(); + + ... + + $statefile->write_logfile('/var/log/messages'); + +=cut + +use strict; +use 5.8.0; +use warnings; + +use Carp qw(:DEFAULT cluck); + +#------------------------------------------------------------------------------------ + +use Data::Dumper; +use POSIX qw( mktime ); +use Cwd qw(cwd getcwd abs_path); + +our $AUTOLOAD; +our %ok_field; + +my $MainVersion = "2.0"; + +my $Revis = <<'ENDE'; + $Revision$ +ENDE +$Revis =~ s/^.*:\s*(\S+)\s*\$.*/$1/s; +our $VERSION = $MainVersion . "." . $Revis; + +$Data::Dumper::Indent = 1; +$Data::Dumper::Sortkeys = 1; + +use constant default_firstline_statusfile => "Logrotate State -- Version 3"; + +my @ValidFields = qw( parent verbose file test ); + +for my $attr ( @ValidFields ) { + $ok_field{$attr}++; +} + +#------------------------------------------------------------------------------------ + +=head1 Funktionen + +=head2 sub new() - Konstruktor + +Wird aufgerufen, um ein neues LogRotate::StateFile-Objekt zu erstellen. + +=cut + +sub new { + + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my ( $res, $cmd ); + + my $self = { + 'verbose' => 0, + 'file' => '/val/lib/logrotate.status', + @_ + }; + + $res = bless $self, $class; + + my $p = $self->verbose() ? __PACKAGE__ . "::new(): " : ""; + + return $res; + +} + +#------------------------------------------------------------------------------------------ + +=head2 AUTOLOAD() + +Autoload-Methode zum Zugriff auf alle möglichen Elemente. + +=cut + +sub AUTOLOAD { + + my $self = shift; + my $attr = $AUTOLOAD; + my ( $val ); + + $attr =~ s/.*:://; + $attr = lc($attr); + + croak "Ungueltige Attributmethode ->$attr()" unless $ok_field{$attr}; + + return $self->file(@_) if $attr eq "file"; + return $self->test(@_) if $attr eq "test"; + return $self->verbose(@_) if $attr eq "verbose"; + + if ( @_ ) { + $val = shift; + $self->{uc($attr)} = $val; + } + return $self->{uc($attr)}; + +} + +#------------------------------------------------------------------------------------------ + +=head2 check( [$file] ) + + + +=cut + +sub check($;$) { + + my $self = shift; + my $file = shift; + my $p = $self->verbose() ? __PACKAGE__ . "::check(): " : ""; + + print $p . "Aufgerufen mit '" . ( defined $file ? $file : "" ) . "'.\n" if $self->verbose() > 2; + + my $res = $self->read($file); + + return undef unless $res; + $file = $self->{'file'}; + + unless ( $self->test() ) { + if ( open FILE, ">>$file" ) { + close FILE; + } else { + warn $p . "Fehler beim Oeffnen der Status-Datei '$file' zum Schreiben: $!\n"; + return undef; + } + } + + return $res; + +} + +#------------------------------------------------------------------------------------------ + +=head2 read( [$file] ) + +Liest die uebergebene Datei in die Konfiguration ein. + +Wenn der Parameter $file nicht uebergeben wurde, wird statt dessen $self->{'file'} +verwendet, welches auch gesetzt wird, wenn $file uebergeben wurde. + +Bei Erfolg wird eine Datenstruktur als Hash-Ref uebergeben, deren +Keys die aus der Datei gelesenen Logdateien sind und deren Values die Zeitstempel +der rotierten Logdateien. + +Bei Misserfolg wird C zurueckgegeben. + +=cut + +sub read($;$) { + + my $self = shift; + my $file = shift; + my $p = $self->verbose() ? __PACKAGE__ . "::read(): " : ""; + + my $res = {}; + + print $p . "Aufgerufen mit '" . ( defined $file ? $file : "" ) . "'.\n" if $self->verbose() > 2; + + my ( $f, $dir, $real_dir, $logfile, $date, $time_t ); + + $file = $self->{'file'} unless $file; + unless ( $file ) { + carp $p . "Keine Datei uebergeben.\n"; + return undef; + } + + if ( $file =~ m#/# ) { + ( $dir, $f ) = $file =~ m#(.*)/([^/]+)$#; + } else { + $dir = "."; + $f = $file; + } + $real_dir = abs_path( $dir ); + print $p . "Real-Path: '$real_dir', Basename: '$f'\n" if $self->{'verbose'} > 2; + $f = $real_dir . "/" . $f; + + + unless ( -f $file ) { + warn $p . "Datei '$file' existiert nicht oder ist keine normale Datei.\n"; + $self->{'file'} = $f; + return $res; + } + + print $p . "Lese Datei '$f' ...\n" if $self->verbose(); + unless ( open FILE, "<$f" ) { + warn $p . "Konnte Datei '$f' nicht oeffnen: $!\n"; + return undef; + } + + my $i = 0; + while ( ) { + + $i++; + s/^\s+//; + s/\s+$//; + + if ( $i == 1 ) { + if ( /^logrotate\s+state\s+-+\s+version\s+[123]$/i ) { + next; + } else { + warn $p . "Inkompatible Version der Statusdatei '$f'.\n"; + close FILE; + return undef; + } + } + + next unless $_; + + ( $logfile, $date ) = $self->parts( $_ ); + if ( $logfile and $date ) { + my @Date = $date =~ /^\s*(\d+)[_\-](\d+)[_\-](\d+)(?:[\s\-_]+(\d+)[_\-:](\d+)[_\-:](\d+))?/; + unless ( @Date ) { + warn $p . "Konnte Datum nicht erkennen: '$date' (Datei '$f', Zeile $.).\n"; + close FILE; + return undef; + } + $time_t = mktime( $Date[5] || 0, $Date[4] || 0, $Date[3] || 0, $Date[2], $Date[1] - 1, $Date[0] - 1900 ); + unless ( $time_t ) { + warn $p . "Unbekanntes Datumsformat: '$date' (Datei '$f', Zeile $.).\n"; + close FILE; + return undef; + } + } + + $res->{$logfile} = $time_t; + + } + + close FILE; + $self->{'file'} = $f; + return $res; + +} + +#------------------------------------------------------------------------------------------ + +=head2 file() + +Setzt bzw. gibt die Status-Datei dieses Moduls zurueck. + +=cut + +sub file($;$) { + + my $self = shift; + my $nv; + if ( @_ ) { + $nv = shift; + $self->{'file'} = $nv if defined $nv; + } + return $self->{'file'}; + +} + +#------------------------------------------------------------------------------------ + +=head2 parts( $string ) + +Zerlegt einen String an Whitespaces in seine Bestandteile unter Beachtung +von Quotierung und gibt diese als Array zurueck. + +=cut + +sub parts($$) { + + my $self = shift; + my $p = $self->verbose() ? __PACKAGE__ . "::parts(): " : ""; + + my $term = shift; + my @Parts = (); + my $part; + + while ( $term =~ /"([^"\\]*(?:\\.[^"\\]*)*)"|(\S+)/g ) { + $part = $1 || $2; + $part =~ s/\\"/"/g; + push @Parts, $part; + } + + return @Parts; + +} + +#------------------------------------------------------------------------------------------ + +=head2 test() + +Setzt bzw. gibt den Test-Modus dieses Moduls zurueck. + +=cut + +sub test($;$) { + + my $self = shift; + my $nv; + if ( @_ ) { + $nv = shift; + $self->{'test'} = $nv; + } + return $self->{'test'}; + +} + +#------------------------------------------------------------------------------------------ + +=head2 verbose() + +Setzt bzw. gibt den Verbose-Level dieses Moduls zurueck. + +=cut + +sub verbose($;$) { + + my $self = shift; + my $nv; + if ( @_ ) { + $nv = shift; + $nv = defined $nv ? ( $nv =~ /(\d+)/ ? $1 : 0 ) : 0; + $self->{'verbose'} = $nv; + } + return $self->{'verbose'}; + +} + +#------------------------------------------------------------------------------------------ + +1; + +__END__ + +#------------------------------------------------------------------------------------------ + +=head1 AUTHOR + +Frank Brehm + +=cut + + -- 2.39.5