Viewing file: logrotate-lib.pl (9.35 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# logrotate-lib.pl # Common functions for parsing the logrotate configuration file
BEGIN { push(@INC, ".."); }; use WebminCore; &init_config();
if (open(VERSION, "$module_config_directory/version")) { chop($logrotate_version = <VERSION>); close(VERSION); }
# Use sample config if it exists but real config doesn't yet if (!-r $config{'logrotate_conf'} && -r $config{'sample_conf'}) { ©_source_dest($config{'sample_conf'}, $config{'logrotate_conf'}); }
sub get_config_parent { if (!$get_config_parent_cache) { local ($conf, $lines) = &get_config(); $get_config_parent_cache = { 'members' => $conf, 'file' => $config{'logrotate_conf'}, 'line' => 0, 'eline' => $lines, 'global' => 1 }; } return $get_config_parent_cache; }
# get_config([file]) # Returns a list of logrotate config file entries sub get_config { local $file = $_[0] || $config{'logrotate_conf'}; if (!$_[0] && $get_config_cache{$file}) { return wantarray ? ( $get_config_cache{$file}, $get_config_lnum_cache{$file}, $get_config_files_cache{$file} ) : $get_config_cache{$file}; } local @files = ( $file ); local @rv; local $addto = \@rv; local $section = undef; local $lnum = 0; local $fh = "FILE".$file_count++; open($fh, $file); while(<$fh>) { s/\r|\n//g; s/#.*$//; if (/^\s*(.*){\s*$/) { # Start of a section push(@name, &split_words($1)); $section = { 'name' => [ @name ], 'members' => [ ], 'index' => scalar(@$addto), 'line' => defined($namestart) ? $namestart : $lnum, 'eline' => $lnum, 'file' => $file }; push(@$addto, $section); $addto = $section->{'members'}; @name = ( ); $namestart = undef; } elsif ((/^\s*\// || /^\s*"\//) && !$section) { # A path before a section $namestart = $lnum if (!@name); push(@name, &split_words($_)); } elsif (/^\s*}\s*$/) { # End of a section $addto = \@rv; $section->{'eline'} = $lnum; $section = undef; } elsif (/^\s*include\s+(.*)$/i) { # Including other directives files local $incfile = $1; if (-d $incfile) { # Multiple files! local $f; opendir(DIR, $incfile); local @dirs = sort { $a cmp $b } readdir(DIR); closedir(DIR); foreach $f (@dirs) { next if ($f =~ /^\./ || $f =~ /\.rpm(save|orig|new)$/ || $f =~ /\~$/ || $f =~ /,v$/ || $f =~ /\.swp$/ || $f =~ /\.lock$/); local ($inc, $ilnum, $ifiles) = &get_config("$incfile/$f"); push(@files, @$ifiles); map { $_->{'index'} += @$addto } @$inc; push(@$addto, @$inc); } closedir(DIR); } else { # A single file local ($inc, $ilnum, $ifiles) = &get_config($incfile); push(@files, @$ifiles); map { $_->{'index'} += @$addto } @$inc; push(@$addto, @$inc); } } elsif (/^\s*(\S+)\s*(.*)$/) { # Single directive local $dir = { 'name' => $1, 'value' => $2, 'index' => scalar(@$addto), 'line' => $lnum, 'eline' => $lnum, 'file' => $file }; push(@$addto, $dir); if ($1 eq 'postrotate' || $1 eq 'prerotate') { # Followed by a multi-line script! while(<$fh>) { $lnum++; s/\r|\n//g; last if (/^\s*(endscript|endrotate)\s*$/); s/^\s+//; $dir->{'script'} .= $_."\n"; } $dir->{'eline'} = $lnum; } } $lnum++; } close($fh); if (!$_[0]) { $get_config_cache{$file} = \@rv; $get_config_lnum_cache{$file} = $lnum; $get_config_files_cache{$file} = \@files; } return wantarray ? (\@rv, $lnum, \@files) : \@rv; }
sub split_words { local @rv; local $str = $_[0]; while($str =~ /^\s*"(.*)"(.*)$/ || $str =~ /^\s*(\S+)(.*)$/) { push(@rv, $1); $str = $2; } return @rv; }
sub join_words { return join(" ", map { /\s/ ? "\"$_\"" : $_ } @_); }
# find(name, &config) sub find { local @rv = grep { lc($_->{'name'}) eq lc($_[0]) } @{$_[1]}; return wantarray ? @rv : $rv[0]; }
# find_value(name, &config) sub find_value { local @rv = map { defined($_->{'script'}) ? $_->{'script'} : $_->{'value'} } grep { lc($_->{'name'}) eq lc($_[0]) } @{$_[1]}; return wantarray ? @rv : $rv[0]; }
# get_logrotate_version(&out) sub get_logrotate_version { local $out = &backquote_command("$config{'logrotate'} -v 2>&1", 1); ${$_[0]} = $out if ($_[0]); return $out =~ /logrotate\s+([0-9\.]+)\s/ || $out =~ /logrotate\-([0-9\.]+)\s/ ? $1 : undef; }
# get_period(&conf) sub get_period { foreach $p ("daily", "weekly", "monthly") { local $ex = &find($p, $_[0]); return $p if ($ex); } return undef; }
# save_directive(&parent, &old|name, &new, [indent]) sub save_directive { local $conf = $_[0]->{'members'}; local $old = !defined($_[1]) ? undef : ref($_[1]) ? $_[1] : &find($_[1], $conf); local $lref = &read_file_lines($old ? $old->{'file'} : $_[0]->{'file'}); local $new = !defined($_[2]) ? undef : ref($_[2]) ? $_[2] : { 'name' => $old ? $old->{'name'} : $_[1], 'value' => $_[2] }; local @lines = &directive_lines($new, $_[3]) if ($new); local $gparent = &get_config_parent(); if ($old && $new) { # Update local $oldlines = $old->{'eline'} - $old->{'line'} + 1; splice(@$lref, $old->{'line'}, $oldlines, @lines); $new->{'line'} = $old->{'line'}; $new->{'index'} = $old->{'index'}; $new->{'file'} = $old->{'file'}; $new->{'eline'} = $new->{'line'} + scalar(@lines) - 1; %$old = %{$new}; &renumber($gparent, $old->{'file'}, $old->{'eline'}, scalar(@lines) - $oldlines, $old); } elsif ($old && !$new) { # Delete local $oldlines = $old->{'eline'} - $old->{'line'} + 1; splice(@$lref, $old->{'line'}, $old->{'eline'} - $old->{'line'} + 1); splice(@$conf, $old->{'index'}, 1); &renumber($gparent, $old->{'file'}, $old->{'line'}, -$oldlines); } elsif (!$old && $new && $_[0]->{'global'} && !$new->{'members'}) { # Add at the start of the file if (defined($_[0]->{'line'})) { splice(@$lref, 0, 0, @lines); $new->{'line'} = 0; $new->{'eline'} = $new->{'line'} + scalar(@lines) - 1; $new->{'file'} = $_[0]->{'file'}; &renumber($gparent, $new->{'file'}, $new->{'line'}-1, scalar(@lines)); } $new->{'index'} = 0; splice(@$conf, 0, 0, $new); } elsif (!$old && $new) { # Add (to end of section) if (defined($_[0]->{'line'})) { if (!$new->{'file'} || $_[0]->{'file'} eq $new->{'file'}) { # Adding to parent file splice(@$lref, $_[0]->{'eline'}, 0, @lines); $new->{'line'} = $_[0]->{'eline'}; $new->{'eline'} = $new->{'line'} + scalar(@lines) - 1; $new->{'file'} = $_[0]->{'file'}; &renumber($gparent, $new->{'file'}, $new->{'line'}-1, scalar(@lines)); } else { # Adding to another file local $lref2 = &read_file_lines($new->{'file'}); $new->{'line'} = scalar(@$lref2); $new->{'eline'} = $new->{'line'} + scalar(@lines) - 1; push(@$lref2, @lines); } } $new->{'index'} = scalar(@$conf); push(@$conf, $new); } }
# renumber(&object, file, startline, count, [&skip]) sub renumber { return if (!$_[3]); if ($_[0]->{'file'} eq $_[1] && $_[0] ne $_[4]) { $_[0]->{'line'} += $_[3] if ($_[0]->{'line'} > $_[2]); $_[0]->{'eline'} += $_[3] if ($_[0]->{'eline'} > $_[2]); } if ($_[0]->{'members'}) { local $c; foreach $c (@{$_[0]->{'members'}}) { &renumber($c, $_[1], $_[2], $_[3], $_[4]); } } }
# directive_lines(&dir, indent) sub directive_lines { local @rv; if ($_[0]->{'members'}) { push(@rv, $_[1].&join_words(@{$_[0]->{'name'}})." {"); foreach $m (@{$_[0]->{'members'}}) { push(@rv, &directive_lines($m, $_[1]."\t")); } push(@rv, $_[1]."}"); } elsif ($_[0]->{'script'}) { push(@rv, $_[1].$_[0]->{'name'}); foreach $s (split(/\n/, $_[0]->{'script'})) { push(@rv, $_[1].$s); } push(@rv, $_[1]."endscript"); } else { push(@rv, $_[1].$_[0]->{'name'}. ($_[0]->{'value'} eq "" ? "" : " ".$_[0]->{'value'})); } return @rv; }
# delete_if_empty(file) sub delete_if_empty { local $conf = &get_config(); local %files = map { $_, 1 } &unique(map { $_->{'file'} } @$conf); &unlink_file($_[0]) if (!$files{$_[0]}); }
%global_default = ( "nocompress" => "", "compress" => undef, "nodelaycompress" => "", "delaycompress" => undef, "ifempty" => "", "notifempty" => undef, "nocopytruncate" => "", "copytruncate" => undef, "nomissingok" => "", "missingok" => undef, "rotate" => 0, "create" => "", "nocreate" => undef, "noolddir" => "", "olddir" => undef, "ext" => undef, "mail" => undef, "nomail" => "", "maillast" => "", "mailfirst" => undef, "errors" => undef, "postrotate" => undef, "prerotate" => undef, "errors" => undef, );
# rotate_log_now(&log) # Call logrotate on a config fragment file to rotate just one set of logs # immediately. sub rotate_log_now { local $conf = &get_config(); local $temp = &transname(); open(TEMP, ">$temp"); local $c; foreach $c (@$conf) { if (!$c->{'members'}) { print TEMP map { "$_\n" } &directive_lines($c); } } print TEMP map { "$_\n" } &directive_lines($_[0]); close(TEMP); local $out = &backquote_logged("$config{'logrotate'} -f $temp 2>&1"); return ($?, $out); }
# get_add_file([filename]) # Returns the file to which new logrotate sections should be added sub get_add_file { local ($filename) = @_; if ($config{'add_file'} && -d $config{'add_file'} && $filename) { # Adding to a new file in a directory return "$config{'add_file'}/$filename.conf"; } elsif ($config{'add_file'} && !-d $config{'add_file'}) { # Make sure file is valid local ($conf, $lnum, $files) = &get_config(); if (&indexof($config{'add_file'}, @$files) >= 0) { return $config{'add_file'}; } } return $config{'logrotate_conf'}; }
1;
|