Question

I've got the following design in a perl script:

my $child_pid = fork;
if( ! $child_pid ){
    # do some stuff...
    exec( $user_specified_command );
else{
   # wait for child to exit
   waitpid( $child_pid, 0 );
}
# Continue with the script

I'm interested in getting an alert in the parent when the child execs, so that I can get some details about $user_specified_command (specifically, to use lsof to find out if stdout is redirected to a regular file). The result would be something like this:

my $child_pid = fork;
if( ! $child_pid ){
    # do some stuff...
    exec( $user_specified_command );
else{
   # wait until the child exec's
   wait_child_exec();

   # do some stuff...

   # wait for child to exit
   waitpid( $child_pid, 0 );
}
# Continue with the script

I could loop and grep ps output until the name changes, but it seems like exec is a serious enough event that there's a better way.

Was it helpful?

Solution

One general approach to this is to create a pipe in the parent which is inherited by the child, and have the parent block (or poll) the read end of the pipe.

Assuming the child has FD_CLOEXEC or, better, a suitable value of $^F, the child's call to exec() will close the pipe's write end and generate an EOF for the parent:

# Run a command in a child process, returning to the parent only after
# the child process has called exec'd or, failing that, terminated.
#
# WARNING - this code not rigorously tested
#
sub spawn_patiently {
  my ($rd, $wr);

  return unless pipe($rd, $wr);
  # XXX This assumes $^F is less than fileno($wr)
  #     In practice, you'd want it to be less than fileno($rd), too

  my $pid = fork();
  return unless defined $pid;

  if (! $pid) {
    exec @_;
    die "exec: $!";
  }

  # parent - wait for child to exec
  close($wr);
  read($rd, my $dummy, 1);

  1;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top