Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you start a LaunchAgent for the first time without rebooting, when your code runs as a LaunchDaemon?

I have a LaunchDaemon. When it runs, it checks if SIMBL is installed. If SIMBL is not installed, it uses NSTask to run /usr/sbin/installer on the SIMBL.pkg.

SIMBL's postflight script then tries to run a launchctl load command to start SIMBL's LaunchAgent immediately:

sudo -u "$USER" -- /bin/launchctl load -F -S Aqua -D user "${LAUNCHD_PLIST}"

This fails, because my LaunchDaemon's NSTask environment doesn't have $USER set.

If I have my daemon detect the current user with the System Configuration framework and pass it to NSTask with setEnvironment, launchctl bugs out on me:

Bug: launchctl.c:2325 (23930):13: (dbfd = open(g_job_overrides_db_path, O_RDONLY | O_EXLOCK | O_CREAT, S_IRUSR | S_IWUSR)) != -1

I realize a daemon, by definition, should not operate in a user session. By the same token, Apple seems to recommend LaunchAgents as helper objects for LaunchDaemons, to do that user session work. Is there any way to get such an agent up and running immediately?

I have all the .plists in the right places (they start running after a reboot, the next time launchctl does its regular loading) so my first thought was to just tell launchctl to reload. But all the code to do that is commented out in launchctl.c:

//  { "reload",         reload_cmd,             "Reload configuration files and/or directories" },

...

 * In later versions of launchd, I hope to load everything in the first pass,
 * then do the Bonjour magic on the jobs that need it, and reload them, but for now,
 * I haven't thought through the various complexities of reloading jobs, and therefore
 * launchd doesn't have reload support right now.
like image 785
jbrjake Avatar asked Oct 25 '11 21:10

jbrjake


People also ask

How do I launch daemons using launchd?

There are four ways to launch daemons using launchd. The preferred method is on-demand launching, but launchd can launch daemons that run continuously, and can replace inetd for launching inetd -style daemons. In addition, launchd can start jobs at timed intervals. Although launchd supports non-launch-on-demand daemons, this use is not recommended.

What is the difference between LaunchDaemons and LaunchAgents?

Specifically, LaunchDaemons are not allowed to connect to the macOS window server. LaunchAgents do have access to the GUI, and to other system features such as locating the current user’s Home folder, but generally have much more limited interfaces than do regular apps.

How to handle dependency ordering In launchd daemon?

The launchd daemon was designed to remove the need for dependency ordering among daemons. If you do not make your daemon be launched on demand, you will have to handle these dependencies in another way, such as by using the legacy startup item mechanism.

Where does launchd run services and components?

Before you have logged in, launchd runs services and other components which are specified in Property List files in the LaunchAgents and LaunchDaemons folders in /System/Library, and in /Library.


1 Answers

Oh how launchd drives me crazy....

To cut to the chase, after much study and experimentation, this is how I do it on 10.5+:

# If possible, tell launchd to start the LaunchAgent. This will fail on 10.4.
# $F[0] is the pid
# $F[1] is the username
# $F[2] is the first word of the command
ps -ww -A -opid,user,command | \
  perl -nae 'if($F[2] =~ /\bloginwindow\b/) { system(
    qq(launchctl bsexec $F[0] su $F[1] -c "launchctl load -w <your_plist>"))
}'

I have found no way to achieve this directly on 10.4. I cheat on 10.4 and just run the thing the LaunchAgent would have run, even though it has a GUI and you're not supposed to be able to do that (you can anyway in 10.4-10.6; you can't in 10.7). On 10.4, the LaunchAgent works correct after the next reboot.

The above code looks for loginwindow processes and uses bsexec to run commands in those contexts. Keep in mind that with Fast User Switching, there can be multiple contexts.

Some useful links:

  • Daemons and Services Programming Guide. You have to read it, but it won't actually answer any of the hard questions. But it will at least give you hints at where everything is located.
  • TN2083. This is a maddening document that raises as many questions as it answers, but is gospel and mandatory reading for anyone entering the abyss of launchd.
  • Starting/stopping a launchd agent for all users with GUI sessions. This has several other useful links and explanation.

IMO, launchd is one of the worst "great ideas" Apple has ever deployed. The idea is very useful, but the API is horrible.

like image 53
Rob Napier Avatar answered Sep 22 '22 17:09

Rob Napier