exec_cmd.con commit Merge branch 'jc/push' (5bcbc7f)
   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(EXEC_PATH_ENVIRONMENT);
  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(EXEC_PATH_ENVIRONMENT),
  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 (!prefixcmp(exec_dir, "./")) {
  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                trace_argv_printf(argv, -1, "trace: exec:");
 101
 102                /* execve() can only ever return if it fails */
 103                execve(git_command, (char **)argv, environ);
 104
 105                trace_printf("trace: exec failed: %s\n", strerror(errno));
 106
 107                argv[0] = tmp;
 108        }
 109        return -1;
 110
 111}
 112
 113
 114int execl_git_cmd(const char *cmd,...)
 115{
 116        int argc;
 117        const char *argv[MAX_ARGS + 1];
 118        const char *arg;
 119        va_list param;
 120
 121        va_start(param, cmd);
 122        argv[0] = cmd;
 123        argc = 1;
 124        while (argc < MAX_ARGS) {
 125                arg = argv[argc++] = va_arg(param, char *);
 126                if (!arg)
 127                        break;
 128        }
 129        va_end(param);
 130        if (MAX_ARGS <= argc)
 131                return error("too many args to run %s", cmd);
 132
 133        argv[argc] = NULL;
 134        return execv_git_cmd(argv);
 135}