[launchd-dev] launch_msg(): Socket is not connected error in Leopard

Quinn eskimo1 at apple.com
Tue Feb 16 01:39:27 PST 2010


At 19:04 +0530 9/2/10, Arun wrote:
>This daemon writes multiple plist files in /Library/LaunchAgents and 
>tries to load the same for all the users currently logged in.  The 
>loading of the agents is failing with "launch_msg(): Socket is not 
>connected".

Before reading this response, you /really/ need to read and 
understand TN2083 "Daemons and Agents".  It describes the background 
to this problem, and you won't be able to understand my response 
without understanding the key points of that technote first.

<http://developer.apple.com/mac/library/technotes/tn2005/tn2083.html>

You can't just run an agent from an arbitrary context.  There are 
multiple instances of launchd on the system, and each instance can be 
running multiple contexts.  When you run launchctl, you're end up 
talking to one specific context, and that context is determined by 
two things:

A. if you run launchctl as root (specifically, the RUID must be 0), 
you always end up talking to the global context managed by the root 
launchd (PID 1)

B. otherwise, the context is determined by the current Mach bootstrap 
namespace (as described in detail in TN2083)

This present a nasty chicken and egg problem.  You can't load an 
agent in a particular context unless you're already running in that 
context.  This is a well-known gotcha, and it's being tracked by us 
as <rdar://problem/5476420>.

The only fully supported solution to this problem is to force a 
restart.  If that's not acceptable, you have to break the problem 
down as follows:

o upgrade -- There /is/ a reasonable way to handle the upgrade 
scenario.  Most agents are running on behalf of a daemon.  In that 
case you can overwrite the agent on disk and then tell the daemon to 
signal all of its agents to quit.  They will be relaunched by their 
respective launchd's, this time running the new code.  You have to be 
a little careful, but this approach works reasonably well.

o uninstall -- You can handle uninstall in much the same way as you 
handle upgrade.  You have your daemon tell its connected agents about 
the uninstall.  The agents can then run launchctl to unload the job 
from their specific context.

o first install -- There isn't a good way to handle the first install 
case.  You can start the agent in the GUI context that you're running 
in, but starting agents in other existing GUI contexts is tricky.  In 
general I'd recommend you /not/ try to solve this.

To expand on this a little, consider the common case of an installer 
running in the foreground user's context.  From that context, it can 
load the agent for that particular user.  OTOH, non-foreground GUI 
users will have to log out and log back in to pick up the agent. If 
that's a problem (for example, you're installing security software), 
force a restart in this case.

Keep in mind that multiple GUI logins via fast user switching is an 
edge case that 90% of your users will never encounter.

However, if you're installing from a daemon you can't directly load 
any agents.  If restarting isn't an acceptable solution, you have to 
stray into the the stuff we really don't support.  Specifically, you 
can talk to a given launchd context by switching your bootstrap 
namespace to match that of a process running in that context.  You 
can find out all the GUI login sessions using the techniques from 
QA1133 "Determining console user login status".

<http://developer.apple.com/qa/qa2001/qa1133.html>

You can then use launchctl's bsexec command to run commands in the 
context associated with a process in the GUI context.

For example, if you're running as root, and there's a logged in GUI 
user called "apple" whose "loginwindow" process is PID 3073, you can 
run a copy of launchctl in their context with the following command:

# launchctl bsexec 3073 chroot -u apple / launchctl list

[Note that the chroot doesn't actually affect the root directory in 
this command; I'm using it solely to switch the user ID.  In real 
software it would be better to create a tiny helper tool to handle 
this task.]

There are two gotchas with this approach:

o It's /so/ not supported.  It works on current systems (10.5.x and 
10.6.x), and is likely to be compatible with 10.6.x software updates, 
but I can't predict how well it will work beyond that.

o It's very hard to target the context used by pre-login launchd 
agents.  The issue here is that those agents run as root so, when you 
try to adopt the user ID associated with your agents, you end up 
talking to the global context (see point A, above).

Just to repeat, there's only one way to solve the "first install 
problem" that's guaranteed to be compatible in the long term: force a 
restart.  Any other solutions is probably going to require you to 
revisit this issue in the future (hopefully to adopt a nice, 
well-supported API, eh Damien? :-).

S+E
-- 
Quinn "The Eskimo!"                    <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


More information about the launchd-dev mailing list