(fd: BorrowedFd<'_>, buf: &mut [MaybeUninit<u8>])
| 370 | #[cfg(feature = "alloc")] |
| 371 | #[cfg(feature = "fs")] |
| 372 | pub(crate) fn ttyname(fd: BorrowedFd<'_>, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> { |
| 373 | let fd_stat = crate::backend::fs::syscalls::fstat(fd)?; |
| 374 | |
| 375 | // Quick check: if `fd` isn't a character device, it's not a tty. |
| 376 | if FileType::from_raw_mode(fd_stat.st_mode) != FileType::CharacterDevice { |
| 377 | return Err(io::Errno::NOTTY); |
| 378 | } |
| 379 | |
| 380 | // Check that `fd` is really a tty. |
| 381 | tcgetwinsize(fd)?; |
| 382 | |
| 383 | // Create the "/proc/self/fd/<fd>" string. |
| 384 | let mut proc_self_fd_buf: [u8; 25] = *b"/proc/self/fd/\0\0\0\0\0\0\0\0\0\0\0"; |
| 385 | let dec_int = DecInt::from_fd(fd); |
| 386 | let bytes_with_nul = dec_int.as_bytes_with_nul(); |
| 387 | proc_self_fd_buf[b"/proc/self/fd/".len()..][..bytes_with_nul.len()] |
| 388 | .copy_from_slice(bytes_with_nul); |
| 389 | |
| 390 | // SAFETY: We just wrote a valid C String. |
| 391 | let proc_self_fd_path = unsafe { CStr::from_ptr(proc_self_fd_buf.as_ptr().cast()) }; |
| 392 | |
| 393 | let ptr = buf.as_mut_ptr(); |
| 394 | let len = { |
| 395 | // Gather the ttyname by reading the "fd" file inside `proc_self_fd`. |
| 396 | let (init, uninit) = crate::fs::readlinkat_raw(crate::fs::CWD, proc_self_fd_path, buf)?; |
| 397 | |
| 398 | // If the number of bytes is equal to the buffer length, truncation may |
| 399 | // have occurred. This check also ensures that we have enough space for |
| 400 | // adding a NUL terminator. |
| 401 | if uninit.is_empty() { |
| 402 | return Err(io::Errno::RANGE); |
| 403 | } |
| 404 | |
| 405 | // `readlinkat` returns the number of bytes placed in the buffer. |
| 406 | // NUL-terminate the string at that offset. |
| 407 | uninit[0].write(b'\0'); |
| 408 | |
| 409 | init.len() |
| 410 | }; |
| 411 | |
| 412 | // Check that the path we read refers to the same file as `fd`. |
| 413 | { |
| 414 | // SAFETY: We just wrote the NUL byte above. |
| 415 | let path = unsafe { CStr::from_ptr(ptr.cast()) }; |
| 416 | |
| 417 | let path_stat = crate::backend::fs::syscalls::stat(path)?; |
| 418 | if path_stat.st_dev != fd_stat.st_dev || path_stat.st_ino != fd_stat.st_ino { |
| 419 | return Err(io::Errno::NODEV); |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | // Return the length, excluding the NUL terminator. |
| 424 | Ok(len) |
| 425 | } |
nothing calls this directly
no test coverage detected