diff --git a/kernel/src/driver/tty/tty_device.rs b/kernel/src/driver/tty/tty_device.rs index 8b87bf465c..e54d77e234 100644 --- a/kernel/src/driver/tty/tty_device.rs +++ b/kernel/src/driver/tty/tty_device.rs @@ -280,12 +280,15 @@ impl IndexNode for TtyDevice { { let pcb = ProcessManager::current_pcb(); let pcb_tty = pcb.sig_info_irqsave().tty(); - - let cond1 = pcb_tty.is_none(); - let _cond2 = tty.core().contorl_info_irqsave().session.is_none(); - - // 注意!!这里为了debug,临时把cond2的判断去掉了,其实要cond1 && cond2才对 - if cond1 { + let is_session_leader = pcb.sig_info_irqsave().is_session_leader; + let tty_session_is_none = tty.core().contorl_info_irqsave().session.is_none(); + // Linux tty_open_proc_set_tty 语义:必须是会话首进程、尚无 controlling tty、 + // tty 当前未被会话占用,且本次 open 具备读权限(不是 O_WRONLY)。 + if is_session_leader + && pcb_tty.is_none() + && tty_session_is_none + && !mode.is_write_only() + { TtyJobCtrlManager::proc_set_tty(tty); } } diff --git a/kernel/src/driver/tty/tty_job_control.rs b/kernel/src/driver/tty/tty_job_control.rs index b5217bcdf8..6e2aefe9ef 100644 --- a/kernel/src/driver/tty/tty_job_control.rs +++ b/kernel/src/driver/tty/tty_job_control.rs @@ -47,6 +47,7 @@ impl TtyJobCtrlManager { pub fn remove_session_tty(tty: &Arc) { let mut ctrl = tty.core().contorl_info_irqsave(); ctrl.session = None; + ctrl.pgid = None; } /// ### 检查tty @@ -176,9 +177,8 @@ impl TtyJobCtrlManager { fn tiocgpgrp(real_tty: Arc, arg: usize) -> Result { // 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) - { + let current_tty = current.sig_info_irqsave().tty(); + if current_tty.is_none() || !Arc::ptr_eq(¤t_tty.unwrap(), &real_tty) { return Err(SystemError::ENOTTY); } @@ -200,9 +200,8 @@ impl TtyJobCtrlManager { fn tiocgsid(real_tty: Arc, arg: usize) -> Result { // 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) - { + let current_tty = current.sig_info_irqsave().tty(); + if current_tty.is_none() || !Arc::ptr_eq(¤t_tty.unwrap(), &real_tty) { return Err(SystemError::ENOTTY); } diff --git a/kernel/src/process/stdio.rs b/kernel/src/process/stdio.rs index 45359c09d4..ee04e32744 100644 --- a/kernel/src/process/stdio.rs +++ b/kernel/src/process/stdio.rs @@ -22,12 +22,17 @@ pub fn stdio_init() -> Result<(), SystemError> { .lookup(&tty_path) .unwrap_or_else(|_| panic!("Init stdio: can't find {}", tty_path)); - let stdin = - File::new(tty_inode.clone(), FileFlags::O_RDONLY).expect("Init stdio: can't create stdin"); - let stdout = - File::new(tty_inode.clone(), FileFlags::O_WRONLY).expect("Init stdio: can't create stdout"); - let stderr = File::new(tty_inode.clone(), FileFlags::O_WRONLY | FileFlags::O_SYNC) - .expect("Init stdio: can't create stderr"); + // Linux 语义对齐:init(pid=1) 的早期 stdio 绑定不应自动获得 controlling tty。 + // 否则会占住 tty session,影响后续用户态会话通过 TIOCSCTTY 建立控制终端。 + let stdin = File::new(tty_inode.clone(), FileFlags::O_RDONLY | FileFlags::O_NOCTTY) + .expect("Init stdio: can't create stdin"); + let stdout = File::new(tty_inode.clone(), FileFlags::O_WRONLY | FileFlags::O_NOCTTY) + .expect("Init stdio: can't create stdout"); + let stderr = File::new( + tty_inode.clone(), + FileFlags::O_WRONLY | FileFlags::O_SYNC | FileFlags::O_NOCTTY, + ) + .expect("Init stdio: can't create stderr"); /* 按照规定,进程的文件描述符数组的前三个位置,分别是stdin, stdout, stderr diff --git a/user/apps/c_unitest/test_tcgetpgrp_no_ctty.c b/user/apps/c_unitest/test_tcgetpgrp_no_ctty.c new file mode 100644 index 0000000000..937af3aa6b --- /dev/null +++ b/user/apps/c_unitest/test_tcgetpgrp_no_ctty.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +int main(void) { + if (!isatty(STDIN_FILENO)) { + printf("[SKIP] stdin is not a tty, skip tcgetpgrp no-ctty test\n"); + return 0; + } + + pid_t pid = fork(); + if (pid < 0) { + perror("fork"); + return 1; + } + + if (pid == 0) { + if (setsid() < 0) { + perror("setsid"); + _exit(2); + } + + errno = 0; + pid_t pgrp = tcgetpgrp(STDIN_FILENO); + if (pgrp == -1 && errno == ENOTTY) { + printf("[PASS] tcgetpgrp without controlling tty returns ENOTTY\n"); + _exit(0); + } + + fprintf(stderr, + "[FAIL] tcgetpgrp without controlling tty: ret=%d errno=%d\n", + (int)pgrp, errno); + _exit(3); + } + + int status = 0; + if (waitpid(pid, &status, 0) < 0) { + perror("waitpid"); + return 1; + } + + if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + + fprintf(stderr, "[FAIL] child did not exit normally\n"); + return 1; +} diff --git a/user/sysconfig/etc/inittab b/user/sysconfig/etc/inittab index ea769beccd..c16a3543bc 100644 --- a/user/sysconfig/etc/inittab +++ b/user/sysconfig/etc/inittab @@ -1,7 +1,7 @@ # /etc/inittab ::sysinit:busybox sh /etc/init.d/rcS # 系统初始化脚本 -::askfirst:/bin/busybox login -f root +::askfirst:-/bin/busybox login -f root # /etc/inittab - 根据源码弄出来的默认inittab # https://code.dragonos.org.cn/xref/busybox-1.35.0/init/init.c#679