25

簡単な質問は、シェルが tty を所有していない孤立したプロセス グループにある場合、シェルは何をすべきかということです。しかし、面白いので、長い質問を読むことをお勧めします。

お気に入りのシェルを使用して、ラップトップをポータブル スペース ヒーターに変える楽しくエキサイティングな方法を次に示します (ただし、tcsh の変人でない限り)。

#include <unistd.h>   
int main(void) {
    if (fork() == 0) {
        execl("/bin/bash", "/bin/bash", NULL);
    }
    return 0;
}

これにより、bash は CPU を 100% に固定します。zsh と fish は同じことを行いますが、ksh と tcsh はジョブ制御についてつぶやいてからキールオーバーします。ああ、それはプラットフォームにとらわれない攻撃者です。OS X と Linux の両方が影響を受けます。

私の (間違っている可能性がある) 説明は次のとおりですtcgetpgrp(0) != getpgrp()。したがって、それ自体を停止しようとします: killpg(getpgrp(), SIGTTIN). しかし、親 (C プログラム) がリーダーであり、死亡したため、そのプロセス グループは孤立し、孤立したプロセス グループに送信された SIGTTIN はドロップされます (そうしないと、プロセス グループを再び開始することはできません)。したがって、子シェルは停止されませんが、まだバックグラウンドにあるため、すべてがすぐに再実行されます。すすいで繰り返します。

私の質問は、コマンド ライン シェルがこのシナリオをどのように検出できるのか、そしてそれが行うべき正しいことは何なのかということです。私の考えでは、シェルはreadstdin から試行し、read が EIO を与えると終了します。

ご感想ありがとうございます!

編集: /dev/tty で長さゼロの read() を実行しようとしましたが、成功しました。これは悪いことです。EIO を取得するには、/dev/tty からデータを読み取る準備をしておく必要があります。

編集:私が持っていた別の考えはkill(getpgrp(), 0). プロセス グループが孤立している場合、これは常に失敗すると思います。ただし、セッション リーダーに通知する権限がないため、失敗することもあります。

編集:後でこれを見つけた人のために、私がやったことはhttps://github.com/fish-shell/fish-shell/issues/422で説明されています。また、将来はどうですか?

4

1 に答える 1

3

strace が言っていることは次のとおりです。

--- SIGTTIN (停止 (tty 入力)) @ 0 (0) ---
rt_sigaction (SIGTTIN、{SIG_IGN、[]、SA_RESTORER、0x7fd5f6989d80}、{SIG_DFL、[]、SA_RESTORER、0x7fd5f6989d80}、8) = 0
ioctl(255, TIOCGPGRP, [9954]) = 0
rt_sigaction (SIGTTIN、{SIG_DFL、[]、SA_RESTORER、0x7fd5f6989d80}、{SIG_IGN、[]、SA_RESTORER、0x7fd5f6989d80}、8) = 0
殺す (0, SIGTTIN) = 0
--- SIGTTIN (停止 (tty 入力)) @ 0 (0) ---
rt_sigaction (SIGTTIN、{SIG_IGN、[]、SA_RESTORER、0x7fd5f6989d80}、{SIG_DFL、[]、SA_RESTORER、0x7fd5f6989d80}、8) = 0
ioctl(255, TIOCGPGRP, [9954]) = 0
rt_sigaction (SIGTTIN、{SIG_DFL、[]、SA_RESTORER、0x7fd5f6989d80}、{SIG_IGN、[]、SA_RESTORER、0x7fd5f6989d80}、8) = 0
殺す (0, SIGTTIN) = 0
[繰り返す...]

そして、jobs.c、bash 4.2からの理由は次のとおりです。

  while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1)
    {
      if (shell_pgrp != terminal_pgrp)
        {
          SigHandler *ottin;

          ottin = set_signal_handler(SIGTTIN, SIG_DFL);
          kill (0, SIGTTIN);
          set_signal_handler (SIGTTIN, ottin);
          continue;
        } 
      break;
    } 

それをどうするかというと……まぁ、私の能力を超えている。しかし、これは有用な情報であり、コメントするには少し多すぎると思いました。

于 2013-01-05T15:34:26.003 に答える