TweetFollow Us on Twitter

launchd: Judge, Jury, Executioner

Volume Number: 21 (2005)
Issue Number: 6
Column Tag: Programming

Mac In The Shell

launchd: Judge, Jury, Executioner

by Edward Marczak

The Changes Apple Has Wrought

Apple, Apple, Apple. Where to start? We've all now heard about different kinds of transitions, and launchd marks a huge one. For a Unix-head that was comfortable with the systems that launchd consumes, I had to ask: why?

Introduction

My wife is an artist. When we were just dating, I bought her a set of markers that she had used before, and wanted for herself. As far as she was concerned, they were perfect: the angles of the nib, the size of the smaller side and the way they stacked up: perfect. She got about a year-and-a-half out of them. Naturally, markers run dry after use, and we needed to replace these markers. We went back to the art supply shop to find that the manufacturer had shipped new markers. Version 2-point-oh, if you will. Well, my wife disliked just about everything about the way these markers had changed. Change for change's sake. Is this the story with launchd?

Investigation

When I got my hands on Tiger during the beta period, I wanted to test how things in my then-current environment would work. I backup my PowerBook every night: a perfect job for cron. After clean-installing Tiger, and moving some data over, I went to go add my nightly backup to cron. What's this? A little note?

# The periodic and atrun jobs have moved to launchd jobs
# See /System/Library/LaunchDaemons

That piqued my interest. I had to follow that trail. Of course, during the beta period, you can't just post to your closest mailing-list asking, "what is this launchd thing?" Over in /System/Library/LaunchDaemons, I found the following file listing:

bootps.plist
com.apple.KernelEventAgent.plist
com.apple.atrun.plist
com.apple.mDNSResponder.plist
com.apple.nibindd.plist
com.apple.periodic-daily.plist
com.apple.periodic-monthly.plist
com.apple.periodic-weekly.plist
com.apple.portmap.plist
com.apple.syslogd.plist
com.apple.xgridagentd.plist
com.apple.xgridcontrollerd.plist
com.vix.cron.plist
comsat.plist
eppc.plist
exec.plist
finger.plist
ftp.plist
login.plist
nmbd.plist
ntalk.plist
org.isc.named.plist
org.postfix.master.plist
org.xinetd.xinetd.plist
printer.plist
shell.plist
smbd.plist
ssh.plist
swat.plist
telnet.plist
tftp.plist

Looks like familiar stuff, but presented in a new way. Is there a man page for this thing? Sure enough, there is. The man page says simply that launchd is the "System wide and per-user daemon/agent manager". A little further down, it hits me: "During boot launchd is invoked by the kernel to run as the first process on the system and to further bootstrap the rest of the system."

Kaboom

Run as the first process? Don't be silly, that's initd's job! Look, I'll just go find initd in my process list and...hmmmm. No initd. OK...breathe slowly.

First cron, and now initd. This launchd thing is ravenous! What else has it taken over? As it turns out, launchd now takes the place of several tried and true systems, namely:

init
Startup Items
inetd/xinetd
watchdog (on OS X Server)
cron
rc (almost)

The rc structure still exists, but there is a note in the (very short) launchd man page, that states, "At some point in the future, we hope to completely phase out the use of rc." Six time-honored, tried-and-true subsystems that get the job done, and are in use on other systems. Again, it makes me ask "why?"

Why

Why take these well-known subsystems and replace them with something unknown and untested? One thing I thought I might find the answer to while at WWDC this year was the reason for the change. Turns out that there was nary a mention of launchd in all of the sessions I attended. There was so much other good content, that I didn't think about it all too much while I was there, but then I got home and looked at all of the non-WWDC e-mail that had accumulated during my trip. I had three requests all looking for more information relating to launchd (though, they just didn't know it yet). While I still don't have the exact answer to "why?", I have been using launchd and it's related programs for various tasks, and it seems to work reasonably well.

Apple's OS X web page (http://www.apple.com/ macosx/features/unix/) makes a mention of launchd thusly:

    "Since Mac OS X rarely requires you to reboot, you'll hardly ever notice it, but Tiger takes less time to start up, thanks to launchd. Launchd provides faster startup through a unified framework for starting, stopping and managing daemons, and incorporates inetd, init, mach_init, System Starter and related services. Administrators have a single mechanism for auditing, configuring and setting resources limits on services."

