Sometimes tracing the invocation of git programs with GIT_TRACE is not quite enough to replay a situation; the interesting input to the program often comes over its standard input. For instance, if you want to replay a particular fetch (e.g., for performance analysis or debugging), you would want both the arguments and stdin sent to pack-objects. This patch lets you capture the stdin of any git process. For instance: GIT_TRACE=/tmp/processes.out \ GIT_TRACE_STDIN=/tmp/stdin.%p \ git daemon ... After a fetch, processes.out will contain a line like: 15:19:08.275493 [pid=13196] git.c:348 trace: built-in: git 'pack-objects' '--revs' '--thin' '--stdout' '--progress' '--delta-base-offset' And stdin.13196 (the pid picked from the above line) will contain its stdin. Signed-off-by: Jeff King <peff@xxxxxxxx> --- git.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/git.c b/git.c index 44374b1..e7e58e3 100644 --- a/git.c +++ b/git.c @@ -616,6 +616,65 @@ static void restore_sigpipe_to_default(void) signal(SIGPIPE, SIG_DFL); } +static int copy_stdin(int in, int out, void *data) +{ + struct trace_key *key = data; + while (1) { + char buf[8192]; + ssize_t len = xread(in, buf, sizeof(buf)); + if (!len) + break; + if (len < 0) { + warning("error reading stdin trace: %s", + strerror(errno)); + break; + } + + trace_verbatim(key, buf, len); + if (write_in_full(out, buf, len) < 0) { + warning("error writing stdin trace: %s", + strerror(errno)); + break; + } + } + close(in); + close(out); + return 0; +} + +static void trace_stdin(void) +{ + static struct trace_key key = TRACE_KEY_INIT(STDIN); + static struct async async; + + if (!trace_want(&key)) + return; + + memset(&async, 0, sizeof(async)); + async.proc = copy_stdin; + async.data = &key; + async.in = dup(0); + async.out = -1; + + if (async.in < 0 || start_async(&async) < 0) { + warning("unable to trace stdin: %s", strerror(errno)); + return ; + } + + /* + * At this point we've handed stdin off to the async process, + * so there we are past the point of no return. + */ + if (dup2(async.out, 0)) + die_errno("unable to redirect stdin from async process"); + close(async.out); + + /* + * leak async; we would know to finish_async() only when we are + * exiting, and there is no point then + */ +} + int main(int argc, char **av) { const char **argv = (const char **) av; @@ -640,6 +699,7 @@ int main(int argc, char **av) git_setup_gettext(); trace_command_performance(argv); + trace_stdin(); /* * "git-xxxx" is the same as "git xxxx", but we obviously: -- 2.4.3.699.g84b4da7 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html