Packaging a LaunchDaemon

JPDyson
Valued Contributor

Folks, I'm bumping into a wall. I've got a LaunchDaemon I'm trying to package and include in my configs. Essentially, it's a "Second Boot" mechanism to kick off our encryption software and some other stuff that's not apparently working as an "after" script, for whatever reason.

I can verify that it's built correctly, and will launch and run appropriately if I manually load it (with launchctl). What I don't get is WHY I had to manually load it! If it's placed in the /Library/LaunchDaemons folder, why wouldn't it automatically load? What else am I missing?

23 REPLIES 23

mm2270
Legendary Contributor III

What OS are you deploying to?
One thing to check is the permissions on the LaunchDaemon. I have run into issues when building daemons and agents that if permissions are off it will not load automatically. Make sure its the same ad other LaunchDaemons in the directory that do work properly.
Also, any launchd item doesn't load automatically just by being in the given folder until a logout/in or a reboot, depending on the type we're taking about. I assume you're not seeing the daemon load after a logout or reboot correct?

franton
Valued Contributor III

How are you creating your LaunchDaemon? If you're doing it by hand, i'd seriously suggest you get a copy of Lingon and build it in that instead. It'll make sure the permissions are ok on the file and I believe the newer versions even do xml checking to make sure it's all valid before you test it.

franton
Valued Contributor III

Another point is, what is it your Daemon is trying to do? If you're trying (for example) to run something over the loginwindow then a daemon simply won't work: you'll need a launchagent instead. Agents do not run as root however.

donmontalvo
Esteemed Contributor III

Lingon X was released yesterday, and it allows you to create without having to logout or reboot. :)

http://sometimesitmatters.com

I'd create it with Lingon X and compare syntax and permissions.

PS, Lingon X is not in the Apple App Store, from the developer's blog it's because Apple doesn't like tools that run with root rights.

Don

--
https://donmontalvo.com

JPDyson
Valued Contributor

mm2270, deplopying hopefully to 10.7 & 10.8, and permissions match existing daemons.
The daemon and the script it runs are put into place on Casper's first boot, and the subsequent second boot is when it should run. It doesn't, even if I reboot again. And again.

franton, I'd say the xml is good, because it matches known working daemons and runs fine when loaded manually. A tool like Lingon shouldn't be neccesary for something so simple. All it's doing is running a script, and no matter what I have that script do (even if it's just a simple Hello World type of deal) it flat-out doesn't load automatically. It's practically identical to the Enroll daemon JAMF uses, with a different label and calling a different script.

don, well crap - another vote for Lingon. What do those guys know that I don't...

mm2270
Legendary Contributor III

Where is the script located on the system the daemon is running? I only ask because I've seen some odd issues at times where even a LaunchDaemon running as root has trouble executing anything from a locked directory such as /Library/Application Support/JAMF/bin/. Don't ask me why that would be but I've seen it happen.

Can you post the contents of your daemon here, genericising it if needed? Maybe getting some eyeballs on it here will help figure it out. Perhaps an additional key is needed to get it to work right.

Other than this, all I can say is I feel your pain. I have had some hair pullingly frustrating moments trying to diagnose why a Launchd item wasn't working as expected. Personally I don't feel there's enough good documentation from Apple or anyone else on how to work them up. I guess that's why apps like Lingon are so popular :)

mbrady
New Contributor

JP-

Do you see any relevant logs in the console? If it fails to launch you may see an error there.
You'll also want to make sure that the daemon's label is unique and that it requires no UI or user interaction of any kind.

JPDyson
Valued Contributor

mm2270, the script is in /Library/Scripts, and it's root:wheel 755

mbrady, I haven't seen anything helpful

The manifest I built:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Disabled</key>
    <false/>
    <key>Label</key>
    <string>com.MyCompany.secondboot</string>
    <key>UserName</key>
    <string>root</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Library/Scripts/secondboot.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
    <integer>300</integer>
</dict>
</plist>

The manifest Lingon built:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.MyCompany.secondboot</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Library/Scripts/secondboot.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
    <integer>300</integer>
</dict>
</plist>

