Merge branch 'sp/run-command'

* sp/run-command:
  Use run_command within send-pack
  Use run_command within receive-pack to invoke index-pack
  Use run_command within merge-index
  Use run_command for proxy connections
  Use RUN_GIT_CMD to run push backends
  Correct new compiler warnings in builtin-revert
  Replace fork_with_pipe in bundle with run_command
  Teach run-command to redirect stdout to /dev/null
  Teach run-command about stdout redirection
maint
Junio C Hamano 2007-03-18 22:21:06 -07:00
commit 3635a18770
11 changed files with 145 additions and 233 deletions

View File

@ -4,7 +4,7 @@
#include "diff.h" #include "diff.h"
#include "revision.h" #include "revision.h"
#include "list-objects.h" #include "list-objects.h"
#include "exec_cmd.h" #include "run-command.h"


/* /*
* Basic handler for bundle files to connect repositories via sneakernet. * Basic handler for bundle files to connect repositories via sneakernet.
@ -99,67 +99,6 @@ static int read_header(const char *path, struct bundle_header *header) {
return fd; return fd;
} }


/* if in && *in >= 0, take that as input file descriptor instead */
static int fork_with_pipe(const char **argv, int *in, int *out)
{
int needs_in, needs_out;
int fdin[2], fdout[2], pid;

needs_in = in && *in < 0;
if (needs_in) {
if (pipe(fdin) < 0)
return error("could not setup pipe");
*in = fdin[1];
}

needs_out = out && *out < 0;
if (needs_out) {
if (pipe(fdout) < 0)
return error("could not setup pipe");
*out = fdout[0];
}

if ((pid = fork()) < 0) {
if (needs_in) {
close(fdin[0]);
close(fdin[1]);
}
if (needs_out) {
close(fdout[0]);
close(fdout[1]);
}
return error("could not fork");
}
if (!pid) {
if (needs_in) {
dup2(fdin[0], 0);
close(fdin[0]);
close(fdin[1]);
} else if (in) {
dup2(*in, 0);
close(*in);
}
if (needs_out) {
dup2(fdout[1], 1);
close(fdout[0]);
close(fdout[1]);
} else if (out) {
dup2(*out, 1);
close(*out);
}
exit(execv_git_cmd(argv));
}
if (needs_in)
close(fdin[0]);
else if (in)
close(*in);
if (needs_out)
close(fdout[1]);
else if (out)
close(*out);
return pid;
}

