hotl_platform/console/
unix.rs1use super::{ConsoleControl, HandlerContract};
4use std::io;
5use std::sync::atomic::{AtomicUsize, Ordering};
6
7#[derive(Debug, Clone, Copy, Default)]
8pub struct UnixConsoleControl;
9
10impl UnixConsoleControl {
11 pub const fn new() -> Self {
12 Self
13 }
14}
15
16impl crate::sealed::Sealed for UnixConsoleControl {}
17
18#[derive(Clone, Copy)]
21pub struct UnixModes(libc::termios);
22
23unsafe impl Send for UnixModes {}
26unsafe impl Sync for UnixModes {}
27
28static ON_INTERRUPT: AtomicUsize = AtomicUsize::new(0);
31
32const TRAPPED: [libc::c_int; 3] = [libc::SIGINT, libc::SIGTERM, libc::SIGHUP];
35
36extern "C" fn on_signal(signal: libc::c_int) {
37 let f = ON_INTERRUPT.load(Ordering::SeqCst);
38 if f != 0 {
39 let f: fn() = unsafe { std::mem::transmute::<usize, fn()>(f) };
41 f();
42 }
43 unsafe { libc::_exit(128 + signal) };
45}
46
47impl ConsoleControl for UnixConsoleControl {
48 type Saved = UnixModes;
49
50 const HANDLER_CONTRACT: HandlerContract = HandlerContract::AsyncSignalSafe;
51
52 fn capture(&self) -> io::Result<Self::Saved> {
53 let mut modes: libc::termios = unsafe { std::mem::zeroed() };
55 if unsafe { libc::tcgetattr(libc::STDIN_FILENO, &mut modes) } != 0 {
57 return Err(io::Error::last_os_error());
58 }
59 Ok(UnixModes(modes))
60 }
61
62 fn restore(&self, saved: &Self::Saved) -> io::Result<()> {
63 if unsafe { libc::tcsetattr(libc::STDIN_FILENO, libc::TCSANOW, &saved.0) } != 0 {
66 return Err(io::Error::last_os_error());
67 }
68 Ok(())
69 }
70
71 fn write_raw(&self, bytes: &[u8]) {
72 unsafe {
75 libc::write(libc::STDOUT_FILENO, bytes.as_ptr().cast(), bytes.len());
76 }
77 }
78
79 fn trap(&self, on_interrupt: fn()) -> io::Result<()> {
80 ON_INTERRUPT.store(on_interrupt as usize, Ordering::SeqCst);
81 for signal in TRAPPED {
82 unsafe {
86 let mut action: libc::sigaction = std::mem::zeroed();
87 action.sa_sigaction = on_signal as *const () as libc::sighandler_t;
88 libc::sigemptyset(&mut action.sa_mask);
89 action.sa_flags = libc::SA_RESTART;
90 if libc::sigaction(signal, &action, std::ptr::null_mut()) != 0 {
91 return Err(io::Error::last_os_error());
92 }
93 }
94 }
95 Ok(())
96 }
97
98 fn interrupt_exit_code(&self) -> i32 {
99 128 + libc::SIGINT
100 }
101}