com.MyCompany.secondboot.plist in /Library/LaunchDaemons, root:wheel 644

mbrady
New Contributor

The StartInterval key will re-run your job every 5 minutes, is that what you intended?

I would think you need /bin/sh (or bash) as the first string in the ProgramArguments array in order for launchd to run the script properly.

mm2270
Legendary Contributor III

@mbrady, no, you don't need a shebang or sh to run the script. because its pointing to the path to the script. As long as the script is coded properly and has correct permissions, it should run it. I've created launchd's to run scripts before and its only necessary to put the full path to it to make it run.

@JP, I assume even the one Lingon created isn't working? And you say it won't run any kind of script or command? Even something that just creates an empty directory or touches a file?

JPDyson
Valued Contributor

mbrady, as to the interval, yes! The script will unload and delete the LaunchDaemon, and then delete itself, when it succeeds.

mm2270, I have not been able to test the one Lingon created yet. I suppose it's possible those additional keys I have are causing the problems... but I doubt it. I DID however stumble onto extended file attributes on my previous files, thanks to TextMate (grumble grumble grumble). I'm wondering if those are a factor.

mm2270
Legendary Contributor III
I DID however stumble onto extended file attributes on my previous files, thanks to TextMate (grumble grumble grumble). I'm wondering if those are a factor.

It very well could be. As I said, I've seen some pretty wacky stuff with launchdaemons that if they are not set EXACTLY the way the OS expects to see them, they won't load. I guess Lion and Mountain Lion's additional security and sandboxing rules. Although, even if that turns out to be the culprit, it doesn't exactly explain why you can load it manually. I would think it would fail to load that way too!

JPDyson
Valued Contributor

It fails to run with Lingon's manifest as well, unless manually loaded. I'm at a loss - it's the same mechanism JAMF uses for the Enroll script, and that one works alright. Maybe I just need to add another script that loads it (fail).

mbrady
New Contributor

Could you show off the script you're using (de-identified as needed)?

mm2270
Legendary Contributor III

Just curious, but have you tried the LaunchDaemon on multiple systems? I assume so but you'd want to be sure you rule out an issue with one particular system.

I second mbrady's suggestion to post the script contents here. Although I think you said you'd tried it with other very simple scripts and had similar failed results.
There's got to a reason its not working automatically. We just haven't found it yet.

JPDyson
Valued Contributor

Script contents won't be necessary. I've reduced it to just a jamf displayMessage command, and again - runs perfectly when the daemon is manually loaded. I'm just going to raise a case with Apple.

mbrady
New Contributor

As far as I know, a launchdaemon can't interact with the UI at all so perhaps that's why it fails.

donmontalvo
Esteemed Contributor III

Might consider giving Eskimo, Stéphane, etc., a crack at this one...

http://lists.apple.com/archives/installer-dev

Don

--
https://donmontalvo.com

JPDyson
Valued Contributor

mbrady, the daemon does nothing of the sort. Again, it loads when manually loaded - and as far as I know, nothing is evaluating my script (which is what "interacts" with the UI, albeit indirectly) before deciding to load it at boot/login.

Don, I'll give Apple a day or two to respond to my ticket, then try the list.

JPDyson
Valued Contributor

So, interestingly I got this working - but I can't make sense of how. I had removed the StartInterval key, and it started working. I put it back, and it kept working. I re-introduced my actual secondboot script, and it kept working.

No idea what made it happy, but it's working now.

mm2270
Legendary Contributor III

Hehe. I hate mysteries like that. But, truthfully, my experience in working with launchd's has lead me to believe its as much voodoo as it is technology in getting them to work.

Anyway, glad its working now.

pblake
Contributor III

I am having the same problem. For me, I know why, the script is set to be run by root. When it is getting installed via pkg, it is not setting the owner of the launchdaemon as root as specified in the composer pkg, it is setting it as the user installing the package.

Anyone have an idea of how to prevent this files ownership by being changed by root when being installed?

donmontalvo
Esteemed Contributor III

FYI, aside from Lingon X, there is also LaunchControl which provides more info/validation:

http://www.soma-zone.com/LaunchControl/

--
https://donmontalvo.com