【问题标题】:Created a bash shell using forkpty(). It seems programs launched by this shell launch with SIGINT ignored. Why?使用 forkpty() 创建了一个 bash shell。似乎此 shell 启动的程序忽略了 SIGINT。为什么?
【发布时间】:2016-02-10 08:37:37
【问题描述】:

我有一个使用 forkpty 执行 bash shell 的 C 程序。我发现这个 shell 启动的程序是在忽略 SIGINT 的情况下启动的,所以当我向 shell 发送 Ctrl-C 时,它们永远不会关闭。

示例:

int masterFd;
char* args[] = {"/bin/bash", "-i", NULL };
int procId = forkpty(&masterFd, NULL, NULL,  NULL);
if( procId == 0 ){
  execve( args[0], args, NULL);
}
else {
   // Simple code that reads from standard in and writes to masterFd.  
   // I also register for Ctrl-C and write it to masterFd if caught
}

其他控制字符似乎可以通过,ctrl-D,ctrl-?等等。但是,每当我查看由新的 bash shell 启动的进程的状态时,它看起来好像 SIGINT 被屏蔽了。

MyShell:# sleep 1000

StandardTerm:#  ps -ef | grep sleep
root    26611  19278  0  17:44  pts/1   00:00:00 sleep 1000
root    26613  32376  0  17:44  pts/1   00:00:00 grep sleep

StandardTerm:# grep Sig proc/26611/status
SigQ:    0/256428
SigPnd:  0000000000000000
SigBlk:  0000000000000000
SigIgn:  0000000000010006   <- THE 6 IS THE PROBLEM
SigCgt:  0000000180000000

SigIgn 设置了 2 位,这意味着 2 (SIGINT) 被忽略。如果我做同样的事情,但在标准终端中运行 sleep (或 cat 一个巨大的文件或其他什么),这个位被清除。当我启动我的 pty bash 导致它创建忽略 SIGINT 的孙子程序时,我在做什么?

此外,如果我向进程发送 SIGINT 信号

StandardTerm:# kill -2 26611

什么都没有发生。奇怪的是,当我向我 forkpty'ed IT 工作的 bash shell 发送相同的命令时,因为那个 bash shell 没有忽略 SIGINT。

提前致谢!

【问题讨论】:

    标签: c linux bash shell pty


    【解决方案1】:

    父进程是否屏蔽了SIGINT

    fork()execve() 都将信号掩码传播到子进程,也许是这样?

    【讨论】:

    • 不,他们没有。父进程的 SigIgn 是 4 而不是上面的 6,可以通过调用 kill -2 来终止
    • 这应该是评论而不是答案。
    【解决方案2】:

    查看 termios(3) 手册页。您在 forkpty 调用中使用 'NULL' 作为 termios(第三个)参数,这意味着 'c_iflag ' termios 结构值将是未定义的,并继承其父进程的值。 (谢谢@djc6535)

    pid_t forkpty(int *amaster, char *name,
                  const struct termios *termp,
                  const struct winsize *winp);
    
    struct termios
      {
        tcflag_t c_iflag;       /* input mode flags */
        tcflag_t c_oflag;       /* output mode flags */
        tcflag_t c_cflag;       /* control mode flags */
        tcflag_t c_lflag;       /* local mode flags */
        cc_t c_line;            /* line discipline */
        cc_t c_cc[NCCS];        /* control characters */
        speed_t c_ispeed;       /* input speed */
        speed_t c_ospeed;       /* output speed */
      };
    

    来自 termios(3) 手册页:

        c_iflag flag constants:
    
        IGNBRK Ignore BREAK condition on input.
    
        BRKINT If IGNBRK is set, a BREAK is ignored.  If it is not set but BRKINT is set, then a  BREAK  causes  the  input  and  output
               queues to be flushed, and if the terminal is the controlling terminal of a foreground process group, it will cause a SIG‐
               INT to be sent to this foreground process group.  When neither IGNBRK nor BRKINT are set, a BREAK reads as  a  null  byte
               ('\0'), except when PARMRK is set, in which case it reads as the sequence \377 \0 \0.
    

    相关部分是 '当 IGNBRK 和 BRKINT 均未设置时,BREAK 读取为空字节 ('\0')

    所以一切都按预期进行。

    或许构建一个termios结构来设置各种重要标志?

    【讨论】:

    • 小心,termios 结构不是 0,而是指向 termios 结构的指针是 0。这并不意味着 IGNBRK 或 BRKINT 未设置,这意味着它们未定义为参数。当它们未定义为参数时,当 termios 为空时,子进程应该继承父进程的设置。我已经通过使用 tcgetattr() 验证了这种情况。此外,请记住 bash 是 forkpty 调用的子进程,它确实响应中断。忽略它们的是 bash 的子代。
    • 但只是为了确保我创建了一个默认设置的 termios 结构,并且 IGNBRK 和 BRKINT 设置正确。相同的行为。我相当有信心 shell 本身正在产生中断,但是正在启动孩子以忽略这些中断。
    • 谢谢,我想知道它是否是 forkpty 和 execve 的组合?调查一下。
    • 如果你删除 '-i' 参数到 bash 会有什么不同吗? '-i/interactive' 标志改变了 bash 处理多个信号的方式,包括 SIGINT。实际上,您可以尝试不同的可执行文件吗?我倾向于 bash 改变它的环境,直到那时 forkpty 工作正常
    • 抱歉,没有。我已经尝试过 -i 和 -l 的所有组合(都打开,都关闭,并且在没有另一个的情况下每个都打开),没有区别。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    • 1970-01-01
    • 2020-05-02
    相关资源
    最近更新 更多