1/// Helpers functions for [ChildStderr].
2use std::{convert::TryInto, process::ChildStderr};
3
4use crate::{Error, ErrorKind};
5
6#[cfg(all(not(unix), not(windows)))]
7compile_error!("Only unix and windows support non-blocking pipes! For other OSes, disable the parallel feature.");
8
9#[cfg(unix)]
10fn get_flags(fd: std::os::unix::io::RawFd) -> Result<i32, Error> {
11 let flags: i32 = unsafe { libc::fcntl(fd, cmd:libc::F_GETFL, 0) };
12 if flags == -1 {
13 Err(Error::new(
14 kind:ErrorKind::IOError,
15 message:format!(
16 "Failed to get flags for pipe {}: {}",
17 fd,
18 std::io::Error::last_os_error()
19 ),
20 ))
21 } else {
22 Ok(flags)
23 }
24}
25
26#[cfg(unix)]
27fn set_flags(fd: std::os::unix::io::RawFd, flags: std::os::raw::c_int) -> Result<(), Error> {
28 if unsafe { libc::fcntl(fd, cmd:libc::F_SETFL, flags) } == -1 {
29 Err(Error::new(
30 kind:ErrorKind::IOError,
31 message:format!(
32 "Failed to set flags for pipe {}: {}",
33 fd,
34 std::io::Error::last_os_error()
35 ),
36 ))
37 } else {
38 Ok(())
39 }
40}
41
42#[cfg(unix)]
43pub fn set_non_blocking(pipe: &impl std::os::unix::io::AsRawFd) -> Result<(), Error> {
44 // On Unix, switch the pipe to non-blocking mode.
45 // On Windows, we have a different way to be non-blocking.
46 let fd: i32 = pipe.as_raw_fd();
47
48 let flags: i32 = get_flags(fd)?;
49 set_flags(fd, flags:flags | libc::O_NONBLOCK)
50}
51
52pub fn bytes_available(stderr: &mut ChildStderr) -> Result<usize, Error> {
53 let mut bytes_available = 0;
54 #[cfg(windows)]
55 {
56 use crate::windows::windows_sys::PeekNamedPipe;
57 use std::os::windows::io::AsRawHandle;
58 use std::ptr::null_mut;
59 if unsafe {
60 PeekNamedPipe(
61 stderr.as_raw_handle(),
62 null_mut(),
63 0,
64 null_mut(),
65 &mut bytes_available,
66 null_mut(),
67 )
68 } == 0
69 {
70 return Err(Error::new(
71 ErrorKind::IOError,
72 format!(
73 "PeekNamedPipe failed with {}",
74 std::io::Error::last_os_error()
75 ),
76 ));
77 }
78 }
79 #[cfg(unix)]
80 {
81 use std::os::unix::io::AsRawFd;
82 if unsafe { libc::ioctl(stderr.as_raw_fd(), libc::FIONREAD, &mut bytes_available) } != 0 {
83 return Err(Error::new(
84 ErrorKind::IOError,
85 format!("ioctl failed with {}", std::io::Error::last_os_error()),
86 ));
87 }
88 }
89 Ok(bytes_available.try_into().unwrap())
90}
91