Acme-Ghost
view release on metacpan or search on metacpan
lib/Acme/Ghost.pm view on Meta::CPAN
die "Detected strange UID. Couldn't become UID \"$uid\": $!\n";
}
}
return $self;
}
sub set_gid {
my $self = shift;
my $gids = shift // $self->{gids};
return $self unless IS_ROOT; # Skip if no ROOT
return $self unless defined $gids; # Skip if no GIDs
# Get GIDs
my $gid = (split /\s+/, $gids)[0]; # Get first GID
$) = "$gid $gids"; # store all the GIDs (calls setgroups)
POSIX::setgid($gid) || die "Setgid $gid failed - $!\n"; # Set first GID
if (! grep {$gid == $_} split /\s+/, $() { # look for any valid id in the list
die "Detected strange GID. Couldn't become GID \"$gid\": $!\n";
}
return $self;
}
sub daemonize {
my $self = shift;
my $safe = shift;
croak "This process is already daemonized (PID=$$)\n" if $self->{daemonized};
# Check PID
my $pid_file = $self->filepid->file; # PID File
if ( my $runned = $self->filepid->running ) {
die "Already running $runned\n";
}
# Store current PID to instance as Parent PID
$self->{ppid} = $$;
# Get UID & GID
my $uid = $self->{uid}; # UID
my $gids = $self->{gid}; # returns list of groups (gids)
my $gid = (split /[\s,]+/, $gids)[0]; # First GID
_debug("!! UID=%s; GID=%s; GIDs=\"%s\"", $uid, $gid, $gids);
# Pre Init Hook
$self->preinit;
$self->{_log} = undef; # Close log handlers before spawn
# Spawn
my $pid = _fork();
if ($pid) {
_debug("!! Spawned (PID=%s)", $pid);
if ($safe) { # For internal use only
$self->{pid} = $pid; # Store child PID to instance
return $self;
}
exit 0; # exit parent process
}
# Child
$self->{daemonized} = 1; # Set daemonized flag
$self->filepid->pid($$)->save; # Set new PID and Write PID file
chown($uid, $gid, $pid_file) if IS_ROOT && -e $pid_file;
# Set GID and UID
$self->set_gid->set_uid;
# Turn process into session leader, and ensure no controlling terminal
unless (DEBUG) {
die "Can't start a new session: $!" if POSIX::setsid() < 0;
}
# Init logger!
my $log = $self->log;
# Close all standart filehandles
unless (DEBUG) {
my $devnull = File::Spec->devnull;
open STDIN, '<', $devnull or die "Can't open STDIN from $devnull: $!\n";
open STDOUT, '>', $devnull or die "Can't open STDOUT to $devnull: $!\n";
open STDERR, '>&', STDOUT or die "Can't open STDERR to $devnull: $!\n";
}
# Chroot if root
if (IS_ROOT) {
my $rootdir = File::Spec->rootdir;
unless (chdir $rootdir) {
$log->fatal("Can't chdir to \"$rootdir\": $!");
die "Can't chdir to \"$rootdir\": $!\n";
}
}
# Clear the file creation mask
umask 0;
# Store current PID to instance
$self->{pid} = $$;
# Set a signal handler to make sure SIGINT's remove our pid_file
$SIG{TERM} = $SIG{INT} = sub {
POSIX::_exit(1) if $self->is_spirited;
$self->cleanup(1);
$log->fatal("Termination on INT/TERM signal");
$self->filepid->remove;
POSIX::_exit(1);
};
# Init Hook
$self->init;
return $self;
}
sub is_daemonized { shift->{daemonized} }
sub is_spirited { shift->{spirited} }
sub pid { shift->{pid} }
# Hooks
sub preinit { }
sub init { }
sub cleanup { } # 0 -- at destroy; 1 -- at interrupt
sub startup { }
sub hangup { }
( run in 1.600 second using v1.01-cache-2.11-cpan-71847e10f99 )