exec_cmd.con commit Use xmalloc instead of malloc (2d7320d)
   1#include "cache.h"
   2#include "exec_cmd.h"
   3#include "quote.h"
   4#define MAX_ARGS        32
   5
   6extern char **environ;
   7static const char *builtin_exec_path = GIT_EXEC_PATH;
   8static const char *current_exec_path;
   9
  10void git_set_exec_path(const char *exec_path)
  11{
  12        current_exec_path = exec_path;
  13}
  14
  15
  16/* Returns the highest-priority, location to look for git programs. */
  17const char *git_exec_path(void)
  18{
  19        const char *env;
  20
  21        if (current_exec_path)
  22                return current_exec_path;
  23
  24        env = getenv("GIT_EXEC_PATH");
  25        if (env && *env) {
  26                return env;
  27        }
  28
  29        return builtin_exec_path;
  30}
  31
  32
  33int execv_git_cmd(const char **argv)
  34{
  35        char git_command[PATH_MAX + 1];
  36        int i;
  37        const char *paths[] = { current_exec_path,
  38                                getenv("GIT_EXEC_PATH"),
  39                                builtin_exec_path };
  40
  41        for (i = 0; i < ARRAY_SIZE(paths); ++i) {
  42                size_t len;
  43                int rc;
  44                const char *exec_dir = paths[i];
  45                const char *tmp;
  46
  47                if (!exec_dir || !*exec_dir) continue;
  48
  49                if (*exec_dir != '/') {
  50                        if (!getcwd(git_command, sizeof(git_command))) {
  51                                fprintf(stderr, "git: cannot determine "
  52                                        "current directory: %s\n",
  53                                        strerror(errno));
  54                                break;
  55                        }
  56                        len = strlen(git_command);
  57
  58                        /* Trivial cleanup */
  59                        while (!strncmp(exec_dir, "./", 2)) {
  60                                exec_dir += 2;
  61                                while (*exec_dir == '/')
  62                                        exec_dir++;
  63                        }
  64
  65                        rc = snprintf(git_command + len,
  66                                      sizeof(git_command) - len, "/%s",
  67                                      exec_dir);
  68                        if (rc < 0 || rc >= sizeof(git_command) - len) {
  69                                fprintf(stderr, "git: command name given "
  70                                        "is too long.\n");
  71                                break;
  72                        }
  73                } else {
  74                        if (strlen(exec_dir) + 1 > sizeof(git_command)) {
  75                                fprintf(stderr, "git: command name given "
  76                                        "is too long.\n");
  77                                break;
  78                        }
  79                        strcpy(git_command, exec_dir);
  80                }
  81
  82                len = strlen(git_command);
  83                rc = snprintf(git_command + len, sizeof(git_command) - len,
  84                              "/git-%s", argv[0]);
  85                if (rc < 0 || rc >= sizeof(git_command) - len) {
  86                        fprintf(stderr,
  87                                "git: command name given is too long.\n");
  88                        break;
  89                }
  90
  91                /* argv[0] must be the git command, but the argv array
  92                 * belongs to the caller, and my be reused in
  93                 * subsequent loop iterations. Save argv[0] and
  94                 * restore it on error.
  95                 */
  96
  97                tmp = argv[0];
  98                argv[0] = git_command;
  99
 100                if (getenv("GIT_TRACE")) {
 101                        const char **p = argv;
 102                        fputs("trace: exec:", stderr);
 103                        while (*p) {
 104                                fputc(' ', stderr);
 105                                sq_quote_print(stderr, *p);
 106                                ++p;
 107                        }
 108                        putc('\n', stderr);
 109                        fflush(stderr);
 110                }
 111
 112                /* execve() can only ever return if it fails */
 113                execve(git_command, (char **)argv, environ);
 114
 115                if (getenv("GIT_TRACE")) {
 116                        fprintf(stderr, "trace: exec failed: %s\n",
 117                                strerror(errno));
 118                        fflush(stderr);
 119                }
 120
 121                argv[0] = tmp;
 122        }
 123        return -1;
 124
 125}
 126
 127
 128int execl_git_cmd(const char *cmd,...)
 129{
 130        int argc;
 131        const char *argv[MAX_ARGS + 1];
 132        const char *arg;
 133        va_list param;
 134
 135        va_start(param, cmd);
 136        argv[0] = cmd;
 137        argc = 1;
 138        while (argc < MAX_ARGS) {
 139                arg = argv[argc++] = va_arg(param, char *);
 140                if (!arg)
 141                        break;
 142        }
 143        va_end(param);
 144        if (MAX_ARGS <= argc)
 145                return error("too many args to run %s", cmd);
 146
 147        argv[argc] = NULL;
 148        return execv_git_cmd(argv);
 149}