Skip to content

Commit

Permalink
Exec git programs without using PATH.
Browse files Browse the repository at this point in the history
The git suite may not be in PATH (and thus programs such as
git-send-pack could not exec git-rev-list).  Thus there is a need for
logic that will locate these programs.  Modifying PATH is not
desirable as it result in behavior differing from the user's
intentions, as we may end up prepending "/usr/bin" to PATH.

- git C programs will use exec*_git_cmd() APIs to exec sub-commands.
- exec*_git_cmd() will execute a git program by searching for it in
  the following directories:
	1. --exec-path (as used by "git")
	2. The GIT_EXEC_PATH environment variable.
	3. $(gitexecdir) as set in Makefile (default value $(bindir)).
- git wrapper will modify PATH as before to enable shell scripts to
  invoke "git-foo" commands.

Ideally, shell scripts should use the git wrapper to become independent
of PATH, and then modifying PATH will not be necessary.

[jc: with minor updates after a brief review.]

Signed-off-by: Michal Ostrowski <mostrows@watson.ibm.com>
Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
Michal Ostrowski authored and Junio C Hamano committed Jan 14, 2006
1 parent c884dd9 commit 77cb17e
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 62 deletions.
13 changes: 9 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ STRIP ?= strip

prefix = $(HOME)
bindir = $(prefix)/bin
gitexecdir = $(prefix)/bin
template_dir = $(prefix)/share/git-core/templates/
GIT_PYTHON_DIR = $(prefix)/share/git-core/python
# DESTDIR=
Expand Down Expand Up @@ -142,7 +143,7 @@ PROGRAMS = \
git-describe$X

# what 'all' will build and 'install' will install.
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)

# Backward compatibility -- to be removed after 1.0
PROGRAMS += git-ssh-pull$X git-ssh-push$X
Expand Down Expand Up @@ -174,7 +175,7 @@ DIFF_OBJS = \

LIB_OBJS = \
blob.o commit.o connect.o count-delta.o csum-file.o \
date.o diff-delta.o entry.o ident.o index.o \
date.o diff-delta.o entry.o exec_cmd.o ident.o index.o \
object.o pack-check.o patch-delta.o path.o pkt-line.o \
quote.o read-cache.o refs.o run-command.o \
server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
Expand Down Expand Up @@ -367,7 +368,7 @@ LIB_OBJS += $(COMPAT_OBJS)
export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
### Build rules

all: $(ALL_PROGRAMS)
all: $(ALL_PROGRAMS) git$X

all:
$(MAKE) -C templates
Expand All @@ -376,7 +377,7 @@ strip: $(PROGRAMS) git$X
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X

git$X: git.c $(LIB_FILE)
$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)

$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
Expand Down Expand Up @@ -416,6 +417,8 @@ git$X git.spec \
%.o: %.S
$(CC) -o $*.o -c $(ALL_CFLAGS) $<

exec_cmd.o: ALL_CFLAGS += -DGIT_EXEC_PATH=\"$(gitexecdir)\"

git-%$X: %.o $(LIB_FILE)
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)

Expand Down Expand Up @@ -472,7 +475,9 @@ check:

install: all
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(gitexecdir))
$(INSTALL) $(ALL_PROGRAMS) $(call shellquote,$(DESTDIR)$(bindir))
$(INSTALL) git$X $(call shellquote,$(DESTDIR)$(gitexecdir))
$(MAKE) -C templates install
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
Expand Down
3 changes: 2 additions & 1 deletion daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <syslog.h>
#include "pkt-line.h"
#include "cache.h"
#include "exec_cmd.h"

static int log_syslog;
static int verbose;
Expand Down Expand Up @@ -227,7 +228,7 @@ static int upload(char *dir)
snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);

/* git-upload-pack only ever reads stuff, so this is safe */
execlp("git-upload-pack", "git-upload-pack", "--strict", timeout_buf, ".", NULL);
execl_git_cmd("upload-pack", "--strict", timeout_buf, ".", NULL);
return -1;
}

Expand Down
117 changes: 117 additions & 0 deletions exec_cmd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#include "cache.h"
#include "exec_cmd.h"
#define MAX_ARGS 32

