From fa7fbeb525b11c21a5caa2ee4d8a027405f2be6f Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:39:25 +0200 Subject: [PATCH 1/7] Windows: Add workaround for MSYS' path conversion MSYS' automatic path conversion causes problems when passing paths as defines ('-D' arguments to the compiler). MSYS tries to be smart and converts absolute paths to native Windows paths, e.g. if MSYS sees "/bin" it converts it to "c:/msysgit/bin". But we want completely unmodified paths; e.g. if we set bindir in the Makefile to "/bin", the define BINDIR shall expand to "/bin". Conversion to absolute Windows path will takes place later, during runtime. This commit adds a workaround by replacing "/" with its octal representation "\057", effectively hiding the path from MSYS' path conversion mechanism. MSYS does no longer see the absolute path and therefore leaves it alone. --- Makefile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 8d81095765..f716fda416 100644 --- a/Makefile +++ b/Makefile @@ -1049,6 +1049,12 @@ template_dir_SQ = $(subst ','\'',$(template_dir)) htmldir_SQ = $(subst ','\'',$(htmldir)) prefix_SQ = $(subst ','\'',$(prefix)) +ETC_GITCONFIG_SQ_C = $(subst /,\057,$(ETC_GITCONFIG_SQ)) +bindir_SQ_C = $(subst /,\057,$(bindir_SQ)) +gitexecdir_SQ_C = $(subst /,\057,$(gitexecdir_SQ)) +htmldir_SQ_C = $(subst /,\057,$(htmldir_SQ)) +template_dir_SQ_C = $(subst /,\057,$(template_dir_SQ)) + SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH)) @@ -1100,7 +1106,7 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS) help.o: help.c common-cmds.h GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ - '-DGIT_HTML_PATH="$(htmldir_SQ)"' \ + '-DGIT_HTML_PATH="$(htmldir_SQ_C)"' \ '-DGIT_MAN_PATH="$(mandir_SQ)"' \ '-DGIT_INFO_PATH="$(infodir_SQ)"' $< @@ -1207,12 +1213,12 @@ git.o git.spec \ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< exec_cmd.o: exec_cmd.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) '-DGIT_EXEC_PATH="$(gitexecdir_SQ_C)"' -DBINDIR='"$(bindir_SQ_C)"' $< builtin-init-db.o: builtin-init-db.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ_C)"' $< config.o: config.c GIT-CFLAGS - $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"' $< + $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ_C)"' $< http.o: http.c GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DGIT_USER_AGENT='"git/$(GIT_VERSION)"' $< From 7b6c6496374073d4519a035b5c2053395a60e014 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 10 Aug 2008 17:52:36 +0200 Subject: [PATCH 2/7] system_path(): Add prefix computation at runtime if RUNTIME_PREFIX set This commit modifies system_path() to compute the prefix at runtime if configured to do so. If RUNTIME_PREFIX is defined, system_path() tries to strip known directories that executables can be located in from the path of the executable. If the path is successfully stripped it is used as the prefix. For example, if the executable is "/msysgit/bin/git" and BINDIR is "/bin", then the prefix is computed as "/msysgit". We report an error if the runtime prefix computation fails, which can happen if the executable is not installed at a known location. The user should know that the global configuration is not picked up, because this can cause unexpected behavior. If we explicitly want to ignore system wide paths, we can set the environment variable GIT_CONFIG_NOSYSTEM, as our tests do. The implementation requires that argv0_path is set up properly, which is currently the case only on Windows. argv0_path must point to the absolute path of the directory of the executable, which is verified by two calls to assert(). On Windows, the wrapper for main() (see compat/mingw.h) guarantees that this is the case. On Unix, further work is required before RUNTIME_PREFIX can be enabled. --- Makefile | 3 +++ exec_cmd.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index f716fda416..b229bff5fb 100644 --- a/Makefile +++ b/Makefile @@ -989,6 +989,9 @@ ifdef INTERNAL_QSORT COMPAT_CFLAGS += -DINTERNAL_QSORT COMPAT_OBJS += compat/qsort.o endif +ifdef RUNTIME_PREFIX + COMPAT_CFLAGS += -DRUNTIME_PREFIX +endif ifdef THREADED_DELTA_SEARCH BASIC_CFLAGS += -DTHREADED_DELTA_SEARCH diff --git a/exec_cmd.c b/exec_cmd.c index ce6741eb68..9fa89b8502 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -9,11 +9,48 @@ static const char *argv0_path; const char *system_path(const char *path) { - if (!is_absolute_path(path) && argv0_path) { - struct strbuf d = STRBUF_INIT; - strbuf_addf(&d, "%s/%s", argv0_path, path); - path = strbuf_detach(&d, NULL); +#ifdef RUNTIME_PREFIX + static const char *prefix; + + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix) { + const char *strip[] = { + GIT_EXEC_PATH, + BINDIR, + 0 + }; + const char **s; + + for (s = strip; *s; s++) { + const char *sargv = argv0_path + strlen(argv0_path); + const char *ss = *s + strlen(*s); + while (argv0_path < sargv && *s < ss + && (*sargv == *ss || + (is_dir_sep(*sargv) && is_dir_sep(*ss)))) { + sargv--; + ss--; + } + if (*s == ss) { + struct strbuf d = STRBUF_INIT; + strbuf_add(&d, argv0_path, sargv - argv0_path); + prefix = strbuf_detach(&d, NULL); + break; + } + } } + + if (!prefix) { + fprintf(stderr, "RUNTIME_PREFIX requested for path '%s', " + "but prefix computation failed.\n", path); + return path; + } + + struct strbuf d = STRBUF_INIT; + strbuf_addf(&d, "%s/%s", prefix, path); + path = strbuf_detach(&d, NULL); +#endif return path; } From f2fdec9debe6803204ce9dd734058188110e3cf9 Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 3/7] Refactor git_set_argv0_path() to git_extract_argv0_path() This commit moves the code that computes the dirname of argv[0] from git.c's main() to git_set_argv0_path() and renames the function to git_extract_argv0_path(). This makes the code in git.c's main less cluttered, and we can use the direname computation from other main() functions too. [spr: split Steve's original commit and wrote new commit message. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- exec_cmd.c | 15 +++++++++++++-- exec_cmd.h | 2 +- git.c | 20 +++++--------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 9fa89b8502..46ebf7ec82 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -54,9 +54,20 @@ const char *system_path(const char *path) return path; } -void git_set_argv0_path(const char *path) +const char *git_extract_argv0_path(const char *argv0) { - argv0_path = path; + const char *slash = argv0 + strlen(argv0); + + do + --slash; + while (slash >= argv0 && !is_dir_sep(*slash)); + + if (slash >= argv0) { + argv0_path = xstrndup(argv0, slash - argv0); + return slash + 1; + } + + return argv0; } void git_set_argv_exec_path(const char *exec_path) diff --git a/exec_cmd.h b/exec_cmd.h index 594f961387..392e9032c3 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -2,7 +2,7 @@ #define GIT_EXEC_CMD_H extern void git_set_argv_exec_path(const char *exec_path); -extern void git_set_argv0_path(const char *path); +extern const char* git_extract_argv0_path(const char *path); extern const char* git_exec_path(void); extern void setup_path(void); extern const char **prepare_git_cmd(const char **argv); diff --git a/git.c b/git.c index fdb0f71019..cfcedc20dc 100644 --- a/git.c +++ b/git.c @@ -416,23 +416,13 @@ static void execv_dashed_external(const char **argv) int main(int argc, const char **argv) { - const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help"; - char *slash = (char *)cmd + strlen(cmd); + const char *cmd; int done_alias = 0; - /* - * Take the basename of argv[0] as the command - * name, and the dirname as the default exec_path - * if we don't have anything better. - */ - do - --slash; - while (cmd <= slash && !is_dir_sep(*slash)); - if (cmd <= slash) { - *slash++ = 0; - git_set_argv0_path(cmd); - cmd = slash; - } + if (argv[0] && *argv[0]) + cmd = git_extract_argv0_path(argv[0]); + else + cmd = "git-help"; /* * "git-xxxx" is the same as "git xxxx", but we obviously: From 2a7e0eeb480c083fc66065a9505fbbfecae2cf4d Mon Sep 17 00:00:00 2001 From: Steve Haslam Date: Wed, 30 Jul 2008 12:27:18 +0100 Subject: [PATCH 4/7] Glean libexec path from argv[0] for git-upload-pack and git-receive-pack. If the user specified the full path to git-upload-pack as the -u option to "git clone" when cloning a remote repository, and git was not on the default PATH on the remote machine, git-upload-pack was failing to exec git-pack-objects. By making the argv[0] path (if any) available to setup_path(), this will allow finding the "git" executable in the same directory as "git-upload-pack". The default built in to exec_cmd.c is to look for "git" in the ".../libexec/git-core" directory, but it is not installed there (any longer). Much the same applies to invoking git-receive-pack from a non-PATH location using the "--exec" argument to "git push". [ spr: split Steve's original commit into two commits. ] Signed-off-by: Steve Haslam Signed-off-by: Steffen Prohaska --- receive-pack.c | 3 +++ upload-pack.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/receive-pack.c b/receive-pack.c index d44c19e6b5..3699b166c7 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -467,6 +467,9 @@ int main(int argc, char **argv) int i; char *dir = NULL; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + argv++; for (i = 1; i < argc; i++) { char *arg = *argv++; diff --git a/upload-pack.c b/upload-pack.c index e5adbc011e..c469a60d79 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -616,6 +616,9 @@ int main(int argc, char **argv) int i; int strict = 0; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + for (i = 1; i < argc; i++) { char *arg = argv[i]; From 9599d567403f6a0bf185f8a3c4e14a77b69004a5 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 08:58:21 +0200 Subject: [PATCH 5/7] Add calls to git_extract_argv0_path() in programs that call git_config_* Programs that use git_config need to find the global configuration. When runtime prefix computation is enabled, this requires that git_extract_argv0_path() is called early in the program's main(). This commit adds the necessary calls in the programs that use git_config. --- daemon.c | 3 +++ fast-import.c | 4 ++++ hash-object.c | 4 ++++ index-pack.c | 4 ++++ unpack-file.c | 4 ++++ var.c | 4 ++++ 6 files changed, 23 insertions(+) diff --git a/daemon.c b/daemon.c index 8dcde73200..172854e74c 100644 --- a/daemon.c +++ b/daemon.c @@ -1055,6 +1055,9 @@ int main(int argc, char **argv) gid_t gid = 0; int i; + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + /* Without this we cannot rely on waitpid() to tell * what happened to our children. */ diff --git a/fast-import.c b/fast-import.c index d85b3a561f..239309f96d 100644 --- a/fast-import.c +++ b/fast-import.c @@ -150,6 +150,7 @@ Format of STDIN stream: #include "refs.h" #include "csum-file.h" #include "quote.h" +#include "exec_cmd.h" #define PACK_ID_BITS 16 #define MAX_PACK_ID ((1<"); if (get_sha1(argv[1], sha1)) diff --git a/var.c b/var.c index f1eb314e89..33457dc6ab 100644 --- a/var.c +++ b/var.c @@ -4,6 +4,7 @@ * Copyright (C) Eric Biederman, 2005 */ #include "cache.h" +#include "exec_cmd.h" static const char var_usage[] = "git var [-l | ]"; @@ -56,6 +57,9 @@ int main(int argc, char **argv) usage(var_usage); } + if (argv[0] && *argv[0]) + git_extract_argv0_path(argv[0]); + setup_git_directory_gently(&nongit); val = NULL; From 8327b82bf72faaa5bcf0cee176312f1f89bae1c3 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 17 Aug 2008 11:30:33 +0200 Subject: [PATCH 6/7] Modify setup_path() to only add git_exec_path() to PATH We should search git programs only in the highest-priority location. The old code added the directories "argv_exec_path", "getenv(EXEC_PATH_ENVIRONMENT)", and "system_path(GIT_EXEC_PATH)" to PATH. The same order is implemented in git_exec_path(), which returns the highest priority location to search for executables. If the user explicitly overrides the default location (by --exec-path or GIT_EXEC_PATH) we can expect that all the required programs are there. It does not make sense that only some of the required programs are located at the highest priority location and other programs are picked up from a lower priority exec-path. If exec-path is overridden a complete set of commands should be provided, otherwise several different versions might easily get mixed, which is likely to spread confusion. Accessing the location with highest priority only is also required for testing of executables built with RUNTIME_PREFIX. Calling system_path(GIT_EXEC_PATH) is avoided if a higher-priority location is provided, which is the case for the tests. The call to system_path() must be avoided, if RUNTIME_PREFIX is set, because the call would fail if the executable is not installed at its final destination. But we test before installing. --- exec_cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/exec_cmd.c b/exec_cmd.c index 46ebf7ec82..2a86670baa 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -111,9 +111,7 @@ void setup_path(void) strbuf_init(&new_path, 0); - add_path(&new_path, argv_exec_path); - add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); - add_path(&new_path, system_path(GIT_EXEC_PATH)); + add_path(&new_path, git_exec_path()); add_path(&new_path, argv0_path); if (old_path) From 1a78826c218ecf8bbda95802e8e0fc912a1d499b Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sat, 16 Aug 2008 16:43:58 +0200 Subject: [PATCH 7/7] Windows: Revert to default paths and convert them by RUNTIME_PREFIX The RUNTIME_PREFIX mechanism allows us to use the default (absolute) paths on Windows too. Defining RUNTIME_PREFIX explicitly requests for translation of paths during runtime, depending on the path to the executable. --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b229bff5fb..b7c4e02d6c 100644 --- a/Makefile +++ b/Makefile @@ -755,6 +755,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) SNPRINTF_RETURNS_BOGUS = YesPlease NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease + RUNTIME_PREFIX = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 @@ -762,9 +763,6 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe - gitexecdir = ../libexec/git-core - template_dir = ../share/git-core/templates/ - ETC_GITCONFIG = ../etc/gitconfig endif ifneq (,$(findstring arm,$(uname_M))) ARM_SHA1 = YesPlease