Net-Server

 view release on metacpan or  search on metacpan

lib/Net/Server/Daemonize.pm  view on Meta::CPAN

### change the process to run as this gid(s)
### multiple groups must be space or comma delimited
sub set_gid {
    my $gids = get_gid(@_);
    my $gid  = (split /\s+/, $gids)[0];
    eval { $) = $gids }; # store all the gids - this is really sort of optional

    POSIX::setgid($gid);
    if (! grep {$gid == $_} split /\s+/, $() { # look for any valid id in the list
        die "Couldn't become gid \"$gid\": $!\n";
    }

    return 1;
}

### backward compatibility sub
sub set_user {
    my ($user, @group) = @_;
    set_gid(@group) || return undef;
    set_uid($user)  || return undef;
    return 1;
}

###----------------------------------------------------------------###

### routine to protect process during fork
sub safe_fork () {

    # block signal for fork
    my $sigset = POSIX::SigSet->new(SIGINT);
    POSIX::sigprocmask(SIG_BLOCK, $sigset) or croak "Can't block SIGINT for fork: [$!]";

    my $pid = fork;
    die "Couldn't fork: [$!]" if ! defined $pid;

    $SIG{'INT'} = 'DEFAULT'; # make SIGINT kill us as it did before

    POSIX::sigprocmask(SIG_UNBLOCK, $sigset) or croak "Can't unblock SIGINT for fork: [$!]";

    return $pid;
}

###----------------------------------------------------------------###

### routine to completely dissociate from terminal process.
sub daemonize ($$$) {
    my ($user, $group, $pid_file) = @_;

    check_pid_file($pid_file) if defined $pid_file;

    my $uid = get_uid($user);
    my $gid = get_gid($group); # returns list of groups
    $gid = (split /[\s,]+/, $gid)[0];

    my $pid = safe_fork();

    exit(0) if $pid; # exit parent

    # child
    create_pid_file($pid_file) if defined $pid_file;
    chown($uid, $gid, $pid_file) if defined $pid_file;

    set_user($uid, $gid);

    open STDIN,  '<', '/dev/null' or die "Can't open STDIN from /dev/null: [$!]\n";
    open STDOUT, '>', '/dev/null' or die "Can't open STDOUT to /dev/null: [$!]\n";
    open STDERR, '>&STDOUT'       or die "Can't open STDERR to STDOUT: [$!]\n";

    ### does this mean to be chroot ?
    chdir '/' or croak "Can't chdir to \"/\": [$!]";

    POSIX::setsid(); # Turn process into session leader, and ensure no controlling terminal

    ### install a signal handler to make sure SIGINT's remove our pid_file
    $SIG{'INT'}  = sub { HUNTSMAN($pid_file) } if defined $pid_file;
    return 1;
}

### SIGINT routine that will remove the pid_file
sub HUNTSMAN {
    my $path = shift;
    unlink $path;

    eval {
        require Unix::Syslog;
        Unix::Syslog::syslog(Unix::Syslog::LOG_ERR(), "Exiting on INT signal.");
    };

    exit;
}


1;

__END__

=head1 NAME

Net::Server::Daemonize - Safe fork and daemonization utilities

=head1 SYNOPSIS

    use Net::Server::Daemonize qw(daemonize);

    daemonize(
      'nobody',                 # User
      'nobody',                 # Group
      '/var/state/mydaemon.pid' # Path to PID file - optional
    );

=head1 DESCRIPTION

This module is intended to let you simply and safely daemonize your
server on systems supporting the POSIX module. This means that your
Perl script runs in the background, and it's process ID is stored in a
file so you can easily stop it later.

=head1 EXPORTED FUNCTIONS

=over 4



( run in 1.115 second using v1.01-cache-2.11-cpan-92ad3014f07 )