]>
Commit | Line | Data |
---|---|---|
b1bf95bb JW |
1 | #include "cache.h" |
2 | #include "run-command.h" | |
77cb17e9 | 3 | #include "exec_cmd.h" |
b1bf95bb | 4 | |
9dc09c76 SP |
5 | static inline void close_pair(int fd[2]) |
6 | { | |
7 | close(fd[0]); | |
8 | close(fd[1]); | |
9 | } | |
10 | ||
ebcb5d16 | 11 | int start_command(struct child_process *cmd) |
b1bf95bb | 12 | { |
4919bf03 SP |
13 | int need_in = !cmd->no_stdin && cmd->in < 0; |
14 | int fdin[2]; | |
15 | ||
16 | if (need_in) { | |
17 | if (pipe(fdin) < 0) | |
18 | return -ERR_RUN_COMMAND_PIPE; | |
19 | cmd->in = fdin[1]; | |
20 | cmd->close_in = 1; | |
21 | } | |
22 | ||
ebcb5d16 | 23 | cmd->pid = fork(); |
4919bf03 | 24 | if (cmd->pid < 0) { |
9dc09c76 SP |
25 | if (need_in) |
26 | close_pair(fdin); | |
b1bf95bb | 27 | return -ERR_RUN_COMMAND_FORK; |
4919bf03 SP |
28 | } |
29 | ||
ebcb5d16 | 30 | if (!cmd->pid) { |
f1000898 | 31 | if (cmd->no_stdin) { |
128aed68 DB |
32 | int fd = open("/dev/null", O_RDWR); |
33 | dup2(fd, 0); | |
77cb17e9 | 34 | close(fd); |
4919bf03 SP |
35 | } else if (need_in) { |
36 | dup2(fdin[0], 0); | |
9dc09c76 | 37 | close_pair(fdin); |
4919bf03 SP |
38 | } else if (cmd->in) { |
39 | dup2(cmd->in, 0); | |
40 | close(cmd->in); | |
95d3c4f5 | 41 | } |
4919bf03 | 42 | |
f1000898 | 43 | if (cmd->stdout_to_stderr) |
cd83c74c | 44 | dup2(2, 1); |
f1000898 SP |
45 | if (cmd->git_cmd) { |
46 | execv_git_cmd(cmd->argv); | |
77cb17e9 | 47 | } else { |
f1000898 | 48 | execvp(cmd->argv[0], (char *const*) cmd->argv); |
128aed68 | 49 | } |
f1000898 | 50 | die("exec %s failed.", cmd->argv[0]); |
b1bf95bb | 51 | } |
4919bf03 SP |
52 | |
53 | if (need_in) | |
54 | close(fdin[0]); | |
55 | else if (cmd->in) | |
56 | close(cmd->in); | |
57 | ||
ebcb5d16 SP |
58 | return 0; |
59 | } | |
60 | ||
61 | int finish_command(struct child_process *cmd) | |
62 | { | |
4919bf03 SP |
63 | if (cmd->close_in) |
64 | close(cmd->in); | |
65 | ||
b1bf95bb JW |
66 | for (;;) { |
67 | int status, code; | |
ebcb5d16 | 68 | pid_t waiting = waitpid(cmd->pid, &status, 0); |
b1bf95bb | 69 | |
6f002f98 | 70 | if (waiting < 0) { |
b1bf95bb JW |
71 | if (errno == EINTR) |
72 | continue; | |
6f002f98 | 73 | error("waitpid failed (%s)", strerror(errno)); |
b1bf95bb JW |
74 | return -ERR_RUN_COMMAND_WAITPID; |
75 | } | |
ebcb5d16 | 76 | if (waiting != cmd->pid) |
b1bf95bb JW |
77 | return -ERR_RUN_COMMAND_WAITPID_WRONG_PID; |
78 | if (WIFSIGNALED(status)) | |
79 | return -ERR_RUN_COMMAND_WAITPID_SIGNAL; | |
80 | ||
81 | if (!WIFEXITED(status)) | |
82 | return -ERR_RUN_COMMAND_WAITPID_NOEXIT; | |
83 | code = WEXITSTATUS(status); | |
84 | if (code) | |
85 | return -code; | |
86 | return 0; | |
87 | } | |
88 | } | |
f1000898 | 89 | |
ebcb5d16 SP |
90 | int run_command(struct child_process *cmd) |
91 | { | |
92 | int code = start_command(cmd); | |
93 | if (code) | |
94 | return code; | |
95 | return finish_command(cmd); | |
96 | } | |
97 | ||
f1000898 SP |
98 | int run_command_v_opt(const char **argv, int opt) |
99 | { | |
100 | struct child_process cmd; | |
101 | memset(&cmd, 0, sizeof(cmd)); | |
102 | cmd.argv = argv; | |
103 | cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0; | |
104 | cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0; | |
105 | cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0; | |
106 | return run_command(&cmd); | |
107 | } |