=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.

Three methods start a child. C<spawn_command()> leaves it running.
C<run()> waits for it and captures what it wrote. C<spawn_peer()>
connects it to the caller over a socketpair(2), for the OpenBSD
pattern of a privileged parent with unprivileged children. Each one
reports a failed execve(2) exactly, over a close-on-exec pipe, and
never by a wait-and-guess sleep(3). None of them 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.

=item C<inherit>

An array reference of open handles that the child keeps across the
execve(2). The default is the empty list.

Perl sets C<FD_CLOEXEC> on each descriptor above C<$^F>, which is 2,
so a descriptor that the parent opened does not survive an exec on
its own. The child clears the flag on each named descriptor. It then
closes every other descriptor from 3 upward, and it keeps a named
descriptor, a standard descriptor, and the pipe that reports an exec
failure. The sweep runs on every call. Perl already closes each
flagged descriptor at the exec. The sweep therefore changes the
outcome only for a descriptor that stayed inheritable. A library can
leave one open, and a caller can clear the flag itself. Name such a
descriptor in C<inherit> when the child must keep it.

On Linux and Darwin the sweep walks the open-descriptor list of the
process, from F</proc/self/fd> or F</dev/fd>, so a large descriptor
limit costs nothing. Where neither list opens, and on OpenBSD, the
sweep is a loop to C<_SC_OPEN_MAX>. The OpenBSD limit is small, and
the loop reads no file, so it needs no pledge(2) promise beyond what
the caller holds.

The method keeps each named descriptor at its own number. A caller
that must tell the child a number reads C<fileno> before the call,
and puts the number in C<cmd>.

The method dies when the value is not an array reference, and when a
member has no descriptor. Both are programming errors.

=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 spawn_peer

C<spawn_peer(%args)> starts a peer child over a socketpair(2). A
daemon that follows the OpenBSD parent-and-children pattern uses it:
the parent creates the pair, forks, and execs its own program with a
role flag, and the child inherits its end of the pair.

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. The method has no
default command: a program can rewrite C<$0>, and a relative C<$0>
breaks after a chdir(2), so the caller names its own program and its
own role flag.

=item C<fd>

The descriptor number that the child receives. The default is 3. The
method dies when the number is below 3, and when it collides with an
C<inherit> descriptor. Both are programming errors.

=item C<inherit>

Extra handles for the child, exactly as on C<spawn_command()>.

=item C<env>

The environment of the child, exactly as on C<spawn_command()>. A
peer child of the privilege-separation pattern holds no secret of
the parent environment when the caller names an exact one.

=back

The method creates the pair with C<socketpair(AF_UNIX, SOCK_STREAM,
PF_UNSPEC)>, forks, and execs. In the child it closes the parent end,
puts the child end on C<fd> with C<FD_CLOEXEC> clear, and sweeps
every other descriptor from 3 upward, as under C<inherit> above. In
the parent it closes the child end and returns the parent end.

The child opens its end with C<open($peer, '+E<lt>&=', $fd)>, so it
needs no descriptor argument. The parent end comes back as a plain
handle, and the caller wraps it when it wants framing, for example
with C<Fugu::Imsg-E<gt>new(fh =E<gt> $handle)>. The module holds no
transport.

The method makes no session and no process group. A peer child stays
in the group of the parent, so one signal can reach the whole set.
The child holds the privileges of the parent at the exec: the
privilege drop and the pledge(2) belong to L<Fugu::Privdrop> and
L<Fugu::Sandbox>, and the child calls them after the exec.

=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<spawn_peer()> returns the same shape, and the success hash also
holds C<socket>, the parent end of the pair.

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 for a failure of the system: the methods report such a
failure through the hash reference or the boolean value that they
return.

A programming error dies. These are the cases: an C<inherit> value
that is not an array reference, an C<inherit> member with no
descriptor, an C<fd> below 3, and an C<fd> that collides with an
C<inherit> descriptor.

=head1 SEE ALSO

execve(2), kill(2), setsid(2), socketpair(2), waitpid(2),
L<Fugu::Imsg>, 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
