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