exec_cmd.con commit Test git-patch-id (b26d8d2)
   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 *argv_exec_path;
   8static const char *argv0_path;
   9
  10const char *system_path(const char *path)
  11{
  12#ifdef RUNTIME_PREFIX
  13        static const char *prefix;
  14#else
  15        static const char *prefix = PREFIX;
  16#endif
  17        struct strbuf d = STRBUF_INIT;
  18
  19        if (is_absolute_path(path))
  20                return path;
  21
  22#ifdef RUNTIME_PREFIX
  23        assert(argv0_path);
  24        assert(is_absolute_path(argv0_path));
  25
  26        if (!prefix) {
  27                const char *strip[] = {
  28                        GIT_EXEC_PATH,
  29                        BINDIR,
  30                        0
  31                };
  32                const char **s;
  33
  34                for (s = strip; *s; s++) {
  35                        const char *sargv = argv0_path + strlen(argv0_path);
  36                        const char *ss = *s + strlen(*s);
  37                        while (argv0_path < sargv && *s < ss
  38                                && (*sargv == *ss ||
  39                                    (is_dir_sep(*sargv) && is_dir_sep(*ss)))) {
  40                                sargv--;
  41                                ss--;
  42                        }
  43                        if (*s == ss) {
  44                                struct strbuf d = STRBUF_INIT;
  45                                /* We also skip the trailing directory separator. */
  46                                assert(sargv - argv0_path - 1 >= 0);
  47                                strbuf_add(&d, argv0_path, sargv - argv0_path - 1);
  48                                prefix = strbuf_detach(&d, NULL);
  49                                break;
  50                        }
  51                }
  52        }
  53
  54        if (!prefix) {
  55                prefix = PREFIX;
  56                fprintf(stderr, "RUNTIME_PREFIX requested, "
  57                                "but prefix computation failed.  "
  58                                "Using static fallback '%s'.\n", prefix);
  59        }
  60#endif
  61
  62        strbuf_addf(&d, "%s/%s", prefix, path);
  63        path = strbuf_detach(&d, NULL);
  64        return path;
  65}
  66
  67const char *git_extract_argv0_path(const char *argv0)
  68{
  69        const char *slash;
  70
  71        if (!argv0 || !*argv0)
  72                return NULL;
  73        slash = argv0 + strlen(argv0);
  74
  75        while (argv0 <= slash && !is_dir_sep(*slash))
  76                slash--;
  77
  78        if (slash >= argv0) {
  79                argv0_path = xstrndup(argv0, slash - argv0);
  80                return slash + 1;
  81        }
  82
  83        return argv0;
  84}
  85
  86void git_set_argv_exec_path(const char *exec_path)
  87{
  88        argv_exec_path = exec_path;
  89}
  90
  91
  92/* Returns the highest-priority, location to look for git programs. */
  93const char *git_exec_path(void)
  94{
  95        const char *env;
  96
  97        if (argv_exec_path)
  98                return argv_exec_path;
  99
 100        env = getenv(EXEC_PATH_ENVIRONMENT);
 101        if (env && *env) {
 102                return env;
 103        }
 104
 105        return system_path(GIT_EXEC_PATH);
 106}
 107
 108static void add_path(struct strbuf *out, const char *path)
 109{
 110        if (path && *path) {
 111                if (is_absolute_path(path))
 112                        strbuf_addstr(out, path);
 113                else
 114                        strbuf_addstr(out, make_nonrelative_path(path));
 115
 116                strbuf_addch(out, PATH_SEP);
 117        }
 118}
 119
 120void setup_path(void)
 121{
 122        const char *old_path = getenv("PATH");
 123        struct strbuf new_path = STRBUF_INIT;
 124
 125        add_path(&new_path, git_exec_path());
 126        add_path(&new_path, argv0_path);
 127
 128        if (old_path)
 129                strbuf_addstr(&new_path, old_path);
 130        else
 131                strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
 132
 133        setenv("PATH", new_path.buf, 1);
 134
 135        strbuf_release(&new_path);
 136}
 137
 138const char **prepare_git_cmd(const char **argv)
 139{
 140        int argc;
 141        const char **nargv;
 142
 143        for (argc = 0; argv[argc]; argc++)
 144                ; /* just counting */
 145        nargv = xmalloc(sizeof(*nargv) * (argc + 2));
 146
 147        nargv[0] = "git";
 148        for (argc = 0; argv[argc]; argc++)
 149                nargv[argc + 1] = argv[argc];
 150        nargv[argc + 1] = NULL;
 151        return nargv;
 152}
 153
 154int execv_git_cmd(const char **argv) {
 155        const char **nargv = prepare_git_cmd(argv);
 156        trace_argv_printf(nargv, "trace: exec:");
 157
 158        /* execvp() can only ever return if it fails */
 159        execvp("git", (char **)nargv);
 160
 161        trace_printf("trace: exec failed: %s\n", strerror(errno));
 162
 163        free(nargv);
 164        return -1;
 165}
 166
 167
 168int execl_git_cmd(const char *cmd,...)
 169{
 170        int argc;
 171        const char *argv[MAX_ARGS + 1];
 172        const char *arg;
 173        va_list param;
 174
 175        va_start(param, cmd);
 176        argv[0] = cmd;
 177        argc = 1;
 178        while (argc < MAX_ARGS) {
 179                arg = argv[argc++] = va_arg(param, char *);
 180                if (!arg)
 181                        break;
 182        }
 183        va_end(param);
 184        if (MAX_ARGS <= argc)
 185                return error("too many args to run %s", cmd);
 186
 187        argv[argc] = NULL;
 188        return execv_git_cmd(argv);
 189}