Subject: Developers of Sympa
List archive
- From: IKEDA Soji <address@concealed>
- To: address@concealed
- Subject: Re: [sympa-developpers] Using exception
- Date: Mon, 21 Oct 2013 22:18:08 +0900
Guillaume and all,
On Mon, 07 Oct 2013 20:15:19 +0200
Guillaume Rousse <address@concealed> wrote:
> Le 07/10/2013 17:55, Guillaume Rousse a écrit :
> > Hence my point: to be discussed later, once we have a working code base,
> > on specific use case.
> Here is an alternative proposal, a little more positive regarding
> current topic.
>
> 1) select a simple ternal function (for instance
> Sympa::Tools::File::set_file_rights())
> 2) replace its current error handling logic with exceptions
> 3) find every place in Sympa code where this function is called
> 4) replace every usage of the function to ensure the exception won't
> propagate further, and the error is properly logged
> 5) add unit tests checking your modifications
> 6) iterate
>
> This way, you're setting up your error handling bottom-up, rather than
> top-down. And if ever you have to refactor it, as you missed something,
> you have unit tests to check regressions.
It is not coding rule.
Anyway, I'll try to find it from actual code.
Here is a playtest, snippets from current code and revised ones
according to top half of your proposal. As both set_file_rights.pm*
files are perltidy'ed, they may be easily diff'ed.
Sympa::Tools::File::set_file_rights():
- New exception Sympa::Exception::File was defined.
- "do_log; return undef" logic was replaced with throw().
- As a result, this function no longer need returning values,
even when it succeeded: "return 1" was also removed.
- It is not necessarily usual. Many functions may both return
values and throw exceptions.
Sympa::Upgrade::to_utf8():
- The logic checking value of set_file_rights() had been replaced
with catch().
- do_log() is exceuted here. There no longer are cascaded err logs.
- I added new full_message() method to exception object: Because
stringified "$e" returns full traceback with multiple lines
(we had defined such), it's not suitable for logging.
- This case might be "catch-all" case, namely, when any exceptions
are thrown, eval'ed process can be concidered to fail _completely_.
If it's the case, isa() and throw() to filter and to re-throw
exceptions might be omitted:
if (my $e = Sympa::Exception->catch) {
Sympa::Log::Syslog::do_log( 'err', '%s', $e->full_message );
next;
}
- However, see the next.
Sympa::Configuration::checkfiles_as_root():
- The same replacement were made (in two places).
- On exception revision, "return undef" are always executed again in
catch-block.
This fact suggests that exceptions would not handled here but in
higher level: Bare set_file_rights(), not wrapped with eval-catch
structure, would be placed here so that exceptions would pass
through this function.
(Final revision of checkfiles_as_root() is attached sepalately).
- On the other hand, in higher level(s), catch-block will catch
the exception which were thrown by the code not directly
enclosed by corresponding eval{}. For example in sympa.pl:
eval {
Sympa::Configuration::checkfiles_as_root()
};
if (my $e = Sympa::Exception->catch) {
# Sympa::Exception::File from lower function can be caught.
...
}
In other words, it is always probable that catch-block will
catch unexpected exceptions.
That's why I argued that uncaught exceptions _must_ be
re-thrown. If they were not propagated, serious errors and
bugs can be hidden.
- Suggestion #1: catch-block must re-throw uncaught exceptions.
- Take one more step. In actual code, failure on
checkfiles_as_root() let sympa.pl terminate immediately.
Thus, exceptions thrown through this function need not be
caught: They should simply be escalated to uppermost level,
Perl itself:
Sympa::Configuration::checkfiles_as_root(); # will die on failure.
- Suggestion #2: Never capture (by eval{}) nor catch (by catch())
any exceptions, _if_ you don't plan to process them.
- However again, see the next.
Sympa::Tools::Daemon::write_pid():
- The similar replacements were made.
- Here, Sympa::Lock::lock() and some built-in functions are assumed
to throw exceptions.
- Despite exceptions thrown by lower levels will pass through
this function, eval-catch structure is required in this function,
because of clean-up process.
- Suggestion #3: If clean-up process is required, capture and catch
exceptions, and execute clean-up process, then re-throw uncaught
exceptions.
Conclusion:
Three suggestions about coding rule were discovered.
- Suggestion #1: catch-block must re-throw uncaught exceptions.
- Suggestion #2: Never capture (by eval{}) nor catch (by catch())
any exceptions, _if_ you don't plan to process them.
- Suggestion #3: If clean-up process is required, capture and catch
exceptions, and execute clean-up process, then re-throw uncaught
exceptions.
Code was refactored to suit to exception scheme.
- It improves error recovery: For example now filehandles are
assured to be closed and unlocked when any errors occurred.
- It improves logging behavior: Cascaded err logs no longer occur,
and we can always get complete tracebacks.
- However, there is one open question: It is not sure that it
improves readability and easiness of writing.
Playtest is done.
Regards,
--- Soji
--
株式会社 コンバージョン セキュリティ&OSSソリューション部 池田荘児
〒231-0004 神奈川県横浜市中区元浜町3-21-2 ヘリオス関内ビル7F
e-mail address@concealed TEL 045-640-3550
http://www.conversion.co.jp/
package Sympa::Tools::File;
#...
=over
=item set_file_rights(%parameters)
Sets owner and/or access rights on a file.
=back
=cut
sub set_file_rights {
my %param = @_;
my ( $uid, $gid );
if ( $param{'user'} ) {
unless ( $uid = ( getpwnam( $param{'user'} ) )[2] ) {
Sympa::Log::Syslog::do_log( 'err',
"User %s can't be found in passwd file",
$param{'user'} );
return undef;
}
} else {
# A value of -1 is interpreted by most systems to leave that value
# unchanged.
$uid = -1;
}
if ( $param{'group'} ) {
unless ( $gid = ( getgrnam( $param{'group'} ) )[2] ) {
Sympa::Log::Syslog::do_log( 'err', "Group %s can't be found",
$param{'group'} );
return undef;
}
} else {
# A value of -1 is interpreted by most systems to leave that value
# unchanged.
$gid = -1;
}
unless ( chown( $uid, $gid, $param{'file'} ) ) {
Sympa::Log::Syslog::do_log( 'err',
"Can't give ownership of file %s to %s.%s: %s",
$param{'file'}, $param{'user'}, $param{'group'}, "$!" );
return undef;
}
if ( $param{'mode'} ) {
unless ( chmod( $param{'mode'}, $param{'file'} ) ) {
Sympa::Log::Syslog::do_log( 'err',
"Can't change rights of file %s to %o: %s",
$param{'file'}, $param{'mode'}, "$!" );
return undef;
}
}
return 1;
}
#...
package Sympa::Upgrade;
#...
=over
=item to_utf8($files)
Used to encode files to UTF-8. also add X-Attach header field if template
requires it
Parameters:
=over
=item arrayref
A list of filepath/lang pairs
=back
=back
=cut
sub to_utf8 {
my $files = shift;
my $with_attachments = qr{ archive.tt2 | digest.tt2 | get_archive.tt2 |
listmaster_notification.tt2 | message_report.tt2 | moderate.tt2 |
modindex.tt2 | send_auth.tt2 }x;
my $total;
foreach my $pair ( @{$files} ) {
my ( $file, $lang ) = @$pair;
unless ( open( TEMPLATE, $file ) ) {
Sympa::Log::Syslog::do_log( 'err', "Cannot open template %s",
$file );
next;
}
my $text = '';
my $modified = 0;
## If filesystem_encoding is set, files are supposed to be encoded
according to it
my $charset;
if ( ( defined $Conf::Conf::Ignored_Conf{'filesystem_encoding'} ) &
( $Conf::Conf::Ignored_Conf{'filesystem_encoding'} ne 'utf-8' ) )
{
$charset = $Conf::Conf::Ignored_Conf{'filesystem_encoding'};
} else {
Sympa::Language::PushLang($lang);
$charset = Sympa::Language::GetCharset;
Sympa::Language::PopLang;
}
# Add X-Sympa-Attach: headers if required.
if ( ( $file =~ /mail_tt2/ )
&& ( $file =~ /\/($with_attachments)$/ ) ) {
while (<TEMPLATE>) {
$text .= $_;
if (m/^Content-Type:\s*message\/rfc822/i) {
while (<TEMPLATE>) {
if (m{^X-Sympa-Attach:}i) {
$text .= $_;
last;
}
if (m/^[\r\n]+$/) {
$text .= "X-Sympa-Attach: yes\n";
$modified = 1;
$text .= $_;
last;
}
$text .= $_;
}
}
}
} else {
$text = join( '', <TEMPLATE> );
}
close TEMPLATE;
# Check if template is encoded by UTF-8.
if ( $text =~ /[^\x20-\x7E]/ ) {
my $t = $text;
eval { Encode::decode( 'UTF-8', $t, Encode::FB_CROAK ); };
if ($@) {
eval {
$t = $text;
Encode::from_to( $t, $charset, "UTF-8",
Encode::FB_CROAK );
};
if ($@) {
Sympa::Log::Syslog::do_log( 'err',
"Template %s cannot be converted from %s to UTF-8",
$charset, $file );
} else {
$text = $t;
$modified = 1;
}
}
}
next unless $modified;
my $date = strftime( "%Y.%m.%d-%H.%M.%S", localtime(time) );
unless ( rename $file, $file . '@' . $date ) {
Sympa::Log::Syslog::do_log( 'err',
"Cannot rename old template %s", $file );
next;
}
unless ( open( TEMPLATE, ">$file" ) ) {
Sympa::Log::Syslog::do_log( 'err', "Cannot open new template %s",
$file );
next;
}
print TEMPLATE $text;
close TEMPLATE;
unless (
Sympa::Tools::set_file_rights(
file => $file,
user => Sympa::Constants::USER,
group => Sympa::Constants::GROUP,
mode => 0644,
)
) {
Sympa::Log::Syslog::do_log( 'err', 'Unable to set rights on %s',
$file );
next;
}
Sympa::Log::Syslog::do_log( 'notice',
'Modified file %s ; original file kept as %s',
$file, $file . '@' . $date );
$total++;
}
return $total;
}
#...
package Sympa::Configuration;
#...
=over
=item checkfiles_as_root()
Check required files and create them if required
=back
=cut
sub checkfiles_as_root {
my $config_err = 0;
## Check aliases file
unless ( -f $Conf{'sendmail_aliases'}
|| ( $Conf{'sendmail_aliases'} =~ /^none$/i ) ) {
unless ( open ALIASES, ">$Conf{'sendmail_aliases'}" ) {
Sympa::Log::Syslog::do_log(
'err',
"Failed to create aliases file %s",
$Conf{'sendmail_aliases'}
);
# printf STDERR "Failed to create aliases file %s", $Conf{'sendmail_aliases'};
return undef;
}
print ALIASES
"## This aliases file is dedicated to Sympa Mailing List
Manager\n";
print ALIASES
"## You should edit your sendmail.mc or sendmail.cf file to
declare it\n";
close ALIASES;
Sympa::Log::Syslog::do_log(
'notice',
"Created missing file %s",
$Conf{'sendmail_aliases'}
);
unless (
Sympa::Tools::File::set_file_rights(
file => $Conf{'sendmail_aliases'},
user => Sympa::Constants::USER,
group => Sympa::Constants::GROUP,
mode => 0644,
)
) {
Sympa::Log::Syslog::do_log(
'err',
'Unable to set rights on %s',
$Conf{'sendmail_aliases'}
);
return undef;
}
}
foreach my $robot ( keys %{ $Conf{'robots'} } ) {
# create static content directory
my $dir = get_robot_conf( $robot, 'static_content_path' );
if ( $dir ne '' && !-d $dir ) {
unless ( mkdir( $dir, 0775 ) ) {
Sympa::Log::Syslog::do_log( 'err',
'Unable to create directory %s: %s',
$dir, $ERRNO );
printf STDERR 'Unable to create directory %s: %s', $dir,
$ERRNO;
$config_err++;
}
unless (
Sympa::Tools::File::set_file_rights(
file => $dir,
user => Sympa::Constants::USER,
group => Sympa::Constants::GROUP,
)
) {
Sympa::Log::Syslog::do_log( 'err',
'Unable to set rights on %s', $dir );
return undef;
}
}
}
return 1;
}
#...
package Sympa::Tools::Daemon;
#...
=over
=item write_pid(%parameters)
Parameters:
=over
=item C<directory> => path
The PID file directory.
=item C<daemon> => string
The daemon name.
=item C<pid> => string
The daemon PID.
=item C<multiple_process> => boolean
FIXME
=item C<method> => string
The PID file locking method.
=item C<user> => string
The PID file user.
=item C<group> => string
The PID file group.
=back
=back
=cut
sub write_pid {
my (%params) = @_;
## Create piddir
mkdir( $params{directory}, 0755 ) unless ( -d $params{directory} );
unless (
Sympa::Tools::File::set_file_rights(
file => $params{directory},
user => $params{user},
group => $params{group},
)
) {
Sympa::Log::Syslog::do_log( 'err', 'Unable to set rights on %s',
$params{directory} );
return undef;
}
my $pid_file = _get_pid_file(%params);
my @pids;
# Lock pid file
my $lock = Sympa::Lock->new(
path => $pid_file,
method => $params{method},
user => $params{user},
group => $params{group},
);
unless ( defined $lock ) {
Sympa::Log::Syslog::do_log( 'err', 'Lock could not be created.' );
return;
}
$lock->set_timeout(5);
unless ( $lock->lock('write') ) {
Sympa::Log::Syslog::do_log( 'err',
'Unable to lock %s file in write mode.', $pid_file );
return;
}
## If pidfile exists, read the PIDs
if ( -f $pid_file ) {
# Read pid file
open( PFILE, '<', $pid_file );
my $l = <PFILE>;
close PFILE;
@pids = grep {/[0-9]+/} split( /\s+/, $l );
}
## If we can have multiple instances for the process.
## Print other pids + this one
if ( $params{multiple_process} ) {
unless ( open( PIDFILE, '>', $pid_file ) ) {
## Unlock pid file
$lock->unlock();
Sympa::Log::Syslog::do_log( 'err', 'Could not open %s: %s',
$pid_file, $ERRNO );
return;
}
## Print other pids + this one
push( @pids, $params{pid} );
print PIDFILE join( ' ', @pids ) . "\n";
close(PIDFILE);
} else {
## Create and write the pidfile
unless ( open( PIDFILE, '+>>', $pid_file ) ) {
## Unlock pid file
$lock->unlock();
Sympa::Log::Syslog::do_log( 'err', 'Could not open %s: %s',
$pid_file );
return;
}
## The previous process died suddenly, without pidfile cleanup
## Send a notice to listmaster with STDERR of the previous process
if ( $#pids >= 0 ) {
my $other_pid = $pids[0];
Sympa::Log::Syslog::do_log( 'notice',
"Previous process %s died suddenly ; notifying listmaster",
$other_pid );
send_crash_report(
directory => $params{directory},
daemon => $params{daemon},
pid => $other_pid,
);
}
#unless ( open( PIDFILE, '>', $pid_file ) ) {
# ## Unlock pid file
# $lock->unlock();
# Sympa::Log::Syslog::do_log( 'err', 'Could not open %s',
# $pid_file );
# return;
#}
unless ( seek( PIDFILE, 0, 0 ) and truncate( PIDFILE, 0 ) ) {
## Unlock pid file
$lock->unlock();
Sympa::Log::Syslog::do_log( 'err', 'Could not truncate %s.',
$pid_file );
return;
}
print PIDFILE $params{pid} . "\n";
close(PIDFILE);
}
unless (
Sympa::Tools::File::set_file_rights(
file => $pid_file,
user => $params{user},
group => $params{group}
)
) {
## Unlock pid file
$lock->unlock();
Sympa::Log::Syslog::do_log( 'err', 'Unable to set rights on %s',
$pid_file );
return;
}
## Unlock pid file
$lock->unlock();
return 1;
}
#...
# Revised
package Sympa::Tools::File;
use Sympa::Exception
'Sympa::Exception::File',
;
#...
=over
=item set_file_rights(%parameters)
Sets owner and/or access rights on a file.
Throws an exception Sympa::Exception::File
if something went wrong.
=back
=cut
sub set_file_rights {
my %param = @_;
my ( $uid, $gid );
if ( $param{'user'} ) {
unless ( $uid = ( getpwnam( $param{'user'} ) )[2] ) {
Sympa::Exception::File->throw(
sprintf "User %s can't be found in passwd file",
$param{'user'} );
}
} else {
# A value of -1 is interpreted by most systems to leave that value
# unchanged.
$uid = -1;
}
if ( $param{'group'} ) {
unless ( $gid = ( getgrnam( $param{'group'} ) )[2] ) {
Sympa::Exception::File->throw( sprintf "Group %s can't be found",
$param{'group'} );
}
} else {
# A value of -1 is interpreted by most systems to leave that value
# unchanged.
$gid = -1;
}
unless ( chown( $uid, $gid, $param{'file'} ) ) {
Sympa::Exception::File->throw(
sprintf "Can't give ownership of file %s to %s.%s: %s",
$param{'file'}, $param{'user'}, $param{'group'}, "$!" );
}
if ( $param{'mode'} ) {
unless ( chmod( $param{'mode'}, $param{'file'} ) ) {
Sympa::Exception::File->throw(
"Can't change rights of file %s to %o: %s",
$param{'file'}, $param{'mode'}, "$!" );
}
}
}
#...
# Revised
package Sympa::Upgrade;
#...
=over
=item to_utf8($files)
Used to encode files to UTF-8. also add X-Attach header field if template
requires it
Parameters:
=over
=item arrayref
A list of filepath/lang pairs
=back
=back
=cut
sub to_utf8 {
my $files = shift;
my $with_attachments = qr{ archive.tt2 | digest.tt2 | get_archive.tt2 |
listmaster_notification.tt2 | message_report.tt2 | moderate.tt2 |
modindex.tt2 | send_auth.tt2 }x;
my $total;
foreach my $pair ( @{$files} ) {
my ( $file, $lang ) = @$pair;
unless ( open( TEMPLATE, $file ) ) {
Sympa::Log::Syslog::do_log( 'err', "Cannot open template %s",
$file );
next;
}
my $text = '';
my $modified = 0;
## If filesystem_encoding is set, files are supposed to be encoded
according to it
my $charset;
if ( ( defined $Conf::Conf::Ignored_Conf{'filesystem_encoding'} ) &
( $Conf::Conf::Ignored_Conf{'filesystem_encoding'} ne 'utf-8' ) )
{
$charset = $Conf::Conf::Ignored_Conf{'filesystem_encoding'};
} else {
Sympa::Language::PushLang($lang);
$charset = Sympa::Language::GetCharset;
Sympa::Language::PopLang;
}
# Add X-Sympa-Attach: headers if required.
if ( ( $file =~ /mail_tt2/ )
&& ( $file =~ /\/($with_attachments)$/ ) ) {
while (<TEMPLATE>) {
$text .= $_;
if (m/^Content-Type:\s*message\/rfc822/i) {
while (<TEMPLATE>) {
if (m{^X-Sympa-Attach:}i) {
$text .= $_;
last;
}
if (m/^[\r\n]+$/) {
$text .= "X-Sympa-Attach: yes\n";
$modified = 1;
$text .= $_;
last;
}
$text .= $_;
}
}
}
} else {
$text = join( '', <TEMPLATE> );
}
close TEMPLATE;
# Check if template is encoded by UTF-8.
if ( $text =~ /[^\x20-\x7E]/ ) {
my $t = $text;
eval { Encode::decode( 'UTF-8', $t, Encode::FB_CROAK ); };
if ($@) {
eval {
$t = $text;
Encode::from_to( $t, $charset, "UTF-8",
Encode::FB_CROAK );
};
if ($@) {
Sympa::Log::Syslog::do_log( 'err',
"Template %s cannot be converted from %s to UTF-8",
$charset, $file );
} else {
$text = $t;
$modified = 1;
}
}
}
next unless $modified;
my $date = strftime( "%Y.%m.%d-%H.%M.%S", localtime(time) );
unless ( rename $file, $file . '@' . $date ) {
Sympa::Log::Syslog::do_log( 'err',
"Cannot rename old template %s", $file );
next;
}
unless ( open( TEMPLATE, ">$file" ) ) {
Sympa::Log::Syslog::do_log( 'err', "Cannot open new template %s",
$file );
next;
}
print TEMPLATE $text;
close TEMPLATE;
eval {
Sympa::Tools::set_file_rights(
file => $file,
user => Sympa::Constants::USER,
group => Sympa::Constants::GROUP,
mode => 0644,
);
};
if ( my $e = Sympa::Exception->catch ) {
if ( $e->isa 'Sympa::Exception::File' ) {
Sympa::Log::Syslog::do_log( 'err', '%s', $e->full_message );
} else {
$e->throw;
}
next;
}
Sympa::Log::Syslog::do_log( 'notice',
'Modified file %s ; original file kept as %s',
$file, $file . '@' . $date );
$total++;
}
return $total;
}
#...
# Revised
package Sympa::Configuration;
#...
=over
=item checkfiles_as_root()
Check required files and create them if required
Throws exception if something went wrong.
=back
=cut
sub checkfiles_as_root {
my $config_err = 0;
## Check aliases file
unless ( -f $Conf{'sendmail_aliases'}
|| ( $Conf{'sendmail_aliases'} =~ /^none$/i ) ) {
unless ( open ALIASES, ">$Conf{'sendmail_aliases'}" ) {
Sympa::Log::Syslog::do_log(
'err',
"Failed to create aliases file %s",
$Conf{'sendmail_aliases'}
);
# printf STDERR "Failed to create aliases file %s", $Conf{'sendmail_aliases'};
return undef;
}
print ALIASES
"## This aliases file is dedicated to Sympa Mailing List
Manager\n";
print ALIASES
"## You should edit your sendmail.mc or sendmail.cf file to
declare it\n";
close ALIASES;
Sympa::Log::Syslog::do_log(
'notice',
"Created missing file %s",
$Conf{'sendmail_aliases'}
);
eval {
Sympa::Tools::File::set_file_rights(
file => $Conf{'sendmail_aliases'},
user => Sympa::Constants::USER,
group => Sympa::Constants::GROUP,
mode => 0644,
);
};
if ( my $e = Sympa::Exception->catch ) {
if ( $e->isa 'Sympa::Exception::File' ) {
Sympa::Log::Syslog::do_log( 'err', '%s', $e->full_message );
} else {
$e->throw;
}
return undef;
}
}
foreach my $robot ( keys %{ $Conf{'robots'} } ) {
# create static content directory
my $dir = get_robot_conf( $robot, 'static_content_path' );
if ( $dir ne '' && !-d $dir ) {
unless ( mkdir( $dir, 0775 ) ) {
Sympa::Log::Syslog::do_log( 'err',
'Unable to create directory %s: %s',
$dir, $ERRNO );
printf STDERR 'Unable to create directory %s: %s', $dir,
$ERRNO;
$config_err++;
}
eval {
Sympa::Tools::File::set_file_rights(
file => $dir,
user => Sympa::Constants::USER,
group => Sympa::Constants::GROUP,
);
};
if ( my $e = Sympa::Exception->catch ) {
if ( $e->isa 'Sympa::Exception::File' ) {
Sympa::Log::Syslog::do_log( 'err', '%s',
$e->full_message );
} else {
$e->throw;
}
return undef;
}
}
}
return 1;
}
#...
# Revised
package Sympa::Tools::Daemon;
#...
# These throw exceptions on failure.
use Sympa::Exception::AutoDie qw(close open seek truncate);
#...
=over
=item write_pid(%parameters)
Parameters:
=over
=item C<directory> => path
The PID file directory.
=item C<daemon> => string
The daemon name.
=item C<pid> => string
The daemon PID.
=item C<multiple_process> => boolean
FIXME
=item C<method> => string
The PID file locking method.
=item C<user> => string
The PID file user.
=item C<group> => string
The PID file group.
=back
Throws exceptions if something went wrong.
=back
=cut
sub write_pid {
my (%params) = @_;
## Create piddir
mkdir( $params{directory}, 0755 ) unless ( -d $params{directory} );
eval {
Sympa::Tools::File::set_file_rights(
file => $params{directory},
user => $params{user},
group => $params{group},
);
};
if ( my $e = Sympa::Exception->catch ) {
rmdir $params{directory};
$e->throw;
}
my $pid_file = _get_pid_file(%params);
my @pids;
# Lock pid file
# NOTE: new(), set_timeout() and lock() are assumed to throw exception on
# failure.
my $lock = Sympa::Lock->new(
path => $pid_file,
method => $params{method},
user => $params{user},
group => $params{group},
);
$lock->set_timeout(5);
$lock->lock('write');
## If pidfile exists, read the PIDs
if ( -f $pid_file ) {
# Read pid file
open( PFILE, '<', $pid_file );
my $l = <PFILE>;
close PFILE;
@pids = grep {/[0-9]+/} split( /\s+/, $l );
}
eval {
## If we can have multiple instances for the process.
## Print other pids + this one
if ( $params{multiple_process} ) {
open( PIDFILE, '>', $pid_file );
## Print other pids + this one
push( @pids, $params{pid} );
print PIDFILE join( ' ', @pids ) . "\n";
close(PIDFILE);
} else {
## Create and write the pidfile
open( PIDFILE, '+>>', $pid_file );
eval {
## The previous process died suddenly, without pidfile cleanup
## Send a notice to listmaster with STDERR of the previous
process
if ( $#pids >= 0 ) {
my $other_pid = $pids[0];
Sympa::Log::Syslog::do_log(
'notice',
"Previous process %s died suddenly ; notifying
listmaster",
$other_pid
);
send_crash_report(
directory => $params{directory},
daemon => $params{daemon},
pid => $other_pid,
);
}
#unless ( open( PIDFILE, '>', $pid_file ) ) {
# ## Unlock pid file
# $lock->unlock();
# Sympa::Log::Syslog::do_log( 'err', 'Could not open %s',
# $pid_file );
# return;
#}
seek( PIDFILE, 0, 0 );
truncate( PIDFILE, 0 );
print PIDFILE $params{pid} . "\n";
};
if ( my $e = Sympa::Exception->catch ) {
## Close pid file
close PIDFILE;
$e->throw;
}
## Close pid file
close(PIDFILE);
}
Sympa::Tools::File::set_file_rights(
file => $pid_file,
user => $params{user},
group => $params{group}
);
};
if ( my $e = Sympa::Exception->catch ) {
## Unlock pid file
$lock->unlock();
$e->throw;
}
## Unlock pid file
$lock->unlock();
return 1;
}
#...
# Revised #2
package Sympa::Configuration;
#...
# This throws exception on failure.
use Sympa::Exception::AutoDie qw(close mkdir open);
#...
=over
=item checkfiles_as_root()
Check required files and create them if required
Throws exception if something went wrong.
=back
=cut
sub checkfiles_as_root {
my $config_err = 0;
## Check aliases file
unless ( -f $Conf{'sendmail_aliases'}
|| ( $Conf{'sendmail_aliases'} =~ /^none$/i ) ) {
open ALIASES, ">$Conf{'sendmail_aliases'}";
print ALIASES
"## This aliases file is dedicated to Sympa Mailing List
Manager\n";
print ALIASES
"## You should edit your sendmail.mc or sendmail.cf file to
declare it\n";
close ALIASES;
Sympa::Log::Syslog::do_log(
'notice',
"Created missing file %s",
$Conf{'sendmail_aliases'}
);
Sympa::Tools::File::set_file_rights(
file => $Conf{'sendmail_aliases'},
user => Sympa::Constants::USER,
group => Sympa::Constants::GROUP,
mode => 0644,
);
}
foreach my $robot ( keys %{ $Conf{'robots'} } ) {
# create static content directory
my $dir = get_robot_conf( $robot, 'static_content_path' );
if ( $dir ne '' && !-d $dir ) {
eval { mkdir( $dir, 0775 ); };
if ( my $e = Sympa::Exception->catch ) {
Sympa::Log::Syslog::do_log( 'err', '%s', $e->full_message );
print STDERR $e->full_message;
$config_err++;
}
Sympa::Tools::File::set_file_rights(
file => $dir,
user => Sympa::Constants::USER,
group => Sympa::Constants::GROUP,
);
}
}
}
#...
-
Re: [sympa-developpers] Merge is over, what now?,
David Verdin, 10/01/2013
-
Re: [sympa-developpers] Merge is over, what now?,
IKEDA Soji, 10/02/2013
- Re: [sympa-developpers] Merge is over, what now?, Guillaume Rousse, 10/03/2013
- <Possible follow-up(s)>
-
Re: [sympa-developpers] Merge is over, what now?,
IKEDA Soji, 10/02/2013
-
Re: [sympa-developpers] Merge is over, what now?,
David Verdin, 10/02/2013
-
Re: [sympa-developpers] Merge is over, what now?,
IKEDA Soji, 10/03/2013
-
Re: [sympa-developpers] Merge is over, what now?,
Guillaume Rousse, 10/03/2013
-
[sympa-developpers] Using exception,
IKEDA Soji, 10/04/2013
-
Re: [sympa-developpers] Using exception,
Guillaume Rousse, 10/07/2013
- Re: [sympa-developpers] Using exception, Guillaume Rousse, 10/07/2013
- Re: [sympa-developpers] Using exception, IKEDA Soji, 10/21/2013
- Re: [sympa-developpers] Using exception, Guillaume Rousse, 10/21/2013
-
Re: [sympa-developpers] Using exception,
Guillaume Rousse, 10/07/2013
-
[sympa-developpers] Using exception,
IKEDA Soji, 10/04/2013
-
Message not available
- Re: [sympa-developpers] Using exception, IKEDA Soji, 10/14/2013
- Re: [sympa-developpers] Using exception, IKEDA Soji, 10/16/2013
-
Re: [sympa-developpers] Merge is over, what now?,
Guillaume Rousse, 10/03/2013
-
Re: [sympa-developpers] Merge is over, what now?,
IKEDA Soji, 10/03/2013
-
Re: [sympa-developpers] Merge is over, what now?,
David Verdin, 10/02/2013
-
Re: [sympa-developpers] Merge is over, what now?,
IKEDA Soji, 10/02/2013
-
[sympa-developpers] coding style,
Guillaume Rousse, 10/03/2013
- Re: [sympa-developpers] coding style, Guillaume Rousse, 10/07/2013
Archive powered by MHonArc 2.6.19+.