]> Frank Brehm's Git Trees - scripts/solaris.git/commitdiff
Weitergemacht
authorFrank Brehm <frank@brehm-online.com>
Tue, 21 Mar 2006 15:49:58 +0000 (15:49 +0000)
committerFrank Brehm <frank@brehm-online.com>
Tue, 21 Mar 2006 15:49:58 +0000 (15:49 +0000)
LogRotate/Conf.pm
logrotate.pl

index 350343d39d99231b8ea403f3b0404df1c17494d5..b3d04593adc7edd4afc4add7a406adc485be6309 100644 (file)
@@ -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 : "<undef>") . "' ...\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,
   };
 
 }
index 77ea21c6b731e655e2b58a58641a35e13e50f356..ff4f384a9884468ce9776b9393a1bc304f14892f 100755 (executable)
@@ -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 <statefile>
                 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