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