git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 2/2] spawn pager via run_command interface

From
Jeff King <peff@peff.net>
Date
Jul 22, 2008, 07:14 UTC
Message-ID
<20080722071411.GB3584@sigill.intra.peff.net>
In-Reply-To
<20080722071246.GA3584@sigill.intra.peff.net>
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.
---
 pager.c |   49 ++++++++-----------------------------------------
 1 files changed, 8 insertions(+), 41 deletions(-)
diff --git a/pager.c b/pager.c
index 6b5c9e4..7743742 100644
--- a/pager.c
+++ b/pager.c
@@ -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
@@ -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
@@ -20,16 +21,17 @@ 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
+	.in = -1,
+#ifndef __MINGW32__
+	.preexec_cb = pager_preexec,
+#endif
 };
 static void wait_for_pager(void)
 {
@@ -40,14 +42,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))
@@ -66,35 +63,6 @@ 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;
 	if (start_command(&pager_process))
@@ -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)
-- 
1.6.0.rc0.1.g9291f.dirty
Previous: Jeff KingNext: Jeff King
Message 16 of 30 in “git status in clean working dir”
  1. David BremnerJul 21, 2008
  2. Junio C HamanoJul 22, 2008
  3. Abhijit Menon-SenJul 22, 2008
  4. Junio C HamanoJul 22, 2008
  5. Junio C HamanoJul 22, 2008
  6. Jeff KingJul 22, 2008
  7. Jeff KingJul 22, 2008
  8. Johannes SchindelinJul 22, 2008
  9. Jeff KingJul 22, 2008
  10. Mike HommeyJul 22, 2008
  11. Jeff KingJul 22, 2008
  12. Mike HommeyJul 22, 2008
  13. Jeff KingJul 22, 2008
  14. Jeff KingJul 22, 2008
  15. 1/2 run-command: add pre-exec callbackJeff King, Jul 22, 2008
  16. 2/2 spawn pager via run_command interfaceJeff King, Jul 22, 2008
  17. Jeff KingJul 22, 2008
  18. Pierre HabouzitJul 22, 2008
  19. Jeff KingJul 22, 2008
  20. Johannes SixtJul 22, 2008
  21. Jeff KingJul 22, 2008
  22. Johannes SixtJul 22, 2008
  23. Junio C HamanoJul 22, 2008
  24. Jeff KingJul 22, 2008
  25. David BremnerJul 22, 2008
  26. Johannes SixtJul 22, 2008
  27. Jeff KingJul 22, 2008
  28. Johannes SixtJul 22, 2008
  29. Ask Bjørn HansenJul 24, 2008
  30. Jeff KingJul 24, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.