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

5
int start_command(struct child_process *cmd)
6
{
7 8 9 10 11 12 13 14 15 16
	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;
	}

17
	cmd->pid = fork();
18 19 20 21 22
	if (cmd->pid < 0) {
		if (need_in) {
			close(fdin[0]);
			close(fdin[1]);
		}
23
		return -ERR_RUN_COMMAND_FORK;
24 25
	}

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

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

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

55 56 57 58 59
	return 0;
}

int finish_command(struct child_process *cmd)
{
60 61 62
	if (cmd->close_in)
		close(cmd->in);

63 64
	for (;;) {
		int status, code;
65
		pid_t waiting = waitpid(cmd->pid, &status, 0);
66

D
David Rientjes 已提交
67
		if (waiting < 0) {
68 69
			if (errno == EINTR)
				continue;
D
David Rientjes 已提交
70
			error("waitpid failed (%s)", strerror(errno));
71 72
			return -ERR_RUN_COMMAND_WAITPID;
		}
73
		if (waiting != cmd->pid)
74 75 76 77 78 79 80 81 82 83 84 85
			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;
	}
}
86

87 88 89 90 91 92 93 94
int run_command(struct child_process *cmd)
{
	int code = start_command(cmd);
	if (code)
		return code;
	return finish_command(cmd);
}

95 96 97 98 99 100 101 102 103 104
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);
}