diff --git a/regression/apps/pty/open_pty.c b/regression/apps/pty/open_pty.c index 4e65d81b4..220d2f3eb 100644 --- a/regression/apps/pty/open_pty.c +++ b/regression/apps/pty/open_pty.c @@ -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); diff --git a/regression/apps/scripts/run_tests.sh b/regression/apps/scripts/run_tests.sh index 7556dde7f..d39bc5442 100755 --- a/regression/apps/scripts/run_tests.sh +++ b/regression/apps/scripts/run_tests.sh @@ -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}......" diff --git a/services/libs/jinux-std/src/device/mod.rs b/services/libs/jinux-std/src/device/mod.rs index 0264c45d7..fa9e6a0d9 100644 --- a/services/libs/jinux-std/src/device/mod.rs +++ b/services/libs/jinux-std/src/device/mod.rs @@ -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; diff --git a/services/libs/jinux-std/src/device/pty/master.rs b/services/libs/jinux-std/src/device/pty/master.rs deleted file mode 100644 index a587e612a..000000000 --- a/services/libs/jinux-std/src/device/pty/master.rs +++ /dev/null @@ -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, - index: usize, - ldisc: LineDiscipline, - master_buffer: SpinLock>, - /// The state of master buffer - pollee: Pollee, -} - -impl PtyMaster { - pub fn new_pair(index: u32, ptmx: Arc) -> Result<(Arc, Arc)> { - 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 { - &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 { - 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) { - 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 { - // 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 { - 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 { - 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(); - } - } -} diff --git a/services/libs/jinux-std/src/device/pty/mod.rs b/services/libs/jinux-std/src/device/pty/mod.rs index d0fc149d2..998b59476 100644 --- a/services/libs/jinux-std/src/device/pty/mod.rs +++ b/services/libs/jinux-std/src/device/pty/mod.rs @@ -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> = 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) -> Result<(Arc, Arc)> { + debug!("pty index = {}", index); + let master = Arc::new(PtyMaster::new(ptmx, index)); + let slave = Arc::new(PtySlave::new(master.clone())); + Ok((master, slave)) +} diff --git a/services/libs/jinux-std/src/device/pty/pty.rs b/services/libs/jinux-std/src/device/pty/pty.rs new file mode 100644 index 000000000..e8d1cc1f8 --- /dev/null +++ b/services/libs/jinux-std/src/device/pty/pty.rs @@ -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, + index: u32, + output: LineDiscipline, + input: SpinLock>, + /// The state of input buffer + pollee: Pollee, +} + +impl PtyMaster { + pub fn new(ptmx: Arc, 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 { + &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 { + 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) { + 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 { + // 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 { + 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 { + 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); + +impl PtySlave { + pub fn new(master: Arc) -> 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 { + self.0.slave_read(buf) + } + + fn write(&self, buf: &[u8]) -> Result { + 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 { + 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) + } +} diff --git a/services/libs/jinux-std/src/device/pty/slave.rs b/services/libs/jinux-std/src/device/pty/slave.rs deleted file mode 100644 index 71a119ac7..000000000 --- a/services/libs/jinux-std/src/device/pty/slave.rs +++ /dev/null @@ -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); - -impl PtySlave { - pub fn new(master: Arc) -> 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 { - self.0.slave_read(buf) - } - - fn write(&self, buf: &[u8]) -> Result { - 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 { - 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) - } -} diff --git a/services/libs/jinux-std/src/device/tty/termio.rs b/services/libs/jinux-std/src/device/tty/termio.rs index 5eef22c3f..00615ec16 100644 --- a/services/libs/jinux-std/src/device/tty/termio.rs +++ b/services/libs/jinux-std/src/device/tty/termio.rs @@ -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 { 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 { - 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 diff --git a/services/libs/jinux-std/src/fs/devpts/mod.rs b/services/libs/jinux-std/src/fs/devpts/mod.rs index 58093bf1c..ac2a0ddd7 100644 --- a/services/libs/jinux-std/src/fs/devpts/mod.rs +++ b/services/libs/jinux-std/src/fs/devpts/mod.rs @@ -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> { + fn remove_slave(&self, index: u32) -> Option> { 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 } diff --git a/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs b/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs index f0011f354..994c94880 100644 --- a/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs +++ b/services/libs/jinux-std/src/vm/vmar/vm_mapping.rs @@ -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 {