6931
6931
use warnings FATAL => 'all';
6932
6932
use English qw(-no_match_vars);
6933
6934
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
6935
6936
use POSIX qw(setsid);
6937
use Fcntl qw(:DEFAULT);
6938
my ( $class, %args ) = @_;
6939
foreach my $arg ( qw(o) ) {
6940
die "I need a $arg argument" unless $args{$arg};
6940
my ($class, %args) = @_;
6945
log_file => $o->has('log') ? $o->get('log') : undef,
6946
PID_file => $o->has('pid') ? $o->get('pid') : undef,
6942
log_file => $args{log_file},
6943
pid_file => $args{pid_file},
6944
daemonize => $args{daemonize},
6945
force_log_file => $args{force_log_file},
6946
parent_exit => $args{parent_exit},
6947
pid_file_owner => 0,
6949
check_PID_file(undef, $self->{PID_file});
6951
PTDEBUG && _d('Daemonized child will log to', $self->{log_file});
6952
6949
return bless $self, $class;
6958
PTDEBUG && _d('About to fork and daemonize');
6959
defined (my $pid = fork()) or die "Cannot fork: $OS_ERROR";
6961
PTDEBUG && _d('Parent PID', $PID, 'exiting after forking child PID',$pid);
6965
PTDEBUG && _d('Daemonizing child PID', $PID);
6966
$self->{PID_owner} = $PID;
6969
POSIX::setsid() or die "Cannot start a new session: $OS_ERROR";
6970
chdir '/' or die "Cannot chdir to /: $OS_ERROR";
6972
$self->_make_PID_file();
6974
$OUTPUT_AUTOFLUSH = 1;
6976
PTDEBUG && _d('Redirecting STDIN to /dev/null');
6978
open STDIN, '/dev/null'
6979
or die "Cannot reopen STDIN to /dev/null: $OS_ERROR";
6981
if ( $self->{log_file} ) {
6982
PTDEBUG && _d('Redirecting STDOUT and STDERR to', $self->{log_file});
6984
open STDOUT, '>>', $self->{log_file}
6985
or die "Cannot open log file $self->{log_file}: $OS_ERROR";
6988
open STDERR, ">&STDOUT"
6989
or die "Cannot dupe STDERR to STDOUT: $OS_ERROR";
6993
PTDEBUG && _d('No log file and STDOUT is a terminal;',
6994
'redirecting to /dev/null');
6955
my $daemonize = $self->{daemonize};
6956
my $pid_file = $self->{pid_file};
6957
my $log_file = $self->{log_file};
6958
my $force_log_file = $self->{force_log_file};
6959
my $parent_exit = $self->{parent_exit};
6961
PTDEBUG && _d('Starting daemon');
6965
$self->_make_pid_file(
6966
pid => $PID, # parent's pid
6967
pid_file => $pid_file,
6970
die "$EVAL_ERROR\n" if $EVAL_ERROR;
6971
if ( !$daemonize ) {
6972
$self->{pid_file_owner} = $PID; # parent's pid
6977
defined (my $child_pid = fork()) or die "Cannot fork: $OS_ERROR";
6979
PTDEBUG && _d('Forked child', $child_pid);
6980
$parent_exit->($child_pid) if $parent_exit;
6984
POSIX::setsid() or die "Cannot start a new session: $OS_ERROR";
6985
chdir '/' or die "Cannot chdir to /: $OS_ERROR";
6988
$self->_update_pid_file(
6989
pid => $PID, # child's pid
6990
pid_file => $pid_file,
6992
$self->{pid_file_owner} = $PID;
6996
if ( $daemonize || $force_log_file ) {
6997
PTDEBUG && _d('Redirecting STDIN to /dev/null');
6999
open STDIN, '/dev/null'
7000
or die "Cannot reopen STDIN to /dev/null: $OS_ERROR";
7002
PTDEBUG && _d('Redirecting STDOUT and STDERR to', $log_file);
6996
open STDOUT, '>', '/dev/null'
6997
or die "Cannot reopen STDOUT to /dev/null: $OS_ERROR";
7000
PTDEBUG && _d('No log file and STDERR is a terminal;',
7001
'redirecting to /dev/null');
7004
open STDOUT, '>>', $log_file
7005
or die "Cannot open log file $log_file: $OS_ERROR";
7003
open STDERR, '>', '/dev/null'
7004
or die "Cannot reopen STDERR to /dev/null: $OS_ERROR";
7011
sub check_PID_file {
7012
my ( $self, $file ) = @_;
7013
my $PID_file = $self ? $self->{PID_file} : $file;
7014
PTDEBUG && _d('Checking PID file', $PID_file);
7015
if ( $PID_file && -f $PID_file ) {
7018
chomp($pid = (slurp_file($PID_file) || ''));
7020
if ( $EVAL_ERROR ) {
7021
die "The PID file $PID_file already exists but it cannot be read: "
7024
PTDEBUG && _d('PID file exists; it contains PID', $pid);
7026
my $pid_is_alive = kill 0, $pid;
7008
open STDERR, ">&STDOUT"
7009
or die "Cannot dupe STDERR to STDOUT: $OS_ERROR";
7013
PTDEBUG && _d('No log file and STDOUT is a terminal;',
7014
'redirecting to /dev/null');
7016
open STDOUT, '>', '/dev/null'
7017
or die "Cannot reopen STDOUT to /dev/null: $OS_ERROR";
7020
PTDEBUG && _d('No log file and STDERR is a terminal;',
7021
'redirecting to /dev/null');
7023
open STDERR, '>', '/dev/null'
7024
or die "Cannot reopen STDERR to /dev/null: $OS_ERROR";
7028
$OUTPUT_AUTOFLUSH = 1;
7031
PTDEBUG && _d('Daemon running');
7035
sub _make_pid_file {
7036
my ($self, %args) = @_;
7037
my @required_args = qw(pid pid_file);
7038
foreach my $arg ( @required_args ) {
7039
die "I need a $arg argument" unless $args{$arg};
7041
my $pid = $args{pid};
7042
my $pid_file = $args{pid_file};
7045
sysopen(PID_FH, $pid_file, O_RDWR|O_CREAT|O_EXCL) or die $OS_ERROR;
7046
print PID_FH $PID, "\n";
7049
if ( my $e = $EVAL_ERROR ) {
7050
if ( $e =~ m/file exists/i ) {
7051
my $old_pid = $self->_check_pid_file(
7052
pid_file => $pid_file,
7056
warn "Overwriting PID file $pid_file because PID $old_pid "
7057
. "is not running.\n";
7059
$self->_update_pid_file(
7061
pid_file => $pid_file
7065
die "Error creating PID file $pid_file: $e\n";
7072
sub _check_pid_file {
7073
my ($self, %args) = @_;
7074
my @required_args = qw(pid_file pid);
7075
foreach my $arg ( @required_args ) {
7076
die "I need a $arg argument" unless $args{$arg};
7078
my $pid_file = $args{pid_file};
7079
my $pid = $args{pid};
7081
PTDEBUG && _d('Checking if PID in', $pid_file, 'is running');
7083
if ( ! -f $pid_file ) {
7084
PTDEBUG && _d('PID file', $pid_file, 'does not exist');
7088
open my $fh, '<', $pid_file
7089
or die "Error opening $pid_file: $OS_ERROR";
7090
my $existing_pid = do { local $/; <$fh> };
7091
chomp($existing_pid) if $existing_pid;
7093
or die "Error closing $pid_file: $OS_ERROR";
7095
if ( $existing_pid ) {
7096
if ( $existing_pid == $pid ) {
7097
warn "The current PID $pid already holds the PID file $pid_file\n";
7101
PTDEBUG && _d('Checking if PID', $existing_pid, 'is running');
7102
my $pid_is_alive = kill 0, $existing_pid;
7027
7103
if ( $pid_is_alive ) {
7028
die "The PID file $PID_file already exists "
7029
. " and the PID that it contains, $pid, is running";
7032
warn "Overwriting PID file $PID_file because the PID that it "
7033
. "contains, $pid, is not running";
7037
die "The PID file $PID_file already exists but it does not "
7104
die "PID file $pid_file exists and PID $existing_pid is running\n";
7042
PTDEBUG && _d('No PID file');
7049
if ( exists $self->{child} ) {
7050
die "Do not call Daemon::make_PID_file() for daemonized scripts";
7052
$self->_make_PID_file();
7053
$self->{PID_owner} = $PID;
7057
sub _make_PID_file {
7060
my $PID_file = $self->{PID_file};
7062
PTDEBUG && _d('No PID file to create');
7066
$self->check_PID_file();
7068
open my $PID_FH, '>', $PID_file
7069
or die "Cannot open PID file $PID_file: $OS_ERROR";
7071
or die "Cannot print to PID file $PID_file: $OS_ERROR";
7073
or die "Cannot close PID file $PID_file: $OS_ERROR";
7075
PTDEBUG && _d('Created PID file:', $self->{PID_file});
7079
sub _remove_PID_file {
7081
if ( $self->{PID_file} && -f $self->{PID_file} ) {
7082
unlink $self->{PID_file}
7083
or warn "Cannot remove PID file $self->{PID_file}: $OS_ERROR";
7109
die "PID file $pid_file exists but it is empty. Remove the file "
7110
. "if the process is no longer running.\n";
7113
return $existing_pid;
7116
sub _update_pid_file {
7117
my ($self, %args) = @_;
7118
my @required_args = qw(pid pid_file);
7119
foreach my $arg ( @required_args ) {
7120
die "I need a $arg argument" unless $args{$arg};
7122
my $pid = $args{pid};
7123
my $pid_file = $args{pid_file};
7125
open my $fh, '>', $pid_file
7126
or die "Cannot open $pid_file: $OS_ERROR";
7127
print { $fh } $pid, "\n"
7128
or die "Cannot print to $pid_file: $OS_ERROR";
7130
or warn "Cannot close $pid_file: $OS_ERROR";
7135
sub remove_pid_file {
7136
my ($self, $pid_file) = @_;
7137
$pid_file ||= $self->{pid_file};
7138
if ( $pid_file && -f $pid_file ) {
7139
unlink $self->{pid_file}
7140
or warn "Cannot remove PID file $pid_file: $OS_ERROR";
7084
7141
PTDEBUG && _d('Removed PID file');
11501
11609
=head1 EXIT STATUS
11503
A non-zero exit status indicates errors, warnings, or checksum differences.
11611
pt-table-checksum has three possible exit statuses: zero, 255, and any other
11612
value is a bitmask with flags for different problems.
11614
A zero exit status indicates no errors, warnings, or checksum differences,
11615
or skipped chunks or tables.
11617
A 255 exit status indicates a fatal error. In other words: the tool died
11618
or crashed. The error is printed to C<STDERR>.
11620
If the exit status is not zero or 255, then its value functions as a bitmask
11623
FLAG BIT VALUE MEANING
11624
================ ========= ==========================================
11625
ERROR 1 A non-fatal error occurred
11626
ALREADY_RUNNING 2 --pid file exists and the PID is running
11627
CAUGHT_SIGNAL 4 Caught SIGHUP, SIGINT, SIGPIPE, or SIGTERM
11628
NO_SLAVES_FOUND 8 No replicas or cluster nodes were found
11629
TABLE_DIFF 16 At least one diff was found
11630
SKIP_CHUNK 32 At least one chunk was skipped
11631
SKIP_TABLE 64 At least one table was skipped
11633
If any flag is set, the exit status will be non-zero. Use the bitwise C<AND>
11634
operation to check for a particular flag. For example, if C<$exit_status & 16>
11635
is true, then at least one diff was found.
11637
As of pt-table-checksum 2.2.5, skipped chunks cause a non-zero exit status.
11638
An exit status of zero or 32 is equivalent to a zero exit status with skipped
11639
chunks in previous versions of the tool.
11505
11641
=head1 OPTIONS