Mac OS X もそれなりに使えるようになってきて、プライベートでは常用している(仕事ではまだまだだけど)。ホームディレクトリにかなりファイルがたまってきたので、バックアップ戦略をまじめに考えることにした。
僕の OS X の使い方は、一日中マシンを立ち上げっぱなしにしておいて、作業が終わったらログアウトしてスリープ、次の日に作業を始めるときはスリープから起こしてログイン、というものである。これだと、バックアップに一番適したタイミングはログアウトしてからスリープするまでの間となる。コンピュータを使っているのだからなるべく手でやる作業を減らして自動実行にしたい。ところが、調べてみるとこれが案外厄介なんですね。
最初に考えたのは「AppleScript でバックアップ作業をやって、終わったら Finder にログアウトさせる」という方法。ところが、Finder に AppleScript でログアウトコマンドを送る方法がどうしてもわからない。その上、この方法だと終了時にダイアログを出すアプリが残っているとそこでログアウトが中断されてしまう恐れがある。バックアップは長時間かかることもあるので、作業が終わった時にマシンの前に自分がいるとは限らないから。
次に考えたのは、C で「ログアウトしてからバックアップスクリプトを起動するツール」を書く、という方法。Mac OS X - System Overview ドキュメントの中の Booting and Logging In の章に、ユーザのログイン/ログアウトを管理する loginwindow というアプリケーションの解説がある。これを見ると、loginwindow に kAELogOut
アップルイベントを送るとログアウトができるようなのだが、この定数の定義がどこを探しても見つからない。それではと、loginwindow に kAEQuitAll
を送ってすべてのアプリケーションを終了させてみようと思ったが、奇妙なことに Finder が時々終了命令を拒否してくれる。時々、というのが微妙に味わい深いのだが、そんなことも言ってられない。というわけでこの方法も却下。
最終的に、loginwindow のデフォルト設定をいじってログアウト時に指定したスクリプトを実行させるようにして、そこからバックアップスクリプトを起動させることにした。具体的なやり方は後ほど。
バックアップツールは意外といろいろ選択肢があるのだが、後に説明するようにシェルスクリプトから呼び出すので、コマンドラインから実行できることが必要。
もちろん最初に試したのは hfspax。これでいけるかと思っていたんだけど、途中で「cpio header field is too small for ...」とか何とかいう意味不明のエラーが出てしまう。ditto
や CpMac
を使うという選択肢もあるのだが、ファイルを削除した時バックアップの方も削除する、という機能がなさそうなので見送り。
結局今回は psync を使うことにした。シンクロナイザなので、アーカイバが好みの僕としては次善の策なのだが、とりあえず使えそうなので、しばらくこれで運用してみる。インストール方法は psync のページに書いてある。英語だけど、この程度なら特に日本語訳も必要ないでしょう。
実際に自動バックアップを実現するための手順を示す。参考にしたのは次の資料。
defaults
コマンドのマニュアルページ。defaults
コマンドを使ったログイン・ログアウトのカスタム化についてはまだ書かれていない。
Mac OS X 関連のメーリングリストを見てていつも思うんだけど、NeXT な人の存在は大きいね。白山さんとかね。本来は Apple がドキュメントを整備しないといけないところを NeXT のパワーユーザーが補っている面はかなりあるんじゃないかな。
ログアウト時に特定のスクリプトを実行するように設定する。
sudo defaults read com.apple.loginwindow # 現在の設定を確認 sudo defaults write com.apple.loginwindow LogoutHook /usr/local/bin/LogoutHook
ついで、/usr/local/bin/LogoutHook
を作成する。すべてのユーザについて共通のスクリプトが適用されてしまうので、UNIX の慣習に従って(?)、ユーザのホームディレクトリに .logouthook
という実行ファイルがあればそれを実行する、という内容にしておいた。下の内容のファイルを作って /usr/local/bin/LogoutHook
とし、実行属性をつけておく (sudo chmod +x /usr/local/bin/LogoutHook
)。
#!/bin/sh if [ -x $HOME/.logouthook ] then (echo Logout at `date`; $HOME/.logouthook 2>&1) >>$HOME/logouthook.out fi
ホームディレクトリの logouthook.out
というファイルに出力を追加書き込みしていくので、このファイルが大きくなったら適当に対処する必要がある。今はまだ何もしてない。
以上の設定が終わったら一度再起動する。ログアウトして >exit
でいいみたいだけど、一度これで再ログイン不可能になって強制再起動する羽目になったので、Finder から手動で再起動することをとりあえずお薦めしておく。
次は自分のホームディレクトリに .logouthook
スクリプトを作成する。直接ここに作業内容を書いてもいいのだが、名前がドットで始まるファイルは Finder で見えないなど何かと扱いづらいので、$HOME/bin/backup_home
を呼び出すだけにしておき、中身は $HOME/bin/backup_home
で記述することにする。.logouthook
の中身は次の1行のみ。実行属性をつけておくのをお忘れなく。
$HOME/bin/backup_home
最後に $HOME/bin/backup_home
である。基本的には psync
をバックグラウンドで実行させるのだが、psync
は時間がかかることがあるので、もしかすると次にログインしてログアウトしたときまだ走っているかもしれない。そこで、バックグラウンドで走らせた直後にそのプロセス ID を記憶しておき、次に実行した時そのプロセスがまだ走っていたならメッセージを出してそのまま終了することにする。
#!/bin/sh if [ -f $HOME/.logouthook.pid ]; then PID=`cat $HOME/.logouthook.pid` if (ps -xa -p $PID | grep $PID >/dev/null); then echo $0 is already running. exit 1 fi fi (/usr/local/bin/psync -q $HOME /Volumes/Backup/$HOME; rm $HOME/.logouthook.pid) & echo $! >$HOME/.logouthook.pid
バックアップは Backup
なるボリューム上に作ることになる。このボリュームのルートに /Users/ユーザ名
というディレクトリが存在すると、それを上書きしてしまう。それは困る場合は9行目の /Volumes/Backup/$HOME
を適当に書き換えていただきたい。