diff --git a/Makefile b/Makefile index 8586fcd397..67dfc22d07 100644 --- a/Makefile +++ b/Makefile @@ -294,7 +294,6 @@ LIB_H = \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ - spawn-pipe.h \ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \ mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h @@ -308,7 +307,6 @@ LIB_OBJS = \ date.o diff-delta.o entry.o exec_cmd.o ident.o \ pretty.o interpolate.o hash.o \ lockfile.o \ - spawn-pipe.o \ patch-ids.o \ object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \ sideband.o reachable.o reflog-walk.o \ diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index a2ca746dd0..b21ba2eb95 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -463,34 +463,12 @@ static int sideband_demux(int fd, void *data) { int *xd = data; - close(xd[1]); return recv_sideband("fetch-pack", xd[0], fd, 2); } -static void setup_sideband(int fd[2], int xd[2], struct async *demux) -{ - if (!use_sideband) { - fd[0] = xd[0]; - fd[1] = xd[1]; - return; - } - /* xd[] is talking with upload-pack; subprocess reads from - * xd[0], spits out band#2 to stderr, and feeds us band#1 - * through demux->out. - */ - demux->proc = sideband_demux; - demux->data = xd; - if (start_async(demux)) - die("fetch-pack: unable to fork off sideband demultiplexer"); - close(xd[0]); - fd[0] = demux->out; - fd[1] = xd[1]; -} - static int get_pack(int xd[2], char **pack_lockfile) { struct async demux; - int fd[2]; const char *argv[20]; char keep_arg[256]; char hdr_arg[256]; @@ -498,7 +476,20 @@ static int get_pack(int xd[2], char **pack_lockfile) int do_keep = args.keep_pack; struct child_process cmd; - setup_sideband(fd, xd, &demux); + memset(&demux, 0, sizeof(demux)); + if (use_sideband) { + /* xd[] is talking with upload-pack; subprocess reads from + * xd[0], spits out band#2 to stderr, and feeds us band#1 + * through demux->out. + */ + demux.proc = sideband_demux; + demux.data = xd; + if (start_async(&demux)) + die("fetch-pack: unable to fork off sideband" + " demultiplexer"); + } + else + demux.out = xd[0]; memset(&cmd, 0, sizeof(cmd)); cmd.argv = argv; @@ -507,7 +498,7 @@ static int get_pack(int xd[2], char **pack_lockfile) if (!args.keep_pack && unpack_limit) { struct pack_header header; - if (read_pack_header(fd[0], &header)) + if (read_pack_header(demux.out, &header)) die("protocol error: bad pack header"); snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%u,%u", ntohl(header.hdr_version), ntohl(header.hdr_entries)); @@ -543,11 +534,10 @@ static int get_pack(int xd[2], char **pack_lockfile) *av++ = hdr_arg; *av++ = NULL; - cmd.in = fd[0]; + cmd.in = demux.out; cmd.git_cmd = 1; if (start_command(&cmd)) die("fetch-pack: unable to fork off %s", argv[0]); - close(fd[1]); if (do_keep && pack_lockfile) *pack_lockfile = index_pack_lockfile(cmd.out); @@ -574,7 +564,6 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "Server supports multi_ack\n"); multi_ack = 1; } -#ifndef __MINGW32__ if (server_supports("side-band-64k")) { if (args.verbose) fprintf(stderr, "Server supports side-band-64k\n"); @@ -585,7 +574,6 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "Server supports side-band\n"); use_sideband = 1; } -#endif if (!ref) { packet_flush(fd[1]); die("no matching remote head"); diff --git a/compat/mingw.c b/compat/mingw.c index b841f6d0ca..306541b246 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -235,7 +235,7 @@ int pipe(int filedes[2]) CloseHandle(h[0]); return -1; } - fd = _open_osfhandle( (int) h[0], O_NOINHERIT); + fd = _open_osfhandle((int)h[0], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); @@ -245,7 +245,7 @@ int pipe(int filedes[2]) } close(filedes[0]); filedes[0] = fd; - fd = _open_osfhandle( (int) h[1], O_NOINHERIT); + fd = _open_osfhandle((int)h[1], O_NOINHERIT); if (fd < 0) { close(filedes[0]); close(filedes[1]); @@ -259,7 +259,62 @@ int pipe(int filedes[2]) int poll(struct pollfd *ufds, unsigned int nfds, int timeout) { - return -1; + int i, pending; + + if (timeout != -1) + return errno = EINVAL, error("poll timeout not supported"); + + /* When there is only one fd to wait for, then we pretend that + * input is available and let the actual wait happen when the + * caller invokes read(). + */ + if (nfds == 1) { + if (!(ufds[0].events & POLLIN)) + return errno = EINVAL, error("POLLIN not set"); + ufds[0].revents = POLLIN; + return 0; + } + +repeat: + pending = 0; + for (i = 0; i < nfds; i++) { + DWORD avail = 0; + HANDLE h = (HANDLE) _get_osfhandle(ufds[i].fd); + if (h == INVALID_HANDLE_VALUE) + return -1; /* errno was set */ + + if (!(ufds[i].events & POLLIN)) + return errno = EINVAL, error("POLLIN not set"); + + /* this emulation works only for pipes */ + if (!PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL)) { + int err = GetLastError(); + if (err == ERROR_BROKEN_PIPE) { + ufds[i].revents = POLLHUP; + pending++; + } else { + errno = EINVAL; + return error("PeekNamedPipe failed," + " GetLastError: %u", err); + } + } else if (avail) { + ufds[i].revents = POLLIN; + pending++; + } else + ufds[i].revents = 0; + } + if (!pending) { + /* The only times that we spin here is when the process + * that is connected through the pipes is waiting for + * its own input data to become available. But since + * the process (pack-objects) is itself CPU intensive, + * it will happily pick up the time slice that we are + * relinguishing here. + */ + Sleep(0); + goto repeat; + } + return 0; } #include @@ -537,6 +592,45 @@ void mingw_execvp(const char *cmd, char *const *argv) mingw_free_path_split(path); } +char **copy_environ() +{ + return copy_env(environ); +} + +char **copy_env(char **env) +{ + char **s; + int n = 1; + for (s = env; *s; s++) + n++; + s = xmalloc(n*sizeof(char *)); + memcpy(s, env, n*sizeof(char *)); + return s; +} + +void env_unsetenv(char **env, const char *name) +{ + int src, dst; + size_t nmln; + + nmln = strlen(name); + + for (src = dst = 0; env[src]; ++src) { + size_t enln; + enln = strlen(env[src]); + if (enln > nmln) { + /* might match, and can test for '=' safely */ + if (0 == strncmp (env[src], name, nmln) + && '=' == env[src][nmln]) + /* matches, so skip */ + continue; + } + env[dst] = env[src]; + ++dst; + } + env[dst] = NULL; +} + int mingw_socket(int domain, int type, int protocol) { SOCKET s = WSASocket(domain, type, protocol, NULL, 0, 0); @@ -666,10 +760,10 @@ static int start_timer_thread(void) timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL); if (!timer_thread ) return errno = ENOMEM, - error("cannot create progress indicator"); + error("cannot start timer thread"); } else return errno = ENOMEM, - error("cannot allocate resources for progress indicator"); + error("cannot allocate resources timer"); return 0; } diff --git a/connect.c b/connect.c index e11cf32321..0f10c40652 100644 --- a/connect.c +++ b/connect.c @@ -5,7 +5,6 @@ #include "refs.h" #include "run-command.h" #include "remote.h" -#include "spawn-pipe.h" static char *server_capabilities; diff --git a/exec_cmd.c b/exec_cmd.c index de4c174b68..9d22e78eb0 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -1,7 +1,6 @@ #include "cache.h" #include "exec_cmd.h" #include "quote.h" -#include "spawn-pipe.h" #define MAX_ARGS 32 extern char **environ; @@ -155,30 +154,3 @@ int execl_git_cmd(const char *cmd,...) argv[argc] = NULL; return execv_git_cmd(argv); } - -int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]) -{ - pid_t pid; - struct strbuf cmd; - const char *tmp; - - strbuf_init(&cmd, 0); - strbuf_addf(&cmd, "git-%s", argv[0]); - - /* argv[0] must be the git command, but the argv array - * belongs to the caller. Save argv[0] and - * restore it later. - */ - - tmp = argv[0]; - argv[0] = cmd.buf; - - trace_argv_printf(argv, -1, "trace: exec:"); - - pid = spawnvpe_pipe(cmd.buf, argv, (const char **)environ, - pin, pout); - - argv[0] = tmp; - return pid; - -} diff --git a/exec_cmd.h b/exec_cmd.h index 9e8a28489e..a892355c82 100644 --- a/exec_cmd.h +++ b/exec_cmd.h @@ -6,7 +6,6 @@ extern const char* git_exec_path(void); extern void setup_path(const char *); extern int execv_git_cmd(const char **argv); /* NULL terminated */ extern int execl_git_cmd(const char *cmd, ...); -extern int spawnv_git_cmd(const char **argv, int pin[2], int pout[2]); #endif /* GIT_EXEC_CMD_H */ diff --git a/git-compat-util.h b/git-compat-util.h index 42564918de..aab57dfaef 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -480,6 +480,10 @@ static inline int waitpid(pid_t pid, unsigned *status, unsigned options) #define SIGCHLD 0 #define SIGPIPE 0 +char **copy_environ(); +char **copy_env(char **env); +void env_unsetenv(char **env, const char *name); + unsigned int sleep (unsigned int __seconds); const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); diff --git a/run-command.c b/run-command.c index 6701684a25..05934f708f 100644 --- a/run-command.c +++ b/run-command.c @@ -1,7 +1,6 @@ #include "cache.h" #include "run-command.h" #include "exec_cmd.h" -#include "spawn-pipe.h" static inline void close_pair(int fd[2]) { @@ -9,13 +8,17 @@ static inline void close_pair(int fd[2]) close(fd[1]); } +static inline void dup_devnull(int to) +{ + int fd = open("/dev/null", O_RDWR); + dup2(fd, to); + close(fd); +} + int start_command(struct child_process *cmd) { int need_in, need_out, need_err; - int fdin[2] = { -1, -1 }; - int fdout[2] = { -1, -1 }; - int fderr[2] = { -1, -1 }; - const char **env = (const char **)environ; + int fdin[2], fdout[2], fderr[2]; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { @@ -50,53 +53,150 @@ int start_command(struct child_process *cmd) cmd->err = fderr[0]; } - { +#ifndef __MINGW32__ + cmd->pid = fork(); + if (!cmd->pid) { if (cmd->no_stdin) - fdin[0] = open("/dev/null", O_RDWR); + dup_devnull(0); else if (need_in) { - /* nothing */ + dup2(fdin[0], 0); + close_pair(fdin); } else if (cmd->in) { - fdin[0] = cmd->in; + dup2(cmd->in, 0); + close(cmd->in); } if (cmd->no_stdout) - fdout[1] = open("/dev/null", O_RDWR); + dup_devnull(1); else if (cmd->stdout_to_stderr) - fdout[1] = dup(2); + dup2(2, 1); else if (need_out) { - /* nothing */ + dup2(fdout[1], 1); + close_pair(fdout); } else if (cmd->out > 1) { - fdout[1] = cmd->out; + dup2(cmd->out, 1); + close(cmd->out); } if (cmd->no_stderr) - fderr[1] = open("/dev/null", O_RDWR); + dup_devnull(2); else if (need_err) { - /* nothing */ + dup2(fderr[1], 2); + close_pair(fderr); } - if (cmd->dir) - die("chdir in start_command() not implemented"); if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { - if (cmd->git_cmd) - die("modifying environment for git_cmd in start_command() not implemented"); - env = copy_environ(); for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - die("setting environment in start_command() not implemented"); + putenv((char*)*cmd->env); else - env_unsetenv(env, *cmd->env); + unsetenv(*cmd->env); } } if (cmd->git_cmd) { - cmd->pid = spawnv_git_cmd(cmd->argv, fdin, fdout); + execv_git_cmd(cmd->argv); } else { - cmd->pid = spawnvpe_pipe(cmd->argv[0], cmd->argv, env, fdin, fdout); + execvp(cmd->argv[0], (char *const*) cmd->argv); + } + die("exec %s failed.", cmd->argv[0]); + } +#else + int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ + const char *sargv0 = cmd->argv[0]; + char **env = environ; + struct strbuf git_cmd; + + if (cmd->no_stdin) { + s0 = dup(0); + dup_devnull(0); + } else if (need_in) { + s0 = dup(0); + dup2(fdin[0], 0); + } else if (cmd->in) { + s0 = dup(0); + dup2(cmd->in, 0); + } + + if (cmd->no_stdout) { + s1 = dup(1); + dup_devnull(1); + } else if (cmd->stdout_to_stderr) { + s1 = dup(1); + dup2(2, 1); + } else if (need_out) { + s1 = dup(1); + dup2(fdout[1], 1); + } else if (cmd->out > 1) { + s1 = dup(1); + dup2(cmd->out, 1); + } + + if (cmd->no_stderr) { + s2 = dup(2); + dup_devnull(2); + } else if (need_err) { + s2 = dup(2); + dup2(fderr[1], 2); + } + + if (cmd->dir) + die("chdir in start_command() not implemented"); + if (cmd->env) { + env = copy_environ(); + for (; *cmd->env; cmd->env++) { + if (strchr(*cmd->env, '=')) + die("setting environment in start_command() not implemented"); + else + env_unsetenv(env, *cmd->env); } } + + if (cmd->git_cmd) { + strbuf_init(&git_cmd, 0); + strbuf_addf(&git_cmd, "git-%s", cmd->argv[0]); + cmd->argv[0] = git_cmd.buf; + } + + char **path = mingw_get_path_split(); + const char *argv0 = cmd->argv[0]; + const char **qargv; + char *prog = mingw_path_lookup(argv0, path); + const char *interpr = parse_interpreter(prog); + int argc; + + for (argc = 0; cmd->argv[argc];) argc++; + qargv = xmalloc((argc+2)*sizeof(char*)); + if (!interpr) { + quote_argv(qargv, cmd->argv); + cmd->pid = spawnve(_P_NOWAIT, prog, qargv, (const char **)env); + } else { + qargv[0] = interpr; + cmd->argv[0] = prog; + quote_argv(&qargv[1], cmd->argv); + cmd->pid = spawnvpe(_P_NOWAIT, interpr, qargv, (const char **)env); + } + + free(qargv); /* TODO: quoted args should be freed, too */ + free(prog); + + mingw_free_path_split(path); + /* TODO: if (cmd->env) free env; */ + + if (cmd->git_cmd) + strbuf_release(&git_cmd); + + cmd->argv[0] = sargv0; + if (s0 >= 0) + dup2(s0, 0), close(s0); + if (s1 >= 0) + dup2(s1, 1), close(s1); + if (s2 >= 0) + dup2(s2, 2), close(s2); +#endif + if (cmd->pid < 0) { if (need_in) close_pair(fdin); @@ -107,6 +207,19 @@ int start_command(struct child_process *cmd) return -ERR_RUN_COMMAND_FORK; } + if (need_in) + close(fdin[0]); + else if (cmd->in) + close(cmd->in); + + if (need_out) + close(fdout[1]); + else if (cmd->out > 1) + close(cmd->out); + + if (need_err) + close(fderr[1]); + return 0; } diff --git a/spawn-pipe.c b/spawn-pipe.c deleted file mode 100644 index e685eff643..0000000000 --- a/spawn-pipe.c +++ /dev/null @@ -1,169 +0,0 @@ -#include "git-compat-util.h" -#include "spawn-pipe.h" - - -/* cmd specifies the command to invoke. - * argv specifies its arguments; argv[0] will be replaced by the basename of cmd. - * env specifies the environment. - * pin and pout specify pipes; the read end of pin is made the standard input - * of the spawned process, and the write end of pout is mad the standard output. - * The respective unused ends of the pipes are closed both in the parent - * process as well as in the child process. - * Anyone of pin or pout can be NULL, or any one of the ends can be -1 to - * indicate that no processing shall occur. - */ -int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, - int pin[], int pout[]) -{ -#ifdef __MINGW32__ - char **path = mingw_get_path_split(); - - pid_t pid = spawnvppe_pipe(cmd, argv, env, path, pin, pout); - - mingw_free_path_split(path); -#else - pid_t pid = spawnvppe_pipe(cmd, argv, env, NULL, pin, pout); -#endif - return pid; -} - -int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, - char **path, - int pin[], int pout[]) -{ - const char *cmd_basename = strrchr(cmd, '/'); - const char *argv0 = argv[0]; - pid_t pid; - -#ifdef __MINGW32__ - int s0 = -1, s1 = -1, argc; - char *prog; - const char **qargv, *interpr; - - if (!cmd_basename) - cmd_basename = strrchr(cmd, '\\'); -#endif - - if (!cmd_basename) - cmd_basename = cmd; - else - cmd_basename++; - argv[0] = cmd_basename; - -#ifndef __MINGW32__ - pid = fork(); - if (pid < 0) - die("unable to fork"); - if (!pid) { - if (pin) { - if (pin[0] >= 0) { - dup2(pin[0], 0); - close(pin[0]); - } - if (pin[1] >= 0) - close(pin[1]); - } - if (pout) { - if (pout[1] >= 0) { - dup2(pout[1], 1); - close(pout[1]); - } - if (pout[0] >= 0) - close(pout[0]); - } - environ = env; - execvp(cmd, argv); - die("exec failed"); - } - - if (pin && pin[0] >= 0) - close(pin[0]); - if (pout && pout[1] >= 1) - close(pout[1]); -#else - if (pin) { - if (pin[0] >= 0) { - s0 = dup(0); - dup2(pin[0], 0); - close(pin[0]); - } - } - if (pout) { - if (pout[1] >= 0) { - s1 = dup(1); - dup2(pout[1], 1); - close(pout[1]); - } - } - - prog = mingw_path_lookup(cmd, path); - interpr = parse_interpreter(prog); - - for (argc = 0; argv[argc];) argc++; - qargv = xmalloc((argc+2)*sizeof(char*)); - if (!interpr) { - quote_argv(qargv, argv); - pid = spawnve(_P_NOWAIT, prog, qargv, env); - } else { - qargv[0] = interpr; - argv[0] = prog; - quote_argv(&qargv[1], argv); - pid = spawnvpe(_P_NOWAIT, interpr, qargv, env); - } - - free(qargv); /* TODO: quoted args should be freed, too */ - free(prog); - - if (s0 >= 0) { - dup2(s0, 0); - close(s0); - } - if (s1 >= 0) { - dup2(s1, 1); - close(s1); - } -#endif - - argv[0] = argv0; - - return pid; -} - -const char **copy_environ() -{ - return copy_env( (const char**)environ); -} - -const char **copy_env(const char **env) -{ - const char **s; - int n = 1; - for (s = env; *s; s++) - n++; - s = xmalloc(n*sizeof(const char *)); - memcpy(s, env, n*sizeof(const char *)); - return s; -} - -void env_unsetenv(const char **env, const char *name) -{ - int src, dst; - size_t nmln; - - nmln = strlen(name); - - for (src = dst = 0; env[src]; ++src) { - size_t enln; - enln = strlen(env[src]); - if (enln > nmln) { - /* might match, and can test for '=' safely */ - if (0 == strncmp (env[src], name, nmln) - && '=' == env[src][nmln]) - /* matches, so skip */ - continue; - } - env[dst] = env[src]; - ++dst; - } - env[dst] = NULL; -} diff --git a/spawn-pipe.h b/spawn-pipe.h deleted file mode 100644 index 3807819ae8..0000000000 --- a/spawn-pipe.h +++ /dev/null @@ -1,5 +0,0 @@ -int spawnvppe_pipe(const char *cmd, const char **argv, const char **env, char **path, int pin[], int pout[]); -int spawnvpe_pipe(const char *cmd, const char **argv, const char **env, int pin[], int pout[]); -const char **copy_environ(); -const char **copy_env(const char **env); -void env_unsetenv(const char **env, const char *name); diff --git a/upload-pack.c b/upload-pack.c index 115f7a1e56..75e2acb29e 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -142,10 +142,7 @@ static void create_pack_file(void) struct async rev_list; struct child_process pack_objects; int create_full_pack = (nr_our_refs == want_obj.nr && !have_obj.nr); - char data[8193]; -#ifndef __MINGW32__ - char progress[128]; -#endif + char data[8193], progress[128]; char abort_msg[] = "aborting due to possible repository " "corruption on the remote side."; int buffered = -1; @@ -177,7 +174,6 @@ static void create_pack_file(void) if (start_command(&pack_objects)) die("git-upload-pack: unable to fork git-pack-objects"); -#ifndef __MINGW32__ /* We read from pack_objects.err to capture stderr output for * progress bar, and pack_objects.out to capture the pack data. */ @@ -268,41 +264,6 @@ static void create_pack_file(void) goto fail; } } -#else - char *cp; - - /* We read from pack_objects.out to capture the pack data. */ - - while ((sz = xread(pack_objects.out, data+1, sizeof(data)-1)) > 0) { - cp = data+1; - /* Data ready; we keep the last byte to ourselves in case we - * detect broken rev-list, so that we can leave the stream - * corrupted. This is unfortunate -- unpack-objects would - * happily accept a valid pack data with trailing garbage, so - * appending garbage after we pass all the pack data is not - * good enough to signal breakage to downstream. - */ - if (0 <= buffered) { - *--cp = buffered; - sz++; - } - if (1 < sz) { - buffered = cp[sz-1] & 0xFF; - sz--; - } - else - buffered = -1; - sz = send_client_data(1, cp, sz); - if (sz < 0) - goto fail; - } - if (sz == 0) { - close(pack_objects.out); - pack_objects.out = -1; - } - else - goto fail; -#endif if (finish_command(&pack_objects)) { error("git-upload-pack: git-pack-objects died with error."); @@ -524,12 +485,10 @@ static void receive_needs(void) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) use_ofs_delta = 1; -#ifndef __MINGW32__ if (strstr(line+45, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; else if (strstr(line+45, "side-band")) use_sideband = DEFAULT_PACKET_MAX; -#endif if (strstr(line+45, "no-progress")) no_progress = 1;