MCPcopy Create free account
hub / github.com/bytecodealliance/rustix / ttyname

Function ttyname

src/backend/linux_raw/termios/syscalls.rs:372–425  ·  view source on GitHub ↗
(fd: BorrowedFd<'_>, buf: &mut [MaybeUninit<u8>])

Source from the content-addressed store, hash-verified

370#[cfg(feature = "alloc")]
371#[cfg(feature = "fs")]
372pub(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}

Callers

nothing calls this directly

Calls 8

readlinkat_rawFunction · 0.85
as_bytes_with_nulMethod · 0.80
tcgetwinsizeFunction · 0.70
fstatFunction · 0.50
statFunction · 0.50
lenMethod · 0.45
as_ptrMethod · 0.45
as_mut_ptrMethod · 0.45

Tested by

no test coverage detected