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