wasmer_wasix/os/tty/
tty_sys.rs1use super::TtyBridge;
2use crate::WasiTtyState;
3
4#[derive(Debug, Default, Clone)]
6pub struct SysTty;
7
8impl TtyBridge for SysTty {
9 fn reset(&self) {
10 sys::reset().ok();
11 }
12
13 fn tty_get(&self) -> WasiTtyState {
14 let echo = sys::is_mode_echo();
15 let line_buffered = sys::is_mode_line_buffering();
16 let line_feeds = sys::is_mode_line_feeds();
17 let stdin_tty = sys::is_stdin_tty();
18 let stdout_tty = sys::is_stdout_tty();
19 let stderr_tty = sys::is_stderr_tty();
20 let (cols, rows) = sys_terminal_size::get_terminal_size();
21
22 WasiTtyState {
23 cols,
24 rows,
25 width: 800,
26 height: 600,
27 stdin_tty,
28 stdout_tty,
29 stderr_tty,
30 echo,
31 line_buffered,
32 line_feeds,
33 }
34 }
35
36 fn tty_set(&self, tty_state: WasiTtyState) {
37 if tty_state.echo {
38 sys::set_mode_echo().ok();
39 } else {
40 sys::set_mode_no_echo().ok();
41 }
42 if tty_state.line_buffered {
43 sys::set_mode_line_buffered().ok();
44 } else {
45 sys::set_mode_no_line_buffered().ok();
46 }
47 if tty_state.line_feeds {
48 sys::set_mode_line_feeds().ok();
49 } else {
50 sys::set_mode_no_line_feeds().ok();
51 }
52 }
53}
54
55mod sys_terminal_size {
56 static DEFAULT_SIZE: (u32, u32) = (80, 25);
57
58 #[cfg(not(target_arch = "wasm32"))]
59 pub fn get_terminal_size() -> (u32, u32) {
60 if let Some((terminal_size::Width(width), terminal_size::Height(height))) =
61 terminal_size::terminal_size()
62 {
63 (width.into(), height.into())
64 } else {
65 DEFAULT_SIZE
66 }
67 }
68
69 #[cfg(target_arch = "wasm32")]
70 pub fn get_terminal_size() -> (u32, u32) {
71 DEFAULT_SIZE
72 }
73}
74
75#[allow(unused_mut, unused_imports)]
76#[cfg(all(unix, not(target_os = "ios")))]
77mod sys {
78 use {
79 libc::{
80 ECHO, ECHOCTL, ECHOE, ECHOK, ECHONL, ICANON, ICRNL, IEXTEN, IGNCR, ISIG, IXON, ONLCR,
81 OPOST, TCSANOW, c_int, tcsetattr, termios,
82 },
83 std::mem,
84 std::os::unix::io::AsRawFd,
85 };
86
87 fn io_result(ret: libc::c_int) -> std::io::Result<()> {
88 match ret {
89 0 => Ok(()),
90 _ => Err(std::io::Error::last_os_error()),
91 }
92 }
93
94 pub fn reset() -> Result<(), anyhow::Error> {
95 let mut termios = mem::MaybeUninit::<termios>::uninit();
96 io_result(unsafe { ::libc::tcgetattr(0, termios.as_mut_ptr()) })?;
97 let mut termios = unsafe { termios.assume_init() };
98
99 termios.c_lflag |= ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL;
100
101 unsafe { tcsetattr(0, TCSANOW, &termios) };
102 Ok(())
103 }
104
105 pub fn is_stdin_tty() -> bool {
106 ::termios::Termios::from_fd(0).is_ok()
107 }
108
109 pub fn is_stdout_tty() -> bool {
110 ::termios::Termios::from_fd(1).is_ok()
111 }
112
113 pub fn is_stderr_tty() -> bool {
114 ::termios::Termios::from_fd(2).is_ok()
115 }
116
117 pub fn is_mode_echo() -> bool {
118 if let Ok(termios) = ::termios::Termios::from_fd(0) {
119 (termios.c_lflag & ::termios::ECHO) != 0
120 } else {
121 false
122 }
123 }
124
125 pub fn is_mode_line_buffering() -> bool {
126 if let Ok(termios) = ::termios::Termios::from_fd(0) {
127 (termios.c_lflag & ::termios::ICANON) != 0
128 } else {
129 false
130 }
131 }
132
133 pub fn is_mode_line_feeds() -> bool {
134 if let Ok(termios) = ::termios::Termios::from_fd(0) {
135 (termios.c_lflag & ::termios::ONLCR) != 0
136 } else {
137 false
138 }
139 }
140
141 pub fn set_mode_no_echo() -> Result<(), anyhow::Error> {
142 let mut termios = mem::MaybeUninit::<termios>::uninit();
143 io_result(unsafe { ::libc::tcgetattr(0, termios.as_mut_ptr()) })?;
144 let mut termios = unsafe { termios.assume_init() };
145
146 termios.c_lflag &= !ECHO;
147 termios.c_lflag &= !ECHOE;
148 termios.c_lflag &= !ECHOK;
149 termios.c_lflag &= !ECHOCTL;
150 termios.c_lflag &= !IEXTEN;
151 unsafe { tcsetattr(0, TCSANOW, &termios) };
159 Ok(())
160 }
161
162 pub fn set_mode_echo() -> Result<(), anyhow::Error> {
163 let mut termios = mem::MaybeUninit::<termios>::uninit();
164 io_result(unsafe { ::libc::tcgetattr(0, termios.as_mut_ptr()) })?;
165 let mut termios = unsafe { termios.assume_init() };
166
167 termios.c_lflag |= ECHO;
168 termios.c_lflag |= ECHOE;
169 termios.c_lflag |= ECHOK;
170 termios.c_lflag |= ECHOCTL;
171 termios.c_lflag |= IEXTEN;
172 unsafe { tcsetattr(0, TCSANOW, &termios) };
180 Ok(())
181 }
182
183 pub fn set_mode_no_line_buffered() -> Result<(), anyhow::Error> {
184 let mut termios = mem::MaybeUninit::<termios>::uninit();
185 io_result(unsafe { ::libc::tcgetattr(0, termios.as_mut_ptr()) })?;
186 let mut termios = unsafe { termios.assume_init() };
187
188 termios.c_lflag &= !ICANON;
189
190 unsafe { tcsetattr(0, TCSANOW, &termios) };
191 Ok(())
192 }
193
194 pub fn set_mode_line_buffered() -> Result<(), anyhow::Error> {
195 let mut termios = mem::MaybeUninit::<termios>::uninit();
196 io_result(unsafe { ::libc::tcgetattr(0, termios.as_mut_ptr()) })?;
197 let mut termios = unsafe { termios.assume_init() };
198
199 termios.c_lflag |= ICANON;
200
201 unsafe { tcsetattr(0, TCSANOW, &termios) };
202 Ok(())
203 }
204
205 pub fn set_mode_no_line_feeds() -> Result<(), anyhow::Error> {
206 let mut termios = mem::MaybeUninit::<termios>::uninit();
207 io_result(unsafe { ::libc::tcgetattr(0, termios.as_mut_ptr()) })?;
208 let mut termios = unsafe { termios.assume_init() };
209
210 termios.c_lflag &= !ONLCR;
211
212 unsafe { tcsetattr(0, TCSANOW, &termios) };
213 Ok(())
214 }
215
216 pub fn set_mode_line_feeds() -> Result<(), anyhow::Error> {
217 let mut termios = mem::MaybeUninit::<termios>::uninit();
218 io_result(unsafe { ::libc::tcgetattr(0, termios.as_mut_ptr()) })?;
219 let mut termios = unsafe { termios.assume_init() };
220
221 termios.c_lflag |= ONLCR;
222
223 unsafe { tcsetattr(0, TCSANOW, &termios) };
224 Ok(())
225 }
226}
227
228#[cfg(any(not(unix), target_os = "ios"))]
229mod sys {
230 pub fn reset() -> Result<(), anyhow::Error> {
231 Ok(())
232 }
233
234 pub fn is_stdin_tty() -> bool {
235 false
236 }
237
238 pub fn is_stdout_tty() -> bool {
239 false
240 }
241
242 pub fn is_stderr_tty() -> bool {
243 false
244 }
245
246 pub fn is_mode_echo() -> bool {
247 true
248 }
249
250 pub fn is_mode_line_buffering() -> bool {
251 true
252 }
253
254 pub fn is_mode_line_feeds() -> bool {
255 true
256 }
257
258 pub fn set_mode_no_echo() -> Result<(), anyhow::Error> {
259 Ok(())
260 }
261
262 pub fn set_mode_echo() -> Result<(), anyhow::Error> {
263 Ok(())
264 }
265
266 pub fn set_mode_no_line_buffered() -> Result<(), anyhow::Error> {
267 Ok(())
268 }
269
270 pub fn set_mode_line_buffered() -> Result<(), anyhow::Error> {
271 Ok(())
272 }
273
274 pub fn set_mode_no_line_feeds() -> Result<(), anyhow::Error> {
275 Ok(())
276 }
277
278 pub fn set_mode_line_feeds() -> Result<(), anyhow::Error> {
279 Ok(())
280 }
281}