oconnor663 / duct.rs

a Rust library for running child processes
MIT License
795 stars 34 forks source link

Pipe to not standard file descriptor #82

Closed jeprojects closed 4 years ago

jeprojects commented 4 years ago

Can this somehow pipe to a process non-standard file descriptor (fd/3, fd4)?

oconnor663 commented 4 years ago

Yes there is. Note that e.g. stdout_file accepts any type that implements IntoRawFd. If you convert your fd into a std::fs::File or an os_pipe::PipeWriter using the FromRawFd trait, you can pass it to stdout_file. However, note that Duct will close the file descriptor after it's done with it, so you have to use a duplicate that's ok to close. (This is why from_raw_fd is unsafe.) PipeWriter::try_clone is one way to do duplication, but if you're making a temporary PipeWriter out of an fd that you don't own, you have to make sure you never destruct it, probably using ManuallyDrop.

I can clarify that if any particular part doesn't make sense?

oconnor663 commented 4 years ago

Note that if you ever use File::try_clone, you might need to be aware of the bug referred to in this commit.

jeprojects commented 4 years ago

Thanks for the detailed info.

Any example code on how to write to fd3 and read from fd4 of a process (using a pipe)?

oconnor663 commented 4 years ago

Knowing nothing about your use case, here's a potential example:

use std::io::prelude::*;
use std::mem::ManuallyDrop;
use std::os::unix::prelude::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // In this particular example, we might not need ManuallyDrop, because
    // these pipes will only be dropped/closed when the process is about to
    // exit anyway. But in other contexts, they're often necessary.
    let mut reader_3 = ManuallyDrop::new(unsafe { os_pipe::PipeReader::from_raw_fd(3) });
    let mut writer_4 = ManuallyDrop::new(unsafe { os_pipe::PipeWriter::from_raw_fd(4) });

    let mut buf = [0];
    reader_3.read_exact(&mut buf)?;
    writer_4.write_all(&buf)?;

    Ok(())
}
jeprojects commented 4 years ago

Thanks very much, I am getting a clearer picture on how to do this :)

How do I attach these to a spawned process using duct?

The child process communicates back and forth to the parent using fd3 and fd4.

oconnor663 commented 4 years ago

There is no simple way to make duct pipe input to anything other than stdin (fd 0). You'll need to set things up manually, either with stdin_file or by falling back to std::process::Command.

I could probably give you better advice if I knew why you needed fd 3 and fd 4. What are you up to?

jeprojects commented 4 years ago

Chrome / Chromium provide an arg "--remote-debugging-pipe" to communicate with the process via fd3 and fd4. You use this pipe to send commands to the chrome process.

In puppeteer (chrome automation package for node) they ignore fd0, fd1, fd2, and pipe fd3 + fd4 only when spawning the chrome executable.

jeprojects commented 4 years ago

Did you have any suggestions?

Thanks in advance.