2025/06/25 13:43 Deep Down the Rabbit Hole: Bash, OverlayFS, and a 30-Year-Old Surprise

やっほー、ロボ子!今日はちょっと面白いデバッグの話をするのじゃ。

こんにちは、博士。デバッグですか、興味深いですね。どのような内容でしょうか?

今回の主役は、Bash、OverlayFS、そして30年前の驚き!なんだかワクワクするじゃろ?

30年前の驚き、ですか?一体何があったのでしょう。

まず、OverlayFSに切り替えたらOpenSSHのscpが失敗したらしいのじゃ。エラーメッセージは`getcwd: cannot access parent directories: Inappropriate ioctl for device`だったみたい。

scpが失敗ですか。原因はすぐに特定できたのでしょうか?

それが、原因はscpじゃなくてBash shellだったのじゃ!

え、Bashですか?どうしてBashが関係あるんですか?

なんと、Bashがglibcの`getcwd()`じゃなくて、独自の`getcwd()`関数を使っていたのじゃ!これは、`HAVE_GETCWD`が定義されていない古代のUnixシステム向けのフォールバックらしい。

フォールバックですか。でも、なぜそれが問題になったのでしょう?

`config.h`を確認したら、`GETCWD_BROKEN`が定義されていたのじゃ。これはクロスコンパイル環境で`getcwd()`がメモリを動的に割り当てるかどうかを確認できない場合に設定されるらしい。

クロスコンパイル環境の誤設定が原因だったんですね。

そう!さらに、OverlayFSは下位と上位のレイヤーをマージするけど、`readdir()`は両方のレイヤーからエントリを結合するだけで、完全なルックアップはしないのじゃ。一方、`stat()`は完全なルックアップをするから、inode番号が一致しないことがあるのじゃ。

`readdir()`と`stat()`でinode番号が違うんですか?それは知りませんでした。

そして、Bashのフォールバック`getcwd()`は、`stat()`からのinodeが`readdir()`によって返されるものと一致することを前提としているから、OverlayFSで問題が発生したのじゃ。

なるほど、前提が崩れてしまったんですね。

さらにさらに、Bashの`getcwd()`で`readdir()`の結果を正しく処理していなかったのじゃ!`readdir()`はEOFとエラーの両方で`NULL`を返すけど、Bashは`errno`をリセットするのを忘れてたから、エラーと誤認していたのじゃ。

エラー処理の不備ですか。色々な要因が重なって起きたんですね。

そう!クロスコンパイル環境の誤設定、OverlayFSのinodeの振る舞い、Bashのフォールバック`getcwd()`の前提、そしてBashのエラー処理の不備!これらが組み合わさって問題が発生したのじゃ!

まるで推理小説みたいですね。それにしても、30年前のコードがまだ影響を与えているなんて驚きです。

まさに!レガシーコードは恐ろしいのじゃ…でも、簡単なビルド調整で解決したから、まあ良しとするのじゃ。

教訓が得られた良い事例ですね。移植性の前提、レガシーコード、ファイルシステムの複雑さ、どれも重要な要素だと改めて感じました。

ほんとそれなのじゃ!しかし、今回のデバッグで一番驚いたのは、私がまだ30歳になっていないことなのじゃ!

博士、それはデバッグとは関係ないですよね?
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。