ctrlc/platform/unix/
mod.rs1use 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 let pipe = (pipe.0.into_raw_fd(), pipe.1.into_raw_fd());
45
46 let mut res = Ok(0);
47
48 if flags.contains(OFlag::O_CLOEXEC) {
49 res = res
50 .and_then(|_| fcntl(pipe.0, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC)))
51 .and_then(|_| fcntl(pipe.1, FcntlArg::F_SETFD(FdFlag::FD_CLOEXEC)));
52 }
53
54 if flags.contains(OFlag::O_NONBLOCK) {
55 res = res
56 .and_then(|_| fcntl(pipe.0, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)))
57 .and_then(|_| fcntl(pipe.1, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)));
58 }
59
60 match res {
61 Ok(_) => Ok(pipe),
62 Err(e) => {
63 let _ = unistd::close(pipe.0);
64 let _ = unistd::close(pipe.1);
65 Err(e)
66 }
67 }
68}
69
70#[inline]
71#[cfg(not(any(
72 target_vendor = "apple",
73 target_os = "haiku",
74 target_os = "aix",
75 target_os = "nto",
76)))]
77fn pipe2(flags: nix::fcntl::OFlag) -> nix::Result<(RawFd, RawFd)> {
78 let pipe = unistd::pipe2(flags)?;
79 Ok((pipe.0.into_raw_fd(), pipe.1.into_raw_fd()))
80}
81
82#[inline]
91pub unsafe fn init_os_handler(overwrite: bool) -> Result<(), Error> {
92 use nix::fcntl;
93 use nix::sys::signal;
94
95 PIPE = pipe2(fcntl::OFlag::O_CLOEXEC)?;
96
97 let close_pipe = |e: nix::Error| -> Error {
98 let _ = unistd::close(PIPE.1);
101 let _ = unistd::close(PIPE.0);
102 e
103 };
104
105 if let Err(e) = fcntl::fcntl(PIPE.1, fcntl::FcntlArg::F_SETFL(fcntl::OFlag::O_NONBLOCK)) {
107 return Err(close_pipe(e));
108 }
109
110 let handler = signal::SigHandler::Handler(os_handler);
111 #[cfg(not(target_os = "nto"))]
112 let new_action = signal::SigAction::new(
113 handler,
114 signal::SaFlags::SA_RESTART,
115 signal::SigSet::empty(),
116 );
117 #[cfg(target_os = "nto")]
119 let new_action =
120 signal::SigAction::new(handler, signal::SaFlags::empty(), signal::SigSet::empty());
121
122 let sigint_old = match signal::sigaction(signal::Signal::SIGINT, &new_action) {
123 Ok(old) => old,
124 Err(e) => return Err(close_pipe(e)),
125 };
126 if !overwrite && sigint_old.handler() != signal::SigHandler::SigDfl {
127 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
128 return Err(close_pipe(nix::Error::EEXIST));
129 }
130
131 #[cfg(feature = "termination")]
132 {
133 let sigterm_old = match signal::sigaction(signal::Signal::SIGTERM, &new_action) {
134 Ok(old) => old,
135 Err(e) => {
136 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
137 return Err(close_pipe(e));
138 }
139 };
140 if !overwrite && sigterm_old.handler() != signal::SigHandler::SigDfl {
141 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
142 signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
143 return Err(close_pipe(nix::Error::EEXIST));
144 }
145 let sighup_old = match signal::sigaction(signal::Signal::SIGHUP, &new_action) {
146 Ok(old) => old,
147 Err(e) => {
148 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
149 signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
150 return Err(close_pipe(e));
151 }
152 };
153 if !overwrite && sighup_old.handler() != signal::SigHandler::SigDfl {
154 signal::sigaction(signal::Signal::SIGINT, &sigint_old).unwrap();
155 signal::sigaction(signal::Signal::SIGTERM, &sigterm_old).unwrap();
156 signal::sigaction(signal::Signal::SIGHUP, &sighup_old).unwrap();
157 return Err(close_pipe(nix::Error::EEXIST));
158 }
159 }
160
161 Ok(())
162}
163
164#[inline]
172pub unsafe fn block_ctrl_c() -> Result<(), CtrlcError> {
173 use std::io;
174 let mut buf = [0u8];
175
176 loop {
180 match unistd::read(PIPE.0, &mut buf[..]) {
181 Ok(1) => break,
182 Ok(_) => return Err(CtrlcError::System(io::ErrorKind::UnexpectedEof.into())),
183 Err(nix::errno::Errno::EINTR) => {}
184 Err(e) => return Err(e.into()),
185 }
186 }
187
188 Ok(())
189}