理系学生日記

おまえはいつまで学生気分なのか

忍者TOOLS

Mac の launchd による定期実行

Linux などでは、(ユーザではなくという意味で)システム側からのプロセス起動という意味では、init、cron、(x?)inetd、rc.d などというように、いくつかタイプがある。当然、それぞれのコンフィグは異なる場所に配置されるし、そのフォーマットも非互換です。それぞれのプロセスを学ぶにはそれなりの学習コストがかかり、その学習コストを支払い終えるまで、その設定はセキュリティリスクにすらさらされます。launchd は、このような状況を改善するために、システム起動用の統一化されたインターフェイスを提供するために、生まれたのだと理解しています。

で、今日ちょっと cron ジョブを追加する必要に迫られたのですが、Mac においては上述の通り、時刻起動のジョブについても cron ではなく launchd を使うことが「preferred」です。というわけで launchd で時刻定期実行ジョブを作ることにしました。

ちなみに、cron による時刻起動と launchd による時刻起動の大きな違いは以下の 2 つです。

  • launchd の設定ファイルはシステム毎(あるいはユーザ毎)ではなくジョブ毎。そのため、ジョブの追加/削除が他ジョブに影響を与えない。
  • 指定時刻にコンピュータがスリープあるいはシャットダウンされていた場合、launchd は当該ジョブを次のシステム起動時に実行する。その意味で、cron というよりは anacron に近い。

Sample

ここでは、port selfupdate を launchd にて実現してみます。
ファイル名は、com.kiririmode.port.selfupdate としました。launchd 用の plist は慣習として、

あとは、launchd.plist の規則に従って、設定をしていくだけです。定期実行の場合、その実行時刻の設定は、StartCalendarInterval を使えます。設定項目は、cron と代わるところがないため、迷う必要もないかと思います。

<?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.kiririmode.port.selfupdate</string>
    <key>UserName</key>
    <string>root</string>
    <key>ProgramArguments</key>    <array>
      <string>/opt/local/bin/port</string>
      <string>selfupdate</string>    </array>
    <key>StartCalendarInterval</key>
    <dict>
      <key>Hour</key>
      <integer>01</integer>
      <key>Minute</key>
      <integer>00</integer>
    </dict>
    <key>EnvironmentVariables</key>
    <dict>
      <key>HOME</key>
      <string>/var/tmp</string>
    </dict>
  </dict>
</plist>

反映は launchctl で。

$ sudo launchctl unload /Library/LaunchAgents/com.kiririmode.port.selfupdate.plist
$ sudo launchctl load /Library/LaunchAgents/com.kiririmode.port.selfupdate.plist

よくよく考えてみると、/etc/periodic/daily にスクリプトを追いとけば良かったんじゃね?という話ではある。

*1:あくまで慣習