Show parameters to execve/builtin-cmds before executing them. This version does not yet have a parameter --trace to git to enable this I just want to get feedback first :) I think this is quite useful to debug what is going on since a command may be another program (shell/python/perl/.. script etc) or just an alias for a internal command. Before that many commands became built-ins this was quite easy to do with strace. Example: % git repo-config alias.showtag trace: exec: /home/matled/local/stow/git/bin/git-repo-config alias.showtag % git showtag v1.4.1-rc1 > /dev/null trace: exec: /home/matled/local/stow/git/bin/git-showtag v1.4.1-rc1 trace: exec failed: No such file or directory trace: built-in command: git cat-file tag v1.4.1-rc1 % git showtag 'a b "c" `d` $e \f' trace: exec: /home/matled/local/stow/git/bin/git-showtag "a b \"c\" \`d\` \$e \\f" trace: exec failed: No such file or directory trace: built-in command: git cat-file tag "a b \"c\" \`d\` \$e \\f" fatal: Not a valid object name a b "c" `d` $e \f % git cat-file tag "a b \"c\" \`d\` \$e \\f" trace: built-in command: git cat-file tag "a b \"c\" \`d\` \$e \\f" fatal: Not a valid object name a b "c" `d` $e \f print_shell_escape will escape the arguments to be used as strings in the shell to prevent ambiguity with spaces and other special characters and make them copy-and-pastable. --- exec_cmd.c | 42 ++++++++++++++++++++++++++++++++++++++++++ exec_cmd.h | 1 + git.c | 10 ++++++++++ 3 files changed, 53 insertions(+), 0 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index c1539d1..85afbf3 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -87,6 +87,16 @@ int execv_git_cmd(const char **argv) break; } + fprintf(stderr, "trace: exec: "); + print_shell_escape(stderr, git_command); + const char **p = argv; + while (*(++p)) { + putc(' ', stderr); + print_shell_escape(stderr, *p); + } + putc('\n', stderr); + fflush(stderr); + /* argv[0] must be the git command, but the argv array * belongs to the caller, and my be reused in * subsequent loop iterations. Save argv[0] and @@ -98,6 +108,8 @@ int execv_git_cmd(const char **argv) /* execve() can only ever return if it fails */ execve(git_command, (char **)argv, environ); + fprintf(stderr, "trace: exec failed: %s\n", strerror(errno)); + fflush(stderr); argv[0] = tmp; } @@ -128,3 +140,33 @@ int execl_git_cmd(const char *cmd,...) argv[argc] = NULL; return execv_git_cmd(argv); } + +void print_shell_escape(FILE *stream, const char *s) +{ + const char *c = s; + short int quote = 0; + while (*c) { + if (*c == '"' || *c == '`' || *c == '$' || *c == '\\' || + isspace(*c)) + { + quote = 1; + break; + } + ++c; + } + + if (!quote) { + fputs(s, stream); + return; + } + + putc('"', stream); + c = s; + while (*c) { + if (*c == '"' || *c == '`' || *c == '$' || *c == '\\') + putc('\\', stream); + putc(*c, stream); + ++c; + } + putc('"', stream); +} diff --git a/exec_cmd.h b/exec_cmd.h index 989621f..8b237fa 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -5,6 +5,7 @@ extern void git_set_exec_path(const char extern const char* git_exec_path(void); extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); +extern void print_shell_escape(FILE *stream, const char *s); #endif /* __GIT_EXEC_CMD_H_ */ diff --git a/git.c b/git.c index 94e9a4a..361fb25 100644 --- a/git.c +++ b/git.c @@ -198,6 +198,16 @@ static void handle_internal_command(int struct cmd_struct *p = commands+i; if (strcmp(p->cmd, cmd)) continue; + + fprintf(stderr, "trace: built-in command: git"); + int i; + for (i = 0; i < argc; ++i) { + putc(' ', stderr); + print_shell_escape(stderr, argv[i]); + } + putc('\n', stderr); + fflush(stderr); + exit(p->fn(argc, argv, envp)); } } -- 1.4.GIT - : send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html