標準愚痴出力

個人的なIT作業ログです。もしかしたら一般的に参考になることが書いているかもしれません(弱気

NYAGOS保守ノート:OpenSSH でパスワード入力中に Ctrl-C で中断すると画面が乱れる

これな

症状

nyagos から OpenSSH を起動して、パスワードプロンプトで Ctrl-C を押下すると、nyagos に復帰してこなくなる(ように見える)。

f:id:zetamatta:20190126103235p:plain

原因

これは実は nyagos には復帰しているのだが、コンソールのモードがパスワード表示向けの状態から元に戻っていないだけである。なので、画面が更新されないが「exit」と入力すると普通に終了する。

対応

コマンドを実行した後、コンソールの出力のモードをいちいち元に戻すようにした。入力のモードについては既に対応していたので、同じような対応を出力にもするようにした。

詳しくは差分みて

余談1

このコンソールのモードを変える関数(dos.ChangeConsoleMode)の仕様は我ながらなかなかうまいこと作れていると思う

if restore,err := dos.ChangeConsoleMode(windows.Stdout, dos.ModeSet(enableVirtualTerminalProcessing)) ; err == nil {
    defer restore()
}
  • モードを元に戻す関数(クロージャ)を戻り値に変えす。一時的にモードを変えるだけなら、これを defer で戻すようにすればよい
  • モードのセット・リセットは、dos.ModeOp というインターフェイスを実装した dos.ModeSet , dos.ModeReset という型をパラメータとして0個以上渡せばよい。
  • コンソールのハンドルはいちいち自分で "$CONIN" "$CONOUT" をオープンしなければいけないと思いがちだが、実は準標準の golang.org/x/sys/windowswindows.Stdout とか windows.Stdin がそのままあるので、これを使った方が早い。

余談2

なぜ、Ctrl-C で OpenSSH を中断すると、コンソールのモードを元に戻してくれないのか? beepcap さんによると、CMD.EXE や PowerShell 上では同症状は発生しなかったそうだ。

可能性としては以下の2説がある。

  • CMD.EXE や PowerShell はコマンド実行ごとにいちいちコンソールモードをリセットしている
  • Ctrl-C をキャッチした時の子プロセスの殺し方がまずい(SIGKILL相当)ので、OpenSSH が SIGINT 扱いでハンドルできない

nyagos の Ctrl-C の扱いについては、最近(go-tty導入前後)になってからうまく処理できなくなったので、 "os/exec".Run を参考にして最近実装しなおしたのだが…見直しが必要かもしれない。

Ctrl-C の取扱については、現在のように Go言語の "os/signal" の関数を使うほか、Windows のそれ用の API SetConsoleCtrlHandlerがある。 おいおいと調べなくては…