Markus Roberts <[email protected]> writes:

> This last bears some elaboration; if the following steps occur:
>
> * Puppet "exec"s child process (apt-get, for example) and attempts to
>   capture the output
> * The child process launches a "grandchild" process (the buggy version
>   of the osirid daemon under Debian Etch, for example) without closing
>   its STDOUT
> * The grandchild does not close its inherited STDOUT
> * The child exits
> * The grandchild does not trap SIGPIPE
> * The grandchild writes to STDOUT
>
> the grandchild will receive an (unhandled) SIGPIPE and exit.  There is
> no presently known case where this would occur (the osirid daemon, as
> best as I can determine, did not actually write to the handle, just
> kept it around out of misplaced sentimentality).  The solutions to
> this problem, if it exists, are messy and best left unimplemented
> unless they are needed.

just a note: it's quite essential that SIGPIPE is set to SIG_DFL in the
child process.  luckily, execve(2) will reset to SIG_DFL unless it's set
to SIG_IGN.  a child with SIGPIPE set unexpectedly to SIG_IGN can easily
get stuck in endless loops.  the grandchild SHOULD die when it tries to
write to the closed stdout.

> +    method = output_read.respond_to?(:readpartial) ? :readpartial : :sysread
> +    begin
> +        # The timeout needs to be high enough to avoid thrashing but low
> +        # enough that we don't waste too much time waiting for processes
> +        # that exit without closing the pipe (see ticket #1563 comment #7)
> +        # One second seems a reasonable compromise.
> +        output << timeout(1) { output_read.send(method,1) } while true
> +    rescue Timeout::Error
> +        break if reaped_pid = Process.waitpid(child_pid,Process::WNOHANG)
> +    rescue Errno::EINTR
> +        # Just popping out to handle an unrelated signal, but we're not done
> +    end while true

I guess this will work, but it seems a bit hackish compared to just
catching SIGCHLD.  if done right, no polling (timeout) is needed.

>          ENV['LANG'] = ENV['LC_ALL'] = ENV['LC_MESSAGES'] = ENV['LANGUAGE'] = 
> 'C'
>          Kernel.exec(*command)

not part of your patch, but I couldn't resist commenting on this cargo
cult code :-).  setting ENV['LC_ALL'] is sufficient.  'LANGUAGE' is not
POSIX, and not consulted when LC_MESSAGES (effectively) is 'C'.

-- 
Kjetil T. Homme
Redpill Linpro AS - Changing the game

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.


Reply via email to