【问题标题】:Terminal Access Control issues终端访问控制问题
【发布时间】:2013-10-20 06:18:17
【问题描述】:

我正在尝试编写一个 shell。当前台进程运行时,分叉的进程管道将被赋予其自己的进程组 ID。然后终端被交给这个进程组 id(使用 tcsetpgrp),shell 等待它终止,然后再给自己终端控制。这工作得很好。

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

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

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

【问题讨论】:

    标签: c shell terminal signals posix


    【解决方案1】:

    解决办法是让分叉的进程在调用 exec 之前执行以下操作:

    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");
    

    【讨论】:

    • 好的,谢谢。还有一件事——这可以防止除 fg 进程之外的任何东西写入终端,但是否有从终端读取的等价物?
    • Afaik 只有 fg 进程可以从终端读取。 bg 进程可以忽略 SIGTTIN 并尝试从终端读取,但无法成功。所以读写是不对称的。
    • 我的问题与外壳有关。在 fg 进程开始执行后,用户对终端的输入会同时提供给分叉的进程和 shell。 shell 试图读取这个输入,这会导致它尝试写入适当的输出,这会导致它被 SIGTTOU 阻塞。
    • 当然,但是 shell 正在那里执行两个单独的操作。它尝试在尝试读取之前写入,因此它永远不会发现读取不起作用。它需要做的是在尝试编写提示之前测试它是否有终端(例如,使用tcgetpgrp)。
    【解决方案2】:

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

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

    【讨论】:

    • 谢谢!这行得通!对于所有想知道的人,我在答案中包含了特定命令。
    猜你喜欢
    • 1970-01-01
    • 2018-10-27
    • 2017-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    相关资源
    最近更新 更多