exec_cmd.con commit git-merge-tree: generalize the "traverse <n> trees in sync" functionality (164dcb9)
   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()
  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(char **argv)
  33{
  34        char git_command[PATH_MAX + 1];
  35        char *tmp;
  36        int len, err, i;
  37        const char *paths[] = { current_exec_path,
  38                                getenv("GIT_EXEC_PATH"),
  39                                builtin_exec_path };
  40
  41        for (i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) {
  42                const char *exec_dir = paths[i];
  43                if (!exec_dir) continue;
  44
  45                if (*exec_dir != '/') {
  46                        if (!getcwd(git_command, sizeof(git_command))) {
  47                                fprintf(stderr, "git: cannot determine "
  48                                        "current directory\n");
  49                                exit(1);
  50                        }
  51                        len = strlen(git_command);
  52
  53                        /* Trivial cleanup */
  54                        while (!strncmp(exec_dir, "./", 2)) {
  55                                exec_dir += 2;
  56                                while (*exec_dir == '/')
  57                                        exec_dir++;
  58                        }
  59                        snprintf(git_command + len, sizeof(git_command) - len,
  60                                 "/%s", exec_dir);
  61                } else {
  62                        strcpy(git_command, exec_dir);
  63                }
  64
  65                len = strlen(git_command);
  66                len += snprintf(git_command + len, sizeof(git_command) - len,
  67                                "/git-%s", argv[0]);
  68
  69                if (sizeof(git_command) <= len) {
  70                        fprintf(stderr,
  71                                "git: command name given is too long.\n");
  72                        break;
  73                }
  74
  75                /* argv[0] must be the git command, but the argv array
  76                 * belongs to the caller, and my be reused in
  77                 * subsequent loop iterations. Save argv[0] and
  78                 * restore it on error.
  79                 */
  80
  81                tmp = argv[0];
  82                argv[0] = git_command;
  83
  84                /* execve() can only ever return if it fails */
  85                execve(git_command, argv, environ);
  86
  87                err = errno;
  88
  89                argv[0] = tmp;
  90        }
  91        return -1;
  92
  93}
  94
  95
  96int execl_git_cmd(char *cmd,...)
  97{
  98        int argc;
  99        char *argv[MAX_ARGS + 1];
 100        char *arg;
 101        va_list param;
 102
 103        va_start(param, cmd);
 104        argv[0] = cmd;
 105        argc = 1;
 106        while (argc < MAX_ARGS) {
 107                arg = argv[argc++] = va_arg(param, char *);
 108                if (!arg)
 109                        break;
 110        }
 111        va_end(param);
 112        if (MAX_ARGS <= argc)
 113                return error("too many args to run %s", cmd);
 114
 115        argv[argc] = NULL;
 116        return execv_git_cmd(argv);
 117}