On OS X 10.9, I'm running a script (e.g., ~/bin/run.sh
) via my user crontab (added using crontab -e
). This script, under some specific conditions (not related to this question), will run the following command to launch a menubar application:
launchctl load /Library/LaunchAgents/com.opendns.osx.RoamingClientMenubar.plist
When I run this command (either ~/bin/run.sh
or the launchctl
statement above directly) from the command line normally, the menubar item launches fine.
When this command is run via crontab (again, directly or via ~/bin/run.sh
), I receive the message nothing found to load
in the cron output (in my mail).
Question: why does this fail when run via cron but not when run on the command line?
I have tried executing it via cron in the simplest way possible:
* * * * * launchctl load /Library/LaunchAgents/com.opendns.osx.RoamingClientMenubar.plist
This doesn't work (I get nothing found to load
).
I have tried emulating the cron environment:
-
Capturing the cron environment by having this execute in cron:
env > ~/cronenv
-
Then opening a shell with this environment:
env - `cat ~/cronenv` /bin/sh
-
And finally running the command:
launchctl load /Library/LaunchAgents/com.opendns.osx.RoamingClientMenubar.plist
It runs find in these conditions (I wouldn't expect it to, if something in the cron environment is the culprit).
I have tried running it from crontab as sudo
. Nope (nothing found to load
).
I have tried running it from crontab with launchctl load -F
and launchctl load -w
. No luck (nothing found to load
).
Permissions on the plist file are:
-rw-r--r-- 1 root wheel 561 Apr 13 20:55 /Library/LaunchAgents/com.opendns.osx.RoamingClientMenubar.plist
What's going on?
(BTW, I know it may seem silly to run a script with a launchctl job from within cron, but because it is run within a shell script it's prevented from being a 100% launchctl-controlled process.)
Update: as requested here is the script that is being run (I've been calling it ~/bin/run.sh
), the line in question being #29, and here is the contents of the plist.
Update: the specific solution that works for me, based on @mateusz-szlosek's suggestion to use bsexec
, looks like this:
sudo launchctl bsexec "$(ps -axwww | grep Dock | grep -v grep | awk {'print $1'};)" sudo -u $USER launchctl load /Library/LaunchAgents/com.opendns.osx.RoamingClientMenubar.plist
The first sudo
is required otherwise the error Couldn't switch to new bootstrap port occurs. The second sudo
is to execute launchctl
as $USER
. The first argument to bsexec
is a parent process ID who's context will be used to launch the new process. $(ps -axwww | grep Dock | grep -v grep | awk {'print $1'};)
returns the pid
of the Dock process, which loads somewhat early in the launchd hierarchy, but under user context.
Best Answer
The problem is execution context and mach bootstrap in OS X (more info on Apple documentation worth reading). You need to simulate execution from proper context. In OS X it's done using
launchctl bsexec
command. From TheDarkKnight's answer to Starting/stopping a launchd agent for all users with GUI sessions you have:On OS X 10.11 and Later
From the comment by vrrathod about OS X 10.11, El Capitain, use: