Mac OSにおける、initや/etc/rcやcronの代わりであるlaunchdの使い方

Mac OSUNIXベースですが、デーモンの起動や管理にはRunCommandを使わなくなっています。
OS X 10.4(Tiger)から、UNIXのPID 1のプロセスはinitでしたが、それに代わって launchd が導入されました。
OS X 10.5(Leopard)では、一応残っていた /etc/rc が無くなりました。
起動時にデーモンを立ち上げたり、デーモンのコントロールに /etc/rc が使えないので、launchd の仕組みを調べてみました。

概要

間違いがあるかもというか、誤解を招くかもしれないけど、ざっくりと。

  • launchd は init の代わりにPID 1で最初に起動して、初期化やシェルの起動を行う。
  • /etc/rc は無くなったけど一部残ってる /etc/rc.common などのrcスクリプトを実行する。
  • /etc/rc のrcスクリプトの代わりに launchd.plist を使う。
  • cron の代わりに時刻をトリガーにしたプロセスの起動をする。
  • inetd/xinetd の代わりにネットワークのポートを監視して、プロセスの起動を行う。
  • ファイルやフォルダを監視し、ファイルの追加や更新をトリガーにして、プロセスの起動を行う。

環境

Mac Mac OS X 10.5.8(Leopard

デーモンをサービスとして登録する

rcスクリプトの代わりにXMLで記述する launchd.plist を作ります。

$ ls -al /Library/LaunchDaemons/
total 40
drwxr-xr-x   7 root  wheel   238  6 21 07:07 .
drwxrwxr-t+ 57 root  admin  1938 12  8  2009 ..
-rw-r--r--  1 root  wheel  694  5 29  2009 de.jinx.SmartSleepDaemon.plist
-rw-r--r--  1 root  wheel  412  6 21 03:13 kanonji.gnump3d.plist
lrwxr-xr-x  1 root  wheel   66 10 22  2009 org.freedesktop.dbus-system.plist -> /opt/local/Library/LaunchDaemons/org.freedesktop.dbus-system.plist
-rw-r--r--  1 root  wheel  474  5 26  2008 org.pqrs.KeyRemap4MacBook.load.plist
-rw-r--r--  1 root  wheel  470  5 25  2008 org.pqrs.PCKeyboardHack.load.plist

置き場所はここです。
/Library/LaunchDaemons/ は root:wheel 所有なので、ここにファイルを作る時は sudo します。

$ less kanonji.gnump3d.plist
<?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>KeepAlive</key>
        <true/>
        <key>Label</key>
        <string>kanonji.gnump3d</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/bin/gnump3d</string>
                <string>--fast</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
</dict>
</plist>

最近インストールした GNUMP3d 用の launchd.plist を作ったので、例にしてみます。

key 説明 必須
Label launchd のジョブの名前。ユニークな名前を付ける。必須か慣例か分からないけど、ファイル名もこのLabelに.plistという拡張子を付けたものにする。 必須
ProgramArguments 実行するプログラムとオプションや引数を、例の通りarrayノードに入れ子で書く。 必須
KeepAlive trueなら常に起動するようにlaunchdががんばる。起動したプロセスをkillしてもすぐ立ち上げなおされる。bool型以外にdictionary型で細かい指定が可能らしい。 falseがデフォルト値
RunAtLoad true なら launchd に launchd.plist がロードされたタイミングで起動する。 不明


この設定で、OSを起動したら /usr/bin/gnump3d --fast が呼ばれて起動します。
KeepAlive true なら、プロセスが落ちても立ち上げなおしてくれるみたいです。

$ launchctl load /Library/LaunchDaemons/kanonji.gnump3d.plist

launchd.plist を書いたら、launchd のCUIツールである launchctl でロードします。
RunAtLoad があるので、ロードしたら gnump3d が起動しました。
ちなみに、RunAtLoad true は一応書いたけど、もしかすると KeepAlive true なら不要かもしれない。
KeepAlive true だけで launchd.plist をロードしても、gnump3d は起動してました。
OS起動時はどうなるかはまだ未確認です。

launchd.plistを書くGUIツール

Lingon - Peter Borg Apps

launchd.plist はXMLで、更にkeyノードの次にそのノードに対応した値ノードが来るという、ちょっと変わった文法なので、あまり手で書きたくはありません。
オープンソースで Lingon.app というツールがあるので、これを使います。
ただ、更新が2008年で止まってるので、Lingonで作った launchd.plist を一部修正して使います。
具体的には、指定して無いのに WatchPaths というキーと QueueDirectories というキーが指定されているってだけなんですけど。
値ノードが空なので、たぶん問題は無いと思うけど一応その2つは vi で消しました。

上から順に、(1)で Label を書いて、(2)で ProgramArguments を書いて、(3)で KeepAlive と RunAtLoad を含むいくつかのキーが設定できるだけって感じです。

新しい設定を作る時、最初にタイプを選ぶダイアログがでます。
この説明は次で。

Daemon と Agent

Daemon
システムの一部としてバックグラウンドで動作するプロセス。特定のユーザーと結びついていない。GUIが持てない。
Agent
特定のユーザー用のバックグラウンドプロセス。GUIが持てる。

ざっくりと言えばこんな感じです。

~/Library/LaunchAgents/ My Agents ホームディレクトリ内なので、自分用のエージェント
/Library/LaunchAgents/ Users Agents ユーザで共有のエージェント
/Library/LaunchDaemons/ Users Daemons デーモン


Lingon のダイアログで、3つのタイプがありましたが launchd.plist の置き場所によって変わります。
gnump3d は名前の最後に d がある様に、デーモンなので /Library/LaunchDaemons/ に設置しました。

/System/Library/LaunchAgents/ と /System/Library/LaunchDaemons/

Lingon の左側にも SYSTEM AGENTS と SYSTEM DAEMONS とあります。
これはたぶん、OS X のシステムの設定と思われるので、ユーザーが追加したり変更したりというのは、基本的に必要ないと思います。
ここにあるという事を覚えておけば、トラブル時に解決の糸口を探れるかもしれません。

launchctlの使い方

$ launchctl list
PID	Status	Label
3440	-	0x112230.launchctl
3388	-	[0x0-0x166166].org.lingon.Lingon
2597	-	0x112950.bash
2596	-	0x112860.login
2533	-	0x111390.bash
2532	-	0x111ae0.login
592	-	[0x0-0x42042].org.mozilla.thunderbird
574	-	[0x0-0x3f03f].com.apple.AppleSpell
中略
-	1	kanonji.gnump3d
以下略

ロード済みの設定を一覧に表示します。
PID に数字が書いてあればプロセスが起動してます。
Status の意味はちょっと調べきれてません。

$ launchctl load /Library/LaunchDaemons/kanonji.gnump3d.plist
$ vi /Library/LaunchDaemons/kanonji.gnump3d.plist
$ launchctl unload /Library/LaunchDaemons/kanonji.gnump3d.plist
$ launchctl load /Library/LaunchDaemons/kanonji.gnump3d.plist

ロードとアンロードは launchd.plist を指定します。
launchd.plist を変更した場合、一旦 unload して再度 load が必要です。

$ launchctl start kanonji.gnump3d
$ launchctl stop kanonji.gnump3d

start や stop*1 はジョブラベルを指定します。

より詳しい使い方はDocumentation Archive

非推奨な手段

起動項目(SystemStarter)

/Library/StartupItemsディレクトリ入れるもので、Windowsで言うところのスタートアップの様なものだったと思います。
StartupItems も LaunchDaemons 知らなかったので、最初はこれを混同しちゃってましたが、launchd とは別の仕組みみたいです。
OS X 10.4からは起動項目に代わり、launchd の使用が推奨されています。

inetdおよびxinetdデーモン

OS X 10.4 からは launchd の使用が推奨されてます。

cron

cronについてはドキュメントが見つかりませんでした。

*1:KeepAlive true な設定をしたプロセスは stop しても直ぐ立ち上げ直されます。止めるには unload です。