=head1 NAME

Fugu::Process - child process management

=head1 SYNOPSIS

    use Fugu::Process;

    my $result = Fugu::Process->spawn_command(
        cmd       => [ '/usr/local/bin/mydaemon', '-f' ],
        daemonize => 1,
        stdout    => '/var/log/mydaemon.log',
    );

    Fugu::Process->terminate($result->{pid}) if $result->{success};

    my $r = Fugu::Process->run(cmd => [ 'rcctl', 'check', 'mydaemon' ]);
    print $r->{stdout} if $r->{success};

=head1 DESCRIPTION

Fugu::Process does the parts of child-process control that are easy to
get wrong. It shows the difference between a child that runs and a
child that exits immediately. It sends C<SIGTERM> first and sends
C<SIGKILL> after a delay. It reaps zombies and does not block.

Two methods start a child. C<spawn_command()> leaves it running.
C<run()> waits for it and captures what it wrote. Both report a failed
execve(2) exactly, over a close-on-exec pipe, and never by a
wait-and-guess sleep(3). Neither one runs a shell: the command is a
list, so no argument needs quoting and no argument can become a shell
operator.

The module keeps no state. Every method is a class method.

The module reads the Perl configuration at compile time, so no
method call opens a configuration file. A caller that uses pledge(2)
must load the module before the pledge. A C<require> of the module
after a pledge without the C<rpath> promise aborts the process, and
no code in the module can prevent that.

=head2 spawn_command

C<spawn_command(%args)> forks, redirects the standard descriptors, and
runs a command.

These are the arguments:

=over 4

=item C<cmd>

An array reference that holds the command and its arguments. This
argument is necessary and must not be empty.

=item C<daemonize>

If this argument is true, the child calls setsid(2) before exec. The
default is false.

=item C<stdin>, C<stdout>, C<stderr>

The paths for the child's standard descriptors. The default for each
path is F</dev/null>.

=item C<env>

A hash reference that names the environment of the child. The keys
are the variable names, and the values are the variable values. The
child holds exactly the named variables. The parent C<%ENV> does not
change: the child assigns its environment between the fork and the
execve(2). An empty hash reference gives the child an empty
environment. Without this argument, the child inherits the
environment of the parent.

The method checks the argument before the fork, and a bad argument
starts nothing. These are the errors:

=over 4

=item *

The value is not a hash reference.

=item *

A name holds no character.

=item *

A name holds an equals sign or a NUL byte.

=item *

A value is not defined, or a value is a reference.

=item *

A value holds a NUL byte.

=item *

A name or a value holds a character above 255. Such a character
cannot reach setenv(3) as one byte, and a silent encoding would give
the child bytes the caller never named.

=back

The exec resolves a bare command name through execvp(3), and
execvp(3) searches C<PATH>. An environment without C<PATH> makes
execvp(3) fall back to the default path of the system. Give an
absolute path, or name C<PATH> in C<env>. C<HOME>, C<TERM>, C<TZ>
and C<LC_ALL> can matter to a given child, and the module adds none
of them.

=back

The parent always waits for the execve(2) to resolve. The child holds
the write end of a close-on-exec pipe. A successful execve(2) closes
that end, and the parent reads end-of-file. A failure leaves a message
in the pipe, and the parent returns it in C<error>. Thus a command
that does not exist reports its own reason at once.

=head2 run

C<run(%args)> runs a command to completion and captures what it wrote.

These are the arguments:

=over 4

=item C<cmd>

An array reference that holds the command and its arguments. This
argument is necessary and must not be empty.

=item C<timeout>

The number of seconds to wait before the method stops the child. The
default is no limit.

=item C<stdin>

A string to feed to the child on its standard input.

=item C<cwd>

A directory to run the child in. The child calls chdir(2) after the
fork and before the execve(2), so the working directory of the caller
does not change. A chdir(2) in the caller would change the meaning of
every other relative path in the program, and a second call that ran
at the same time would race it.

A directory that the child cannot enter is a startup failure with the
reason in C<error>, not a silent run in the wrong place.

=item C<env>

The environment of the child, exactly as on C<spawn_command()>.

=item C<passthrough>

Let the child write straight to the caller's terminal. C<stdout> and
C<stderr> then come back empty.

=item C<new_session>

If this argument is true, the child calls setsid(2) before the
redirect. The default is false.

The child then leads a new session and a new process group, and its
group id equals its pid. On a timeout the method signals the whole
group, in the capture form and in the passthrough form alike. A
grandchild that holds a pipe open therefore dies with the child, and
the read of the pipes ends.

setsid(2) removes the controlling terminal. A child with
C<new_session> cannot read the terminal and cannot hold the
foreground. Do not combine C<new_session> with a command that prompts
on the terminal under C<passthrough>.

