トップ «前の日記 最新 次の日記»

2020-02-11 (Tu) [長年日記]

_ 建国記念日

…は月曜に移動しないんだな。

_ またメールが届かない?

今朝目が覚めた時、メールを確認したら何も来てなくて、また?? と思った。

そこで gmail から自分宛にメール送ったら届いた。大丈夫っぽいので、そのまま放置。

1時間後くらいにいくつかメール届いた。

このメールサーバ、まだ不安だなぁ。

_ assignment in conditional expression

https://ja.stackoverflow.com/questions/1961/

kernel の device driver を書く時、I/O ポートを

volatile unsigned char *port;

とか定義して、

*port = 0x12;

とか書くと思うし、

#define PORT (*port)

とか書くこともあると思う。

こういう場合、

if ((PORT = func()) == 0x12)

PORT = func();
if (PORT == 0x12)

では意味が異なってくるんだよね。 前者は I/O ポートから読まないけど、後者は読む。 書いたものがそのまま読めるだけのポートなら遅くなるだけで済むけど、 そうでなかったら、全然違う結果になってしまう。

まぁ、そんなことを気にしなきゃいけない人は極少数だから、 「分けるべし!」に異論はないんだけど、 「ほとんどのコーディング規約で許可されない」ほどのものなのか。

私は好んで使ってるなぁ。 返り値を確認しなきゃいけないことはそりゃ頻繁にあるし、 そういう場合は一時的に分けてるんだけど。

話が C じゃなくなるけど、 rubocop の default 設定が私の感性と合わないらしく、 しょっちゅう怒られるんだよね… sweat_smile

_ scp のバグに遭遇

scp で巨大なファイルを手元にコピーしたい。よくある話。

時間がかかるので、nohup 付けて & も付けて background にした。

その後、端末が落ちてしまった。

そうすると、転送が止まってしまった。scp のプロセスは生きているのに。

という話。

https://blog.ingage.jp/entry/2020/02/10/114509

↑途中まで調べられるだけ調べたので、ブログ記事にした。というのが昨日。

今日は原因を更に追求してみて、解ったので書いてみる。

まずは zsh が SIGHUP を送っているのは確からしい。

で、データの流れを図にすると、↓こんな感じ。

scp -- (PIPE) -- ssh -- (TCP) -- sshd --...
↓
ファイル

scp が fork して ssh プロセスを作り、ssh が sshd に TCP で接続し、 おそらくその向こうにも scp がいて、ファイルをこっち側の scp に送り、 scp がファイルに落とす。という感じ。

で、

  1. nohup を付けてるので、scp は SIGHUP が SIG_IGN の状態で起動する
  2. scp が ssh を起動する。この時、SIGHUP は SIG_IGN。
  3. scp は SIGHUP を自前のハンドラに設定する。
  4. いろいろやった後、転送が始まる。
  5. 端末が落ちる。
  6. zsh が scp と ssh に SIGHUP を送る。
  7. scp では自前のハンドラが呼ばれる。ssh では無視される。
  8. scp の自前ハンドラでは子プロセス (=ssh) に SIGHUP を送る。
  9. ssh はこの SIGHUP も無視する。
  10. scp は ssh が終わるのをひたすら待つ。ssh が PIPE 経由でデータを送ってるのを無視して。
  11. ssh は scp がデータを受け取ってくれるのを待つ。

こんな状態で止まってるっぽい。

ssh は、SIGHUP ハンドラを設定する時に、既に SIG_IGN だったら設定しないようになっている。 だから SIG_IGN のまま変わらない。しかし、scp は必ず自前ハンドラに設定し、SIGHUP 時に 子プロセスの終了を待つようになっている。

これは scp のバグだと思うな。SIG_IGN の場合は、ハンドラを設定するのはともかくとして、 子プロセスの終了を待っちゃいかんと思う。SIG_IGN でなくても、ハンドラ内で待つなんて、 行儀が悪い。

バグレポートは… どうしようかと思ったんだけど、 こんな症状、今までに報告がなかったとは思えないんだよね… たぶん、報告はあったけど放置してる、って状態なんじゃないかな、と。

http://bugzilla.mindrot.org/show_bug.cgi?id=2091

↑これやね。最近になってログが添付されたりして、進みそうな気配。 私の調査結果をコメントしとこ。

たぶん、最近の流行としては、disown を使うんだろうな。 そうすれば、shell の job 管理から外れて、signal が飛ばなくなる? いや、tty から飛ぶことはありそうに思うけど。

https://qiita.com/aosho235/items/24bf88462811eccbdec8

↑UART ドライバから飛ぶらしい。じゃぁ ssh の場合は関係ないね。

つまり、serial tty からの login でない限りは、

command < /dev/null >& /dev/null &
disown

で大丈夫ってことかな。


編集 パスワード変更