Rubén Justo <rjusto@xxxxxxxxx> writes: > static struct child_process pager_process; > static const char *pager_program; > -static int close_fd2; > +static int old_fd1 = -1, old_fd2 = -1; ;-) Presumably when old_fd2 does not have a valid value (i.e. -1) it means we did not do dup2() to save it away, and we refrain from closing #2 in that case? It is curious that #1 did not have similar problem 2/6 addressed, as we never redirected it with dup() to save it away. But now we do for some reason that the proposed log message did not explain. We should say something like We need to take back the standard output and the standard error stream after we are done with an invocation of the pager. For that, save away the original file descriptors 1 and 2 when spawning the pager, and restore them once the pager exits. The presence of saved fd#2 can be used to replace the "close_fd2" flag introduced in the previous patch. perhaps. > /* Is the value coming back from term_columns() just a guess? */ > static int term_columns_guessed; > @@ -24,20 +24,41 @@ static void close_pager_fds(void) > { > /* signal EOF to pager */ > close(1); > - if (close_fd2) > + if (old_fd2 != -1) > close(2); > } OK. > static void wait_for_pager_atexit(void) > { > + if (old_fd1 == -1) > + return; > + > fflush(stdout); > fflush(stderr); > close_pager_fds(); > finish_command(&pager_process); > } > > +void wait_for_pager(void) > +{ > + if (old_fd1 == -1) > + return; > + > + wait_for_pager_atexit(); > + unsetenv("GIT_PAGER_IN_USE"); > + dup2(old_fd1, 1); > + old_fd1 = -1; > + if (old_fd2 != -1) { > + dup2(old_fd2, 2); > + old_fd2 = -1; > + } > +} Presumably these use old_fd1's validity as a signal to see if have pager running that need to be cleaned up? It feels a bit unnatural why we do not ask about such a process the structure that is set up to control it, namely, the pager_process structure, but this is OK for now. It is just a naming issue, but it smells strange that the normal code path (wait_for_pager()) calls a function that is an atexit handler, which is more specific and only to be called atexit. I would have made static void finish_pager(void) { fflush(stdout); fflush(stderr); close_pager_fds(); finish_command(&pager_process); } and then called it from the atexit handler and wait_for_pager(). > @@ -113,6 +134,7 @@ void prepare_pager_args(struct child_process *pager_process, const char *pager) > > void setup_pager(void) > { > + static int once = 0; > const char *pager = git_pager(isatty(1)); > > if (!pager) > @@ -142,16 +164,18 @@ void setup_pager(void) > return; > > /* original process continues, but writes to the pipe */ > + old_fd1 = dup(1); > dup2(pager_process.in, 1); > if (isatty(2)) { > - close_fd2 = 1; > + old_fd2 = dup(2); > dup2(pager_process.in, 2); > } > close(pager_process.in); Can dup(2) fail and return -1? > > - /* this makes sure that the parent terminates after the pager */ > - sigchain_push_common(wait_for_pager_signal); > - atexit(wait_for_pager_atexit); > + if (!once++) { > + sigchain_push_common(wait_for_pager_signal); > + atexit(wait_for_pager_atexit); > + } > } Can we give a name better than "once" to this thing? > int pager_in_use(void) > diff --git a/pager.h b/pager.h > index b77433026d..103ecac476 100644 > --- a/pager.h > +++ b/pager.h > @@ -5,6 +5,7 @@ struct child_process; > > const char *git_pager(int stdout_is_tty); > void setup_pager(void); > +void wait_for_pager(void); > int pager_in_use(void); > int term_columns(void); > void term_clear_line(void); Other than that, overall it looks good. Thanks, will queue.