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)))
|
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||||
CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
|
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<()> {
|
pub(super) fn slave_push_char(&self, item: u8) -> Result<()> {
|
||||||
let mut buf = self.master_buffer.lock_irq_disabled();
|
let mut buf = self.master_buffer.lock_irq_disabled();
|
||||||
if buf.is_full() {
|
buf.push_overwrite(item);
|
||||||
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);
|
self.update_state(&buf);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -93,13 +89,11 @@ impl PtyMaster {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_state(&self, buf: &HeapRb<u8>) {
|
pub(super) fn slave_buf_len(&self) -> usize {
|
||||||
if buf.is_full() {
|
self.ldisc.buffer_len()
|
||||||
self.pollee.del_events(IoEvents::OUT);
|
}
|
||||||
} else {
|
|
||||||
self.pollee.add_events(IoEvents::OUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fn update_state(&self, buf: &HeapRb<u8>) {
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
self.pollee.del_events(IoEvents::IN)
|
self.pollee.del_events(IoEvents::IN)
|
||||||
} else {
|
} else {
|
||||||
@ -139,18 +133,10 @@ impl FileLike for PtyMaster {
|
|||||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||||
let mut master_buf = self.master_buffer.lock();
|
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 {
|
for item in buf {
|
||||||
self.ldisc.push_char(*item, |content| {
|
self.ldisc.push_char(*item, |content| {
|
||||||
for byte in content.as_bytes() {
|
for byte in content.as_bytes() {
|
||||||
// Unwrap safety: the master buf is ensured to have enough space.
|
master_buf.push_overwrite(*byte);
|
||||||
master_buf.push(*byte).unwrap();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -203,9 +189,18 @@ impl FileLike for PtyMaster {
|
|||||||
};
|
};
|
||||||
Ok(fd)
|
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 => {
|
IoctlCmd::TIOCSCTTY => {
|
||||||
// TODO
|
// TODO: reimplement when adding session.
|
||||||
let foreground = {
|
let foreground = {
|
||||||
let current = current!();
|
let current = current!();
|
||||||
let process_group = current.process_group().lock();
|
let process_group = current.process_group().lock();
|
||||||
@ -225,9 +220,15 @@ impl FileLike for PtyMaster {
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
IoctlCmd::TIOCNOTTY => {
|
IoctlCmd::TIOCNOTTY => {
|
||||||
|
// TODO: reimplement when adding session.
|
||||||
self.ldisc.set_fg(Weak::new());
|
self.ldisc.set_fg(Weak::new());
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
IoctlCmd::FIONREAD => {
|
||||||
|
let len = self.master_buffer.lock().len() as i32;
|
||||||
|
write_val_to_user(arg, &len)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
_ => Ok(0),
|
_ => Ok(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,8 +238,6 @@ impl FileLike for PtyMaster {
|
|||||||
let poll_in_mask = mask & IoEvents::IN;
|
let poll_in_mask = mask & IoEvents::IN;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let _master_buf = self.master_buffer.lock_irq_disabled();
|
|
||||||
|
|
||||||
let mut poll_status = IoEvents::empty();
|
let mut poll_status = IoEvents::empty();
|
||||||
|
|
||||||
if !poll_in_mask.is_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::file_handle::FileLike;
|
||||||
use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
|
use crate::fs::utils::{IoEvents, IoctlCmd, Poller};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::util::write_val_to_user;
|
||||||
|
|
||||||
use super::master::PtyMaster;
|
use super::master::PtyMaster;
|
||||||
|
|
||||||
@ -45,8 +46,12 @@ impl Device for PtySlave {
|
|||||||
|
|
||||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||||
match cmd {
|
match cmd {
|
||||||
IoctlCmd::TCGETS | IoctlCmd::TCSETS | IoctlCmd::TIOCGPGRP => self.0.ioctl(cmd, arg),
|
IoctlCmd::TCGETS
|
||||||
IoctlCmd::TIOCGWINSZ => Ok(0),
|
| IoctlCmd::TCSETS
|
||||||
|
| IoctlCmd::TIOCGPGRP
|
||||||
|
| IoctlCmd::TIOCGPTN
|
||||||
|
| IoctlCmd::TIOCGWINSZ
|
||||||
|
| IoctlCmd::TIOCSWINSZ => self.0.ioctl(cmd, arg),
|
||||||
IoctlCmd::TIOCSCTTY => {
|
IoctlCmd::TIOCSCTTY => {
|
||||||
// TODO:
|
// TODO:
|
||||||
Ok(0)
|
Ok(0)
|
||||||
@ -55,6 +60,11 @@ impl Device for PtySlave {
|
|||||||
// TODO:
|
// TODO:
|
||||||
Ok(0)
|
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),
|
_ => Ok(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use alloc::format;
|
|||||||
use jinux_frame::trap::disable_local;
|
use jinux_frame::trap::disable_local;
|
||||||
use ringbuf::{ring_buffer::RbBase, Rb, StaticRb};
|
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
|
// This implementation refers the implementation of linux
|
||||||
// https://elixir.bootlin.com/linux/latest/source/include/linux/tty_ldisc.h
|
// https://elixir.bootlin.com/linux/latest/source/include/linux/tty_ldisc.h
|
||||||
@ -25,6 +25,8 @@ pub struct LineDiscipline {
|
|||||||
foreground: SpinLock<Weak<ProcessGroup>>,
|
foreground: SpinLock<Weak<ProcessGroup>>,
|
||||||
/// termios
|
/// termios
|
||||||
termios: SpinLock<KernelTermios>,
|
termios: SpinLock<KernelTermios>,
|
||||||
|
/// Windows size,
|
||||||
|
winsize: SpinLock<WinSize>,
|
||||||
/// Pollee
|
/// Pollee
|
||||||
pollee: Pollee,
|
pollee: Pollee,
|
||||||
}
|
}
|
||||||
@ -72,6 +74,7 @@ impl LineDiscipline {
|
|||||||
read_buffer: SpinLock::new(StaticRb::default()),
|
read_buffer: SpinLock::new(StaticRb::default()),
|
||||||
foreground: SpinLock::new(Weak::new()),
|
foreground: SpinLock::new(Weak::new()),
|
||||||
termios: SpinLock::new(KernelTermios::default()),
|
termios: SpinLock::new(KernelTermios::default()),
|
||||||
|
winsize: SpinLock::new(WinSize::default()),
|
||||||
pollee: Pollee::new(IoEvents::empty()),
|
pollee: Pollee::new(IoEvents::empty()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,6 +353,18 @@ impl LineDiscipline {
|
|||||||
self.current_line.lock().drain();
|
self.current_line.lock().drain();
|
||||||
let _: Vec<_> = self.read_buffer.lock().pop_iter().collect();
|
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 {
|
fn meet_new_line(item: u8, termios: &KernelTermios) -> bool {
|
||||||
|
@ -130,7 +130,13 @@ impl Device for Tty {
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
IoctlCmd::TIOCGWINSZ => {
|
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)
|
Ok(0)
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
|
@ -33,22 +33,76 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl C_IFLAGS {
|
||||||
|
pub fn new_default() -> Self {
|
||||||
|
C_IFLAGS::ICRNL | C_IFLAGS::IXON
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Pod)]
|
#[derive(Pod)]
|
||||||
pub struct C_OFLAGS: u32 {
|
pub struct C_OFLAGS: u32 {
|
||||||
const OPOST = 0x01; /* Perform output processing */
|
const OPOST = 0x1 << 0; /* Perform output processing */
|
||||||
const OCRNL = 0x08;
|
const OLCUC = 0x1 << 1;
|
||||||
const ONOCR = 0x10;
|
const ONLCR = 0x1 << 2;
|
||||||
const ONLRET= 0x20;
|
const OCRNL = 0x1 << 3;
|
||||||
const OFILL = 0x40;
|
const ONOCR = 0x1 << 4;
|
||||||
const OFDEL = 0x80;
|
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)]
|
#[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 */
|
B0 = 0x00000000, /* hang up */
|
||||||
B50 = 0x00000001,
|
B50 = 0x00000001,
|
||||||
B75 = 0x00000002,
|
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*/
|
/* c_cc characters index*/
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
#[derive(Debug, Clone, Copy, Pod)]
|
#[derive(Debug, Clone, Copy, Pod)]
|
||||||
@ -114,26 +181,26 @@ pub enum CC_C_CHAR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CC_C_CHAR {
|
impl CC_C_CHAR {
|
||||||
// The special char is the same as ubuntu
|
// The special char is from gvisor
|
||||||
pub fn char(&self) -> u8 {
|
pub fn default_char(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
CC_C_CHAR::VINTR => 3,
|
CC_C_CHAR::VINTR => control_character('C'),
|
||||||
CC_C_CHAR::VQUIT => 28,
|
CC_C_CHAR::VQUIT => control_character('\\'),
|
||||||
CC_C_CHAR::VERASE => 127,
|
CC_C_CHAR::VERASE => '\x7f' as u8,
|
||||||
CC_C_CHAR::VKILL => 21,
|
CC_C_CHAR::VKILL => control_character('U'),
|
||||||
CC_C_CHAR::VEOF => 4,
|
CC_C_CHAR::VEOF => control_character('D'),
|
||||||
CC_C_CHAR::VTIME => 0,
|
CC_C_CHAR::VTIME => '\0' as u8,
|
||||||
CC_C_CHAR::VMIN => 1,
|
CC_C_CHAR::VMIN => 1,
|
||||||
CC_C_CHAR::VSWTC => 0,
|
CC_C_CHAR::VSWTC => '\0' as u8,
|
||||||
CC_C_CHAR::VSTART => 17,
|
CC_C_CHAR::VSTART => control_character('Q'),
|
||||||
CC_C_CHAR::VSTOP => 19,
|
CC_C_CHAR::VSTOP => control_character('S'),
|
||||||
CC_C_CHAR::VSUSP => 26,
|
CC_C_CHAR::VSUSP => control_character('Z'),
|
||||||
CC_C_CHAR::VEOL => 255,
|
CC_C_CHAR::VEOL => '\0' as u8,
|
||||||
CC_C_CHAR::VREPRINT => 18,
|
CC_C_CHAR::VREPRINT => control_character('R'),
|
||||||
CC_C_CHAR::VDISCARD => 15,
|
CC_C_CHAR::VDISCARD => control_character('O'),
|
||||||
CC_C_CHAR::VWERASE => 23,
|
CC_C_CHAR::VWERASE => control_character('W'),
|
||||||
CC_C_CHAR::VLNEXT => 22,
|
CC_C_CHAR::VLNEXT => control_character('V'),
|
||||||
CC_C_CHAR::VEOL2 => 255,
|
CC_C_CHAR::VEOL2 => '\0' as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,28 +209,28 @@ impl CC_C_CHAR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_char(item: u8) -> Result<Self> {
|
pub fn from_char(item: u8) -> Result<Self> {
|
||||||
if item == Self::VINTR.char() {
|
if item == Self::VINTR.default_char() {
|
||||||
return Ok(Self::VINTR);
|
return Ok(Self::VINTR);
|
||||||
}
|
}
|
||||||
if item == Self::VQUIT.char() {
|
if item == Self::VQUIT.default_char() {
|
||||||
return Ok(Self::VQUIT);
|
return Ok(Self::VQUIT);
|
||||||
}
|
}
|
||||||
if item == Self::VINTR.char() {
|
if item == Self::VINTR.default_char() {
|
||||||
return Ok(Self::VINTR);
|
return Ok(Self::VINTR);
|
||||||
}
|
}
|
||||||
if item == Self::VERASE.char() {
|
if item == Self::VERASE.default_char() {
|
||||||
return Ok(Self::VERASE);
|
return Ok(Self::VERASE);
|
||||||
}
|
}
|
||||||
if item == Self::VEOF.char() {
|
if item == Self::VEOF.default_char() {
|
||||||
return Ok(Self::VEOF);
|
return Ok(Self::VEOF);
|
||||||
}
|
}
|
||||||
if item == Self::VSTART.char() {
|
if item == Self::VSTART.default_char() {
|
||||||
return Ok(Self::VSTART);
|
return Ok(Self::VSTART);
|
||||||
}
|
}
|
||||||
if item == Self::VSTOP.char() {
|
if item == Self::VSTOP.default_char() {
|
||||||
return Ok(Self::VSTOP);
|
return Ok(Self::VSTOP);
|
||||||
}
|
}
|
||||||
if item == Self::VSUSP.char() {
|
if item == Self::VSUSP.default_char() {
|
||||||
return Ok(Self::VSUSP);
|
return Ok(Self::VSUSP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,44 +252,33 @@ 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::ICRNL,
|
c_iflags: C_IFLAGS::new_default(),
|
||||||
c_oflags: C_OFLAGS::empty(),
|
c_oflags: C_OFLAGS::new_default(),
|
||||||
c_cflags: C_CFLAGS::B0,
|
c_cflags: C_CFLAGS::new_default(),
|
||||||
c_lflags: C_LFLAGS::ICANON | C_LFLAGS::ECHO,
|
c_lflags: C_LFLAGS::new_default(),
|
||||||
c_line: 0,
|
c_line: 0,
|
||||||
c_cc: [0; KERNEL_NCCS],
|
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::VINTR) = CC_C_CHAR::VINTR.default_char();
|
||||||
*termios.get_special_char_mut(CC_C_CHAR::VQUIT) = CC_C_CHAR::VQUIT.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.char();
|
*termios.get_special_char_mut(CC_C_CHAR::VEOL2) = CC_C_CHAR::VEOL2.default_char();
|
||||||
termios
|
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 {
|
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()]
|
||||||
}
|
}
|
||||||
@ -265,3 +321,17 @@ impl KernelTermios {
|
|||||||
self.c_lflags.contains(C_LFLAGS::IEXTEN)
|
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 {
|
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.index();
|
|
||||||
let fs = self.0.ptmx().fs();
|
let fs = self.0.ptmx().fs();
|
||||||
let devpts = fs.downcast_ref::<DevPts>().unwrap();
|
let devpts = fs.downcast_ref::<DevPts>().unwrap();
|
||||||
|
|
||||||
|
let index = self.0.index();
|
||||||
devpts.remove_slave(index);
|
devpts.remove_slave(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ pub enum IoctlCmd {
|
|||||||
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,
|
||||||
|
/// Get the number of bytes in the input buffer.
|
||||||
|
FIONREAD = 0x541B,
|
||||||
/// Set window size
|
/// Set window size
|
||||||
TIOCGWINSZ = 0x5413,
|
TIOCGWINSZ = 0x5413,
|
||||||
TIOCSWINSZ = 0x5414,
|
TIOCSWINSZ = 0x5414,
|
||||||
|
@ -146,6 +146,7 @@ impl Vnode {
|
|||||||
if let Some(page_cache) = &inner.page_cache {
|
if let Some(page_cache) = &inner.page_cache {
|
||||||
page_cache.evict_range(0..file_len);
|
page_cache.evict_range(0..file_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
inner.inode.read_at(0, &mut buf[..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 {
|
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> {
|
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> {
|
pub fn fs(&self) -> Arc<dyn FileSystem> {
|
||||||
|
@ -150,12 +150,26 @@ 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;
|
||||||
|
|
||||||
|
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)?;
|
self.vmo.read_bytes(vmo_read_offset, buf)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
pub fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
||||||
let vmo_write_offset = self.vmo_offset() + offset;
|
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)?;
|
self.vmo.write_bytes(vmo_write_offset, buf)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -198,7 +212,9 @@ impl VmMapping {
|
|||||||
} else {
|
} else {
|
||||||
self.vmo.check_rights(Rights::READ)?;
|
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)?;
|
let frame = self.vmo.get_committed_frame(page_idx, write)?;
|
||||||
|
|
||||||
@ -300,8 +316,8 @@ impl VmMapping {
|
|||||||
self.inner.lock().trim_right(vm_space, vaddr)
|
self.inner.lock().trim_right(vm_space, vaddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_perm(&self, page_idx: &usize, write: bool) -> Result<()> {
|
fn check_perm(&self, page_idx: &usize, perm: &VmPerm) -> Result<()> {
|
||||||
self.inner.lock().check_perm(page_idx, write)
|
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
|
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
|
let page_perm = self
|
||||||
.page_perms
|
.page_perms
|
||||||
.get(&page_idx)
|
.get(&page_idx)
|
||||||
.ok_or(Error::with_message(Errno::EINVAL, "invalid 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 !page_perm.contains(*perm) {
|
||||||
}
|
return_errno_with_message!(Errno::EACCES, "perm check fails");
|
||||||
if write && !page_perm.contains(VmPerm::W) {
|
|
||||||
return_errno_with_message!(Errno::EINVAL, "perm should contain write for write access");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Reference in New Issue
Block a user