Well, OK, that explains a little bit...or perhaps even more than a bit. Look at what's happening here. Instead of this (10.3):

$ ps ax
PID  TT  STAT      TIME COMMAND
  1  ??  Ss     0:00.85 /sbin/init 
  2  ??  Ss     5:35.22 /sbin/mach_init
...

Tiger gives us this:

PID  TT  STAT      TIME COMMAND
  1  ??  S<s    0:04.40 /sbin/launchd
...

launchd is now responsible for pretty much everything. All your bases belong to launchd!

P to the L to the I-S-T

When you read the man page for launchd, you may notice under the 'see also' section, that it mentions launchd.plist. If you go looking on your system for launchd.plist, you're not going to find it. They're actually referring to the concept of launchd plists.

For the uninitiated, 'plist' stands for "Property List." Plists provide a standardized way for applications to store data, and then later retrieve this data. You can think of it like a better Windows INI file. However, there are three kinds of plists: old-style ASCII, XML and binary. The ASCII format has been inherited from NeXT, and still supported for legacy reasons. The binary version was introduced with 10.2, but has only really been pushed by Apple in Tiger. launchd stores its plists in XML format. XML plists are plain-text files that can be read by a text editor. Even better is to use an editor that understands plists. Apple's GUI-based Property List editor is one such editor. I also hope to have a curses based (TUI) editor finished by the time this goes to print (life, however, may get in the way of that deadline). So, for now, copy /System/Library/LaunchDaemons/ssh.plist to your desktop or some other out of the way place, and open it with "Property List Editor" (which, under Tiger is in your Applications directory. Panther users need to have the developer tools installed, and will find it under /Developer/Applications/Utilities, however, if you're on Panther, you don't have launchd...but it's a nice exercise. A double-click on the plist should launch Property List Editor also, if installed). Figure 1 illustrates how the hierarchal key/value system is displayed.


Figure 1. Property List Editor displaying sshd.plist

Property lists are able to store several Core Foundation types (CFString, CFNumber, CFBoolean, CFDate, CFData, CFArray, and CFDictionary), and are really aimed at storing values of 100kb or less. You'll notice that all of the types are basically strings and numbers. Also, in addition to simple flat list of key/value pairs, parameters in a plist can be structured hierarchically. So, what are the parameters of a launchd plist, and how do we write our own? Right this way, my friend...

DIY

The first thing to notice from Figure 1 is the 'Label' key. This is a way to uniquely identify a job to launchd. You'll see a little later on why launchd needs to do this. 'Label' can be any value you wish, however, it's easiest to name it something resembling the job, or stick with the domain scheme Apple has adopted (yes, 'adopted', not 'created'). The next thing to do is to specify the program that you want to run. Interestingly (or frustratingly), there are two ways to specify this. One way, like the example in Figure 1, is to use the 'Program' key, and specify the value as the full path to the executable. If the program has any parameters, those can be specified in the 'ProgramArguments' array key. The second way to specify the program to run is to forgo the 'Program' key altogether, and simply use 'ProgramArguments'. Using this method, the first value in the array is taken as the executable, and the remaining array elements are the arguments. Let's make a sample plist. First, we need something to run. How about a script that speaks the current time? Here it is:

~ $ mkdir bin
~ $ cd bin
~/bin $ vi speakdate.sh
#!/bin/bash
say `date "+%H:%M"`
:wq

