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