ctrlc/platform/unix/
mod.rs
1use crate::error::Error as CtrlcError;
11use nix::unistd;
12use std::os::fd::BorrowedFd;
13use std::os::fd::IntoRawFd;
14use std::os::unix::io::RawFd;
15
16static mut PIPE: (RawFd, RawFd) = (-1, -1);
17
18pub type Error = nix::Error;
20
21pub type Signal = nix::sys::signal::Signal;
23
24extern "C" fn os_handler(_: nix::libc::c_int) {
25 unsafe {
27 let fd = BorrowedFd::borrow_raw(PIPE.1);
28 let _ = unistd::write(fd, &[0u8]);
29 }
30}
31
32#[inline]
34#[cfg(any(
35 target_vendor = "apple",
36 target_os = "haiku",
37 target_os = "aix",
38 target_os = "nto",
39))]
40fn pipe2(flags: nix::fcntl::OFlag) -> nix::Result<(RawFd, RawFd)> {
41 use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag};
42
43 let pipe = unistd::pipe()?;
44
45 if flags.contains(OFlag::O_CLOEXEC) {
46 fcntl(&pipe.0, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC))?;
47 fcntl(&pipe.1, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC))?;
48 }
49
50 if flags.contains(OFlag::O_NONBLOCK) {
51 fcntl(&pipe.0, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?;
52 fcntl(&pipe.1, FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?;
53 }
54
55 Ok((pipe.0.into_raw_fd(), pipe.1.into_raw_fd()))
56}
57
58#[inline]
59#[cfg(not(any(
60 target_vendor = "apple",
61 target_os = "haiku",
62 target_os = "aix",
63 target_os = "nto",
64)))]
65fn pipe2(flags: nix::fcntl::OFlag) -> nix::Result<(RawFd, RawFd)> {
66 let pipe = unistd::pipe2(flags)?;
67 Ok((pipe.0.into_raw_fd(), pipe.1.into_raw_fd()))
68}
69
70#[inline]
79pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> {
80 use nix::fcntl;
81 use nix::sys::signal;
82
83 PIPE = pipe2(fcntl::OFlag::O_CLOEXEC)?;
84
85 let close_pipe = |e: nix::Error| -> Error {
86 let _ = unistd::close(PIPE.1);
89 let _ = unistd::close(PIPE.0);
90 e
91 };
92
93 if let Err(e) = fcntl::fcntl(
95 BorrowedFd::borrow_raw(PIPE.1),
96 fcntl::FcntlArg::F_SETFL(fcntl::OFlag::O_NONBLOCK),
97 ) {
98 return Err(close_pipe(e));
99 }
100
101 let handler = signal::SigHandler::Handler(os_handler);
102 #[cfg(not(target_os = "nto"))]
103 let new_action = signal::SigAction::new(
104 handler,
105 signal::SaFlags::SA_RESTART,
106 signal::SigSet::empty(),
107 );
108 #[cfg(target_os = "nto")]
110 let new_action =
111 signal::SigAction::new(handler, signal::SaFlags::empty(), signal::SigSet::empty());
112
113 let sigint_old = match signal::sigaction(signal::Signal::SIGINT, &new_action) {
114 Ok(old) => old,
115 Err(e) => return Err(close_pipe(e)),
116 };
117 if !overwrite && sigint_old.handler() != signal::SigHandler::SigDfl {
118 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
119 return Err(close_pipe(nix::Error::EEXIST));
120 }
121
122 #[cfg(feature = "termination")]
123 {
124 let sigterm_old = match signal::sigaction(signal::Signal::SIGTERM, &new_action) {
125 Ok(old) => old,
126 Err(e) => {
127 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
128 return Err(close_pipe(e));
129 }
130 };
131 if !overwrite && sigterm_old.handler() != signal::SigHandler::SigDfl {
132 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
133 signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
134 return Err(close_pipe(nix::Error::EEXIST));
135 }
136 let sighup_old = match signal::sigaction(signal::Signal::SIGHUP, &new_action) {
137 Ok(old) => old,
138 Err(e) => {
139 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
140 signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
141 return Err(close_pipe(e));
142 }
143 };
144 if !overwrite && sighup_old.handler() != signal::SigHandler::SigDfl {
145 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
146 signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
147 signal::sigaction(signal::Signal::SIGHUP, &sighup_old).unwrap();
148 return Err(close_pipe(nix::Error::EEXIST));
149 }
150 }
151
152 Ok(())
153}
154
155#[inline]
163pub unsafe fn block_ctrl_c() -> Result<(), CtrlcError> {
164 use std::io;
165 let mut buf = [0u8];
166
167 loop {
171 match unistd::read(BorrowedFd::borrow_raw(PIPE.0), &mut buf[..]) {
172 Ok(1) => break,
173 Ok(_) => return Err(CtrlcError::System(io::ErrorKind::UnexpectedEof.into())),
174 Err(nix::errno::Errno::EINTR) => {}
175 Err(e) => return Err(e.into()),
176 }
177 }
178
179 Ok(())
180}