exec_cmd.con commit Merge branch 'master' into jc/cache-tree (e7afa11)
   1#include "cache.h"
   2#include "exec_cmd.h"
   3#define MAX_ARGS        32
   4
   5extern char **environ;
   6static const char *builtin_exec_path = GIT_EXEC_PATH;
   7static const char *current_exec_path = NULL;
   8
   9void git_set_exec_path(const char *exec_path)
  10{
  11        current_exec_path = exec_path;
  12}
  13
  14
  15/* Returns the highest-priority, location to look for git programs. */
  16const char *git_exec_path(void)
  17{
  18        const char *env;
  19
  20        if (current_exec_path)
  21                return current_exec_path;
  22
  23        env = getenv("GIT_EXEC_PATH");
  24        if (env) {
  25                return env;
  26        }
  27
  28        return builtin_exec_path;
  29}
  30
  31
  32int execv_git_cmd(const char **argv)
  33{
  34        char git_command[PATH_MAX + 1];
  35        int len,  i;
  36        const char *paths[] = { current_exec_path,
  37                                getenv("GIT_EXEC_PATH"),
  38                                builtin_exec_path };
  39
  40        for (i = 0; i < ARRAY_SIZE(paths); ++i) {
  41                const char *exec_dir = paths[i];
  42                const char *tmp;
  43
  44                if (!exec_dir) continue;
  45
  46                if (*exec_dir != '/') {
  47                        if (!getcwd(git_command, sizeof(git_command))) {
  48                                fprintf(stderr, "git: cannot determine "
  49                                        "current directory\n");
  50                                exit(1);
  51                        }
  52                        len = strlen(git_command);
  53
  54                        /* Trivial cleanup */
  55                        while (!strncmp(exec_dir, "./", 2)) {
  56                                exec_dir += 2;
  57                                while (*exec_dir == '/')
  58                                        exec_dir++;
  59                        }
  60                        snprintf(git_command + len, sizeof(git_command) - len,
  61                                 "/%s", exec_dir);
  62                } else {
  63                        strcpy(git_command, exec_dir);
  64                }
  65
  66                len = strlen(git_command);
  67                len += snprintf(git_command + len, sizeof(git_command) - len,
  68                                "/git-%s", argv[0]);
  69
  70                if (sizeof(git_command) <= len) {
  71                        fprintf(stderr,
  72                                "git: command name given is too long.\n");
  73                        break;
  74                }
  75
  76                /* argv[0] must be the git command, but the argv array
  77                 * belongs to the caller, and my be reused in
  78                 * subsequent loop iterations. Save argv[0] and
  79                 * restore it on error.
  80                 */
  81
  82                tmp = argv[0];
  83                argv[0] = git_command;
  84
  85                /* execve() can only ever return if it fails */
  86                execve(git_command, (char **)argv, environ);
  87
  88                argv[0] = tmp;
  89        }
  90        return -1;
  91
  92}
  93
  94
  95int execl_git_cmd(const char *cmd,...)
  96{
  97        int argc;
  98        const char *argv[MAX_ARGS + 1];
  99        const char *arg;
 100        va_list param;
 101
 102        va_start(param, cmd);
 103        argv[0] = cmd;
 104        argc = 1;
 105        while (argc < MAX_ARGS) {
 106                arg = argv[argc++] = va_arg(param, char *);
 107                if (!arg)
 108                        break;
 109        }
 110        va_end(param);
 111        if (MAX_ARGS <= argc)
 112                return error("too many args to run %s", cmd);
 113
 114        argv[argc] = NULL;
 115        return execv_git_cmd(argv);
 116}