1 #include "cache.h" 2 #include "run-command.h" 3 #include "exec_cmd.h" 4 5 static inline void close_pair(int fd[2]) 6 { 7 close(fd[0]); 8 close(fd[1]); 9 } 10 11 static inline void dup_devnull(int to) 12 { 13 int fd = open("/dev/null", O_RDWR); 14 dup2(fd, to); 15 close(fd); 16 } 17 18 int start_command(struct child_process *cmd) 19 { 20 int need_in, need_out, need_err; 21 int fdin[2], fdout[2], fderr[2]; 22 23 /* 24 * In case of errors we must keep the promise to close FDs 25 * that have been passed in via ->in and ->out. 26 */ 27 28 need_in = !cmd->no_stdin && cmd->in < 0; 29 if (need_in) { 30 if (pipe(fdin) < 0) { 31 if (cmd->out > 0) 32 close(cmd->out); 33 return -ERR_RUN_COMMAND_PIPE; 34 } 35 cmd->in = fdin[1]; 36 } 37 38 need_out = !cmd->no_stdout 39 && !cmd->stdout_to_stderr 40 && cmd->out < 0; 41 if (need_out) { 42 if (pipe(fdout) < 0) { 43 if (need_in) 44 close_pair(fdin); 45 else if (cmd->in) 46 close(cmd->in); 47 return -ERR_RUN_COMMAND_PIPE; 48 } 49 cmd->out = fdout[0]; 50 } 51 52 need_err = !cmd->no_stderr && cmd->err < 0; 53 if (need_err) { 54 if (pipe(fderr) < 0) { 55 if (need_in) 56 close_pair(fdin); 57 else if (cmd->in) 58 close(cmd->in); 59 if (need_out) 60 close_pair(fdout); 61 else if (cmd->out) 62 close(cmd->out); 63 return -ERR_RUN_COMMAND_PIPE; 64 } 65 cmd->err = fderr[0]; 66 } 67 68 fflush(NULL); 69 cmd->pid = fork(); 70 if (!cmd->pid) { 71 if (cmd->no_stdin) 72 dup_devnull(0); 73 else if (need_in) { 74 dup2(fdin[0], 0); 75 close_pair(fdin); 76 } else if (cmd->in) { 77 dup2(cmd->in, 0); 78 close(cmd->in); 79 } 80 81 if (cmd->no_stderr) 82 dup_devnull(2); 83 else if (need_err) { 84 dup2(fderr[1], 2); 85 close_pair(fderr); 86 } 87 88 if (cmd->no_stdout) 89 dup_devnull(1); 90 else if (cmd->stdout_to_stderr) 91 dup2(2, 1); 92 else if (need_out) { 93 dup2(fdout[1], 1); 94 close_pair(fdout); 95 } else if (cmd->out > 1) { 96 dup2(cmd->out, 1); 97 close(cmd->out); 98 } 99 100 if (cmd->dir && chdir(cmd->dir)) 101 die("exec %s: cd to %s failed (%s)", cmd->argv[0], 102 cmd->dir, strerror(errno)); 103 if (cmd->env) { 104 for (; *cmd->env; cmd->env++) { 105 if (strchr(*cmd->env, '=')) 106 putenv((char*)*cmd->env); 107 else 108 unsetenv(*cmd->env); 109 } 110 } 111 if (cmd->preexec_cb) 112 cmd->preexec_cb(); 113 if (cmd->perf_cmd) { 114 execv_perf_cmd(cmd->argv); 115 } else { 116 execvp(cmd->argv[0], (char *const*) cmd->argv); 117 } 118 exit(127); 119 } 120 121 if (cmd->pid < 0) { 122 int err = errno; 123 if (need_in) 124 close_pair(fdin); 125 else if (cmd->in) 126 close(cmd->in); 127 if (need_out) 128 close_pair(fdout); 129 else if (cmd->out) 130 close(cmd->out); 131 if (need_err) 132 close_pair(fderr); 133 return err == ENOENT ? 134 -ERR_RUN_COMMAND_EXEC : 135 -ERR_RUN_COMMAND_FORK; 136 } 137 138 if (need_in) 139 close(fdin[0]); 140 else if (cmd->in) 141 close(cmd->in); 142 143 if (need_out) 144 close(fdout[1]); 145 else if (cmd->out) 146 close(cmd->out); 147 148 if (need_err) 149 close(fderr[1]); 150 151 return 0; 152 } 153 154 static int wait_or_whine(pid_t pid) 155 { 156 for (;;) { 157 int status, code; 158 pid_t waiting = waitpid(pid, &status, 0); 159 160 if (waiting < 0) { 161 if (errno == EINTR) 162 continue; 163 error("waitpid failed (%s)", strerror(errno)); 164 return -ERR_RUN_COMMAND_WAITPID; 165 } 166 if (waiting != pid) 167 return -ERR_RUN_COMMAND_WAITPID_WRONG_PID; 168 if (WIFSIGNALED(status)) 169 return -ERR_RUN_COMMAND_WAITPID_SIGNAL; 170 171 if (!WIFEXITED(status)) 172 return -ERR_RUN_COMMAND_WAITPID_NOEXIT; 173 code = WEXITSTATUS(status); 174 switch (code) { 175 case 127: 176 return -ERR_RUN_COMMAND_EXEC; 177 case 0: 178 return 0; 179 default: 180 return -code; 181 } 182 } 183 } 184 185 int finish_command(struct child_process *cmd) 186 { 187 return wait_or_whine(cmd->pid); 188 } 189 190 int run_command(struct child_process *cmd) 191 { 192 int code = start_command(cmd); 193 if (code) 194 return code; 195 return finish_command(cmd); 196 } 197 198 static void prepare_run_command_v_opt(struct child_process *cmd, 199 const char **argv, 200 int opt) 201 { 202 memset(cmd, 0, sizeof(*cmd)); 203 cmd->argv = argv; 204 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0; 205 cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0; 206 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0; 207 } 208 209 int run_command_v_opt(const char **argv, int opt) 210 { 211 struct child_process cmd; 212 prepare_run_command_v_opt(&cmd, argv, opt); 213 return run_command(&cmd); 214 } 215