Skip to content

Commit 77cb17e

Browse files
Michal OstrowskiJunio C Hamano
authored andcommitted
Exec git programs without using PATH.
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>
1 parent c884dd9 commit 77cb17e

File tree

12 files changed

+176
-62
lines changed

12 files changed

+176
-62
lines changed

Makefile

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ STRIP ?= strip
6969

7070
prefix = $(HOME)
7171
bindir = $(prefix)/bin
72+
gitexecdir = $(prefix)/bin
7273
template_dir = $(prefix)/share/git-core/templates/
7374
GIT_PYTHON_DIR = $(prefix)/share/git-core/python
7475
# DESTDIR=
@@ -142,7 +143,7 @@ PROGRAMS = \
142143
git-describe$X
143144

144145
# what 'all' will build and 'install' will install.
145-
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X
146+
ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
146147

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

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

370-
all: $(ALL_PROGRAMS)
371+
all: $(ALL_PROGRAMS) git$X
371372

372373
all:
373374
$(MAKE) -C templates
@@ -376,7 +377,7 @@ strip: $(PROGRAMS) git$X
376377
$(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
377378

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

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

420+
exec_cmd.o: ALL_CFLAGS += -DGIT_EXEC_PATH=\"$(gitexecdir)\"
421+
419422
git-%$X: %.o $(LIB_FILE)
420423
$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
421424

@@ -472,7 +475,9 @@ check:
472475

473476
install: all
474477
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))
478+
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(gitexecdir))
475479
$(INSTALL) $(ALL_PROGRAMS) $(call shellquote,$(DESTDIR)$(bindir))
480+
$(INSTALL) git$X $(call shellquote,$(DESTDIR)$(gitexecdir))
476481
$(MAKE) -C templates install
477482
$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
478483
$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))

daemon.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <syslog.h>
1010
#include "pkt-line.h"
1111
#include "cache.h"
12+
#include "exec_cmd.h"
1213

1314
static int log_syslog;
1415
static int verbose;
@@ -227,7 +228,7 @@ static int upload(char *dir)
227228
snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
228229

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

exec_cmd.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#include "cache.h"
2+
#include "exec_cmd.h"
3+
#define MAX_ARGS 32
4+
5+
extern char **environ;
6+
static const char *builtin_exec_path = GIT_EXEC_PATH;
7+
static const char *current_exec_path = NULL;
8+
9+
void git_set_exec_path(const char *exec_path)
10+
{
11+
current_exec_path = exec_path;
12+
}
13+
14+
15+
/* Returns the highest-priority, location to look for git programs. */
16+
const char *git_exec_path()
17+
{
18+
const char *env;
19+
20+
if (current_exec_path)
21+
return current_exec_path;
22+
23+
env = getenv("GIT_EXEC_PATH");
24+
if (env) {
25+
return env;
26+
}
27+
28+
return builtin_exec_path;
29+
}
30+
31+
32+
int execv_git_cmd(char **argv)
33+
{
34+
char git_command[PATH_MAX + 1];
35+
char *tmp;
36+
int len, err, i;
37+
const char *paths[] = { current_exec_path,
38+
getenv("GIT_EXEC_PATH"),
39+
builtin_exec_path };
40+
41+
for (i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) {
42+
const char *exec_dir = paths[i];
43+
if (!exec_dir) continue;
44+
45+
if (*exec_dir != '/') {
46+
if (!getcwd(git_command, sizeof(git_command))) {
47+
fprintf(stderr, "git: cannot determine "
48+
"current directory\n");
49+
exit(1);
50+
}
51+
len = strlen(git_command);
52+
53+
/* Trivial cleanup */
54+
while (!strncmp(exec_dir, "./", 2)) {
55+
exec_dir += 2;
56+
while (*exec_dir == '/')
57+
exec_dir++;
58+
}
59+
snprintf(git_command + len, sizeof(git_command) - len,
60+
"/%s", exec_dir);
61+
} else {
62+
strcpy(git_command, exec_dir);
63+
}
64+
65+
len = strlen(git_command);
66+
len += snprintf(git_command + len, sizeof(git_command) - len,
67+
"/git-%s", argv[0]);
68+
69+
if (sizeof(git_command) <= len) {
70+
fprintf(stderr,
71+
"git: command name given is too long.\n");
72+
break;
73+
}
74+
75+
/* argv[0] must be the git command, but the argv array
76+
* belongs to the caller, and my be reused in
77+
* subsequent loop iterations. Save argv[0] and
78+
* restore it on error.
79+
*/
80+
81+
tmp = argv[0];
82+
argv[0] = git_command;
83+
84+
/* execve() can only ever return if it fails */
85+
execve(git_command, argv, environ);
86+
87+
err = errno;
88+
89+
argv[0] = tmp;
90+
}
91+
return -1;
92+
93+
}
94+
95+
96+
int execl_git_cmd(char *cmd,...)
97+
{
98+
int argc;
99+
char *argv[MAX_ARGS + 1];
100+
char *arg;
101+
va_list param;
102+
103+
va_start(param, cmd);
104+
argv[0] = cmd;
105+
argc = 1;
106+
while (argc < MAX_ARGS) {
107+
arg = argv[argc++] = va_arg(param, char *);
108+
if (!arg)
109+
break;
110+
}
111+
va_end(param);
112+
if (MAX_ARGS <= argc)
113+
return error("too many args to run %s", cmd);
114+
115+
argv[argc] = NULL;
116+
return execv_git_cmd(argv);
117+
}

