Enable gvisor pty test

This commit is contained in:
Jianfeng Jiang
2023-08-17 14:15:35 +08:00
committed by Tate, Hongliang Tian
parent f802ff40c5
commit 40056f0692
11 changed files with 269 additions and 107 deletions

View File

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

View 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

View File

@ -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() {

View File

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

View File

@ -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 {

View File

@ -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!(),

View File

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

View File

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

View File

@ -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,

View File

@ -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> {

View File

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