1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Stdin;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::zeroed;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::RawFd;
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use libc::isatty;
10*bb4ee6a4SAndroid Build Coastguard Worker use libc::read;
11*bb4ee6a4SAndroid Build Coastguard Worker use libc::tcgetattr;
12*bb4ee6a4SAndroid Build Coastguard Worker use libc::tcsetattr;
13*bb4ee6a4SAndroid Build Coastguard Worker use libc::termios;
14*bb4ee6a4SAndroid Build Coastguard Worker use libc::ECHO;
15*bb4ee6a4SAndroid Build Coastguard Worker use libc::ICANON;
16*bb4ee6a4SAndroid Build Coastguard Worker use libc::ISIG;
17*bb4ee6a4SAndroid Build Coastguard Worker use libc::O_NONBLOCK;
18*bb4ee6a4SAndroid Build Coastguard Worker use libc::STDIN_FILENO;
19*bb4ee6a4SAndroid Build Coastguard Worker use libc::TCSANOW;
20*bb4ee6a4SAndroid Build Coastguard Worker
21*bb4ee6a4SAndroid Build Coastguard Worker use crate::errno::Result;
22*bb4ee6a4SAndroid Build Coastguard Worker use crate::errno_result;
23*bb4ee6a4SAndroid Build Coastguard Worker use crate::unix::add_fd_flags;
24*bb4ee6a4SAndroid Build Coastguard Worker use crate::unix::clear_fd_flags;
25*bb4ee6a4SAndroid Build Coastguard Worker
modify_mode<F: FnOnce(&mut termios)>(fd: RawFd, f: F) -> Result<()>26*bb4ee6a4SAndroid Build Coastguard Worker fn modify_mode<F: FnOnce(&mut termios)>(fd: RawFd, f: F) -> Result<()> {
27*bb4ee6a4SAndroid Build Coastguard Worker // Safety:
28*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we check the return value of isatty.
29*bb4ee6a4SAndroid Build Coastguard Worker if unsafe { isatty(fd) } != 1 {
30*bb4ee6a4SAndroid Build Coastguard Worker return Ok(());
31*bb4ee6a4SAndroid Build Coastguard Worker }
32*bb4ee6a4SAndroid Build Coastguard Worker
33*bb4ee6a4SAndroid Build Coastguard Worker // Safety:
34*bb4ee6a4SAndroid Build Coastguard Worker // The following pair are safe because termios gets totally overwritten by tcgetattr and we
35*bb4ee6a4SAndroid Build Coastguard Worker // check the return result.
36*bb4ee6a4SAndroid Build Coastguard Worker let mut termios: termios = unsafe { zeroed() };
37*bb4ee6a4SAndroid Build Coastguard Worker // Safety:
38*bb4ee6a4SAndroid Build Coastguard Worker // The following pair are safe because termios gets totally overwritten by tcgetattr and we
39*bb4ee6a4SAndroid Build Coastguard Worker // check the return result.
40*bb4ee6a4SAndroid Build Coastguard Worker let ret = unsafe { tcgetattr(fd, &mut termios as *mut _) };
41*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 {
42*bb4ee6a4SAndroid Build Coastguard Worker return errno_result();
43*bb4ee6a4SAndroid Build Coastguard Worker }
44*bb4ee6a4SAndroid Build Coastguard Worker let mut new_termios = termios;
45*bb4ee6a4SAndroid Build Coastguard Worker f(&mut new_termios);
46*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
47*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the syscall will only read the extent of termios and we check the return result.
48*bb4ee6a4SAndroid Build Coastguard Worker let ret = unsafe { tcsetattr(fd, TCSANOW, &new_termios as *const _) };
49*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 {
50*bb4ee6a4SAndroid Build Coastguard Worker return errno_result();
51*bb4ee6a4SAndroid Build Coastguard Worker }
52*bb4ee6a4SAndroid Build Coastguard Worker
53*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
54*bb4ee6a4SAndroid Build Coastguard Worker }
55*bb4ee6a4SAndroid Build Coastguard Worker
56*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
57*bb4ee6a4SAndroid Build Coastguard Worker ///
58*bb4ee6a4SAndroid Build Coastguard Worker /// Safe only when the FD given is valid and reading the fd will have no Rust safety implications.
read_raw(fd: RawFd, out: &mut [u8]) -> Result<usize>59*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn read_raw(fd: RawFd, out: &mut [u8]) -> Result<usize> {
60*bb4ee6a4SAndroid Build Coastguard Worker let ret = read(fd, out.as_mut_ptr() as *mut _, out.len());
61*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 {
62*bb4ee6a4SAndroid Build Coastguard Worker return errno_result();
63*bb4ee6a4SAndroid Build Coastguard Worker }
64*bb4ee6a4SAndroid Build Coastguard Worker
65*bb4ee6a4SAndroid Build Coastguard Worker Ok(ret as usize)
66*bb4ee6a4SAndroid Build Coastguard Worker }
67*bb4ee6a4SAndroid Build Coastguard Worker
68*bb4ee6a4SAndroid Build Coastguard Worker /// Read raw bytes from stdin.
69*bb4ee6a4SAndroid Build Coastguard Worker ///
70*bb4ee6a4SAndroid Build Coastguard Worker /// This will block depending on the underlying mode of stdin. This will ignore the usual lock
71*bb4ee6a4SAndroid Build Coastguard Worker /// around stdin that the stdlib usually uses. If other code is using stdin, it is undefined who
72*bb4ee6a4SAndroid Build Coastguard Worker /// will get the underlying bytes.
read_raw_stdin(out: &mut [u8]) -> Result<usize>73*bb4ee6a4SAndroid Build Coastguard Worker pub fn read_raw_stdin(out: &mut [u8]) -> Result<usize> {
74*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
75*bb4ee6a4SAndroid Build Coastguard Worker // Safe because reading from stdin shouldn't have any safety implications.
76*bb4ee6a4SAndroid Build Coastguard Worker unsafe { read_raw(STDIN_FILENO, out) }
77*bb4ee6a4SAndroid Build Coastguard Worker }
78*bb4ee6a4SAndroid Build Coastguard Worker
79*bb4ee6a4SAndroid Build Coastguard Worker /// Trait for file descriptors that are TTYs, according to `isatty(3)`.
80*bb4ee6a4SAndroid Build Coastguard Worker ///
81*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
82*bb4ee6a4SAndroid Build Coastguard Worker /// This is marked unsafe because the implementation must promise that the returned RawFd is a valid
83*bb4ee6a4SAndroid Build Coastguard Worker /// fd and that the lifetime of the returned fd is at least that of the trait object.
84*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe trait Terminal {
85*bb4ee6a4SAndroid Build Coastguard Worker /// Gets the file descriptor of the TTY.
tty_fd(&self) -> RawFd86*bb4ee6a4SAndroid Build Coastguard Worker fn tty_fd(&self) -> RawFd;
87*bb4ee6a4SAndroid Build Coastguard Worker
88*bb4ee6a4SAndroid Build Coastguard Worker /// Set this terminal's mode to canonical mode (`ICANON | ECHO | ISIG`).
set_canon_mode(&self) -> Result<()>89*bb4ee6a4SAndroid Build Coastguard Worker fn set_canon_mode(&self) -> Result<()> {
90*bb4ee6a4SAndroid Build Coastguard Worker modify_mode(self.tty_fd(), |t| t.c_lflag |= ICANON | ECHO | ISIG)
91*bb4ee6a4SAndroid Build Coastguard Worker }
92*bb4ee6a4SAndroid Build Coastguard Worker
93*bb4ee6a4SAndroid Build Coastguard Worker /// Set this terminal's mode to raw mode (`!(ICANON | ECHO | ISIG)`).
set_raw_mode(&self) -> Result<()>94*bb4ee6a4SAndroid Build Coastguard Worker fn set_raw_mode(&self) -> Result<()> {
95*bb4ee6a4SAndroid Build Coastguard Worker modify_mode(self.tty_fd(), |t| t.c_lflag &= !(ICANON | ECHO | ISIG))
96*bb4ee6a4SAndroid Build Coastguard Worker }
97*bb4ee6a4SAndroid Build Coastguard Worker
98*bb4ee6a4SAndroid Build Coastguard Worker /// Sets the non-blocking mode of this terminal's file descriptor.
99*bb4ee6a4SAndroid Build Coastguard Worker ///
100*bb4ee6a4SAndroid Build Coastguard Worker /// If `non_block` is `true`, then `read_raw` will not block. If `non_block` is `false`, then
101*bb4ee6a4SAndroid Build Coastguard Worker /// `read_raw` may block if there is nothing to read.
set_non_block(&self, non_block: bool) -> Result<()>102*bb4ee6a4SAndroid Build Coastguard Worker fn set_non_block(&self, non_block: bool) -> Result<()> {
103*bb4ee6a4SAndroid Build Coastguard Worker if non_block {
104*bb4ee6a4SAndroid Build Coastguard Worker add_fd_flags(self.tty_fd(), O_NONBLOCK)
105*bb4ee6a4SAndroid Build Coastguard Worker } else {
106*bb4ee6a4SAndroid Build Coastguard Worker clear_fd_flags(self.tty_fd(), O_NONBLOCK)
107*bb4ee6a4SAndroid Build Coastguard Worker }
108*bb4ee6a4SAndroid Build Coastguard Worker }
109*bb4ee6a4SAndroid Build Coastguard Worker }
110*bb4ee6a4SAndroid Build Coastguard Worker
111*bb4ee6a4SAndroid Build Coastguard Worker // # SAFETY:
112*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we return a genuine terminal fd that never changes and shares our lifetime.
113*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl Terminal for Stdin {
tty_fd(&self) -> RawFd114*bb4ee6a4SAndroid Build Coastguard Worker fn tty_fd(&self) -> RawFd {
115*bb4ee6a4SAndroid Build Coastguard Worker STDIN_FILENO
116*bb4ee6a4SAndroid Build Coastguard Worker }
117*bb4ee6a4SAndroid Build Coastguard Worker }
118