fsniperによる新規ファイルの自動処理

 fsniperを使用すると、監視対象のディレクトリを指定し、それらのディレクトリで新しいファイルが作成されたときにスクリプトを実行することができる。fsniperはディレクトリの監視にinotifyを利用するので、ファイルシステムで変化が起こると定義したアクションが直ちに実行される。これによりfsniperは定時実行のcronジョブより即時的で、より効率的となる。

 ディレクトリ内に作成されるファイルをその場で自動的に処理するというと、まず思い浮かぶのはインターネットからダウンロードしたファイルを何らかの基準で分類することである。実際、fsniperのWebサイトに掲載されている最初の例がこれだ。

 セキュリティ関連でもう1つの応用例が思い浮かぶ。ファイルサーバーを使ってメディアファイルのコレクションを読み取り専用で共有しているとしよう。現段階のセキュリティは、このサーバーにユーザーが新規のファイルを追加できないようにする、というものだ。fsniperを使えば、アップロード用のディレクトリを共有し、そこにアップロードされたファイルをスクリプトで読み取り専用のファイルサーバーへ自動的に転送できる。クライアントマシンに問題が生じてアップロードディレクトリにでたらめなファイルが書き込まれたとしても、fsniperから呼び出される転送スクリプトでアップロードディレクトリ内の新規ファイルを適切に管理すればよい。たとえば、ファイル名の異常やファイルタイプを確認して、でたらめなファイルを阻止し、正当なJPEGファイルだけを受け付けるようなことができる。最低限でもファイルの上書きを阻止するか、版管理システムに送って上書きするようなことは可能だろう。

 fsniperではファイルの転送にスクリプトが使われるので、ファイルプロテクションを変更する、新規ファイルをデータベースに記録する、電子メールを送信する、RSSニュースフィードを更新して関係者に新規ファイルのことをすぐ通知する、といった処理を付加できる。fsniperから実行されるスクリプトでsudoやその他の機能を利用すれば、ファイルのユーザーや所有者の変更のようなユーザー本人に許可されていないアクションを実行することもできる。

 fsniperはopenSUSE 11、Ubuntu Hardy、Fedora 9に同梱されていないが、通常の「./configure && make && sudo make install」という手順でソースからビルドできる。fsniperではファイル内のデータ種別の判定にlibmagicが利用されるため、あらかじめfile-develパッケージ(Fedora 9またはopenSUSE 11で実行する場合)かlibmagic-dev(Ubuntu Hardyで実行する場合)をインストールしておく必要がある。

 この段階でfsniperを実行すると、「設定ファイル~/.config/fsniper/configが見つからない」というエラーメッセージを出してfsniperは終了する。fsniperのtarアーカイブにサンプルの設定ファイルexample.confが含まれているので、これを参考にするとよい。この設定ファイルのフォーマットを見ると、{}文字で区切られたスコープが入れ子になっている。一番外側のスコープで監視対象(watch)が定義される。特定のwatch内の最初のスコープで定義されるのは監視対象となるディレクトリで、さらにその内側のスコープでマッチパターン(監視対象のディレクトリで何か変化が生じたときに実行されるパターン)が定義される。

 次の例(example.confファイルから抜粋)が、パターンを理解するヒントになるだろう。最初にwatchスコープが定義され、~/dropスコープで監視対象のパスが設定される。~/dropスコープの内側のimage/*スコープは、~/dropディレクトリに書き込まれて閉じられたファイルで、かつimage/で始まるMIMEタイプのファイルに対して実行される。話の見通しをよくするために、一番外側のスコープをwatchスコープ、その内側でディレクトリパスを定義するスコープをdirectoryスコープ、そして一番内側のスコープをmatchスコープと呼ぶことにする。

watch {
    # watch the ~/drop directory for new files
    ~/drop {
        # matches any mimetype beginning with image/
        image/* {
            # %% is replaced with the filename of the new file
            handler = echo found an image: %%
        }
	...
     }
}

 directoryスコープはデフォルトでは再帰的でないので、~/drop/foo内に新しいイメージファイルを作成したとすると、そのファイルに対して上記のmatchスコープは実行されない。このデフォルトを変更するには、directoryスコープの最初にrecurse = trueと設定すればよい。

 matchスコープ内のhandlerでは、matchスコープが成功したときに実行されるコマンドを定義する。上の例では、新しいイメージが見つかったとき、fsniperを開始した端末にそのパスが表示されるようにしている。fsniperは%%変数を、watchで見つかったファイルのパスに置き換えてくれる。また、%fでファイル名のみ、%dでファイルのディレクトリパスのみを表示することもできる。handler行でパスを表すこれらの特殊文字を省略した場合、どのコマンドでも最後の引数としてファイルのパスが自動的に付加される。

 上のmatchスコープでは実行するコマンドをhandlerとして定義しているが、複数のコマンドをスクリプトに記述すれば、それらをmatchスコープから呼び出すことも可能である。これで機能を設定ファイルから切り離し、より複雑なコマンドを定義したり、Perlスクリプトを使用したりすることができる。fsniperは現在の$PATH~/.config/fsniper/scriptsを付加してからmatchスコープを実行してくれるので、新規のスクリプトの追加先を~/.config/fsniper/scriptsとしている限りスクリプトの名前だけを使用し、カスタムスクリプトごとにいちいちフルパスを指定しなくて済むので手間が省ける。

 コマンドをhandler内で定義するのはなぜか。matchスコープ内に直接定義してもいいのではないか。そうしない理由は、matchスコープに対して複数のhandlerを連接的に設定できるからである。handlerの復帰コードが0の場合、fsniperはそのhandlerによってファイルの処理がすべて完了したものと見なして同じmatchスコープ内のそれ以降のhandlerを実行しない。復帰コードが2の場合、fsniperはhandlerがイベントの処理を望んでいるが、今すぐにはそれを行えないものと見なす。これはネットワークで接続されたコンピュータを扱うときに便利である。handlerが連絡を取らなければならないコンピュータが一時的にダウンしていることもあるからだ。handlerから返された値が0でも2でもない場合、fsniperはmatchブロック内の次のhandlerを実行する。こうして処理すべきファイルをきめ細かく選択するスクリプトを用意し、該当するファイルでなければスクリプトから1を返してそのファイルを次のスクリプトで処理させることができる。

 matchスコープ内ではhandlerの復帰コードによって次のhandlerを実行するかどうかが決まるので、handler行を指定する順番が意味を持つ。matchスコープも上から順番に実行される。イベントごとに1つのmatchスコープしか実行されないので、directoryスコープの先頭に一番詳細なmatchスコープを置き、一番包括的なmatchスコープを最後に置くのがよい。

 doc/doc.txtファイルに、Firefoxのダウンロードディレクトリでfsniperを使う場合の注意が書かれている。厄介なのは、ダウンロードの際にFirefoxが長さ0バイトのファイル(“file”)と、それとは別にデータを収容するためのファイル(“file.part”)を作成する点だ。ダウンロードが完了してファイルの名前が“file.part”から“file”に変更されたときだけスクリプトが実行されるようにfsniperをセットアップする必要がある。

 次の点に注意してほしい。matchスコープ内にコメントを書いたところ、fsniperが開始時にクラッシュした。コメントをmatchスコープのすぐ上に書いた場合はdirectoryスコープが正しく実行されなかった。タブでインデントしたコメントとインデントなしのコメントの両方で試したが、結局、コメントをすべて取り除いたときだけ正常に実行された。

 fsniperを使うと、ファイルが間を置かずに自動的に処理されるようにすることができる。また、その自動処理の際に、ファイルを書き込む本人が持っている権限よりも高い権限で処理を実行できる。たとえば、ファイル所有者を変更する権限を持つ特別なユーザーをファイルサーバーに作成するようなことが可能となる。いずれにしても、fsniperのディレクトリとスクリプトを準備したなら、ファイル処理はルールの問題に還元される。

Ben Martinは、10年越しでファイルシステムと取り組んできた。博士課程終了。現在、libferris、ファイルシステム、サーチソリューションを中心にコンサルタント業務を展開している。

Linux.com 原文(2008年10月17日)