Home | History | Annotate | Download | only in util
      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