exec_cmd.con commit Merge git://git.kernel.org/pub/scm/gitk/gitk (0825de8)
   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 && *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 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                size_t len;
  42                int rc;
  43                const char *exec_dir = paths[i];
  44                const char *tmp;
  45
  46                if (!exec_dir || !*exec_dir) continue;
  47
  48                if (*exec_dir != '/') {
  49                        if (!getcwd(git_command, sizeof(git_command))) {
  50                                fprintf(stderr, "git: cannot determine "
  51                                        "current directory: %s\n",
  52                                        strerror(errno));
  53                                break;
  54                        }
  55                        len = strlen(git_command);
  56
  57                        /* Trivial cleanup */
  58                        while (!strncmp(exec_dir, "./", 2)) {
  59                                exec_dir += 2;
  60                                while (*exec_dir == '/')
  61                                        exec_dir++;
  62                        }
  63
  64                        rc = snprintf(git_command + len,
  65                                      sizeof(git_command) - len, "/%s",
  66                                      exec_dir);
  67                        if (rc < 0 || rc >= sizeof(git_command) - len) {
  68                                fprintf(stderr, "git: command name given "
  69                                        "is too long.\n");
  70                                break;
  71                        }
  72                } else {
  73                        if (strlen(exec_dir) + 1 > sizeof(git_command)) {
  74                                fprintf(stderr, "git: command name given "
  75                                        "is too long.\n");
  76                                break;
  77                        }
  78                        strcpy(git_command, exec_dir);
  79                }
  80
  81                len = strlen(git_command);
  82                rc = snprintf(git_command + len, sizeof(git_command) - len,
  83                              "/git-%s", argv[0]);
  84                if (rc < 0 || rc >= sizeof(git_command) - len) {
  85                        fprintf(stderr,
  86                                "git: command name given is too long.\n");
  87                        break;
  88                }
  89
  90                /* argv[0] must be the git command, but the argv array
  91                 * belongs to the caller, and my be reused in
  92                 * subsequent loop iterations. Save argv[0] and
  93                 * restore it on error.
  94                 */
  95
  96                tmp = argv[0];
  97                argv[0] = git_command;
  98
  99                /* execve() can only ever return if it fails */
 100                execve(git_command, (char **)argv, environ);
 101
 102                argv[0] = tmp;
 103        }
 104        return -1;
 105
 106}
 107
 108
 109int execl_git_cmd(const char *cmd,...)
 110{
 111        int argc;
 112        const char *argv[MAX_ARGS + 1];
 113        const char *arg;
 114        va_list param;
 115
 116        va_start(param, cmd);
 117        argv[0] = cmd;
 118        argc = 1;
 119        while (argc < MAX_ARGS) {
 120                arg = argv[argc++] = va_arg(param, char *);
 121                if (!arg)
 122                        break;
 123        }
 124        va_end(param);
 125        if (MAX_ARGS <= argc)
 126                return error("too many args to run %s", cmd);
 127
 128        argv[argc] = NULL;
 129        return execv_git_cmd(argv);
 130}