mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 18:03:25 +00:00
Enable gvisor pty test
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
f802ff40c5
commit
40056f0692
@ -1,4 +1,4 @@
|
||||
TESTS ?= open_test read_test statfs_test chmod_test
|
||||
TESTS ?= open_test read_test statfs_test chmod_test pty_test
|
||||
|
||||
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
|
||||
|
42
regression/syscall_test/blocklists/pty_test
Normal file
42
regression/syscall_test/blocklists/pty_test
Normal file
@ -0,0 +1,42 @@
|
||||
PtyTrunc.Truncate
|
||||
PtyTest.MasterTermiosUnchangable
|
||||
PtyTest.TermiosICRNL
|
||||
PtyTest.TermiosONLCR
|
||||
PtyTest.TermiosINLCR
|
||||
PtyTest.TermiosOCRNL
|
||||
PtyTest.SwitchCanonToNonCanonNewline
|
||||
PtyTest.TermiosICANONNewline
|
||||
PtyTest.TermiosICANONEOF
|
||||
PtyTest.CanonDiscard
|
||||
PtyTest.CanonMultiline
|
||||
PtyTest.SimpleEcho
|
||||
PtyTest.TermiosIGNCR
|
||||
PtyTest.TermiosONOCR
|
||||
PtyTest.VEOLTermination
|
||||
PtyTest.CanonBigWrite
|
||||
PtyTest.SwitchCanonToNoncanon
|
||||
PtyTest.SwitchNoncanonToCanonNewlineBig
|
||||
PtyTest.SwitchNoncanonToCanonNoNewline
|
||||
PtyTest.SwitchNoncanonToCanonNoNewlineBig
|
||||
PtyTest.NoncanonBigWrite
|
||||
PtyTest.SwitchNoncanonToCanonMultiline
|
||||
PtyTest.SwitchTwiceMultiline
|
||||
JobControlTest.SetTTYMaster
|
||||
JobControlTest.SetTTY
|
||||
JobControlTest.SetTTYNonLeader
|
||||
JobControlTest.SetTTYBadArg
|
||||
JobControlTest.SetTTYDifferentSession
|
||||
JobControlTest.ReleaseTTY
|
||||
JobControlTest.ReleaseUnsetTTY
|
||||
JobControlTest.ReleaseWrongTTY
|
||||
JobControlTest.ReleaseTTYNonLeader
|
||||
JobControlTest.ReleaseTTYDifferentSession
|
||||
JobControlTest.ReleaseTTYSignals
|
||||
JobControlTest.GetForegroundProcessGroup
|
||||
JobControlTest.GetForegroundProcessGroupNonControlling
|
||||
JobControlTest.SetForegroundProcessGroup
|
||||
JobControlTest.SetForegroundProcessGroupWrongTTY
|
||||
JobControlTest.SetForegroundProcessGroupNegPgid
|
||||
JobControlTest.SetForegroundProcessGroupEmptyProcessGroup
|
||||
JobControlTest.SetForegroundProcessGroupDifferentSession
|
||||
JobControlTest.OrphanRegression
|
@ -55,11 +55,7 @@ impl PtyMaster {
|
||||
|
||||
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();
|
||||
buf.push_overwrite(item);
|
||||
self.update_state(&buf);
|
||||
Ok(())
|
||||
}
|
||||
@ -93,13 +89,11 @@ impl PtyMaster {
|
||||
}
|
||||
}
|
||||
|
||||
fn update_state(&self, buf: &HeapRb<u8>) {
|
||||
if buf.is_full() {
|
||||
self.pollee.del_events(IoEvents::OUT);
|
||||
} else {
|
||||
self.pollee.add_events(IoEvents::OUT);
|
||||
}
|
||||
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 {
|
||||
@ -139,18 +133,10 @@ impl FileLike for PtyMaster {
|
||||
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();
|
||||
master_buf.push_overwrite(*byte);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -203,9 +189,18 @@ impl FileLike for PtyMaster {
|
||||
};
|
||||
Ok(fd)
|
||||
}
|
||||
IoctlCmd::TIOCGWINSZ => Ok(0),
|
||||
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
|
||||
// TODO: reimplement when adding session.
|
||||
let foreground = {
|
||||
let current = current!();
|
||||
let process_group = current.process_group().lock();
|
||||
@ -225,9 +220,15 @@ impl FileLike for PtyMaster {
|
||||
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),
|
||||
}
|
||||
}
|
||||
@ -237,8 +238,6 @@ impl FileLike for PtyMaster {
|
||||
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() {
|
||||
|
@ -2,6 +2,7 @@ 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;
|
||||
|
||||
@ -45,8 +46,12 @@ impl Device for PtySlave {
|
||||
|
||||
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::TCGETS
|
||||
| IoctlCmd::TCSETS
|
||||
| IoctlCmd::TIOCGPGRP
|
||||
| IoctlCmd::TIOCGPTN
|
||||
| IoctlCmd::TIOCGWINSZ
|
||||
| IoctlCmd::TIOCSWINSZ => self.0.ioctl(cmd, arg),
|
||||
IoctlCmd::TIOCSCTTY => {
|
||||
// TODO:
|
||||
Ok(0)
|
||||
@ -55,6 +60,11 @@ impl Device for PtySlave {
|
||||
// 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),
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use alloc::format;
|
||||
use jinux_frame::trap::disable_local;
|
||||
use ringbuf::{ring_buffer::RbBase, Rb, StaticRb};
|
||||
|
||||
use super::termio::{KernelTermios, CC_C_CHAR};
|
||||
use super::termio::{KernelTermios, WinSize, CC_C_CHAR};
|
||||
|
||||
// This implementation refers the implementation of linux
|
||||
// https://elixir.bootlin.com/linux/latest/source/include/linux/tty_ldisc.h
|
||||
@ -25,6 +25,8 @@ pub struct LineDiscipline {
|
||||
foreground: SpinLock<Weak<ProcessGroup>>,
|
||||
/// termios
|
||||
termios: SpinLock<KernelTermios>,
|
||||
/// Windows size,
|
||||
winsize: SpinLock<WinSize>,
|
||||
/// Pollee
|
||||
pollee: Pollee,
|
||||
}
|
||||
@ -72,6 +74,7 @@ impl LineDiscipline {
|
||||
read_buffer: SpinLock::new(StaticRb::default()),
|
||||
foreground: SpinLock::new(Weak::new()),
|
||||
termios: SpinLock::new(KernelTermios::default()),
|
||||
winsize: SpinLock::new(WinSize::default()),
|
||||
pollee: Pollee::new(IoEvents::empty()),
|
||||
}
|
||||
}
|
||||
@ -350,6 +353,18 @@ impl LineDiscipline {
|
||||
self.current_line.lock().drain();
|
||||
let _: Vec<_> = self.read_buffer.lock().pop_iter().collect();
|
||||
}
|
||||
|
||||
pub fn buffer_len(&self) -> usize {
|
||||
self.read_buffer.lock().len()
|
||||
}
|
||||
|
||||
pub fn window_size(&self) -> WinSize {
|
||||
self.winsize.lock().clone()
|
||||
}
|
||||
|
||||
pub fn set_window_size(&self, winsize: WinSize) {
|
||||
*self.winsize.lock() = winsize;
|
||||
}
|
||||
}
|
||||
|
||||
fn meet_new_line(item: u8, termios: &KernelTermios) -> bool {
|
||||
|
@ -130,7 +130,13 @@ impl Device for Tty {
|
||||
Ok(0)
|
||||
}
|
||||
IoctlCmd::TIOCGWINSZ => {
|
||||
// TODO:get window size
|
||||
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)
|
||||
}
|
||||
_ => todo!(),
|
||||
|
@ -33,22 +33,76 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
impl C_IFLAGS {
|
||||
pub fn new_default() -> Self {
|
||||
C_IFLAGS::ICRNL | C_IFLAGS::IXON
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[repr(C)]
|
||||
#[derive(Pod)]
|
||||
pub struct C_OFLAGS: u32 {
|
||||
const OPOST = 0x01; /* Perform output processing */
|
||||
const OCRNL = 0x08;
|
||||
const ONOCR = 0x10;
|
||||
const ONLRET= 0x20;
|
||||
const OFILL = 0x40;
|
||||
const OFDEL = 0x80;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
impl C_OFLAGS {
|
||||
pub fn new_default() -> Self {
|
||||
C_OFLAGS::OPOST | C_OFLAGS::ONLCR
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
pub enum C_CFLAGS {
|
||||
pub struct C_CFLAGS(u32);
|
||||
|
||||
impl C_CFLAGS {
|
||||
pub fn new_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)
|
||||
}
|
||||
|
||||
pub fn cbaud(&self) -> Result<C_CFLAGS_BAUD> {
|
||||
let cbaud = self.0 & CBAUD_MASK;
|
||||
Ok(C_CFLAGS_BAUD::try_from(cbaud)?)
|
||||
}
|
||||
|
||||
pub fn csize(&self) -> Result<C_CFLAGS_CSIZE> {
|
||||
let csize = self.0 & CSIZE_MASK;
|
||||
Ok(C_CFLAGS_CSIZE::try_from(csize)?)
|
||||
}
|
||||
|
||||
pub fn cread(&self) -> bool {
|
||||
self.0 & CREAD != 0
|
||||
}
|
||||
}
|
||||
|
||||
const CREAD: u32 = 0x00000080;
|
||||
const CBAUD_MASK: u32 = 0x0000100f;
|
||||
const CSIZE_MASK: u32 = 0x00000030;
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, TryFromInt)]
|
||||
pub enum C_CFLAGS_CSIZE {
|
||||
CS5 = 0x00000000,
|
||||
CS6 = 0x00000010,
|
||||
CS7 = 0x00000020,
|
||||
CS8 = 0x00000030,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Clone, Copy, TryFromInt)]
|
||||
pub enum C_CFLAGS_BAUD {
|
||||
B0 = 0x00000000, /* hang up */
|
||||
B50 = 0x00000001,
|
||||
B75 = 0x00000002,
|
||||
@ -90,6 +144,19 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
impl C_LFLAGS {
|
||||
pub fn new_default() -> Self {
|
||||
C_LFLAGS::ICANON
|
||||
| C_LFLAGS::ECHO
|
||||
| C_LFLAGS::ISIG
|
||||
| C_LFLAGS::ECHOE
|
||||
| C_LFLAGS::ECHOK
|
||||
| C_LFLAGS::ECHOCTL
|
||||
| C_LFLAGS::ECHOKE
|
||||
| C_LFLAGS::IEXTEN
|
||||
}
|
||||
}
|
||||
|
||||
/* c_cc characters index*/
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
@ -114,26 +181,26 @@ pub enum CC_C_CHAR {
|
||||
}
|
||||
|
||||
impl CC_C_CHAR {
|
||||
// The special char is the same as ubuntu
|
||||
pub fn char(&self) -> u8 {
|
||||
// The special char is from gvisor
|
||||
pub fn default_char(&self) -> u8 {
|
||||
match self {
|
||||
CC_C_CHAR::VINTR => 3,
|
||||
CC_C_CHAR::VQUIT => 28,
|
||||
CC_C_CHAR::VERASE => 127,
|
||||
CC_C_CHAR::VKILL => 21,
|
||||
CC_C_CHAR::VEOF => 4,
|
||||
CC_C_CHAR::VTIME => 0,
|
||||
CC_C_CHAR::VINTR => control_character('C'),
|
||||
CC_C_CHAR::VQUIT => control_character('\\'),
|
||||
CC_C_CHAR::VERASE => '\x7f' as u8,
|
||||
CC_C_CHAR::VKILL => control_character('U'),
|
||||
CC_C_CHAR::VEOF => control_character('D'),
|
||||
CC_C_CHAR::VTIME => '\0' as u8,
|
||||
CC_C_CHAR::VMIN => 1,
|
||||
CC_C_CHAR::VSWTC => 0,
|
||||
CC_C_CHAR::VSTART => 17,
|
||||
CC_C_CHAR::VSTOP => 19,
|
||||
CC_C_CHAR::VSUSP => 26,
|
||||
CC_C_CHAR::VEOL => 255,
|
||||
CC_C_CHAR::VREPRINT => 18,
|
||||
CC_C_CHAR::VDISCARD => 15,
|
||||
CC_C_CHAR::VWERASE => 23,
|
||||
CC_C_CHAR::VLNEXT => 22,
|
||||
CC_C_CHAR::VEOL2 => 255,
|
||||
CC_C_CHAR::VSWTC => '\0' as u8,
|
||||
CC_C_CHAR::VSTART => control_character('Q'),
|
||||
CC_C_CHAR::VSTOP => control_character('S'),
|
||||
CC_C_CHAR::VSUSP => control_character('Z'),
|
||||
CC_C_CHAR::VEOL => '\0' as u8,
|
||||
CC_C_CHAR::VREPRINT => control_character('R'),
|
||||
CC_C_CHAR::VDISCARD => control_character('O'),
|
||||
CC_C_CHAR::VWERASE => control_character('W'),
|
||||
CC_C_CHAR::VLNEXT => control_character('V'),
|
||||
CC_C_CHAR::VEOL2 => '\0' as u8,
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,28 +209,28 @@ impl CC_C_CHAR {
|
||||
}
|
||||
|
||||
pub fn from_char(item: u8) -> Result<Self> {
|
||||
if item == Self::VINTR.char() {
|
||||
if item == Self::VINTR.default_char() {
|
||||
return Ok(Self::VINTR);
|
||||
}
|
||||
if item == Self::VQUIT.char() {
|
||||
if item == Self::VQUIT.default_char() {
|
||||
return Ok(Self::VQUIT);
|
||||
}
|
||||
if item == Self::VINTR.char() {
|
||||
if item == Self::VINTR.default_char() {
|
||||
return Ok(Self::VINTR);
|
||||
}
|
||||
if item == Self::VERASE.char() {
|
||||
if item == Self::VERASE.default_char() {
|
||||
return Ok(Self::VERASE);
|
||||
}
|
||||
if item == Self::VEOF.char() {
|
||||
if item == Self::VEOF.default_char() {
|
||||
return Ok(Self::VEOF);
|
||||
}
|
||||
if item == Self::VSTART.char() {
|
||||
if item == Self::VSTART.default_char() {
|
||||
return Ok(Self::VSTART);
|
||||
}
|
||||
if item == Self::VSTOP.char() {
|
||||
if item == Self::VSTOP.default_char() {
|
||||
return Ok(Self::VSTOP);
|
||||
}
|
||||
if item == Self::VSUSP.char() {
|
||||
if item == Self::VSUSP.default_char() {
|
||||
return Ok(Self::VSUSP);
|
||||
}
|
||||
|
||||
@ -185,44 +252,33 @@ pub struct KernelTermios {
|
||||
impl KernelTermios {
|
||||
pub fn default() -> Self {
|
||||
let mut termios = Self {
|
||||
c_iflags: C_IFLAGS::ICRNL,
|
||||
c_oflags: C_OFLAGS::empty(),
|
||||
c_cflags: C_CFLAGS::B0,
|
||||
c_lflags: C_LFLAGS::ICANON | C_LFLAGS::ECHO,
|
||||
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_line: 0,
|
||||
c_cc: [0; KERNEL_NCCS],
|
||||
};
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VINTR) = CC_C_CHAR::VINTR.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VQUIT) = CC_C_CHAR::VQUIT.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VERASE) = CC_C_CHAR::VERASE.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VKILL) = CC_C_CHAR::VKILL.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VEOF) = CC_C_CHAR::VEOF.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VTIME) = CC_C_CHAR::VTIME.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VMIN) = CC_C_CHAR::VMIN.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VSWTC) = CC_C_CHAR::VSWTC.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VSTART) = CC_C_CHAR::VSTART.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VSTOP) = CC_C_CHAR::VSTOP.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VSUSP) = CC_C_CHAR::VSUSP.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VEOL) = CC_C_CHAR::VEOL.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VREPRINT) = CC_C_CHAR::VREPRINT.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VDISCARD) = CC_C_CHAR::VDISCARD.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VWERASE) = CC_C_CHAR::VWERASE.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VLNEXT) = CC_C_CHAR::VLNEXT.char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VEOL2) = CC_C_CHAR::VEOL2.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::VERASE) = CC_C_CHAR::VERASE.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VKILL) = CC_C_CHAR::VKILL.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VEOF) = CC_C_CHAR::VEOF.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VTIME) = CC_C_CHAR::VTIME.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VMIN) = CC_C_CHAR::VMIN.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VSWTC) = CC_C_CHAR::VSWTC.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VSTART) = CC_C_CHAR::VSTART.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VSTOP) = CC_C_CHAR::VSTOP.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VSUSP) = CC_C_CHAR::VSUSP.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VEOL) = CC_C_CHAR::VEOL.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VREPRINT) = CC_C_CHAR::VREPRINT.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VDISCARD) = CC_C_CHAR::VDISCARD.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VWERASE) = CC_C_CHAR::VWERASE.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VLNEXT) = CC_C_CHAR::VLNEXT.default_char();
|
||||
*termios.get_special_char_mut(CC_C_CHAR::VEOL2) = CC_C_CHAR::VEOL2.default_char();
|
||||
termios
|
||||
}
|
||||
|
||||
fn new() -> Self {
|
||||
KernelTermios {
|
||||
c_iflags: C_IFLAGS::empty(),
|
||||
c_oflags: C_OFLAGS::empty(),
|
||||
c_cflags: C_CFLAGS::B0,
|
||||
c_lflags: C_LFLAGS::empty(),
|
||||
c_line: 0,
|
||||
c_cc: [0; KERNEL_NCCS],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_special_char(&self, cc_c_char: CC_C_CHAR) -> &CcT {
|
||||
&self.c_cc[cc_c_char.as_usize()]
|
||||
}
|
||||
@ -265,3 +321,17 @@ impl KernelTermios {
|
||||
self.c_lflags.contains(C_LFLAGS::IEXTEN)
|
||||
}
|
||||
}
|
||||
|
||||
const fn control_character(c: char) -> u8 {
|
||||
debug_assert!(c as u8 >= 'A' as u8);
|
||||
c as u8 - 'A' as u8 + 1u8
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, Pod)]
|
||||
#[repr(C)]
|
||||
pub struct WinSize {
|
||||
ws_row: u16,
|
||||
ws_col: u16,
|
||||
ws_xpixel: u16,
|
||||
ws_ypixel: u16,
|
||||
}
|
||||
|
@ -16,9 +16,10 @@ impl PtyMasterInode {
|
||||
impl Drop for PtyMasterInode {
|
||||
fn drop(&mut self) {
|
||||
// Remove the slave from fs.
|
||||
let index = self.0.index();
|
||||
let fs = self.0.ptmx().fs();
|
||||
let devpts = fs.downcast_ref::<DevPts>().unwrap();
|
||||
|
||||
let index = self.0.index();
|
||||
devpts.remove_slave(index);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ pub enum IoctlCmd {
|
||||
TIOCGPGRP = 0x540f,
|
||||
/// Set the foreground process group ID of this terminal.
|
||||
TIOCSPGRP = 0x5410,
|
||||
/// Get the number of bytes in the input buffer.
|
||||
FIONREAD = 0x541B,
|
||||
/// Set window size
|
||||
TIOCGWINSZ = 0x5413,
|
||||
TIOCSWINSZ = 0x5414,
|
||||
|
@ -146,6 +146,7 @@ impl Vnode {
|
||||
if let Some(page_cache) = &inner.page_cache {
|
||||
page_cache.evict_range(0..file_len);
|
||||
}
|
||||
|
||||
inner.inode.read_at(0, &mut buf[..file_len])
|
||||
}
|
||||
|
||||
@ -196,11 +197,13 @@ impl Vnode {
|
||||
}
|
||||
|
||||
pub fn poll(&self, mask: IoEvents, poller: Option<&Poller>) -> IoEvents {
|
||||
self.inner.read().inode.poll(mask, poller)
|
||||
let inode = self.inner.read().inode.clone();
|
||||
inode.poll(mask, poller)
|
||||
}
|
||||
|
||||
pub fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||
self.inner.read().inode.ioctl(cmd, arg)
|
||||
let inode = self.inner.read().inode.clone();
|
||||
inode.ioctl(cmd, arg)
|
||||
}
|
||||
|
||||
pub fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
|
@ -150,12 +150,26 @@ impl VmMapping {
|
||||
}
|
||||
pub fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
||||
let vmo_read_offset = self.vmo_offset() + offset;
|
||||
|
||||
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 {
|
||||
self.check_perm(&page_idx, &read_perm)?;
|
||||
}
|
||||
|
||||
self.vmo.read_bytes(vmo_read_offset, buf)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||
let vmo_write_offset = self.vmo_offset() + offset;
|
||||
|
||||
let page_idx_range = get_page_idx_range(&(vmo_write_offset..vmo_write_offset + buf.len()));
|
||||
let write_perm = VmPerm::W;
|
||||
for page_idx in page_idx_range {
|
||||
self.check_perm(&page_idx, &write_perm)?;
|
||||
}
|
||||
|
||||
self.vmo.write_bytes(vmo_write_offset, buf)?;
|
||||
Ok(())
|
||||
}
|
||||
@ -198,7 +212,9 @@ impl VmMapping {
|
||||
} else {
|
||||
self.vmo.check_rights(Rights::READ)?;
|
||||
}
|
||||
self.check_perm(&page_idx, write)?;
|
||||
|
||||
let required_perm = if write { VmPerm::W } else { VmPerm::R };
|
||||
self.check_perm(&page_idx, &required_perm)?;
|
||||
|
||||
let frame = self.vmo.get_committed_frame(page_idx, write)?;
|
||||
|
||||
@ -300,8 +316,8 @@ impl VmMapping {
|
||||
self.inner.lock().trim_right(vm_space, vaddr)
|
||||
}
|
||||
|
||||
fn check_perm(&self, page_idx: &usize, write: bool) -> Result<()> {
|
||||
self.inner.lock().check_perm(page_idx, write)
|
||||
fn check_perm(&self, page_idx: &usize, perm: &VmPerm) -> Result<()> {
|
||||
self.inner.lock().check_perm(page_idx, perm)
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,16 +473,14 @@ impl VmMappingInner {
|
||||
self.map_to_addr..self.map_to_addr + self.map_size
|
||||
}
|
||||
|
||||
fn check_perm(&self, page_idx: &usize, write: bool) -> Result<()> {
|
||||
fn check_perm(&self, page_idx: &usize, perm: &VmPerm) -> Result<()> {
|
||||
let page_perm = self
|
||||
.page_perms
|
||||
.get(&page_idx)
|
||||
.ok_or(Error::with_message(Errno::EINVAL, "invalid page idx"))?;
|
||||
if !page_perm.contains(VmPerm::R) {
|
||||
return_errno_with_message!(Errno::EINVAL, "perm should at least contain read");
|
||||
}
|
||||
if write && !page_perm.contains(VmPerm::W) {
|
||||
return_errno_with_message!(Errno::EINVAL, "perm should contain write for write access");
|
||||
|
||||
if !page_perm.contains(*perm) {
|
||||
return_errno_with_message!(Errno::EACCES, "perm check fails");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
Reference in New Issue
Block a user