1 // SPDX-License-Identifier: GPL-2.0 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <ctype.h> 6 #include <fcntl.h> 7 #include <string.h> 8 #include <linux/string.h> 9 #include <errno.h> 10 #include <sys/wait.h> 11 #include "subcmd-util.h" 12 #include "run-command.h" 13 #include "exec-cmd.h" 14 15 #define STRERR_BUFSIZE 128 16 17 static inline void close_pair(int fd[2]) 18 { 19 close(fd[0]); 20 close(fd[1]); 21 } 22 23 static inline void dup_devnull(int to) 24 { 25 int fd = open("/dev/null", O_RDWR); 26 dup2(fd, to); 27 close(fd); 28 } 29 30 int start_command(struct child_process *cmd) 31 { 32 int need_in, need_out, need_err; 33 int fdin[2], fdout[2], fderr[2]; 34 char sbuf[STRERR_BUFSIZE]; 35 36 /* 37 * In case of errors we must keep the promise to close FDs 38 * that have been passed in via ->in and ->out. 39 */ 40 41 need_in = !cmd->no_stdin && cmd->in < 0; 42 if (need_in) { 43 if (pipe(fdin) < 0) { 44 if (cmd->out > 0) 45 close(cmd->out); 46 return -ERR_RUN_COMMAND_PIPE; 47 } 48 cmd->in = fdin[1]; 49 } 50 51 need_out = !cmd->no_stdout 52 && !cmd->stdout_to_stderr 53 && cmd->out < 0; 54 if (need_out) { 55 if (pipe(fdout) < 0) { 56 if (need_in) 57 close_pair(fdin); 58 else if (cmd->in) 59 close(cmd->in); 60 return -ERR_RUN_COMMAND_PIPE; 61 } 62 cmd->out = fdout[0]; 63 } 64 65 need_err = !cmd->no_stderr && cmd->err < 0; 66 if (need_err) { 67 if (pipe(fderr) < 0) { 68 if (need_in) 69 close_pair(fdin); 70 else if (cmd->in) 71 close(cmd->in); 72 if (need_out) 73 close_pair(fdout); 74 else if (cmd->out) 75 close(cmd->out); 76 return -ERR_RUN_COMMAND_PIPE; 77 } 78 cmd->err = fderr[0]; 79 } 80 81 fflush(NULL); 82 cmd->pid = fork(); 83 if (!cmd->pid) { 84 if (cmd->no_stdin) 85 dup_devnull(0); 86 else if (need_in) { 87 dup2(fdin[0], 0); 88 close_pair(fdin); 89 } else if (cmd->in) { 90 dup2(cmd->in, 0); 91 close(cmd->in); 92 } 93 94 if (cmd->no_stderr) 95 dup_devnull(2); 96 else if (need_err) { 97 dup2(fderr[1], 2); 98 close_pair(fderr); 99 } 100 101 if (cmd->no_stdout) 102 dup_devnull(1); 103 else if (cmd->stdout_to_stderr) 104 dup2(2, 1); 105 else if (need_out) { 106 dup2(fdout[1], 1); 107 close_pair(fdout); 108 } else if (cmd->out > 1) { 109 dup2(cmd->out, 1); 110 close(cmd->out); 111 } 112 113 if (cmd->dir && chdir(cmd->dir)) 114 die("exec %s: cd to %s failed (%s)", cmd->argv[0], 115 cmd->dir, str_error_r(errno, sbuf, sizeof(sbuf))); 116 if (cmd->env) { 117 for (; *cmd->env; cmd->env++) { 118 if (strchr(*cmd->env, '=')) 119 putenv((char*)*cmd->env); 120 else 121 unsetenv(*cmd->env); 122 } 123 } 124 if (cmd->preexec_cb) 125 cmd->preexec_cb(); 126 if (cmd->no_exec_cmd) 127 exit(cmd->no_exec_cmd(cmd)); 128 if (cmd->exec_cmd) { 129 execv_cmd(cmd->argv); 130 } else { 131 execvp(cmd->argv[0], (char *const*) cmd->argv); 132 } 133 exit(127); 134 } 135 136 if (cmd->pid < 0) { 137 int err = errno; 138 if (need_in) 139 close_pair(fdin); 140 else if (cmd->in) 141 close(cmd->in); 142 if (need_out) 143 close_pair(fdout); 144 else if (cmd->out) 145 close(cmd->out); 146 if (need_err) 147 close_pair(fderr); 148 return err == ENOENT ? 149 -ERR_RUN_COMMAND_EXEC : 150 -ERR_RUN_COMMAND_FORK; 151 } 152 153 if (need_in) 154 close(fdin[0]); 155 else if (cmd->in) 156 close(cmd->in); 157 158 if (need_out) 159 close(fdout[1]); 160 else if (cmd->out) 161 close(cmd->out); 162 163 if (need_err) 164 close(fderr[1]); 165 166 return 0; 167 } 168 169 static int wait_or_whine(struct child_process *cmd, bool block) 170 { 171 bool finished = cmd->finished; 172 int result = cmd->finish_result; 173 174 while (!finished) { 175 int status, code; 176 pid_t waiting = waitpid(cmd->pid, &status, block ? 0 : WNOHANG); 177 178 if (!block && waiting == 0) 179 break; 180 181 if (waiting < 0 && errno == EINTR) 182 continue; 183 184 finished = true; 185 if (waiting < 0) { 186 char sbuf[STRERR_BUFSIZE]; 187 188 fprintf(stderr, " Error: waitpid failed (%s)", 189 str_error_r(errno, sbuf, sizeof(sbuf))); 190 result = -ERR_RUN_COMMAND_WAITPID; 191 } else if (waiting != cmd->pid) { 192 result = -ERR_RUN_COMMAND_WAITPID_WRONG_PID; 193 } else if (WIFSIGNALED(status)) { 194 result = -ERR_RUN_COMMAND_WAITPID_SIGNAL; 195 } else if (!WIFEXITED(status)) { 196 result = -ERR_RUN_COMMAND_WAITPID_NOEXIT; 197 } else { 198 code = WEXITSTATUS(status); 199 switch (code) { 200 case 127: 201 result = -ERR_RUN_COMMAND_EXEC; 202 break; 203 case 0: 204 result = 0; 205 break; 206 default: 207 result = -code; 208 break; 209 } 210 } 211 } 212 if (finished) { 213 cmd->finished = 1; 214 cmd->finish_result = result; 215 } 216 return result; 217 } 218 219 int check_if_command_finished(struct child_process *cmd) 220 { 221 #ifdef __linux__ 222 char filename[FILENAME_MAX + 12]; 223 char status_line[256]; 224 FILE *status_file; 225 226 /* 227 * Check by reading /proc/<pid>/status as calling waitpid causes 228 * stdout/stderr to be closed and data lost. 229 */ 230 sprintf(filename, "/proc/%d/status", cmd->pid); 231 status_file = fopen(filename, "r"); 232 if (status_file == NULL) { 233 /* Open failed assume finish_command was called. */ 234 return true; 235 } 236 while (fgets(status_line, sizeof(status_line), status_file) != NULL) { 237 char *p; 238 239 if (strncmp(status_line, "State:", 6)) 240 continue; 241 242 fclose(status_file); 243 p = status_line + 6; 244 while (isspace(*p)) 245 p++; 246 return *p == 'Z' ? 1 : 0; 247 } 248 /* Read failed assume finish_command was called. */ 249 fclose(status_file); 250 return 1; 251 #else 252 wait_or_whine(cmd, /*block=*/false); 253 return cmd->finished; 254 #endif 255 } 256 257 int finish_command(struct child_process *cmd) 258 { 259 return wait_or_whine(cmd, /*block=*/true); 260 } 261 262 int run_command(struct child_process *cmd) 263 { 264 int code = start_command(cmd); 265 if (code) 266 return code; 267 return finish_command(cmd); 268 } 269 270 static void prepare_run_command_v_opt(struct child_process *cmd, 271 const char **argv, 272 int opt) 273 { 274 memset(cmd, 0, sizeof(*cmd)); 275 cmd->argv = argv; 276 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0; 277 cmd->exec_cmd = opt & RUN_EXEC_CMD ? 1 : 0; 278 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0; 279 } 280 281 int run_command_v_opt(const char **argv, int opt) 282 { 283 struct child_process cmd; 284 prepare_run_command_v_opt(&cmd, argv, opt); 285 return run_command(&cmd); 286 } 287