exec_cmd.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifndef __GIT_EXEC_CMD_H_
2+
#define __GIT_EXEC_CMD_H_
3+
4+
extern void git_set_exec_path(const char *exec_path);
5+
extern const char* git_exec_path(void);
6+
extern int execv_git_cmd(char **argv); /* NULL terminated */
7+
extern int execl_git_cmd(char *cmd, ...);
8+
9+
10+
#endif /* __GIT_EXEC_CMD_H_ */

fetch-clone.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "cache.h"
2+
#include "exec_cmd.h"
23
#include <sys/wait.h>
34

45
static int finish_pack(const char *pack_tmp_name, const char *me)
@@ -27,8 +28,7 @@ static int finish_pack(const char *pack_tmp_name, const char *me)
2728
dup2(pipe_fd[1], 1);
2829
close(pipe_fd[0]);
2930
close(pipe_fd[1]);
30-
execlp("git-index-pack","git-index-pack",
31-
"-o", idx, pack_tmp_name, NULL);
31+
execl_git_cmd("index-pack", "-o", idx, pack_tmp_name, NULL);
3232
error("cannot exec git-index-pack <%s> <%s>",
3333
idx, pack_tmp_name);
3434
exit(1);
@@ -105,8 +105,7 @@ int receive_unpack_pack(int fd[2], const char *me, int quiet)
105105
dup2(fd[0], 0);
106106
close(fd[0]);
107107
close(fd[1]);
108-
execlp("git-unpack-objects", "git-unpack-objects",
109-
quiet ? "-q" : NULL, NULL);
108+
execl_git_cmd("unpack-objects", quiet ? "-q" : NULL, NULL);
110109
die("git-unpack-objects exec failed");
111110
}
112111
close(fd[0]);

git.c

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stdarg.h>
1111
#include <sys/ioctl.h>
1212
#include "git-compat-util.h"
13+
#include "exec_cmd.h"
1314

