int System::Exec()

in util/process_wrapper/system_posix.cc [121:195]


int System::Exec(const System::StrType &executable,
                 const System::Arguments &arguments,
                 const System::EnvironmentBlock &environment_block,
                 const StrType &stdout_file, const StrType &stderr_file) {
  OutputPipe stdout_pipe;
  if (!stdout_file.empty() && !stdout_pipe.CreateEnds()) {
    return -1;
  }
  OutputPipe stderr_pipe;
  if (!stderr_file.empty() && !stderr_pipe.CreateEnds()) {
    return -1;
  }

  pid_t child_pid = fork();
  if (child_pid < 0) {
    std::cerr << "process wrapper error: failed to fork the current process: "
              << std::strerror(errno) << ".\n";
    return -1;
  } else if (child_pid == 0) {
    if (!stdout_file.empty()) {
      stdout_pipe.DupWriteEnd(STDOUT_FILENO);
    }
    if (!stderr_file.empty()) {
      stderr_pipe.DupWriteEnd(STDERR_FILENO);
    }
    std::vector<char *> argv;
    argv.push_back(const_cast<char *>(executable.c_str()));
    for (const StrType &argument : arguments) {
      argv.push_back(const_cast<char *>(argument.c_str()));
    }
    argv.push_back(nullptr);

    std::vector<char *> envp;
    for (const StrType &ev : environment_block) {
      envp.push_back(const_cast<char *>(ev.c_str()));
    }
    envp.push_back(nullptr);

    umask(022);

    execve(executable.c_str(), argv.data(), envp.data());
    std::cerr << "process wrapper error: failed to exec the new process: "
              << std::strerror(errno) << ".\n";
    return -1;
  }

  if (!stdout_file.empty()) {
    if (!stdout_pipe.WriteToFile(stdout_file)) {
      return -1;
    }
  }
  if (!stderr_file.empty()) {
    if (!stderr_pipe.WriteToFile(stderr_file)) {
      return -1;
    }
  }

  int err, exit_status;
  do {
    err = waitpid(child_pid, &exit_status, 0);
  } while (err == -1 && errno == EINTR);

  if (WIFEXITED(exit_status)) {
    return WEXITSTATUS(exit_status);
  } else if (WIFSIGNALED(exit_status)) {
    raise(WTERMSIG(exit_status));
  } else if (WIFSTOPPED(exit_status)) {
    raise(WSTOPSIG(exit_status));
  } else {
    std::cerr << "process wrapper error: failed to parse exit code of the "
                 "child process: "
              << exit_status << ".\n";
  }
  return -1;
}