static int list_refs(struct ref_list *r, int argc, const char **argv) static int list_refs(struct ref_list *r, int argc, const char **argv)
{ {
int i; int i;
@ -263,9 +202,10 @@ static int create_bundle(struct bundle_header *header, const char *path,
int bundle_fd = -1; int bundle_fd = -1;
const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *)); const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
const char **argv_pack = xmalloc(5 * sizeof(const char *)); const char **argv_pack = xmalloc(5 * sizeof(const char *));
int pid, in, out, i, status, ref_count = 0; int i, ref_count = 0;
char buffer[1024]; char buffer[1024];
struct rev_info revs; struct rev_info revs;
struct child_process rls;


bundle_fd = (!strcmp(path, "-") ? 1 : bundle_fd = (!strcmp(path, "-") ? 1 :
open(path, O_CREAT | O_EXCL | O_WRONLY, 0666)); open(path, O_CREAT | O_EXCL | O_WRONLY, 0666));
@ -285,11 +225,13 @@ static int create_bundle(struct bundle_header *header, const char *path,
argv_boundary[1] = "--boundary"; argv_boundary[1] = "--boundary";
argv_boundary[2] = "--pretty=oneline"; argv_boundary[2] = "--pretty=oneline";
argv_boundary[argc + 2] = NULL; argv_boundary[argc + 2] = NULL;
out = -1; memset(&rls, 0, sizeof(rls));
pid = fork_with_pipe(argv_boundary, NULL, &out); rls.argv = argv_boundary;
if (pid < 0) rls.out = -1;
rls.git_cmd = 1;
if (start_command(&rls))
return -1; return -1;
while ((i = read_string(out, buffer, sizeof(buffer))) > 0) { while ((i = read_string(rls.out, buffer, sizeof(buffer))) > 0) {
unsigned char sha1[20]; unsigned char sha1[20];
if (buffer[0] == '-') { if (buffer[0] == '-') {
write_or_die(bundle_fd, buffer, i); write_or_die(bundle_fd, buffer, i);
@ -303,11 +245,8 @@ static int create_bundle(struct bundle_header *header, const char *path,
object->flags |= SHOWN; object->flags |= SHOWN;
} }
} }
while ((i = waitpid(pid, &status, 0)) < 0) if (finish_command(&rls))
if (errno != EINTR) return error("rev-list died");
return error("rev-list died");
if (!WIFEXITED(status) || WEXITSTATUS(status))
return error("rev-list died %d", WEXITSTATUS(status));


/* write references */ /* write references */
argc = setup_revisions(argc, argv, &revs, NULL); argc = setup_revisions(argc, argv, &revs, NULL);
@ -352,26 +291,23 @@ static int create_bundle(struct bundle_header *header, const char *path,
argv_pack[2] = "--stdout"; argv_pack[2] = "--stdout";
argv_pack[3] = "--thin"; argv_pack[3] = "--thin";
argv_pack[4] = NULL; argv_pack[4] = NULL;
in = -1; memset(&rls, 0, sizeof(rls));
out = bundle_fd; rls.argv = argv_pack;
pid = fork_with_pipe(argv_pack, &in, &out); rls.in = -1;
if (pid < 0) rls.out = bundle_fd;
rls.git_cmd = 1;
if (start_command(&rls))
return error("Could not spawn pack-objects"); return error("Could not spawn pack-objects");
for (i = 0; i < revs.pending.nr; i++) { for (i = 0; i < revs.pending.nr; i++) {
struct object *object = revs.pending.objects[i].item; struct object *object = revs.pending.objects[i].item;
if (object->flags & UNINTERESTING) if (object->flags & UNINTERESTING)
write(in, "^", 1); write(rls.in, "^", 1);
write(in, sha1_to_hex(object->sha1), 40); write(rls.in, sha1_to_hex(object->sha1), 40);
write(in, "\n", 1); write(rls.in, "\n", 1);
} }
close(in); if (finish_command(&rls))
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
return -1;
if (!WIFEXITED(status) || WEXITSTATUS(status))
return error ("pack-objects died"); return error ("pack-objects died");

return 0;
return status;
} }


static int unbundle(struct bundle_header *header, int bundle_fd, static int unbundle(struct bundle_header *header, int bundle_fd,
@ -379,22 +315,17 @@ static int unbundle(struct bundle_header *header, int bundle_fd,
{ {
const char *argv_index_pack[] = {"index-pack", const char *argv_index_pack[] = {"index-pack",
"--fix-thin", "--stdin", NULL}; "--fix-thin", "--stdin", NULL};
int pid, status, dev_null; struct child_process ip;


if (verify_bundle(header, 0)) if (verify_bundle(header, 0))
return -1; return -1;
dev_null = open("/dev/null", O_WRONLY); memset(&ip, 0, sizeof(ip));
if (dev_null < 0) ip.argv = argv_index_pack;
return error("Could not open /dev/null"); ip.in = bundle_fd;
pid = fork_with_pipe(argv_index_pack, &bundle_fd, &dev_null); ip.no_stdout = 1;
if (pid < 0) ip.git_cmd = 1;
return error("Could not spawn index-pack"); if (run_command(&ip))
while (waitpid(pid, &status, 0) < 0) return error("index-pack died");
if (errno != EINTR)
return error("index-pack died");
if (!WIFEXITED(status) || WEXITSTATUS(status))
return error("index-pack exited with status %d",
WEXITSTATUS(status));
return list_heads(header, argc, argv); return list_heads(header, argc, argv);
} }



View File

@ -323,10 +323,10 @@ static int do_push(const char *repo)
int dest_refspec_nr = refspec_nr; int dest_refspec_nr = refspec_nr;
const char **dest_refspec = refspec; const char **dest_refspec = refspec;
const char *dest = uri[i]; const char *dest = uri[i];
const char *sender = "git-send-pack"; const char *sender = "send-pack";
if (!prefixcmp(dest, "http://") || if (!prefixcmp(dest, "http://") ||
!prefixcmp(dest, "https://")) !prefixcmp(dest, "https://"))
sender = "git-http-push"; sender = "http-push";
else if (thin) else if (thin)
argv[dest_argc++] = "--thin"; argv[dest_argc++] = "--thin";
argv[0] = sender; argv[0] = sender;
@ -336,7 +336,7 @@ static int do_push(const char *repo)
argv[dest_argc] = NULL; argv[dest_argc] = NULL;
if (verbose) if (verbose)
fprintf(stderr, "Pushing to %s\n", dest); fprintf(stderr, "Pushing to %s\n", dest);
err = run_command_v_opt(argv, 0); err = run_command_v_opt(argv, RUN_GIT_CMD);
if (!err) if (!err)
continue; continue;
switch (err) { switch (err) {

View File

@ -235,8 +235,8 @@ static int revert_or_cherry_pick(int argc, const char **argv)
unsigned char head[20]; unsigned char head[20];
struct commit *base, *next; struct commit *base, *next;
int i; int i;
char *oneline, *encoding, *reencoded_message = NULL; char *oneline, *reencoded_message = NULL;
const char *message; const char *message, *encoding;


git_config(git_default_config); git_config(git_default_config);
me = action == REVERT ? "revert" : "cherry-pick"; me = action == REVERT ? "revert" : "cherry-pick";

View File

@ -451,7 +451,7 @@ extern int check_repository_format_version(const char *var, const char *value);
extern char git_default_email[MAX_GITNAME]; extern char git_default_email[MAX_GITNAME];
extern char git_default_name[MAX_GITNAME]; extern char git_default_name[MAX_GITNAME];


extern char *git_commit_encoding; extern const char *git_commit_encoding;
extern const char *git_log_output_encoding; extern const char *git_log_output_encoding;


extern int copy_fd(int ifd, int ofd); extern int copy_fd(int ifd, int ofd);

View File

@ -3,6 +3,7 @@
#include "pkt-line.h" #include "pkt-line.h"
#include "quote.h" #include "quote.h"
#include "refs.h" #include "refs.h"
#include "run-command.h"


static char *server_capabilities; static char *server_capabilities;


@ -598,8 +599,8 @@ static void git_proxy_connect(int fd[2], char *host)
{ {
const char *port = STR(DEFAULT_GIT_PORT); const char *port = STR(DEFAULT_GIT_PORT);
char *colon, *end; char *colon, *end;
int pipefd[2][2]; const char *argv[4];
pid_t pid; struct child_process proxy;


if (host[0] == '[') { if (host[0] == '[') {
end = strchr(host + 1, ']'); end = strchr(host + 1, ']');
@ -618,25 +619,18 @@ static void git_proxy_connect(int fd[2], char *host)
port = colon + 1; port = colon + 1;
} }


if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0) argv[0] = git_proxy_command;
die("unable to create pipe pair for communication"); argv[1] = host;
pid = fork(); argv[2] = port;
if (!pid) { argv[3] = NULL;
dup2(pipefd[1][0], 0); memset(&proxy, 0, sizeof(proxy));
dup2(pipefd[0][1], 1); proxy.argv = argv;
close(pipefd[0][0]); proxy.in = -1;
close(pipefd[0][1]); proxy.out = -1;
close(pipefd[1][0]); if (start_command(&proxy))
close(pipefd[1][1]); die("cannot start proxy %s", argv[0]);
execlp(git_proxy_command, git_proxy_command, host, port, NULL); fd[0] = proxy.out; /* read from proxy stdout */
die("exec failed"); fd[1] = proxy.in; /* write to proxy stdin */
}
if (pid < 0)
die("fork failed");
fd[0] = pipefd[0][0];
fd[1] = pipefd[1][1];
close(pipefd[0][1]);
close(pipefd[1][0]);
} }


#define MAX_CMD_LEN 1024 #define MAX_CMD_LEN 1024

View File

@ -20,7 +20,7 @@ int is_bare_repository_cfg = -1; /* unspecified */
int log_all_ref_updates = -1; /* unspecified */ int log_all_ref_updates = -1; /* unspecified */
int warn_ambiguous_refs = 1; int warn_ambiguous_refs = 1;
int repository_format_version; int repository_format_version;
char *git_commit_encoding; const char *git_commit_encoding;
const char *git_log_output_encoding; const char *git_log_output_encoding;
int shared_repository = PERM_UMASK; int shared_repository = PERM_UMASK;
const char *apply_default_whitespace; const char *apply_default_whitespace;

View File

@ -1,4 +1,5 @@
#include "cache.h" #include "cache.h"
#include "run-command.h"


static const char *pgm; static const char *pgm;
static const char *arguments[8]; static const char *arguments[8];
@ -7,24 +8,10 @@ static int err;


static void run_program(void) static void run_program(void)
{ {
pid_t pid = fork(); struct child_process child;
int status; memset(&child, 0, sizeof(child));

child.argv = arguments;
if (pid < 0) if (run_command(&child)) {
die("unable to fork");
if (!pid) {
execlp(pgm, arguments[0],
arguments[1],
arguments[2],
arguments[3],
arguments[4],
arguments[5],
arguments[6],
arguments[7],
NULL);
die("unable to execute '%s'", pgm);
}
if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) {
if (one_shot) { if (one_shot) {
err++; err++;
} else { } else {

View File

@ -382,10 +382,10 @@ static const char *unpack(void)
} }
} else { } else {
const char *keeper[6]; const char *keeper[6];
int fd[2], s, len, status; int s, len, status;
pid_t pid;
char keep_arg[256]; char keep_arg[256];
char packname[46]; char packname[46];
struct child_process ip;


s = sprintf(keep_arg, "--keep=receive-pack %i on ", getpid()); s = sprintf(keep_arg, "--keep=receive-pack %i on ", getpid());
if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) if (gethostname(keep_arg + s, sizeof(keep_arg) - s))
@ -397,20 +397,12 @@ static const char *unpack(void)
keeper[3] = hdr_arg; keeper[3] = hdr_arg;
keeper[4] = keep_arg; keeper[4] = keep_arg;
keeper[5] = NULL; keeper[5] = NULL;

memset(&ip, 0, sizeof(ip));
if (pipe(fd) < 0) ip.argv = keeper;
return "index-pack pipe failed"; ip.out = -1;
pid = fork(); ip.git_cmd = 1;
if (pid < 0) if (start_command(&ip))
return "index-pack fork failed"; return "index-pack fork failed";
if (!pid) {
dup2(fd[1], 1);
close(fd[1]);
close(fd[0]);
execv_git_cmd(keeper);
die("execv of index-pack failed");
}
close(fd[1]);


/* /*
* The first thing we expects from index-pack's output * The first thing we expects from index-pack's output
@ -420,9 +412,8 @@ static const char *unpack(void)
* later on. If we don't get that then tough luck with it. * later on. If we don't get that then tough luck with it.
*/ */
for (len = 0; for (len = 0;
len < 46 && (s = xread(fd[0], packname+len, 46-len)) > 0; len < 46 && (s = xread(ip.out, packname+len, 46-len)) > 0;
len += s); len += s);
close(fd[0]);
if (len == 46 && packname[45] == '\n' && if (len == 46 && packname[45] == '\n' &&
memcmp(packname, "keep\t", 5) == 0) { memcmp(packname, "keep\t", 5) == 0) {
char path[PATH_MAX]; char path[PATH_MAX];
@ -432,14 +423,8 @@ static const char *unpack(void)
pack_lockfile = xstrdup(path); pack_lockfile = xstrdup(path);
} }


/* Then wrap our index-pack process. */ status = finish_command(&ip);
while (waitpid(pid, &status, 0) < 0) if (!status) {
if (errno != EINTR)
return "waitpid failed";
if (WIFEXITED(status)) {
int code = WEXITSTATUS(status);
if (code)
return "index-pack exited with error code";
reprepare_packed_git(); reprepare_packed_git();
return NULL; return NULL;
} }

View File

@ -8,11 +8,19 @@ static inline void close_pair(int fd[2])
close(fd[1]); 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 start_command(struct child_process *cmd)
{ {
int need_in = !cmd->no_stdin && cmd->in < 0; int need_in, need_out;
int fdin[2]; int fdin[2], fdout[2];


need_in = !cmd->no_stdin && cmd->in < 0;
if (need_in) { if (need_in) {
if (pipe(fdin) < 0) if (pipe(fdin) < 0)
return -ERR_RUN_COMMAND_PIPE; return -ERR_RUN_COMMAND_PIPE;
@ -20,19 +28,32 @@ int start_command(struct child_process *cmd)
cmd->close_in = 1; cmd->close_in = 1;
} }


need_out = !cmd->no_stdout
&& !cmd->stdout_to_stderr
&& cmd->out < 0;
if (need_out) {
if (pipe(fdout) < 0) {
if (need_in)
close_pair(fdin);
return -ERR_RUN_COMMAND_PIPE;
}
cmd->out = fdout[0];
cmd->close_out = 1;
}

cmd->pid = fork(); cmd->pid = fork();
if (cmd->pid < 0) { if (cmd->pid < 0) {
if (need_in) if (need_in)
close_pair(fdin); close_pair(fdin);
if (need_out)
close_pair(fdout);
return -ERR_RUN_COMMAND_FORK; return -ERR_RUN_COMMAND_FORK;
} }


if (!cmd->pid) { if (!cmd->pid) {
if (cmd->no_stdin) { if (cmd->no_stdin)
int fd = open("/dev/null", O_RDWR); dup_devnull(0);
dup2(fd, 0); else if (need_in) {
close(fd);
} else if (need_in) {
dup2(fdin[0], 0); dup2(fdin[0], 0);
close_pair(fdin); close_pair(fdin);
} else if (cmd->in) { } else if (cmd->in) {
@ -40,8 +61,18 @@ int start_command(struct child_process *cmd)
close(cmd->in); close(cmd->in);
} }


if (cmd->stdout_to_stderr) if (cmd->no_stdout)
dup_devnull(1);
else if (cmd->stdout_to_stderr)
dup2(2, 1); dup2(2, 1);
else if (need_out) {
dup2(fdout[1], 1);
close_pair(fdout);
} else if (cmd->out > 1) {
dup2(cmd->out, 1);
close(cmd->out);
}

if (cmd->git_cmd) { if (cmd->git_cmd) {
execv_git_cmd(cmd->argv); execv_git_cmd(cmd->argv);
} else { } else {
@ -55,6 +86,11 @@ int start_command(struct child_process *cmd)
else if (cmd->in) else if (cmd->in)
close(cmd->in); close(cmd->in);


if (need_out)
close(fdout[1]);
else if (cmd->out > 1)
close(cmd->out);

return 0; return 0;
} }


@ -62,6 +98,8 @@ int finish_command(struct child_process *cmd)
{ {
if (cmd->close_in) if (cmd->close_in)
close(cmd->in); close(cmd->in);
if (cmd->close_out)
close(cmd->out);


for (;;) { for (;;) {
int status, code; int status, code;

View File

@ -15,8 +15,11 @@ struct child_process {
const char **argv; const char **argv;
pid_t pid; pid_t pid;
int in; int in;
int out;
unsigned close_in:1; unsigned close_in:1;
unsigned close_out:1;
unsigned no_stdin:1; unsigned no_stdin:1;
unsigned no_stdout:1;
unsigned git_cmd:1; /* if this is to be git sub-command */ unsigned git_cmd:1; /* if this is to be git sub-command */
unsigned stdout_to_stderr:1; unsigned stdout_to_stderr:1;
}; };

View File

@ -3,7 +3,7 @@
#include "tag.h" #include "tag.h"
#include "refs.h" #include "refs.h"
#include "pkt-line.h" #include "pkt-line.h"
#include "exec_cmd.h" #include "run-command.h"


static const char send_pack_usage[] = static const char send_pack_usage[] =
"git-send-pack [--all] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" "git-send-pack [--all] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@ -19,46 +19,35 @@ static int use_thin_pack;
*/ */
static int pack_objects(int fd, struct ref *refs) static int pack_objects(int fd, struct ref *refs)
{ {
int pipe_fd[2]; /*
pid_t pid; * The child becomes pack-objects --revs; we feed
* the revision parameters to it via its stdin and
* let its stdout go back to the other end.
*/
const char *args[] = {
"pack-objects",
"--all-progress",
"--revs",
"--stdout",
NULL,
NULL,
};
struct child_process po;


if (pipe(pipe_fd) < 0) if (use_thin_pack)
return error("send-pack: pipe failed"); args[4] = "--thin";
pid = fork(); memset(&po, 0, sizeof(po));
if (pid < 0) po.argv = args;
return error("send-pack: unable to fork git-pack-objects"); po.in = -1;
if (!pid) { po.out = fd;
/* po.git_cmd = 1;
* The child becomes pack-objects --revs; we feed if (start_command(&po))
* the revision parameters to it via its stdin and die("git-pack-objects failed (%s)", strerror(errno));
* let its stdout go back to the other end.
*/
static const char *args[] = {
"pack-objects",
"--all-progress",
"--revs",
"--stdout",
NULL,
NULL,
};
if (use_thin_pack)
args[4] = "--thin";
dup2(pipe_fd[0], 0);
dup2(fd, 1);
close(pipe_fd[0]);
close(pipe_fd[1]);
close(fd);
execv_git_cmd(args);
die("git-pack-objects exec failed (%s)", strerror(errno));
}


/* /*
* We feed the pack-objects we just spawned with revision * We feed the pack-objects we just spawned with revision
* parameters by writing to the pipe. * parameters by writing to the pipe.
*/ */
close(pipe_fd[0]);
close(fd);

while (refs) { while (refs) {
char buf[42]; char buf[42];


@ -67,38 +56,23 @@ static int pack_objects(int fd, struct ref *refs)
memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40); memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
buf[0] = '^'; buf[0] = '^';
buf[41] = '\n'; buf[41] = '\n';
if (!write_or_whine(pipe_fd[1], buf, 42, if (!write_or_whine(po.in, buf, 42,
"send-pack: send refs")) "send-pack: send refs"))
break; break;
} }
if (!is_null_sha1(refs->new_sha1)) { if (!is_null_sha1(refs->new_sha1)) {
memcpy(buf, sha1_to_hex(refs->new_sha1), 40); memcpy(buf, sha1_to_hex(refs->new_sha1), 40);
buf[40] = '\n'; buf[40] = '\n';
if (!write_or_whine(pipe_fd[1], buf, 41, if (!write_or_whine(po.in, buf, 41,
"send-pack: send refs")) "send-pack: send refs"))
break; break;
} }
refs = refs->next; refs = refs->next;
} }
close(pipe_fd[1]);


for (;;) { if (finish_command(&po))
int status, code; return error("pack-objects died with strange error");
pid_t waiting = waitpid(pid, &status, 0); return 0;

if (waiting < 0) {
if (errno == EINTR)
continue;
return error("waitpid failed (%s)", strerror(errno));
}
if ((waiting != pid) || WIFSIGNALED(status) ||
!WIFEXITED(status))
return error("pack-objects died with strange error");
code = WEXITSTATUS(status);
if (code)
return -code;
return 0;
}
} }


static void unmark_and_free(struct commit_list *list, unsigned int mark) static void unmark_and_free(struct commit_list *list, unsigned int mark)