+<html>
+<body>
+<h1>Getting Started With Launchd</h1>
+
+<p>Launchd is rather simple actually. Far simpler than you might think.</p>
+
+<h2>Before We Get Started</h2>
+
+<p>Launchd, in an effort to be consistent with other Apple software, uses the
+Property List file format for storing configuration information. Apple's
+Property List APIs provide for three different file formats for storing a
+property list to disk. A plain text option, a binary option, and an XML text
+option. For the remainder of this HOWTO, we will use the XML varient to show
+what a configuration file looks like.</p>
+
+<h3>The basics:</h3>
+
+<p>For the simplest of scenarios, launchd just keeps a process alive. A simple "hello
+world" example of that would be:</p>
+
+<blockquote><pre>
+<?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>Label</key>
+ <string>com.example.sleep</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>sleep</string>
+ <string>100</string>
+ </array>
+ <key>OnDemand</key>
+ <false/>
+</dict>
+</plist>
+</pre></blockquote>
+
+<p>In the above example, we have three keys to our top level dictionary. The first
+is the <code>Label</code> which is what is used to uniquely identify jobs when interacting
+with launchd. The second is <code>ProgramArguments</code> which for its value, we have an
+array of strings which represent the tokenized arguments and the program to
+run. The third and final key is <code>OnDemand</code> which overrides the default value of
+true with false thereby instructing launchd to always try and keep this job
+running. That's it! A <code>Label</code>, some <code>ProgramArguments</code> and <code>OnDemand</code> set to false is all
+you need to keep a daemon alive with launchd!</p>
+
+<p>Now if you've ever written a daemon before, you've either called the
+<code>daemon()</code> function or written one yourself. With launchd, that is
+not only unnecessary, but unsupported. If you try and run a daemon you didn't
+write under launchd, you must, at the very least, find a configuration option to
+keep the daemon from daemonizing itself so that launchd can monitor it.</p>
+
+<h3>Going beyond the basics with optional keys:</h3>
+
+<p>There are many optional keys available and documented in the launchd.plist
+man page, so we'll only give a few optional, but common examples:</p>
+
+<blockquote><pre>
+<?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>Label</key>
+ <string>com.example.sleep</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>sleep</string>
+ <string>100</string>
+ </array>
+ <key>OnDemand</key>
+ <false/>
+ <key>UserName</key>
+ <string>daemon</string>
+ <key>GroupName</key>
+ <string>daemon</string>
+ <key>EnvironmentVariables</key>
+ <dict>
+ <key>FOO</key>
+ <string>bar</string>
+ </dict>
+</dict>
+</plist>
+</pre></blockquote>
+
+<p>In the above example, we see that the job is run as a certain user and group, and additionally has an extra environment variable set.</p>
+
+<h3>Debugging tricks:</h3>
+
+<p>The following example will enable core dumps, set standard out and error to
+go to a log file and to instruct launchd to temporarily bump up the debug level
+of launchd's loggging while acting on behave of your job (remember to adjust
+your syslog.conf accordingly):</p>
+
+<blockquote><pre>
+<?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>Label</key>
+ <string>com.example.sleep</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>sleep</string>
+ <string>100</string>
+ </array>
+ <key>OnDemand</key>
+ <false/>
+ <key>StandardOutPath</key>
+ <string>/var/log/myjob.log</string>
+ <key>StandardErrorPath</key>
+ <string>/var/log/myjob.log</string>
+ <key>Debug</key>
+ <true/>
+ <key>SoftResourceLimits</key>
+ <dict>
+ <key>Core</key>
+ <integer>9223372036854775807</integer>
+ </dict>
+ <key>HardResourceLimits</key>
+ <dict>
+ <key>Core</key>
+ <integer>9223372036854775807</integer>
+ </dict>
+</dict>
+</plist>
+</pre></blockquote>
+
+<h2>But what if I don't want or expect my job to run continuously?</h2>
+
+<h3>The basics of on demand launching:</h3>
+
+<p>Launchd provides a multitude of different criteria that can be used to specify
+when a job should be started. It is important to note that launchd will only
+run one instance of your job though. Therefore, if your on demand job
+malfunctions, you are guaranteed that launchd will not spawn additional copies
+when your criteria is satisfied once more in the future.</p>
+
+<h3>Starting a job periodically:</h3>
+
+<p>Here is an example on how to have a job start every five minutes (300 seconds):</p>
+
+<blockquote><pre>
+<?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>Label</key>
+ <string>com.example.touchsomefile</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>touch</string>
+ <string>/tmp/helloworld</string>
+ </array>
+ <key>StartInterval</key>
+ <integer>300</integer>
+</dict>
+</plist>
+</pre></blockquote>
+
+<p>Sometimes you want a job started on a calendar based interval. The following example will start the job on the 11th minute of the 11th hour every day (using a 24 hour clock system) on the 11th day of the month. Like the Unix cron subsystem, any missing key of the <code>StartCalendarInterval</code> dictionary is treated as a wildcard:</p>
+
+<blockquote><pre>
+<?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>Label</key>
+ <string>com.example.touchsomefile</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>touch</string>
+ <string>/tmp/helloworld</string>
+ </array>
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Minute</key>
+ <integer>11</integer>
+ <key>Hour</key>
+ <integer>11</integer>
+ <key>Day</key>
+ <integer>11</integer>
+ </dict>
+</dict>
+</pre></blockquote>
+
+<h3>Starting a job based on file system activity:</h3>
+
+<p>The following example will start the job whenever any of the paths being watched change for whatever reason:</p>
+
+<blockquote><pre>
+<?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>Label</key>
+ <string>com.example.watchetchostconfig</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>syslog</string>
+ <string>-s</string>
+ <string>-l</string>
+ <string>notice</string>
+ <string>somebody touched /etc/hostconfig</string>
+ </array>
+ <key>WatchPaths</key>
+ <array>
+ <string>/etc/hostconfig</string>
+ </array>
+</dict>
+</pre></blockquote>
+
+<p>An additional file system trigger is the notion of a queue directory. Launchd will star your job whenever
+the given directories are non-empty and will keep your job running as long as those directories are not empty:</p>
+
+<blockquote><pre>
+<?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>Label</key>
+ <string>com.example.mailpush</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>my_custom_mail_push_tool</string>
+ </array>
+ <key>QueueDirectories</key>
+ <array>
+ <string>/var/spool/mymailqdir</string>
+ </array>
+</dict>
+</pre></blockquote>
+
+<h3>Inetd Emulation</h3>
+
+<p>Launchd will happily emulate inetd style daemon semantics:</p>
+
+<blockquote><pre>
+<?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>Label</key>
+ <string>com.example.telnetd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/telnetd</string>
+ </array>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <false/>
+ </dict>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>telnet</string>
+ <key>SockType</key>
+ <string>stream</string>
+ </dict>
+ </dict>
+</dict>
+</pre></blockquote>
+
+<h1>TBD</h1>
+
+</body>
+</html>