终端访问控制问题

时间:2013-10-12 04:16:58

标签: c shell terminal signals posix

我正在尝试编写一个shell。运行前台进程时,分叉进程管道将获得其自己的进程组标识。然后终端被赋予该进程组id(使用tcsetpgrp),并且shell在再次给自己终端控制之前等待它终止。这完全没问题。

出现的问题是当我尝试运行后台进程时。同样,我给管道中的所有进程提供了一个进程组ID,但这次我没有给该组提供终端控制。在运行时,给定后台命令的输出被输出到终端(在它完成执行之前)并且终端同时向用户提供提示。应该发生的是,尝试写入终端的子进程应该得到一个SIGTTOU并且它应该停止,但这显然不会发生。我验证了分叉进程都具有相同的进程组ID,并且此id与shell的不同。

退出shell(通过ctrl-c)并返回运行它的标准bash shell,因为我没有在shell终止时收到后台进程,后台进程继续运行(除外)。但奇怪的是,这个过程继续将输出写入bash shell,即使它不是前台进程。这使我得出结论,由于POSIX错误(不太可能),这个后台进程没有得到任何SIGTTOU,它正在处理它们(导致停止的默认操作被忽略),或者后台进程忽略了SIGTTOU。

在执行分叉进程之前,有没有办法确保它在收到SIGTTOU时停止(假设exec二进制文件没有改变任何东西)?

2 个答案:

答案 0 :(得分:3)

SIGTTOU被发送到后台进程,该进程仅在为该终端设置了termios标志TOSTOP时才尝试写入终端。默认情况下,通常不设置,在这种情况下,后台进程可以愉快地写入终端。 (TOSTOP标志不会影响读取权限。如果进程尝试读取,则会发送SIGTTIN。)

所以,是的,前台流程可以做一些事情:使用tcsetattr设置TOSTOP

答案 1 :(得分:1)

解决方案是在调用exec:

之前使forked进程执行以下命令
struct termios term; 
if (tcgetattr(STDIN_FILENO, &term) < 0)
        printf("ERROR\n");
    term.c_lflag = TOSTOP;
    if (tcsetattr(STDIN_FILENO,TCSANOW,&term)<0)
        printf("ERROR\n");