linux/tools/lib/subcmd/run-command.c
<<
>>
Prefs
   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
  14static inline void close_pair(int fd[2])
  15{
  16        close(fd[0]);
  17        close(fd[1]);
  18}
  19
  20static inline void dup_devnull(int to)
  21{
  22        int fd = open("/dev/null", O_RDWR);
  23        dup2(fd, to);
  24        close(fd);
  25}
  26
  27int 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
 164static 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
 198int finish_command(struct child_process *cmd)
 199{
 200        return wait_or_whine(cmd->pid);
 201}
 202
 203int 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
 211static 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
 222int 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