• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Functions which operate on file descriptors which might be terminals.
2 
3 use crate::backend;
4 #[cfg(any(
5     all(linux_raw, feature = "procfs"),
6     all(libc, not(any(target_os = "fuchsia", target_os = "wasi"))),
7 ))]
8 use crate::io;
9 use backend::fd::AsFd;
10 #[cfg(any(
11     all(linux_raw, feature = "procfs"),
12     all(libc, not(any(target_os = "fuchsia", target_os = "wasi"))),
13 ))]
14 use {
15     crate::ffi::CString, crate::path::SMALL_PATH_BUFFER_SIZE, alloc::vec::Vec,
16     backend::fd::BorrowedFd,
17 };
18 
19 /// `isatty(fd)`—Tests whether a file descriptor refers to a terminal.
20 ///
21 /// # References
22 ///  - [POSIX]
23 ///  - [Linux]
24 ///
25 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/isatty.html
26 /// [Linux]: https://man7.org/linux/man-pages/man3/isatty.3.html
27 #[inline]
isatty<Fd: AsFd>(fd: Fd) -> bool28 pub fn isatty<Fd: AsFd>(fd: Fd) -> bool {
29     backend::termios::syscalls::isatty(fd.as_fd())
30 }
31 
32 /// `ttyname_r(fd)`
33 ///
34 /// If `reuse` is non-empty, reuse its buffer to store the result if possible.
35 ///
36 /// # References
37 ///  - [POSIX]
38 ///  - [Linux]
39 ///
40 /// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/ttyname.html
41 /// [Linux]: https://man7.org/linux/man-pages/man3/ttyname.3.html
42 #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
43 #[cfg(feature = "procfs")]
44 #[cfg_attr(doc_cfg, doc(cfg(feature = "procfs")))]
45 #[inline]
ttyname<Fd: AsFd, B: Into<Vec<u8>>>(dirfd: Fd, reuse: B) -> io::Result<CString>46 pub fn ttyname<Fd: AsFd, B: Into<Vec<u8>>>(dirfd: Fd, reuse: B) -> io::Result<CString> {
47     _ttyname(dirfd.as_fd(), reuse.into())
48 }
49 
50 #[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
51 #[cfg(feature = "procfs")]
_ttyname(dirfd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<CString>52 fn _ttyname(dirfd: BorrowedFd<'_>, mut buffer: Vec<u8>) -> io::Result<CString> {
53     // This code would benefit from having a better way to read into
54     // uninitialized memory, but that requires `unsafe`.
55     buffer.clear();
56     buffer.reserve(SMALL_PATH_BUFFER_SIZE);
57     buffer.resize(buffer.capacity(), 0_u8);
58 
59     loop {
60         match backend::termios::syscalls::ttyname(dirfd, &mut buffer) {
61             Err(io::Errno::RANGE) => {
62                 buffer.reserve(1); // use `Vec` reallocation strategy to grow capacity exponentially
63                 buffer.resize(buffer.capacity(), 0_u8);
64             }
65             Ok(len) => {
66                 buffer.resize(len, 0_u8);
67                 return Ok(CString::new(buffer).unwrap());
68             }
69             Err(errno) => return Err(errno),
70         }
71     }
72 }
73