{"thread":{"id":"3025","subject":"[PATCH 0/2] Remember and use GIT_EXEC_PATH on exec()'s","startedAt":"2006-01-09T23:34:37Z","lastAt":"2006-01-12T05:38:39Z","messageCount":33,"participants":["Michal Ostrowski","Junio C Hamano","Andreas Ericsson","Johannes Schindelin","Alex Riesen","Jon Loeliger","Linus Torvalds","H. Peter Anvin"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"14372","messageId":"1136849678.11717.514.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":null,"subject":"[PATCH 0/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-09T23:34:37Z","receivedAt":"2006-01-09T23:34:37Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"I've been trying to setup a git repository for access via ssh, on a\nsystem where git is to be installed under ~user/bin, and ~user/bin is\nnot included in the PATH that sshd provides.\n\nConsequently I need to execute something like:\n\ngit-clone -u /home/user/bin/git-upload-pack \\\nssh://user@system/home/user/repo.git repo\n\nWhen git-upload-pack executes on the remote system, it tries to execute\ngit-rev-list and fails, since /home/user/bin is not in the path.\n\nThe following patches handle this issue by appending GIT_EXEC_PATH to\nPATH prior to exec calls (via git_setup_exec_path()).  Also, the value\nof ${bindir} at build time is encoded and used as a default value for\n\"GIT_EXEC_PATH\", if the latter is not present. \n\n\n-- \nMichal Ostrowski <mostrows@watson.ibm.com>\n"},{"id":"14373","messageId":"1136849754.11717.517.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"1136849678.11717.514.camel@brick.watson.ibm.com","subject":"[PATCH 1/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-09T23:35:53Z","receivedAt":"2006-01-09T23:35:53Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"If git-upload-pack is invoked by ssh, it may have been invoked because\nssh was explicitly told which program to execute on the remote end\n(i.e. --exec had been used with git-clone-pack).  In this case, the\ngit suite may not be in the PATH, and so subsequent exec's by\ngit-upload-pack (i.e. git-rev-list, git-pack-objects) will fail.\n\nThese changes provide for ${bindir} to be stored at compile time in\nenvironment.c. git_setup_exec_path() is implemented; this function\nwill append GIT_EXEC_PATH or the saved ${bindir} to PATH.\n\nSigned-off-by: Michal Ostrowski <mostrows@watson.ibm.com>\n\n---\n\n Makefile      |    7 +++++++\n cache.h       |    1 +\n environment.c |   29 +++++++++++++++++++++++++++++\n 3 files changed, 37 insertions(+), 0 deletions(-)\n\nb24fde016c2d7382016b80bc0b9a011db3413bb3\ndiff --git a/Makefile b/Makefile\nindex c9c15b5..ffd2a68 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -437,6 +437,13 @@ init-db.o: init-db.c\n \t$(CC) -c $(ALL_CFLAGS) \\\n \t\t-DDEFAULT_GIT_TEMPLATE_DIR=$(call shellquote,\"$(template_dir)\") $*.c\n \n+# Recompile environment.o if GIT_EXEC_PATH changes\n+.environment.GIT_EXEC_PATH:\n+\t@(test -e $@ && grep -h -e '^$(bindir)$$' $@) || echo $(bindir) > $@\n+environment.o: .environment.GIT_EXEC_PATH\n+environment.o: CFLAGS+= -DGIT_EXEC_PATH=\\\"$(bindir)\\\"\n+\n+\n $(LIB_OBJS): $(LIB_H)\n $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H)\n $(DIFF_OBJS): diffcore.h\ndiff --git a/cache.h b/cache.h\nindex 29c9e81..d73071e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -244,6 +244,7 @@ unsigned long approxidate(const char *);\n extern int setup_ident(void);\n extern const char *git_author_info(void);\n extern const char *git_committer_info(void);\n+extern void git_setup_exec_path(void);\n \n struct checkout {\n \tconst char *base_dir;\ndiff --git a/environment.c b/environment.c\nindex 0596fc6..4dc0249 100644\n--- a/environment.c\n+++ b/environment.c\n@@ -9,6 +9,10 @@\n  */\n #include \"cache.h\"\n \n+#ifndef GIT_EXEC_PATH\n+#define GIT_EXEC_PATH NULL\n+#endif\n+\n char git_default_email[MAX_GITNAME];\n char git_default_name[MAX_GITNAME];\n int trust_executable_bit = 1;\n@@ -16,6 +20,7 @@ int only_use_symrefs = 0;\n int repository_format_version = 0;\n char git_commit_encoding[MAX_ENCODING_LENGTH] = \"utf-8\";\n int shared_repository = 0;\n+char *git_exec_path = GIT_EXEC_PATH;\n \n static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,\n \t*git_graft_file;\n@@ -76,4 +81,28 @@ char *get_graft_file(void)\n \treturn git_graft_file;\n }\n \n+void git_setup_exec_path(void)\n+{\n+\tchar *path, *old_path = getenv(\"PATH\");\n+\tint path_len, len, old_len;\n+\tchar *exec_path = getenv(\"GIT_EXEC_PATH\");\n+\n+\tif (!exec_path)\n+\t\texec_path = git_exec_path;\n+\n+\tlen = strlen(exec_path);\n+\n+\tif (!old_path)\n+\t\told_path = \"/usr/local/bin:/usr/bin:/bin\";\n \n+\told_len = strlen(old_path);\n+\tpath_len = len + old_len + 1;\n+\n+\tpath = malloc(path_len + 1);\n+\n+\tmemcpy(path, old_path, old_len);\n+\tpath[old_len] = ':';\n+\tmemcpy(path + old_len + 1, exec_path, len);\n+\n+\tsetenv(\"PATH\", path, 1);\n+}\n-- \n0.99.9m-g02ad\n"},{"id":"14375","messageId":"1136849810.11717.518.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"1136849678.11717.514.camel@brick.watson.ibm.com","subject":"[PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-09T23:36:50Z","receivedAt":"2006-01-09T23:36:50Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"Calls to git_setup_exec_path() are inserted on paths that will execute\nother git programs. git_setup_exec_path() will ensure that the git\ninstallation directories are in the path.\n\nSigned-off-by: Michal Ostrowski <mostrows@watson.ibm.com>\n\n---\n\n daemon.c      |    2 ++\n fetch-clone.c |    2 ++\n run-command.c |    1 +\n send-pack.c   |    2 ++\n upload-pack.c |    4 +++-\n 5 files changed, 10 insertions(+), 1 deletions(-)\n\nbb14b4b61f53f755486695e5bdc45b5623a6f8c5\ndiff --git a/daemon.c b/daemon.c\nindex 3bd1426..d653f33 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -226,6 +226,8 @@ static int upload(char *dir)\n \n \tsnprintf(timeout_buf, sizeof timeout_buf, \"--timeout=%u\", timeout);\n \n+\tgit_setup_exec_path();\n+\n \t/* git-upload-pack only ever reads stuff, so this is safe */\n \texeclp(\"git-upload-pack\", \"git-upload-pack\", \"--strict\", timeout_buf,\n\".\", NULL);\n \treturn -1;\ndiff --git a/fetch-clone.c b/fetch-clone.c\nindex f46fe6e..afbbb79 100644\n--- a/fetch-clone.c\n+++ b/fetch-clone.c\n@@ -98,6 +98,8 @@ int receive_unpack_pack(int fd[2], const\n \tint status;\n \tpid_t pid;\n \n+\tgit_setup_exec_path();\n+\n \tpid = fork();\n \tif (pid < 0)\n \t\tdie(\"%s: unable to fork off git-unpack-objects\", me);\ndiff --git a/run-command.c b/run-command.c\nindex 8bf5922..993a3f9 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -9,6 +9,7 @@ int run_command_v_opt(int argc, char **a\n \tif (pid < 0)\n \t\treturn -ERR_RUN_COMMAND_FORK;\n \tif (!pid) {\n+\t\tgit_setup_exec_path();\n \t\tif (flags & RUN_COMMAND_NO_STDIO) {\n \t\t\tint fd = open(\"/dev/null\", O_RDWR);\n \t\t\tdup2(fd, 0);\ndiff --git a/send-pack.c b/send-pack.c\nindex cd36193..a241f00 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -30,6 +30,7 @@ static void exec_pack_objects(void)\n \t\t\"--stdout\",\n \t\tNULL\n \t};\n+\tgit_setup_exec_path();\n \texecvp(\"git-pack-objects\", args);\n \tdie(\"git-pack-objects exec failed (%s)\", strerror(errno));\n }\n@@ -58,6 +59,7 @@ static void exec_rev_list(struct ref *re\n \t\trefs = refs->next;\n \t}\n \targs[i] = NULL;\n+\tgit_setup_exec_path();\n \texecvp(\"git-rev-list\", args);\n \tdie(\"git-rev-list exec failed (%s)\", strerror(errno));\n }\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 1834b6b..f8d4fbe 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -270,7 +270,9 @@ int main(int argc, char **argv)\n \t\t\tbreak;\n \t\t}\n \t}\n-\t\n+\n+\tgit_setup_exec_path();\n+\n \tif (i != argc-1)\n \t\tusage(upload_pack_usage);\n \tdir = argv[i];\n-- \n0.99.9m-g02ad\n"},{"id":"14385","messageId":"7vwth8bxqd.fsf@assigned-by-dhcp.cox.net","threadId":"3025","inReplyTo":"1136849810.11717.518.camel@brick.watson.ibm.com","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-10T02:52:42Z","receivedAt":"2006-01-10T02:52:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michal Ostrowski <mostrows@watson.ibm.com> writes:\n\n> Calls to git_setup_exec_path() are inserted on paths that will execute\n> other git programs. git_setup_exec_path() will ensure that the git\n> installation directories are in the path.\n\nAbout fetch-clone.c (which is shared by fetch-pack and\nclone-pack), it runs \"git-index-pack\" from finish_pack and\n\"git-unpack-objects\" from unpack_pack, so spelling these exec\nwith execlp(\"git\", \"git\", \"index-pack\", ...) might be cleaner,\nsince \"git\" is required to be in users' PATH even though git-*\nmay be moved out of the PATH in later versions of git.  I\ndunno...\n\nIn send-pack.c, I wonder why you didn't do a setup_exec_path()\nat the beginning of main() instead of having two calls close to\nexec*() call site.\n\nThe same comment applies for run-command.c; you do it once for\neach child, but calling it once at the beginning of receive-pack\nwould be good enough.  The same thing for daemon.c.\n\nI suspect you are trying to limit the extent of damage, but I do\nnot think of a downside if we just call setup_exec_path() once\nat the beginning of main().  $GIT_EXEC_PATH _could_ have a\nprivate copy of broken \"diff\" to confuse diff-* family, but you\ncannot say \"git diff\" in such a setup anyway because \"git\" does\nthe PATH prefixing already, so it would be a moot point.\n\nHere is the list my \"nm | grep ' exec[vlpe]*\\($\\|@@\\)'\" found\nthat use some variant of exec* family (except \"git-diff-*\"):\n\n\tclone-pack\n        daemon\n        fetch-pack\n        merge-index\n        peek-remote\n        receive-pack\n        send-pack\n        shell\n        ssh-fetch/ssh-pull\n        ssh-upload/ssh-push\n        upload-pack\n\nI do not care too much about ssh-* commit walkers (users can say\ne.g. GIT_SSH_PUSH themselves).\n\nAnyway, thanks for starting this.  I need a bit more thought and\na bit of list discussion to convince myself this is a good\nchange.\n"},{"id":"14387","messageId":"7vfynwbxpc.fsf@assigned-by-dhcp.cox.net","threadId":"3025","inReplyTo":"1136849754.11717.517.camel@brick.watson.ibm.com","subject":"Re: [PATCH 1/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-10T02:53:19Z","receivedAt":"2006-01-10T02:53:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michal Ostrowski <mostrows@watson.ibm.com> writes:\n\n> If git-upload-pack is invoked by ssh, it may have been invoked because\n> ssh was explicitly told which program to execute on the remote end\n> (i.e. --exec had been used with git-clone-pack).  In this case, the\n> git suite may not be in the PATH, and so subsequent exec's by\n> git-upload-pack (i.e. git-rev-list, git-pack-objects) will fail.\n\nTrue.\n\n> +.environment.GIT_EXEC_PATH:\n> +\t@(test -e $@ && grep -h -e '^$(bindir)$$' $@) || echo $(bindir) > $@\n\nHmph.\n\n  * I did not know \"test -e\" was portable (it is in POSIX.1),\n    but since you are creating the file yourself anyway,\n    wouldn't \"test -f\" look more familiar?\n\n  * Perhaps grep -F (--fixed-strings), not as regexp?\n\n  * I do not get the point of using \"grep -h\" here (it's not in\n    POSIX.1).  Perhaps just >/dev/null?\n\nBut I like the timestamp trick here that uses ||.  Maybe I\nshould borrow it for GIT-VERSION-GEN.  Maybe not.\n\n> --- a/environment.c\n> +++ b/environment.c\n> @@ -9,6 +9,10 @@\n>   */\n>  #include \"cache.h\"\n>  \n> +#ifndef GIT_EXEC_PATH\n> +#define GIT_EXEC_PATH NULL\n> +#endif\n\nI wonder if not having GIT_EXEC_PATH defined should be an error here.\n\n> +void git_setup_exec_path(void)\n> +{\n>...\n> +}\n\nMaybe move git.c::prepend_to_path() to a single library file and\nuse it here?\n"},{"id":"14406","messageId":"1136900174.11717.537.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"7vwth8bxqd.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-10T13:36:14Z","receivedAt":"2006-01-10T13:36:14Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"On Mon, 2006-01-09 at 18:52 -0800, Junio C Hamano wrote:\n> Michal Ostrowski <mostrows@watson.ibm.com> writes:\n> \n> > Calls to git_setup_exec_path() are inserted on paths that will execute\n> > other git programs. git_setup_exec_path() will ensure that the git\n> > installation directories are in the path.\n> \n> About fetch-clone.c (which is shared by fetch-pack and\n> clone-pack), it runs \"git-index-pack\" from finish_pack and\n> \"git-unpack-objects\" from unpack_pack, so spelling these exec\n> with execlp(\"git\", \"git\", \"index-pack\", ...) might be cleaner,\n> since \"git\" is required to be in users' PATH even though git-*\n> may be moved out of the PATH in later versions of git.  I\n> dunno...\n> \n> In send-pack.c, I wonder why you didn't do a setup_exec_path()\n> at the beginning of main() instead of having two calls close to\n> exec*() call site.\n>\n> The same comment applies for run-command.c; you do it once for\n> each child, but calling it once at the beginning of receive-pack\n> would be good enough.  The same thing for daemon.c.\n>\n> I suspect you are trying to limit the extent of damage, but I do\n> not think of a downside if we just call setup_exec_path() once\n> at the beginning of main().  $GIT_EXEC_PATH _could_ have a\n> private copy of broken \"diff\" to confuse diff-* family, but you\n> cannot say \"git diff\" in such a setup anyway because \"git\" does\n> the PATH prefixing already, so it would be a moot point.\n> \n\nI'm not actually happy with the idea of mucking around with PATH, even\nwithin git.c.  Hence I tried to only change PATH if the code had already\ncommitted to an exec.\n\nAn approach that I think is better is to require all exec's of git\nprograms from within git programs to use a specific git interface,\nrather than letting each one set up it's own exec parameters.\n\nOnce you have that implemented, we can have a separate discussion of how\nthe executable is to be found; \n - should we use PATH?\n - should we change PATH?\n - should we always exec using an absolute file name? (my preference)\n \nIf a user invokes /home/user/bin/git-foo, and git-foo wants to call\ngit-bar, is it legitimate for git-foo to call /usr/local/bin/git-bar, or\nshould it require /home/user/bin/git-bar?\n\nShould the same rules be applied to the shell scripts? (In which case\nwe'd want to do something like s:git-:$(GIT_EXEC_PATH)/git-:g.)\n\nAnyways, it may just be easier to show this in C (patch below).\n\n\n-- \nMichal Ostrowski <mostrows@watson.ibm.com>\n\ndiff --git a/Makefile b/Makefile\nindex c9c15b5..db57858 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -173,7 +173,7 @@ DIFF_OBJS = \\\n \n LIB_OBJS = \\\n \tblob.o commit.o connect.o count-delta.o csum-file.o \\\n-\tdate.o diff-delta.o entry.o ident.o index.o \\\n+\tdate.o diff-delta.o entry.o exec_cmd.o ident.o index.o \\\n \tobject.o pack-check.o patch-delta.o path.o pkt-line.o \\\n \tquote.o read-cache.o refs.o run-command.o \\\n \tserver-info.o setup.o sha1_file.o sha1_name.o strbuf.o \\\n@@ -184,6 +184,16 @@ LIB_OBJS = \\\n LIBS = $(LIB_FILE)\n LIBS += -lz\n \n+\n+# .exec_cmd.bindir stores $(bindir) used to compile exec_cmd.o\n+# If it has changed, store the new value and force exec_cmd.o to be\nrebuilt\n+ifneq ($(shell cat .exec_cmd.bindir 2>/dev/null),$(bindir))\n+.PHONY: exec_cmd.c\n+$(shell echo $(bindir) > .exec_cmd.bindir)\n+endif\n+\n+exec_cmd.o: CFLAGS+=-DGIT_EXEC_PATH=\\\"$(bindir)\\\"\n+\n # Shell quote;\n # Result of this needs to be placed inside ''\n shq = $(subst ','\\'',$(1))\ndiff --git a/daemon.c b/daemon.c\nindex 3bd1426..ab793bd 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -9,6 +9,7 @@\n #include <syslog.h>\n #include \"pkt-line.h\"\n #include \"cache.h\"\n+#include \"exec_cmd.h\"\n \n static int log_syslog;\n static int verbose;\n@@ -227,7 +228,7 @@ static int upload(char *dir)\n \tsnprintf(timeout_buf, sizeof timeout_buf, \"--timeout=%u\", timeout);\n \n \t/* git-upload-pack only ever reads stuff, so this is safe */\n-\texeclp(\"git-upload-pack\", \"git-upload-pack\", \"--strict\", timeout_buf,\n\".\", NULL);\n+\texec_git_cmd(\"upload-pack\", \"--strict\", timeout_buf, \".\");\n \treturn -1;\n }\n \ndiff --git a/fetch-clone.c b/fetch-clone.c\nindex f46fe6e..5ae9bda 100644\n--- a/fetch-clone.c\n+++ b/fetch-clone.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"exec_cmd.h\"\n #include <sys/wait.h>\n \n static int finish_pack(const char *pack_tmp_name, const char *me)\n@@ -27,8 +28,7 @@ static int finish_pack(const char *pack_\n \t\tdup2(pipe_fd[1], 1);\n \t\tclose(pipe_fd[0]);\n \t\tclose(pipe_fd[1]);\n-\t\texeclp(\"git-index-pack\",\"git-index-pack\",\n-\t\t       \"-o\", idx, pack_tmp_name, NULL);\n+\t\texec_git_cmd(\"index-pack\", \"-o\", idx, pack_tmp_name);\n \t\terror(\"cannot exec git-index-pack <%s> <%s>\",\n \t\t      idx, pack_tmp_name);\n \t\texit(1);\n@@ -105,8 +105,7 @@ int receive_unpack_pack(int fd[2], const\n \t\tdup2(fd[0], 0);\n \t\tclose(fd[0]);\n \t\tclose(fd[1]);\n-\t\texeclp(\"git-unpack-objects\", \"git-unpack-objects\",\n-\t\t       quiet ? \"-q\" : NULL, NULL);\n+\t\texec_git_cmd(\"unpack-objects\", quiet ? \"-q\" : NULL);\n \t\tdie(\"git-unpack-objects exec failed\");\n \t}\n \tclose(fd[0]);\ndiff --git a/git.c b/git.c\nindex 5e7da74..a45dc54 100644\n--- a/git.c\n+++ b/git.c\n@@ -10,6 +10,7 @@\n #include <stdarg.h>\n #include <sys/ioctl.h>\n #include \"git-compat-util.h\"\n+#include \"exec_cmd.h\"\n \n #ifndef PATH_MAX\n # define PATH_MAX 4096\n@@ -192,25 +193,6 @@ static void cmd_usage(const char *exec_p\n \texit(1);\n }\n \n-static void prepend_to_path(const char *dir, int len)\n-{\n-\tchar *path, *old_path = getenv(\"PATH\");\n-\tint path_len = len;\n-\n-\tif (!old_path)\n-\t\told_path = \"/usr/local/bin:/usr/bin:/bin\";\n-\n-\tpath_len = len + strlen(old_path) + 1;\n-\n-\tpath = malloc(path_len + 1);\n-\n-\tmemcpy(path, dir, len);\n-\tpath[len] = ':';\n-\tmemcpy(path + len + 1, old_path, path_len - len);\n-\n-\tsetenv(\"PATH\", path, 1);\n-}\n-\n static void show_man_page(char *git_cmd)\n {\n \tchar *page;\n@@ -233,14 +215,10 @@ int main(int argc, char **argv, char **e\n {\n \tchar git_command[PATH_MAX + 1];\n \tchar wd[PATH_MAX + 1];\n-\tint i, len, show_help = 0;\n-\tchar *exec_path = getenv(\"GIT_EXEC_PATH\");\n+\tint i, show_help = 0;\n \n \tgetcwd(wd, PATH_MAX);\n \n-\tif (!exec_path)\n-\t\texec_path = GIT_EXEC_PATH;\n-\n \tfor (i = 1; i < argc; i++) {\n \t\tchar *arg = argv[i];\n \n@@ -257,9 +235,9 @@ int main(int argc, char **argv, char **e\n \t\tif (!strncmp(arg, \"exec-path\", 9)) {\n \t\t\targ += 9;\n \t\t\tif (*arg == '=')\n-\t\t\t\texec_path = arg + 1;\n+\t\t\t\tgit_set_exec_path(arg + 1);\n \t\t\telse {\n-\t\t\t\tputs(exec_path);\n+\t\t\t\tputs(git_exec_path());\n \t\t\t\texit(0);\n \t\t\t}\n \t\t}\n@@ -275,48 +253,18 @@ int main(int argc, char **argv, char **e\n \n \tif (i >= argc || show_help) {\n \t\tif (i >= argc)\n-\t\t\tcmd_usage(exec_path, NULL);\n+\t\t\tcmd_usage(git_exec_path(), NULL);\n \n \t\tshow_man_page(argv[i]);\n \t}\n \n-\tif (*exec_path != '/') {\n-\t\tif (!getcwd(git_command, sizeof(git_command))) {\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"git: cannot determine current directory\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\tlen = strlen(git_command);\n-\n-\t\t/* Trivial cleanup */\n-\t\twhile (!strncmp(exec_path, \"./\", 2)) {\n-\t\t\texec_path += 2;\n-\t\t\twhile (*exec_path == '/')\n-\t\t\t\texec_path++;\n-\t\t}\n-\t\tsnprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t \"/%s\", exec_path);\n-\t}\n-\telse\n-\t\tstrcpy(git_command, exec_path);\n-\tlen = strlen(git_command);\n-\tprepend_to_path(git_command, len);\n-\n-\tlen += snprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t\"/git-%s\", argv[i]);\n-\tif (sizeof(git_command) <= len) {\n-\t\tfprintf(stderr, \"git: command name given is too long.\\n\");\n-\t\texit(1);\n-\t}\n-\n-\t/* execve() can only ever return if it fails */\n-\texecve(git_command, &argv[i], envp);\n+\texecv_git_cmd(argv + i);\n \n \tif (errno == ENOENT)\n-\t\tcmd_usage(exec_path, \"'%s' is not a git-command\", argv[i]);\n+\t\tcmd_usage(git_exec_path(), \"'%s' is not a git-command\",\n+\t\t\t  argv[i]);\n \n \tfprintf(stderr, \"Failed to run command '%s': %s\\n\",\n \t\tgit_command, strerror(errno));\n-\n \treturn 1;\n }\ndiff --git a/receive-pack.c b/receive-pack.c\nindex f847ec2..8e78e32 100644\n--- a/receive-pack.c\n+++ b/receive-pack.c\n@@ -257,7 +257,7 @@ static void read_head_info(void)\n \n static const char *unpack(int *error_code)\n {\n-\tint code = run_command(unpacker, NULL);\n+\tint code = run_command_v_opt(1, &unpacker, RUN_GIT_CMD);\n \n \t*error_code = 0;\n \tswitch (code) {\ndiff --git a/run-command.c b/run-command.c\nindex 8bf5922..b3d287e 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"run-command.h\"\n #include <sys/wait.h>\n+#include \"exec_cmd.h\"\n \n int run_command_v_opt(int argc, char **argv, int flags)\n {\n@@ -13,9 +14,13 @@ int run_command_v_opt(int argc, char **a\n \t\t\tint fd = open(\"/dev/null\", O_RDWR);\n \t\t\tdup2(fd, 0);\n \t\t\tdup2(fd, 1);\n-\t\t\tclose(fd);\t\t\t\n+\t\t\tclose(fd);\n+\t\t}\n+\t\tif (flags & RUN_GIT_CMD) {\n+\t\t\texecv_git_cmd(argv);\n+\t\t} else {\n+\t\t\texecvp(argv[0], (char *const*) argv);\n \t\t}\n-\t\texecvp(argv[0], (char *const*) argv);\n \t\tdie(\"exec %s failed.\", argv[0]);\n \t}\n \tfor (;;) {\ndiff --git a/run-command.h b/run-command.h\nindex 2469eea..ef3ee05 100644\n--- a/run-command.h\n+++ b/run-command.h\n@@ -12,7 +12,7 @@ enum {\n };\n \n #define RUN_COMMAND_NO_STDIO 1\n-\n+#define RUN_GIT_CMD\t     2\t/*If this is to be git sub-command */\n int run_command_v_opt(int argc, char **argv, int opt);\n int run_command_v(int argc, char **argv);\n int run_command(const char *cmd, ...);\ndiff --git a/shell.c b/shell.c\nindex cd31618..0d4891f 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -12,7 +12,7 @@ static int do_generic_cmd(const char *me\n \tmy_argv[1] = arg;\n \tmy_argv[2] = NULL;\n \n-\treturn execvp(me, (char**) my_argv);\n+\treturn execv_git_cmd((char**) my_argv);\n }\n \n static struct commands {\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 1834b6b..6602d68 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -4,6 +4,7 @@\n #include \"tag.h\"\n #include \"object.h\"\n #include \"commit.h\"\n+#include \"exec_cmd.h\"\n \n static const char upload_pack_usage[] = \"git-upload-pack [--strict]\n[--timeout=nn] <dir>\";\n \n@@ -60,7 +61,7 @@ static void create_pack_file(void)\n \t\tclose(0);\n \t\tclose(fd[0]);\n \t\tclose(fd[1]);\n-\t\t*p++ = \"git-rev-list\";\n+\t\t*p++ = \"rev-list\";\n \t\t*p++ = \"--objects\";\n \t\tif (create_full_pack || MAX_NEEDS <= nr_needs)\n \t\t\t*p++ = \"--all\";\n@@ -79,13 +80,13 @@ static void create_pack_file(void)\n \t\t\t\tbuf += 41;\n \t\t\t}\n \t\t*p++ = NULL;\n-\t\texecvp(\"git-rev-list\", argv);\n+\t\texecv_git_cmd(argv);\n \t\tdie(\"git-upload-pack: unable to exec git-rev-list\");\n \t}\n \tdup2(fd[0], 0);\n \tclose(fd[0]);\n \tclose(fd[1]);\n-\texeclp(\"git-pack-objects\", \"git-pack-objects\", \"--stdout\", NULL);\n+\texec_git_cmd(\"pack-objects\", \"--stdout\");\n \tdie(\"git-upload-pack: unable to exec git-pack-objects\");\n }\n \n"},{"id":"14409","messageId":"43C3CC4A.4030805@op5.se","threadId":"3025","inReplyTo":"1136900174.11717.537.camel@brick.watson.ibm.com","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-01-10T15:01:30Z","receivedAt":"2006-01-10T15:01:30Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Michal Ostrowski wrote:\n> On Mon, 2006-01-09 at 18:52 -0800, Junio C Hamano wrote:\n> \n>>About fetch-clone.c (which is shared by fetch-pack and\n>>clone-pack), it runs \"git-index-pack\" from finish_pack and\n>>\"git-unpack-objects\" from unpack_pack, so spelling these exec\n>>with execlp(\"git\", \"git\", \"index-pack\", ...) might be cleaner,\n>>since \"git\" is required to be in users' PATH even though git-*\n>>may be moved out of the PATH in later versions of git.  I\n>>dunno...\n>>\n>>In send-pack.c, I wonder why you didn't do a setup_exec_path()\n>>at the beginning of main() instead of having two calls close to\n>>exec*() call site.\n>>\n>>The same comment applies for run-command.c; you do it once for\n>>each child, but calling it once at the beginning of receive-pack\n>>would be good enough.  The same thing for daemon.c.\n>>\n>>I suspect you are trying to limit the extent of damage, but I do\n>>not think of a downside if we just call setup_exec_path() once\n>>at the beginning of main().  $GIT_EXEC_PATH _could_ have a\n>>private copy of broken \"diff\" to confuse diff-* family, but you\n>>cannot say \"git diff\" in such a setup anyway because \"git\" does\n>>the PATH prefixing already, so it would be a moot point.\n>>\n> \n> \n> I'm not actually happy with the idea of mucking around with PATH, even\n> within git.c.  Hence I tried to only change PATH if the code had already\n> committed to an exec.\n> \n\nThis is the case in the git potty already. git.c must prepend \n--exec-path to $PATH, or the whole idea of being able to move scripts \nout of the $PATH fails (at least it fails without changing quite a few \nof the scripts).\n\nSince it's already in place in the potty and that's required to be in \nthe $PATH, I think Junio's suggestion of running execlp(\"git\", \"git\", \n...) is a good one. It will add one extra fork() and execve() for each \nclone/pull/push, but that isn't much of an issue, really.\n\n\n> An approach that I think is better is to require all exec's of git\n> programs from within git programs to use a specific git interface,\n> rather than letting each one set up it's own exec parameters.\n> \n\nA better idea would be to teach {send,upload}-pack about $GIT_EXEX_PATH \nand export it from your shells rc-file.\n\n\n> Once you have that implemented, we can have a separate discussion of how\n> the executable is to be found; \n>  - should we use PATH?\n>  - should we change PATH?\n>  - should we always exec using an absolute file name? (my preference)\n>  \n> If a user invokes /home/user/bin/git-foo, and git-foo wants to call\n> git-bar, is it legitimate for git-foo to call /usr/local/bin/git-bar, or\n> should it require /home/user/bin/git-bar?\n> \n\nIf a user invokes \"/home/user/bin/git-foo\" rather than \n\"/home/user/bin/git foo\" he/she will have to have the rest of the \ngit-suite in the $PATH. Prepending whatever directory any git-* program \nhappens to reside in to $PATH is not a good idea. Trying to execute \nprograms residing in the same directory is an even worse.\n\n\n> Should the same rules be applied to the shell scripts? (In which case\n> we'd want to do something like s:git-:$(GIT_EXEC_PATH)/git-:g.)\n> \n\nAll shell-scripts (that I'm aware of) are porcelainish. They should be \nrun through the git potty and thus should always run the git-programs \nfrom the same release as they themselves were built from regardless of \nwhether they call them through the potty or directly. This is both sane \nand simple. It was also one of the reasons that the 'git' program was \nimplemented in C to begin with.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"14413","messageId":"1136910406.11717.579.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"43C3CC4A.4030805@op5.se","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-10T16:26:46Z","receivedAt":"2006-01-10T16:26:46Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"On Tue, 2006-01-10 at 16:01 +0100, Andreas Ericsson wrote:\n\n> \n> This is the case in the git potty already. git.c must prepend \n> --exec-path to $PATH, or the whole idea of being able to move scripts \n> out of the $PATH fails (at least it fails without changing quite a few \n> of the scripts).\n\nOne could make all the scripts depend on GIT_EXEC_PATH instead of PATH.\nAt build time one could generate wrapper functions in git-sh-setup:\n\nfunction git-foo () {\n\t$(GIT_EXEC_PATH)/git-foo $*;\n}\n\nPresuming that all scripts include git-sh-setup, no other shell script\nchanges would be needed.\n\n\n\n> \n> Since it's already in place in the potty and that's required to be in \n> the $PATH, I think Junio's suggestion of running execlp(\"git\", \"git\", \n> ...) is a good one. It will add one extra fork() and execve() for each \n> clone/pull/push, but that isn't much of an issue, really.\n> \n\nThe patch I posted most recently does something comparable; all exec's\nby C git programs go through exec_git_cmd, which actually implements the\n\"git potty\" logic (and git.c itself uses exec_git_cmd).  If there is to\nbe a consistent rule for how to exec a git program from a git C program,\nI think that it's reasonable that there be an API to enforce it.  \n\nNote that the creation and use of such a function simply means that we\nhide the logic that handles PATH/GIT_EXEC_PATH; how git_exec_cmd()\nactually calls execve() and how PATH and GIT_EXEC_PATH are used is a\nseparate issue.  When it comes to the former, I think it is best to have\nall exec's of git programs go through an interface that imposes the same\nPATH/GIT_EXEC_PATH logics.  As to the latter, my only concern is that we\nshould never do 'setenv(\"PATH\",....)'.\n\n> \n> > An approach that I think is better is to require all exec's of git\n> > programs from within git programs to use a specific git interface,\n> > rather than letting each one set up it's own exec parameters.\n> > \n> \n> A better idea would be to teach {send,upload}-pack about $GIT_EXEX_PATH \n> and export it from your shells rc-file.\n> \n\nMy shell's rc-file doesn't get invoked when using ssh as a transport;\nthat's part of the problem.\n\n> \n> > Once you have that implemented, we can have a separate discussion of how\n> > the executable is to be found; \n> >  - should we use PATH?\n> >  - should we change PATH?\n> >  - should we always exec using an absolute file name? (my preference)\n> >  \n> > If a user invokes /home/user/bin/git-foo, and git-foo wants to call\n> > git-bar, is it legitimate for git-foo to call /usr/local/bin/git-bar, or\n> > should it require /home/user/bin/git-bar?\n> > \n> \n> If a user invokes \"/home/user/bin/git-foo\" rather than \n> \"/home/user/bin/git foo\" he/she will have to have the rest of the \n> git-suite in the $PATH. Prepending whatever directory any git-* program \n> happens to reside in to $PATH is not a good idea. \n\nIsn't this exactly what git.c is doing currently via prepend_to_path()?\n\ngit programs exec other git programs, but they also exec non-git\nprograms.  I think it is not appropriate to change PATH (via\nprepend_to_path) because this may result in unexpected behavior when\nexec'ing non-git programs:\n\nSuppose git is installed in /usr/bin, where a \"diff\" resided.\nI've got my own version of \"diff\" in /home/user/bin.\nPATH=/home/user/bin:/usr/bin.\n\nIf git now tries to execute \"diff\", after having run\nprepend_to_path(), /usr/bin/diff gets executed, not /home/user/bin/diff.\nThe user has set up PATH to ensure that /home/user/bin/diff is the diff,\nbut by mucking with PATH we subvert their intentions.\n\nThis is why in my original patch I tried to put the manipulations to\nPATH only in points where I knew that it would only affect the exec'ing\nof a git program.\n\n\n\n\n> \n> \n> > Should the same rules be applied to the shell scripts? (In which case\n> > we'd want to do something like s:git-:$(GIT_EXEC_PATH)/git-:g.)\n> > \n> \n> All shell-scripts (that I'm aware of) are porcelainish. They should be \n> run through the git potty and thus should always run the git-programs \n> from the same release as they themselves were built from regardless of \n> whether they call them through the potty or directly. This is both sane \n> and simple. It was also one of the reasons that the 'git' program was \n> implemented in C to begin with.\n> \n\nAs described above, we can have shells scripts \"always run the\ngit-programs from the same release as they themselves were built from\"\nwithout ever changing PATH.\n\n\n-- \nMichal Ostrowski <mostrows@watson.ibm.com>\n"},{"id":"14423","messageId":"43C4075E.4070407@op5.se","threadId":"3025","inReplyTo":"1136910406.11717.579.camel@brick.watson.ibm.com","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-01-10T19:13:34Z","receivedAt":"2006-01-10T19:13:34Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Michal Ostrowski wrote:\n> On Tue, 2006-01-10 at 16:01 +0100, Andreas Ericsson wrote:\n> \n> \n>>This is the case in the git potty already. git.c must prepend \n>>--exec-path to $PATH, or the whole idea of being able to move scripts \n>>out of the $PATH fails (at least it fails without changing quite a few \n>>of the scripts).\n> \n> \n> One could make all the scripts depend on GIT_EXEC_PATH instead of PATH.\n> At build time one could generate wrapper functions in git-sh-setup:\n> \n> function git-foo () {\n> \t$(GIT_EXEC_PATH)/git-foo $*;\n> }\n> \n> Presuming that all scripts include git-sh-setup, no other shell script\n> changes would be needed.\n> \n\nYuck, for two reasons.\n\n* Not all scripts include git-sh-setup, and for good reasons. If this is \nwhat you intend please make sure you don't break anything in the process.\n\n* This will spawn a sub-shell for each git-foo process called. Shells \nare way more expensive than the git potty, so the performance hit in \niterations might be considerable. Think StGit and Cogito as well.\n\n\nOn a side-note, $* will break quoting (you should use \"$@\" instead, with \ndouble-quotes attached), and\n\n\t$(GIT_EXEC_PATH)/git-foo $*\n\nwill try to execute GIT_EXEC_PATH and prepend its output to the rest of \nthe command, which is quite obviously wrong.\n\n\n> \n>>Since it's already in place in the potty and that's required to be in \n>>the $PATH, I think Junio's suggestion of running execlp(\"git\", \"git\", \n>>...) is a good one. It will add one extra fork() and execve() for each \n>>clone/pull/push, but that isn't much of an issue, really.\n>>\n> \n> \n> The patch I posted most recently does something comparable; all exec's\n> by C git programs go through exec_git_cmd, which actually implements the\n> \"git potty\" logic (and git.c itself uses exec_git_cmd).  If there is to\n> be a consistent rule for how to exec a git program from a git C program,\n> I think that it's reasonable that there be an API to enforce it.  \n> \n\nTrue. Perhaps I misread your patch or your reasoning.\n\n\n> Note that the creation and use of such a function simply means that we\n> hide the logic that handles PATH/GIT_EXEC_PATH; how git_exec_cmd()\n> actually calls execve() and how PATH and GIT_EXEC_PATH are used is a\n> separate issue.  When it comes to the former, I think it is best to have\n> all exec's of git programs go through an interface that imposes the same\n> PATH/GIT_EXEC_PATH logics.  As to the latter, my only concern is that we\n> should never do 'setenv(\"PATH\",....)'.\n> \n\nsetenv(\"PATH\", ..) is way preferrable over the git-setup.sh hackery \nsuggested above, so long as it's only ever done in the git potty. That's \nwhat the potty is there for, after all.\n\n> \n>>>An approach that I think is better is to require all exec's of git\n>>>programs from within git programs to use a specific git interface,\n>>>rather than letting each one set up it's own exec parameters.\n>>>\n>>\n>>A better idea would be to teach {send,upload}-pack about $GIT_EXEX_PATH \n>>and export it from your shells rc-file.\n>>\n> \n> \n> My shell's rc-file doesn't get invoked when using ssh as a transport;\n> that's part of the problem.\n> \n\nIt does for me and everybody else. $HOME/.bashrc is read even for \nnon-interactive shells. $HOME/.bash_profile isn't. If you're using \ngit-shell you're in to a whole different situation, but you didn't say \nso so I don't think you are.\n\n>>\n>>If a user invokes \"/home/user/bin/git-foo\" rather than \n>>\"/home/user/bin/git foo\" he/she will have to have the rest of the \n>>git-suite in the $PATH. Prepending whatever directory any git-* program \n>>happens to reside in to $PATH is not a good idea. \n> \n> \n> Isn't this exactly what git.c is doing currently via prepend_to_path()?\n> \n\nNo. git prepends whatever was passed in --exec-path=/some/path, what's \nfound in $GIT_EXEC_PATH or the GIT_EXEC_PATH pre-processor macro set at \ncompile-time, in that order of preference. There's a very big difference.\n\n\n> git programs exec other git programs, but they also exec non-git\n> programs.  I think it is not appropriate to change PATH (via\n> prepend_to_path) because this may result in unexpected behavior when\n> exec'ing non-git programs:\n> \n> Suppose git is installed in /usr/bin, where a \"diff\" resided.\n> I've got my own version of \"diff\" in /home/user/bin.\n> PATH=/home/user/bin:/usr/bin.\n> \n> If git now tries to execute \"diff\", after having run\n> prepend_to_path(), /usr/bin/diff gets executed, not /home/user/bin/diff.\n> The user has set up PATH to ensure that /home/user/bin/diff is the diff,\n> but by mucking with PATH we subvert their intentions.\n> \n\nGood point. Perhaps we should only prepend to path when the directory \nisn't already in $PATH, or append rather than prepend.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"14429","messageId":"7vzmm36f1x.fsf@assigned-by-dhcp.cox.net","threadId":"3025","inReplyTo":"1136910406.11717.579.camel@brick.watson.ibm.com","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-10T19:47:22Z","receivedAt":"2006-01-10T19:47:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michal Ostrowski <mostrows@watson.ibm.com> writes:\n\n> One could make all the scripts depend on GIT_EXEC_PATH instead of PATH.\n> At build time one could generate wrapper functions in git-sh-setup:\n>\n> function git-foo () {\n> \t$(GIT_EXEC_PATH)/git-foo $*;\n> }\n>\n> Presuming that all scripts include git-sh-setup, no other shell script\n> changes would be needed.\n\nIs \"git-foo\" a valid name to define shell function as?\n\n> My shell's rc-file doesn't get invoked when using ssh as a transport;\n> that's part of the problem.\n\nNot any rc, or are you bitten by bash/ssh misfeature that\nnoninteractive sessions do not start with .bash_profile?\n\n>> > Once you have that implemented, we can have a separate discussion of how\n>> > the executable is to be found; \n>> >  - should we use PATH?\n>> >  - should we change PATH?\n>> >  - should we always exec using an absolute file name? (my preference)\n\nThe goal here is to make sure we exec the program from the same\nrelease (unless user overrides it with GIT_EXEC_PATH to say \"I\nwant to try 0.99.9k, not the latest one\"), but how?  The last\none feels the most correct way if done right.\n\n> git programs exec other git programs, but they also exec non-git\n> programs.  I think it is not appropriate to change PATH (via\n> prepend_to_path) because this may result in unexpected behavior when\n> exec'ing non-git programs:\n\nThis is a valid concern.\n"},{"id":"14430","messageId":"Pine.LNX.4.63.0601102054200.27363@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"3025","inReplyTo":"7vzmm36f1x.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-01-10T19:55:01Z","receivedAt":"2006-01-10T19:55:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 10 Jan 2006, Junio C Hamano wrote:\n\n> Michal Ostrowski <mostrows@watson.ibm.com> writes:\n> \n> > git programs exec other git programs, but they also exec non-git\n> > programs.  I think it is not appropriate to change PATH (via\n> > prepend_to_path) because this may result in unexpected behavior when\n> > exec'ing non-git programs:\n> \n> This is a valid concern.\n\nWhy? If what is prepended to PATH only contains git programs?\n\nCiao,\nDscho\n"},{"id":"14432","messageId":"20060110201536.GA3155@steel.home","threadId":"3025","inReplyTo":"43C4075E.4070407@op5.se","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2006-01-10T20:15:36Z","receivedAt":"2006-01-10T20:15:36Z","isPatch":true,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Andreas Ericsson, Tue, Jan 10, 2006 20:13:34 +0100:\n> >My shell's rc-file doesn't get invoked when using ssh as a transport;\n> >that's part of the problem.\n> \n> It does for me and everybody else. $HOME/.bashrc is read even for \n> non-interactive shells. ...\n\nNot really:\n\n$ man bash\n\n       When bash is started non-interactively, to  run  a  shell  script,  for\n       example, it looks for the variable BASH_ENV in the environment, expands\n       its value if it appears there, and uses the expanded value as the  name\n       of  a  file to read and execute.  Bash behaves as if the following com-\n       mand were executed:\n              if [ -n \"$BASH_ENV\" ]; then . \"$BASH_ENV\"; fi\n       but the value of the PATH variable is not used to search for  the  file\n       name.\n\n$ ssh host2 strace -e open bash -c :\nopen(\"/etc/ld.so.cache\", O_RDONLY)      = 3\nopen(\"/lib/libncurses.so.5\", O_RDONLY)  = 3\nopen(\"/lib/tls/libdl.so.2\", O_RDONLY)   = 3\nopen(\"/lib/tls/libc.so.6\", O_RDONLY)    = 3\nopen(\"/dev/tty\", O_RDWR|O_NONBLOCK|O_LARGEFILE) = -1 ENXIO (No such device or address)\nopen(\"/etc/mtab\", O_RDONLY)             = 3\nopen(\"/proc/meminfo\", O_RDONLY)         = 3\nopen(\"/proc/sys/kernel/ngroups_max\", O_RDONLY) = 3\n"},{"id":"14434","messageId":"1136924980.11717.603.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"7vu0cb6f1n.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-10T20:29:40Z","receivedAt":"2006-01-10T20:29:40Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"On Tue, 2006-01-10 at 11:47 -0800, Junio C Hamano wrote:\n\n\n> > No. git prepends whatever was passed in --exec-path=/some/path, what's\n> > found in $GIT_EXEC_PATH or the GIT_EXEC_PATH pre-processor macro set\n> > at compile-time, in that order of preference. There's a very big\n> > difference.\n> \n> True.\n> \n> > Good point. Perhaps we should only prepend to path when the directory\n> > isn't already in $PATH, or append rather than prepend.\n> \n> I think appending not prepending would stop letting me say\n> \n>  $ GIT_EXEC_PATH=/usr/libexec/git-core/0.99.9k git foo\n> \n> to try out older version, if I have more recent git in my PATH.\n> But I agree with Michal it is not nice to affect invocations of\n> \"diff\" (and things spawned from hooks, which would inherit PATH\n> from receive-pack).\n> \n> \n\nHow about searching for executables in the following places, and in this\norder:\n\n1. --exec-path setting, if any\n2. GIT_EXEC_PATH env var, if set\n3. PATH (never modified)\n4. Value of ${bindir} at build time\n\n\nTo accomplish this I'd suggest reworking the logic the git c programs\nuse to exec another git program.  The patch I sent out this morning\nattempts to do this.  (I'll append again to avoid confusion with\nprevious patches.)  But note that the patch below doesn't implement this\npolicy above; the point is that it provides for a single location where\nit has to be implemented (in exec_cmd.c).  I'd be happy to clean it up\nand submit it formally as a clean-up patch (one that doesn't change the\nPATH/GIT_EXEC_PATH search behavior currently implemented).\n\nSecondly, the shell scripts as is cannot utilize this search order as\nlong as they don't religiously use the git potty internally.  If we were\nto \"sed -e 's/git-/git /g' -i git*.sh\" (grotesquely simplified of\ncourse) then they would. \n\n\n\n-- \nMichal Ostrowski <mostrows@watson.ibm.com>\n\ndiff --git a/Makefile b/Makefile\nindex c9c15b5..db57858 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -173,7 +173,7 @@ DIFF_OBJS = \\\n \n LIB_OBJS = \\\n \tblob.o commit.o connect.o count-delta.o csum-file.o \\\n-\tdate.o diff-delta.o entry.o ident.o index.o \\\n+\tdate.o diff-delta.o entry.o exec_cmd.o ident.o index.o \\\n \tobject.o pack-check.o patch-delta.o path.o pkt-line.o \\\n \tquote.o read-cache.o refs.o run-command.o \\\n \tserver-info.o setup.o sha1_file.o sha1_name.o strbuf.o \\\n@@ -184,6 +184,16 @@ LIB_OBJS = \\\n LIBS = $(LIB_FILE)\n LIBS += -lz\n \n+\n+# .exec_cmd.bindir stores $(bindir) used to compile exec_cmd.o\n+# If it has changed, store the new value and force exec_cmd.o to be\nrebuilt\n+ifneq ($(shell cat .exec_cmd.bindir 2>/dev/null),$(bindir))\n+.PHONY: exec_cmd.c\n+$(shell echo $(bindir) > .exec_cmd.bindir)\n+endif\n+\n+exec_cmd.o: CFLAGS+=-DGIT_EXEC_PATH=\\\"$(bindir)\\\"\n+\n # Shell quote;\n # Result of this needs to be placed inside ''\n shq = $(subst ','\\'',$(1))\ndiff --git a/daemon.c b/daemon.c\nindex 3bd1426..ab793bd 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -9,6 +9,7 @@\n #include <syslog.h>\n #include \"pkt-line.h\"\n #include \"cache.h\"\n+#include \"exec_cmd.h\"\n \n static int log_syslog;\n static int verbose;\n@@ -227,7 +228,7 @@ static int upload(char *dir)\n \tsnprintf(timeout_buf, sizeof timeout_buf, \"--timeout=%u\", timeout);\n \n \t/* git-upload-pack only ever reads stuff, so this is safe */\n-\texeclp(\"git-upload-pack\", \"git-upload-pack\", \"--strict\", timeout_buf,\n\".\", NULL);\n+\texec_git_cmd(\"upload-pack\", \"--strict\", timeout_buf, \".\");\n \treturn -1;\n }\n \ndiff --git a/fetch-clone.c b/fetch-clone.c\nindex f46fe6e..5ae9bda 100644\n--- a/fetch-clone.c\n+++ b/fetch-clone.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"exec_cmd.h\"\n #include <sys/wait.h>\n \n static int finish_pack(const char *pack_tmp_name, const char *me)\n@@ -27,8 +28,7 @@ static int finish_pack(const char *pack_\n \t\tdup2(pipe_fd[1], 1);\n \t\tclose(pipe_fd[0]);\n \t\tclose(pipe_fd[1]);\n-\t\texeclp(\"git-index-pack\",\"git-index-pack\",\n-\t\t       \"-o\", idx, pack_tmp_name, NULL);\n+\t\texec_git_cmd(\"index-pack\", \"-o\", idx, pack_tmp_name);\n \t\terror(\"cannot exec git-index-pack <%s> <%s>\",\n \t\t      idx, pack_tmp_name);\n \t\texit(1);\n@@ -105,8 +105,7 @@ int receive_unpack_pack(int fd[2], const\n \t\tdup2(fd[0], 0);\n \t\tclose(fd[0]);\n \t\tclose(fd[1]);\n-\t\texeclp(\"git-unpack-objects\", \"git-unpack-objects\",\n-\t\t       quiet ? \"-q\" : NULL, NULL);\n+\t\texec_git_cmd(\"unpack-objects\", quiet ? \"-q\" : NULL);\n \t\tdie(\"git-unpack-objects exec failed\");\n \t}\n \tclose(fd[0]);\ndiff --git a/git.c b/git.c\nindex 5e7da74..a45dc54 100644\n--- a/git.c\n+++ b/git.c\n@@ -10,6 +10,7 @@\n #include <stdarg.h>\n #include <sys/ioctl.h>\n #include \"git-compat-util.h\"\n+#include \"exec_cmd.h\"\n \n #ifndef PATH_MAX\n # define PATH_MAX 4096\n@@ -192,25 +193,6 @@ static void cmd_usage(const char *exec_p\n \texit(1);\n }\n \n-static void prepend_to_path(const char *dir, int len)\n-{\n-\tchar *path, *old_path = getenv(\"PATH\");\n-\tint path_len = len;\n-\n-\tif (!old_path)\n-\t\told_path = \"/usr/local/bin:/usr/bin:/bin\";\n-\n-\tpath_len = len + strlen(old_path) + 1;\n-\n-\tpath = malloc(path_len + 1);\n-\n-\tmemcpy(path, dir, len);\n-\tpath[len] = ':';\n-\tmemcpy(path + len + 1, old_path, path_len - len);\n-\n-\tsetenv(\"PATH\", path, 1);\n-}\n-\n static void show_man_page(char *git_cmd)\n {\n \tchar *page;\n@@ -233,14 +215,10 @@ int main(int argc, char **argv, char **e\n {\n \tchar git_command[PATH_MAX + 1];\n \tchar wd[PATH_MAX + 1];\n-\tint i, len, show_help = 0;\n-\tchar *exec_path = getenv(\"GIT_EXEC_PATH\");\n+\tint i, show_help = 0;\n \n \tgetcwd(wd, PATH_MAX);\n \n-\tif (!exec_path)\n-\t\texec_path = GIT_EXEC_PATH;\n-\n \tfor (i = 1; i < argc; i++) {\n \t\tchar *arg = argv[i];\n \n@@ -257,9 +235,9 @@ int main(int argc, char **argv, char **e\n \t\tif (!strncmp(arg, \"exec-path\", 9)) {\n \t\t\targ += 9;\n \t\t\tif (*arg == '=')\n-\t\t\t\texec_path = arg + 1;\n+\t\t\t\tgit_set_exec_path(arg + 1);\n \t\t\telse {\n-\t\t\t\tputs(exec_path);\n+\t\t\t\tputs(git_exec_path());\n \t\t\t\texit(0);\n \t\t\t}\n \t\t}\n@@ -275,48 +253,18 @@ int main(int argc, char **argv, char **e\n \n \tif (i >= argc || show_help) {\n \t\tif (i >= argc)\n-\t\t\tcmd_usage(exec_path, NULL);\n+\t\t\tcmd_usage(git_exec_path(), NULL);\n \n \t\tshow_man_page(argv[i]);\n \t}\n \n-\tif (*exec_path != '/') {\n-\t\tif (!getcwd(git_command, sizeof(git_command))) {\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"git: cannot determine current directory\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\tlen = strlen(git_command);\n-\n-\t\t/* Trivial cleanup */\n-\t\twhile (!strncmp(exec_path, \"./\", 2)) {\n-\t\t\texec_path += 2;\n-\t\t\twhile (*exec_path == '/')\n-\t\t\t\texec_path++;\n-\t\t}\n-\t\tsnprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t \"/%s\", exec_path);\n-\t}\n-\telse\n-\t\tstrcpy(git_command, exec_path);\n-\tlen = strlen(git_command);\n-\tprepend_to_path(git_command, len);\n-\n-\tlen += snprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t\"/git-%s\", argv[i]);\n-\tif (sizeof(git_command) <= len) {\n-\t\tfprintf(stderr, \"git: command name given is too long.\\n\");\n-\t\texit(1);\n-\t}\n-\n-\t/* execve() can only ever return if it fails */\n-\texecve(git_command, &argv[i], envp);\n+\texecv_git_cmd(argv + i);\n \n \tif (errno == ENOENT)\n-\t\tcmd_usage(exec_path, \"'%s' is not a git-command\", argv[i]);\n+\t\tcmd_usage(git_exec_path(), \"'%s' is not a git-command\",\n+\t\t\t  argv[i]);\n \n \tfprintf(stderr, \"Failed to run command '%s': %s\\n\",\n \t\tgit_command, strerror(errno));\n-\n \treturn 1;\n }\ndiff --git a/receive-pack.c b/receive-pack.c\nindex f847ec2..8e78e32 100644\n--- a/receive-pack.c\n+++ b/receive-pack.c\n@@ -257,7 +257,7 @@ static void read_head_info(void)\n \n static const char *unpack(int *error_code)\n {\n-\tint code = run_command(unpacker, NULL);\n+\tint code = run_command_v_opt(1, &unpacker, RUN_GIT_CMD);\n \n \t*error_code = 0;\n \tswitch (code) {\ndiff --git a/run-command.c b/run-command.c\nindex 8bf5922..b3d287e 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"run-command.h\"\n #include <sys/wait.h>\n+#include \"exec_cmd.h\"\n \n int run_command_v_opt(int argc, char **argv, int flags)\n {\n@@ -13,9 +14,13 @@ int run_command_v_opt(int argc, char **a\n \t\t\tint fd = open(\"/dev/null\", O_RDWR);\n \t\t\tdup2(fd, 0);\n \t\t\tdup2(fd, 1);\n-\t\t\tclose(fd);\t\t\t\n+\t\t\tclose(fd);\n+\t\t}\n+\t\tif (flags & RUN_GIT_CMD) {\n+\t\t\texecv_git_cmd(argv);\n+\t\t} else {\n+\t\t\texecvp(argv[0], (char *const*) argv);\n \t\t}\n-\t\texecvp(argv[0], (char *const*) argv);\n \t\tdie(\"exec %s failed.\", argv[0]);\n \t}\n \tfor (;;) {\ndiff --git a/run-command.h b/run-command.h\nindex 2469eea..ef3ee05 100644\n--- a/run-command.h\n+++ b/run-command.h\n@@ -12,7 +12,7 @@ enum {\n };\n \n #define RUN_COMMAND_NO_STDIO 1\n-\n+#define RUN_GIT_CMD\t     2\t/*If this is to be git sub-command */\n int run_command_v_opt(int argc, char **argv, int opt);\n int run_command_v(int argc, char **argv);\n int run_command(const char *cmd, ...);\ndiff --git a/shell.c b/shell.c\nindex cd31618..0d4891f 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -12,7 +12,7 @@ static int do_generic_cmd(const char *me\n \tmy_argv[1] = arg;\n \tmy_argv[2] = NULL;\n \n-\treturn execvp(me, (char**) my_argv);\n+\treturn execv_git_cmd((char**) my_argv);\n }\n \n static struct commands {\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 1834b6b..6602d68 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -4,6 +4,7 @@\n #include \"tag.h\"\n #include \"object.h\"\n #include \"commit.h\"\n+#include \"exec_cmd.h\"\n \n static const char upload_pack_usage[] = \"git-upload-pack [--strict]\n[--timeout=nn] <dir>\";\n \n@@ -60,7 +61,7 @@ static void create_pack_file(void)\n \t\tclose(0);\n \t\tclose(fd[0]);\n \t\tclose(fd[1]);\n-\t\t*p++ = \"git-rev-list\";\n+\t\t*p++ = \"rev-list\";\n \t\t*p++ = \"--objects\";\n \t\tif (create_full_pack || MAX_NEEDS <= nr_needs)\n \t\t\t*p++ = \"--all\";\n@@ -79,13 +80,13 @@ static void create_pack_file(void)\n \t\t\t\tbuf += 41;\n \t\t\t}\n \t\t*p++ = NULL;\n-\t\texecvp(\"git-rev-list\", argv);\n+\t\texecv_git_cmd(argv);\n \t\tdie(\"git-upload-pack: unable to exec git-rev-list\");\n \t}\n \tdup2(fd[0], 0);\n \tclose(fd[0]);\n \tclose(fd[1]);\n-\texeclp(\"git-pack-objects\", \"git-pack-objects\", \"--stdout\", NULL);\n+\texec_git_cmd(\"pack-objects\", \"--stdout\");\n \tdie(\"git-upload-pack: unable to exec git-pack-objects\");\n }\n \n"},{"id":"14436","messageId":"1136925066.11717.605.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"Pine.LNX.4.63.0601102054200.27363@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-10T20:31:05Z","receivedAt":"2006-01-10T20:31:05Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"On Tue, 2006-01-10 at 20:55 +0100, Johannes Schindelin wrote:\n> Hi,\n> \n> On Tue, 10 Jan 2006, Junio C Hamano wrote:\n> \n> > Michal Ostrowski <mostrows@watson.ibm.com> writes:\n> > \n> > > git programs exec other git programs, but they also exec non-git\n> > > programs.  I think it is not appropriate to change PATH (via\n> > > prepend_to_path) because this may result in unexpected behavior when\n> > > exec'ing non-git programs:\n> > \n> > This is a valid concern.\n> \n> Why? If what is prepended to PATH only contains git programs?\n> \n\n\nIf git is installed with prefix=/usr, then that won't be the case.\n\n\n-- \nMichal Ostrowski <mostrows@watson.ibm.com>\n"},{"id":"14437","messageId":"1136925167.11717.607.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"20060110201536.GA3155@steel.home","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-10T20:32:47Z","receivedAt":"2006-01-10T20:32:47Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"On Tue, 2006-01-10 at 21:15 +0100, Alex Riesen wrote:\n> Andreas Ericsson, Tue, Jan 10, 2006 20:13:34 +0100:\n> > >My shell's rc-file doesn't get invoked when using ssh as a transport;\n> > >that's part of the problem.\n> > \n> > It does for me and everybody else. $HOME/.bashrc is read even for \n> > non-interactive shells. ...\n\nOn the system I'm dealing with, ssh does not invoke bash if a command is\nspecified.\n\nIf I do ssh user@system /home/user/bin/foo,  ssh performs an exec\nof /home/user/bin/foo; my shell is never invoked.  This isn't up to me;\nI don't have root on this system.\n\n\n-- \nMichal Ostrowski <mostrows@watson.ibm.com>\n"},{"id":"14442","messageId":"Pine.LNX.4.63.0601102200040.31923@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"3025","inReplyTo":"1136925066.11717.605.camel@brick.watson.ibm.com","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-01-10T21:03:22Z","receivedAt":"2006-01-10T21:03:22Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 10 Jan 2006, Michal Ostrowski wrote:\n\n> On Tue, 2006-01-10 at 20:55 +0100, Johannes Schindelin wrote:\n> > Hi,\n> > \n> > On Tue, 10 Jan 2006, Junio C Hamano wrote:\n> > \n> > > Michal Ostrowski <mostrows@watson.ibm.com> writes:\n> > > \n> > > > git programs exec other git programs, but they also exec non-git\n> > > > programs.  I think it is not appropriate to change PATH (via\n> > > > prepend_to_path) because this may result in unexpected behavior when\n> > > > exec'ing non-git programs:\n> > > \n> > > This is a valid concern.\n> > \n> > Why? If what is prepended to PATH only contains git programs?\n> > \n> \n> \n> If git is installed with prefix=/usr, then that won't be the case.\n\nOkay, so here we have the problem: Two completely different setups. One \ninto a standard location on the PATH (which used to be the default), the \nother with a libexec/ directory (which some want in the future). And a git \nwrapper which makes no difference between both.\n\nWouldn't it make much more sense to have a switch in the Makefile, which \nsays *if* we have a libexec/ directory? This switch would decide if we \never prepend the path with the libexec/ directory or not.\n\nCiao,\nDscho\n"},{"id":"14443","messageId":"7vhd8b6b8k.fsf@assigned-by-dhcp.cox.net","threadId":"3025","inReplyTo":"Pine.LNX.4.63.0601102054200.27363@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-10T21:09:47Z","receivedAt":"2006-01-10T21:09:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Why? If what is prepended to PATH only contains git programs?\n\nRecall the \"diff\" example Michal gave us.\n\n\n \n"},{"id":"14453","messageId":"43C44C12.3050609@op5.se","threadId":"3025","inReplyTo":"1136924980.11717.603.camel@brick.watson.ibm.com","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-01-11T00:06:42Z","receivedAt":"2006-01-11T00:06:42Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Michal Ostrowski wrote:\n> On Tue, 2006-01-10 at 11:47 -0800, Junio C Hamano wrote:\n> \n>>\n>>>Good point. Perhaps we should only prepend to path when the directory\n>>>isn't already in $PATH, or append rather than prepend.\n>>\n>>I think appending not prepending would stop letting me say\n>>\n>> $ GIT_EXEC_PATH=/usr/libexec/git-core/0.99.9k git foo\n>>\n>>to try out older version, if I have more recent git in my PATH.\n>>But I agree with Michal it is not nice to affect invocations of\n>>\"diff\" (and things spawned from hooks, which would inherit PATH\n>>from receive-pack).\n>>\n\nSo how about prepending only when the directory isn't already in the \nPATH? That can be done with a two-line patch to git.c only.\n\nIt will break the \"diff in another dir\" scenario in the highly unlikely \nevent that the other diff is located in the same dir as the git suite, \nisn't supposed to be used, and the directory in question isn't in $PATH \nalready. People who have such a setup will be too ashamed to admit it, \nso we're not likely to be blamed for it either. ;)\n\n>>\n> \n> \n> How about searching for executables in the following places, and in this\n> order:\n> \n> 1. --exec-path setting, if any\n> 2. GIT_EXEC_PATH env var, if set\n> 3. PATH (never modified)\n> 4. Value of ${bindir} at build time\n> \n\nThis is more or less what's done today, with the exception that $PATH \nisn't searched and it throws an error immediately no matter where \nexec_path (the git.c variable) came from.\n\nAdding $PATH to the search-pattern would be a simple matter of falling \nback to execvp() if execve(), but then we could end up with running \nprograms from a different release while the user thinks he/she's \nspecifically running 1.0.3... Tricky problem, really.\n\n> \n> Secondly, the shell scripts as is cannot utilize this search order as\n> long as they don't religiously use the git potty internally.  If we were\n> to \"sed -e 's/git-/git /g' -i git*.sh\" (grotesquely simplified of\n> course) then they would. \n> \n\nI think this has been done, but as it happened to be convenient. I'd \nprefer if the git potty could keep prepending the GIT_EXEC_PATH to the \npath, really. We're bound to run into setup-related problems otherwise, \nsuch as;\n\nAlice writes a script that works fine for her and her friends, so she \nshares it freely with Bob and whoever else might be listening. Bob's \ngit-tools aren't in the $PATH but he keeps the potty handy at all times. \nHe can't always run it through the potty because in some code-paths \nAlice's script uses git-tools without going through the potty. Bob \nthinks Alice puts entropy in her programs on purpose, so Alice flees, \nsobbing and shaking in anger and betrayed trust. The two never speak again.\n\nLuckily, Bruce Schneier shows up and saves the day.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"14454","messageId":"43C44CF2.5050808@op5.se","threadId":"3025","inReplyTo":"Pine.LNX.4.63.0601102200040.31923@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-01-11T00:10:26Z","receivedAt":"2006-01-11T00:10:26Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Johannes Schindelin wrote:\n>>>>>git programs exec other git programs, but they also exec non-git\n>>>>>programs.  I think it is not appropriate to change PATH (via\n>>>>>prepend_to_path) because this may result in unexpected behavior when\n>>>>>exec'ing non-git programs:\n>>>>\n>>>>This is a valid concern.\n>>>\n>>>Why? If what is prepended to PATH only contains git programs?\n>>>\n>>\n>>\n>>If git is installed with prefix=/usr, then that won't be the case.\n> \n> \n> Okay, so here we have the problem: Two completely different setups. One \n> into a standard location on the PATH (which used to be the default), the \n> other with a libexec/ directory (which some want in the future). And a git \n> wrapper which makes no difference between both.\n> \n> Wouldn't it make much more sense to have a switch in the Makefile, which \n> says *if* we have a libexec/ directory?\n\n\nNo, it wouldn't, because then we can't use a different release of the \ngit-tools without re-compiling the potty.\n\nvoid prepend_to_path(old_path, to_prep)\n{\n\tif (strstr(old_path, to_prep))\n\t\treturn;\n\n\treally_prepend_to_path(old_path, to_prep);\n}\n\nwould work just fine though.\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"14456","messageId":"7vd5iz4mt7.fsf@assigned-by-dhcp.cox.net","threadId":"3025","inReplyTo":"1136924980.11717.603.camel@brick.watson.ibm.com","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-11T00:42:44Z","receivedAt":"2006-01-11T00:42:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michal Ostrowski <mostrows@watson.ibm.com> writes:\n\n> How about searching for executables in the following places, and in this\n> order:\n>\n> 1. --exec-path setting, if any\n> 2. GIT_EXEC_PATH env var, if set\n> 3. PATH (never modified)\n> 4. Value of ${bindir} at build time\n\nMy preference is to first do this to the Makefile:\n\n-- >8 --\ndiff --git a/Makefile b/Makefile\nindex 5817e86..b1e3055 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -71,6 +71,7 @@ ALL_LDFLAGS = $(LDFLAGS)\n \n prefix = $(HOME)\n bindir = $(prefix)/bin\n+gitexecdir = $(prefix)/bin\n template_dir = $(prefix)/share/git-core/templates/\n GIT_PYTHON_DIR = $(prefix)/share/git-core/python\n # DESTDIR=\n@@ -144,7 +145,7 @@ PROGRAMS = \\\n \tgit-describe$X\n \n # what 'all' will build and 'install' will install.\n-ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X\n+ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)\n \n # Backward compatibility -- to be removed after 1.0\n PROGRAMS += git-ssh-pull$X git-ssh-push$X\n@@ -368,13 +369,13 @@ LIB_OBJS += $(COMPAT_OBJS)\n export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir\n ### Build rules\n \n-all: $(ALL_PROGRAMS)\n+all: $(ALL_PROGRAMS) git$X\n \n all:\n \t$(MAKE) -C templates\n \n git$X: git.c $(LIB_FILE)\n-\t$(CC) -DGIT_EXEC_PATH='\"$(bindir)\"' -DGIT_VERSION='\"$(GIT_VERSION)\"' \\\n+\t$(CC) -DGIT_EXEC_PATH='\"$(gitexecdir)\"' -DGIT_VERSION='\"$(GIT_VERSION)\"' \\\n \t\t$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)\n \n $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh\n@@ -470,7 +471,9 @@ check:\n \n install: all\n \t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))\n-\t$(INSTALL) $(ALL_PROGRAMS) $(call shellquote,$(DESTDIR)$(bindir))\n+\t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(gitexecdir))\n+\t$(INSTALL) $(ALL_PROGRAMS) $(call shellquote,$(DESTDIR)$(gitexecdir))\n+\t$(INSTALL) git$X $(call shellquote,$(DESTDIR)$(bindir))\n \t$(MAKE) -C templates install\n \t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))\n \t$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))\n\n-- 8< --\n\nand then make the rule for git things:\n\n 1. --exec-path\n 2. GIT_EXEC_PATH environment\n 3. $(gitexecdir)\n\nin this order.  Non git things should just use $PATH without\nlooking at anything else --- as long as a hook script calls a git\nwrapper (i.e. \"git foo\" not \"git-foo\") I think things should\nwork fine.\n\n> ...  The patch I sent out this morning\n> attempts to do this.  (I'll append again to avoid confusion with\n> previous patches)...\n\n> +\t\tif (flags & RUN_GIT_CMD) {\n> +\t\t\texecv_git_cmd(argv);\n> +\t\t} else {\n> +\t\t\texecvp(argv[0], (char *const*) argv);\n>  \t\t}\n\nThis bit sounds good, but if you were to go this route I'd\nsuggest to rename your exec_git_cmd() to execl_git_cmd() (and\nterminate the vararg list with NULL) for naming consistency.\nexecv_git_cmd() is good---we do not *want* execvp_git_cmd(),\nbecause we do not run git subcommand using PATH.\n"},{"id":"14457","messageId":"7v8xtn4m59.fsf@assigned-by-dhcp.cox.net","threadId":"3025","inReplyTo":"43C44CF2.5050808@op5.se","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-11T00:57:06Z","receivedAt":"2006-01-11T00:57:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andreas Ericsson <ae@op5.se> writes:\n\n> Johannes Schindelin wrote:\n\n>> Wouldn't it make much more sense to have a switch in the Makefile,\n>> which says *if* we have a libexec/ directory?\n>\n> No, it wouldn't, because then we can't use a different release of the\n> git-tools without re-compiling the potty.\n\nTrue, but *please* stop calling \"git wrapper\" a potty.  It gives\nme an impression that it is not connected to the plumbing.\n\nI do not do Porcelain, but I do not do plastics nor glass either\n;-).\n\nThanks.\n"},{"id":"14460","messageId":"1136945343.11717.638.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"7vd5iz4mt7.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-11T02:09:02Z","receivedAt":"2006-01-11T02:09:02Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"On Tue, 2006-01-10 at 16:42 -0800, Junio C Hamano wrote:\n> Michal Ostrowski <mostrows@watson.ibm.com> writes:\n> \n> > How about searching for executables in the following places, and in this\n> > order:\n> >\n> > 1. --exec-path setting, if any\n> > 2. GIT_EXEC_PATH env var, if set\n> > 3. PATH (never modified)\n> > 4. Value of ${bindir} at build time\n> \n\n\n> and then make the rule for git things:\n> \n>  1. --exec-path\n>  2. GIT_EXEC_PATH environment\n>  3. $(gitexecdir)\n> \n> in this order.  Non git things should just use $PATH without\n> looking at anything else --- as long as a hook script calls a git\n> wrapper (i.e. \"git foo\" not \"git-foo\") I think things should\n> work fine.\n> \n\nThe patch that follows implements your suggested search order and\nincludes suggested Makefile changes.\n\n-- \nMichal Ostrowski <mostrows@watson.ibm.com>\n"},{"id":"14461","messageId":"1136945538.11717.643.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"7vd5iz4mt7.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] Exec git programs without using PATH.","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-11T02:12:17Z","receivedAt":"2006-01-11T02:12:17Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"\nThe git suite may not be in PATH (and thus programs such as\ngit-send-pack could not exec git-rev-list).  Thus there is a need for\nlogic that will locate these programs.  Modifying PATH is not\ndesirable as it result in behavior differing from the user's\nintentions, as we may end up prepending \"/usr/bin\" to PATH.\n\n- git C programs will use exec*_git_cmd() APIs to exec sub-commands.\n- exec*_git_cmd() will execute a git program by searching for it in\n  the following directories:\n\t1. --exec-path (as used by \"git\")\n\t2. The GIT_EXEC_PATH environment variable.\n\t3. $(gitexecdir) as set in Makefile (default value $(bindir)).\n- git potty will modify PATH as before to enable shell scripts to  \n  invoke \"git-foo\" commands.\n\nIdeally, shell scripts should use the git potty to become independent of\nPATH, and then modifying PATH will not be necessary.\n\nSigned-off-by: Michal Ostrowski <mostrows@watson.ibm.com>\n\n---\n\n Makefile       |   21 ++++++++--\n daemon.c       |    3 +\n exec_cmd.c     |  118\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n exec_cmd.h     |   10 +++++\n fetch-clone.c  |    7 +--\n git.c          |   54 ++++++--------------------\n receive-pack.c |    2 -\n run-command.c  |    9 +++-\n run-command.h  |    2 -\n send-pack.c    |    8 ++--\n shell.c        |    2 -\n upload-pack.c  |    7 ++-\n 12 files changed, 181 insertions(+), 62 deletions(-)\n create mode 100644 exec_cmd.c\n create mode 100644 exec_cmd.h\n\nd6dbbb5b9b47c37f44c3494962b9fa534677729f\ndiff --git a/Makefile b/Makefile\nindex c9c15b5..912c223 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -68,6 +68,7 @@ ALL_LDFLAGS = $(LDFLAGS)\n \n prefix = $(HOME)\n bindir = $(prefix)/bin\n+gitexecdir = $(prefix)/bin\n template_dir = $(prefix)/share/git-core/templates/\n GIT_PYTHON_DIR = $(prefix)/share/git-core/python\n # DESTDIR=\n@@ -141,7 +142,7 @@ PROGRAMS = \\\n \tgit-describe$X\n \n # what 'all' will build and 'install' will install.\n-ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X\n+ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)\n \n # Backward compatibility -- to be removed after 1.0\n PROGRAMS += git-ssh-pull$X git-ssh-push$X\n@@ -173,7 +174,7 @@ DIFF_OBJS = \\\n \n LIB_OBJS = \\\n \tblob.o commit.o connect.o count-delta.o csum-file.o \\\n-\tdate.o diff-delta.o entry.o ident.o index.o \\\n+\tdate.o diff-delta.o entry.o exec_cmd.o ident.o index.o \\\n \tobject.o pack-check.o patch-delta.o path.o pkt-line.o \\\n \tquote.o read-cache.o refs.o run-command.o \\\n \tserver-info.o setup.o sha1_file.o sha1_name.o strbuf.o \\\n@@ -184,6 +185,16 @@ LIB_OBJS = \\\n LIBS = $(LIB_FILE)\n LIBS += -lz\n \n+\n+# .exec_cmd.gitexecdir stores $(gitexecir) used to compile exec_cmd.o\n+# If it has changed, store the new value and force exec_cmd.o to be\nrebuilt\n+ifneq ($(shell cat .exec_cmd.gitexecdir 2>/dev/null),$(gitexecdir))\n+.PHONY: exec_cmd.c\n+$(shell echo $(gitexecdir) > .exec_cmd.gitexecdir)\n+endif\n+\n+exec_cmd.o: CFLAGS+=-DGIT_EXEC_PATH=\\\"$(gitexecdir)\\\"\n+\n # Shell quote;\n # Result of this needs to be placed inside ''\n shq = $(subst ','\\'',$(1))\n@@ -366,13 +377,13 @@ LIB_OBJS += $(COMPAT_OBJS)\n export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir\n ### Build rules\n \n-all: $(ALL_PROGRAMS)\n+all: $(ALL_PROGRAMS) git$X\n \n all:\n \t$(MAKE) -C templates\n \n git$X: git.c $(LIB_FILE)\n-\t$(CC) -DGIT_EXEC_PATH='\"$(bindir)\"' -DGIT_VERSION='\"$(GIT_VERSION)\"' \\\n+\t$(CC) -DGIT_VERSION='\"$(GIT_VERSION)\"' \\\n \t\t$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)\n \n $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh\n@@ -468,7 +479,9 @@ check:\n \n install: all\n \t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))\n+\t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(gitexecdir))\n \t$(INSTALL) $(ALL_PROGRAMS) $(call shellquote,$(DESTDIR)$(bindir))\n+\t$(INSTALL) git$X $(call shellquote,$(DESTDIR)$(gitexecdir))\n \t$(MAKE) -C templates install\n \t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))\n \t$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))\ndiff --git a/daemon.c b/daemon.c\nindex 3bd1426..bb014fa 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -9,6 +9,7 @@\n #include <syslog.h>\n #include \"pkt-line.h\"\n #include \"cache.h\"\n+#include \"exec_cmd.h\"\n \n static int log_syslog;\n static int verbose;\n@@ -227,7 +228,7 @@ static int upload(char *dir)\n \tsnprintf(timeout_buf, sizeof timeout_buf, \"--timeout=%u\", timeout);\n \n \t/* git-upload-pack only ever reads stuff, so this is safe */\n-\texeclp(\"git-upload-pack\", \"git-upload-pack\", \"--strict\", timeout_buf,\n\".\", NULL);\n+\texecl_git_cmd(\"upload-pack\", \"--strict\", timeout_buf, \".\", NULL);\n \treturn -1;\n }\n \ndiff --git a/exec_cmd.c b/exec_cmd.c\nnew file mode 100644\nindex 0000000..a3bd40a\n--- /dev/null\n+++ b/exec_cmd.c\n@@ -0,0 +1,118 @@\n+#include \"cache.h\"\n+#include \"exec_cmd.h\"\n+#define MAX_ARGS\t32\n+\n+extern char **environ;\n+static const char *builtin_exec_path = GIT_EXEC_PATH;\n+static const char *current_exec_path = NULL;\n+\n+void git_set_exec_path(const char *exec_path)\n+{\n+\tcurrent_exec_path = exec_path;\n+}\n+\n+\n+/* Returns the highest-priority, location to look for git programs. */\n+const char *git_exec_path()\n+{\n+\tconst char *env;\n+\n+\tif (current_exec_path)\n+\t\treturn current_exec_path;\n+\n+\tenv = getenv(\"GIT_EXEC_PATH\");\n+\tif (env) {\n+\t\treturn env;\n+\t}\n+\n+\treturn builtin_exec_path;\n+}\n+\n+\n+int execv_git_cmd(char **argv)\n+{\n+\tchar git_command[PATH_MAX + 1];\n+\tchar *tmp;\n+\tint len, err, i;\n+\tconst char *paths[] = { current_exec_path,\n+\t\t\t\tgetenv(\"GIT_EXEC_PATH\"),\n+\t\t\t\tbuiltin_exec_path,\n+\t\t\t\tNULL };\n+\n+\tfor (i = 0; i < 4; ++i) {\n+\t\tconst char *exec_dir = paths[i];\n+\t\tif (!exec_dir) continue;\n+\n+\t\tif (*exec_dir != '/') {\n+\t\t\tif (!getcwd(git_command, sizeof(git_command))) {\n+\t\t\t\tfprintf(stderr, \"git: cannot determine \"\n+\t\t\t\t\t\"current directory\\n\");\n+\t\t\t\texit(1);\n+\t\t\t}\n+\t\t\tlen = strlen(git_command);\n+\n+\t\t\t/* Trivial cleanup */\n+\t\t\twhile (!strncmp(exec_dir, \"./\", 2)) {\n+\t\t\t\texec_dir += 2;\n+\t\t\t\twhile (*exec_dir == '/')\n+\t\t\t\t\texec_dir++;\n+\t\t\t}\n+\t\t\tsnprintf(git_command + len, sizeof(git_command) - len,\n+\t\t\t\t \"/%s\", exec_dir);\n+\t\t} else {\n+\t\t\tstrcpy(git_command, exec_dir);\n+\t\t}\n+\n+\t\tlen = strlen(git_command);\n+\t\tlen += snprintf(git_command + len, sizeof(git_command) - len,\n+\t\t\t\t\"/git-%s\", argv[0]);\n+\n+\t\tif (sizeof(git_command) <= len) {\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"git: command name given is too long.\\n\");\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* argv[0] must be the git command, but the argv array\n+\t\t * belongs to the caller, and my be reused in\n+\t\t * subsequent loop iterations. Save argv[0] and\n+\t\t * restore it on error.\n+\t\t */\n+\n+\t\ttmp = argv[0];\n+\t\targv[0] = git_command;\n+\n+\t\t/* execve() can only ever return if it fails */\n+\t\texecve(git_command, argv, environ);\n+\n+\t\terr = errno;\n+\n+\t\targv[0] = tmp;\n+\t}\n+\treturn -1;\n+\n+}\n+\n+\n+int execl_git_cmd(char *cmd,...)\n+{\n+\tint argc;\n+\tchar *argv[MAX_ARGS + 1];\n+\tchar *arg;\n+\tva_list param;\n+\n+\tva_start(param, cmd);\n+\targv[0] = cmd;\n+\targc = 1;\n+\twhile (argc < MAX_ARGS) {\n+\t\targ = argv[argc++] = va_arg(param, char *);\n+\t\tif (!arg)\n+\t\t\tbreak;\n+\t}\n+\tva_end(param);\n+\tif (MAX_ARGS <= argc)\n+\t\treturn error(\"too many args to run %s\", cmd);\n+\n+\targv[argc] = NULL;\n+\treturn execv_git_cmd(argv);\n+}\ndiff --git a/exec_cmd.h b/exec_cmd.h\nnew file mode 100644\nindex 0000000..06d5ec3\n--- /dev/null\n+++ b/exec_cmd.h\n@@ -0,0 +1,10 @@\n+#ifndef __GIT_EXEC_CMD_H_\n+#define __GIT_EXEC_CMD_H_\n+\n+extern void git_set_exec_path(const char *exec_path);\n+extern const char* git_exec_path();\n+extern int execv_git_cmd(char **argv); /* NULL terminated */\n+extern int execl_git_cmd(char *cmd, ...);\n+\n+\n+#endif /* __GIT_EXEC_CMD_H_ */\ndiff --git a/fetch-clone.c b/fetch-clone.c\nindex f46fe6e..859f400 100644\n--- a/fetch-clone.c\n+++ b/fetch-clone.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"exec_cmd.h\"\n #include <sys/wait.h>\n \n static int finish_pack(const char *pack_tmp_name, const char *me)\n@@ -27,8 +28,7 @@ static int finish_pack(const char *pack_\n \t\tdup2(pipe_fd[1], 1);\n \t\tclose(pipe_fd[0]);\n \t\tclose(pipe_fd[1]);\n-\t\texeclp(\"git-index-pack\",\"git-index-pack\",\n-\t\t       \"-o\", idx, pack_tmp_name, NULL);\n+\t\texecl_git_cmd(\"index-pack\", \"-o\", idx, pack_tmp_name, NULL);\n \t\terror(\"cannot exec git-index-pack <%s> <%s>\",\n \t\t      idx, pack_tmp_name);\n \t\texit(1);\n@@ -105,8 +105,7 @@ int receive_unpack_pack(int fd[2], const\n \t\tdup2(fd[0], 0);\n \t\tclose(fd[0]);\n \t\tclose(fd[1]);\n-\t\texeclp(\"git-unpack-objects\", \"git-unpack-objects\",\n-\t\t       quiet ? \"-q\" : NULL, NULL);\n+\t\texecl_git_cmd(\"unpack-objects\", quiet ? \"-q\" : NULL, NULL);\n \t\tdie(\"git-unpack-objects exec failed\");\n \t}\n \tclose(fd[0]);\ndiff --git a/git.c b/git.c\nindex 5e7da74..fdd02ed 100644\n--- a/git.c\n+++ b/git.c\n@@ -10,6 +10,7 @@\n #include <stdarg.h>\n #include <sys/ioctl.h>\n #include \"git-compat-util.h\"\n+#include \"exec_cmd.h\"\n \n #ifndef PATH_MAX\n # define PATH_MAX 4096\n@@ -233,14 +234,11 @@ int main(int argc, char **argv, char **e\n {\n \tchar git_command[PATH_MAX + 1];\n \tchar wd[PATH_MAX + 1];\n-\tint i, len, show_help = 0;\n-\tchar *exec_path = getenv(\"GIT_EXEC_PATH\");\n+\tint i, show_help = 0;\n+\tchar *exec_path;\n \n \tgetcwd(wd, PATH_MAX);\n \n-\tif (!exec_path)\n-\t\texec_path = GIT_EXEC_PATH;\n-\n \tfor (i = 1; i < argc; i++) {\n \t\tchar *arg = argv[i];\n \n@@ -256,10 +254,11 @@ int main(int argc, char **argv, char **e\n \n \t\tif (!strncmp(arg, \"exec-path\", 9)) {\n \t\t\targ += 9;\n-\t\t\tif (*arg == '=')\n+\t\t\tif (*arg == '=') {\n \t\t\t\texec_path = arg + 1;\n-\t\t\telse {\n-\t\t\t\tputs(exec_path);\n+\t\t\t\tgit_set_exec_path(exec_path);\n+\t\t\t} else {\n+\t\t\t\tputs(git_exec_path());\n \t\t\t\texit(0);\n \t\t\t}\n \t\t}\n@@ -275,48 +274,21 @@ int main(int argc, char **argv, char **e\n \n \tif (i >= argc || show_help) {\n \t\tif (i >= argc)\n-\t\t\tcmd_usage(exec_path, NULL);\n+\t\t\tcmd_usage(git_exec_path(), NULL);\n \n \t\tshow_man_page(argv[i]);\n \t}\n \n-\tif (*exec_path != '/') {\n-\t\tif (!getcwd(git_command, sizeof(git_command))) {\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"git: cannot determine current directory\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\tlen = strlen(git_command);\n+\texec_path = git_exec_path();\n+\tprepend_to_path(exec_path, strlen(exec_path));\n \n-\t\t/* Trivial cleanup */\n-\t\twhile (!strncmp(exec_path, \"./\", 2)) {\n-\t\t\texec_path += 2;\n-\t\t\twhile (*exec_path == '/')\n-\t\t\t\texec_path++;\n-\t\t}\n-\t\tsnprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t \"/%s\", exec_path);\n-\t}\n-\telse\n-\t\tstrcpy(git_command, exec_path);\n-\tlen = strlen(git_command);\n-\tprepend_to_path(git_command, len);\n-\n-\tlen += snprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t\"/git-%s\", argv[i]);\n-\tif (sizeof(git_command) <= len) {\n-\t\tfprintf(stderr, \"git: command name given is too long.\\n\");\n-\t\texit(1);\n-\t}\n-\n-\t/* execve() can only ever return if it fails */\n-\texecve(git_command, &argv[i], envp);\n+\texecv_git_cmd(argv + i);\n \n \tif (errno == ENOENT)\n-\t\tcmd_usage(exec_path, \"'%s' is not a git-command\", argv[i]);\n+\t\tcmd_usage(git_exec_path(), \"'%s' is not a git-command\",\n+\t\t\t  argv[i]);\n \n \tfprintf(stderr, \"Failed to run command '%s': %s\\n\",\n \t\tgit_command, strerror(errno));\n-\n \treturn 1;\n }\ndiff --git a/receive-pack.c b/receive-pack.c\nindex f847ec2..8e78e32 100644\n--- a/receive-pack.c\n+++ b/receive-pack.c\n@@ -257,7 +257,7 @@ static void read_head_info(void)\n \n static const char *unpack(int *error_code)\n {\n-\tint code = run_command(unpacker, NULL);\n+\tint code = run_command_v_opt(1, &unpacker, RUN_GIT_CMD);\n \n \t*error_code = 0;\n \tswitch (code) {\ndiff --git a/run-command.c b/run-command.c\nindex 8bf5922..b3d287e 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"run-command.h\"\n #include <sys/wait.h>\n+#include \"exec_cmd.h\"\n \n int run_command_v_opt(int argc, char **argv, int flags)\n {\n@@ -13,9 +14,13 @@ int run_command_v_opt(int argc, char **a\n \t\t\tint fd = open(\"/dev/null\", O_RDWR);\n \t\t\tdup2(fd, 0);\n \t\t\tdup2(fd, 1);\n-\t\t\tclose(fd);\t\t\t\n+\t\t\tclose(fd);\n+\t\t}\n+\t\tif (flags & RUN_GIT_CMD) {\n+\t\t\texecv_git_cmd(argv);\n+\t\t} else {\n+\t\t\texecvp(argv[0], (char *const*) argv);\n \t\t}\n-\t\texecvp(argv[0], (char *const*) argv);\n \t\tdie(\"exec %s failed.\", argv[0]);\n \t}\n \tfor (;;) {\ndiff --git a/run-command.h b/run-command.h\nindex 2469eea..ef3ee05 100644\n--- a/run-command.h\n+++ b/run-command.h\n@@ -12,7 +12,7 @@ enum {\n };\n \n #define RUN_COMMAND_NO_STDIO 1\n-\n+#define RUN_GIT_CMD\t     2\t/*If this is to be git sub-command */\n int run_command_v_opt(int argc, char **argv, int opt);\n int run_command_v(int argc, char **argv);\n int run_command(const char *cmd, ...);\ndiff --git a/send-pack.c b/send-pack.c\nindex cd36193..4a420a6 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -26,11 +26,11 @@ static int is_zero_sha1(const unsigned c\n static void exec_pack_objects(void)\n {\n \tstatic char *args[] = {\n-\t\t\"git-pack-objects\",\n+\t\t\"pack-objects\",\n \t\t\"--stdout\",\n \t\tNULL\n \t};\n-\texecvp(\"git-pack-objects\", args);\n+\texecv_git_cmd(args);\n \tdie(\"git-pack-objects exec failed (%s)\", strerror(errno));\n }\n \n@@ -39,7 +39,7 @@ static void exec_rev_list(struct ref *re\n \tstatic char *args[1000];\n \tint i = 0;\n \n-\targs[i++] = \"git-rev-list\";\t/* 0 */\n+\targs[i++] = \"rev-list\";\t/* 0 */\n \targs[i++] = \"--objects\";\t/* 1 */\n \twhile (refs) {\n \t\tchar *buf = malloc(100);\n@@ -58,7 +58,7 @@ static void exec_rev_list(struct ref *re\n \t\trefs = refs->next;\n \t}\n \targs[i] = NULL;\n-\texecvp(\"git-rev-list\", args);\n+\texecv_git_cmd(args);\n \tdie(\"git-rev-list exec failed (%s)\", strerror(errno));\n }\n \ndiff --git a/shell.c b/shell.c\nindex cd31618..0d4891f 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -12,7 +12,7 @@ static int do_generic_cmd(const char *me\n \tmy_argv[1] = arg;\n \tmy_argv[2] = NULL;\n \n-\treturn execvp(me, (char**) my_argv);\n+\treturn execv_git_cmd((char**) my_argv);\n }\n \n static struct commands {\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 1834b6b..d198055 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -4,6 +4,7 @@\n #include \"tag.h\"\n #include \"object.h\"\n #include \"commit.h\"\n+#include \"exec_cmd.h\"\n \n static const char upload_pack_usage[] = \"git-upload-pack [--strict]\n[--timeout=nn] <dir>\";\n \n@@ -60,7 +61,7 @@ static void create_pack_file(void)\n \t\tclose(0);\n \t\tclose(fd[0]);\n \t\tclose(fd[1]);\n-\t\t*p++ = \"git-rev-list\";\n+\t\t*p++ = \"rev-list\";\n \t\t*p++ = \"--objects\";\n \t\tif (create_full_pack || MAX_NEEDS <= nr_needs)\n \t\t\t*p++ = \"--all\";\n@@ -79,13 +80,13 @@ static void create_pack_file(void)\n \t\t\t\tbuf += 41;\n \t\t\t}\n \t\t*p++ = NULL;\n-\t\texecvp(\"git-rev-list\", argv);\n+\t\texecv_git_cmd(argv);\n \t\tdie(\"git-upload-pack: unable to exec git-rev-list\");\n \t}\n \tdup2(fd[0], 0);\n \tclose(fd[0]);\n \tclose(fd[1]);\n-\texeclp(\"git-pack-objects\", \"git-pack-objects\", \"--stdout\", NULL);\n+\texecl_git_cmd(\"pack-objects\", \"--stdout\", NULL);\n \tdie(\"git-upload-pack: unable to exec git-pack-objects\");\n }\n \n-- \n0.99.9m-g5a22\n"},{"id":"14467","messageId":"7v4q4bwavi.fsf@assigned-by-dhcp.cox.net","threadId":"3025","inReplyTo":"1136945538.11717.643.camel@brick.watson.ibm.com","subject":"Re: [PATCH] Exec git programs without using PATH.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-11T06:13:05Z","receivedAt":"2006-01-11T06:13:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michal Ostrowski <mostrows@watson.ibm.com> writes:\n\n>  exec_cmd.c     |  118\n> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\nThis is a giveaway sign that your MUA is wrapping lines, so\nplease double-check before sending things out next time around.\n\nIt seems yours is not as bad as others I've seen; I could manage\nto trivially hand-edit to make it appliable (although I am\ninclined to ask you to polish it a bit further).\n\n> +ifneq ($(shell cat .exec_cmd.gitexecdir 2>/dev/null),$(gitexecdir))\n> +.PHONY: exec_cmd.c\n> +$(shell echo $(gitexecdir) > .exec_cmd.gitexecdir)\n> +endif\n\nAlthough this check is much better than the last round, I changed\nmy mind about this part.  We do not do the equivalent checks and\nrebuild when somebody once builds with NO_OPENSSL and then tries\nto rebuild without, or for any other compile time configuration\n(template_dir, for example).  Ideally we _could_ keep track of\nall of them but I suspect that would be an overkill, so I am\ninclined to drop this part.\n\nWe need to make sure that we clean .exec_cmd.gitexecdir on the\nclean: target in the Makefile, if we _were_ to keep this, OTOH.\n\n> +exec_cmd.o: CFLAGS+=-DGIT_EXEC_PATH=\\\"$(gitexecdir)\\\"\n\nPlease do not override CFLAGS like this; it breaks this common\nusage:\n\n\t$ make CFLAGS='-g -O1' exec_cmd.o\n\n> diff --git a/exec_cmd.c b/exec_cmd.c\n> +void git_set_exec_path(const char *exec_path)\n> +{\n> +\tcurrent_exec_path = exec_path;\n> +}\n\nI've always wondered what we should do when --exec-path is given\nmore than once, but you decided it for me.  I agree that\nsilently overwriting is just fine.\n\n> +\tconst char *paths[] = { current_exec_path,\n> +\t\t\t\tgetenv(\"GIT_EXEC_PATH\"),\n> +\t\t\t\tbuiltin_exec_path,\n> +\t\t\t\tNULL };\n\nI do not think you need the last NULL element in paths[] here,\ngiven what the loop that uses this array does.\n\n> +\tfor (i = 0; i < 4; ++i) {\n\nIf your paths[] is fixed size, please do this instead:\n\n\tfor (i = 0; sizeof(paths)/sizeof(paths[0]); i++)\n\nThen I do not have to remember that I need to update \"4\" when I\nupdate paths[].\n\n> diff --git a/exec_cmd.h b/exec_cmd.h\n\n> +extern const char* git_exec_path();\n\nANSI C please: extern const char* git_exec_path(void);\n\n> diff --git a/git.c b/git.c\n\n>  \tif (errno == ENOENT)\n> -\t\tcmd_usage(exec_path, \"'%s' is not a git-command\", argv[i]);\n> +\t\tcmd_usage(git_exec_path(), \"'%s' is not a git-command\",\n> +\t\t\t  argv[i]);\n\nYou have assigned to exec_path before the failed execv_git_cmd()\nalready; I think change in this line is unneeded.\n\n> diff --git a/receive-pack.c b/receive-pack.c\n> index f847ec2..8e78e32 100644\n> --- a/receive-pack.c\n> +++ b/receive-pack.c\n> @@ -257,7 +257,7 @@ static void read_head_info(void)\n>  \n>  static const char *unpack(int *error_code)\n>  {\n> -\tint code = run_command(unpacker, NULL);\n> +\tint code = run_command_v_opt(1, &unpacker, RUN_GIT_CMD);\n\nThis one is questionable; run_command_v_opt() calls\nexecv_git_cmd() which expects the second argument of\nrun_command_v_opt() to be NULL terminated, doesn't it?\n\n> diff --git a/shell.c b/shell.c\n> index cd31618..0d4891f 100644\n> --- a/shell.c\n> +++ b/shell.c\n> @@ -12,7 +12,7 @@ static int do_generic_cmd(const char *me\n>  \tmy_argv[1] = arg;\n>  \tmy_argv[2] = NULL;\n>  \n> -\treturn execvp(me, (char**) my_argv);\n> +\treturn execv_git_cmd((char**) my_argv);\n>  }\n\nHere my_argv comes from cmd_list[] which has \"git-\" prefix to\ntheir command name, but I thought your exec[vl]_git_cmd() took\ncommand names without.\n\nHere is my suggestion on top of your patch, summarizing all of\nthe above comments.\n\n-- >8 --\n\ndiff --git a/Makefile b/Makefile\nindex e7c7763..6694627 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -185,16 +185,6 @@ LIB_OBJS = \\\n LIBS = $(LIB_FILE)\n LIBS += -lz\n \n-\n-# .exec_cmd.gitexecdir stores $(gitexecir) used to compile exec_cmd.o\n-# If it has changed, store the new value and force exec_cmd.o to be rebuilt\n-ifneq ($(shell cat .exec_cmd.gitexecdir 2>/dev/null),$(gitexecdir))\n-.PHONY: exec_cmd.c\n-$(shell echo $(gitexecdir) > .exec_cmd.gitexecdir)\n-endif\n-\n-exec_cmd.o: CFLAGS+=-DGIT_EXEC_PATH=\\\"$(gitexecdir)\\\"\n-\n # Shell quote;\n # Result of this needs to be placed inside ''\n shq = $(subst ','\\'',$(1))\n@@ -423,6 +413,8 @@ git$X git.spec \\\n %.o: %.S\n \t$(CC) -o $*.o -c $(ALL_CFLAGS) $<\n \n+exec_cmd.o: ALL_CFLAGS += -DGIT_EXEC_PATH=\\\"$(gitexecdir)\\\"\n+\n git-%$X: %.o $(LIB_FILE)\n \t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \ndiff --git a/exec_cmd.c b/exec_cmd.c\nindex a3bd40a..55af33b 100644\n--- a/exec_cmd.c\n+++ b/exec_cmd.c\n@@ -36,10 +36,9 @@ int execv_git_cmd(char **argv)\n \tint len, err, i;\n \tconst char *paths[] = { current_exec_path,\n \t\t\t\tgetenv(\"GIT_EXEC_PATH\"),\n-\t\t\t\tbuiltin_exec_path,\n-\t\t\t\tNULL };\n+\t\t\t\tbuiltin_exec_path };\n \n-\tfor (i = 0; i < 4; ++i) {\n+\tfor (i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) {\n \t\tconst char *exec_dir = paths[i];\n \t\tif (!exec_dir) continue;\n \ndiff --git a/exec_cmd.h b/exec_cmd.h\nindex 06d5ec3..5150ee2 100644\n--- a/exec_cmd.h\n+++ b/exec_cmd.h\n@@ -2,7 +2,7 @@\n #define __GIT_EXEC_CMD_H_\n \n extern void git_set_exec_path(const char *exec_path);\n-extern const char* git_exec_path();\n+extern const char* git_exec_path(void);\n extern int execv_git_cmd(char **argv); /* NULL terminated */\n extern int execl_git_cmd(char *cmd, ...);\n \ndiff --git a/git.c b/git.c\nindex fdd02ed..e3a0b59 100644\n--- a/git.c\n+++ b/git.c\n@@ -285,10 +285,10 @@ int main(int argc, char **argv, char **e\n \texecv_git_cmd(argv + i);\n \n \tif (errno == ENOENT)\n-\t\tcmd_usage(git_exec_path(), \"'%s' is not a git-command\",\n-\t\t\t  argv[i]);\n+\t\tcmd_usage(exec_path, \"'%s' is not a git-command\", argv[i]);\n \n \tfprintf(stderr, \"Failed to run command '%s': %s\\n\",\n \t\tgit_command, strerror(errno));\n+\n \treturn 1;\n }\ndiff --git a/receive-pack.c b/receive-pack.c\nindex 8e78e32..6120dbe 100644\n--- a/receive-pack.c\n+++ b/receive-pack.c\n@@ -6,7 +6,7 @@\n \n static const char receive_pack_usage[] = \"git-receive-pack <git-dir>\";\n \n-static const char unpacker[] = \"git-unpack-objects\";\n+static char *unpacker[] = { \"git-unpack-objects\", NULL };\n \n static int report_status = 0;\n \n@@ -257,7 +257,7 @@ static void read_head_info(void)\n \n static const char *unpack(int *error_code)\n {\n-\tint code = run_command_v_opt(1, &unpacker, RUN_GIT_CMD);\n+\tint code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);\n \n \t*error_code = 0;\n \tswitch (code) {\ndiff --git a/shell.c b/shell.c\nindex 0d4891f..d40dfe4 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -7,8 +7,10 @@ static int do_generic_cmd(const char *me\n \n \tif (!arg || !(arg = sq_dequote(arg)))\n \t\tdie(\"bad argument\");\n+\tif (strncmp(me, \"git-\", 4))\n+\t\tdie(\"bad command\");\n \n-\tmy_argv[0] = me;\n+\tmy_argv[0] = me + 4;\n \tmy_argv[1] = arg;\n \tmy_argv[2] = NULL;\n \n"},{"id":"14471","messageId":"43C4F292.7010404@op5.se","threadId":"3025","inReplyTo":"7v8xtn4m59.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-01-11T11:57:06Z","receivedAt":"2006-01-11T11:57:06Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> \n> True, but *please* stop calling \"git wrapper\" a potty.  It gives\n> me an impression that it is not connected to the plumbing.\n> \n\nAww... And here I was being quite pleased with this wording in the man-page:\n\n\"The program git is just a wrapper to reach the core git programs (or  a \npotty if  you like, as it's not exactly porcelain but still brings your \nstuff to the plumbing).\"\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"14477","messageId":"1136999157.11717.658.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"7v4q4bwavi.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] (Updated) Exec git programs without using PATH.","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-11T17:05:56Z","receivedAt":"2006-01-11T17:05:56Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"\n\nThe git suite may not be in PATH (and thus programs such as\ngit-send-pack could not exec git-rev-list).  Thus there is a need for\nlogic that will locate these programs.  Modifying PATH is not\ndesirable as it result in behavior differing from the user's\nintentions, as we may end up prepending \"/usr/bin\" to PATH.\n\n- git C programs will use exec*_git_cmd() APIs to exec sub-commands.\n- exec*_git_cmd() will execute a git program by searching for it in\n  the following directories:\n\t1. --exec-path (as used by \"git\")\n\t2. The GIT_EXEC_PATH environment variable.\n\t3. $(gitexecdir) as set in Makefile (default value $(bindir)).\n- all exec's of git programs will use exec*_git_cmd() interfaces,\n- C programs will not modify PATH\n\nIf the git suite is not in PATH, C programs will function, but there\nis no guarantee that shell scripts will, as shell scripts may invoke\n\"git-foo\" rather than \"git foo\".  Shell scripts that are modified to\nuse the git potty should become independent of PATH.\n\nIncludes modifications by Junio C Hamano <junkio@cox.net>.\n\nSigned-off-by: Michal Ostrowski <mostrows@watson.ibm.com>\n\n---\n\n Makefile       |   13 ++++--\n daemon.c       |    3 +\n exec_cmd.c     |  117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n exec_cmd.h     |   10 +++++\n fetch-clone.c  |    7 +--\n git.c          |   50 +++++-------------------\n receive-pack.c |    4 +-\n run-command.c  |    9 +++-\n run-command.h  |    2 -\n send-pack.c    |    8 ++--\n shell.c        |    6 ++-\n upload-pack.c  |    7 ++-\n 12 files changed, 174 insertions(+), 62 deletions(-)\n create mode 100644 exec_cmd.c\n create mode 100644 exec_cmd.h\n\n565e290d6e7f24bd4e72ca7494297230799d118a\ndiff --git a/Makefile b/Makefile\nindex c9c15b5..abcb771 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -68,6 +68,7 @@ ALL_LDFLAGS = $(LDFLAGS)\n \n prefix = $(HOME)\n bindir = $(prefix)/bin\n+gitexecdir = $(prefix)/bin\n template_dir = $(prefix)/share/git-core/templates/\n GIT_PYTHON_DIR = $(prefix)/share/git-core/python\n # DESTDIR=\n@@ -141,7 +142,7 @@ PROGRAMS = \\\n \tgit-describe$X\n \n # what 'all' will build and 'install' will install.\n-ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X\n+ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)\n \n # Backward compatibility -- to be removed after 1.0\n PROGRAMS += git-ssh-pull$X git-ssh-push$X\n@@ -173,7 +174,7 @@ DIFF_OBJS = \\\n \n LIB_OBJS = \\\n \tblob.o commit.o connect.o count-delta.o csum-file.o \\\n-\tdate.o diff-delta.o entry.o ident.o index.o \\\n+\tdate.o diff-delta.o entry.o exec_cmd.o ident.o index.o \\\n \tobject.o pack-check.o patch-delta.o path.o pkt-line.o \\\n \tquote.o read-cache.o refs.o run-command.o \\\n \tserver-info.o setup.o sha1_file.o sha1_name.o strbuf.o \\\n@@ -366,13 +367,13 @@ LIB_OBJS += $(COMPAT_OBJS)\n export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir\n ### Build rules\n \n-all: $(ALL_PROGRAMS)\n+all: $(ALL_PROGRAMS) git$X\n \n all:\n \t$(MAKE) -C templates\n \n git$X: git.c $(LIB_FILE)\n-\t$(CC) -DGIT_EXEC_PATH='\"$(bindir)\"' -DGIT_VERSION='\"$(GIT_VERSION)\"' \\\n+\t$(CC) -DGIT_VERSION='\"$(GIT_VERSION)\"' \\\n \t\t$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)\n \n $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh\n@@ -412,6 +413,8 @@ git$X git.spec \\\n %.o: %.S\n \t$(CC) -o $*.o -c $(ALL_CFLAGS) $<\n \n+exec_cmd.o: ALL_CFLAGS += -DGIT_EXEC_PATH=\\\"$(gitexecdir)\\\"\n+\n git-%$X: %.o $(LIB_FILE)\n \t$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n@@ -468,7 +471,9 @@ check:\n \n install: all\n \t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))\n+\t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(gitexecdir))\n \t$(INSTALL) $(ALL_PROGRAMS) $(call shellquote,$(DESTDIR)$(bindir))\n+\t$(INSTALL) git$X $(call shellquote,$(DESTDIR)$(gitexecdir))\n \t$(MAKE) -C templates install\n \t$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))\n \t$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))\ndiff --git a/daemon.c b/daemon.c\nindex 3bd1426..bb014fa 100644\n--- a/daemon.c\n+++ b/daemon.c\n@@ -9,6 +9,7 @@\n #include <syslog.h>\n #include \"pkt-line.h\"\n #include \"cache.h\"\n+#include \"exec_cmd.h\"\n \n static int log_syslog;\n static int verbose;\n@@ -227,7 +228,7 @@ static int upload(char *dir)\n \tsnprintf(timeout_buf, sizeof timeout_buf, \"--timeout=%u\", timeout);\n \n \t/* git-upload-pack only ever reads stuff, so this is safe */\n-\texeclp(\"git-upload-pack\", \"git-upload-pack\", \"--strict\", timeout_buf, \".\", NULL);\n+\texecl_git_cmd(\"upload-pack\", \"--strict\", timeout_buf, \".\", NULL);\n \treturn -1;\n }\n \ndiff --git a/exec_cmd.c b/exec_cmd.c\nnew file mode 100644\nindex 0000000..55af33b\n--- /dev/null\n+++ b/exec_cmd.c\n@@ -0,0 +1,117 @@\n+#include \"cache.h\"\n+#include \"exec_cmd.h\"\n+#define MAX_ARGS\t32\n+\n+extern char **environ;\n+static const char *builtin_exec_path = GIT_EXEC_PATH;\n+static const char *current_exec_path = NULL;\n+\n+void git_set_exec_path(const char *exec_path)\n+{\n+\tcurrent_exec_path = exec_path;\n+}\n+\n+\n+/* Returns the highest-priority, location to look for git programs. */\n+const char *git_exec_path()\n+{\n+\tconst char *env;\n+\n+\tif (current_exec_path)\n+\t\treturn current_exec_path;\n+\n+\tenv = getenv(\"GIT_EXEC_PATH\");\n+\tif (env) {\n+\t\treturn env;\n+\t}\n+\n+\treturn builtin_exec_path;\n+}\n+\n+\n+int execv_git_cmd(char **argv)\n+{\n+\tchar git_command[PATH_MAX + 1];\n+\tchar *tmp;\n+\tint len, err, i;\n+\tconst char *paths[] = { current_exec_path,\n+\t\t\t\tgetenv(\"GIT_EXEC_PATH\"),\n+\t\t\t\tbuiltin_exec_path };\n+\n+\tfor (i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) {\n+\t\tconst char *exec_dir = paths[i];\n+\t\tif (!exec_dir) continue;\n+\n+\t\tif (*exec_dir != '/') {\n+\t\t\tif (!getcwd(git_command, sizeof(git_command))) {\n+\t\t\t\tfprintf(stderr, \"git: cannot determine \"\n+\t\t\t\t\t\"current directory\\n\");\n+\t\t\t\texit(1);\n+\t\t\t}\n+\t\t\tlen = strlen(git_command);\n+\n+\t\t\t/* Trivial cleanup */\n+\t\t\twhile (!strncmp(exec_dir, \"./\", 2)) {\n+\t\t\t\texec_dir += 2;\n+\t\t\t\twhile (*exec_dir == '/')\n+\t\t\t\t\texec_dir++;\n+\t\t\t}\n+\t\t\tsnprintf(git_command + len, sizeof(git_command) - len,\n+\t\t\t\t \"/%s\", exec_dir);\n+\t\t} else {\n+\t\t\tstrcpy(git_command, exec_dir);\n+\t\t}\n+\n+\t\tlen = strlen(git_command);\n+\t\tlen += snprintf(git_command + len, sizeof(git_command) - len,\n+\t\t\t\t\"/git-%s\", argv[0]);\n+\n+\t\tif (sizeof(git_command) <= len) {\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"git: command name given is too long.\\n\");\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* argv[0] must be the git command, but the argv array\n+\t\t * belongs to the caller, and my be reused in\n+\t\t * subsequent loop iterations. Save argv[0] and\n+\t\t * restore it on error.\n+\t\t */\n+\n+\t\ttmp = argv[0];\n+\t\targv[0] = git_command;\n+\n+\t\t/* execve() can only ever return if it fails */\n+\t\texecve(git_command, argv, environ);\n+\n+\t\terr = errno;\n+\n+\t\targv[0] = tmp;\n+\t}\n+\treturn -1;\n+\n+}\n+\n+\n+int execl_git_cmd(char *cmd,...)\n+{\n+\tint argc;\n+\tchar *argv[MAX_ARGS + 1];\n+\tchar *arg;\n+\tva_list param;\n+\n+\tva_start(param, cmd);\n+\targv[0] = cmd;\n+\targc = 1;\n+\twhile (argc < MAX_ARGS) {\n+\t\targ = argv[argc++] = va_arg(param, char *);\n+\t\tif (!arg)\n+\t\t\tbreak;\n+\t}\n+\tva_end(param);\n+\tif (MAX_ARGS <= argc)\n+\t\treturn error(\"too many args to run %s\", cmd);\n+\n+\targv[argc] = NULL;\n+\treturn execv_git_cmd(argv);\n+}\ndiff --git a/exec_cmd.h b/exec_cmd.h\nnew file mode 100644\nindex 0000000..5150ee2\n--- /dev/null\n+++ b/exec_cmd.h\n@@ -0,0 +1,10 @@\n+#ifndef __GIT_EXEC_CMD_H_\n+#define __GIT_EXEC_CMD_H_\n+\n+extern void git_set_exec_path(const char *exec_path);\n+extern const char* git_exec_path(void);\n+extern int execv_git_cmd(char **argv); /* NULL terminated */\n+extern int execl_git_cmd(char *cmd, ...);\n+\n+\n+#endif /* __GIT_EXEC_CMD_H_ */\ndiff --git a/fetch-clone.c b/fetch-clone.c\nindex f46fe6e..859f400 100644\n--- a/fetch-clone.c\n+++ b/fetch-clone.c\n@@ -1,4 +1,5 @@\n #include \"cache.h\"\n+#include \"exec_cmd.h\"\n #include <sys/wait.h>\n \n static int finish_pack(const char *pack_tmp_name, const char *me)\n@@ -27,8 +28,7 @@ static int finish_pack(const char *pack_\n \t\tdup2(pipe_fd[1], 1);\n \t\tclose(pipe_fd[0]);\n \t\tclose(pipe_fd[1]);\n-\t\texeclp(\"git-index-pack\",\"git-index-pack\",\n-\t\t       \"-o\", idx, pack_tmp_name, NULL);\n+\t\texecl_git_cmd(\"index-pack\", \"-o\", idx, pack_tmp_name, NULL);\n \t\terror(\"cannot exec git-index-pack <%s> <%s>\",\n \t\t      idx, pack_tmp_name);\n \t\texit(1);\n@@ -105,8 +105,7 @@ int receive_unpack_pack(int fd[2], const\n \t\tdup2(fd[0], 0);\n \t\tclose(fd[0]);\n \t\tclose(fd[1]);\n-\t\texeclp(\"git-unpack-objects\", \"git-unpack-objects\",\n-\t\t       quiet ? \"-q\" : NULL, NULL);\n+\t\texecl_git_cmd(\"unpack-objects\", quiet ? \"-q\" : NULL, NULL);\n \t\tdie(\"git-unpack-objects exec failed\");\n \t}\n \tclose(fd[0]);\ndiff --git a/git.c b/git.c\nindex 5e7da74..4616df6 100644\n--- a/git.c\n+++ b/git.c\n@@ -10,6 +10,7 @@\n #include <stdarg.h>\n #include <sys/ioctl.h>\n #include \"git-compat-util.h\"\n+#include \"exec_cmd.h\"\n \n #ifndef PATH_MAX\n # define PATH_MAX 4096\n@@ -233,14 +234,11 @@ int main(int argc, char **argv, char **e\n {\n \tchar git_command[PATH_MAX + 1];\n \tchar wd[PATH_MAX + 1];\n-\tint i, len, show_help = 0;\n-\tchar *exec_path = getenv(\"GIT_EXEC_PATH\");\n+\tint i, show_help = 0;\n+\tconst char *exec_path;\n \n \tgetcwd(wd, PATH_MAX);\n \n-\tif (!exec_path)\n-\t\texec_path = GIT_EXEC_PATH;\n-\n \tfor (i = 1; i < argc; i++) {\n \t\tchar *arg = argv[i];\n \n@@ -256,10 +254,11 @@ int main(int argc, char **argv, char **e\n \n \t\tif (!strncmp(arg, \"exec-path\", 9)) {\n \t\t\targ += 9;\n-\t\t\tif (*arg == '=')\n+\t\t\tif (*arg == '=') {\n \t\t\t\texec_path = arg + 1;\n-\t\t\telse {\n-\t\t\t\tputs(exec_path);\n+\t\t\t\tgit_set_exec_path(exec_path);\n+\t\t\t} else {\n+\t\t\t\tputs(git_exec_path());\n \t\t\t\texit(0);\n \t\t\t}\n \t\t}\n@@ -275,42 +274,15 @@ int main(int argc, char **argv, char **e\n \n \tif (i >= argc || show_help) {\n \t\tif (i >= argc)\n-\t\t\tcmd_usage(exec_path, NULL);\n+\t\t\tcmd_usage(git_exec_path(), NULL);\n \n \t\tshow_man_page(argv[i]);\n \t}\n \n-\tif (*exec_path != '/') {\n-\t\tif (!getcwd(git_command, sizeof(git_command))) {\n-\t\t\tfprintf(stderr,\n-\t\t\t\t\"git: cannot determine current directory\\n\");\n-\t\t\texit(1);\n-\t\t}\n-\t\tlen = strlen(git_command);\n-\n-\t\t/* Trivial cleanup */\n-\t\twhile (!strncmp(exec_path, \"./\", 2)) {\n-\t\t\texec_path += 2;\n-\t\t\twhile (*exec_path == '/')\n-\t\t\t\texec_path++;\n-\t\t}\n-\t\tsnprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t \"/%s\", exec_path);\n-\t}\n-\telse\n-\t\tstrcpy(git_command, exec_path);\n-\tlen = strlen(git_command);\n-\tprepend_to_path(git_command, len);\n-\n-\tlen += snprintf(git_command + len, sizeof(git_command) - len,\n-\t\t\t\"/git-%s\", argv[i]);\n-\tif (sizeof(git_command) <= len) {\n-\t\tfprintf(stderr, \"git: command name given is too long.\\n\");\n-\t\texit(1);\n-\t}\n+\texec_path = git_exec_path();\n+\tprepend_to_path(exec_path, strlen(exec_path));\n \n-\t/* execve() can only ever return if it fails */\n-\texecve(git_command, &argv[i], envp);\n+\texecv_git_cmd(argv + i);\n \n \tif (errno == ENOENT)\n \t\tcmd_usage(exec_path, \"'%s' is not a git-command\", argv[i]);\ndiff --git a/receive-pack.c b/receive-pack.c\nindex f847ec2..6120dbe 100644\n--- a/receive-pack.c\n+++ b/receive-pack.c\n@@ -6,7 +6,7 @@\n \n static const char receive_pack_usage[] = \"git-receive-pack <git-dir>\";\n \n-static const char unpacker[] = \"git-unpack-objects\";\n+static char *unpacker[] = { \"git-unpack-objects\", NULL };\n \n static int report_status = 0;\n \n@@ -257,7 +257,7 @@ static void read_head_info(void)\n \n static const char *unpack(int *error_code)\n {\n-\tint code = run_command(unpacker, NULL);\n+\tint code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);\n \n \t*error_code = 0;\n \tswitch (code) {\ndiff --git a/run-command.c b/run-command.c\nindex 8bf5922..b3d287e 100644\n--- a/run-command.c\n+++ b/run-command.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"run-command.h\"\n #include <sys/wait.h>\n+#include \"exec_cmd.h\"\n \n int run_command_v_opt(int argc, char **argv, int flags)\n {\n@@ -13,9 +14,13 @@ int run_command_v_opt(int argc, char **a\n \t\t\tint fd = open(\"/dev/null\", O_RDWR);\n \t\t\tdup2(fd, 0);\n \t\t\tdup2(fd, 1);\n-\t\t\tclose(fd);\t\t\t\n+\t\t\tclose(fd);\n+\t\t}\n+\t\tif (flags & RUN_GIT_CMD) {\n+\t\t\texecv_git_cmd(argv);\n+\t\t} else {\n+\t\t\texecvp(argv[0], (char *const*) argv);\n \t\t}\n-\t\texecvp(argv[0], (char *const*) argv);\n \t\tdie(\"exec %s failed.\", argv[0]);\n \t}\n \tfor (;;) {\ndiff --git a/run-command.h b/run-command.h\nindex 2469eea..ef3ee05 100644\n--- a/run-command.h\n+++ b/run-command.h\n@@ -12,7 +12,7 @@ enum {\n };\n \n #define RUN_COMMAND_NO_STDIO 1\n-\n+#define RUN_GIT_CMD\t     2\t/*If this is to be git sub-command */\n int run_command_v_opt(int argc, char **argv, int opt);\n int run_command_v(int argc, char **argv);\n int run_command(const char *cmd, ...);\ndiff --git a/send-pack.c b/send-pack.c\nindex cd36193..4a420a6 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -26,11 +26,11 @@ static int is_zero_sha1(const unsigned c\n static void exec_pack_objects(void)\n {\n \tstatic char *args[] = {\n-\t\t\"git-pack-objects\",\n+\t\t\"pack-objects\",\n \t\t\"--stdout\",\n \t\tNULL\n \t};\n-\texecvp(\"git-pack-objects\", args);\n+\texecv_git_cmd(args);\n \tdie(\"git-pack-objects exec failed (%s)\", strerror(errno));\n }\n \n@@ -39,7 +39,7 @@ static void exec_rev_list(struct ref *re\n \tstatic char *args[1000];\n \tint i = 0;\n \n-\targs[i++] = \"git-rev-list\";\t/* 0 */\n+\targs[i++] = \"rev-list\";\t/* 0 */\n \targs[i++] = \"--objects\";\t/* 1 */\n \twhile (refs) {\n \t\tchar *buf = malloc(100);\n@@ -58,7 +58,7 @@ static void exec_rev_list(struct ref *re\n \t\trefs = refs->next;\n \t}\n \targs[i] = NULL;\n-\texecvp(\"git-rev-list\", args);\n+\texecv_git_cmd(args);\n \tdie(\"git-rev-list exec failed (%s)\", strerror(errno));\n }\n \ndiff --git a/shell.c b/shell.c\nindex cd31618..d40dfe4 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -7,12 +7,14 @@ static int do_generic_cmd(const char *me\n \n \tif (!arg || !(arg = sq_dequote(arg)))\n \t\tdie(\"bad argument\");\n+\tif (strncmp(me, \"git-\", 4))\n+\t\tdie(\"bad command\");\n \n-\tmy_argv[0] = me;\n+\tmy_argv[0] = me + 4;\n \tmy_argv[1] = arg;\n \tmy_argv[2] = NULL;\n \n-\treturn execvp(me, (char**) my_argv);\n+\treturn execv_git_cmd((char**) my_argv);\n }\n \n static struct commands {\ndiff --git a/upload-pack.c b/upload-pack.c\nindex 1834b6b..d198055 100644\n--- a/upload-pack.c\n+++ b/upload-pack.c\n@@ -4,6 +4,7 @@\n #include \"tag.h\"\n #include \"object.h\"\n #include \"commit.h\"\n+#include \"exec_cmd.h\"\n \n static const char upload_pack_usage[] = \"git-upload-pack [--strict] [--timeout=nn] <dir>\";\n \n@@ -60,7 +61,7 @@ static void create_pack_file(void)\n \t\tclose(0);\n \t\tclose(fd[0]);\n \t\tclose(fd[1]);\n-\t\t*p++ = \"git-rev-list\";\n+\t\t*p++ = \"rev-list\";\n \t\t*p++ = \"--objects\";\n \t\tif (create_full_pack || MAX_NEEDS <= nr_needs)\n \t\t\t*p++ = \"--all\";\n@@ -79,13 +80,13 @@ static void create_pack_file(void)\n \t\t\t\tbuf += 41;\n \t\t\t}\n \t\t*p++ = NULL;\n-\t\texecvp(\"git-rev-list\", argv);\n+\t\texecv_git_cmd(argv);\n \t\tdie(\"git-upload-pack: unable to exec git-rev-list\");\n \t}\n \tdup2(fd[0], 0);\n \tclose(fd[0]);\n \tclose(fd[1]);\n-\texeclp(\"git-pack-objects\", \"git-pack-objects\", \"--stdout\", NULL);\n+\texecl_git_cmd(\"pack-objects\", \"--stdout\", NULL);\n \tdie(\"git-upload-pack: unable to exec git-pack-objects\");\n }\n \n-- \n0.99.9m-g5a22\n"},{"id":"14478","messageId":"1136999518.29751.233.camel@cashmere.sps.mot.com","threadId":"3025","inReplyTo":"43C4F292.7010404@op5.se","subject":"Re: [PATCH 2/2] Remember and use GIT_EXEC_PATH on exec()'s","fromName":"Jon Loeliger","fromEmail":"jdl@freescale.com","sentAt":"2006-01-11T17:11:58Z","receivedAt":"2006-01-11T17:11:58Z","isPatch":true,"sender":{"key":"jdl@jdl.com","avatar":"https://gravatar.com/avatar/75ce9a10b151acd2c28ec4ab2136dba7b2ff1634530bd04b155981a749d08a64?d=mp&s=160"},"body":"On Wed, 2006-01-11 at 05:57, Andreas Ericsson wrote:\n> Junio C Hamano wrote:\n> > \n> > True, but *please* stop calling \"git wrapper\" a potty.  It gives\n> > me an impression that it is not connected to the plumbing.\n> > \n> \n> Aww... And here I was being quite pleased with this wording in the man-page:\n> \n> \"The program git is just a wrapper to reach the core git programs (or  a \n> potty if  you like, as it's not exactly porcelain but still brings your \n> stuff to the plumbing).\"\n\nOh man.  So, do we have to go with \"kitchen sink\" instead? ;-)\n\njdl\n"},{"id":"14499","messageId":"7vek3esdw0.fsf@assigned-by-dhcp.cox.net","threadId":"3025","inReplyTo":"1136999157.11717.658.camel@brick.watson.ibm.com","subject":"Re: [PATCH] (Updated) Exec git programs without using PATH.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-11T20:33:51Z","receivedAt":"2006-01-11T20:33:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michal Ostrowski <mostrows@watson.ibm.com> writes:\n\n> The git suite may not be in PATH (and thus programs such as\n>...\n> Includes modifications by Junio C Hamano <junkio@cox.net>.\n\nThanks for the update (you did it even without line wrapping\nthis time).\n\nI made further fixes last night and it is in the proposed\nupdates (\"pu\") branch.  This branch is used to hold and showcase\nwhat I plan to eventually merge into the master branch, and\nconsists of the topic branches merged on top of what is in the\nmaster branch.  To disect to see what shape I munged your patch\ninto, please look at it with gitk or gitweb and find \"Merge\nbranch mo/exec\" commit (my topic branches are named after patch\nauthor and topic keyword).  The second parent of that commit is\nthe tip of the topic branch mo/exec when the merge was made.\n\nA word of caution to people on the list (not limited to Michal)\nis needed again, because it's been a while since I talked about\nthe proposed updates branch last time (which was pre 1.0.0\nrelease IIRC).\n\nThe \"pu\" branch is regularly rebuilt by merging private topic\nbranches on top of the then-current master branch, by doing\nthis:\n\n\t$ git checkout pu\n        $ git reset --hard master ;# build from scratch!\n        $ git pull . topic1\n        $ git pull . topic2\n        $ ...\n        $ git pull . topicN\n\nWhat this means is that you (not just Michal---\"people\") should\nnot base your development on top of \"pu\" branch proper, since\nyou will have a hard time updating and merging.  Disecting my\n\"pu\" branch to find the topic branch that corresponds to your\ntopic, and doing your development and patch preparation based on\nthat branch tip (and tell me that the patch is against your\ntopic branch, or \"pu\") is possible, but even that is not always\nan easy option, since I may occasionally have to rebase my topic\nbranches as well.  You can always send in an updated patch based\non my master, and I'll manage with three-way merge to pick out\nthe real changes since your last iteration.\n\nFor your (primarily Michal, but other interested parties as\nwell) reference, here is the diff between your patch in the\nmessage I am replying to and what I placed in the \"pu\" branch\nlast night.\n\n-- >8 --\nUpdates on top of comments last night.\n\n - git-unpack-objects are run via execv_git_cmd, so no \"git-\"\n   prefix should be given.\n\n - two more files need #include \"exec_cmd.h\".\n\n---\ndiff --git a/receive-pack.c b/receive-pack.c\nindex 6120dbe..eae31e3 100644\n--- a/receive-pack.c\n+++ b/receive-pack.c\n@@ -6,7 +6,7 @@\n \n static const char receive_pack_usage[] = \"git-receive-pack <git-dir>\";\n \n-static char *unpacker[] = { \"git-unpack-objects\", NULL };\n+static char *unpacker[] = { \"unpack-objects\", NULL };\n \n static int report_status = 0;\n \ndiff --git a/send-pack.c b/send-pack.c\nindex 4a420a6..990be3f 100644\n--- a/send-pack.c\n+++ b/send-pack.c\n@@ -3,6 +3,7 @@\n #include \"tag.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\n+#include \"exec_cmd.h\"\n \n static const char send_pack_usage[] =\n \"git-send-pack [--all] [--exec=git-receive-pack] <remote> [<head>...]\\n\"\ndiff --git a/shell.c b/shell.c\nindex d40dfe4..fc0c73c 100644\n--- a/shell.c\n+++ b/shell.c\n@@ -1,5 +1,6 @@\n #include \"cache.h\"\n #include \"quote.h\"\n+#include \"exec_cmd.h\"\n \n static int do_generic_cmd(const char *me, char *arg)\n {\n"},{"id":"14500","messageId":"Pine.LNX.4.64.0601111238550.5073@g5.osdl.org","threadId":"3025","inReplyTo":"7vek3esdw0.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] (Updated) Exec git programs without using PATH.","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-01-11T20:42:35Z","receivedAt":"2006-01-11T20:42:35Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 11 Jan 2006, Junio C Hamano wrote:\n> \n> For your (primarily Michal, but other interested parties as\n> well) reference, here is the diff between your patch in the\n> message I am replying to and what I placed in the \"pu\" branch\n> last night.\n\nTangentially related note: maybe we should try to move to a \"spawn()\" like \ninterface so that it could port better to native Windows interfaces?\n\nEven under Linux, using vfork()+exec() is actually faster than a regular \nfork/exec, so there are potential advantages.\n\nThe real advantage of fork+exec is how you can do arbitrary setup between \nthe two, without needing insanely complex rules for file descriptors etc. \nBut maybe we don't have tons of those issues?\n\n\t\tLinus\n"},{"id":"14504","messageId":"1137014812.11717.669.camel@brick.watson.ibm.com","threadId":"3025","inReplyTo":"Pine.LNX.4.64.0601111238550.5073@g5.osdl.org","subject":"Re: [PATCH] (Updated) Exec git programs without using PATH.","fromName":"Michal Ostrowski","fromEmail":"mostrows@watson.ibm.com","sentAt":"2006-01-11T21:26:52Z","receivedAt":"2006-01-11T21:26:52Z","isPatch":true,"sender":{"key":"mostrows@watson.ibm.com","avatar":null},"body":"On Wed, 2006-01-11 at 12:42 -0800, Linus Torvalds wrote:\n> \n> On Wed, 11 Jan 2006, Junio C Hamano wrote:\n> > \n> > For your (primarily Michal, but other interested parties as\n> > well) reference, here is the diff between your patch in the\n> > message I am replying to and what I placed in the \"pu\" branch\n> > last night.\n> \n> Tangentially related note: maybe we should try to move to a \"spawn()\" like \n> interface so that it could port better to native Windows interfaces?\n> \n> Even under Linux, using vfork()+exec() is actually faster than a regular \n> fork/exec, so there are potential advantages.\n> \n> The real advantage of fork+exec is how you can do arbitrary setup between \n> the two, without needing insanely complex rules for file descriptors etc. \n> But maybe we don't have tons of those issues?\n> \n\nI briefly tried to consider if I could hide the various fork()+exec()\nsequences behind something like the run_command*() interfaces (which\nwould move us down the direction of something \"spawn()\"-like).  I found\nthat there's a lot of variation between the various paths in terms of\nwhat happens between fork() and exec() on the various paths that does\nnot lend itself to such consolidation.\n\nI'd love to be convinced otherwise.\n\n-- \nMichal Ostrowski <mostrows@watson.ibm.com>\n"},{"id":"14505","messageId":"7vk6d6qwmn.fsf@assigned-by-dhcp.cox.net","threadId":"3025","inReplyTo":"1137014812.11717.669.camel@brick.watson.ibm.com","subject":"Re: [PATCH] (Updated) Exec git programs without using PATH.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-11T21:32:00Z","receivedAt":"2006-01-11T21:32:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Michal Ostrowski <mostrows@watson.ibm.com> writes:\n\n> I briefly tried to consider if I could hide the various fork()+exec()\n> sequences behind something like the run_command*() interfaces (which\n> would move us down the direction of something \"spawn()\"-like).  I found\n> that there's a lot of variation between the various paths in terms of\n> what happens between fork() and exec() on the various paths that does\n> not lend itself to such consolidation.\n>\n> I'd love to be convinced otherwise.\n\nUnfortunately I am with Michal on this one (both \"eh, I do not\nthink that is feasible\" and \"I'd love to be...\").\n\nThe run_command*() interfaces and its users were the best I\ncould come up with as far as such consolidations could go when I\ndid it.\n"},{"id":"14523","messageId":"43C59EC6.6070905@op5.se","threadId":"3025","inReplyTo":"7vk6d6qwmn.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] (Updated) Exec git programs without using PATH.","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-01-12T00:11:50Z","receivedAt":"2006-01-12T00:11:50Z","isPatch":true,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Michal Ostrowski <mostrows@watson.ibm.com> writes:\n> \n> \n>>I briefly tried to consider if I could hide the various fork()+exec()\n>>sequences behind something like the run_command*() interfaces (which\n>>would move us down the direction of something \"spawn()\"-like).  I found\n>>that there's a lot of variation between the various paths in terms of\n>>what happens between fork() and exec() on the various paths that does\n>>not lend itself to such consolidation.\n>>\n>>I'd love to be convinced otherwise.\n> \n> \n> Unfortunately I am with Michal on this one (both \"eh, I do not\n> think that is feasible\" and \"I'd love to be...\").\n> \n> The run_command*() interfaces and its users were the best I\n> could come up with as far as such consolidations could go when I\n> did it.\n> \n\nNot being entirely knowledgeable on what spawn() actually does and how \nits semantics differ from fork() and exec*() style API's (Google was \ndepressingly unhelpful and wikipedia dredged up froglings...), I've got \na decent \"clone-lots-of-processes-and-multiplex-between-them\" kind of \nlibrary lying around. Would it be of any use?\n\n From the prototypes I've seen on spawn it doesn't seem to be much more \nthan a fork() + execve(), either closing or dup2'ing all the \nfile-descriptors, so I don't understand why that couldn't be implemented \nfor git. Some pointers, anyone?\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"14533","messageId":"43C5EB5F.6000402@zytor.com","threadId":"3025","inReplyTo":"43C59EC6.6070905@op5.se","subject":"Re: [PATCH] (Updated) Exec git programs without using PATH.","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2006-01-12T05:38:39Z","receivedAt":"2006-01-12T05:38:39Z","isPatch":true,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Andreas Ericsson wrote:\n> \n> Not being entirely knowledgeable on what spawn() actually does and how \n> its semantics differ from fork() and exec*() style API's (Google was \n> depressingly unhelpful and wikipedia dredged up froglings...), I've got \n> a decent \"clone-lots-of-processes-and-multiplex-between-them\" kind of \n> library lying around. Would it be of any use?\n> \n>  From the prototypes I've seen on spawn it doesn't seem to be much more \n> than a fork() + execve(), either closing or dup2'ing all the \n> file-descriptors, so I don't understand why that couldn't be implemented \n> for git. Some pointers, anyone?\n> \n\nRTFM(posix_spawn)...\n\n\t-hpa\n"}]}