The Future of Init, Part IIa: OS X SystemStarter
23 Oct '05 - 01:03 by benrAlmost 2 years ago I bought Tamarah a 15" G4 PowerBook, which shipped with Mac OS X 10.3 (aka: Panther). One of the rules I set down when we got it was that it was her system, and I'd keep my mits off of it. Since that time I've only used it for some small things when she wasn't busy, such as using iTunes to load music on our iPod and using iMovie to create the SVOSUG videos. I've never really dug around in the bowels of the OS like I'd like to. So when I started this series reguarding init replacements I had launchd in mind, but as I started digging around in OS X I learned of something else, SystemStarter.
SystemStarter isn't truely an init replacement, the old init still runs and calls rc scripts, but the bulk of the deamons a started via SystemStarter and not from init directly. I found a lot of parallels between launchd and SystemStarter making it fairly obvious that Apple has been working toward something, and SystemStarter was the begining, but didn't go far enough; just a part of the evolution. With all this in mind, I feel compelled to break the OS X portion of our init discussion into two parts: In this part (2a) we'll look at SystemStarter, and then in the next chapter of our story (2b) we'll look at launchd where you'll see some of these paralells I'm talking about.
Under the nifty Aqua desktop interfaces lies Darwin, OS X's BSD core. As such, rather than using a pile of /etc/init.d or /etc/rc.X/ scripts like we have on SysV, a small handful of rc scripts are found in /etc. Particularly:
- /etc/rc: Primary system startup script, executed at system startup when init is started by the kernel. Does basic system configuration and then calls SystemStarter to bring up everything else; in Tiger it then starts launchd.
- /etc/rc.common: Contains various Borne Shell functions used by /etc/rc and /etc/rc.netboot.
- /etc/rc.netboot: Executed to configure netboot (beyond the scope of this discussion)
- /etc/rc.shutdown: Executed when system is told to shutdown, if /etc/rc.shutdown.local doesn't exist, SystemStarter is told to stop.
OS X introduced SystemStarter. Rather than have /etc/rc start your daemons and services SystemStarter was called and it handled the job. On the backend is a directory structure with entries for each service (found in /System/Library/StartupItems) that contained at least two files: one is an XML file that contains a service description (a Property List, or plist) that details what the service requires and what it provides, and another that contained Borne Shell functions for starting, stopping, and restarting a service.
Lets look at an example of a SystemStarter service on Panther, in this case Postfix:
calypso:/System/Library/StartupItems/Postfix benr$ ls -l
total 16
-rwxr-xr-x 1 root wheel 598 8 Sep 2003 Postfix
-rw-r--r-- 1 root wheel 310 31 Jul 2003 StartupParameters.plist
calypso:/System/Library/StartupItems/Postfix benr$ cat StartupParameters.plist
{
Description = "Postfix mail server";
Provides = ("SMTP");
Requires = ("Resolver");
Uses = ("Network Time", "NFS");
Preference = "None";
Messages =
{
start = "Starting Postfix";
stop = "Stopping Postfix";
restart = "Reloading Postfix Configuration";
};
}
calypso:/System/Library/StartupItems/Postfix benr$ cat Postfix
#!/bin/sh
. /etc/rc.common
StartService ()
{
if [ "${MAILSERVER:=-NO-}" = "-YES-" ]; then
ConsoleMessage "Starting mail services"
/usr/sbin/postfix start
elif [ "${MAILSERVER:=-NO-}" = "-AUTOMATIC-" ]; then
/usr/sbin/postfix-watch
fi
}
StopService ()
{
ConsoleMessage "Stopping Postfix mail services"
/usr/sbin/postfix stop
killall -1 postfix-watch 2> /dev/null
}
RestartService ()
{
if [ "${MAILSERVER:=-NO-}" = "-YES-" ]; then
ConsoleMessage "Reloading Postfix configuration"
/usr/sbin/postfix reload
else
StopService
fi
}
RunService "$1"
You can see that its really pretty simple and self explanatory. The plist contains information about our service and the accompanying script contains functions for start, stop and restart.
Control of SystemStarter services is really limited. Seemingly everywhere you look in SystemStarter are signs saying "You shouldn't tinker man.." There is limited control using the SystemStarter command itself. Without args it'll start everything. You can pass three diffrent commands to SystemStarter: start, stop, and restart. However there isn't a way to list the status of the services, you have to just use "ps" to see what is or isn't running. Furthermore, some of the services are written in such as way as to evade the usefulness of service control, here is my favorite example found in the NFS SystemStarter script:
#!/bin/sh
##
# Network File System
##
. /etc/rc.common
StartService ()
{
CheckForNetwork
if [ "${NETWORKUP}" = "-NO-" ]; then exit; fi
lockfile -r 0 /var/run/NFS.StartupItem || exit 0
##
# Set up NFS client.
##
ConsoleMessage "Starting network file system"
... Snipped ...
}
StopService ()
{
return 0
}
RestartService ()
{
return 0
}
RunService "$1"
Isn't that nice? You can actually stop the service. Not to mention the bad output from SystemStarter:
calypso:/System/Library/StartupItems/NFS benr$ sudo SystemStarter stop "NFS" Welcome to Macintosh. Startup complete. Hangup calypso:/System/Library/StartupItems/NFS benr$
So, in that example nothing happened... but I get this pointless output. Furthermore, you can start all services despite the fact that they are already running. Look what happens when on a running system I run SystemStarter by itself without args:
calypso:/System/Library/StartupItems/NFS benr$ sudo SystemStarter Welcome to Macintosh. Starting SecurityServer Initializing network Starting kernel event agent Checking disks Loading Shared IP extension Hangup calypso:/System/Library/StartupItems/NFS benr$ lockfile: Sorry, giving up on "/var/run/NFS.StartupItem" Starting Apple File Service Starting printing services kextload: extension /System/Library/Extensions/SharedIP.kext appears to be valid kextload: loading extension /System/Library/Extensions/SharedIP.kext kextload: sending 1 personality to the kernel kextload: extension /System/Library/Extensions/SharedIP.kext is already loaded Loading IP Firewall extension kextload: extension /System/Library/Extensions/IPFirewall.kext appears to be valid kextload: loading extension /System/Library/Extensions/IPFirewall.kext kextload: sending 1 personality to the kernel kextload: extension /System/Library/Extensions/IPFirewall.kext is already loaded Starting internet services Waiting for Printing Services Waiting for Printing Services cupsd: Child exited with status 48! Startup complete.
So SystemStarter was a good first step for OS X. It feels like a great Init system that was started and then just never completed. It works, thousands of users are using it every day without realizing it, we can't argue that, but from the standpoint of an administrator I just can't stomach it. Its better than /etc/rc's, without a doubt, but its just not there. With a little love and some extra utility functions (like "SystemStarter list" for instance) it would be significantly more robust in feel.
Which brings us to SystemStarters successor: launchd. Introduced in OS X Tiger (10.4) it is a real init replacement, running as PID 1. Its much more robust and feels like the natural progression of where SystemStarter was going but never got to. We'll look at launchd in our next exciting chapter.
For more information about SystemStarter I suggest the following resources:
- Introduction to System Startup Programming Topics: A series of ADC (Apple Developer Connection) articles reguarding startup.
- SystemStarter and the Mac OS X Startup Process: USENIX Paper by Wilfredo Sanchez and Kevin Van Vechten.
- Man page for SystemStarter
Follow your dreams, you can reach your goals.
nicholas (Email) (URL) - 12 June '06 - 21:55
Hello! Very interesting and professional site.dianne (Email) (URL) - 13 June '06 - 00:05
This site is a lot of fun very well designed.eloy (Email) (URL) - 13 June '06 - 01:06
Thanks for the special work and information!sonia (Email) (URL) - 13 June '06 - 16:01
It looks like you really had a nice time.