extern char **environ;
static const char *builtin_exec_path = GIT_EXEC_PATH;
static const char *current_exec_path = NULL;

void git_set_exec_path(const char *exec_path)
{
current_exec_path = exec_path;
}


/* Returns the highest-priority, location to look for git programs. */
const char *git_exec_path()
{
const char *env;

if (current_exec_path)
return current_exec_path;

env = getenv("GIT_EXEC_PATH");
if (env) {
return env;
}

return builtin_exec_path;
}


int execv_git_cmd(char **argv)
{
char git_command[PATH_MAX + 1];
char *tmp;
int len, err, i;
const char *paths[] = { current_exec_path,
getenv("GIT_EXEC_PATH"),
builtin_exec_path };

for (i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) {
const char *exec_dir = paths[i];
if (!exec_dir) continue;

if (*exec_dir != '/') {
if (!getcwd(git_command, sizeof(git_command))) {
fprintf(stderr, "git: cannot determine "
"current directory\n");
exit(1);
}
len = strlen(git_command);

/* Trivial cleanup */
while (!strncmp(exec_dir, "./", 2)) {
exec_dir += 2;
while (*exec_dir == '/')
exec_dir++;
}
snprintf(git_command + len, sizeof(git_command) - len,
"/%s", exec_dir);
} else {
strcpy(git_command, exec_dir);
}

len = strlen(git_command);
len += snprintf(git_command + len, sizeof(git_command) - len,
"/git-%s", argv[0]);

if (sizeof(git_command) <= len) {
fprintf(stderr,
"git: command name given is too long.\n");
break;
}

/* argv[0] must be the git command, but the argv array
* belongs to the caller, and my be reused in
* subsequent loop iterations. Save argv[0] and
* restore it on error.
*/

tmp = argv[0];
argv[0] = git_command;

/* execve() can only ever return if it fails */
execve(git_command, argv, environ);

err = errno;

argv[0] = tmp;
}
return -1;

}


int execl_git_cmd(char *cmd,...)
{
int argc;
char *argv[MAX_ARGS + 1];
char *arg;
va_list param;

va_start(param, cmd);
argv[0] = cmd;
argc = 1;
while (argc < MAX_ARGS) {
arg = argv[argc++] = va_arg(param, char *);
if (!arg)
break;
}
va_end(param);
if (MAX_ARGS <= argc)
return error("too many args to run %s", cmd);

argv[argc] = NULL;
return execv_git_cmd(argv);
}
10 changes: 10 additions & 0 deletions exec_cmd.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef __GIT_EXEC_CMD_H_
#define __GIT_EXEC_CMD_H_

extern void git_set_exec_path(const char *exec_path);
extern const char* git_exec_path(void);
extern int execv_git_cmd(char **argv); /* NULL terminated */
extern int execl_git_cmd(char *cmd, ...);


#endif /* __GIT_EXEC_CMD_H_ */
7 changes: 3 additions & 4 deletions fetch-clone.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "cache.h"
#include "exec_cmd.h"
#include <sys/wait.h>

static int finish_pack(const char *pack_tmp_name, const char *me)
Expand Down Expand Up @@ -27,8 +28,7 @@ static int finish_pack(const char *pack_tmp_name, const char *me)
dup2(pipe_fd[1], 1);
close(pipe_fd[0]);
close(pipe_fd[1]);
execlp("git-index-pack","git-index-pack",
"-o", idx, pack_tmp_name, NULL);
execl_git_cmd("index-pack", "-o", idx, pack_tmp_name, NULL);
error("cannot exec git-index-pack <%s> <%s>",
idx, pack_tmp_name);
exit(1);
Expand Down Expand Up @@ -105,8 +105,7 @@ int receive_unpack_pack(int fd[2], const char *me, int quiet)
dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);
execlp("git-unpack-objects", "git-unpack-objects",
quiet ? "-q" : NULL, NULL);
execl_git_cmd("unpack-objects", quiet ? "-q" : NULL, NULL);
die("git-unpack-objects exec failed");
}
close(fd[0]);
Expand Down
50 changes: 11 additions & 39 deletions git.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <stdarg.h>
#include <sys/ioctl.h>
#include "git-compat-util.h"
#include "exec_cmd.h"