1415
#ifndef PATH_MAX
1516
# define PATH_MAX 4096
@@ -233,14 +234,11 @@ int main(int argc, char **argv, char **envp)
233234
{
234235
char git_command[PATH_MAX + 1];
235236
char wd[PATH_MAX + 1];
236-
int i, len, show_help = 0;
237-
char *exec_path = getenv("GIT_EXEC_PATH");
237+
int i, show_help = 0;
238+
const char *exec_path;
238239

239240
getcwd(wd, PATH_MAX);
240241

241-
if (!exec_path)
242-
exec_path = GIT_EXEC_PATH;
243-
244242
for (i = 1; i < argc; i++) {
245243
char *arg = argv[i];
246244

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

257255
if (!strncmp(arg, "exec-path", 9)) {
258256
arg += 9;
259-
if (*arg == '=')
257+
if (*arg == '=') {
260258
exec_path = arg + 1;
261-
else {
262-
puts(exec_path);
259+
git_set_exec_path(exec_path);
260+
} else {
261+
puts(git_exec_path());
263262
exit(0);
264263
}
265264
}
@@ -275,42 +274,15 @@ int main(int argc, char **argv, char **envp)
275274

276275
if (i >= argc || show_help) {
277276
if (i >= argc)
278-
cmd_usage(exec_path, NULL);
277+
cmd_usage(git_exec_path(), NULL);
279278

280279
show_man_page(argv[i]);
281280
}
282281

283-
if (*exec_path != '/') {
284-
if (!getcwd(git_command, sizeof(git_command))) {
285-
fprintf(stderr,
286-
"git: cannot determine current directory\n");
287-
exit(1);
288-
}
289-
len = strlen(git_command);
290-
291-
/* Trivial cleanup */
292-
while (!strncmp(exec_path, "./", 2)) {
293-
exec_path += 2;
294-
while (*exec_path == '/')
295-
exec_path++;
296-
}
297-
snprintf(git_command + len, sizeof(git_command) - len,
298-
"/%s", exec_path);
299-
}
300-
else
301-
strcpy(git_command, exec_path);
302-
len = strlen(git_command);
303-
prepend_to_path(git_command, len);
304-
305-
len += snprintf(git_command + len, sizeof(git_command) - len,
306-
"/git-%s", argv[i]);
307-
if (sizeof(git_command) <= len) {
308-
fprintf(stderr, "git: command name given is too long.\n");
309-
exit(1);
310-
}
282+
exec_path = git_exec_path();
283+
prepend_to_path(exec_path, strlen(exec_path));
311284

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

315287
if (errno == ENOENT)
316288
cmd_usage(exec_path, "'%s' is not a git-command", argv[i]);

receive-pack.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

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

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

1111
static int report_status = 0;
1212

@@ -257,7 +257,7 @@ static void read_head_info(void)
257257

258258
static const char *unpack(int *error_code)
259259
{
260-
int code = run_command(unpacker, NULL);
260+
int code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);
261261

262262
*error_code = 0;
263263
switch (code) {

run-command.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "cache.h"
22
#include "run-command.h"
33
#include <sys/wait.h>
4+
#include "exec_cmd.h"
45

56
int run_command_v_opt(int argc, char **argv, int flags)
67
{
@@ -13,9 +14,13 @@ int run_command_v_opt(int argc, char **argv, int flags)
1314
int fd = open("/dev/null", O_RDWR);
1415
dup2(fd, 0);
1516
dup2(fd, 1);
16-
close(fd);
17+
close(fd);
18+
}
19+
if (flags & RUN_GIT_CMD) {
20+
execv_git_cmd(argv);
21+
} else {
22+
execvp(argv[0], (char *const*) argv);
1723
}
18-
execvp(argv[0], (char *const*) argv);
1924
die("exec %s failed.", argv[0]);
2025
}
2126
for (;;) {

run-command.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ enum {
1212
};
1313

1414
#define RUN_COMMAND_NO_STDIO 1
15-
15+
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
1616
int run_command_v_opt(int argc, char **argv, int opt);
1717
int run_command_v(int argc, char **argv);
1818
int run_command(const char *cmd, ...);

0 commit comments

Comments
 (0)