mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 17:03:23 +00:00
Implement pseudo terminal
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
a042da1847
commit
f802ff40c5
@ -7,6 +7,7 @@ mod zero;
|
|||||||
|
|
||||||
use crate::fs::device::{add_node, Device, DeviceId, DeviceType};
|
use crate::fs::device::{add_node, Device, DeviceId, DeviceType};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
pub use pty::{PtyMaster, PtySlave};
|
||||||
pub use random::Random;
|
pub use random::Random;
|
||||||
pub use urandom::Urandom;
|
pub use urandom::Urandom;
|
||||||
|
|
||||||
|
261
services/libs/jinux-std/src/device/pty/master.rs
Normal file
261
services/libs/jinux-std/src/device/pty/master.rs
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
use crate::{
|
||||||
|
fs::{
|
||||||
|
file_handle::FileLike,
|
||||||
|
fs_resolver::FsPath,
|
||||||
|
utils::{AccessMode, Inode, InodeMode, IoEvents, IoctlCmd, Poller},
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
util::{read_val_from_user, write_val_to_user},
|
||||||
|
};
|
||||||
|
use alloc::format;
|
||||||
|
use jinux_frame::sync::SpinLock;
|
||||||
|
use ringbuf::{ring_buffer::RbBase, HeapRb, Rb};
|
||||||
|
|
||||||
|
use crate::{device::tty::line_discipline::LineDiscipline, fs::utils::Pollee};
|
||||||
|
|
||||||
|
use super::slave::PtySlave;
|
||||||
|
|
||||||
|
const PTS_DIR: &str = "/dev/pts";
|
||||||
|
const BUFFER_CAPACITY: usize = 4096;
|
||||||
|
|
||||||
|
/// Pesudo terminal master.
|
||||||
|
/// Internally, it has two buffers.
|
||||||
|
/// One is inside ldisc, which is written by master and read by slave,
|
||||||
|
/// the other is a ring buffer, which is written by slave and read by master.
|
||||||
|
pub struct PtyMaster {
|
||||||
|
ptmx: Arc<dyn Inode>,
|
||||||
|
index: usize,
|
||||||
|
ldisc: LineDiscipline,
|
||||||
|
master_buffer: SpinLock<HeapRb<u8>>,
|
||||||
|
/// The state of master buffer
|
||||||
|
pollee: Pollee,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PtyMaster {
|
||||||
|
pub fn new_pair(index: u32, ptmx: Arc<dyn Inode>) -> Result<(Arc<PtyMaster>, Arc<PtySlave>)> {
|
||||||
|
debug!("allocate pty index = {}", index);
|
||||||
|
let master = Arc::new(PtyMaster {
|
||||||
|
ptmx,
|
||||||
|
index: index as usize,
|
||||||
|
master_buffer: SpinLock::new(HeapRb::new(BUFFER_CAPACITY)),
|
||||||
|
pollee: Pollee::new(IoEvents::OUT),
|
||||||
|
ldisc: LineDiscipline::new(),
|
||||||
|
});
|
||||||
|
let slave = Arc::new(PtySlave::new(master.clone()));
|
||||||
|
Ok((master, slave))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
self.index
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptmx(&self) -> &Arc<dyn Inode> {
|
||||||
|
&self.ptmx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn slave_push_char(&self, item: u8) -> Result<()> {
|
||||||
|
let mut buf = self.master_buffer.lock_irq_disabled();
|
||||||
|
if buf.is_full() {
|
||||||
|
return_errno_with_message!(Errno::EIO, "the buffer is full");
|
||||||
|
}
|
||||||
|
// Unwrap safety: the buf is not full, so push will always succeed.
|
||||||
|
buf.push(item).unwrap();
|
||||||
|
self.update_state(&buf);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn slave_read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
self.ldisc.read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn slave_poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
||||||
|
let poll_out_mask = mask & IoEvents::OUT;
|
||||||
|
let poll_in_mask = mask & IoEvents::IN;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut poll_status = IoEvents::empty();
|
||||||
|
|
||||||
|
if !poll_in_mask.is_empty() {
|
||||||
|
let poll_in_status = self.ldisc.poll(poll_in_mask, poller);
|
||||||
|
poll_status |= poll_in_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !poll_out_mask.is_empty() {
|
||||||
|
let poll_out_status = self.pollee.poll(poll_out_mask, poller);
|
||||||
|
poll_status |= poll_out_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !poll_status.is_empty() || poller.is_none() {
|
||||||
|
return poll_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
poller.unwrap().wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_state(&self, buf: &HeapRb<u8>) {
|
||||||
|
if buf.is_full() {
|
||||||
|
self.pollee.del_events(IoEvents::OUT);
|
||||||
|
} else {
|
||||||
|
self.pollee.add_events(IoEvents::OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if buf.is_empty() {
|
||||||
|
self.pollee.del_events(IoEvents::IN)
|
||||||
|
} else {
|
||||||
|
self.pollee.add_events(IoEvents::IN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileLike for PtyMaster {
|
||||||
|
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
// TODO: deal with nonblocking read
|
||||||
|
if buf.len() == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let poller = Poller::new();
|
||||||
|
loop {
|
||||||
|
let mut master_buf = self.master_buffer.lock_irq_disabled();
|
||||||
|
|
||||||
|
if master_buf.is_empty() {
|
||||||
|
self.update_state(&master_buf);
|
||||||
|
let events = self.pollee.poll(IoEvents::IN, Some(&poller));
|
||||||
|
if !events.contains(IoEvents::IN) {
|
||||||
|
drop(master_buf);
|
||||||
|
poller.wait();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let read_len = master_buf.len().min(buf.len());
|
||||||
|
master_buf.pop_slice(&mut buf[..read_len]);
|
||||||
|
self.update_state(&master_buf);
|
||||||
|
return Ok(read_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||||
|
let mut master_buf = self.master_buffer.lock();
|
||||||
|
|
||||||
|
if self.ldisc.termios().contain_echo() && master_buf.len() + buf.len() > BUFFER_CAPACITY {
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EIO,
|
||||||
|
"the written bytes exceeds the master buf capacity"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for item in buf {
|
||||||
|
self.ldisc.push_char(*item, |content| {
|
||||||
|
for byte in content.as_bytes() {
|
||||||
|
// Unwrap safety: the master buf is ensured to have enough space.
|
||||||
|
master_buf.push(*byte).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update_state(&master_buf);
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||||
|
match cmd {
|
||||||
|
IoctlCmd::TCGETS => {
|
||||||
|
let termios = self.ldisc.termios();
|
||||||
|
write_val_to_user(arg, &termios)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TCSETS => {
|
||||||
|
let termios = read_val_from_user(arg)?;
|
||||||
|
self.ldisc.set_termios(termios);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCSPTLCK => {
|
||||||
|
// TODO: lock/unlock pty
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCGPTN => {
|
||||||
|
let idx = self.index() as u32;
|
||||||
|
write_val_to_user(arg, &idx)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCGPTPEER => {
|
||||||
|
let current = current!();
|
||||||
|
|
||||||
|
// TODO: deal with open options
|
||||||
|
let slave = {
|
||||||
|
let slave_name = format!("{}/{}", PTS_DIR, self.index());
|
||||||
|
let fs_path = FsPath::try_from(slave_name.as_str())?;
|
||||||
|
|
||||||
|
let inode_handle = {
|
||||||
|
let fs = current.fs().read();
|
||||||
|
let flags = AccessMode::O_RDWR as u32;
|
||||||
|
let mode = (InodeMode::S_IRUSR | InodeMode::S_IWUSR).bits();
|
||||||
|
fs.open(&fs_path, flags, mode)?
|
||||||
|
};
|
||||||
|
Arc::new(inode_handle)
|
||||||
|
};
|
||||||
|
|
||||||
|
let fd = {
|
||||||
|
let mut file_table = current.file_table().lock();
|
||||||
|
file_table.insert(slave)
|
||||||
|
};
|
||||||
|
Ok(fd)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCGWINSZ => Ok(0),
|
||||||
|
IoctlCmd::TIOCSCTTY => {
|
||||||
|
// TODO
|
||||||
|
let foreground = {
|
||||||
|
let current = current!();
|
||||||
|
let process_group = current.process_group().lock();
|
||||||
|
process_group.clone()
|
||||||
|
};
|
||||||
|
self.ldisc.set_fg(foreground);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCGPGRP => {
|
||||||
|
let Some(fg_pgid) = self.ldisc.fg_pgid() else {
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::ESRCH,
|
||||||
|
"the foreground process group does not exist"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
write_val_to_user(arg, &fg_pgid)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCNOTTY => {
|
||||||
|
self.ldisc.set_fg(Weak::new());
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
_ => Ok(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
||||||
|
let poll_out_mask = mask & IoEvents::OUT;
|
||||||
|
let poll_in_mask = mask & IoEvents::IN;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let _master_buf = self.master_buffer.lock_irq_disabled();
|
||||||
|
|
||||||
|
let mut poll_status = IoEvents::empty();
|
||||||
|
|
||||||
|
if !poll_in_mask.is_empty() {
|
||||||
|
let poll_in_status = self.pollee.poll(poll_in_mask, poller);
|
||||||
|
poll_status |= poll_in_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !poll_out_mask.is_empty() {
|
||||||
|
let poll_out_status = self.ldisc.poll(poll_out_mask, poller);
|
||||||
|
poll_status |= poll_out_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !poll_status.is_empty() || poller.is_none() {
|
||||||
|
return poll_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
poller.unwrap().wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,9 @@
|
|||||||
|
mod master;
|
||||||
|
mod slave;
|
||||||
|
|
||||||
|
pub use master::PtyMaster;
|
||||||
|
pub use slave::PtySlave;
|
||||||
|
|
||||||
use crate::fs::{
|
use crate::fs::{
|
||||||
devpts::DevPts,
|
devpts::DevPts,
|
||||||
fs_resolver::{FsPath, FsResolver},
|
fs_resolver::{FsPath, FsResolver},
|
65
services/libs/jinux-std/src/device/pty/slave.rs
Normal file
65
services/libs/jinux-std/src/device/pty/slave.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use crate::fs::device::{Device, DeviceId, DeviceType};
|
||||||
|
use crate::fs::file_handle::FileLike;
|
||||||
|
use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
use super::master::PtyMaster;
|
||||||
|
|
||||||
|
pub struct PtySlave(Arc<PtyMaster>);
|
||||||
|
|
||||||
|
impl PtySlave {
|
||||||
|
pub fn new(master: Arc<PtyMaster>) -> Self {
|
||||||
|
PtySlave(master)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
self.0.index()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for PtySlave {
|
||||||
|
fn type_(&self) -> DeviceType {
|
||||||
|
DeviceType::CharDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> crate::fs::device::DeviceId {
|
||||||
|
DeviceId::new(88, self.index() as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
self.0.slave_read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||||
|
for ch in buf {
|
||||||
|
// do we need to add '\r' here?
|
||||||
|
if *ch == b'\n' {
|
||||||
|
self.0.slave_push_char(b'\r')?;
|
||||||
|
self.0.slave_push_char(b'\n')?;
|
||||||
|
} else {
|
||||||
|
self.0.slave_push_char(*ch)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||||
|
match cmd {
|
||||||
|
IoctlCmd::TCGETS | IoctlCmd::TCSETS | IoctlCmd::TIOCGPGRP => self.0.ioctl(cmd, arg),
|
||||||
|
IoctlCmd::TIOCGWINSZ => Ok(0),
|
||||||
|
IoctlCmd::TIOCSCTTY => {
|
||||||
|
// TODO:
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCNOTTY => {
|
||||||
|
// TODO:
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
_ => Ok(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
||||||
|
self.0.slave_poll(mask, poller)
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ use crate::process::process_group::ProcessGroup;
|
|||||||
use crate::process::signal::constants::{SIGINT, SIGQUIT};
|
use crate::process::signal::constants::{SIGINT, SIGQUIT};
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{process_table, signal::signals::kernel::KernelSignal, Pgid},
|
process::{signal::signals::kernel::KernelSignal, Pgid},
|
||||||
};
|
};
|
||||||
use alloc::format;
|
use alloc::format;
|
||||||
use jinux_frame::trap::disable_local;
|
use jinux_frame::trap::disable_local;
|
||||||
@ -77,7 +77,7 @@ impl LineDiscipline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Push char to line discipline.
|
/// Push char to line discipline.
|
||||||
pub fn push_char(&self, mut item: u8, echo_callback: fn(&str)) {
|
pub fn push_char<F: FnMut(&str)>(&self, mut item: u8, echo_callback: F) {
|
||||||
let termios = self.termios.lock_irq_disabled();
|
let termios = self.termios.lock_irq_disabled();
|
||||||
if termios.contains_icrnl() && item == b'\r' {
|
if termios.contains_icrnl() && item == b'\r' {
|
||||||
item = b'\n'
|
item = b'\n'
|
||||||
@ -162,7 +162,7 @@ impl LineDiscipline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: respect output flags
|
// TODO: respect output flags
|
||||||
fn output_char(&self, item: u8, termios: &KernelTermios, echo_callback: fn(&str)) {
|
fn output_char<F: FnMut(&str)>(&self, item: u8, termios: &KernelTermios, mut echo_callback: F) {
|
||||||
match item {
|
match item {
|
||||||
b'\n' => echo_callback("\n"),
|
b'\n' => echo_callback("\n"),
|
||||||
b'\r' => echo_callback("\r\n"),
|
b'\r' => echo_callback("\r\n"),
|
||||||
|
@ -6,7 +6,7 @@ use super::*;
|
|||||||
use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
|
use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::process::process_group::ProcessGroup;
|
use crate::process::process_group::ProcessGroup;
|
||||||
use crate::process::{process_table, Pgid};
|
use crate::process::process_table;
|
||||||
use crate::util::{read_val_from_user, write_val_to_user};
|
use crate::util::{read_val_from_user, write_val_to_user};
|
||||||
|
|
||||||
pub mod driver;
|
pub mod driver;
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use crate::prelude::*;
|
use crate::{fs::file_handle::FileLike, prelude::*};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use crate::device::PtyMaster;
|
||||||
|
|
||||||
/// Pty master inode for the master device.
|
/// Pty master inode for the master device.
|
||||||
pub struct PtyMasterInode(Arc<PtyMaster>);
|
pub struct PtyMasterInode(Arc<PtyMaster>);
|
||||||
|
|
||||||
@ -14,8 +16,10 @@ impl PtyMasterInode {
|
|||||||
impl Drop for PtyMasterInode {
|
impl Drop for PtyMasterInode {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Remove the slave from fs.
|
// Remove the slave from fs.
|
||||||
let index = self.0.slave_index();
|
let index = self.0.index();
|
||||||
let _ = self.0.ptmx().devpts().remove_slave(index);
|
let fs = self.0.ptmx().fs();
|
||||||
|
let devpts = fs.downcast_ref::<DevPts>().unwrap();
|
||||||
|
devpts.remove_slave(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,52 +81,6 @@ impl Inode for PtyMasterInode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||||
self.0.ptmx().devpts()
|
self.0.ptmx().fs()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement real pty master.
|
|
||||||
pub struct PtyMaster {
|
|
||||||
slave_index: u32,
|
|
||||||
ptmx: Arc<Ptmx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PtyMaster {
|
|
||||||
pub fn new(slave_index: u32, ptmx: Arc<Ptmx>) -> Arc<Self> {
|
|
||||||
Arc::new(Self { slave_index, ptmx })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn slave_index(&self) -> u32 {
|
|
||||||
self.slave_index
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ptmx(&self) -> &Ptmx {
|
|
||||||
&self.ptmx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device for PtyMaster {
|
|
||||||
fn type_(&self) -> DeviceType {
|
|
||||||
self.ptmx.device_type()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id(&self) -> DeviceId {
|
|
||||||
self.ptmx.device_id()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
|
||||||
todo!();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,10 @@ use core::time::Duration;
|
|||||||
use jinux_frame::vm::VmFrame;
|
use jinux_frame::vm::VmFrame;
|
||||||
use jinux_util::{id_allocator::IdAlloc, slot_vec::SlotVec};
|
use jinux_util::{id_allocator::IdAlloc, slot_vec::SlotVec};
|
||||||
|
|
||||||
use self::master::{PtyMaster, PtyMasterInode};
|
use self::master::PtyMasterInode;
|
||||||
use self::ptmx::Ptmx;
|
use self::ptmx::Ptmx;
|
||||||
use self::slave::{PtySlave, PtySlaveInode};
|
use self::slave::PtySlaveInode;
|
||||||
|
use crate::device::PtyMaster;
|
||||||
|
|
||||||
mod master;
|
mod master;
|
||||||
mod ptmx;
|
mod ptmx;
|
||||||
@ -60,8 +61,7 @@ impl DevPts {
|
|||||||
.alloc()
|
.alloc()
|
||||||
.ok_or_else(|| Error::with_message(Errno::EIO, "cannot alloc index"))?;
|
.ok_or_else(|| Error::with_message(Errno::EIO, "cannot alloc index"))?;
|
||||||
|
|
||||||
let master = PtyMaster::new(index as u32, self.root.ptmx.clone());
|
let (master, slave) = PtyMaster::new_pair(index as u32, self.root.ptmx.clone())?;
|
||||||
let slave = PtySlave::new(master.clone());
|
|
||||||
|
|
||||||
let master_inode = PtyMasterInode::new(master);
|
let master_inode = PtyMasterInode::new(master);
|
||||||
let slave_inode = PtySlaveInode::new(slave, self.this.clone());
|
let slave_inode = PtySlaveInode::new(slave, self.this.clone());
|
||||||
@ -73,10 +73,10 @@ impl DevPts {
|
|||||||
/// Remove the slave from fs.
|
/// Remove the slave from fs.
|
||||||
///
|
///
|
||||||
/// This is called when the master is being dropped.
|
/// This is called when the master is being dropped.
|
||||||
fn remove_slave(&self, index: u32) -> Option<Arc<PtySlaveInode>> {
|
fn remove_slave(&self, index: usize) -> Option<Arc<PtySlaveInode>> {
|
||||||
let removed_slave = self.root.remove_slave(&index.to_string());
|
let removed_slave = self.root.remove_slave(&index.to_string());
|
||||||
if removed_slave.is_some() {
|
if removed_slave.is_some() {
|
||||||
self.index_alloc.lock().free(index as usize);
|
self.index_alloc.lock().free(index);
|
||||||
}
|
}
|
||||||
removed_slave
|
removed_slave
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ use crate::prelude::*;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
use crate::device::PtySlave;
|
||||||
|
|
||||||
/// Same major number with Linux, the minor number is the index of slave.
|
/// Same major number with Linux, the minor number is the index of slave.
|
||||||
const SLAVE_MAJOR_NUM: u32 = 3;
|
const SLAVE_MAJOR_NUM: u32 = 3;
|
||||||
|
|
||||||
@ -88,44 +90,3 @@ impl Inode for PtySlaveInode {
|
|||||||
self.fs.upgrade().unwrap()
|
self.fs.upgrade().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement real pty slave.
|
|
||||||
pub struct PtySlave {
|
|
||||||
master: Arc<PtyMaster>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PtySlave {
|
|
||||||
pub fn new(master: Arc<PtyMaster>) -> Arc<Self> {
|
|
||||||
Arc::new(Self { master })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn index(&self) -> u32 {
|
|
||||||
self.master.slave_index()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device for PtySlave {
|
|
||||||
fn type_(&self) -> DeviceType {
|
|
||||||
DeviceType::CharDevice
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id(&self) -> DeviceId {
|
|
||||||
DeviceId::new(SLAVE_MAJOR_NUM, self.index())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -3,18 +3,28 @@ use crate::prelude::*;
|
|||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Debug, Clone, Copy, TryFromInt)]
|
#[derive(Debug, Clone, Copy, TryFromInt)]
|
||||||
pub enum IoctlCmd {
|
pub enum IoctlCmd {
|
||||||
// Get terminal attributes
|
/// Get terminal attributes
|
||||||
TCGETS = 0x5401,
|
TCGETS = 0x5401,
|
||||||
TCSETS = 0x5402,
|
TCSETS = 0x5402,
|
||||||
// Drain the output buffer and set attributes
|
/// Drain the output buffer and set attributes
|
||||||
TCSETSW = 0x5403,
|
TCSETSW = 0x5403,
|
||||||
// Drain the output buffer, and discard pending input, and set attributes
|
/// Drain the output buffer, and discard pending input, and set attributes
|
||||||
TCSETSF = 0x5404,
|
TCSETSF = 0x5404,
|
||||||
// Get the process group ID of the foreground process group on this terminal
|
/// Make the given terminal the controlling terminal of the calling process.
|
||||||
|
TIOCSCTTY = 0x540e,
|
||||||
|
/// Get the process group ID of the foreground process group on this terminal
|
||||||
TIOCGPGRP = 0x540f,
|
TIOCGPGRP = 0x540f,
|
||||||
// Set the foreground process group ID of this terminal.
|
/// Set the foreground process group ID of this terminal.
|
||||||
TIOCSPGRP = 0x5410,
|
TIOCSPGRP = 0x5410,
|
||||||
// Set window size
|
/// Set window size
|
||||||
TIOCGWINSZ = 0x5413,
|
TIOCGWINSZ = 0x5413,
|
||||||
TIOCSWINSZ = 0x5414,
|
TIOCSWINSZ = 0x5414,
|
||||||
|
/// the calling process gives up this controlling terminal
|
||||||
|
TIOCNOTTY = 0x5422,
|
||||||
|
/// Get Pty Number
|
||||||
|
TIOCGPTN = 0x80045430,
|
||||||
|
/// Lock/unlock Pty
|
||||||
|
TIOCSPTLCK = 0x40045431,
|
||||||
|
/// Safely open the slave
|
||||||
|
TIOCGPTPEER = 0x40045441,
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user