Merge branch 'lt/run'
authorJunio C Hamano <gitster@pobox.com>
Sat, 30 Jun 2007 18:22:08 +0000 (11:22 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 30 Jun 2007 18:22:08 +0000 (11:22 -0700)
* lt/run:
  Check for IO errors after running a command
  Clean up internal command handling

git.c

diff --git a/git.c b/git.c
index 29b55a1..c65e52f 100644 (file)
--- a/git.c
+++ b/git.c
@@ -216,14 +216,53 @@ const char git_version_string[] = GIT_VERSION;
  */
 #define NOT_BARE       (1<<2)
 
-static void handle_internal_command(int argc, const char **argv, char **envp)
+struct cmd_struct {
+       const char *cmd;
+       int (*fn)(int, const char **, const char *);
+       int option;
+};
+
+static int run_command(struct cmd_struct *p, int argc, const char **argv)
+{
+       int status;
+       struct stat st;
+       const char *prefix;
+
+       prefix = NULL;
+       if (p->option & RUN_SETUP)
+               prefix = setup_git_directory();
+       if (p->option & USE_PAGER)
+               setup_pager();
+       if (p->option & NOT_BARE) {
+               if (is_bare_repository() || is_inside_git_dir())
+                       die("%s must be run in a work tree", p->cmd);
+       }
+       trace_argv_printf(argv, argc, "trace: built-in: git");
+
+       status = p->fn(argc, argv, prefix);
+       if (status)
+               return status;
+
+       /* Somebody closed stdout? */
+       if (fstat(fileno(stdout), &st))
+               return 0;
+       /* Ignore write errors for pipes and sockets.. */
+       if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
+               return 0;
+
+       /* Check for ENOSPC and EIO errors.. */
+       if (ferror(stdout))
+               die("write failure on standard output");
+       if (fflush(stdout) || fclose(stdout))
+               die("write failure on standard output: %s", strerror(errno));
+
+       return 0;
+}
+
+static void handle_internal_command(int argc, const char **argv)
 {
        const char *cmd = argv[0];
-       static struct cmd_struct {
-               const char *cmd;
-               int (*fn)(int, const char **, const char *);
-               int option;
-       } commands[] = {
+       static struct cmd_struct commands[] = {
                { "add", cmd_add, RUN_SETUP | NOT_BARE },
                { "annotate", cmd_annotate, RUN_SETUP | USE_PAGER },
                { "apply", cmd_apply },
@@ -307,25 +346,13 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
 
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
                struct cmd_struct *p = commands+i;
-               const char *prefix;
                if (strcmp(p->cmd, cmd))
                        continue;
-
-               prefix = NULL;
-               if (p->option & RUN_SETUP)
-                       prefix = setup_git_directory();
-               if (p->option & USE_PAGER)
-                       setup_pager();
-               if ((p->option & NOT_BARE) &&
-                               (is_bare_repository() || is_inside_git_dir()))
-                       die("%s must be run in a work tree", cmd);
-               trace_argv_printf(argv, argc, "trace: built-in: git");
-
-               exit(p->fn(argc, argv, prefix));
+               exit(run_command(p, argc, argv));
        }
 }
 
-int main(int argc, const char **argv, char **envp)
+int main(int argc, const char **argv)
 {
        const char *cmd = argv[0] ? argv[0] : "git-help";
        char *slash = strrchr(cmd, '/');
@@ -358,7 +385,7 @@ int main(int argc, const char **argv, char **envp)
        if (!prefixcmp(cmd, "git-")) {
                cmd += 4;
                argv[0] = cmd;
-               handle_internal_command(argc, argv, envp);
+               handle_internal_command(argc, argv);
                die("cannot handle %s internally", cmd);
        }
 
@@ -390,7 +417,7 @@ int main(int argc, const char **argv, char **envp)
 
        while (1) {
                /* See if it's an internal command */
-               handle_internal_command(argc, argv, envp);
+               handle_internal_command(argc, argv);
 
                /* .. then try the external ones */
                execv_git_cmd(argv);