1 | /// Helpers functions for [ChildStderr]. |
2 | use std::{convert::TryInto, process::ChildStderr}; |
3 | |
4 | use crate::{Error, ErrorKind}; |
5 | |
6 | #[cfg (all(not(unix), not(windows)))] |
7 | compile_error!("Only unix and windows support non-blocking pipes! For other OSes, disable the parallel feature." ); |
8 | |
9 | #[cfg (unix)] |
10 | fn 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)] |
27 | fn 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)] |
43 | pub 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 | |
52 | pub 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 | |