Refactor the pty implementation

This commit is contained in:
Jianfeng Jiang 2023-08-28 14:28:23 +08:00 committed by Tate, Hongliang Tian
parent 40056f0692
commit 038c19b693
10 changed files with 396 additions and 443 deletions

View File

@ -15,8 +15,6 @@ int main() {
exit(EXIT_FAILURE);
}
printf("master fd: %d\n", master);
printf("slave fd: %d\n", slave);
printf("slave name: %s\n", name);
// Set pty slave terminal attributes
@ -33,7 +31,7 @@ int main() {
char buf[256];
ssize_t n = read(master, buf, sizeof(buf));
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
@ -43,7 +41,7 @@ int main() {
char nbuf[256];
ssize_t nn = read(slave, nbuf, sizeof(nbuf));
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);

View File

@ -6,7 +6,7 @@ SCRIPT_DIR=/regression
cd ${SCRIPT_DIR}/..
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}
do
echo "Running test ${testcase}......"

View File

@ -7,6 +7,7 @@ mod zero;
use crate::fs::device::{add_node, Device, DeviceId, DeviceType};
use crate::prelude::*;
pub use pty::new_pty_pair;
pub use pty::{PtyMaster, PtySlave};
pub use random::Random;
pub use urandom::Urandom;

View File

@ -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();
}
}
}

View File

@ -1,16 +1,15 @@
mod master;
mod slave;
pub use master::PtyMaster;
pub use slave::PtySlave;
use crate::fs::{
devpts::DevPts,
fs_resolver::{FsPath, FsResolver},
utils::{InodeMode, InodeType},
};
use crate::fs::devpts::DevPts;
use crate::fs::fs_resolver::{FsPath, FsResolver};
use crate::fs::utils::{Dentry, Inode, InodeMode, InodeType};
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<()> {
let fs = FsResolver::new();
@ -19,6 +18,8 @@ pub fn init() -> Result<()> {
let devpts = dev.create("pts", InodeType::Dir, InodeMode::from_bits_truncate(0o755))?;
devpts.mount(DevPts::new())?;
DEV_PTS.call_once(|| devpts);
// Create the "ptmx" symlink.
let ptmx = dev.create(
"ptmx",
@ -28,3 +29,10 @@ pub fn init() -> Result<()> {
ptmx.write_link("pts/ptmx")?;
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))
}

View 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)
}
}

View File

@ -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)
}
}

View File

