From fde6a62aac59ec1ce1326b946f38081710d48b0c Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Tue, 21 Mar 2006 15:49:58 +0000 Subject: [PATCH] Weitergemacht --- LogRotate/Conf.pm | 707 ++++++++++++++++++++++++++++++++++++++++++---- logrotate.pl | 39 +-- 2 files changed, 676 insertions(+), 70 deletions(-) diff --git a/LogRotate/Conf.pm b/LogRotate/Conf.pm index 350343d..b3d0459 100644 --- a/LogRotate/Conf.pm +++ b/LogRotate/Conf.pm @@ -56,10 +56,19 @@ for my $attr ( @ValidFields ) { } my %ValidPeriods = ( + 'hourly' => (1/24), + '2hourly' => (2/24), + '4hourly' => (4/24), + '6hourly' => (6/24), + '12hourly' => (12/24), 'daily' => 1, - 'weekly' => 1, - 'monthly' => 1, - 'yearly' => 1, + '2daily' => 2, + 'weekly' => 7, + 'monthly' => 30.4, + '2monthly' => 60.8, + '4monthly' => 121.7, + '6monthly' => 182.5, + 'yearly' => 365, ); my @StandardCompressPrograms = ( @@ -74,6 +83,13 @@ my %StandardCompressPrograms = ( 'compress' => '.Z', ); +my %ScriptDirectives = ( + 'postrotate' => 1, + 'prerotate' => 1, + 'firstaction' => 1, + 'lastaction' => 1, +); + #use constant default_firstline_statusfile => "Logrotate State -- Version 2"; #use constant default_buffer_size => 4096; #use constant max_rotate => 100000; @@ -98,6 +114,8 @@ sub new { 'verbose' => 0, 'included_files' => {}, 'compress_cmd' => 'Compress::Zlib', + 'pidfile' => '/var/run/logrotate.pid', + 'statusfile' => '/var/lib/logrotate.status', 'COMPRESSEXT' => ".gz", 'COMPRESSOPTIONS' => "", 'scripts' => {}, @@ -364,40 +382,6 @@ sub compress_cmd($;$) { #------------------------------------------------------------------------------------------ -=head2 compress_statement( $_, $f, $in_fd, $linenr ); - -Setzt als logischen Wert, ob die Logdateien komprimiert werden sollen oder nicht. - -=cut - -sub compress_statement($$$$$) { - - my $self = shift; - my $line = shift || ""; - my $f = shift || "'unknown'"; - my $in_fd = shift || 0; - my $linenr = shift || "'unknown'"; - my $p = $self->verbose() ? __PACKAGE__ . "::compress_statement(): " : ""; - - if ( $self->{'compress_cmd'} ) { - if ( $in_fd ) { - $self->{'newfile'}{'compress'} = 1; - } else { - $self->{'default'}{'compress'} = 1; - } - } else { - warn $p . "Kompression unmoeglich, kein Kompressions-Kommando gegeben (Datei '$f', Zeile '$f')\n" if $self->{'verbose'} > 1; - if ( $in_fd ) { - $self->{'newfile'}{'compress'} = undef; - } else { - $self->{'default'}{'compress'} = undef; - } - } - -} - -#------------------------------------------------------------------------------------------ - =head2 compresscmd_statement( $_, $f, $in_fd, $linenr ); Gibt ein alternatives Kompressionsprogramm fuer Logdateien an. @@ -823,7 +807,12 @@ sub default_period($;$) { $nv = shift; if ( defined $nv ) { $nv = lc($nv); - $self->{'default'}{'period'} = $nv if $ValidPeriods{$nv}; + if ( $ValidPeriods{$nv} ) { + $self->{'default'}{'period'} = $ValidPeriods{$nv}; + } else { + $nv = $self->period2days($nv); + $self->{'default'}{'period'} = $nv if defined $nv; + } } } return $self->{'default'}{'period'}; @@ -875,6 +864,419 @@ sub default_size($;$) { #------------------------------------------------------------------------------------------ +=head2 directive( $_, $f, $in_fd, $linenr ); + +Wertet die aktuelle Direktive aus und setzt entsprechende Werte in der aktuellen +oder der Default-Logfile-Definition. + +=cut + +sub directive($$$$$) { + + my $self = shift; + my $line = shift || ""; + my $f = shift || "'unknown'"; + my $in_fd = shift || 0; + my $linenr = shift || "'unknown'"; + my $p = $self->verbose() ? __PACKAGE__ . "::directive(): " : ""; + + print $p . "Untersuche '$line' (Datei '$f', Zeilennr $linenr) ...\n" if $self->verbose() > 5; + my ( $directive, $val ) = $line =~ /^(\S+)\s*(.*)/; + my ( $key, $negated, $name, $pattern, $wert ); + my ( @Values ); + my $wo = $in_fd ? 'newfile' : 'default'; + $directive = lc($directive); + + my %GlobalDirectives = ( + 'compresscmd' => 1, + 'statusfile' => 1, + 'pidfile' => 1, + 'compressext' => 1, + 'compressoptions' => 1, + ); + + my %BoolDirectives = ( + 'compress' => 1, + 'copytruncate' => 1, + 'ifempty' => 1, + 'missingok' => 1, + 'sharedscripts' => 1, + ); + + my %DirectivesWithValues = ( + 'compresscmd' => 1, + 'statusfile' => 1, + 'pidfile' => 1, + 'compressext' => 1, + 'rotate' => 1, + 'maxage' => 1, + ); + + my %PathDirectives = ( + 'statusfile' => 1, + 'pidfile' => 1, + ); + + my %UnsupportedDirectives = ( + '(?:no)?mail' => 1, + 'mail(?:first|last)' => 1, + 'uncompresscmd' => 1, + 'error' => 1, + ); + + my %IntegerDirectives = ( + 'delaycompress' => 1, + 'rotate' => 1, + 'maxage' => 1, + 'start' => 1, + ); + + my %StringDirectives = ( + 'extension' => 1, + ); + + my %YesValues = ( + '1' => 1, + 'on' => 1, + 'yes' => 1, + 'ja' => 1, + 'y' => 1, + 'j' => 1, + ); + + my %NoValues = ( + '0' => 1, + 'off' => 1, + 'no' => 1, + 'nein' => 1, + 'n' => 1, + ); + + + # Jetzt nicht unterstuetzte Direktiven ... + $pattern = join( "|", keys %UnsupportedDirectives ); + if ( $directive =~ /^($pattern)$/i ) { + $key = lc($1); + warn $p . "Direktive '$key' wird nicht unterstuetzt (Datei '$f', Zeile $linenr).\n"; + return 1; + } + + # jetzt die Logischen Werte untersuchen ... + $pattern = join( "|", keys %BoolDirectives ); + if ( $directive =~ /^(not?)?($pattern)$/i ) { + $negated = $1; + $key = lc($2); + print $p . "Untersuche boolsche Direktive '$key' ...\n" if $self->verbose() > 5; + if ( defined $val and $val ne "" ) { + warn $p . "Wert '$val' hinter logischer Direktive $directive gefunden (Datei '$f', Zeile $linenr)\n"; + } + $val = $negated ? 0 : 1; + if ( $key eq 'compress' and not $self->{'compress_cmd'} and $val ) { + warn $p . "Kompression unmoeglich, kein Kompressions-Kommando gegeben (Datei '$f', Zeile $linenr)\n"; + $val = 0; + } + print $p . "Setze '$key' in '$wo' auf $val.\n" if $self->verbose() > 5; + $self->{$wo}{$key} = $val; + return 1; + } + + # und nun die Integer-Direktiven ... + $pattern = join( "|", keys %IntegerDirectives ); + if ( $directive =~ /^(not?)?($pattern)$/i ) { + $negated = $1; + $key = lc($2); + print $p . "Untersuche Integer-Direktive '$key' ...\n" if $self->verbose() > 5; + if ( $DirectivesWithValues{$key} ) { + print $p . "Direktive '$key' muss einen Wert haben.\n" if $self->verbose() > 5; + unless ( defined $val and $val !~ /^\s*$/ ) { + warn $p . "Direktive '$key' ohne erforderlichen Wert angegeben (Datei '$f', Zeile $linenr).\n"; + return 1; + } + } + if ( $negated ) { + $wert = 0; + } else { + if ( not defined($val) or $val =~ /^\s*$/ ) { + $wert = 1; + } else { + $wert = $self->to_int($val); + } + } + unless ( defined $wert ) { + warn $p . "Ungueltiger Wert '$val' fuer Direktive '$key' (Datei '$f', Zeile $linenr).\n"; + return 1; + } + $self->{$wo}{$key} = $wert + 0; + return 1; + } + + # und hier allgemeine String-Direktiven + $pattern = join( "|", keys %StringDirectives ); + if ( $directive =~ /^($pattern)$/i ) { + $negated = $1; + $key = lc($2); + print $p . "Untersuche String-Direktive '$key' ...\n" if $self->verbose() > 5; + if ( $DirectivesWithValues{$key} ) { + print $p . "Direktive '$key' muss einen Wert haben.\n" if $self->verbose() > 5; + unless ( defined $val and $val !~ /^\s*$/ ) { + warn $p . "Direktive '$key' ohne erforderlichen Wert angegeben (Datei '$f', Zeile $linenr).\n"; + return 1; + } + } + if ( $negated ) { + $val = ""; + } + $wert = defined $val ? $val : ""; + $self->{$wo}{$key} = $wert; + return 1; + } + + # Jetzt die Werte, die nur ausserhalb von Logfile-Definitionen gueltig sind + $pattern = join( "|", keys %GlobalDirectives ); + if ( $directive =~ /^($pattern)$/i ) { + $key = lc($1); + print $p . "Untersuche globale Direktive '$key' ...\n" if $self->verbose() > 5; + if ( $in_fd ) { + warn $p . "Direktive '$key' ist nicht innerhalb von Logdatei-Definitionen erlaubt (Datei '$f', Zeile $linenr).\n"; + return 1; + } + if ( $DirectivesWithValues{$key} ) { + print $p . "Direktive '$key' muss einen Wert haben.\n" if $self->verbose() > 5; + unless ( defined $val and $val ne "" ) { + warn $p . "Direktive '$key' ohne erforderlichen Wert angegeben (Datei '$f', Zeile $linenr).\n"; + return 1; + } + } + $val = "" if $key eq "compressoptions" and not defined $val; + if ( $key eq 'compresscmd' ) { + if ( $name = $self->check_compress_program( $val ) ) { + print $p . "Setze 'compress_cmd' auf '$name'.\n" if $self->verbose() > 4; + $self->{'compress_cmd'} = $name; + return 1; + } + warn $p . "Das gegebene Kompressions-Kommando ist ungueltig, verwende das alte " . + "Kommando '" . $self->{'compress_cmd'} . "' (Datei '$f', Zeile '$f').\n"; + } + if ( $PathDirectives{$key} ) { + unless ( $val =~ m#^/# ) { + warn $p . "Direktive '$key' erfordert absolute Pfadangaben ( '$val' in Datei '$f', Zeile $linenr).\n"; + return 1; + } + } + print $p . "Setze '$key' auf '$val'.\n" if $self->verbose() > 4; + $self->{$key} = $val; + return 1; + } + + # Rotations-Periode ermitteln + $pattern = join( "|", 'period', keys %ValidPeriods ); + if ( $directive =~ /^($pattern)$/i ) { + + $key = lc($1); + print $p . "Untersuche Rotations-Perioden-Direktive '$key' ...\n" if $self->verbose() > 5; + + if ( $ValidPeriods{$key} ) { + warn $p . "Direktive '$key' darf keine Argumente haben ( '$val' in Datei '$f', Zeile $linenr).\n" + if defined $val and $val !~ /^\s*$/; + $val = $ValidPeriods{$key}; + } else { + $val = $self->period2days($val); + unless ( defined $val ) { + warn $p . "Ungueltige Perioden-Definition (Datei '$f', Zeile $linenr).\n"; + return 1; + } + } + + print $p . "Setze Periode in '$wo' auf '$val'.\n" if $self->verbose() > 5; + $self->{$wo}{'period'} = $val; + return 1; + } + + # Datumserweiterung der rotierten Logdateien festlegen ... + if ( $directive =~ /^(no)?dateext$/ ) { + + $negated = $1; + print $p . "Untersuche Direktive 'dateext' ...\n" if $self->verbose() > 5; + @Values = $val ? $self->parts( $val ) : (); + + if ( $negated ) { + $val = 0; + $name = undef; + } else { + $val = lc( defined $Values[0] ? $Values[0] : '' ); + $val = 1 if $val =~ /^\s*$/; + if ( $YesValues{$val} ) { + $val = 1; + $name = undef; + } elsif ( $NoValues{$val} ) { + $val = 0; + $name = undef; + } else { + $name = $val; + $val = 1; + } + } + + print $p . "Setze dateext in '$wo' auf $val.\n" if $self->verbose() > 5; + $self->{$wo}{'dateext'} = $val; + + if ( defined $name ) { + print $p . "Setze datepattern in '$wo' auf '$name'.\n" if $self->verbose() > 5; + $self->{$wo}{'datepattern'} = $name; + } + return 1; + + } + + # Erstellungs-Modi festlegen + if ( $directive eq 'create' ) { + + print $p . "Untersuche Direktive 'create' ...\n" if $self->verbose() > 5; + @Values = $val ? $self->parts( $val ) : (); + $self->{$wo}{'copytruncate'} = 0; + + # Mode (Permission) definition + if ( defined $Values[0] ) { + if ( $Values[0] =~ /^\d+$/ ) { + $self->{$wo}{'create'}{'mode'} = oct( $Values[0] ); + } else { + warn $p . "Directive 'create' mit ungueltigem Modus '" . $Values[0] . "' (Datei '$f', Zeile '$f').\n"; + } + } + + # User (owner, uid) definition + if ( defined $Values[1] and $Values[1] ne "" ) { + if ( $Values[1] =~ /^[1-9]\d*$/ ) { + $self->{$wo}{'create'}{'owner'} = $Values[1]; + } else { + $self->{$wo}{'create'}{'owner'} = scalar getpwnam( $Values[1] ); + } + } + + # Group (gid) definition + if ( defined $Values[2] and $Values[2] ne "" ) { + if ( $Values[2] =~ /^[1-9]\d*$/ ) { + $self->{$wo}{'create'}{'group'} = $Values[2]; + } else { + $self->{$wo}{'create'}{'group'} = scalar getgrnam( $Values[2] ); + } + } + + return 1; + + } + + # Olddir-Verhalten festlegen ... + if ( $directive =~ /^(not?)?olddir$/i ) { + + $negated = $1; + $directive = 'olddir'; + + print $p . "Untersuche Direktive 'olddir' ...\n" if $self->verbose() > 5; + + if ( $negated ) { + print $p . "Direktive 'olddir' wird in '$wo' enfernt.\n" if $self->verbose() > 5; + $self->{$wo}{'olddir'} = undef; + return 1; + } + + @Values = $val ? $self->parts( $val ) : (); + + if ( $Values[0] ) { + $self->{$wo}{'olddir'} = {} unless $self->{$wo}{'olddir'}; + $self->{$wo}{'olddir'}{'dirname'} = $Values[0]; + } else { + warn $p . "Direktive '$directive' ohne erforderlichen Wert angegeben (Datei '$f', Zeile $linenr).\n"; + return 1; + } + + $self->{$wo}{'olddir'}{'mode'} = undef; + $self->{$wo}{'olddir'}{'owner'} = undef; + $self->{$wo}{'olddir'}{'group'} = undef; + + # Mode (Permission) definition + if ( defined $Values[1] ) { + if ( $Values[0] =~ /^\d+$/ ) { + $self->{$wo}{'olddir'}{'mode'} = oct( $Values[1] ); + } else { + warn $p . "Directive 'olddir' mit ungueltigem Modus '" . $Values[1] . "' (Datei '$f', Zeile '$f').\n"; + } + } + + # User (owner, uid) definition + if ( defined $Values[2] and $Values[2] ne "" ) { + if ( $Values[1] =~ /^[1-9]\d*$/ ) { + $self->{$wo}{'olddir'}{'owner'} = $Values[2]; + } else { + $self->{$wo}{'olddir'}{'owner'} = scalar getpwnam( $Values[2] ); + } + } + + # Group (gid) definition + if ( defined $Values[3] and $Values[3] ne "" ) { + if ( $Values[2] =~ /^[1-9]\d*$/ ) { + $self->{$wo}{'olddir'}{'group'} = $Values[3]; + } else { + $self->{$wo}{'olddir'}{'group'} = scalar getgrnam( $Values[3] ); + } + } + + return 1; + + } + + # Rotations-Mindestgroesse ermitteln + if ( $line =~ /^size(?:\s*(?:=|\s)\s*(.*)?)?$/i ) { + $directive = 'size'; + $val = $1; + print $p . "Untersuche Direktive 'size' mit Groesse '" . (defined $val ? $val : "") . "' ...\n" if $self->verbose() > 5; + unless ( defined $val ) { + warn $p . "Ungueltige Groessen-Definition (Datei '$f', Zeile $linenr).\n"; + return 1; + } + $wert = $self->human2byte($val); + unless ( defined $wert ) { + warn $p . "Ungueltige Groessen-Definition ('$val' in Datei '$f', Zeile $linenr).\n"; + return 1; + } + print $p . "Setze Groesse in '$wo' auf '$wert'.\n" if $self->verbose() > 5; + $self->{$wo}{'size'} = $wert; + return 1; + } + + # Tabu-Pattern aendern bzw. hinzufuegen + if ( $directive =~ /^taboo(ext|file|prefix)$/ ) { + + $key = lc($1); + print $p . "Untersuche globale Direktive '$key' ...\n" if $self->verbose() > 5; + + if ( $in_fd ) { + warn $p . "Direktive '$directive' ist nicht innerhalb von Logdatei-Definitionen erlaubt (Datei '$f', Zeile $linenr).\n"; + return 1; + } + + @Values = $val ? $self->parts( $val ) : (); + my $extend = 0; + if ( $Values[0] and $Values[0] eq "+" ) { + $extend = 1; + shift @Values; + } + + $self->{'taboo'} = [] unless $extend; + for $name ( @Values ) { + $self->add_taboo( $name, $key ); + } + + return 1; + } + + warn $p . "Unbekannte Direktive '$directive' (Datei '$f', Zeile $linenr).\n"; + return 1; + +} + +#------------------------------------------------------------------------------------------ + =head2 do_include( $zeile, $file, $in_fd, $linenr ) Fuehrt eine Include-Anweisung aus. @@ -985,6 +1387,95 @@ sub do_include($$$$$) { #------------------------------------------------------------------------------------------ +=head2 do_logfilescript( $_, $f, $in_fd, $linenr ); + +Wertet den Beginn einer Script-Definition innerhalb einer Logfile-Definition aus. + +=cut + +sub do_logfilescript($$$$$) { + + my $self = shift; + my $line = shift || ""; + my $f = shift || "'unknown'"; + my $in_fd = shift || 0; + my $linenr = shift || "'unknown'"; + my $p = $self->verbose() ? __PACKAGE__ . "::do_logfilescript(): " : ""; + + print $p . "Scriptdefinition '$line' (Datei '$f', Zeilennr $linenr) ...\n" if $self->verbose() > 5; + my ( $directive, $val ) = $line =~ /^(\S+)\s*(.*)/; + $directive = lc($directive); + + unless ( $in_fd ) { + warn $p . "Direktive '$directive' ist nicht erlaubt ausserhalb einer Logfile-Definition (Datei '$f', Zeile $linenr).\n"; + return undef; + } + + my @Values = $val ? $self->parts( $val ) : (); + + my $name; + if ( $Values[0] ) { + $self->{'newfile'}{$directive} = lc($Values[0]); + return undef; + } else { + $name = $self->new_script_name($directive); + $self->{'scripts'}{$name}{'cmd'} = []; + $self->{'scripts'}{$name}{'post'} = 0; + $self->{'scripts'}{$name}{'prerun'} = 0; + $self->{'newfile'}{$directive} = $name; + return $name; + } + + return undef; +} + +#------------------------------------------------------------------------------------------ + +=head2 do_script( $_, $f, $in_fd, $linenr ); + +Wertet den Beginn einer allgemeinen Script-Definition. + +=cut + +sub do_script($$$$$) { + + my $self = shift; + my $line = shift || ""; + my $f = shift || "'unknown'"; + my $in_fd = shift || 0; + my $linenr = shift || "'unknown'"; + my $p = $self->verbose() ? __PACKAGE__ . "::do_script(): " : ""; + + print $p . "Scriptdefinition '$line' (Datei '$f', Zeilennr $linenr) ...\n" if $self->verbose() > 5; + my ( $directive, $val ) = $line =~ /^(\S+)\s*(.*)/; + $directive = lc($directive); + + if ( $in_fd ) { + warn $p . "Direktive '$directive' ist nicht erlaubt innerhalb einer Logfile-Definition (Datei '$f', Zeile $linenr).\n"; + return undef; + } + + my @Values = $val ? $self->parts( $val ) : (); + + unless ( $Values[0] ) { + warn $p . "Direktive '$directive' ohne gueltigen Scriptnamen (Datei '$f', Zeile $linenr).\n"; + return undef; + } + + my $name = lc($Values[0]); + if ( $self->{'scripts'}{$name} ) { + warn $p . "Das Script '$name' ist bereits deklariert, wird ueberschrieben (Datei '$f', Zeile $linenr).\n"; + } + + $self->{'scripts'}{$name}{'cmd'} = []; + $self->{'scripts'}{$name}{'post'} = 0; + $self->{'scripts'}{$name}{'prerun'} = 0; + return $name; + +} + +#------------------------------------------------------------------------------------------ + =head2 human2byte( $wert ) Wandelt eine Bytzahl, die fuer den Menschen lesbar ist, in einen Integer-Wert von Bytes um. @@ -1007,7 +1498,7 @@ sub human2byte($$) { my ( $unit, $factor ); - if ( $val =~ /^\s*(\d+(?:\.\d*))\s*(?:([kmg])(?:b|byte))?\s*$/i ) { + if ( $val =~ /^\s*(\d+(?:\.\d*)?)\s*(?:([kmg])(?:b|byte)?)?\s*$/i ) { $factor = 1; $val = $1 + 0; $unit = lc( $2 || 'b' ); @@ -1100,8 +1591,12 @@ sub log_begin($$$$$) { $self->{'newfile'}{'files'} = [ @Files ]; $self->{'newfile'}{'create'} = {}; %{$self->{'newfile'}{'create'}} = %{$self->{'default'}{'create'}}; - $self->{'newfile'}{'olddir'} = {}; - %{$self->{'newfile'}{'olddir'}} = %{$self->{'default'}{'olddir'}}; + if ( $self->{'default'}{'olddir'} ) { + $self->{'newfile'}{'olddir'} = {}; + %{$self->{'newfile'}{'olddir'}} = %{$self->{'default'}{'olddir'}}; + } else { + $self->{'newfile'}{'olddir'} = undef; + } } return 1; @@ -1147,6 +1642,7 @@ sub log_end($$$$$) { } delete $self->{'logfiles'}{$name}{'files'} if $self->{'logfiles'}{$name}{'files'}; $self->{'scripts'}{ $self->{'newfile'}{'postrotate'} }{'post'}++ if $self->{'newfile'}{'postrotate'}; + $self->{'scripts'}{ $self->{'newfile'}{'lastaction'} }{'post'}++ if $self->{'newfile'}{'lastaction'}; } return 1; @@ -1217,6 +1713,94 @@ sub parts($$) { #------------------------------------------------------------------------------------------ +=head2 period2days( $period_string ) + +Wandelt eine Perioden-Angabe der Form "5d 8h" in eine Anzahl von Tagen um. + +=cut + +sub period2days($$) { + + my $self = shift; + my $period = shift; + my $p = $self->verbose() ? __PACKAGE__ . "::period2days(): " : ""; + + $period = "" unless defined $period; + my $orig = $period; + print $p . "Aufgerufen mit '" . $period . "'.\n" if $self->verbose() > 5; + $period =~ s/^\s+//; + $period =~ s/\s+$//; + + if ( $period eq "" ) { + warn $p . "Ungültige Periodenangabe.\n"; + return undef; + } + + if ( $period =~ /^now$/i ) { + # Rotation immer sofort + return 0; + } + + if ( $period =~ /^never$/i ) { + # Rotation in 400 Jahren (also hoffentlich nie) + return 36525 * 4; + } + + my $days = undef; + my $t = 0; + + if ( $period =~ /(\d+)\s*h(?:ours?)?/i ) { + $t = $1; + print $p . "$t Stunden.\n" if $self->verbose() > 5; + $t /= 24; + $days += $t; + $period =~ s/\d+\s*h(?:ours?)?//i; + } + print $p . "Noch uebrig nach Stunden: '$period'.\n" if $self->verbose() > 5; + + if ( $period =~ /(\d+(?:\.\d*)?)\s*w(?:eeks?)?/i ) { + $t = $1; + print $p . "$t Wochen.\n" if $self->verbose() > 5; + $t *= 7; + $days += $t; + $period =~ s/\d+(?:\.\d*)?\s*w(?:eeks?)?//i; + } + print $p . "Noch uebrig nach Wochen: '$period'.\n" if $self->verbose() > 5; + + if ( $period =~ /(\d+(?:\.\d*)?)\s*m(?:onths?)?/i ) { + $t = $1; + print $p . "$t Monate.\n" if $self->verbose() > 5; + $t *= 30.4; + $days += $t; + $period =~ s/\d+(?:\.\d*)?\s*m(?:onths?)?//i; + } + print $p . "Noch uebrig nach Monaten: '$period'.\n" if $self->verbose() > 5; + + if ( $period =~ /(\d+(?:\.\d*)?)\s*y(?:ears?)?/i ) { + $t = $1; + print $p . "$t Jahre.\n" if $self->verbose() > 5; + $t *= 365; + $days += $t; + $period =~ s/\d+(?:\.\d*)?\s*y(?:ears?)?//i; + } + print $p . "Noch uebrig nach Jahren: '$period'.\n" if $self->verbose() > 5; + + if ( $period =~ /(\d+(?:\.\d*)?)\s*(?:d(?:ays?)?\s*)?$/i ) { + $t = $1; + print $p . "$t Tage.\n" if $self->verbose() > 5; + $days += $t; + $period =~ s/\d+(?:\.\d*)?\s*(?:d(?:ays?)?\s*)?$//i; + } + print $p . "Noch uebrig nach Tagen: '$period'.\n" if $self->verbose() > 5; + + warn $p . "Ungueltige Angabe einer Periode: '" . $orig . "'.\n" unless $period =~ /^\s*$/; + + return $days; + +} + +#------------------------------------------------------------------------------------------ + =head2 read( $file ) Liest die uebergebene Datei in die Konfiguration ein. @@ -1229,7 +1813,7 @@ sub read($$) { my $file = shift; my $p = $self->verbose() ? __PACKAGE__ . "::read(): " : ""; - my ( $dir, $f, $real_dir, $linenr, $in_fd, $in_script, $newscript, $lastrow ); + my ( $dir, $f, $real_dir, $linenr, $in_fd, $in_script, $newscript, $lastrow, $pattern ); my ( @Lines ); print $p . "Aufgerufen mit '" . $file . "'.\n" if $self->verbose() > 2; @@ -1261,7 +1845,7 @@ sub read($$) { $self->{'configfiles'}{$f} = 1; - print $p . "Lese Datei '$f' ...\n" if $self->{'verbose'}; + print $p . "Lese Datei '$f' ...\n"; unless ( open FILE, "<$f" ) { warn $p . "Konnte Datei '$f' nicht oeffnen: $!\n"; return undef; @@ -1309,28 +1893,45 @@ sub read($$) { next; } + # Beginn Logfile-Definition if ( /{$/ ) { return undef unless $in_fd = $self->log_begin( $_, $f, $in_fd, $linenr ); next; } + # Ende Logfile-Definition if ( /^}/ ) { return undef unless $self->log_end( $_, $f, $in_fd, $linenr ); $in_fd = 0; next; } + # Includes ... if ( /^include\s/i ) { return undef unless $self->do_include( $_, $f, $in_fd, $linenr ); next; } - if ( /^compress$/i ) { - $self->compress_statement( $_, $f, $in_fd, $linenr ); + # Beginn Script-Definition fuer Logfile + $pattern = join( "|", keys %ScriptDirectives ); + if ( /^$pattern(?:\s+.*)?$/i ) { + $in_script = 1 if $newscript = $self->do_logfilescript( $_, $f, $in_fd, $linenr ); next; } + # Beginn allgemeine Script-Definition + if ( /^script\s/i ) { + $in_script = 1 if $newscript = $self->do_script( $_, $f, $in_fd, $linenr ); + next; + } + # alle sonstigen Direktiven + if ( $self->directive($_, $f, $in_fd, $linenr ) ) { + next; + } else { + warn $p . "Schwerer Fehler beim Lesen der Konfigdatei '$f', Zeile Nr. $linenr: '$_'.\n"; + return undef; + } } @@ -1357,21 +1958,21 @@ sub reset_defaults($) { print $p . "Setze \$self->{'defaults'} auf Vorgabewerte zurueck.\n" if $self->verbose > 3; $self->{'default'} = { - 'compress' => 0, - 'copytruncate' => 0, + 'compress' => undef, + 'copytruncate' => undef, 'create' => { 'mode' => 0644, 'owner' => $uid, 'group' => $gid, }, - 'period' => 'weekly', - 'dateext' => 0, + 'period' => 7, + 'dateext' => undef, 'datepattern' => '%Y-%m-%d', - 'delaycompress' => 0, + 'delaycompress' => undef, 'extension' => "", 'ifempty' => 1, - 'maxage' => 0, - 'missingok' => 0, + 'maxage' => undef, + 'missingok' => undef, 'olddir' => { 'dirname' => '', 'dateformat' => undef, @@ -1380,7 +1981,7 @@ sub reset_defaults($) { 'group' => undef, }, 'rotate' => 4, - 'size' => 0, + 'size' => undef, }; } diff --git a/logrotate.pl b/logrotate.pl index 77ea21c..ff4f384 100755 --- a/logrotate.pl +++ b/logrotate.pl @@ -66,9 +66,8 @@ use LogRotate; our $VERSION = "2.0"; my $DefConfigFile = "/etc/logrotate.conf"; -my $DefStateFile = "/var/lib/logrotate.status"; my $ConfigFile = $DefConfigFile; -my $StateFile = $DefStateFile; +my $StateFile; my $force = 0; my $Debug = 0; my $help = 0; @@ -123,24 +122,18 @@ $test = 1 if $config_check; $test = 1; -if ( $verbose and not $test ) { - print "\n" . ( "#" x 80 ) . "\n"; - print "$0 starts with logrotation at: " . localtime() . "\n\n"; +unless ( $test ) { + print "\n" . ( "#" x 80 ) . "\n" if $verbose; + print "$0 beginnt mit Logrotation um: " . localtime() . "\n\n"; } -print "Test mode is ON.\n" if $test and $verbose; +print "Test mode is ON.\n" if $test; print "Verbose mode is ON on level: $verbose.\n" if $verbose; -print "Force mode is ON.\n" if $force and $verbose; -print "Configuration check only.\n" if $config_check and $verbose; +print "Force mode is ON.\n" if $force; +print "Configuration check only.\n" if $config_check; my $p = $verbose > 1 ? "$0 - " : ""; -unless ( $StateFile ) { - warn "No Statefile given with option --state|-s.\n"; - exit 2; -} -print "Status file is: '$StateFile'.\n" if $verbose > 1; - if ( @ARGV ) { @ConfigFiles = @ARGV; } else { @@ -162,7 +155,7 @@ print "\n" . $p . "initialisation:\n\n" if $verbose; my $lr = new LogRotate( verbose => $verbose, test => $test, force => $force, - statusfile => $StateFile ); + ); print "\n" . $p . "Lese Konfig-Dateien:\n\n" if $verbose > 1; foreach $ConfigFile ( @ConfigFiles ) { @@ -172,7 +165,19 @@ foreach $ConfigFile ( @ConfigFiles ) { } -print Dumper( $lr ) if $verbose > 3; +if ( $StateFile ) { + $lr->{'statusfile'} = $StateFile; +} else { + $lr->{'statusfile'} = $lr->{'c'}{'statusfile'} if $lr->{'c'}{'statusfile'}; +} + +unless ( $lr->{'statusfile'} ) { + warn "Keine Statusdatei gegeben.\n"; + exit 2; +} +print "Statusdatei ist: '" . $lr->{'statusfile'} . "'.\n" if $verbose; + +print "\n" . $p . "Gelesene Konfiguration: " . Dumper( $lr ) if $verbose > 3; exit 0; @@ -215,7 +220,7 @@ Usage: $0 [[-d]|[-v]] [-V] [-f|--force] [-s|--state file] [-h|--help|--usage] co -s, --state Tells $0 to use an alternate state file. This is useful if $0 is being run as a different user for various sets of log files. - The default state file is '$DefStateFile'. + The default state file is '/var/lib/logrotate.status'. ENDE -- 2.39.5