mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-25 05:53:22 +00:00
Feat(tty): Supplement process group logic (#1139)
* 添加busybox的编译 * 完善tty job control的逻辑 * 修改copy_sighand的逻辑,符合Linux语义 * 以busybox作为启动shell去运行 * 修改setsid的逻辑 * 解决前台进程组无法处理信号的问题 * 移除ProcessBasicInfo其中的pgid和sid信息 * 修改setsid * 新增get_pcb_info * 在etc目录下新增必要的文件 * 改用busybox init作为引导程序 * 恢复dragonreach文件 * 修改busybox编译选项,能够读取环境变量 * 先让SYS_RT_SIGTIMEDWAIT返回Ok(0),能够正常进入系统 * 一些小更改 * 删除get_pcb_info * 增加对默认termios的判断 * 完成backspace的修复 * 更改inittab,在shell启动之后更改termios * 增加executable_path信息 * 补充proc下的exe链接文件以及读取逻辑 * 更改PosixTermios,使用stty完成erase的设置 * 用busybox作为引导程序 * 修改波特率的获取 * 修改函数方法 * 在baud_rate方法中添加对于cbaud的与操作 * 为rv64下的SigSet实现From<Signal> * refactor(driver): 移除`#[derive(Debug)]`并手动实现`Debug` trait 移除`VirtIOBlkDevice`、`VirtIOConsoleDevice`和`VirtIONetDevice`的`#[derive(Debug)]`,并手动实现`Debug` trait以提供更详细的调试信息。 Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
@ -1,4 +1,7 @@
|
||||
use core::{any::Any, fmt::Debug};
|
||||
use core::{
|
||||
any::Any,
|
||||
fmt::{Debug, Formatter},
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
@ -147,7 +150,6 @@ impl VirtIOBlkManager {
|
||||
}
|
||||
|
||||
/// virtio block device
|
||||
#[derive(Debug)]
|
||||
#[cast_to([sync] VirtIODevice)]
|
||||
#[cast_to([sync] Device)]
|
||||
pub struct VirtIOBlkDevice {
|
||||
@ -158,6 +160,15 @@ pub struct VirtIOBlkDevice {
|
||||
self_ref: Weak<Self>,
|
||||
}
|
||||
|
||||
impl Debug for VirtIOBlkDevice {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("VirtIOBlkDevice")
|
||||
.field("devname", &self.blkdev_meta.devname)
|
||||
.field("dev_id", &self.dev_id.id())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for VirtIOBlkDevice {}
|
||||
unsafe impl Sync for VirtIOBlkDevice {}
|
||||
|
||||
|
@ -90,7 +90,7 @@ pub fn virtio_console(
|
||||
}
|
||||
|
||||
//
|
||||
#[derive(Debug)]
|
||||
|
||||
#[cast_to([sync] VirtIODevice)]
|
||||
#[cast_to([sync] Device)]
|
||||
pub struct VirtIOConsoleDevice {
|
||||
@ -103,6 +103,22 @@ pub struct VirtIOConsoleDevice {
|
||||
unsafe impl Send for VirtIOConsoleDevice {}
|
||||
unsafe impl Sync for VirtIOConsoleDevice {}
|
||||
|
||||
impl Debug for VirtIOConsoleDevice {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("VirtIOConsoleDevice")
|
||||
.field(
|
||||
"devname",
|
||||
&self
|
||||
.dev_name
|
||||
.try_get()
|
||||
.map(|x| x.as_str())
|
||||
.unwrap_or("uninitialized"),
|
||||
)
|
||||
.field("dev_id", &self.dev_id.id())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtIOConsoleDevice {
|
||||
pub fn new(transport: VirtIOTransport, dev_id: Arc<DeviceId>) -> Option<Arc<Self>> {
|
||||
// 设置中断
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::{
|
||||
any::Any,
|
||||
cell::UnsafeCell,
|
||||
fmt::Debug,
|
||||
fmt::{Debug, Formatter},
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
@ -62,7 +62,6 @@ fn virtio_net_driver() -> Arc<VirtIONetDriver> {
|
||||
}
|
||||
|
||||
/// virtio net device
|
||||
#[derive(Debug)]
|
||||
#[cast_to([sync] VirtIODevice)]
|
||||
#[cast_to([sync] Device)]
|
||||
pub struct VirtIONetDevice {
|
||||
@ -71,6 +70,14 @@ pub struct VirtIONetDevice {
|
||||
locked_kobj_state: LockedKObjectState,
|
||||
}
|
||||
|
||||
impl Debug for VirtIONetDevice {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("VirtIONetDevice")
|
||||
.field("dev_id", &self.dev_id.id())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for VirtIONetDevice {}
|
||||
unsafe impl Sync for VirtIONetDevice {}
|
||||
|
||||
@ -84,7 +91,7 @@ struct InnerVirtIONetDevice {
|
||||
|
||||
impl Debug for InnerVirtIONetDevice {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("InnerVirtIOBlkDevice").finish()
|
||||
f.debug_struct("InnerVirtIONetDevice").finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,10 +44,8 @@ pub struct PosixTermios {
|
||||
pub c_oflag: u32,
|
||||
pub c_cflag: u32,
|
||||
pub c_lflag: u32,
|
||||
pub c_cc: [u8; CONTORL_CHARACTER_NUM],
|
||||
pub c_line: u8,
|
||||
pub c_ispeed: u32,
|
||||
pub c_ospeed: u32,
|
||||
pub c_cc: [u8; CONTORL_CHARACTER_NUM],
|
||||
}
|
||||
|
||||
impl PosixTermios {
|
||||
@ -59,8 +57,6 @@ impl PosixTermios {
|
||||
c_lflag: termios.local_mode.bits,
|
||||
c_cc: termios.control_characters,
|
||||
c_line: termios.line as u8,
|
||||
c_ispeed: termios.input_speed,
|
||||
c_ospeed: termios.output_speed,
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,8 +69,24 @@ impl PosixTermios {
|
||||
local_mode: LocalMode::from_bits_truncate(self.c_lflag),
|
||||
control_characters: self.c_cc,
|
||||
line: LineDisciplineType::from_line(self.c_line),
|
||||
input_speed: self.c_ispeed,
|
||||
output_speed: self.c_ospeed,
|
||||
input_speed: self.input_speed().unwrap_or(38400),
|
||||
output_speed: self.output_speed().unwrap_or(38400),
|
||||
}
|
||||
}
|
||||
|
||||
fn output_speed(&self) -> Option<u32> {
|
||||
let flag = ControlMode::from_bits_truncate(
|
||||
self.c_cflag & ControlMode::CBAUD.intersection(ControlMode::CBAUDEX).bits(),
|
||||
); // CBAUD + CBAUDEX
|
||||
flag.baud_rate()
|
||||
}
|
||||
|
||||
fn input_speed(&self) -> Option<u32> {
|
||||
let ibaud = (self.c_cflag & ControlMode::CIBAUD.bits()) >> 16;
|
||||
if ibaud == 0 {
|
||||
self.output_speed()
|
||||
} else {
|
||||
ControlMode::from_bits_truncate(ibaud).baud_rate()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -352,6 +364,47 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
impl ControlMode {
|
||||
/// 获取波特率
|
||||
pub fn baud_rate(&self) -> Option<u32> {
|
||||
let flag = self.intersection(Self::CBAUD);
|
||||
match flag {
|
||||
Self::B0 => Some(0),
|
||||
Self::B50 => Some(50),
|
||||
Self::B75 => Some(75),
|
||||
Self::B110 => Some(110),
|
||||
Self::B134 => Some(134),
|
||||
Self::B150 => Some(150),
|
||||
Self::B200 => Some(200),
|
||||
Self::B300 => Some(300),
|
||||
Self::B600 => Some(600),
|
||||
Self::B1200 => Some(1200),
|
||||
Self::B1800 => Some(1800),
|
||||
Self::B2400 => Some(2400),
|
||||
Self::B4800 => Some(4800),
|
||||
Self::B9600 => Some(9600),
|
||||
Self::B19200 => Some(19200),
|
||||
Self::B38400 => Some(38400),
|
||||
Self::B57600 => Some(57600),
|
||||
Self::B115200 => Some(115200),
|
||||
Self::B230400 => Some(230400),
|
||||
Self::B460800 => Some(460800),
|
||||
Self::B500000 => Some(500000),
|
||||
Self::B576000 => Some(576000),
|
||||
Self::B921600 => Some(921600),
|
||||
Self::B1000000 => Some(1000000),
|
||||
Self::B1152000 => Some(1152000),
|
||||
Self::B1500000 => Some(1500000),
|
||||
Self::B2000000 => Some(2000000),
|
||||
Self::B2500000 => Some(2500000),
|
||||
Self::B3000000 => Some(3000000),
|
||||
Self::B3500000 => Some(3500000),
|
||||
Self::B4000000 => Some(4000000),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 对应termios中控制字符的索引
|
||||
pub struct ControlCharIndex;
|
||||
#[allow(dead_code)]
|
||||
|
@ -19,7 +19,7 @@ use crate::{
|
||||
},
|
||||
mm::VirtAddr,
|
||||
net::event_poll::{EPollEventType, EPollItem},
|
||||
process::Pid,
|
||||
process::{process_group::Pgid, session::Sid, ProcessControlBlock},
|
||||
syscall::user_access::{UserBufferReader, UserBufferWriter},
|
||||
};
|
||||
|
||||
@ -280,16 +280,23 @@ impl TtyCore {
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TtyContorlInfo {
|
||||
/// 前台进程pid
|
||||
pub session: Option<Pid>,
|
||||
/// 当前会话的SId
|
||||
pub session: Option<Sid>,
|
||||
/// 前台进程组id
|
||||
pub pgid: Option<Pid>,
|
||||
pub pgid: Option<Pgid>,
|
||||
|
||||
/// packet模式下使用,目前未用到
|
||||
pub pktstatus: TtyPacketStatus,
|
||||
pub packet: bool,
|
||||
}
|
||||
|
||||
impl TtyContorlInfo {
|
||||
pub fn set_info_by_pcb(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
self.session = Some(pcb.sid());
|
||||
self.pgid = Some(pcb.pgid());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TtyFlowState {
|
||||
/// 表示流控是否被停止
|
||||
|
@ -4,7 +4,7 @@ use system_error::SystemError;
|
||||
use crate::{
|
||||
arch::ipc::signal::{SigSet, Signal},
|
||||
mm::VirtAddr,
|
||||
process::{Pid, ProcessFlags, ProcessManager},
|
||||
process::{process_group::Pgid, Pid, ProcessFlags, ProcessManager},
|
||||
syscall::{
|
||||
user_access::{UserBufferReader, UserBufferWriter},
|
||||
Syscall,
|
||||
@ -19,16 +19,13 @@ impl TtyJobCtrlManager {
|
||||
/// ### 设置当前进程的tty
|
||||
pub fn proc_set_tty(tty: Arc<TtyCore>) {
|
||||
let core = tty.core();
|
||||
let mut ctrl = core.contorl_info_irqsave();
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
|
||||
let pid = Pid::new(pcb.basic().sid().into());
|
||||
ctrl.session = Some(pid);
|
||||
|
||||
assert!(pcb.sig_info_irqsave().tty().is_none());
|
||||
let mut ctrl = core.contorl_info_irqsave();
|
||||
ctrl.set_info_by_pcb(pcb.clone());
|
||||
drop(ctrl);
|
||||
|
||||
let mut singal = pcb.sig_info_mut();
|
||||
drop(ctrl);
|
||||
singal.set_tty(Some(tty.clone()));
|
||||
}
|
||||
|
||||
@ -42,27 +39,27 @@ impl TtyJobCtrlManager {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let core = tty.core();
|
||||
let ctrl = core.contorl_info_irqsave();
|
||||
let pgid = pcb.pgid();
|
||||
|
||||
// todo pgid
|
||||
let pgid = pcb.pid();
|
||||
let ctrl = tty.core().contorl_info_irqsave();
|
||||
let tty_pgid = ctrl.pgid;
|
||||
drop(ctrl);
|
||||
|
||||
if tty_pgid.is_some() && tty_pgid.unwrap() != pgid {
|
||||
if pcb
|
||||
.sig_info_irqsave()
|
||||
.sig_blocked()
|
||||
.contains(SigSet::from_bits_truncate(1 << sig as u64))
|
||||
.contains(SigSet::from(sig))
|
||||
|| pcb.sig_struct_irqsave().handlers[sig as usize - 1].is_ignore()
|
||||
{
|
||||
// 忽略该信号
|
||||
if sig == Signal::SIGTTIN {
|
||||
return Err(SystemError::EIO);
|
||||
}
|
||||
} else if ProcessManager::is_current_pgrp_orphaned() {
|
||||
return Err(SystemError::EIO);
|
||||
} else {
|
||||
// 暂时使用kill而不是killpg
|
||||
Syscall::kill_process(pgid, sig)?;
|
||||
Syscall::kill_process_group(pgid, sig)?;
|
||||
ProcessManager::current_pcb()
|
||||
.flags()
|
||||
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
|
||||
@ -74,74 +71,146 @@ impl TtyJobCtrlManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn job_ctrl_ioctl(tty: Arc<TtyCore>, cmd: u32, arg: usize) -> Result<usize, SystemError> {
|
||||
pub fn job_ctrl_ioctl(
|
||||
real_tty: Arc<TtyCore>,
|
||||
cmd: u32,
|
||||
arg: usize,
|
||||
) -> Result<usize, SystemError> {
|
||||
match cmd {
|
||||
TtyIoctlCmd::TIOCSPGRP => {
|
||||
match Self::tty_check_change(tty.clone(), Signal::SIGTTOU) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
if e == SystemError::EIO {
|
||||
return Err(SystemError::ENOTTY);
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
let user_reader = UserBufferReader::new(
|
||||
VirtAddr::new(arg).as_ptr::<i32>(),
|
||||
core::mem::size_of::<i32>(),
|
||||
true,
|
||||
)?;
|
||||
|
||||
let pgrp = user_reader.read_one_from_user::<i32>(0)?;
|
||||
|
||||
let current = ProcessManager::current_pcb();
|
||||
|
||||
let mut ctrl = tty.core().contorl_info_irqsave();
|
||||
|
||||
if current.sig_info_irqsave().tty().is_none()
|
||||
|| !Arc::ptr_eq(¤t.sig_info_irqsave().tty().clone().unwrap(), &tty)
|
||||
|| ctrl.session.is_none()
|
||||
|| ctrl.session.unwrap() != Pid::from(current.basic().sid().into())
|
||||
{
|
||||
return Err(SystemError::ENOTTY);
|
||||
}
|
||||
|
||||
ctrl.pgid = Some(Pid::from(*pgrp as usize));
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
TtyIoctlCmd::TIOCGPGRP => {
|
||||
let current = ProcessManager::current_pcb();
|
||||
if current.sig_info_irqsave().tty().is_some()
|
||||
&& !Arc::ptr_eq(¤t.sig_info_irqsave().tty().unwrap(), &tty)
|
||||
{
|
||||
return Err(SystemError::ENOTTY);
|
||||
}
|
||||
|
||||
let mut user_writer = UserBufferWriter::new(
|
||||
VirtAddr::new(arg).as_ptr::<i32>(),
|
||||
core::mem::size_of::<i32>(),
|
||||
true,
|
||||
)?;
|
||||
|
||||
user_writer.copy_one_to_user(
|
||||
&(tty
|
||||
.core()
|
||||
.contorl_info_irqsave()
|
||||
.pgid
|
||||
.unwrap_or(Pid::new(0))
|
||||
.data() as i32),
|
||||
0,
|
||||
)?;
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
TtyIoctlCmd::TIOCSPGRP => Self::tiocspgrp(real_tty, arg),
|
||||
TtyIoctlCmd::TIOCGPGRP => Self::tiocgpgrp(real_tty, arg),
|
||||
TtyIoctlCmd::TIOCGSID => Self::tiocgsid(real_tty, arg),
|
||||
TtyIoctlCmd::TIOCSCTTY => Self::tiocsctty(real_tty),
|
||||
_ => {
|
||||
return Err(SystemError::ENOIOCTLCMD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tiocsctty(real_tty: Arc<TtyCore>) -> Result<usize, SystemError> {
|
||||
let current = ProcessManager::current_pcb();
|
||||
// log::debug!("job_ctrl_ioctl: TIOCSCTTY,current: {:?}", current.pid());
|
||||
if current.is_session_leader()
|
||||
&& real_tty.core().contorl_info_irqsave().session.unwrap() == current.sid()
|
||||
{
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
if !current.is_session_leader() || current.sig_info_irqsave().tty().is_some() {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
|
||||
//todo 权限检查?
|
||||
// https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/tty/tty_jobctrl.c#tiocsctty
|
||||
if let Some(sid) = real_tty.core().contorl_info_irqsave().session {
|
||||
//todo 目前只有一个tty设备,所以选择复用1号进程的tty,因此修改1号进程的tty暂时被允许
|
||||
if sid != Pid::new(1) {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
Self::proc_set_tty(real_tty);
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn tiocgpgrp(real_tty: Arc<TtyCore>, arg: usize) -> Result<usize, SystemError> {
|
||||
// log::debug!("job_ctrl_ioctl: TIOCGPGRP");
|
||||
let current = ProcessManager::current_pcb();
|
||||
if current.sig_info_irqsave().tty().is_some()
|
||||
&& !Arc::ptr_eq(¤t.sig_info_irqsave().tty().unwrap(), &real_tty)
|
||||
{
|
||||
return Err(SystemError::ENOTTY);
|
||||
}
|
||||
|
||||
let mut user_writer = UserBufferWriter::new(
|
||||
VirtAddr::new(arg).as_ptr::<i32>(),
|
||||
core::mem::size_of::<i32>(),
|
||||
true,
|
||||
)?;
|
||||
|
||||
user_writer.copy_one_to_user(
|
||||
&(real_tty
|
||||
.core()
|
||||
.contorl_info_irqsave()
|
||||
.pgid
|
||||
.unwrap_or(Pid::new(1))
|
||||
.data() as i32),
|
||||
0,
|
||||
)?;
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
fn tiocgsid(real_tty: Arc<TtyCore>, arg: usize) -> Result<usize, SystemError> {
|
||||
// log::debug!("job_ctrl_ioctl: TIOCGSID");
|
||||
let current = ProcessManager::current_pcb();
|
||||
if current.sig_info_irqsave().tty().is_some()
|
||||
&& !Arc::ptr_eq(¤t.sig_info_irqsave().tty().unwrap(), &real_tty)
|
||||
{
|
||||
return Err(SystemError::ENOTTY);
|
||||
}
|
||||
|
||||
let guard = real_tty.core().contorl_info_irqsave();
|
||||
if guard.session.is_none() {
|
||||
return Err(SystemError::ENOTTY);
|
||||
}
|
||||
let sid = guard.session.unwrap();
|
||||
drop(guard);
|
||||
|
||||
let mut user_writer = UserBufferWriter::new(
|
||||
VirtAddr::new(arg).as_ptr::<i32>(),
|
||||
core::mem::size_of::<i32>(),
|
||||
true,
|
||||
)?;
|
||||
user_writer.copy_one_to_user(&(sid.data() as i32), 0)?;
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
fn tiocspgrp(real_tty: Arc<TtyCore>, arg: usize) -> Result<usize, SystemError> {
|
||||
// log::debug!("job_ctrl_ioctl: TIOCSPGRP");
|
||||
match Self::tty_check_change(real_tty.clone(), Signal::SIGTTOU) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
if e == SystemError::EIO {
|
||||
return Err(SystemError::ENOTTY);
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
|
||||
let user_reader = UserBufferReader::new(
|
||||
VirtAddr::new(arg).as_ptr::<i32>(),
|
||||
core::mem::size_of::<i32>(),
|
||||
true,
|
||||
)?;
|
||||
|
||||
let pgrp = user_reader.read_one_from_user::<i32>(0)?;
|
||||
|
||||
let current = ProcessManager::current_pcb();
|
||||
|
||||
let mut ctrl = real_tty.core().contorl_info_irqsave();
|
||||
|
||||
if current.sig_info_irqsave().tty().is_none()
|
||||
|| !Arc::ptr_eq(
|
||||
¤t.sig_info_irqsave().tty().clone().unwrap(),
|
||||
&real_tty,
|
||||
)
|
||||
|| ctrl.session.is_none()
|
||||
|| ctrl.session.unwrap() != current.sid()
|
||||
{
|
||||
return Err(SystemError::ENOTTY);
|
||||
}
|
||||
|
||||
let pg = ProcessManager::find_process_group(Pgid::from(*pgrp as usize));
|
||||
if pg.is_none() {
|
||||
return Err(SystemError::ESRCH);
|
||||
} else if !Arc::ptr_eq(&pg.unwrap().session().unwrap(), ¤t.session().unwrap()) {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
|
||||
ctrl.pgid = Some(Pid::from(*pgrp as usize));
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +390,7 @@ impl NTtyData {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((c as usize) < self.char_map.size()) && self.char_map.get(c as usize).unwrap() {
|
||||
if ((c as usize) < self.char_map.len()) && self.char_map.get(c as usize).unwrap() {
|
||||
// 特殊字符
|
||||
self.receive_special_char(c, tty.clone(), lookahead_done);
|
||||
} else {
|
||||
@ -790,7 +790,7 @@ impl NTtyData {
|
||||
let ctrl_info = tty.core().contorl_info_irqsave();
|
||||
let pg = ctrl_info.pgid;
|
||||
if let Some(pg) = pg {
|
||||
let _ = Syscall::kill_process(pg, signal);
|
||||
let _ = Syscall::kill_process_group(pg, signal);
|
||||
}
|
||||
|
||||
if !termios.local_mode.contains(LocalMode::NOFLSH) {
|
||||
|
Reference in New Issue
Block a user