@ -14,27 +14,27 @@ bitflags! {
#[repr(C)]
pub struct C_IFLAGS: u32 {
// https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/asm-generic/termbits-common.h
const IGNBRK = 0x001; /* Ignore break condition */
const BRKINT = 0x002; /* Signal interrupt on break */
const IGNPAR = 0x004; /* Ignore characters with parity errors */
const PARMRK = 0x008; /* Mark parity and framing errors */
const INPCK = 0x010; /* Enable input parity check */
const ISTRIP = 0x020; /* Strip 8th bit off characters */
const INLCR = 0x040; /* Map NL to CR on input */
const IGNCR = 0x080; /* Ignore CR */
const ICRNL = 0x100; /* Map CR to NL on input */
const IXANY = 0x800; /* Any character will restart after stop */
const IGNBRK = 0x001; /* Ignore break condition */
const BRKINT = 0x002; /* Signal interrupt on break */
const IGNPAR = 0x004; /* Ignore characters with parity errors */
const PARMRK = 0x008; /* Mark parity and framing errors */
const INPCK = 0x010; /* Enable input parity check */
const ISTRIP = 0x020; /* Strip 8th bit off characters */
const INLCR = 0x040; /* Map NL to CR on input */
const IGNCR = 0x080; /* Ignore CR */
const ICRNL = 0x100; /* Map CR to NL on input */
const IXANY = 0x800; /* Any character will restart after stop */
// https://elixir.bootlin.com/linux/v6.0.9/source/include/uapi/asm-generic/termbits.h
const IUCLC = 0x0200;
const IXON = 0x0400;
const IXOFF = 0x1000;
const IMAXBEL = 0x2000;
const IUTF8 = 0x4000;
const IUCLC = 0x0200;
const IXON = 0x0400;
const IXOFF = 0x1000;
const IMAXBEL = 0x2000;
const IUTF8 = 0x4000;
}
}
impl C_IFLAGS {
pub fn new_default() -> Self {
impl Default for C_IFLAGS {
fn default() -> Self {
C_IFLAGS::ICRNL | C_IFLAGS::IXON
}
}
@ -43,19 +43,19 @@ bitflags! {
#[repr(C)]
#[derive(Pod)]
pub struct C_OFLAGS: u32 {
const OPOST = 0x1 << 0; /* Perform output processing */
const OLCUC = 0x1 << 1;
const ONLCR = 0x1 << 2;
const OCRNL = 0x1 << 3;
const ONOCR = 0x1 << 4;
const ONLRET= 0x1 << 5;
const OFILL = 0x1 << 6;
const OFDEL = 0x1 << 7;
const OPOST = 1 << 0; /* Perform output processing */
const OLCUC = 1 << 1;
const ONLCR = 1 << 2;
const OCRNL = 1 << 3;
const ONOCR = 1 << 4;
const ONLRET = 1 << 5;
const OFILL = 1 << 6;
const OFDEL = 1 << 7;
}
}
impl C_OFLAGS {
pub fn new_default() -> Self {
impl Default for C_OFLAGS {
fn default() -> Self {
C_OFLAGS::OPOST | C_OFLAGS::ONLCR
}
}
@ -64,14 +64,16 @@ impl C_OFLAGS {
#[derive(Debug, Clone, Copy, Pod)]
pub struct C_CFLAGS(u32);
impl C_CFLAGS {
pub fn new_default() -> Self {
impl Default for C_CFLAGS {
fn default() -> Self {
let cbaud = C_CFLAGS_BAUD::B38400 as u32;
let csize = C_CFLAGS_CSIZE::CS8 as u32;
let c_cflags = cbaud | csize | CREAD;
Self(c_cflags)
}
}
impl C_CFLAGS {
pub fn cbaud(&self) -> Result<C_CFLAGS_BAUD> {
let cbaud = self.0 & CBAUD_MASK;
Ok(C_CFLAGS_BAUD::try_from(cbaud)?)
@ -125,27 +127,27 @@ bitflags! {
#[repr(C)]
#[derive(Pod)]
pub struct C_LFLAGS: u32 {
const ISIG = 0x00001;
const ICANON= 0x00002;
const XCASE = 0x00004;
const ECHO = 0x00008;
const ECHOE = 0x00010;
const ECHOK = 0x00020;
const ECHONL= 0x00040;
const NOFLSH= 0x00080;
const TOSTOP= 0x00100;
const ECHOCTL= 0x00200;
const ECHOPRT= 0x00400;
const ECHOKE= 0x00800;
const FLUSHO= 0x01000;
const PENDIN= 0x04000;
const IEXTEN= 0x08000;
const EXTPROC= 0x10000;
const ISIG = 0x00001;
const ICANON = 0x00002;
const XCASE = 0x00004;
const ECHO = 0x00008;
const ECHOE = 0x00010;
const ECHOK = 0x00020;
const ECHONL = 0x00040;
const NOFLSH = 0x00080;
const TOSTOP = 0x00100;
const ECHOCTL = 0x00200;
const ECHOPRT = 0x00400;
const ECHOKE = 0x00800;
const FLUSHO = 0x01000;
const PENDIN = 0x04000;
const IEXTEN = 0x08000;
const EXTPROC = 0x10000;
}
}
impl C_LFLAGS {
pub fn new_default() -> Self {
impl Default for C_LFLAGS {
fn default() -> Self {
C_LFLAGS::ICANON
| C_LFLAGS::ECHO
| C_LFLAGS::ISIG
@ -159,7 +161,7 @@ impl C_LFLAGS {
/* c_cc characters index*/
#[repr(u32)]
#[derive(Debug, Clone, Copy, Pod)]
#[derive(Debug, Clone, Copy, TryFromInt)]
pub enum CC_C_CHAR {
VINTR = 0,
VQUIT = 1,
@ -203,39 +205,6 @@ impl CC_C_CHAR {
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)]
@ -252,12 +221,12 @@ pub struct KernelTermios {
impl KernelTermios {
pub fn default() -> Self {
let mut termios = Self {
c_iflags: C_IFLAGS::new_default(),
c_oflags: C_OFLAGS::new_default(),
c_cflags: C_CFLAGS::new_default(),
c_lflags: C_LFLAGS::new_default(),
c_iflags: C_IFLAGS::default(),
c_oflags: C_OFLAGS::default(),
c_cflags: C_CFLAGS::default(),
c_lflags: C_LFLAGS::default(),
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::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 {
&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 {
&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

View File

@ -12,7 +12,6 @@ use jinux_util::{id_allocator::IdAlloc, slot_vec::SlotVec};
use self::master::PtyMasterInode;
use self::ptmx::Ptmx;
use self::slave::PtySlaveInode;
use crate::device::PtyMaster;
mod master;
mod ptmx;
@ -61,7 +60,7 @@ impl DevPts {
.alloc()
.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 slave_inode = PtySlaveInode::new(slave, self.this.clone());
@ -73,10 +72,10 @@ impl DevPts {
/// Remove the slave from fs.
///
/// 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());
if removed_slave.is_some() {
self.index_alloc.lock().free(index);
self.index_alloc.lock().free(index as usize);
}
removed_slave
}

View File

@ -151,6 +151,7 @@ impl VmMapping {
pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
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 read_perm = VmPerm::R;
for page_idx in page_idx_range {