From 47d0b4ff57f391786ed050f38c0de51462eda97a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 24 Jun 2007 10:10:40 -0700 Subject: [PATCH 1/2] Clean up internal command handling This should change no code at all, it just moves the definition of "struct cmd_struct" out, and then splits out the running of the right command into the "run_command()" function. It also removes the long-unused 'envp' pointer passing. This is just preparation for adding some more error checking. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- git.c | 52 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/git.c b/git.c index 29b55a1604..911fd3dabb 100644 --- a/git.c +++ b/git.c @@ -216,14 +216,34 @@ 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) +{ + 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"); + + return p->fn(argc, argv, prefix); +} + +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 +327,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 +366,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 +398,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); From 0f157315a1020fce76fe2c5a703e40684b9b1699 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 24 Jun 2007 10:29:33 -0700 Subject: [PATCH 2/2] Check for IO errors after running a command This is trying to implement the strict IO error checks that Jim Meyering suggested, but explicitly limits it to just regular files. If a pipe gets closed on us, we shouldn't complain about it. If the subcommand already returned an error, that takes precedence (and we assume that the subcommand already printed out any relevant messages relating to it) Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- git.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/git.c b/git.c index 911fd3dabb..c65e52f3db 100644 --- a/git.c +++ b/git.c @@ -224,6 +224,8 @@ struct cmd_struct { static int run_command(struct cmd_struct *p, int argc, const char **argv) { + int status; + struct stat st; const char *prefix; prefix = NULL; @@ -237,7 +239,24 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv) } trace_argv_printf(argv, argc, "trace: built-in: git"); - return p->fn(argc, argv, prefix); + 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)