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