Server IP : 85.214.239.14 / Your IP : 18.220.255.227 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/2/cwd/proc/2/root/proc/2/cwd/proc/3/root/proc/2/cwd/usr/share/perl5/Amavis/ |
Upload File : |
package Amavis::Log; use strict; use re 'taint'; BEGIN { require Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '2.412'; @ISA = qw(Exporter); @EXPORT_OK = qw(&init &amavis_log_id &collect_log_stats &log_to_stderr &log_fd &open_log &close_log &write_log); } use subs @EXPORT_OK; use POSIX qw(locale_h strftime); use Fcntl qw(:flock F_GETFL F_SETFL FD_CLOEXEC); use IO::File qw(O_RDONLY O_WRONLY O_RDWR O_APPEND O_CREAT O_EXCL); use Unix::Syslog qw(:macros :subs); use Time::HiRes (); use Amavis::Util; # since IO::File 1.10 (comes with perl 5.8.1): # If "IO::File::open" is given a mode that includes the ":" character, # it passes all the three arguments to a three-argument "open" operator. use Amavis::Conf qw(:platform $DEBUG $TEMPBASE c cr ca $myversion $logline_maxlen $daemon_user); use vars qw($loghandle); # log file handle when logging to a file use vars qw($log_to_stderr $log_to_syslog $logfile_name $within_write_log); use vars qw($current_amavis_log_id); # tracks am_id() / $msginfo->log_id use vars qw($current_actual_syslog_ident $current_actual_syslog_facility); use vars qw($log_lines $log_retries %log_entries_by_level %log_status_counts); use vars qw($log_prio_debug $log_prio_info $log_prio_notice $log_prio_warning $log_prio_err $log_prio_crit); BEGIN { # saves a few ms by avoiding a subroutine call later $log_prio_debug = LOG_DEBUG; $log_prio_info = LOG_INFO; $log_prio_notice = LOG_NOTICE; $log_prio_warning = LOG_WARNING; $log_prio_err = LOG_ERR; $log_prio_crit = LOG_CRIT; $log_to_stderr = 1; # default until config files have been read } sub init($$) { ($log_to_syslog, $logfile_name) = @_; $log_lines = 0; %log_entries_by_level = (); $log_retries = 0; %log_status_counts = (); $log_to_stderr = $log_to_syslog || (defined $logfile_name && $logfile_name ne '') ? 0 : 1; open_log(); } sub collect_log_stats() { my(@result) = ($log_lines, {%log_entries_by_level}, $log_retries, {%log_status_counts}); $log_lines = 0; %log_entries_by_level = (); $log_retries = 0; %log_status_counts = (); @result; } # task id as shown in the log, also known as am_id, tracks $msginfo->log_id # sub amavis_log_id(;$) { $current_amavis_log_id = $_[0] if @_; $current_amavis_log_id; } # turn debug logging to STDERR on or off # sub log_to_stderr(;$) { $log_to_stderr = $_[0] if @_; $log_to_stderr; } # try to obtain file descriptor used by write_log, undef if unknown # sub log_fd() { $log_to_stderr ? fileno(STDERR) : $log_to_syslog ? undef # no fd for syslog : defined $loghandle ? $loghandle->fileno : fileno(STDERR); } sub open_log() { if ($log_to_syslog && !$log_to_stderr) { my $id = c('syslog_ident'); my $fac = c('syslog_facility'); $fac =~ /^[A-Za-z0-9_]+\z/ or die "Suspicious syslog facility name: $fac"; my $syslog_facility_num = eval("LOG_\U$fac"); $syslog_facility_num =~ /^\d+\z/ or die "Unknown syslog facility name: $fac"; # man syslog(3) on Linux: The argument 'ident' in the call of openlog() # is probably stored as-is. Thus, if the string it points to is changed, # syslog() may start prepending the changed string, and if the string # it points to ceases to exist, the results are undefined. Most portable # is to use a string constant. (we use a static variable here) $current_actual_syslog_ident = $id; $current_actual_syslog_facility = $fac; openlog($id, LOG_PID | LOG_NDELAY, $syslog_facility_num); } elsif ($log_to_stderr || $logfile_name eq '') { # logging to STDERR STDERR->autoflush(1); # just in case (should already be on by default) STDERR->fcntl(F_SETFL, O_APPEND) or warn "Error setting O_APPEND on STDERR: $!"; } elsif ($logfile_name ne '') { $loghandle = IO::File->new; # O_WRONLY etc. can become tainted in Perl5.8.9 [perlbug #62502] $loghandle->open($logfile_name, Amavis::Util::untaint(O_CREAT|O_APPEND|O_WRONLY), 0640) or die "Failed to open log file $logfile_name: $!"; binmode($loghandle,':bytes') or die "Can't cancel :utf8 mode: $!"; $loghandle->autoflush(1); if (defined $daemon_user && $daemon_user ne '' && $> == 0) { local($1); my $uid = $daemon_user=~/^(\d+)$/ ? $1 : (getpwnam($daemon_user))[2]; if ($uid) { chown($uid,-1,$logfile_name) or die "Can't chown logfile $logfile_name to $uid: $!"; } } } } sub close_log() { if ($log_to_syslog) { closelog(); $current_actual_syslog_ident = $current_actual_syslog_facility = undef; } elsif (defined($loghandle) && $logfile_name ne '') { $loghandle->close or die "Error closing log file $logfile_name: $!"; undef $loghandle; } } # Log either to syslog or to a file # sub write_log($$) { my($level,$errmsg) = @_; return if $within_write_log; $within_write_log++; my $am_id = !defined $current_amavis_log_id ? '' : "($current_amavis_log_id) "; # my $old_locale = POSIX::setlocale(LC_TIME,'C'); # English dates required! my $alert_mark = $level >= 0 ? '' : $level >= -1 ? '(!)' : '(!!)'; # $alert_mark .= '*' if $> == 0; $log_entries_by_level{"$level"}++; my $prio = $level >= 3 ? $log_prio_debug # most frequent first # : $level >= 2 ? $log_prio_info : $level >= 1 ? $log_prio_info : $level >= 0 ? $log_prio_notice : $level >= -1 ? $log_prio_warning : $level >= -2 ? $log_prio_err : $log_prio_crit; if ($log_to_syslog && !$log_to_stderr) { if ($Amavis::Util::current_config_syslog_ident ne $current_actual_syslog_ident || $Amavis::Util::current_config_syslog_facility ne $current_actual_syslog_facility) { close_log() if defined $current_actual_syslog_ident || defined $current_actual_syslog_facility; open_log(); } my $pre = $alert_mark; # $logline_maxlen should be less than (1023 - prefix) for a typical syslog, # 980 is a suitable length to avoid truncations by the syslogd daemon my $logline_size = $logline_maxlen; $logline_size = 50 if $logline_size < 50; # let at least something out while (length($am_id)+length($pre)+length($errmsg) > $logline_size) { my $avail = $logline_size - length($am_id . $pre . '...'); $log_lines++; $! = 0; # syslog($prio, '%s', $am_id . $pre . substr($errmsg,0,$avail) . '...'); Unix::Syslog::_isyslog($prio, $am_id . $pre . substr($errmsg,0,$avail) . '...'); if ($! != 0) { $log_retries++; $log_status_counts{"$!"}++ } $pre = $alert_mark . '...'; $errmsg = substr($errmsg,$avail); } $log_lines++; $! = 0; # syslog($prio, '%s', $am_id . $pre . $errmsg); Unix::Syslog::_isyslog($prio, $am_id . $pre . $errmsg); if ($! != 0) { $log_retries++; $log_status_counts{"$!"}++ } } elsif ($log_to_stderr || !defined $loghandle) { $log_lines++; my $prefix; if ($DEBUG) { my $now = Time::HiRes::time; # timestamp with milliseconds $prefix = sprintf('%s:%06.3f %s %s[%s]: ', # syslog-like prefix strftime('%b %e %H:%M',localtime($now)), $now-int($now/60)*60, Amavis::Util::idn_to_utf8(c('myhostname')), c('myprogram_name'), $$); } else { $prefix = "<$prio>"; # sd-daemon(3), SyslogLevelPrefix=true } # avoid multiple calls to write(2), join the string first! my $s = $prefix . $am_id . $alert_mark . $errmsg . "\n"; # # IEEE Std 1003.1, 2013: Write requests to a pipe or FIFO shall be handled # in the same way as a regular file with the following exceptions: [...] # - There is no file offset associated with a pipe, hence each write # request shall append to the end of the pipe. # - Write requests of {PIPE_BUF} bytes or less shall not be interleaved # with data from other processes doing writes on the same pipe. # Writes of greater than {PIPE_BUF} bytes may have data interleaved, on # arbitrary boundaries, with writes by other processes, whether or not # the O_NONBLOCK flag of the file status flags is set. # # PIPE_BUF is 512 on *BSD, 4096 on Linux. print STDERR ($s) or die "Error writing to STDERR: $!"; } else { $log_lines++; my $now = Time::HiRes::time; my $prefix = sprintf('%s %s %s[%s]: ', # prepare a syslog-like prefix strftime('%b %e %H:%M:%S',localtime($now)), Amavis::Util::idn_to_utf8(c('myhostname')), c('myprogram_name'), $$); my $s = $prefix . $am_id . $alert_mark . $errmsg . "\n"; # NOTE: a lock is on a file, not on a file handle flock($loghandle,LOCK_EX) or die "Can't lock a log file: $!"; # seek() seems redundant with O_APPEND: # IEEE Std 1003.1, 2013: If the O_APPEND flag of the file status flags is # set, the file offset shall be set to the end of the file prior to each # write and no intervening file modification operation shall occur between # changing the file offset and the write operation. seek($loghandle,0,2) or die "Can't position log file to its tail: $!"; $loghandle->print($s) or die "Error writing to log file: $!"; # we have autoflush on, so unlocking here is safe flock($loghandle,LOCK_UN) or die "Can't unlock a log file: $!"; } # POSIX::setlocale(LC_TIME, $old_locale); $within_write_log = 0; } 1;