A few pointers about launchd and daemondo

Panagiotis Atmatzidis atma at convalesco.org
Wed Nov 4 22:10:55 PST 2009

On 05 Νοε 2009, at 1:54 π.μ., Scott Haneda wrote:

> On Oct 30, 2009, at 2:55 PM, Panagiotis Atmatzidis wrote:
>> Greetings,
>> I've created my first launchd script. It's for OpenVPN2. Here are  
>> the files I've created so far:
> Just out of general curiosity, why use openVPN2?  I have been  
> meaning to create a set of launchd items that start the built in VPN  
> server on OS X.  It is really quite trivial with the inbuilt one.   
> Just start it up, give it a range, plop in some user:pass stuff, and  
> you have a pretty nice VPN ready to go.
> Apparently OS X Sever has a GUI for this, but OS X Client does not  
> even claim to support it, though it does, and has been every day I  
> am at the coffee shop :)
> What advantages, and what am I missing out on by using this method  
> over openVPN?

None I believe. I run a mac mini G4 ppc with MacOSX Tiger Desktop  
edition though and I don't plan to buy the server edition of tiger for  
home usage only. So actually I don't have that option. I can't recall  
now, but there are also a few more advantages to openvpn over the  
standard L2TP/IPsec implementation.

>> devo:/opt/local/etc/LaunchDaemons root# ls -l org.macports.OpenVPN2/
>> total 16
>> -rwxr-xr-x   1 root  admin   957 Oct 30 23:06 OpenVPN2.wrapper
>> -rw-r--r--   1 root  admin  1026 Oct 30 23:39  
>> org.macports.OpenVPN2.plist
> I do not like the way in which launchd scrips are put into play in  
> MacPorts.  I never could understand the magic it was doing under the  
> hood.  Since I consider them almost always starting servers of some  
> form, I have moved to making my own normal .plist files and putting  
> them in files/tld.app.binary.plist, so org.pure-ftpd.ftpd.plist or  
> similar.

It works with abstractions. In some cases even triple ones. Launchd  
calles a script, which calls a second script, which (it may) call a  
third script. While the magic of launchd should be the capability to  
handle everything using a clean .plist file, but apparently that's not  
the case.

> it would seem every time I needed to add something a little out of  
> the ordinary I was getting stuck, whereas a plist is rather simple  
> for me to understand, and just as easy to copy into place.

True. plist and XML in general is *easy* to understand. Launchd is  
easy to explain, it's hard to make it work though. I believe that it  
is a great idea, implemented badly. But that's my opinion, I don't  
plan to start a flamewar, but for me (and I've lost several hours on  
it) lacks of flexibility and I fail to see how it will replace cron  
(among other things).

>> The Wrapper
>> [snip... removed wrapper code]	
>> the .plist which is an: ln -sf /opt/local/etc/LaunchDaemons/ 
>> org.macports.OpenVPN2/org.macports.OpenVPN2.plist /Library/ 
>> LaunchDaemons/....
>> ------------------------
>> <?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>org.macports.OpenVPN2</string>
>> <key>ProgramArguments</key>
>> <array>
>>       <string>/opt/local/bin/daemondo</string>
>>       <string>--label=OpenVPN2</string>
>>       <string>--start-cmd</string>
>>       <string>/opt/local/etc/LaunchDaemons/org.macports.OpenVPN2/ 
>> OpenVPN2.wrapper</string>
>>       <string>start</string>
>>       <string>;</string>
>>       <string>--stop-cmd</string>
>>       <string>/opt/local/etc/LaunchDaemons/org.macports.OpenVPN2/ 
>> OpenVPN2.wrapper</string>
>>       <string>stop</string>
>>       <string>;</string>
>>       <string>--restart-cmd</string>
>>       <string>/opt/local/etc/LaunchDaemons/org.macports.OpenVPN2/ 
>> OpenVPN2.wrapper</string>
>>       <string>restart</string>
>>       <string>;</string>
>>       <string>--pid=none</string>
>> </array>
>> <key>Debug</key><false/>
>> <key>Disabled</key><false/>
>> <key>OnDemand</key><false/>
>> <key>RunAtLoad</key><true/>
>> <key>NetworkState</key><true/>
>> </dict>
>> </plist>
>> However, there are two issues that I can't seem to be able to  
>> manage right now.
>> The first is that OpenVPN does not start at boot while the module  
>> is loaded succesfully. When I login to the system and kill  
>> daemondo, it relaunches itself and ovpn works fine. I suspect that  
>> the problem is en0. Launchd tries to launchd openvpn before en0  
>> comes up. That's why I put the NetworkState keyword, but it does  
>> not seem to effect *any* startup script. I had issues with dnsmasq  
>> also in the recent past.
> Are you sure that "NetworkState" is what you are looking for?
> From the man page  $man 5 launchd.plist
>     NetworkState <boolean>
>     If true, the job will be kept alive as long as the network is up,
>     where up is defined as at least one non-loopback interface being  
> up
>     and having IPv4 or IPv6 addresses assigned to them.  If false, the
>     job will be kept alive in the inverse condition.
> NetworkState seems to be for keeping a job alive if the network is  
> up, or keeping it dead if the network is down.  In your case, the  
> app is not up yet.  My interpretation is that since the app never  
> launched via launchd, the NetworkState test never comes into play.
> I could be wrong, that is just how I am reading that man page.
> I have a machine that loads a good chunk of IP's into an interface,  
> and I need to make sure they are all up before moving on, or the  
> final app will not work correctly.  I used `ipconfig` to make sure  
> this happened in a "wrapper" script.
> $man ipconfig
> There is a lot of good stuff in there that could help you, even just  
> the logging verbosity you can kick up and see what is going on.
> The argument I used was
>     waitall     Blocks until all network services have completed  
> configuring,
> 		 or have timed out in the process of configuring.
>                 This is only useful for initial system start-up time
> 		 synchronization for legacy network services that are inca-
>                 pable of dealing with dynamic network configuration  
> changes.
> If you were to add to your wrapper/start script:
> /usr/sbin/ipconfig waitall

