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