]> git.ipfire.org Git - thirdparty/git.git/commit - run-command.c
run-command: introduce capture_command helper
authorJeff King <peff@peff.net>
Mon, 23 Mar 2015 03:53:43 +0000 (23:53 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 23 Mar 2015 04:38:31 +0000 (21:38 -0700)
commit911ec99b688fc4d5673a0fc8984b22ff2251e490
treef83abd01d4e7034bd6be3646960f2ee7faf8f640
parentd56d966b3b03d2849ef9e20cacd7965106e8fdf0
run-command: introduce capture_command helper

Something as simple as reading the stdout from a command
turns out to be rather hard to do right. Doing:

  cmd.out = -1;
  run_command(&cmd);
  strbuf_read(&buf, cmd.out, 0);

can result in deadlock if the child process produces a large
amount of output. What happens is:

  1. The parent spawns the child with its stdout connected
     to a pipe, of which the parent is the sole reader.

  2. The parent calls wait(), blocking until the child exits.

  3. The child writes to stdout. If it writes more data than
     the OS pipe buffer can hold, the write() call will
     block.

This is a deadlock; the parent is waiting for the child to
exit, and the child is waiting for the parent to call
read().

So we might try instead:

  start_command(&cmd);
  strbuf_read(&buf, cmd.out, 0);
  finish_command(&cmd);

But that is not quite right either. We are examining cmd.out
and running finish_command whether start_command succeeded
or not, which is wrong. Moreover, these snippets do not do
any error handling. If our read() fails, we must make sure
to still call finish_command (to reap the child process).
And both snippets failed to close the cmd.out descriptor,
which they must do (provided start_command succeeded).

Let's introduce a run-command helper that can make this a
bit simpler for callers to get right.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
run-command.c
run-command.h