sticky bit

/tmpのように誰にでも読み書きを許したいけど、勝手に消されては困るというディレクトリを実現するために、UNIXではsticky bitを使う。lsして、パーミッションの最後の"t"がsticky bit。

$ ls -l / | grep tmp
drwxrwxrwt   28 root root  4096 Jun  9 14:26 tmp

ちなみに、MacOS Xでは共有フォルダとして利用する(?)/Users/Sharedにsticky bitが立っている。

Plan9にも/tmpはあるが、stikcy bitのようないかにも取ってつけたような機能は使っていない。$HOME/tmpを/tmpにbindしている。-cオプションは、ファイルの生成を許可するという意味
*1

term% ns | grep tmp
bind -c /usr/oraccha/tmp /tmp

余談だけど、UNIXの部屋によると、

昔の UNIX の sticky bit というのは、実行ファイルに対して設定するものであった。頻繁に使用するプログラムについてこのビットを立てておくと、常にメモリ上にバイナリを保存しておく効果があった。しかし今では仮想記憶の発達により、意味をなさなくなったので、ファイルに対してこのビットを立てても無視される。「sticky」は「貼り付けておく」という意味であるが、現在では「sticky」という意味はなく、名前だけが残っているわけである。

だとか。へぇ。

(2011-06-20)Lions本読書会でsticky bitの話題が出たので、歴史を少し調べてみた。WikipediaNetBSDのman sticky(8)の記述が違うけど、V6のman chmod(1)にsticky bitの説明があることから、Wikipediaの説を信じることにする。sticky bitの出現はV5にさかのぼるようだ。コアメモリから二次記憶にスワップアウトしたテキストを、プロセス終了時に消去せず、再利用するために導入された。これがオリジナルの意味だが、その後、いろんな拡張がなされて、紆余曲折の末、現在はディレクトリをappend onlyにするという意味で使われている。

スワップからのロードと、ファイルシステム経由のロードにどれくらいの速度差があったのか、よくわからないが、シェルやエディタなど、頻繁に使われるプログラムにsticky bitが立てられた。しかし、副作用もあって、一度スワップに書き出されたものは、削除されなくなるので、プログラムを変更したいときに面倒な手数をかける必要があった。まず対象実行ファイルのsticky bitを落として、プロセスを起動、終了してスワップ上のテキストを削除し、改めてsticky bitを立てて、プロセスを実行する必要があった。

このようにsticky bitは通常ファイルを対象にしていたが、4.3BSDでディレクトリに対してsticky bitを立てるとappend onlyになるという仕組みが導入された。これは本文でも書いたとおり、現在も大半のUNIXで使われている。

まぁ、こんな面倒くさい仕組みもデマンドページングとバッファキャッシュがあれば不要になるので、自然と淘汰されていったが、その空き地に目を付けてハックした開発者がときたま現れる。SunOS 4.xではNFS環境などでバッファキャッシュを介さず、直接I/Oを実行する意味で使われ、組込みLinuxではcramfs上でXIP(eXecution In Place)対応するために、非圧縮格納するファイルを指定するために使われた。個人的にはsticky bitなど使わず拡張ファイル属性を使う方がよいと思うのだが。。。

あと、@kojiandoさんに教えてもらったfjの議論(sticky bit for /tmp)も興味深い。

*1:bindについてはbind遊びあたりを見て。