API documentation for remote.h
[gitweb.git] / exec_cmd.c
index 55af33bb7eeb4224ea583fce3008a3fb878d0fe6..e189caca629262334541ea8313d2931b06e67adf 100644 (file)
 #include "cache.h"
 #include "exec_cmd.h"
+#include "quote.h"
 #define MAX_ARGS       32
 
 extern char **environ;
 static const char *builtin_exec_path = GIT_EXEC_PATH;
-static const char *current_exec_path = NULL;
+static const char *argv_exec_path;
 
-void git_set_exec_path(const char *exec_path)
+void git_set_argv_exec_path(const char *exec_path)
 {
-       current_exec_path = exec_path;
+       argv_exec_path = exec_path;
 }
 
 
 /* Returns the highest-priority, location to look for git programs. */
-const char *git_exec_path()
+const char *git_exec_path(void)
 {
        const char *env;
 
-       if (current_exec_path)
-               return current_exec_path;
+       if (argv_exec_path)
+               return argv_exec_path;
 
-       env = getenv("GIT_EXEC_PATH");
-       if (env) {
+       env = getenv(EXEC_PATH_ENVIRONMENT);
+       if (env && *env) {
                return env;
        }
 
        return builtin_exec_path;
 }
 
+static void add_path(struct strbuf *out, const char *path)
+{
+       if (path && *path) {
+               if (is_absolute_path(path))
+                       strbuf_addstr(out, path);
+               else
+                       strbuf_addstr(out, make_absolute_path(path));
 
-int execv_git_cmd(char **argv)
+               strbuf_addch(out, ':');
+       }
+}
+
+void setup_path(const char *cmd_path)
 {
-       char git_command[PATH_MAX + 1];
-       char *tmp;
-       int len, err, i;
-       const char *paths[] = { current_exec_path,
-                               getenv("GIT_EXEC_PATH"),
-                               builtin_exec_path };
-
-       for (i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) {
-               const char *exec_dir = paths[i];
-               if (!exec_dir) continue;
-
-               if (*exec_dir != '/') {
-                       if (!getcwd(git_command, sizeof(git_command))) {
-                               fprintf(stderr, "git: cannot determine "
-                                       "current directory\n");
-                               exit(1);
-                       }
-                       len = strlen(git_command);
-
-                       /* Trivial cleanup */
-                       while (!strncmp(exec_dir, "./", 2)) {
-                               exec_dir += 2;
-                               while (*exec_dir == '/')
-                                       exec_dir++;
-                       }
-                       snprintf(git_command + len, sizeof(git_command) - len,
-                                "/%s", exec_dir);
-               } else {
-                       strcpy(git_command, exec_dir);
-               }
-
-               len = strlen(git_command);
-               len += snprintf(git_command + len, sizeof(git_command) - len,
-                               "/git-%s", argv[0]);
-
-               if (sizeof(git_command) <= len) {
-                       fprintf(stderr,
-                               "git: command name given is too long.\n");
-                       break;
-               }
+       const char *old_path = getenv("PATH");
+       struct strbuf new_path;
 
-               /* argv[0] must be the git command, but the argv array
-                * belongs to the caller, and my be reused in
-                * subsequent loop iterations. Save argv[0] and
-                * restore it on error.
-                */
+       strbuf_init(&new_path, 0);
 
-               tmp = argv[0];
-               argv[0] = git_command;
+       add_path(&new_path, argv_exec_path);
+       add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT));
+       add_path(&new_path, builtin_exec_path);
+       add_path(&new_path, cmd_path);
 
-               /* execve() can only ever return if it fails */
-               execve(git_command, argv, environ);
+       if (old_path)
+               strbuf_addstr(&new_path, old_path);
+       else
+               strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
 
-               err = errno;
+       setenv("PATH", new_path.buf, 1);
 
-               argv[0] = tmp;
-       }
-       return -1;
+       strbuf_release(&new_path);
+}
+
+int execv_git_cmd(const char **argv)
+{
+       struct strbuf cmd;
+       const char *tmp;
+
+       strbuf_init(&cmd, 0);
+       strbuf_addf(&cmd, "git-%s", argv[0]);
+
+       /*
+        * argv[0] must be the git command, but the argv array
+        * belongs to the caller, and may be reused in
+        * subsequent loop iterations. Save argv[0] and
+        * restore it on error.
+        */
+       tmp = argv[0];
+       argv[0] = cmd.buf;
+
+       trace_argv_printf(argv, "trace: exec:");
+
+       /* execvp() can only ever return if it fails */
+       execvp(cmd.buf, (char **)argv);
 
+       trace_printf("trace: exec failed: %s\n", strerror(errno));
+
+       argv[0] = tmp;
+
+       strbuf_release(&cmd);
+
+       return -1;
 }
 
 
-int execl_git_cmd(char *cmd,...)
+int execl_git_cmd(const char *cmd,...)
 {
        int argc;
-       char *argv[MAX_ARGS + 1];
-       char *arg;
+       const char *argv[MAX_ARGS + 1];
+       const char *arg;
        va_list param;
 
        va_start(param, cmd);