Skip to main content

relibc/header/termios/
mod.rs

1//! `termios.h` implementation.
2//!
3//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/termios.h.html>.
4
5use crate::{
6    header::{errno, sys_ioctl},
7    platform::{
8        self,
9        types::{c_int, c_uchar, c_uint, c_ulong, c_void, pid_t},
10    },
11};
12
13pub use crate::header::bits_winsize::winsize;
14
15pub use self::sys::*;
16
17#[cfg(target_os = "linux")]
18#[path = "linux.rs"]
19pub mod sys;
20
21#[cfg(target_os = "redox")]
22#[path = "redox.rs"]
23pub mod sys;
24
25/// Used for terminal special characters.
26pub type cc_t = c_uchar;
27/// Used for terminal baud rates.
28pub type speed_t = c_uint;
29/// Used for terminal modes.
30pub type tcflag_t = c_uint;
31
32/// Suspend output.
33pub const TCOOFF: c_int = 0;
34/// Restart output.
35pub const TCOON: c_int = 1;
36/// Transmit a `STOP` character, intended to suspend input data.
37pub const TCIOFF: c_int = 2;
38/// Transmit a `START` character, intended to restart input data.
39pub const TCION: c_int = 3;
40
41/// Flush pending input.
42pub const TCIFLUSH: c_int = 0;
43/// Flush untransmitted output.
44pub const TCOFLUSH: c_int = 1;
45/// Flush bot pending input and untransmitted output.
46pub const TCIOFLUSH: c_int = 2;
47
48/// Change attributes immediately.
49pub const TCSANOW: c_int = 0;
50/// Change attributes when output has drained.
51pub const TCSADRAIN: c_int = 1;
52/// Change attributes when output has drained; also flush pending input.
53pub const TCSAFLUSH: c_int = 2;
54
55/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/termios.h.html>.
56#[cfg(target_os = "linux")]
57#[repr(C)]
58#[derive(Default, Clone)]
59pub struct termios {
60    /// Input modes.
61    pub c_iflag: tcflag_t,
62    /// Output modes.
63    pub c_oflag: tcflag_t,
64    /// Control modes.
65    pub c_cflag: tcflag_t,
66    /// Local modes.
67    pub c_lflag: tcflag_t,
68    pub c_line: cc_t,
69    /// Control characters.
70    pub c_cc: [cc_t; NCCS],
71    pub __c_ispeed: speed_t,
72    pub __c_ospeed: speed_t,
73}
74
75// Must match structure in redox_termios
76/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/termios.h.html>.
77#[cfg(target_os = "redox")]
78#[repr(C)]
79#[derive(Default, Clone)]
80pub struct termios {
81    /// Input modes.
82    pub c_iflag: tcflag_t,
83    /// Output modes.
84    pub c_oflag: tcflag_t,
85    /// Control modes.
86    pub c_cflag: tcflag_t,
87    /// Local modes.
88    pub c_lflag: tcflag_t,
89    /// Control characters.
90    pub c_cc: [cc_t; NCCS],
91}
92
93/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcgetattr.html>.
94#[unsafe(no_mangle)]
95pub unsafe extern "C" fn tcgetattr(fd: c_int, out: *mut termios) -> c_int {
96    unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCGETS, out.cast::<c_void>()) }
97}
98
99/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcsetattr.html>.
100#[unsafe(no_mangle)]
101pub unsafe extern "C" fn tcsetattr(fd: c_int, act: c_int, value: *const termios) -> c_int {
102    if !(0..=2).contains(&act) {
103        platform::ERRNO.set(errno::EINVAL);
104        return -1;
105    }
106    // This is safe because ioctl shouldn't modify the value
107    unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCSETS + act as c_ulong, value as *mut c_void) }
108}
109
110/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcgetsid.html>.
111#[unsafe(no_mangle)]
112pub unsafe extern "C" fn tcgetsid(fd: c_int) -> pid_t {
113    let mut sid = 0;
114    if unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCGSID, (&raw mut sid).cast::<c_void>()) } < 0 {
115        return -1;
116    }
117    sid
118}
119
120/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cfgetispeed.html>.
121#[cfg(target_os = "linux")]
122#[unsafe(no_mangle)]
123pub unsafe extern "C" fn cfgetispeed(termios_p: *const termios) -> speed_t {
124    unsafe { (*termios_p).__c_ispeed }
125}
126
127/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cfgetispeed.html>.
128#[cfg(target_os = "redox")]
129#[unsafe(no_mangle)]
130pub unsafe extern "C" fn cfgetispeed(termios_p: *const termios) -> speed_t {
131    //TODO
132    0
133}
134
135/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cfgetospeed.html>.
136#[cfg(target_os = "linux")]
137#[unsafe(no_mangle)]
138pub unsafe extern "C" fn cfgetospeed(termios_p: *const termios) -> speed_t {
139    unsafe { (*termios_p).__c_ospeed }
140}
141
142/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cfgetospeed.html>.
143#[cfg(target_os = "redox")]
144#[unsafe(no_mangle)]
145pub unsafe extern "C" fn cfgetospeed(termios_p: *const termios) -> speed_t {
146    //TODO
147    0
148}
149
150/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cfsetispeed.html>.
151#[cfg(target_os = "linux")]
152#[unsafe(no_mangle)]
153pub unsafe extern "C" fn cfsetispeed(termios_p: *mut termios, speed: speed_t) -> c_int {
154    match speed as usize {
155        B0..=B38400 | B57600..=B4000000 => {
156            unsafe { (*termios_p).__c_ispeed = speed };
157            0
158        }
159        _ => {
160            platform::ERRNO.set(errno::EINVAL);
161            -1
162        }
163    }
164}
165
166/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cfsetispeed.html>.
167#[cfg(target_os = "redox")]
168#[unsafe(no_mangle)]
169pub unsafe extern "C" fn cfsetispeed(termios_p: *mut termios, speed: speed_t) -> c_int {
170    //TODO
171    platform::ERRNO.set(errno::EINVAL);
172    -1
173}
174
175/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cfsetospeed.html>.
176#[cfg(target_os = "linux")]
177#[unsafe(no_mangle)]
178pub unsafe extern "C" fn cfsetospeed(termios_p: *mut termios, speed: speed_t) -> c_int {
179    match speed as usize {
180        B0..=B38400 | B57600..=B4000000 => {
181            unsafe { (*termios_p).__c_ospeed = speed };
182            0
183        }
184        _ => {
185            platform::ERRNO.set(errno::EINVAL);
186            -1
187        }
188    }
189}
190
191/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/cfsetospeed.html>.
192#[cfg(target_os = "redox")]
193#[unsafe(no_mangle)]
194pub unsafe extern "C" fn cfsetospeed(termios_p: *mut termios, speed: speed_t) -> c_int {
195    //TODO
196    platform::ERRNO.set(errno::EINVAL);
197    -1
198}
199
200/// Non-POSIX, 4.4 BSD extension
201///
202/// See <https://www.man7.org/linux/man-pages/man3/cfsetispeed.3.html>.
203#[unsafe(no_mangle)]
204pub unsafe extern "C" fn cfsetspeed(termios_p: *mut termios, speed: speed_t) -> c_int {
205    let r = unsafe { cfsetispeed(termios_p, speed) };
206    if r < 0 {
207        return r;
208    }
209    unsafe { cfsetospeed(termios_p, speed) }
210}
211
212/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcflush.html>.
213#[unsafe(no_mangle)]
214pub unsafe extern "C" fn tcflush(fd: c_int, queue: c_int) -> c_int {
215    unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCFLSH, queue as *mut c_void) }
216}
217
218/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcdrain.html>.
219#[unsafe(no_mangle)]
220pub unsafe extern "C" fn tcdrain(fd: c_int) -> c_int {
221    unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCSBRK, core::ptr::dangling_mut()) }
222}
223
224/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcsendbreak.html>.
225#[unsafe(no_mangle)]
226pub unsafe extern "C" fn tcsendbreak(fd: c_int, _dur: c_int) -> c_int {
227    // non-zero duration is ignored by musl due to it being
228    // implementation-defined. we do the same.
229    unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCSBRK, core::ptr::null_mut()) }
230}
231
232/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcgetwinsize.html>.
233#[unsafe(no_mangle)]
234pub unsafe extern "C" fn tcgetwinsize(fd: c_int, sws: *mut winsize) -> c_int {
235    unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCGWINSZ, sws.cast()) }
236}
237
238/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcsetwinsize.html>.
239#[unsafe(no_mangle)]
240pub unsafe extern "C" fn tcsetwinsize(fd: c_int, sws: *const winsize) -> c_int {
241    unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TIOCSWINSZ, sws.cast_mut().cast()) }
242}
243
244/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/tcflow.html>.
245#[unsafe(no_mangle)]
246pub unsafe extern "C" fn tcflow(fd: c_int, action: c_int) -> c_int {
247    // non-zero duration is ignored by musl due to it being
248    // implementation-defined. we do the same.
249    unsafe { sys_ioctl::ioctl(fd, sys_ioctl::TCXONC, action as *mut _) }
250}
251
252/// Non-POSIX, BSD extension
253///
254/// See <https://www.man7.org/linux/man-pages/man3/cfmakeraw.3.html>.
255#[unsafe(no_mangle)]
256pub unsafe extern "C" fn cfmakeraw(termios_p: *mut termios) {
257    unsafe {
258        (*termios_p).c_iflag &=
259            !(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON) as u32;
260        (*termios_p).c_oflag &= !OPOST as u32;
261        (*termios_p).c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN) as u32;
262        (*termios_p).c_cflag &= !(CSIZE | PARENB) as u32;
263        (*termios_p).c_cflag |= CS8 as u32;
264        (*termios_p).c_cc[VMIN] = 1;
265        (*termios_p).c_cc[VTIME] = 0;
266    }
267}