# syslog-lib.pl
# Functions for the syslog module

do '../web-lib.pl';
&init_config();
require '../ui-lib.pl';
%access = &get_module_acl();

# get_config()
sub get_config
{
local $lnum = 0;
local ($line, $cont, @rv);
local $tag = { 'tag' => '*',
	       'index' => 0,
	       'line' => 0 };
push(@rv, $tag);
&open_readfile(CONF, $config{'syslog_conf'});
while($line = <CONF>) {
	local $slnum = $lnum;
	$line =~ s/\r|\n//g;
	if ($line =~ /\\$/) {
		# continuation .. get the next lines
		$line =~ s/\\$//;
		while($cont = <CONF>) {
			$lnum++;
			$cont =~ s/^[#\s]+//;
			$cont =~ s/\r|\n//g;
			$line .= $cont;
			last if ($line !~ s/\\$//);
			}
		}
	if ($line =~ /^(#*)\s*([^#\s]+\.\S+)\s+(\S+)$/ ||
	    $line =~ /^(#*)\s*([^#\s]+\.\S+)\s+(\|.*)$/) {
		local $act = $3;
		local $log = { 'active' => !$1,
			       'sel' => [ split(/;/, $2) ],
			       'line' => $slnum,
			       'eline' => $lnum };
		if ($act =~ /^\-(\/\S+)$/) {
			$log->{'file'} = $1;
			$log->{'sync'} = 0;
			}
		elsif ($act =~ /^\|(.*)$/) {
			$log->{'pipe'} = $1;
			}
		elsif ($act =~ /^(\/\S+)$/) {
			$log->{'file'} = $1;
			$log->{'sync'} = 1;
			}
		elsif ($act =~ /^\@\@(\S+)$/) {
			$log->{'socket'} = $1;
			}
		elsif ($act =~ /^\@(\S+)$/) {
			$log->{'host'} = $1;
			}
		elsif ($act eq '*') {
			$log->{'all'} = 1;
			}
		else {
			$log->{'users'} = [ split(/,/, $act) ];
			}
		$log->{'index'} = scalar(@rv);
		$log->{'section'} = $tag;
		$tag->{'eline'} = $lnum;
		push(@rv, $log);
		}
	elsif ($line =~ /^(#?)!(\S+)$/) {
		push(@rv, { 'tag' => $2,
			    'index' => scalar(@rv),
			    'line' => $lnum,
			    'eline' => $lnum });
		$tag = $rv[@rv-1];
		}
	$lnum++;
	}
close(CONF);
return \@rv;
}

# create_log(&log)
sub create_log
{
local $lref = &read_file_lines($config{'syslog_conf'});
if ($config{'tags'}) {
	splice(@$lref, $_[0]->{'section'}->{'eline'}+1, 0, &log_line($_[0]));
	}
else {
	push(@$lref, &log_line($_[0]));
	}
&flush_file_lines();
}

# update_log(&old, &log)
sub update_log
{
local $lref = &read_file_lines($config{'syslog_conf'});
if ($config{'tags'} && $_[0]->{'section'} ne $_[1]->{'section'}) {
	if ($_[0]->{'section'}->{'line'} < $_[1]->{'section'}->{'line'}) {
		splice(@$lref, $_[1]->{'section'}->{'eline'}+1, 0,
		       &log_line($_[1]));
		splice(@$lref, $_[0]->{'line'},
		       $_[0]->{'eline'} - $_[0]->{'line'} + 1);
		}
	else {
		splice(@$lref, $_[0]->{'line'},
		       $_[0]->{'eline'} - $_[0]->{'line'} + 1);
		splice(@$lref, $_[1]->{'section'}->{'eline'}+1, 0,
		       &log_line($_[1]));
		}
	}
else {
	splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1,
	       &log_line($_[1]));
	}
&flush_file_lines();
}

# delete_log(&log)
sub delete_log
{
local $lref = &read_file_lines($config{'syslog_conf'});
splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1);
&flush_file_lines();
}

sub log_line
{
local $d;
if ($_[0]->{'file'}) {
	$d = ($_[0]->{'sync'} || !$config{'sync'} ? "" : "-").$_[0]->{'file'};
	}
elsif ($_[0]->{'pipe'}) {
	$d = '|'.$_[0]->{'pipe'};
	}
elsif ($_[0]->{'host'}) {
	$d = '@'.$_[0]->{'host'};
	}
elsif ($_[0]->{'users'}) {
	$d = join(",", @{$_[0]->{'users'}});
	}
elsif ($_[0]->{'socket'}) {
	$d = '@@'.$_[0]->{'socket'};
	}
else {
	$d = '*';
	}
return ($_[0]->{'active'} ? "" : "#").join(";", @{$_[0]->{'sel'}})."\t".$d;
}

# list_priorities()
# Returns a list of all priorities
sub list_priorities
{
return ( 'debug', 'info', 'notice', 'warning',
	 'err', 'crit', 'alert', 'emerg' );
}

# can_edit_log(&log)
# Returns 1 if some log can be viewed/edited, 0 if not
sub can_edit_log
{
return 1 if (!$access{'logs'});
local @files = split(/\s+/, $access{'logs'});
local $lf = $_[0]->{'file'} || $_[0]->{'pipe'} || $_[0]->{'host'} ||
	    $_[0]->{'socket'} || ($_[0]->{'all'} ? "*" : "users");
foreach $f (@files) {
	return 1 if ($f eq $lf || &is_under_directory($f, $lf));
	}
return 0;
}

sub needs_m4
{
local $oldslash = $/;
$/ = undef;
&open_readfile(CONF, $config{'syslog_conf'});
local $conf1 = <CONF>;
close(CONF);
&open_execute_command(CONF, "$config{'m4_path'} $config{'syslog_conf'}", 1, 1);
local $conf2 = <CONF>;
close(CONF);
$/ = $oldslash;
return $conf1 ne $conf2;
}

# get_syslog_pid(pid)
# Returns the syslog PID file
sub get_syslog_pid
{
local $pid;
if ($config{'pid_file'}) {
	if (&open_readfile(PID, $config{'pid_file'}) &&
	    <PID> =~ /^(\d+)$/ && kill(0, $1)) {
		$pid = $1;
		}
	}
else {
	($pid) = &find_byname("syslogd");
	}
return $pid;
}

# restart_syslog()
# Stop and re-start the syslog server. Returns an error message on failure.
sub restart_syslog
{
if ($config{'restart_cmd'}) {
	&system_logged("$config{'restart_cmd'} >/dev/null 2>/dev/null </dev/null");
	}
else {
	local $pid = &get_syslog_pid();
	$pid && &kill_logged('TERM', $pid) ||
		return &text('restart_ekill', $pid, $!);
	sleep(2);
	if ($config{'start_cmd'}) {
		&system_logged("$config{'start_cmd'} >/dev/null 2>/dev/null </dev/null");
		}
	else {
		&system_logged("cd / ; $config{'syslogd'} >/dev/null 2>/dev/null </dev/null &");
		}
	}
return undef;
}

# signal_syslog()
# Tell the syslog server to re-open it's log files
sub signal_syslog
{
local $pid = &get_syslog_pid();
if ($pid) {
	&kill_logged('HUP', $pid);
	}
}

# all_log_files(file)
# Given a filename, returns all rotated versions, ordered by oldest first
sub all_log_files
{
$_[0] =~ /^(.*)\/([^\/]+)$/;
local $dir = $1;
local $base = $2;
local ($f, @rv);
opendir(DIR, &translate_filename($dir));
foreach $f (readdir(DIR)) {
	local $trans = &translate_filename("$dir/$f");
	if ($f =~ /^\Q$base\E/ && -f $trans) {
		push(@rv, "$dir/$f");
		$mtime{"$dir/$f"} = [ stat($trans) ];
		}
	}
closedir(DIR);
return sort { $mtime{$a}->[7] <=> $mtime{$b}->[7] } @rv;
}

1;

