Help us understand the problem. What is going on with this article?

macOSの$TMPDIR以下のファイルが部分的に削除された理由

MacOSX El Capitan(10.11)で起きたトラブルです(2020-06-06追記: Mojave(10.14)でも状況は同じです)。

某OSSのtar ballを$TMPDIR以下に展開してビルドしていたのですが、なぜか展開後のファイルのうち一部のファイルだけ1日後に消える事件が発生しました。

消されるファイルのうちinstall-shconfigureで必要なファイルなので、昨日作業したディレクトリで今日も./configureしようと思ったら次のようにエラーで怒られてしまいます。

$ ./configure
checking for grep that handles long lines and -e... /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking for a sed that does not truncate output... /usr/local/bin/gsed
configure: error: cannot find install-sh, install.sh, or shtool in "." "./.." "./../.."

手元の環境の$TMPDIRは次のようにランダム文字列を含むディレクトリになっていました。

$ echo $TMPDIR
/var/folders/_0/lkp460qj0j1ftylt6w_3mjxr0000gn/T/

犯人はperiodicか?

調べてみると近い話題で苦しんでいる人が見つかります。

macOS上でJenkinsのファイルが消えてしまうトラブルがあり、periodicで起動される日次バッチが悪さをしているのでは?という内容です。

しかし、日次のファイル消去スクリプト /etc/periodic/daily/110.clean-tmps/tmp 以下が対象で、今回話題にしている /var/folders 以下を消すようには見えません。また、このスクリプトが消したファイルが/var/log/daily.outに出力されるはずですが、該当ファイルを消した記録は見当たりませんでした。

というわけでperiodicが犯人ではないようです。

毎晩3時35分にdirhelperがファイルを消している

dtraceを有効にしてfbt::VNOP_REMOVE:entryを監視してみたところ、毎日3時35分に$TMPDIR以下のファイルを消しているdirhelperというプロセスを見つけました。

1414517           0  17049 dirhelper    VNOP_REMOVE  tests/empty.html
1414519           0  17049 dirhelper    VNOP_REMOVE  fileinfo/EXPERIMENTAL
1414530           0  17049 dirhelper    VNOP_REMOVE  pdo_oci/EXPERIMENTAL
1414531           0  17049 dirhelper    VNOP_REMOVE  bug53872/second.txt
1414535           0  17049 dirhelper    VNOP_REMOVE  skeleton/EXPERIMENTAL
1414546           0  17049 dirhelper    VNOP_REMOVE  image/blank_file.bmp
1414551           0  17049 dirhelper    VNOP_REMOVE  5.6.31/install-sh
1414552           0  17049 dirhelper    VNOP_REMOVE  5.6.31/missing
1414552           0  17049 dirhelper    VNOP_REMOVE  5.6.31/mkinstalldirs
1414552           0  17049 dirhelper    VNOP_REMOVE  cgi/php.sym
1414553           0  17049 dirhelper    VNOP_REMOVE  pi3web/php.sym
1414554           0  17049 dirhelper    VNOP_REMOVE  thttpd/stub.c
1414556           0  17049 dirhelper    VNOP_REMOVE  build/default.manifest

今回問題になったinstall-shも含め、多くのファイルが消されていることがわかります。

このdirhelperとは何者でしょうか。man dirhelperによれば、/System/Library/LaunchDaemons/com.apple.bsd.dirhelper.plistの設定で起動されている管理用コマンドのようです。このplist中に次の内容が見つかります。

    <dict>
        <key>CLEAN_FILES_OLDER_THAN_DAYS</key>
        <string>3</string>
    </dict>

3日前より古いファイルを消す設定、ということのようです。またdirhelperのソースコードを見ると、/var/folders以下の掃除をしているらしいこと、ファイルのbirthtimeとatimeの両方が指定日数より古かったらファイルを消していることがわかります。

下記URLのコメントも参考になりました。

なぜ一部のファイルだけ消えたのか

macOSでは$TMPDIR以下のファイルは寿命が3日しかないということなら設定通りであり何の問題もありませんが、なぜ一部のファイルは1日で消えてしまったのでしょうか。

これはmacOS標準のbsdtarの挙動が関係しています。bsdtarでファイルを展開するとbirthtimeはアーカイブの時刻と同じ時刻(大抵は3日前より古い)になります。また、atimeはunix epoch(1970-01-01 0時)になるようです。

つまり、tar ballをbsdtarで展開した場合、大半のファイルは展開直後からdirhelperの削除対象になるのです。夜中の3時30分にtar ballを展開したのが3時35分に勝手に消えているようだと悲惨ですね。

私の場合ビルドしていたので、ビルドに必要なファイルはコンパイラが読むためatimeが更新されて削除対象から外れたものの、問題となったinstall-shはファイルの存在チェックしか行われないためatimeが書き換わらず、dirhelperに消されてしまったというわけです。

ちなみにGNU tarを使えばファイル展開時にatimeが現在時刻になるため、展開後3日間は消されることはありません。

こんないつファイルが消されるかわからないディレクトリに居られるか!俺は出て行くぞ!

どうやらmacOSの$TMPDIR以下でOSSのビルドをしてはいけない、という身も蓋もない結論のような気がしますね。$HOME/src/以下で行うなどした方が平和なんじゃないでしょうか。

(2018-01-23追記)誰が悪いのか

この問題はdirhelperのバグと言って差し支えないでしょう。使われていないファイルを探すのにbirthtimeとatimeしか見ないというのは現実に即していません。

アーカイバ類が作るファイルが過去のbirthtimeになるのは当然の挙動です。既に指摘したようにbsdtarだとatimeもアテにならないわけで、まず見るべきはctimeでしょう。昨日展開したファイルであればctimeだけは確実に昨日の日付になるわけですから、これを見ない理由がありません。今のままだと3時30分に展開したファイルを3時35分に消されてしまう可能性さえあるので、dirhelperがctimeも見るような修正をぜひ入れて頂きたいところです。

一方で、ctimeを見ていたとしても上記の問題が完全に解決するわけではありません。configureinstall-shのファイル存在チェックしか行わないので、毎日ビルドを繰り返していたとしてもinstall-shのbirthtime・atime・ctimeのいずれも更新されず、どのみち4日後には削除される運命です。

そもそも論として、使われていないファイルだけを消すという要求自体が無茶だとも言えるでしょう。つまり、dirhelperの実装上の問題というよりは要求仕様の問題なのかもしれません。

(2020-06-06追記)最近のmacOSでも挙動は変わっていない

macOS Mojave(10.14)でも上記の挙動は変わっていませんでした。この挙動はバグだろうと私は考えていますが、Appleはそう考えていないようですね。

バグかどうかはさておき、macOSのdirhelperがファイルを消す基準とbsdtarの相性が悪いのは間違いありません。ユーザーとしては$TMPDIRの使い方に注意するしかないでしょう。

参考URL

hnw
境界値バグが大好物。自分の日記で書くには小ネタすぎるネタをQiitaに書いています。
https://hnw.hatenablog.com/
klab
モバイルオンラインゲーム、その他スマートフォン関連サービス、及びサーバーインフラ開発・運用
http://www.klab.com/jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away