(note that this is in my home directory, and I'm running as a regular user, not root)

Make sure it's executable:

~/bin $ chmod 750 speakdate.sh

...and test it:

$ ./speakdate.sh

You should hear the current time (in 24-hour 'military' designation) spoken. Now we can create our plist for launchd. I'm going to recommend using Apple's Property List Editor for the simple fact that you'll get all of the DTD tag info right, and the editor will write proper XML without you breaking a sweat. We'll look at it after the editor gets through with it.

Once the editor is up, click on the 'New Root' button. Knock the disclosure triangle down on the newly created root node, and then click on the 'New Child' button three times. Change the key names, classes and values to the following values:

Name: Label
Class: String
Value: speakdate

Name: OnDemand
Class: Boolean
Value: Yes

Name: ProgramArguments
Class: Array

Once again, highlight this array, drop the disclosure triangle and click on the 'New Child' button in the toolbar. Simply change the value of item 0 in this array to be the full path to the script - mine's at /Users/marczak/bin/speakdate.sh and your's will vary based on your user name.

Save this plist as '~/Library/LaunchAgents/speakdate.plist'. The final plist, as seen in Property List Editor is shown in Figure 2. (Please note that like everything else on OS X, you should follow the system hierarchy: per user files go in ~/Library/Launch*, system-wide additions go into /Library/Launch*, and you should never touch /System/* !)


Figure 2: Our plist for launchd, version 1

Just for completeness sake, let's see what the file really looks like:

$ cat speakdate.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>Label</key>
  <string>speakdate</string>
  <key>OnDemand</key>
  <true/>
  <key>ProgramArguments</key>
  <array>
      <string>/Users/marczak/bin/speakdate.sh</string>
  </array>
  </dict>
</plist>

Again, we see that by using an editor that understands the plist format, a lot gets filled in for us. Of course, one could do this by hand, but you risk more errors that way.

How do we control this launchd thing? By using a CLI utility named 'launchdctl'. launchdctl can do many things, but for now, let's look at loading a plist into its environment. To load speakdate, issue the following command:

launchctl load -w /Users/marczak/Library/LaunchAgents/speakdate.plist

The 'load' verb instructs launchctl to tell launchd to add the plist to its list of jobs. The '-w' flag removes the disabled flag from the plist, and updates the plist itself. We can see that it has been added to our per user list by using launchctl with the 'list' verb:

$ launchctl list
speakdate

It's really beautiful that launchd operates on a per user basis. It wouldn't surprise me if we see launchd taking over user login items in the future. Now, on to the magic - making it run! The 'start' verb tells launchctl to have launchd start a job. The second parameter is the label you gave the job in the plist. It's as easy as:

$ launchctl start speakdate

In a second or two, your Mac should speak the current time (make sure your volume is up!). All in all, that was pretty lame, right? For all that work, you could manually run the script and have your Mac speak the time. Faithful readers of this column know that I'm all about automation, so let's get to it. First, we'll unload the plist:

launchctl unload -w /Users/marczak/Library/LaunchAgents/speakdate.plist

The 'unload' verb does what you expect. Like the 'load' verb, there's a '-w' flag. This time, it marks the plist as disabled, and writes that flag into the plist. Before we run Property List Editor, we need a test folder for this example. Create /Users/Shared/watch. Now bring up Property List Editor and open up our plist (use the handy 'File->Open Recent' menu for quick access. See? Sometimes it's the little things that count!).

Tilt down the disclosure triangle on 'Root', then click the 'New Child' button. Name the key 'WatchPaths', make it an array, and then click 'New Child'. Change the value for item 0 to '/Users/Shared/watch'. Save it, load it, and invoke it:

$ launchctl unload /Users/marczak/Library/LaunchAgents/speakdate.plist 
$ launchctl load -w /Users/marczak/Library/LaunchAgents/speakdate.plist 
$ touch /Users/Shared/watch/temp1

Tell me you don't think that's pretty cool! Really, go on. Have fun and do that again:

$ touch /Users/Shared/watch/temp2

The value for "WatchPaths" can also be brought down to the file level (watching a particular file). Another way to watch an entire directory is with the use of the "QueueDirectories". It differs from "WatchPaths" by running the program until the queue is cleared. I'll illustrate this with our example, once again. Unload speakdate, first. Load up the plist into Property Editor. Change the "WatchPaths" key name to "QueueDirectories". Save, quit and load it with launchctl. You'll notice that...uh...hello? You can stop now. Really. Please, stop telling me the time. I'm begging you! The quick and easy way to keep the script loaded, but make it idle is to clear the queue directory:

$ rm /Users/Shared/watch/* 

Ahhhh, peace and quiet. "QueueDirectories" is a great way to have a script process items that come into a directory and need to be dealt with. Of course, you'll need to move or remove them once you've processed them.

Just like cron! Kinda...

As mentioned, in Tiger, launchd has taken the place of cron...mostly. cron does still exist and will run jobs that you put in the various crontab files (thankfully - see "Utopia, it's not", below). If you want to do it the launchd way, there are two separate keys that will help. "StartInterval" takes a numeric value ("n"), in seconds, and causes the job to fire every n seconds. This one's simple. So simple, that I even want to introduce an additional key: "RunAtLoad". "RunAtLoad" takes a boolean that determines if the program runs once when loaded, or not. Just so this does what you expect, we'll use it in our example. Do the 'launchctl unload' and edit dance once again. Delete the "QueueDirectories" node. Add a new Boolean key called "RunAtLoad" and make sure its value is 'yes'. Add another key, this time numeric, called "StartInterval". Make the value 10. Save it, and go load it. You should immediately hear the time spoken, and then every ten seconds after. StartInterval: says what it does, does what it says. Unload it when you've heard enough.

According to the man page, the "StartCalendarInterval" key is supposed to cause "the job to be started every calendar interval as specified. Missing arguments are considered to be wildcard. The semantics are much like crontab". Well, it's supposed to - please see "Utopia, it's not," below. Let's run our example again. Edit the plist once again.

Delete the "StartInterval" key, and create a new one named "StartCalendarInterval". Make its class a dictionary, and then add two children. Each child should be a number. Name the first child key 'Hour' and the second 'Minute'. 'Hour' is the hour number, from 0 to 23, and minute is the minute, from 0 though 59. Just so you can hear this job run, choose something in about 5 minutes from the current time. I want my list to run at 8:30pm, as you can see in figure 3.


Figure 3. Our sample plist, now using <StartCalendarInterval>

Save the new version, and then use launchctl to load it up. When the clock strikes the appropriate hour and minute, the script will run and you'll hear the time spoken. Any values that are left out, are considered cron-like wildcards. In our case, this script is intended to run at 8:30pm every day, of every month.

Didn't you mention xinetd?

Yes, launchd also takes over for xinetd, and there's a whole host of ways that it stays compatible. The interesting thing is the way launchd handles this. In Apple's quest to speed up boot times, launchd basically fakes the fact that there's a bunch of programs to start, and it doesn't really start any of the ones that would traditionally be started. It does read the plists and figure out which ports to reserve and listen to.

Since you've probably had enough editing of plists for now, let's look at two services that Apple had been running through xinetd, and how they made the transition to launchd. The first of those being sshd (which, on other platforms I've dealt with, usually runs standalone), and the second, ftpd.

We saw the plist for sshd back in figure 1, and there's a lot going on in there! Try looking at the file itself:

<?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.openssh.sshd</string>
        <key>Program</key>
        <string>/usr/libexec/sshd-keygen-wrapper</string>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/sbin/sshd</string>
                <string>-i</string>
        </array>
        <key>SessionCreate</key>
        <true/>
        <key>Sockets</key>
        <dict>
                <key>Listeners</key>
                <dict>
                        <key>Bonjour</key>
                        <array>
                                <string>ssh</string>
                                <string>sftp-ssh</string>
                        </array>
                        <key>SockServiceName</key>
                        <string>ssh</string>
                </dict>
        </dict>
        <key>StandardErrorPath</key>
        <string>/dev/null</string>
        <key>inetdCompatibility</key>
        <dict>
                <key>Wait</key>
                <false/>
        </dict>
</dict>
</plist>

You've already seen 'Label', 'Program' and 'ProgramArguments'. Here's the goodies: "SessionCreate", "Sockets" and "inetdCompatibility".

"inetdCompatibility" is really the thrust of this whole thing, so I'll start there. This tells launchd that this program thinks that it's being run though inetd/xinetd. The 'wait' subkey is the analog of xinet's wait parameter. Basically, we need to know if this program is single or multi-threaded. If it's single-threaded, you want to set 'Wait' to true. This way, launchd runs the program, and then stops answering for it. If set to 'false', launchd will continue to accept connections for the program, and spawn new copies as needed. Somewhat undocumented is the fact that a separate program, 'launchproxy', handles programs that need inetd compatibility. 'launchproxy' has a short little man page, but isn't mentioned in launchd's other man pages.

"SessionCreate" is also mostly undocumented. Undocumented as far as the man page, Apple Developer docs and that little thing called Google. Of course, there's always the source. Defining this key reaches into Apple's security framework and creates a security session for the launched program. Now, this only works if "inetdCompatibility" is not configured to wait.

"Sockets" is an optional key that tells launchd to use on demand sockets to trigger the job. The job can check-in and get a copy of the file descriptors in use. There are several sub-keys that go along with "Sockets", such as:

Listeners/SockServiceName - Important one: determines the service that the program 'bind's or 'connect's to, based on /etc/services. (This can get a little frustrating. For example, if you want to run ssh on an alternate port, you need to add it in /etc/services, and then tell the plist that the "SockServiceName" should bind to that alternate name. Goofy).

Listeners/Bonjour - This is an incredibly easy way to register the service with the mDNSResponder. Brilliant.

Quick example: on a server, look at the process list before anyone tries to access it over ssh:

# ps ax | grep ssh
15922  p1   S+    0:00.01 grep ssh

No permanent sshd is running. Once someone gets in via ssh:

# ps ax | grep [s]sh
15939  ??  S      0:00.11 /usr/sbin/sshd -i

launchd is doing its job. As promised, here's ftp's launchd.plist:

# cat /System/Library/LaunchDaemons/ftp.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>Disabled</key>
        <true/>
        <key>Label</key>
        <string>com.apple.xftpd</string>
        <key>Program</key>
        <string>/usr/libexec/xftpd</string>
        <key>ProgramArguments</key>
        <array>
                <string>xftpd</string>
                <string>-a</string>
        </array>
        <key>Sockets</key>
        <dict>
                <key>Listeners</key>
                <dict>
                        <key>SockPassive</key>
                        <true/>
                        <key>SockServiceName</key>
                        <string>ftp</string>
                        <key>SockType</key>
                        <string>SOCK_STREAM</string>
                </dict>
        </dict>
        <key>inetdCompatibility</key>
        <dict>
                <key>Wait</key>
                <false/>
        </dict>
</dict>
</plist>

The key differences from sshd's plist are the keys "SockPassive" and "SockType":

SockPassive - Is this a 'listen' socket, or connect? Default/true is 'listen'.

SockType - what kind of socket to create (stream - the default, dgram and seqpacket).

Again, these are part of the "Sockets" key.

Avertissement !

There are certain ways that launchd expects a daemon to behave. Specifically (and this is right from the man page):

    A daemon or agent launched by launchd MUST NOT do the following in the process directly launched by launchd:

               -   fork(2) and have the parent process exit(3) or _exit(2).
               -   Call daemon(3)
    
         A daemon or agent launched by launchd SHOULD NOT do the following as a part 
         of their startup initialization:
    
               -   Setup the user ID or group ID.
               -   Setup the working directory.
               -   chroot(2)
               -   setsid(2)
               -   Close "stray" file descriptors.
               -   Change stdio(3) to /dev/null.
               -   Setup resource limits with setrusage(2).
               -   Setup priority with setpriority(2).
               -   Ignore the SIGTERM signal.
    
         A daemon or agent launched by launchd SHOULD:
    
               -   Launch on demand given criteria specified in the XML property
                   list.  More information can be found in launch(3).
               -   Catch the SIGTERM signal.

Those are some pretty important guidelines. Mind them as you're writing your scripts!

Utopia, it's not

While launchd has a lot of great features, it can still be a little rough around the edges, somewhat typical of a 1-dot-oh release. In particular:

Sometimes, nothing happens. I've had problems with launchd that, after loading a plist, I can't get the job to start. However, after a reboot, the same plist runs just fine. Can't explain that one just yet.

Sometimes, something happens, just not what I expect. Again, a reboot seems to fix it. Case in point: while testing the plist for this article, I wrote the sample and loaded it. I could start it just fine. But asking for a list gave me:

com.apple.launchd.firstborn: execve(): No such file or directory

...and then launchctl needed to be killed to get my prompt back. After a reboot, the same, untouched plist loaded and listed just fine.

It's the intended replacement for cron, however, there are two problems:

It doesn't fully encompass everything cron can do. Such as run a command in a limited scope, such as every 3 hours, Monday though Friday, only between 8am and 8pm ("0 8-20/3 * * 1-5 root /path/to/program", for example.)

<StartCalendarInterval> doesn't work! Well, it does...once. After which, it never fires again. Not fixed in 10.4.1. (hopefully, 10.4.2 nails this issue down).

No graceful way to unload a daemon. Now, some hard-core Unix folks will yell at me about this one. That's just how some Unicies work. OS X has SystemStarter to deal with this, and it's still in place. I imagine that launchd will someday overtake this system as well. However, if you have services that need to be started or stopped a very specific way, you may find that writing a StartupItem is, for now, the way to go.

The workarounds for now seem to be the use of the 'old' systems: cron and SystemStarter. If you need some very specific way to shut down a process (fmserver users, I'm looking in your direction), make it a StartupItem. I have OpenBase running on some Tiger systems this way. Works just fine.

As for StartCalendarInterval, well, just use cron. You can simply copy over any crontab entries you had been using on Panther, or create new entries, and put them in the appropriate place. Apple was kind enough to make sure that launchd calls cron to run any jobs that it should. Of course, you can use launchd to unload and re-load cron:

# launchctl unload /System/Library/LaunchDaemons/com.vix.cron.plist
# launchctl load /System/Library/LaunchDaemons/com.vix.cron.plist

cron also remains the more flexible of the two in terms of scheduling flexibility. That's life on the edge, I suppose.

What about watchdog?

Yes, I did mention that launchd replaces watchdog. This takes place thanks to the "OnDemand" key. When this Boolean key is set to 'false', launchd watches the process and restarts it if necessary. Try this 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>Label</key>
        <string>iCalForever</string>
        <key>OnDemand</key>
        <false/>
        <key>ProgramArguments</key>
        <array>
                <string>/Applications/iCal.app/Contents/MacOS/iCal</string>
        </array>
</dict>
</plist>

Load it into launchd:

$ launchctl load /Users/marczak/Library/LaunchAgents/icalforever.plist

There's iCal! Now, try to quit it. Back it comes!...and again tell it to quit...there it is again! Unload the job to rid yourself of iCal for a bit:

$ launchctl unload /Users/marczak/Library/LaunchAgents/icalforever.plist

If you really were quitting it quickly, and you still had your terminal visible, you'll notice a series of messages:

launchd[1447]: iCalForever: exited: Terminated
launchd[1447]: iCalForever: respawning too quickly! throttling
launchd[1447]: iCalForever: 9 more failures without living at least 60 seconds will 
               cause job removal
launchd[1447]: iCalForever: will restart in 10 seconds

This is really nice protection against some job going bonkers and taking down your system.

Conclusion

So, is launchd really like my wife's situation with her illustration markers? Is it really just change for change's sake? In this case, the answer is no. Just as the Unix world went through the transition from stand-alone daemons to inetd, and ultimately xinetd, we're ready for launchd. The real question is if launchd is ready for us. Fortunately, cron and xinetd are still in place and are called by launchd. cron continues to do the right (and more flexible) thing, so use it if you need to. Launchd is extremely version one-dot-oh, but I expect that it will come up to speed very quickly. All in all, launchd has the right motivation: a unified way of launching and managing daemons, no matter which stage of system operation they're run at.

I think that most people's gripe with launchd is simply the scarcity of documentation. The Tiger server docs briefly mention launchd, and even in those cases refer you to the man page. Actually, that's something that even I haven't done yet! If you do want to dig into launchd, you should read the man pages. While you will still be left with some questions, it does get you going.

The "Utopia it's not" section above lists a few workarounds to launchd's bugs. Even in the source code, there's a TODO list. One of the items on the list? "cron". Another? "Documentation". Indeed.

I was just about to package this month's column up, and get it in for print when I was made aware of a plist editor specifically for launchd items. I haven't used it, so I can't vouch for it, but it looks nice. It's called (amazingly), "Launchd Editor", and can be found at <http://www.codepoetry.net/products/launchdeditor>. Worth a mention.

Dig in and experiment with launchd - it's probably the best way to learn its many ins and outs. I'll certainly be following the development of launchd pretty closely, and will be updating you as I know more.


Ed Marczak, owns and operates Radiotope, a technology consulting company that tries its hardest to avoid bad puns regarding launchd, such as 'time for launch' or '3, 2, 1, launch!'. Get launched at http://www.radiotope.com

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Arq 5.8.5 - Online backup to Google Driv...
Arq is super-easy online backup for Mac and Windows computers. Back up to your own cloud account (Amazon Cloud Drive, Google Drive, Dropbox, OneDrive, Google Cloud Storage, any S3-compatible server... Read more
Backblaze 4.3.0.44 - Online backup servi...
Backblaze is an online backup service designed from the ground-up for the Mac. With unlimited storage available for $5 per month, as well as a free 15-day trial, peace of mind is within reach with... Read more
Instaradio 7.1 - Listen to your favorite...
Instaradio is fast, and it could be the radio player you have been waiting for. Try the app thousands of people rely on for listening to radio. Features Listen to radio from all around the world... Read more
EtreCheck 3.3.3 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
Hopper Disassembler 4.2.1- - Binary disa...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32-bit and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about... Read more
Slack 2.6.2 - Collaborative communicatio...
Slack is a collaborative communication app that simplifies real-time messaging, archiving, and search for modern working teams. Version 2.6.2: Fixed Inexplicably, context menus and spell-check... Read more
Apple Final Cut Pro X 10.3.4 - Professio...
Apple Final Cut Pro X is a professional video editing solution.Completely redesigned from the ground up, Final Cut Pro adds extraordinary speed, quality, and flexibility to every part of the post-... Read more
Numi 3.15 - Menu-bar calculator supports...
Numi is a calculator that magically combines calculations with text, and allows you to freely share your computations. Numi combines text editor and calculator Support plain English. For example, '5... Read more
TunnelBear 3.0.14 - Subscription-based p...
TunnelBear is a subscription-based virtual private network (VPN) service and companion app, enabling you to browse the internet privately and securely. Features Browse privately - Secure your data... Read more
Apple iMovie 10.1.6 - Edit personal vide...
With an all-new design, Apple iMovie lets you enjoy your videos like never before. Browse your clips more easily, instantly share your favorite moments, and create beautiful HD movies and Hollywood-... Read more

Latest Forum Discussions

See All

Goat Simulator PAYDAY (Games)
Goat Simulator PAYDAY 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ** IMPORTANT - SUPPORTED DEVICES **iPhone 4S, iPad 2, iPod Touch 5 or better Goat Simulator: Payday is the most... | Read more »
Zombie Gunship Survival Beginner's...
The much anticipated Zombie Gunship Survival is here. In this latest entry in the Zombie Gunship franchise, you're tasked with supporting ground troops and protecting your base from the zombie horde. There's a lot of rich base building fun, and... | Read more »
Mordheim: Warband Skirmish (Games)
Mordheim: Warband Skirmish 1.2.2 Device: iOS Universal Category: Games Price: $3.99, Version: 1.2.2 (iTunes) Description: Explore the ruins of the City of Mordheim, clash with other scavenging warbands and collect Wyrdstone -... | Read more »
Mordheim: Warband Skirmish brings tablet...
Legendary Games has just launched Mordheim: Warband Skirmish, a new turn-based action game for iOS and Android. | Read more »
Magikarp Jump splashes onto Android worl...
If you're tired ofPokémon GObut still want something to satisfy your mobilePokémon fix,Magikarp Jumpmay just do the trick. It's out now on Android devices the world over. While it looks like a simple arcade jumper, there's quite a bit more to it... | Read more »
Purrfectly charming open-world RPG Cat Q...
Cat Quest, an expansive open-world RPG from former Koei-Tecmo developers, got a new gameplay trailer today. The video showcases the combat and exploration features of this feline-themed RPG. Cat puns abound as you travel across a large map in a... | Read more »
Jaipur: A Card Game of Duels (Games)
Jaipur: A Card Game of Duels 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: ** WARNING: iPad 2, iPad Mini 1 & iPhone 4S are NOT compatible. ** *** Special Launch Price for a limited... | Read more »
Subdivision Infinity (Games)
Subdivision Infinity 1.03 Device: iOS Universal Category: Games Price: $2.99, Version: 1.03 (iTunes) Description: Launch sale! 40% Off! Subdivision Infinity is an immersive and pulse pounding sci-fi 3D space shooter. https://www.... | Read more »
Clash of Clans' gets a huge new upd...
Clash of Clans just got a massive new update, and that's not hyperbole. The update easily tacks on a whole new game's worth of content to the hit base building game. In the update, that mysterious boat on the edge of the map has been repaired and... | Read more »
Thimbleweed Park officially headed to iO...
Welp, it's official. Thimbleweed Park will be getting a mobile version. After lots of wondering and speculation, the developers confirmed it today. Thimbleweed Park will be available on both iOS and Android sometime in the near future. There's no... | Read more »

Price Scanner via MacPrices.net

Best value this Memorial Day weekend: Touch B...
Apple has Certified Refurbished 2016 15″ and 13″ MacBook Pros available for $230 to $420 off original MSRP. An Apple one-year warranty is included with each model, and shipping is free: - 15″ 2.6GHz... Read more
13-inch MacBook Airs on sale for up to $130 o...
Overstock.com has 13″ MacBook Airs on sale for up to $130 off MSRP including free shipping: - 13″ 1.6GHz/128GB MacBook Air (sku MMGF2LL/A): $869.99 $130 off MSRP - 13″ 1.6GHz/256GB MacBook Air (sku... Read more
2.8GHz Mac mini available for $973 with free...
Adorama has the 2.8GHz Mac mini available for $973, $16 off MSRP, including a free copy of Apple’s 3-Year AppleCare Protection Plan. Shipping is free, and Adorama charges sales tax in NY & NJ... Read more
15-inch 2.2GHz Retina MacBook Pro on sale for...
Amazon has 15″ 2.2GHz Retina MacBook Pros (MJLQ2LL/A) available for $1749.99 including free shipping. Apple charges $1999 for this model, so Amazon’s price is represents a $250 savings. Note that... Read more
Huawei Unveils New ‘Business-Styled’ MateBook...
Huawei has introduced a trio of new MateBook laptops, expanding its mobile portfolio and building on its success in delivering attractive and powerful high-end devices. The company claims the HUAWEI... Read more
Deal! Gold 12-inch 1.2GHz Retina MacBook for...
Amazon has the 2016 Gold 12″ 1.2GHz Retina MacBook (MLHF2LL/A) on sale for $350 off MSRP for a limited time. Shipping is free: - 12″ 1.2GHz Gold Retina MacBook: $1249.99 $350 off MSRP We expect this... Read more
13-inch 2.0GHz MacBook Pros on sale for $100...
B&H has the non-Touch Bar 13″ 2.0GHz MacBook Pros in stock today and on sale for $100 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 13″ 2.0GHz MacBook Pro Space... Read more
15-inch 2.2GHz Retina MacBook Pro, Apple refu...
Apple has Certified Refurbished 2015 15″ 2.2GHz Retina MacBook Pros available for $1699. That’s $300 off MSRP, and it’s the lowest price available for a 15″ MacBook Pro. An Apple one-year warranty is... Read more
Apple refurbished 9-inch and 12-inch iPad Pro...
Apple has Certified Refurbished 9″ and 12″ Apple iPad Pros available for up to $160 off the cost of new iPads. An Apple one-year warranty is included with each model, and shipping is free: - 32GB 9″... Read more
Apple Certified Refurbished iMacs available f...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more

Jobs Board

Best Buy *Apple* Computing Master - Best Bu...
**509110BR** **Job Title:** Best Buy Apple Computing Master **Location Number:** 000048-Topeka-Store **Job Description:** **What does a Best Buy Apple Computing Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Systems Engineer - California Polyte...
Cal Poly, San Luis Obispo Apple Systems Engineer Department: ITS - Customer & Tech Support (134900) College/Division: Academic Affairs Salary Range: Position Read more
Best Buy *Apple* Computing Master - Best Bu...
**508718BR** **Job Title:** Best Buy Apple Computing Master **Location Number:** 001526-Odessa-Store **Job Description:** **What does a Best Buy Apple Computing Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.