Implement a wrapper of execve that can invoke shell scripts.

When an external git command is invoked, it can be a Bourne shell script.
This patch looks into the command file to see whether it is one.
In this case, the command line is rearranged to invoke the shell
with the proper arguments.

Moreover, the arguments are quoted if necessary because Windows'
spawn functions paste the arguments again into a command line that
is disassembled by the invoked process.
This commit is contained in:
Johannes Sixt
2006-12-29 09:01:17 +01:00
parent 90262b5fae
commit 2de27f2cbb
2 changed files with 90 additions and 0 deletions

View File

@@ -139,3 +139,91 @@ void sync(void)
void openlog(const char *ident, int option, int facility)
{
}
static const char *quote_arg(const char *arg)
{
/* count chars to quote */
int len = 0, n = 0;
int force_quotes = 0;
char *q, *d;
const char *p = arg;
while (*p) {
if (isspace(*p))
force_quotes = 1;
else if (*p == '"' || *p == '\\')
n++;
len++;
p++;
}
if (!force_quotes && n == 0)
return arg;
/* insert \ where necessary */
d = q = xmalloc(len+n+3);
*d++ = '"';
while (*arg) {
if (*arg == '"' || *arg == '\\')
*d++ = '\\';
*d++ = *arg++;
}
*d++ = '"';
*d++ = 0;
return q;
}
static void quote_argv(const char **dst, const char **src)
{
while (*src)
*dst++ = quote_arg(*src++);
*dst = NULL;
}
static int try_shell_exec(const char *cmd, const char **argv, const char **env)
{
char buf[100], *p;
const char **sh_argv;
int n;
int fd = open(cmd, O_RDONLY);
if (fd < 0)
return 0;
n = read(fd, buf, sizeof(buf)-1);
close(fd);
if (n < 5) /* at least '#!/sh' and not error */
return 0;
/* check whether the interpreter is sh */
if (buf[0] != '#' || buf[1] != '!')
return 0;
buf[n] = '\0';
p = strchr(buf, '\n');
if (!p ||
(p[-3] != '/' && p[-3] != '\\') ||
p[-2] != 's' || p[-1] != 'h')
return 0;
/*
* expand
* git-foo args...
* into
* sh git-foo args...
*/
for (n = 0; argv[n];) n++;
sh_argv = xmalloc((n+2)*sizeof(char*));
sh_argv[0] = "sh";
sh_argv[1] = cmd;
quote_argv(&sh_argv[2], &argv[1]);
n = spawnvpe(_P_WAIT, "sh", sh_argv, env);
if (n == -1)
return 1; /* indicate that we tried but failed */
exit(n);
}
void mingw_execve(const char *cmd, const char **argv, const char **env)
{
/* check if git_command is a shell script */
if (!try_shell_exec(cmd, argv, env)) {
int ret = spawnve(_P_WAIT, cmd, argv, env);
if (ret != -1)
exit(ret);
}
}

View File

@@ -306,6 +306,8 @@ int syslog(int type, char *bufp, ...);
#define LOG_DAEMON 4
unsigned int alarm(unsigned int seconds);
#include <winsock2.h>
void mingw_execve(const char *cmd, const char **argv, const char **env);
#define execve mingw_execve
int fork();
typedef int pid_t;
pid_t waitpid(pid_t pid, int *status, int options);