=back

The method reads standard output and standard error at the same time.
A reader that took them in sequence would deadlock: a child that fills
one pipe blocks until someone drains it.

=head2 exit_code

C<exit_code($status)> maps a raw waitpid(2) status, or the return
value of C<system>, to an exit code between 0 and 255. The low byte
holds the terminating signal. The high byte holds the exit code. A
value of -1 means the child never started.

A caller that gives a raw status to C<exit> turns a remote exit code
of 1 into C<exit(256)>, which the kernel truncates to 0. That silently
reports a failed command as a success.

=head2 is_alive

C<is_alive($pid)> reports if a process exists and is not a zombie. The
check reaps a zombie child as a side effect and then reports it as not
alive. A caller that needs the exit status uses C<run()>, or waits
itself.

=head2 terminate

C<terminate($pid, %args)> sends C<SIGTERM>, waits, and sends
C<SIGKILL> if the process continues to run.

These are the arguments:

=over 4

=item C<grace_period>

The number of seconds to wait between the two signals. The default is
5.

=item C<on_kill>

A code reference that the method calls when the process is gone.

=item C<group>

If this argument is true, each signal goes to the process group of
C<$pid>. The default is false.

C<$pid> must be the pid of a process-group leader. C<run()> with
C<new_session> and C<spawn_command()> with C<daemonize> each make
one. The method sends C<SIGTERM> to the group, waits for the grace
period, and sends C<SIGKILL> to the group when a member is still
alive.

The liveness test differs between the two forms. The default form
asks C<is_alive($pid)>, which reaps a zombie child. The group form
asks kill(2) with signal 0 on the group, and it reaps each child
member first. A group can outlive its leader, so the group form does
not return early on a dead leader.

=back

The wait polls with sub-second granularity. Thus a child that stops at
once does not cost a whole second.

=head2 wait_exit

C<wait_exit($pid, $timeout)> polls until the process exits or until
the timeout ends. The default for C<$timeout> is 30 seconds.

=head2 spawn_perl

C<spawn_perl(%args)> runs Perl code in a child process. It gives the
child the parent's C<-I> paths. The parent gets these paths from
C<-I>, C<use lib> or C<PERL5LIB>. Thus the child sees the same
modules.

C<code> is the program text. C<args> is an array reference of
arguments for the program. The method gives all other arguments to
C<spawn_command()>, so C<env> works here too.

The paths travel as C<-I> flags in the argument list, not in
C<PERL5LIB>. An C<env> argument that clears the environment
therefore costs the child no module.

=head1 RETURN VALUES

C<spawn_command()> and C<spawn_perl()> return a hash reference. On
success, the hash holds C<success> set to 1 and C<pid>. On failure,
C<success> is 0 and C<error> gives the cause.

C<run()> returns a hash reference that holds C<success>, C<stdout>,
C<stderr>, C<exit_code> and C<timed_out>. On a failure to start the
child, it also holds C<error>. C<success> is 1 only when the child
exited with code 0 and did not time out.

C<exit_code()> returns a number between 0 and 255.

C<is_alive()> returns 1 or 0.

C<terminate()> returns 1 if the process is gone. It returns 0 if the
process continues after C<SIGKILL>. In the group form, it returns 1
when no member of the group answers kill(2) with signal 0. It returns
0 when a member answers after C<SIGKILL>.

C<wait_exit()> returns 1 if the process exits in the timeout period.
If not, it returns 0.

=head1 EXAMPLES

This example runs a helper and then stops it:

    my $r = Fugu::Process->spawn_command(
        cmd => [ 'mdnsctl', 'publish', $name, '_hap', 'tcp', $port ],
    );

    Fugu::Process->terminate($r->{pid}, grace_period => 10)
        if $r->{success};

=head1 ERRORS

No method dies. The methods report failures through the hash reference
or the boolean value that they return.

=head1 SEE ALSO

execve(2), kill(2), setsid(2), waitpid(2), L<Fugu::Log>,
L<Fugu::Pidfile>

=head1 AUTHORS

Dick Olsson E<lt>hi@senzilla.ioE<gt>

=head1 CAVEATS

C<run()> holds the whole output of the child in memory. Do not use it
for a command that writes without a bound.

C<is_alive()> calls waitpid(2). That call reaps only the children of
the caller. For all other processes, it uses kill(2) with signal 0.
This signal cannot show the difference between a live process and a
zombie.

The group form of C<terminate()> cannot wait for a member that is not
a child of the caller. A member that init(8) has yet to reap can
therefore still answer for a moment after the method returns.

The operating system uses process IDs again for new processes. The
module cannot show the difference between the initial process and a
later process with the same number.

=cut
