Skip to content

Commit

Permalink
spawn pager via run_command interface
Browse files Browse the repository at this point in the history
This has two important effects:

 1. The pager is now the _child_ process, instead of the
    parent. This means that whatever spawned git (e.g., the
    shell) will see the exit code of the git process, and
    not the pager.

 2. The mingw and regular code are now unified, which makes
    the setup_pager function much simpler.

There are two caveats:

 1. We used to call execlp directly on the pager, followed
    by trying to exec it via the shall. We now just use the
    shell (which is what mingw has always done). This may
    have different results for pager names which contain
    shell metacharacters.

    It is also slightly less efficient because we
    unnecessarily run the shell; however, pager spawning is
    by definition an interactive task, so it shouldn't be
    a huge problem.

 2. The git process will remain in memory while the user
    looks through the pager. This is potentially wasteful.
    We could get around this by turning the parent into a
    meta-process which spawns _both_ git and the pager,
    collects the exit status from git, waits for both to
    end, and then exits with git's exit code.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jeff King authored and Junio C Hamano committed Jul 26, 2008
1 parent ccf08bc commit ea27a18
Showing 1 changed file with 11 additions and 44 deletions.
55 changes: 11 additions & 44 deletions pager.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "cache.h"
#include "run-command.h"

/*
* This is split up from the rest of git so that we can do
Expand All @@ -8,7 +9,7 @@
static int spawned_pager;

#ifndef __MINGW32__
static void run_pager(const char *pager)
static void pager_preexec(void)
{
/*
* Work around bug in "less" by not starting it until we
Expand All @@ -20,17 +21,13 @@ static void run_pager(const char *pager)
FD_SET(0, &in);
select(1, &in, NULL, &in, NULL);

execlp(pager, pager, NULL);
execl("/bin/sh", "sh", "-c", pager, NULL);
setenv("LESS", "FRSX", 0);
}
#else
#include "run-command.h"
#endif

static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
static struct child_process pager_process = {
.argv = pager_argv,
.in = -1
};
static struct child_process pager_process;

static void wait_for_pager(void)
{
fflush(stdout);
Expand All @@ -40,14 +37,9 @@ static void wait_for_pager(void)
close(2);
finish_command(&pager_process);
}
#endif

void setup_pager(void)
{
#ifndef __MINGW32__
pid_t pid;
int fd[2];
#endif
const char *pager = getenv("GIT_PAGER");

if (!isatty(1))
Expand All @@ -66,37 +58,13 @@ void setup_pager(void)

spawned_pager = 1; /* means we are emitting to terminal */

#ifndef __MINGW32__
if (pipe(fd) < 0)
return;
pid = fork();
if (pid < 0) {
close(fd[0]);
close(fd[1]);
return;
}

/* return in the child */
if (!pid) {
dup2(fd[1], 1);
dup2(fd[1], 2);
close(fd[0]);
close(fd[1]);
return;
}

/* The original process turns into the PAGER */
dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);

setenv("LESS", "FRSX", 0);
run_pager(pager);
die("unable to execute pager '%s'", pager);
exit(255);
#else
/* spawn the pager */
pager_argv[2] = pager;
pager_process.argv = pager_argv;
pager_process.in = -1;
#ifndef __MINGW32__
pager_process.preexec_cb = pager_preexec;
#endif
if (start_command(&pager_process))
return;

Expand All @@ -107,7 +75,6 @@ void setup_pager(void)

/* this makes sure that the parent terminates after the pager */
atexit(wait_for_pager);
#endif
}

int pager_in_use(void)
Expand Down

0 comments on commit ea27a18

Please sign in to comment.