App-Base

 view release on metacpan or  search on metacpan

lib/App/Base/Daemon.pm  view on Meta::CPAN

                die("Couldn't lock " . $self->pid_file . ". Is another copy of this daemon already running?");
            }
        }
    }

    $SIG{PIPE} = 'IGNORE';    ## no critic (RequireLocalizedPunctuationVars)
    foreach my $signal (@{$self->shutdown_signals}) {
        $SIG{$signal} = sub { App::Base::Daemon::_signal_shutdown($self, @_) };    ## no critic (RequireLocalizedPunctuationVars)
    }

    # Daemonize unless specifically asked not to.
    unless ($self->getOption('no-fork') or $hot_reload) {
        my $child_pid = fork();
        if (!defined($child_pid)) {
            die("Can't fork child process: $!");
        } elsif ($child_pid == 0) {
            POSIX::setsid();
            my $grandchild_pid = fork();
            if (!defined($grandchild_pid)) {
                die("Can't fork grandchild process: $!");
            } elsif ($grandchild_pid != 0) {
                $pid->close if $pid;
                exit 0;
            } else {
                # close all STD* files, and redirect STD* to /dev/null
                for (0 .. 2) {
                    POSIX::close($_) unless $pid and $_ == $pid->fileno;
                }
                (open(STDIN, '<', '/dev/null') and open(STDOUT, '>', '/dev/null') and open(STDERR, '>', '/dev/null'))
                    or die "Couldn't open /dev/null: $!";
            }
        } else {
            waitpid($child_pid, 0);
            $pid->close if $pid;
            return $?;
        }
    }

    $self->_set_user_and_group unless $hot_reload;

    $pid->write_pid if $pid;

    my $result;
    try { $result = $self->daemon_run(@{$self->parsed_args}); }
    catch ($e) {
        $self->error($e);
    }

    undef $pid;

    return $result;
}

sub _set_user_and_group {
    my $self = shift;

    my $user  = $self->getOption('user')  // $self->user;
    my $group = $self->getOption('group') // $self->group;
    if ($user or $group) {
        if ($> == 0) {
            my ($uid, $gid) = (0, 0);
            if ($group) {
                $gid = getgrnam($group) or $self->error("Can't find group $group");
            }
            if ($user) {
                $uid = getpwnam($user) or $self->error("Can't find user $user");
            }
            if ($uid or $gid) {
                chown $uid, $gid, $self->pid_file;
            }
            if ($gid) {
                POSIX::setgid($gid);
            }
            if ($uid) {
                POSIX::setuid($uid);
            }
        } else {
            warn("Not running as root, can't setuid/setgid") unless $self->getOption('no-warn');
        }
    }

    return;
}

=head2 error

Handles the output of errors, including shutting down the running daemon by
calling handle_shutdown().  If you have a serious problem that should NOT
result in shutting down your daemon, use warn() instead.

=cut

sub error {    ## no critic (RequireArgUnpacking)
    my $self = shift;
    warn("Shutting down: " . join(' ', @_)) unless $self->getOption('no-warn');

    $self->handle_shutdown();
    return exit(-1);
}

no Moose::Role;
1;

__END__

=head1 USAGE

=head2 Inheritance

Invocation of a App::Base::Daemon-based daemon is accomplished as follows:

=over 4

=item -

Define a class that implements App::Base::Daemon

=item -

Instantiate an object of that class via new()

=item -

Run the daemon by calling run(). The return value of run() is the exit
status of the daemon, and should typically be passed back to the calling
program via exit()

=back

=head2 The new() method

(See App::Base::Script::Common::new)

=head2 Options handling

(See App::Base::Script::Common, "Options handling")

=head1 LICENSE AND COPYRIGHT



( run in 2.159 seconds using v1.01-cache-2.11-cpan-ceb78f64989 )