launchdをcronの代わりに使うための簡易メモ

launchdとは?

プロセスの定期実行管理でLinuxUnixユーザに馴染み深いcronだが,MacOS X 10.6では特に設定しない限り,デーモンすら起動していない.そこで定期実行を担っているのがlaunchdである.しかしlaunchdは何もyet another cronという訳ではない.launchdはUnix系OSで一番最初に起動するプロセスであるinitを置き換える形で10.3 Tigerで登場し,initよりも広範なプロセス管理をシンプルに管理することが出来る.
cron的役割という意味では,cron同様の定期実行に加え,kqueue(2)を利用して,ファイルの変更やシグナルの着信,プロセスの起動や終了など多彩なイベントを監視してプロセスを起動出来る.ならばこれを利用しない手はない,以前はLingonという便利なGUIインターフェイスがあったようだが,有料*1になってしまった・・ということでlaunchdをcron代わりに使うのに最低限必要な知識をまとめてみる.

launchdのファイル構成

launchdの設定は,以下のディレクトリ下にlaunchd.plist形式のXMLファイルを置くことで行う.

~/Library/LaunchAgents
ユーザが提供するユーザごとのエージェント*2を設定する.
/Library/LaunchAgents
管理者が提供するユーザごとのエージェントを設定する.
/Library/LaunchDaemons
管理者が提供するシステム全体のデーモン*3を設定する.
/System/Library/LaunchAgents
MacOSが提供するユーザごとのエージェントを設定する.
/System/Library/LaunchDaemons
管理者が提供するシステム全体のデーモンを設定する.

LaunchDaemonsで設定されたサービスはシステム起動時にroot権限で起動されるPID 1のlaunchdによって処理され, LaunchAgentsで設定されたサービスは,各ユーザのログイン時に各ユーザの環境・権限で起動されるlaunchdによって処理される.
大変シンプルな構成なので,自分の管理したいプロセスによってどこにファイルを置いて設定すればよいか,すぐに分かる.

必要最低限の.plist(プロパティリスト)の知識

MacOS上でプログラム内のオブジェクトをファイルとして保存するために定義されたファイル形式.Cocoaフレームワークの文字列や連想配列といった基本データクラスと対応しているため,型にストリクト.
それを念頭に置いて実際のファイルを見れば,大体雰囲気がわかる.以下はMobileMeの同期を一時間毎に実行するもの.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.apple.MobileMeSyncClientAgent</string>
	<key>LimitLoadToSessionType</key>
	<string>Aqua</string>
	<key>ProgramArguments</key>
	<array>
		<string>/System/Library/PrivateFrameworks/DotMacSyncManager.framework/Resources/mobilemesyncclient</string>
		<string>--sync</string>
		<string>--periodic</string>
	</array>
	<key>StartInterval</key>
	<integer>3600</integer>
</dict>
</plist>

タグの中に,連想配列に当たるタグでキーとその値を順に書き連ねていけば良い.

launchd.plistのキー

まず,以下のキーが必須

key value
Label 管理するジョブの名前.ファイル名から拡張子を抜いたものにするのが一般的のよう.
ProgramingArguments 実行するプロセスの宣言.execvp(3)の第二引数に渡される文字列の配列.要は,タグの中に,実行したいコマンドをスペースで区切って前から順番にタグで括って入れていけば良い.

起動のタイミングを以下のキーで設定できる.

key value
StartInterval 起動間隔を秒数で指定
WatchPaths リスト内のパスに変更があった場合に起動する.(※パス内の半角スペースを\でエスケープする必要は無い)

また,crontab愛好家のためにStartCalendarIntervalというKeyも用意されている

00 10  *  *  1 echo hoge

のようにしたければ,

<key>ProgramArguments</key>
<array>
  <string>echo</string>
  <string>hoge</string>
</array>
<key>StartCalendarInterval</key>
<array>
  <dict>
    <key>Minute</key>
    <integer>0</integer>
    <key>Hour</key>
    <integer>10</integer>
    <key>Weekday</key>
    <integer>1</integer>
  </dict>
</array>

指定しない日付キーはワイルドカードとして扱われる.
その他ソケットを見たり,継続的に起動させたりする,様々なkeyがあるので,詳しくはマニュアルを参照されたし.

XMLを直接編集するのが面倒であれば,Property List Editorを利用するのも手だろう.

*1:たかが4.99$ですw

*2:各ユーザ単位で起動されるサービス

*3:システム全体で一つだけ起動されるサービス