run-command.c 2.0 KB
Newer Older
1 2
#include "cache.h"
#include "run-command.h"
3
#include "exec_cmd.h"
4

5 6 7 8 9 10
static inline void close_pair(int fd[2])
{
	close(fd[0]);
	close(fd[1]);
}

11
int start_command(struct child_process *cmd)
12
{
13 14 15 16 17 18 19 20 21 22
	int need_in = !cmd->no_stdin && cmd->in < 0;
	int fdin[2];

	if (need_in) {
		if (pipe(fdin) < 0)
			return -ERR_RUN_COMMAND_PIPE;
		cmd->in = fdin[1];
		cmd->close_in = 1;
	}

23
	cmd->pid = fork();
24
	if (cmd->pid < 0) {
25 26
		if (need_in)
			close_pair(fdin);
27
		return -ERR_RUN_COMMAND_FORK;
28 29
	}

30
	if (!cmd->pid) {
31
		if (cmd->no_stdin) {
32 33
			int fd = open("/dev/null", O_RDWR);
			dup2(fd, 0);
34
			close(fd);
35 36
		} else if (need_in) {
			dup2(fdin[0], 0);
37
			close_pair(fdin);
38 39 40
		} else if (cmd->in) {
			dup2(cmd->in, 0);
			close(cmd->in);
41
		}
42

43
		if (cmd->stdout_to_stderr)
44
			dup2(2, 1);
45 46
		if (cmd->git_cmd) {
			execv_git_cmd(cmd->argv);
47
		} else {
48
			execvp(cmd->argv[0], (char *const*) cmd->argv);
49
		}
50
		die("exec %s failed.", cmd->argv[0]);
51
	}
52 53 54 55 56 57

	if (need_in)
		close(fdin[0]);
	else if (cmd->in)
		close(cmd->in);

58 59 60 61 62
	return 0;
}

int finish_command(struct child_process *cmd)
{
63 64 65
	if (cmd->close_in)
		close(cmd->in);

66 67
	for (;;) {
		int status, code;
68
		pid_t waiting = waitpid(cmd->pid, &status, 0);
69

D
David Rientjes 已提交
70
		if (waiting < 0) {
71 72
			if (errno == EINTR)
				continue;
D
David Rientjes 已提交
73
			error("waitpid failed (%s)", strerror(errno));
74 75
			return -ERR_RUN_COMMAND_WAITPID;
		}
76
		if (waiting != cmd->pid)
77 78 79 80 81 82 83 84 85 86 87 88
			return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
		if (WIFSIGNALED(status))
			return -ERR_RUN_COMMAND_WAITPID_SIGNAL;

		if (!WIFEXITED(status))
			return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
		code = WEXITSTATUS(status);
		if (code)
			return -code;
		return 0;
	}
}
89

90 91 92 93 94 95 96 97
int run_command(struct child_process *cmd)
{
	int code = start_command(cmd);
	if (code)
		return code;
	return finish_command(cmd);
}

98 99 100 101 102 103 104 105 106 107
int run_command_v_opt(const char **argv, int opt)
{
	struct child_process cmd;
	memset(&cmd, 0, sizeof(cmd));
	cmd.argv = argv;
	cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
	cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
	cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
	return run_command(&cmd);
}