如何在Rust中从进程内部重定向stderr?

6ojccjat  于 2022-11-12  发布在  其他
关注(0)|答案(2)|浏览(186)

我尝试从进程内部重定向Stderr文件描述符,但似乎没有它的实现,而且我没有看到从C/C++到类似dup2的任何内容的明确路径。
我试过了:

  • 直接实现Readimpl Read for Stderr),但这需要一个完整的代码库。
  • 使用文件描述符中的数据,然后将其存储到File,再存储到ReadBuf
trait FDReader {
    fn consume(&mut self);
}

impl FDReader for Stderr {
    fn consume(&mut self) {
        let f = std::fs::File::from_raw_fd(self.as_raw_fd());
        let mut extract = String::new();
        BufReader::new(f).read_to_string(&mut extract);
    }
}

我把注意力集中在consume上,因为在测试代码时,我不需要返回任何东西,尽管这样做不起作用。

  • 由于我是在Linux系统上运行的,而且我不打算发布代码,所以我还考虑过重定向/proc/self/fd/2 -> /dev/null,然后在我想写入到那里时返回原始指针引用。

我还 * 考虑过 * 直接使用libc::dup2--尽管我已经厌倦了。

kmbjn2e3

kmbjn2e31#

gag crate允许将stderr或stdout重定向到一个文件或不重定向到任何文件,但它只适用于 *nix系统。
从另一个Angular 来看这个问题,我建议您不要直接使用stdout或stderr,而是使用 * 依赖注入 * 来传递可以写入的值。
另请参阅:

另请参阅:

q35jwt9p

q35jwt9p2#

在POSIX系统(Linux/BSD/MacOS)上,有一个不安全的(不止一种方式)黑客,让你在一个较低的级别上,使用libc crate
也就是说,在程序打开更多的文件之前,拖动并替换标准文件描述符0(stdin)、1(stdout)和2(stderr)。
它依赖于libc通常将第一个(最低)可用描述符分配给新打开的文件的事实。遗憾的是,不能保证(我知道)它总是这样工作。

  • 在C语言中,FILE* stdout可以用fdopen()重新赋值,并且,由于printf()和其他函数使用FILE* stdout,这样就可以了。
  • 但是Rust的标准库使用文件描述符,所以我们必须依赖于操作系统或libc实现细节。

在这个例子中我用stdout描述符代替,它在MacOS上工作。

use std::ffi::c_char;
use libc;

fn main() {

    unsafe {
        let out_file_path = "console.txt".to_string().as_ptr() as *const c_char;
        // let open_flag = libc::O_WRONLY | libc::O_CREAT | libc::O_APPEND | libc::FD_CLOEXEC;

        libc::close(libc::STDOUT_FILENO);
        let new_fd = libc::creat(out_file_path, libc::S_IRUSR | libc::S_IWUSR);
        if new_fd < 0 {
            libc::perror(std::ptr::null());
        }
        eprintln!("new fd: {}, expected {}", new_fd, libc::STDOUT_FILENO);
    }

    println!("Yohoho!");
}

在Windows上也一定有办法做到这一点,就像在this question中一样,但我将把这作为一个练习留给读者。

相关问题