# # LogBase.pm: logging library (base functionality) for sbuild # Copyright © 2005 Ryan Murray # Copyright © 2005-2009 Roger Leigh # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see # . # ####################################################################### package Sbuild::LogBase; use strict; use warnings; use English; sub open_log ($$$); sub close_log ($); our $log = undef; our $saved_stdout = undef; our $saved_stderr = undef; BEGIN { use Exporter (); our (@ISA, @EXPORT_OK); @ISA = qw(Exporter); @EXPORT_OK = qw(open_log close_log $log $saved_stdout $saved_stderr); } sub open_log ($$$) { my $conf = shift; my $log_file = shift; # File to log to my $logfunc = shift; # Function to handle logging if (!defined($logfunc)) { $logfunc = sub { my $log_file = shift; my $message = shift; print $log_file $message; } } $log_file->autoflush(1) if defined($log_file); my $pid; ($pid = open($log, "|-")); if (!defined $pid) { warn "Cannot open pipe to log: $!\n"; } elsif ($pid == 0) { # We ignore SIG(INT|QUIT|TERM) because they will be caught in # the parent which will subsequently close the logging stream # resulting in our termination. This is needed to ensure the # final log messages are sent and the parent doesn't die with # SIGPIPE. $SIG{'INT'} = 'IGNORE'; $SIG{'QUIT'} = 'IGNORE'; $SIG{'TERM'} = 'IGNORE'; $PROGRAM_NAME = 'main log for ' . $PROGRAM_NAME; while () { $logfunc->($log_file, $_) if (!$conf->get('NOLOG') && defined($log_file)); $logfunc->(\*STDOUT, $_) if ($conf->get('VERBOSE')); } undef $log_file; exit 0; } undef $log_file; # Close in parent $log->autoflush(1); # Automatically flush select($log); # It's the default stream open($saved_stdout, ">&STDOUT") or warn "Can't redirect stdout\n"; open($saved_stderr, ">&STDERR") or warn "Can't redirect stderr\n"; open(STDOUT, '>&', $log) or warn "Can't redirect stdout\n"; open(STDERR, '>&', $log) or warn "Can't redirect stderr\n"; return $log; } sub close_log ($) { my $conf = shift; # Note: It's imperative to close and reopen in the exact order in # which we originally opened and reopened, or else we can deadlock # in wait4 when closing the log stream due to waiting on the child # forever. open(STDERR, '>&', $saved_stderr) or warn "Can't redirect stderr\n" if defined($saved_stderr); open(STDOUT, '>&', $saved_stdout) or warn "Can't redirect stdout\n" if defined($saved_stdout); $saved_stderr->close(); undef $saved_stderr; $saved_stdout->close(); undef $saved_stdout; $log->close(); undef $log; } 1;