Mac OS X comes with several daemons that provide most of the basic system services. Examples of these services include handling network lookup requests, serving web pages, monitoring hardware devices, and gathering metadata from the file system. The clients of these services may be the operating system, client applications, or both. An example of a daemon used by the system is the mds
daemon, which monitors the file system and initiates the gathering of metadata. The system gathers the metadata and puts it in a central repository, which client applications can then access.
Although the general steps for how to create a new daemon are beyond the scope of this document, there are some things that daemon writers need to understand before writing daemons for Mac OS X.
When Is a Custom Daemon Appropriate?
Launching Daemons
Most application developers will never need to create a daemon directly. Even those developers that need some sort of background server may not find a daemon to be the best choice in all cases.
Daemons run in the root context, which means they are unaware of the users logged on to the system. A daemon cannot initiate contact with a user process directly, although it can respond to requests made by user processes. Because they have no knowledge of users, daemons also have no access to the window server, and thus no ability to post a visual interface. Daemons are strictly background processes that respond to low-level requests.
If you need to provide user-specific services, you should create an agent instead of a daemon. An agent is essentially the same thing as a daemon, except that it runs in the context of a user session. Agents can communicate with other processes in the same user session and with system-wide daemons in the root context. Because they have access to the window server, agents can also post a user interface, although they should do so sparingly, if at all. Like daemons, agents should be launched automatically.
The only difference between a daemon and an agent is location: daemons are installed in /Library/LaunchDaemons
, while agents are installed in /Library/LaunchAgents
or in the LaunchAgents
subdirectory of an individual user’s Library
directory.
If you find that your code provides both user-specific and user-independent services, you might want to create both a daemon and an agent. Your daemon would run in the root context and provide the user-independent services while a copy of your agent would run in each user session. The agents would then coordinate with the daemon to provide the services to each user.
For more information about the root context and user sessions, see Multiple User Environments.
Mac OS X provides two methods for launching daemons: startup items and launchd
daemons. Which one you use depends largely on the versions of Mac OS X that the daemon must support.
Mac OS X v10.3 and earlier: You must
use startup items. The launchd
service is not supported prior to v10.4.
Mac OS X v10.4 and later: You can either use startup items or launchd
daemons. Using launchd
daemons is preferred unless you also require backwards compatibility with versions of Mac OS X prior to v10.4.
Of course, you do not necessarily have to choose one or the other. For optimal compatibility and performance, you could use both. The key is to add a command-line argument or arguments to enable or disable launchd-compliant behavior, such as launch-on-demand support.
Once you have the ability to launch your daemon in either form, you can install both a launchd
property list and a startup item. To avoid launching your daemon twice, be sure to add code to the startup item to disable it in Mac OS X v10.4 or later. For example, the following will print “10.3 or earlier” if it is running on a version of Mac OS X prior to v10.4:
Listing 1 Conditional Startup Item Execution
#!/bin/sh |
OSVERSION="$(sw_vers -productVersion)" |
MAJOR="$(echo $OSVERSION | sed 's/\..*//')" |
MINOR="$(echo $OSVERSION | sed -E 's/[0-9]+\.([0-9]+)\..*/\1/')" |
PATCH="$(echo $OSVERSION | sed -E 's/[0-9]+\.[0-9]+\.([0-9]+).*/\1/')" |
echo "MAJOR: $MAJOR" |
echo "MINOR: $MINOR" |
echo "PATCH: $PATCH" |
if [ $MAJOR -eq 10 ] ; then |
if [ $MINOR -le 3 ] ; then |
echo "10.3 or earlier"; |
fi |
fi |
For more information about shell scripting, read Shell Scripting Primer.
With the introduction of launchd
in Mac OS X v10.4, an effort was made to improve the steps needed to launch and maintain daemons. Prior to 10.4, if you wanted to launch a custom daemon, you had to create a startup item to do so. During boot up, the system would execute your startup item, allowing you to run a script that launched your daemon. Once launched, your daemon would continue running (and continue holding on to memory and resources) until the computer was shut down or restarted, the daemon was manually shut down, or the daemon itself crashed.
What launchd
does is provide a harness for launching and relaunching your daemon as needed. To client programs, the port representing your daemon’s service is always available and ready to handle requests. In reality, the daemon may or may not be running. So, when a client sends a request to the port, launchd
may have to launch the daemon so that it can handle the request. Once launched, the daemon can continue running or shut itself down to free up the memory and resources it holds. If a daemon shuts itself down, launchd
once again relaunches it as needed to process requests.
In addition to the launch-on-demand feature, launchd
provides the following benefits to daemon developers:
Simplifies the daemonization process by handling many of the standard housekeeping chores normally associated with launching a daemon.
Provides system administrators with a central place to manage daemons on the system.
Supports inetd
-style daemons.
Eliminates the primary reason for running daemons as root. Because launchd runs as root, it can create low-numbered TCP/IP listen sockets and hand them off to the daemon.
Simplifies error handling and dependency management for inter-daemon communication. Because daemons launch on demand, communication requests do not fail if the daemon is not launched. They are simply delayed until the daemon can launch and process them.
For more information on how to create a launch-on-demand daemon, see “Creating launchd Daemons and Agents.”
If your software includes a custom daemon and must support versions of Mac OS X prior to 10.4, use a startup item to launch the daemon. A startup item is a bundled shell script or executable binary that runs once when the computer first boots (see “The Boot Process”).
If you have custom startup items, you should install them in the /Library/StartupItems
directory. Apple startup items are located in the /System/Library/StartupItems
directory, although most of them have been stubbed out in Mac OS X v10.4 and later and replaced by launchd
-compliant versions. The stubbed out versions remain for the benefit of other startup items that have dependencies on them.
For information on how to create a startup item, see “Creating a Startup Item.”
© 2003, 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-11-19)