Thanks, I figure this out [1]. Here is my solution on the problem. I  
have just two interfaces here, en0 and tun. We need to load tun, after  
en0 is up.

>> The second problem with this script is that when I unload it via  
>> launchd it does not kill the process. Launchd unloads the script  
>> and (probably) will not be launchd (if -w is added) in the next  
>> boot but daemondo keeps running the process nevertheless. Is this a  
>> normal behaviour?
> I can not help on this one, unload should not only remove the job,  
> but also stop it if it is running.  Though I find this very  
> dependent on how the app itself works.  For example, I never seem to  
> get a unloading of Apache2 to stop apache, which I assume is why  
> there are tools like `apachectl stop`.
> Apache spawns a number of processes of itself as needed, so to me,  
> it make sense that launchd would only be able to track the initial  
> app it started.  If I had a launchd item that started 10 copies of  
> `find`, and then unloaded that launchd, I would imagine I would only  
> stop 9 of those copies, the rest would keep running.  Or maybe I  
> only stop the script itself, and all the copies of `find` keep  
> running.
> Maybe keep that in mind when working on this.

This one was also bad shell script. Apparently now it does [1].  
However, the shell script I wrote can be done a lot better, I just  
don't have the time (and will at this point) to polish it.

>> I'm not *that* worried about the second. I'd prefer to have a  
>> solution about the first one, which is the most important for me.
> I would get a standalone launchd plist calling a script that does  
> the work of starting the job as you want it.  While you can jam all  
> sorts of commands and scripting into a launchd file, I find them to  
> be messy and hard to debug.  You have to take special care with  
> spaces, quotes, and paths and some other little "gotcha" areas.

Yes, this is true.

> I find if I can get a local script to start my app as I want it,  
> then I just have one command in my plist to call that script, things  
> are a lot cleaner.
> Once you have that working, it is up to you to use `daemondo` or not.
> Hopefully some of this is of help.  I am not very versed in much of  
> this, so it is mostly just to point you in a direction that  
> hopefully gets you where you need to go.
> -- 
> Scott * If you contact me off list replace talklists@ with scott@ *

Thank you nevertheless. I was "saved" by the 'ipconfig wait' keyword.  
I thought that launchd came up to make us get rid of the script lying  
all over the place in /. Probably it's not like that. Still I fail to  
see the "greatness" in launchd.

[1]  http://www.convalesco.org/2009/10/31/manage-to-launch-openvpn-at-boot-under-macosx/

Panagiotis (atmosx) Atmatzidis

email:	atma at convalesco.org
URL:	http://www.convalesco.org
GnuPG key id: 0xFC4E8BB4
The wise man said: "Never argue with an idiot. They bring you down to  
their level and beat you with experience."

More information about the macports-users mailing list