Table of Contents

launchd

Background

Mac OS X provides two methods for launching daemons: startup items and launchd(8) daemons. Which one you use depends largely on the versions of Mac OS X that the daemon must support.

Creating a launchd job

  1. review the External Links below to get a better understanding of how launchd and launchctl work
  2. open Property List Editor (included in Developer Tools) or use a text editor to create files like the examples below
  3. save the file with a namespaced filename, such as com.example.MyApp.plist
    • if you edit the file in a text editor and launchctl complains later, you can check the file for errors with
      plutil -lint <path to your plist file>
  4. decide how you want the job to run
    • ~/Library/LaunchAgents/ - will run when user logs in, as that user (UserName key is ignored in plist file)
    • /Library/LaunchAgents/ - will run when any user logs in, as that user (UserName key is ignored in plist file)
    • /Library/LaunchDaemons/ - will run when system starts, as root; file permissions need to be 644, owned as root
  5. the job will start when your computer is restarted or if you log out and back in, depending on where you placed the file. To start the job now, run this:
    launchctl load <path to your plist file>
    • if you get a “nothing found to load” message, use the -w parameter:
      launchctl load -w <path to your plist file>
  6. to stop the job, run this:
    launchctl unload <path to your plist file>
  7. if the job needs to run as root, use sudo before the commands
  8. you can start an interactive session by running launchctl. If you do this with sudo, it will be the root launchd session; otherwise it will only be for your user

Example: Apache2

Since the apachectl program spawns a daemon and doesn't stay open, we need launchd to work with a script that will monitor the Apache server and kickstart it appropriately when necessary.

/usr/local/apache2/bin/launchd_apache.sh

#!/bin/sh
/usr/local/apache2/bin/apachectl graceful
 
sleeptime=40
 
httpdArray=(`ps -U www | grep httpd | awk '{print $1}'`);
let httpdCount=${#httpdArray[*]};
 
while (($httpdCount > 0))
do  
    sleep $sleeptime;
    hpptdArray=(`ps -U www | grep httpd | awk '{print $1}'`);
    let httpdCount=${#httpdArray[*]};
done
 
echo "Apache Stopped, restarting..."

/Library/LaunchDaemons/local.apache2.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>GroupName</key>
    <string>admin</string>
    <key>Label</key>
    <string>Apache2</string>
    <key>KeepAlive</key>
    <false/>
    <key>Program</key>
    <string>/usr/local/apache2/bin/launchd_apache.sh</string>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceDescription</key>
    <string>Launches the Apache2 httpd web server</string>
    <key>UserName</key>
    <string>root</string>
</dict>
</plist>

Example: MySQL

/Library/LaunchDaemons/local.mysql.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>Label</key>
    <string>MySQL</string>
    <key>UserName</key>
    <string>root</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/mysql/bin/mysqld_safe</string>
      <string>--user=mysql</string>
    </array>
    <key>WorkingDirectory</key>
    <string>/usr/local/mysql</string>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

Example: Postgres

/Library/LaunchDaemons/local.postgres.plist

<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd";>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>Postgres</string>
    <key>Disabled</key>
    <false/>
    <key>UserName</key>
    <string>postgres</string>
    <key>GroupName</key>
    <string>postgres</string>
    <key>Program</key>
    <string>/usr/local/pgsql/bin/postgres</string>
    <key>StandardOutPath</key>
    <string>/usr/local/pgsql/log/postgres.log</string>
    <key>StandardErrorPath</key>
    <string>/usr/local/pgsql/log/postgres.log</string>
    <key>EnvironmentVariables</key>
    <dict>
    <key>PGDATA</key>
    <string>/usr/local/pgsql/data/</string>
    </dict>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

GUI's