重定向标准输出时调用 dup2 失败

Call to dup2 fails when redirecting stdout

本文关键字:dup2 失败 调用 标准输出 重定向      更新时间:2023-10-16

我已经为此苦苦挣扎了一段时间。我正在尝试围绕运行子进程编写一个C++类。我正在使用fork()pipe()dup2()execv()来启动子进程并将其标准输出和标准重定向到父进程。据我所知,一切都很好,直到调用dup2()并且它因EINVAL而失败(在 macOS 上,我认为这不是 Linux 中允许的错误类型)。如果我删除管道周围的所有逻辑,该类将按预期工作。

类声明:

class PosixSubprocess : public Subprocess {
    std::string _cmd = {};
    std::string _stdout = "";
    std::string _stderr = "";
    std::vector<std::string> _args = {};
    long _pid = -1;
    int _status = -1;
public:
    void cmd(std::string val) override;
    void addArg(std::string val) override;
    void run() override;
    int status() const override;
    std::string out() const override;
    std::string err() const override;
};

run()的定义:

void PosixSubprocess::run() {
    std::array<int, 2> stdoutPipe = {};
    std::array<int, 2> stderrPipe = {};
    if (pipe(stdoutPipe.data()) < 0)
    {
        throw std::runtime_error("Subprocess: failed to create pipes. Errno: " + std::to_string(errno));
    }
    if (pipe(stderrPipe.data()) < 0)
    {
        throw std::runtime_error("Subprocess: failed to create pipes. Errno: " + std::to_string(errno));
    }
    _pid = fork();
    if (_pid == 0) {
        if (dup2(stderrPipe[1], STDERR_FILENO)) {
            std::cout << "Subprocess: failed to redirect stderr. Errno " << errno << 'n';
            exit(errno);
        }
        if (dup2(stdoutPipe[1], STDOUT_FILENO)) {
            std::cout << "Subprocess: failed to redirect stdout. Errno " << errno << 'n';
            exit(errno);
        }
        close(stdoutPipe[0]);
        close(stdoutPipe[1]);
        close(stderrPipe[0]);
        close(stderrPipe[1]);
        auto argv = std::make_unique<char*[]>(_args.size() + 1);
        argv[_args.size()] = nullptr;
        for (size_t i = 0; i < _args.size(); ++i) {
            argv[i] = &(_args[i].front());
        }
        if(execvp(_cmd.c_str(), argv.get())) {
            std::cerr << "Subprocess: failed to launch. Errno " << errno << 'n';
            exit(errno);
        }
    } else if (_pid > 0) {
        close(stdoutPipe[1]);
        close(stderrPipe[1]);
        std::array<char, 1024> buf;
        auto appendPipe = [&buf](int fd, std::string& str) {
            ssize_t nBytes = 0;
            do {
                nBytes = read(fd, buf.data(), buf.size());
                str.append(buf.data(), nBytes);
                if (nBytes) std::cout << nBytes << 'n';
            } while (nBytes > 0);
        };
        while(!waitpid(_pid, &_status, WNOHANG)) {
            appendPipe(stdoutPipe[0], _stdout);
            appendPipe(stdoutPipe[0], _stderr);
        }
    } else {
        close(stdoutPipe[0]);
        close(stdoutPipe[1]);
        close(stderrPipe[0]);
        close(stderrPipe[1]);
        throw std::runtime_error("Subprocess: fork failed.");
    }
}

很抱歉这里的代码墙,我不能肯定地说与问题无关。

来自dup2的手册页:

返回值

成功完成后,应返回

一个非负整数,即文件描述符;否则,应返回 -1 并设置 errno 以指示错误。

由于显然,dup2()返回原始文件描述符,并且它不为零,因此显示的代码认为这是一个错误。

错误条件由返回值指示。