# Functions for managing logrotate
sub init_logrotate
{
$feature_depends{'logrotate'} = [ 'web' ];
}
sub require_logrotate
{
return if ($require_logrotate++);
&foreign_require("logrotate", "logrotate-lib.pl");
}
# setup_logrotate(&domain)
# Create logrotate entries for the server's access and error logs
sub setup_logrotate
{
&$first_print($text{'setup_logrotate'});
&require_logrotate();
&require_apache();
# Work out the log files we are rotating
local $alog = &get_apache_log($_[0]->{'dom'}, $_[0]->{'web_port'}, 0);
local $elog = &get_apache_log($_[0]->{'dom'}, $_[0]->{'web_port'}, 1);
local @logs = ( $alog, $elog );
if ($_[0]->{'ftp'}) {
push(@logs, &get_proftpd_log($_[0]->{'ip'}));
}
local @logs = &unique(grep { $_ } @logs);
local $tmpl = &get_template($_[0]->{'template'});
if (@logs) {
# Check if any are already rotated
local $parent = &logrotate::get_config_parent();
foreach my $c (@{$parent->{'members'}}) {
foreach my $n (@{$c->{'name'}}) {
if (&indexof($n, @logs) >= 0) {
# Clash!!
&error(&text('setup_clashlogrotate',
"$n"));
}
}
}
# Add the new section
local $lconf = { 'file' => &logrotate::get_add_file(),
'name' => \@logs };
if ($tmpl->{'logrotate'} eq 'none') {
# Use automatic configurtation
local $apachectl = $apache::config{'apachectl_path'} ||
&has_command("apachectl") ||
&has_command("apache2ctl");
local $script = $apache::config{'graceful_cmd'} ||
"$apachectl graceful";
$lconf->{'members'} = [
{ 'name' => 'rotate',
'value' => $config{'logrotate_num'} || 5 },
{ 'name' => 'weekly' },
{ 'name' => 'compress' },
{ 'name' => 'postrotate',
'script' => $script }
];
}
else {
# Use manually defined directives
local $temp = &transname();
local $txt = $tmpl->{'logrotate'};
$txt =~ s/\t/\n/g;
&open_tempfile(TEMP, ">$temp");
&print_tempfile(TEMP, "/dev/null {\n");
&print_tempfile(TEMP,
&substitute_domain_template($txt, $_[0])."\n");
&print_tempfile(TEMP, "}\n");
&close_tempfile(TEMP);
local $tconf = &logrotate::get_config($temp);
$lconf->{'members'} = $tconf->[0]->{'members'};
unlink($temp);
}
&lock_file($lconf->{'file'});
&logrotate::save_directive($parent, undef, $lconf);
&flush_file_lines($lconf->{'file'});
&unlock_file($lconf->{'file'});
&$second_print($text{'setup_done'});
}
else {
&$second_print($text{'setup_nolog'});
}
}
# modify_logrotate(&domain, &olddomain)
# Adjust path if home directory has changed
sub modify_logrotate
{
if ($_[0]->{'home'} ne $_[1]->{'home'}) {
&require_logrotate();
&$first_print($text{'save_logrotate'});
# Work out the *old* access log, which will have already been renamed
local $oldalog = &get_apache_log($_[0]->{'dom'}, $_[0]->{'web_port'});
$oldalog =~ s/$_[0]->{'home'}/$_[1]->{'home'}/;
local $lconf = &get_logrotate_section($oldalog);
if ($lconf) {
&lock_file($lconf->{'file'});
local $parent = &logrotate::get_config_parent();
local $n;
foreach $n (@{$lconf->{'name'}}) {
$n =~ s/(^|\s)$_[1]->{'home'}/$1$_[0]->{'home'}/g;
}
&logrotate::save_directive($parent, $lconf, $lconf);
&flush_file_lines();
&unlock_file($lconf->{'file'});
&$second_print($text{'setup_done'});
}
else {
&$second_print($text{'setup_nologrotate'});
}
}
}
# delete_logrotate(&domain)
# Remove logrotate section for this domain
sub delete_logrotate
{
&require_logrotate();
&$first_print($text{'delete_logrotate'});
local $lconf = &get_logrotate_section($_[0]);
if ($lconf) {
local $parent = &logrotate::get_config_parent();
&lock_file($lconf->{'file'});
&logrotate::save_directive($parent, $lconf, undef);
&flush_file_lines();
&unlock_file($lconf->{'file'});
undef($logrotate::get_config_parent_cache);
undef($logrotate::get_config_cache);
&$second_print($text{'setup_done'});
}
else {
&$second_print($text{'setup_nologrotate'});
}
}
# validate_logrotate(&domain)
# Returns an error message if a domain's logrotate section is not found
sub validate_logrotate
{
local ($d) = @_;
local $log = &get_apache_log($d->{'dom'}, $d->{'web_port'});
return &text('validate_elogfile', "$d->{'dom'}") if (!$log);
local $lconf = &get_logrotate_section($d);
return &text('validate_elogrotate', "$logfile") if (!$lconf);
return undef;
}
# get_logrotate_section(&domain|log-file)
sub get_logrotate_section
{
&require_logrotate();
&require_apache();
local $alog = ref($_[0]) ? &get_apache_log($_[0]->{'dom'}, $_[0]->{'web_port'})
: $_[0];
if (!$alog && ref($_[0])) {
# Website may have been already deleted, so we don't know the log
# file path! Try the template default.
$alog = &get_apache_template_log($_[0]);
}
local $conf = &logrotate::get_config();
local ($c, $n);
foreach $c (@$conf) {
foreach $n (@{$c->{'name'}}) {
return $c if ($n eq $alog);
}
}
return undef;
}
# check_logrotate_clash()
# No need to check for clashes ..
sub check_logrotate_clash
{
return 0;
}
# backup_logrotate(&domain, file)
# Saves the log rotation section for this domain to a file
sub backup_logrotate
{
&$first_print($text{'backup_logrotatecp'});
local $lconf = &get_logrotate_section($_[0]);
if ($lconf) {
local $lref = &read_file_lines($lconf->{'file'});
local $l;
&open_tempfile(FILE, ">$_[1]");
foreach $l (@$lref[$lconf->{'line'} .. $lconf->{'eline'}]) {
&print_tempfile(FILE, "$l\n");
}
&close_tempfile(FILE);
&$second_print($text{'setup_done'});
return 1;
}
else {
&$second_print($text{'setup_nologrotate'});
return 0;
}
}
# restore_logrotate(&domain, file, &options, &all-options, home-format,
# &olddomain)
sub restore_logrotate
{
&$first_print($text{'restore_logrotatecp'});
local $lconf = &get_logrotate_section($_[0]);
if ($lconf) {
local $srclref = &read_file_lines($_[1]);
local $dstlref = &read_file_lines($lconf->{'file'});
&lock_file($lconf->{'file'});
splice(@$dstlref, $lconf->{'line'}+1,
$lconf->{'eline'}-$lconf->{'line'}-1,
@$srclref[1 .. @$srclref-2]);
if ($_[5]->{'home'} && $_[5]->{'home'} ne $_[0]->{'home'}) {
# Fix up any references to old home dir
local $i;
foreach $i ($lconf->{'line'} .. $lconf->{'line'}+scalar(@$srclref)-1) {
$dstlref->[$i] =~ s/(^|\s)$_[5]->{'home'}/$1$_[0]->{'home'}/g;
}
}
&flush_file_lines($lconf->{'file'});
&unlock_file($lconf->{'file'});
undef($logrotate::get_config_parent_cache);
undef($logrotate::get_config_cache);
&$second_print($text{'setup_done'});
return 1;
}
else {
&$second_print($text{'setup_nologrotate'});
return 0;
}
}
# sysinfo_logrotate()
# Returns the Logrotate version
sub sysinfo_logrotate
{
&require_logrotate();
$logrotate::logrotate_version ||= &logrotate::get_logrotate_version();
return ( [ $text{'sysinfo_logrotate'}, $logrotate::logrotate_version ] );
}
# check_logrotate_template([directives])
# Returns an error message if the default Logrotate directives don't look valid
sub check_logrotate_template
{
local ($d, $gotpostrotate);
local @dirs = split(/\t+/, $_[0]);
foreach $d (@dirs) {
if ($d =~ /\s*postrotate/) {
$gotpostrotate = 1;
}
}
$gotpostrotate || return $text{'lcheck_epost'};
return undef;
}
# show_template_logrotate(&tmpl)
# Outputs HTML for editing Logrotate related template options
sub show_template_logrotate
{
local ($tmpl) = @_;
# Logrotate directives
print &ui_table_row(
&hlink($text{'tmpl_logrotate'}, "template_logrotate"),
&none_def_input("logrotate", $tmpl->{'logrotate'},
$text{'tmpl_ftpbelow'}, 0, 0,
$text{'tmpl_logrotatenone'}, [ "logrotate" ])."
\n".
&ui_textarea("logrotate",
$tmpl->{'logrotate'} eq "none" ? undef :
join("\n", split(/\t/, $tmpl->{'logrotate'})),
5, 60));
}
# parse_template_logrotate(&tmpl)
# Updates Logrotate related template options from %in
sub parse_template_logrotate
{
local ($tmpl) = @_;
# Save logrotate settings
$tmpl->{'logrotate'} = &parse_none_def("logrotate");
if ($in{"logrotate_mode"} == 2) {
local $err = &check_logrotate_template($in{'logrotate'});
&error($err) if ($err);
}
}
# chained_logrotate(&domain, [&old-domain])
# Logrotate is automatically enabled when a website is, if set to always mode
# and if the website is just being turned on now.
sub chained_logrotate
{
local ($d, $oldd) = @_;
if ($config{'logrotate'} != 3) {
# Not in auto mode, so don't touch
return undef;
}
elsif ($d->{'alias'} || $d->{'subdom'}) {
# These types never have logs
return 0;
}
elsif ($d->{'web'}) {
if (!$oldd || !$oldd->{'web'}) {
# Turning on web, so turn on logrotate
return 1;
}
else {
# Don't do anything
return undef;
}
}
else {
# Always off when web is
return 0;
}
return $d->{'web'} && (!$oldd || !$oldd->{'web'}) &&
!$d->{'alias'} && !$d->{'subdom'} &&
$config{'logrotate'} == 3;
}
$done_feature_script{'logrotate'} = 1;
1;