Skip to content

Commit 41de8ac

Browse files
authored
refactor(tty): enhance TTY session management and stdio initialization (DragonOS-Community#1786)
- Update TTY session checks to ensure proper session leader and controlling TTY conditions during open. - Modify stdio initialization to prevent init process from acquiring a controlling TTY, aligning with Linux semantics. - Add a new test case to validate behavior of tcgetpgrp without a controlling TTY. Signed-off-by: longjin <longjin@DragonOS.org>
1 parent 2140513 commit 41de8ac

File tree

5 files changed

+76
-19
lines changed

5 files changed

+76
-19
lines changed

kernel/src/driver/tty/tty_device.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,15 @@ impl IndexNode for TtyDevice {
280280
{
281281
let pcb = ProcessManager::current_pcb();
282282
let pcb_tty = pcb.sig_info_irqsave().tty();
283-
284-
let cond1 = pcb_tty.is_none();
285-
let _cond2 = tty.core().contorl_info_irqsave().session.is_none();
286-
287-
// 注意!!这里为了debug,临时把cond2的判断去掉了,其实要cond1 && cond2才对
288-
if cond1 {
283+
let is_session_leader = pcb.sig_info_irqsave().is_session_leader;
284+
let tty_session_is_none = tty.core().contorl_info_irqsave().session.is_none();
285+
// Linux tty_open_proc_set_tty 语义:必须是会话首进程、尚无 controlling tty、
286+
// tty 当前未被会话占用,且本次 open 具备读权限(不是 O_WRONLY)。
287+
if is_session_leader
288+
&& pcb_tty.is_none()
289+
&& tty_session_is_none
290+
&& !mode.is_write_only()
291+
{
289292
TtyJobCtrlManager::proc_set_tty(tty);
290293
}
291294
}

kernel/src/driver/tty/tty_job_control.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ impl TtyJobCtrlManager {
4747
pub fn remove_session_tty(tty: &Arc<TtyCore>) {
4848
let mut ctrl = tty.core().contorl_info_irqsave();
4949
ctrl.session = None;
50+
ctrl.pgid = None;
5051
}
5152

5253
/// ### 检查tty
@@ -176,9 +177,8 @@ impl TtyJobCtrlManager {
176177
fn tiocgpgrp(real_tty: Arc<TtyCore>, arg: usize) -> Result<usize, SystemError> {
177178
// log::debug!("job_ctrl_ioctl: TIOCGPGRP");
178179
let current = ProcessManager::current_pcb();
179-
if current.sig_info_irqsave().tty().is_some()
180-
&& !Arc::ptr_eq(&current.sig_info_irqsave().tty().unwrap(), &real_tty)
181-
{
180+
let current_tty = current.sig_info_irqsave().tty();
181+
if current_tty.is_none() || !Arc::ptr_eq(&current_tty.unwrap(), &real_tty) {
182182
return Err(SystemError::ENOTTY);
183183
}
184184

@@ -200,9 +200,8 @@ impl TtyJobCtrlManager {
200200
fn tiocgsid(real_tty: Arc<TtyCore>, arg: usize) -> Result<usize, SystemError> {
201201
// log::debug!("job_ctrl_ioctl: TIOCGSID");
202202
let current = ProcessManager::current_pcb();
203-
if current.sig_info_irqsave().tty().is_some()
204-
&& !Arc::ptr_eq(&current.sig_info_irqsave().tty().unwrap(), &real_tty)
205-
{
203+
let current_tty = current.sig_info_irqsave().tty();
204+
if current_tty.is_none() || !Arc::ptr_eq(&current_tty.unwrap(), &real_tty) {
206205
return Err(SystemError::ENOTTY);
207206
}
208207

kernel/src/process/stdio.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,17 @@ pub fn stdio_init() -> Result<(), SystemError> {
2222
.lookup(&tty_path)
2323
.unwrap_or_else(|_| panic!("Init stdio: can't find {}", tty_path));
2424

25-
let stdin =
26-
File::new(tty_inode.clone(), FileFlags::O_RDONLY).expect("Init stdio: can't create stdin");
27-
let stdout =
28-
File::new(tty_inode.clone(), FileFlags::O_WRONLY).expect("Init stdio: can't create stdout");
29-
let stderr = File::new(tty_inode.clone(), FileFlags::O_WRONLY | FileFlags::O_SYNC)
30-
.expect("Init stdio: can't create stderr");
25+
// Linux 语义对齐:init(pid=1) 的早期 stdio 绑定不应自动获得 controlling tty。
26+
// 否则会占住 tty session,影响后续用户态会话通过 TIOCSCTTY 建立控制终端。
27+
let stdin = File::new(tty_inode.clone(), FileFlags::O_RDONLY | FileFlags::O_NOCTTY)
28+
.expect("Init stdio: can't create stdin");
29+
let stdout = File::new(tty_inode.clone(), FileFlags::O_WRONLY | FileFlags::O_NOCTTY)
30+
.expect("Init stdio: can't create stdout");
31+
let stderr = File::new(
32+
tty_inode.clone(),
33+
FileFlags::O_WRONLY | FileFlags::O_SYNC | FileFlags::O_NOCTTY,
34+
)
35+
.expect("Init stdio: can't create stderr");
3136

3237
/*
3338
按照规定,进程的文件描述符数组的前三个位置,分别是stdin, stdout, stderr
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#include <errno.h>
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
#include <sys/wait.h>
5+
#include <unistd.h>
6+
7+
int main(void) {
8+
if (!isatty(STDIN_FILENO)) {
9+
printf("[SKIP] stdin is not a tty, skip tcgetpgrp no-ctty test\n");
10+
return 0;
11+
}
12+
13+
pid_t pid = fork();
14+
if (pid < 0) {
15+
perror("fork");
16+
return 1;
17+
}
18+
19+
if (pid == 0) {
20+
if (setsid() < 0) {
21+
perror("setsid");
22+
_exit(2);
23+
}
24+
25+
errno = 0;
26+
pid_t pgrp = tcgetpgrp(STDIN_FILENO);
27+
if (pgrp == -1 && errno == ENOTTY) {
28+
printf("[PASS] tcgetpgrp without controlling tty returns ENOTTY\n");
29+
_exit(0);
30+
}
31+
32+
fprintf(stderr,
33+
"[FAIL] tcgetpgrp without controlling tty: ret=%d errno=%d\n",
34+
(int)pgrp, errno);
35+
_exit(3);
36+
}
37+
38+
int status = 0;
39+
if (waitpid(pid, &status, 0) < 0) {
40+
perror("waitpid");
41+
return 1;
42+
}
43+
44+
if (WIFEXITED(status)) {
45+
return WEXITSTATUS(status);
46+
}
47+
48+
fprintf(stderr, "[FAIL] child did not exit normally\n");
49+
return 1;
50+
}

user/sysconfig/etc/inittab

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# /etc/inittab
22
::sysinit:busybox sh /etc/init.d/rcS # 系统初始化脚本
33

4-
::askfirst:/bin/busybox login -f root
4+
::askfirst:-/bin/busybox login -f root
55

66
# /etc/inittab - 根据源码弄出来的默认inittab
77
# https://code.dragonos.org.cn/xref/busybox-1.35.0/init/init.c#679

0 commit comments

Comments
 (0)