mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-18 12:06:43 +00:00
Refactor the pty implementation
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
40056f0692
commit
038c19b693
@ -15,8 +15,6 @@ int main() {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("master fd: %d\n", master);
|
|
||||||
printf("slave fd: %d\n", slave);
|
|
||||||
printf("slave name: %s\n", name);
|
printf("slave name: %s\n", name);
|
||||||
|
|
||||||
// Set pty slave terminal attributes
|
// Set pty slave terminal attributes
|
||||||
@ -33,7 +31,7 @@ int main() {
|
|||||||
char buf[256];
|
char buf[256];
|
||||||
ssize_t n = read(master, buf, sizeof(buf));
|
ssize_t n = read(master, buf, sizeof(buf));
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
printf("read %ld bytes from slave: %.*s\n", n, (int)n, buf);
|
printf("read %ld bytes from slave: %.*s", n, (int)n, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to pty master
|
// Write to pty master
|
||||||
@ -43,7 +41,7 @@ int main() {
|
|||||||
char nbuf[256];
|
char nbuf[256];
|
||||||
ssize_t nn = read(slave, nbuf, sizeof(nbuf));
|
ssize_t nn = read(slave, nbuf, sizeof(nbuf));
|
||||||
if (nn > 0) {
|
if (nn > 0) {
|
||||||
printf("read %ld bytes from master: %.*s\n", nn, (int)nn, nbuf);
|
printf("read %ld bytes from master: %.*s", nn, (int)nn, nbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(master);
|
close(master);
|
||||||
|
@ -6,7 +6,7 @@ SCRIPT_DIR=/regression
|
|||||||
cd ${SCRIPT_DIR}/..
|
cd ${SCRIPT_DIR}/..
|
||||||
|
|
||||||
echo "Running tests......"
|
echo "Running tests......"
|
||||||
tests="hello_world/hello_world fork/fork execve/execve fork_c/fork signal_c/signal_test pthread/pthread_test hello_pie/hello"
|
tests="hello_world/hello_world fork/fork execve/execve fork_c/fork signal_c/signal_test pthread/pthread_test hello_pie/hello pty/open_pty"
|
||||||
for testcase in ${tests}
|
for testcase in ${tests}
|
||||||
do
|
do
|
||||||
echo "Running test ${testcase}......"
|
echo "Running test ${testcase}......"
|
||||||
|
@ -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::new_pty_pair;
|
||||||
pub use pty::{PtyMaster, PtySlave};
|
pub use pty::{PtyMaster, PtySlave};
|
||||||
pub use random::Random;
|
pub use random::Random;
|
||||||
pub use urandom::Urandom;
|
pub use urandom::Urandom;
|
||||||
|
@ -1,260 +0,0 @@
|
|||||||
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();
|
|
||||||
buf.push_overwrite(item);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn slave_buf_len(&self) -> usize {
|
|
||||||
self.ldisc.buffer_len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_state(&self, buf: &HeapRb<u8>) {
|
|
||||||
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();
|
|
||||||
|
|
||||||
for item in buf {
|
|
||||||
self.ldisc.push_char(*item, |content| {
|
|
||||||
for byte in content.as_bytes() {
|
|
||||||
master_buf.push_overwrite(*byte);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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 => {
|
|
||||||
let winsize = self.ldisc.window_size();
|
|
||||||
write_val_to_user(arg, &winsize)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
IoctlCmd::TIOCSWINSZ => {
|
|
||||||
let winsize = read_val_from_user(arg)?;
|
|
||||||
self.ldisc.set_window_size(winsize);
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
IoctlCmd::TIOCSCTTY => {
|
|
||||||
// TODO: reimplement when adding session.
|
|
||||||
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 => {
|
|
||||||
// TODO: reimplement when adding session.
|
|
||||||
self.ldisc.set_fg(Weak::new());
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
IoctlCmd::FIONREAD => {
|
|
||||||
let len = self.master_buffer.lock().len() as i32;
|
|
||||||
write_val_to_user(arg, &len)?;
|
|
||||||
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 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,16 +1,15 @@
|
|||||||
mod master;
|
use crate::fs::devpts::DevPts;
|
||||||
mod slave;
|
use crate::fs::fs_resolver::{FsPath, FsResolver};
|
||||||
|
use crate::fs::utils::{Dentry, Inode, InodeMode, InodeType};
|
||||||
pub use master::PtyMaster;
|
|
||||||
pub use slave::PtySlave;
|
|
||||||
|
|
||||||
use crate::fs::{
|
|
||||||
devpts::DevPts,
|
|
||||||
fs_resolver::{FsPath, FsResolver},
|
|
||||||
utils::{InodeMode, InodeType},
|
|
||||||
};
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
mod pty;
|
||||||
|
|
||||||
|
pub use pty::{PtyMaster, PtySlave};
|
||||||
|
use spin::Once;
|
||||||
|
|
||||||
|
static DEV_PTS: Once<Arc<Dentry>> = Once::new();
|
||||||
|
|
||||||
pub fn init() -> Result<()> {
|
pub fn init() -> Result<()> {
|
||||||
let fs = FsResolver::new();
|
let fs = FsResolver::new();
|
||||||
|
|
||||||
@ -19,6 +18,8 @@ pub fn init() -> Result<()> {
|
|||||||
let devpts = dev.create("pts", InodeType::Dir, InodeMode::from_bits_truncate(0o755))?;
|
let devpts = dev.create("pts", InodeType::Dir, InodeMode::from_bits_truncate(0o755))?;
|
||||||
devpts.mount(DevPts::new())?;
|
devpts.mount(DevPts::new())?;
|
||||||
|
|
||||||
|
DEV_PTS.call_once(|| devpts);
|
||||||
|
|
||||||
// Create the "ptmx" symlink.
|
// Create the "ptmx" symlink.
|
||||||
let ptmx = dev.create(
|
let ptmx = dev.create(
|
||||||
"ptmx",
|
"ptmx",
|
||||||
@ -28,3 +29,10 @@ pub fn init() -> Result<()> {
|
|||||||
ptmx.write_link("pts/ptmx")?;
|
ptmx.write_link("pts/ptmx")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_pty_pair(index: u32, ptmx: Arc<dyn Inode>) -> Result<(Arc<PtyMaster>, Arc<PtySlave>)> {
|
||||||
|
debug!("pty index = {}", index);
|
||||||
|
let master = Arc::new(PtyMaster::new(ptmx, index));
|
||||||
|
let slave = Arc::new(PtySlave::new(master.clone()));
|
||||||
|
Ok((master, slave))
|
||||||
|
}
|
||||||
|
312
services/libs/jinux-std/src/device/pty/pty.rs
Normal file
312
services/libs/jinux-std/src/device/pty/pty.rs
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
use alloc::format;
|
||||||
|
use ringbuf::{ring_buffer::RbBase, HeapRb, Rb};
|
||||||
|
|
||||||
|
use crate::device::tty::line_discipline::LineDiscipline;
|
||||||
|
use crate::fs::device::{Device, DeviceId, DeviceType};
|
||||||
|
use crate::fs::file_handle::FileLike;
|
||||||
|
use crate::fs::fs_resolver::FsPath;
|
||||||
|
use crate::fs::utils::{AccessMode, Inode, InodeMode, IoEvents, IoctlCmd, Pollee, Poller};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::util::{read_val_from_user, write_val_to_user};
|
||||||
|
|
||||||
|
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: u32,
|
||||||
|
output: LineDiscipline,
|
||||||
|
input: SpinLock<HeapRb<u8>>,
|
||||||
|
/// The state of input buffer
|
||||||
|
pollee: Pollee,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PtyMaster {
|
||||||
|
pub fn new(ptmx: Arc<dyn Inode>, index: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
ptmx,
|
||||||
|
index,
|
||||||
|
output: LineDiscipline::new(),
|
||||||
|
input: SpinLock::new(HeapRb::new(BUFFER_CAPACITY)),
|
||||||
|
pollee: Pollee::new(IoEvents::OUT),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&self) -> u32 {
|
||||||
|
self.index
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptmx(&self) -> &Arc<dyn Inode> {
|
||||||
|
&self.ptmx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn slave_push_byte(&self, byte: u8) {
|
||||||
|
let mut input = self.input.lock_irq_disabled();
|
||||||
|
input.push_overwrite(byte);
|
||||||
|
self.update_state(&input);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn slave_read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
self.output.read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn slave_poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
||||||
|
let mut poll_status = IoEvents::empty();
|
||||||
|
|
||||||
|
let poll_in_mask = mask & IoEvents::IN;
|
||||||
|
if !poll_in_mask.is_empty() {
|
||||||
|
let poll_in_status = self.output.poll(poll_in_mask, poller);
|
||||||
|
poll_status |= poll_in_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
let poll_out_mask = mask & IoEvents::OUT;
|
||||||
|
if !poll_out_mask.is_empty() {
|
||||||
|
let poll_out_status = self.pollee.poll(poll_out_mask, poller);
|
||||||
|
poll_status |= poll_out_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_status
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn slave_buf_len(&self) -> usize {
|
||||||
|
self.output.buffer_len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_state(&self, buf: &HeapRb<u8>) {
|
||||||
|
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 input = self.input.lock_irq_disabled();
|
||||||
|
|
||||||
|
if input.is_empty() {
|
||||||
|
let events = self.pollee.poll(IoEvents::IN, Some(&poller));
|
||||||
|
|
||||||
|
if events.contains(IoEvents::ERR) {
|
||||||
|
return_errno_with_message!(Errno::EACCES, "unexpected err");
|
||||||
|
}
|
||||||
|
|
||||||
|
if events.is_empty() {
|
||||||
|
drop(input);
|
||||||
|
poller.wait();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let read_len = input.len().min(buf.len());
|
||||||
|
input.pop_slice(&mut buf[..read_len]);
|
||||||
|
self.update_state(&input);
|
||||||
|
return Ok(read_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||||
|
let mut input = self.input.lock();
|
||||||
|
|
||||||
|
for character in buf {
|
||||||
|
self.output.push_char(*character, |content| {
|
||||||
|
for byte in content.as_bytes() {
|
||||||
|
input.push_overwrite(*byte);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.update_state(&input);
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||||
|
match cmd {
|
||||||
|
IoctlCmd::TCGETS => {
|
||||||
|
let termios = self.output.termios();
|
||||||
|
write_val_to_user(arg, &termios)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TCSETS => {
|
||||||
|
let termios = read_val_from_user(arg)?;
|
||||||
|
self.output.set_termios(termios);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCSPTLCK => {
|
||||||
|
// TODO: lock/unlock pty
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCGPTN => {
|
||||||
|
let idx = self.index();
|
||||||
|
write_val_to_user(arg, &idx)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCGPTPEER => {
|
||||||
|
let current = current!();
|
||||||
|
|
||||||
|
// TODO: deal with open options
|
||||||
|
let slave = {
|
||||||
|
let slave_name = {
|
||||||
|
let devpts_path = super::DEV_PTS.get().unwrap().abs_path();
|
||||||
|
format!("{}/{}", devpts_path, 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 => {
|
||||||
|
let winsize = self.output.window_size();
|
||||||
|
write_val_to_user(arg, &winsize)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCSWINSZ => {
|
||||||
|
let winsize = read_val_from_user(arg)?;
|
||||||
|
self.output.set_window_size(winsize);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCSCTTY => {
|
||||||
|
// TODO: reimplement when adding session.
|
||||||
|
let foreground = {
|
||||||
|
let current = current!();
|
||||||
|
let process_group = current.process_group().lock();
|
||||||
|
process_group.clone()
|
||||||
|
};
|
||||||
|
self.output.set_fg(foreground);
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCGPGRP => {
|
||||||
|
let Some(fg_pgid) = self.output.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 => {
|
||||||
|
// TODO: reimplement when adding session.
|
||||||
|
self.output.set_fg(Weak::new());
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::FIONREAD => {
|
||||||
|
let len = self.input.lock().len() as i32;
|
||||||
|
write_val_to_user(arg, &len)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
_ => Ok(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
||||||
|
let mut poll_status = IoEvents::empty();
|
||||||
|
|
||||||
|
let poll_in_mask = mask & IoEvents::IN;
|
||||||
|
if !poll_in_mask.is_empty() {
|
||||||
|
let poll_in_status = self.pollee.poll(poll_in_mask, poller);
|
||||||
|
poll_status |= poll_in_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
let poll_out_mask = mask & IoEvents::OUT;
|
||||||
|
if !poll_out_mask.is_empty() {
|
||||||
|
let poll_out_status = self.output.poll(poll_out_mask, poller);
|
||||||
|
poll_status |= poll_out_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll_status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PtySlave(Arc<PtyMaster>);
|
||||||
|
|
||||||
|
impl PtySlave {
|
||||||
|
pub fn new(master: Arc<PtyMaster>) -> Self {
|
||||||
|
PtySlave(master)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&self) -> u32 {
|
||||||
|
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_byte(b'\r');
|
||||||
|
self.0.slave_push_byte(b'\n');
|
||||||
|
} else {
|
||||||
|
self.0.slave_push_byte(*ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||||
|
match cmd {
|
||||||
|
IoctlCmd::TCGETS
|
||||||
|
| IoctlCmd::TCSETS
|
||||||
|
| IoctlCmd::TIOCGPGRP
|
||||||
|
| IoctlCmd::TIOCGPTN
|
||||||
|
| IoctlCmd::TIOCGWINSZ
|
||||||
|
| IoctlCmd::TIOCSWINSZ => self.0.ioctl(cmd, arg),
|
||||||
|
IoctlCmd::TIOCSCTTY => {
|
||||||
|
// TODO:
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::TIOCNOTTY => {
|
||||||
|
// TODO:
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
IoctlCmd::FIONREAD => {
|
||||||
|
let buffer_len = self.0.slave_buf_len() as i32;
|
||||||
|
write_val_to_user(arg, &buffer_len)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
_ => Ok(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
||||||
|
self.0.slave_poll(mask, poller)
|
||||||
|
}
|
||||||
|
}
|
@ -1,75 +0,0 @@
|
|||||||
use crate::fs::device::{Device, DeviceId, DeviceType};
|
|
||||||
use crate::fs::file_handle::FileLike;
|
|
||||||
use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
|
|
||||||
use crate::prelude::*;
|
|
||||||
use crate::util::write_val_to_user;
|
|
||||||
|
|
||||||
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
|
|
||||||
| IoctlCmd::TIOCGPTN
|
|
||||||
| IoctlCmd::TIOCGWINSZ
|
|
||||||
| IoctlCmd::TIOCSWINSZ => self.0.ioctl(cmd, arg),
|
|
||||||
IoctlCmd::TIOCSCTTY => {
|
|
||||||
// TODO:
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
IoctlCmd::TIOCNOTTY => {
|
|
||||||
// TODO:
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
IoctlCmd::FIONREAD => {
|
|
||||||
let buffer_len = self.0.slave_buf_len() as i32;
|
|
||||||
write_val_to_user(arg, &buffer_len)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
_ => Ok(0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
|
||||||
self.0.slave_poll(mask, poller)
|
|
||||||
}
|
|
||||||
}
|
|
@ -33,8 +33,8 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl C_IFLAGS {
|
impl Default for C_IFLAGS {
|
||||||
pub fn new_default() -> Self {
|
fn default() -> Self {
|
||||||
C_IFLAGS::ICRNL | C_IFLAGS::IXON
|
C_IFLAGS::ICRNL | C_IFLAGS::IXON
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,19 +43,19 @@ bitflags! {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Pod)]
|
#[derive(Pod)]
|
||||||
pub struct C_OFLAGS: u32 {
|
pub struct C_OFLAGS: u32 {
|
||||||
const OPOST = 0x1 << 0; /* Perform output processing */
|
const OPOST = 1 << 0; /* Perform output processing */
|
||||||
const OLCUC = 0x1 << 1;
|
const OLCUC = 1 << 1;
|
||||||
const ONLCR = 0x1 << 2;
|
const ONLCR = 1 << 2;
|
||||||
const OCRNL = 0x1 << 3;
|
const OCRNL = 1 << 3;
|
||||||
const ONOCR = 0x1 << 4;
|
const ONOCR = 1 << 4;
|
||||||
const ONLRET= 0x1 << 5;
|
const ONLRET = 1 << 5;
|
||||||
const OFILL = 0x1 << 6;
|
const OFILL = 1 << 6;
|
||||||
const OFDEL = 0x1 << 7;
|
const OFDEL = 1 << 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl C_OFLAGS {
|
impl Default for C_OFLAGS {
|
||||||
pub fn new_default() -> Self {
|
fn default() -> Self {
|
||||||
C_OFLAGS::OPOST | C_OFLAGS::ONLCR
|
C_OFLAGS::OPOST | C_OFLAGS::ONLCR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,14 +64,16 @@ impl C_OFLAGS {
|
|||||||
#[derive(Debug, Clone, Copy, Pod)]
|
#[derive(Debug, Clone, Copy, Pod)]
|
||||||
pub struct C_CFLAGS(u32);
|
pub struct C_CFLAGS(u32);
|
||||||
|
|
||||||
impl C_CFLAGS {
|
impl Default for C_CFLAGS {
|
||||||
pub fn new_default() -> Self {
|
fn default() -> Self {
|
||||||
let cbaud = C_CFLAGS_BAUD::B38400 as u32;
|
let cbaud = C_CFLAGS_BAUD::B38400 as u32;
|
||||||
let csize = C_CFLAGS_CSIZE::CS8 as u32;
|
let csize = C_CFLAGS_CSIZE::CS8 as u32;
|
||||||
let c_cflags = cbaud | csize | CREAD;
|
let c_cflags = cbaud | csize | CREAD;
|
||||||
Self(c_cflags)
|
Self(c_cflags)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl C_CFLAGS {
|
||||||
pub fn cbaud(&self) -> Result<C_CFLAGS_BAUD> {
|
pub fn cbaud(&self) -> Result<C_CFLAGS_BAUD> {
|
||||||
let cbaud = self.0 & CBAUD_MASK;
|
let cbaud = self.0 & CBAUD_MASK;
|
||||||
Ok(C_CFLAGS_BAUD::try_from(cbaud)?)
|
Ok(C_CFLAGS_BAUD::try_from(cbaud)?)
|
||||||
@ -126,26 +128,26 @@ bitflags! {
|
|||||||
#[derive(Pod)]
|
#[derive(Pod)]
|
||||||
pub struct C_LFLAGS: u32 {
|
pub struct C_LFLAGS: u32 {
|
||||||
const ISIG = 0x00001;
|
const ISIG = 0x00001;
|
||||||
const ICANON= 0x00002;
|
const ICANON = 0x00002;
|
||||||
const XCASE = 0x00004;
|
const XCASE = 0x00004;
|
||||||
const ECHO = 0x00008;
|
const ECHO = 0x00008;
|
||||||
const ECHOE = 0x00010;
|
const ECHOE = 0x00010;
|
||||||
const ECHOK = 0x00020;
|
const ECHOK = 0x00020;
|
||||||
const ECHONL= 0x00040;
|
const ECHONL = 0x00040;
|
||||||
const NOFLSH= 0x00080;
|
const NOFLSH = 0x00080;
|
||||||
const TOSTOP= 0x00100;
|
const TOSTOP = 0x00100;
|
||||||
const ECHOCTL= 0x00200;
|
const ECHOCTL = 0x00200;
|
||||||
const ECHOPRT= 0x00400;
|
const ECHOPRT = 0x00400;
|
||||||
const ECHOKE= 0x00800;
|
const ECHOKE = 0x00800;
|
||||||
const FLUSHO= 0x01000;
|
const FLUSHO = 0x01000;
|
||||||
const PENDIN= 0x04000;
|
const PENDIN = 0x04000;
|
||||||
const IEXTEN= 0x08000;
|
const IEXTEN = 0x08000;
|
||||||
const EXTPROC= 0x10000;
|
const EXTPROC = 0x10000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl C_LFLAGS {
|
impl Default for C_LFLAGS {
|
||||||
pub fn new_default() -> Self {
|
fn default() -> Self {
|
||||||
C_LFLAGS::ICANON
|
C_LFLAGS::ICANON
|
||||||
| C_LFLAGS::ECHO
|
| C_LFLAGS::ECHO
|
||||||
| C_LFLAGS::ISIG
|
| C_LFLAGS::ISIG
|
||||||
@ -159,7 +161,7 @@ impl C_LFLAGS {
|
|||||||
|
|
||||||
/* c_cc characters index*/
|
/* c_cc characters index*/
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Debug, Clone, Copy, Pod)]
|
#[derive(Debug, Clone, Copy, TryFromInt)]
|
||||||
pub enum CC_C_CHAR {
|
pub enum CC_C_CHAR {
|
||||||
VINTR = 0,
|
VINTR = 0,
|
||||||
VQUIT = 1,
|
VQUIT = 1,
|
||||||
@ -203,39 +205,6 @@ impl CC_C_CHAR {
|
|||||||
CC_C_CHAR::VEOL2 => '\0' as u8,
|
CC_C_CHAR::VEOL2 => '\0' as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_usize(&self) -> usize {
|
|
||||||
*self as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_char(item: u8) -> Result<Self> {
|
|
||||||
if item == Self::VINTR.default_char() {
|
|
||||||
return Ok(Self::VINTR);
|
|
||||||
}
|
|
||||||
if item == Self::VQUIT.default_char() {
|
|
||||||
return Ok(Self::VQUIT);
|
|
||||||
}
|
|
||||||
if item == Self::VINTR.default_char() {
|
|
||||||
return Ok(Self::VINTR);
|
|
||||||
}
|
|
||||||
if item == Self::VERASE.default_char() {
|
|
||||||
return Ok(Self::VERASE);
|
|
||||||
}
|
|
||||||
if item == Self::VEOF.default_char() {
|
|
||||||
return Ok(Self::VEOF);
|
|
||||||
}
|
|
||||||
if item == Self::VSTART.default_char() {
|
|
||||||
return Ok(Self::VSTART);
|
|
||||||
}
|
|
||||||
if item == Self::VSTOP.default_char() {
|
|
||||||
return Ok(Self::VSTOP);
|
|
||||||
}
|
|
||||||
if item == Self::VSUSP.default_char() {
|
|
||||||
return Ok(Self::VSUSP);
|
|
||||||
}
|
|
||||||
|
|
||||||
return_errno_with_message!(Errno::EINVAL, "Not a valid cc_char");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Pod)]
|
#[derive(Debug, Clone, Copy, Pod)]
|
||||||
@ -252,12 +221,12 @@ pub struct KernelTermios {
|
|||||||
impl KernelTermios {
|
impl KernelTermios {
|
||||||
pub fn default() -> Self {
|
pub fn default() -> Self {
|
||||||
let mut termios = Self {
|
let mut termios = Self {
|
||||||
c_iflags: C_IFLAGS::new_default(),
|
c_iflags: C_IFLAGS::default(),
|
||||||
c_oflags: C_OFLAGS::new_default(),
|
c_oflags: C_OFLAGS::default(),
|
||||||
c_cflags: C_CFLAGS::new_default(),
|
c_cflags: C_CFLAGS::default(),
|
||||||
c_lflags: C_LFLAGS::new_default(),
|
c_lflags: C_LFLAGS::default(),
|
||||||
c_line: 0,
|
c_line: 0,
|
||||||
c_cc: [0; KERNEL_NCCS],
|
c_cc: [CcT::default(); KERNEL_NCCS],
|
||||||
};
|
};
|
||||||
*termios.get_special_char_mut(CC_C_CHAR::VINTR) = CC_C_CHAR::VINTR.default_char();
|
*termios.get_special_char_mut(CC_C_CHAR::VINTR) = CC_C_CHAR::VINTR.default_char();
|
||||||
*termios.get_special_char_mut(CC_C_CHAR::VQUIT) = CC_C_CHAR::VQUIT.default_char();
|
*termios.get_special_char_mut(CC_C_CHAR::VQUIT) = CC_C_CHAR::VQUIT.default_char();
|
||||||
@ -280,11 +249,11 @@ impl KernelTermios {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_special_char(&self, cc_c_char: CC_C_CHAR) -> &CcT {
|
pub fn get_special_char(&self, cc_c_char: CC_C_CHAR) -> &CcT {
|
||||||
&self.c_cc[cc_c_char.as_usize()]
|
&self.c_cc[cc_c_char as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_special_char_mut(&mut self, cc_c_char: CC_C_CHAR) -> &mut CcT {
|
pub fn get_special_char_mut(&mut self, cc_c_char: CC_C_CHAR) -> &mut CcT {
|
||||||
&mut self.c_cc[cc_c_char.as_usize()]
|
&mut self.c_cc[cc_c_char as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Canonical mode means we will handle input by lines, not by single character
|
/// Canonical mode means we will handle input by lines, not by single character
|
||||||
|
@ -12,7 +12,6 @@ use jinux_util::{id_allocator::IdAlloc, slot_vec::SlotVec};
|
|||||||
use self::master::PtyMasterInode;
|
use self::master::PtyMasterInode;
|
||||||
use self::ptmx::Ptmx;
|
use self::ptmx::Ptmx;
|
||||||
use self::slave::PtySlaveInode;
|
use self::slave::PtySlaveInode;
|
||||||
use crate::device::PtyMaster;
|
|
||||||
|
|
||||||
mod master;
|
mod master;
|
||||||
mod ptmx;
|
mod ptmx;
|
||||||
@ -61,7 +60,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, slave) = PtyMaster::new_pair(index as u32, self.root.ptmx.clone())?;
|
let (master, slave) = crate::device::new_pty_pair(index as u32, self.root.ptmx.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 +72,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: usize) -> Option<Arc<PtySlaveInode>> {
|
fn remove_slave(&self, index: u32) -> 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);
|
self.index_alloc.lock().free(index as usize);
|
||||||
}
|
}
|
||||||
removed_slave
|
removed_slave
|
||||||
}
|
}
|
||||||
|
@ -151,6 +151,7 @@ impl VmMapping {
|
|||||||
pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||||
let vmo_read_offset = self.vmo_offset() + offset;
|
let vmo_read_offset = self.vmo_offset() + offset;
|
||||||
|
|
||||||
|
// TODO: the current logic is vulnerable to TOCTTOU attack, since the permission may change after check.
|
||||||
let page_idx_range = get_page_idx_range(&(vmo_read_offset..vmo_read_offset + buf.len()));
|
let page_idx_range = get_page_idx_range(&(vmo_read_offset..vmo_read_offset + buf.len()));
|
||||||
let read_perm = VmPerm::R;
|
let read_perm = VmPerm::R;
|
||||||
for page_idx in page_idx_range {
|
for page_idx in page_idx_range {
|
||||||
|
Reference in New Issue
Block a user