at v2.6.32 6.0 kB view raw
1#include "cache.h" 2#include "run-command.h" 3#include "exec_cmd.h" 4 5static inline void close_pair(int fd[2]) 6{ 7 close(fd[0]); 8 close(fd[1]); 9} 10 11static inline void dup_devnull(int to) 12{ 13 int fd = open("/dev/null", O_RDWR); 14 dup2(fd, to); 15 close(fd); 16} 17 18int 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 154static 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 185int finish_command(struct child_process *cmd) 186{ 187 return wait_or_whine(cmd->pid); 188} 189 190int 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 198static 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 209int 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 216int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env) 217{ 218 struct child_process cmd; 219 prepare_run_command_v_opt(&cmd, argv, opt); 220 cmd.dir = dir; 221 cmd.env = env; 222 return run_command(&cmd); 223} 224 225int start_async(struct async *async) 226{ 227 int pipe_out[2]; 228 229 if (pipe(pipe_out) < 0) 230 return error("cannot create pipe: %s", strerror(errno)); 231 async->out = pipe_out[0]; 232 233 /* Flush stdio before fork() to avoid cloning buffers */ 234 fflush(NULL); 235 236 async->pid = fork(); 237 if (async->pid < 0) { 238 error("fork (async) failed: %s", strerror(errno)); 239 close_pair(pipe_out); 240 return -1; 241 } 242 if (!async->pid) { 243 close(pipe_out[0]); 244 exit(!!async->proc(pipe_out[1], async->data)); 245 } 246 close(pipe_out[1]); 247 248 return 0; 249} 250 251int finish_async(struct async *async) 252{ 253 int ret = 0; 254 255 if (wait_or_whine(async->pid)) 256 ret = error("waitpid (async) failed"); 257 258 return ret; 259} 260 261int run_hook(const char *index_file, const char *name, ...) 262{ 263 struct child_process hook; 264 const char **argv = NULL, *env[2]; 265 char idx[PATH_MAX]; 266 va_list args; 267 int ret; 268 size_t i = 0, alloc = 0; 269 270 if (access(perf_path("hooks/%s", name), X_OK) < 0) 271 return 0; 272 273 va_start(args, name); 274 ALLOC_GROW(argv, i + 1, alloc); 275 argv[i++] = perf_path("hooks/%s", name); 276 while (argv[i-1]) { 277 ALLOC_GROW(argv, i + 1, alloc); 278 argv[i++] = va_arg(args, const char *); 279 } 280 va_end(args); 281 282 memset(&hook, 0, sizeof(hook)); 283 hook.argv = argv; 284 hook.no_stdin = 1; 285 hook.stdout_to_stderr = 1; 286 if (index_file) { 287 snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file); 288 env[0] = idx; 289 env[1] = NULL; 290 hook.env = env; 291 } 292 293 ret = start_command(&hook); 294 free(argv); 295 if (ret) { 296 warning("Could not spawn %s", argv[0]); 297 return ret; 298 } 299 ret = finish_command(&hook); 300 if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL) 301 warning("%s exited due to uncaught signal", argv[0]); 302 303 return ret; 304}