#ifndef PATH_MAX
# define PATH_MAX 4096
Expand Down Expand Up @@ -233,14 +234,11 @@ int main(int argc, char **argv, char **envp)
{
char git_command[PATH_MAX + 1];
char wd[PATH_MAX + 1];
int i, len, show_help = 0;
char *exec_path = getenv("GIT_EXEC_PATH");
int i, show_help = 0;
const char *exec_path;

getcwd(wd, PATH_MAX);

if (!exec_path)
exec_path = GIT_EXEC_PATH;

for (i = 1; i < argc; i++) {
char *arg = argv[i];

Expand All @@ -256,10 +254,11 @@ int main(int argc, char **argv, char **envp)

if (!strncmp(arg, "exec-path", 9)) {
arg += 9;
if (*arg == '=')
if (*arg == '=') {
exec_path = arg + 1;
else {
puts(exec_path);
git_set_exec_path(exec_path);
} else {
puts(git_exec_path());
exit(0);
}
}
Expand All @@ -275,42 +274,15 @@ int main(int argc, char **argv, char **envp)

if (i >= argc || show_help) {
if (i >= argc)
cmd_usage(exec_path, NULL);
cmd_usage(git_exec_path(), NULL);

show_man_page(argv[i]);
}

if (*exec_path != '/') {
if (!getcwd(git_command, sizeof(git_command))) {
fprintf(stderr,
"git: cannot determine current directory\n");
exit(1);
}
len = strlen(git_command);

/* Trivial cleanup */
while (!strncmp(exec_path, "./", 2)) {
exec_path += 2;
while (*exec_path == '/')
exec_path++;
}
snprintf(git_command + len, sizeof(git_command) - len,
"/%s", exec_path);
}
else
strcpy(git_command, exec_path);
len = strlen(git_command);
prepend_to_path(git_command, len);

len += snprintf(git_command + len, sizeof(git_command) - len,
"/git-%s", argv[i]);
if (sizeof(git_command) <= len) {
fprintf(stderr, "git: command name given is too long.\n");
exit(1);
}
exec_path = git_exec_path();
prepend_to_path(exec_path, strlen(exec_path));

/* execve() can only ever return if it fails */
execve(git_command, &argv[i], envp);
execv_git_cmd(argv + i);

if (errno == ENOENT)
cmd_usage(exec_path, "'%s' is not a git-command", argv[i]);
Expand Down
4 changes: 2 additions & 2 deletions receive-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

static const char receive_pack_usage[] = "git-receive-pack <git-dir>";

static const char unpacker[] = "git-unpack-objects";
static char *unpacker[] = { "unpack-objects", NULL };

static int report_status = 0;

Expand Down Expand Up @@ -257,7 +257,7 @@ static void read_head_info(void)

static const char *unpack(int *error_code)
{
int code = run_command(unpacker, NULL);
int code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);

*error_code = 0;
switch (code) {
Expand Down
9 changes: 7 additions & 2 deletions run-command.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "cache.h"
#include "run-command.h"
#include <sys/wait.h>
#include "exec_cmd.h"

int run_command_v_opt(int argc, char **argv, int flags)
{
Expand All @@ -13,9 +14,13 @@ int run_command_v_opt(int argc, char **argv, int flags)
int fd = open("/dev/null", O_RDWR);
dup2(fd, 0);
dup2(fd, 1);
close(fd);
close(fd);
}
if (flags & RUN_GIT_CMD) {
execv_git_cmd(argv);
} else {
execvp(argv[0], (char *const*) argv);
}
execvp(argv[0], (char *const*) argv);
die("exec %s failed.", argv[0]);
}
for (;;) {
Expand Down
2 changes: 1 addition & 1 deletion run-command.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ enum {
};

#define RUN_COMMAND_NO_STDIO 1

#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
int run_command_v_opt(int argc, char **argv, int opt);
int run_command_v(int argc, char **argv);
int run_command(const char *cmd, ...);
Expand Down
Loading

0 comments on commit 77cb17e

Please sign in to comment.