Launchctl Start Interval - macos

I know when using a plist in the launch daemons folder there is a key called <StartInterval>. I much prefer using launchctl when I can because it is a lot quicker then writing out a whole plist, but I have not been able to figure out how to get the process to restart after it has been killed. I have already read the man page and haven't found anything there. Is there a way? Typically I use the following command:
launchctl submit -l somename -p /path/to/script -o output.txt -e errors.txt
But that will not restart the program if it is killed after any time interval.

launchctl submit should already run the program again if it terminates for some reason:
submit -l label [-p executable] [-o path] [-e path] -- command [args]
A simple way of submitting a program to run without a configura-
tion file. This mechanism also tells launchd to keep the program
alive in the event of failure.
-l label
What unique label to assign this job to launchd.
-p program
What program to really execute, regardless of what fol-
lows the -- in the submit sub-command.
-o path Where to send the stdout of the program.
-e path Where to send the stderr of the program.
To run a program again if it exits with an error, set the SuccessfulExit criteria for KeepAlive to false:
<?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>test</string>
<key>ProgramArguments</key>
<array>
<string>bash</string>
<string>-c</string>
<string>n=$((RANDOM%2));say $n;exit $n</string>
</array>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>StartInterval</key>
<integer>60</integer>
</dict>
</plist>
launchd throttles jobs so it takes about 10 seconds for the program to respawn.

Related

Is there a way to authorize a script running through launchd to use the camera on MacOs

I wrote a script to take a picture with my webcam. I want it to run everytime I unlock my mac, so I created a com.example.selfie.plist file in ~/Library/LaunchAgents/. The sh script is working well from a terminal, my plist is working well when I just write text in a file, but I cannot make the imagesnap command to work through the plist file.
selfie.sh
#!/bin/bash
datetime=$(date "+%Y%m%d_%H%M%S")
imagesnap -q -w 2 "/Users/taccle/Documents/Projets/Selfie/Photos/${datetime}.jpg"
com.example.selfie.plist
<?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.example.selfie</string>
<key>ProgramArguments</key>
<array>
<string>/Users/taccle/Documents/Projets/Selfie/selfie.sh</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Library/Preferences/com.apple.biometrickitd.plist</string>
</array>
</dict>
</plist>
I suppose the issue is coming from Security and Privacy which doesn't allow launchd to access the camera (I'm not sure how I can get the logs when launchd scripts are running).
I found a workaround but I don't like it so much, my plist file calls run_in_command_line.sh which will open a terminal and then run selfie.sh.
#!/bin/bash
osascript -e 'tell application "Terminal"
do script "/Users/taccle/Documents/Projets/Selfie/selfie.sh; exit"
end tell'
It's working well but I would prefer to have only one script and not starting a terminal like this. Do you know if there's any way to give my launchd access to the camera?

Launch agent runs the script every 10 seconds

I have a launch agent that runs a bash script whenever a usb device is connected. I want it to run just once, but when i connect the device, the script keeps running every 10 seconds.
Here is the plist:
<?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>com.example.program</string>
<key>Program</key>
<string>/Users/Peter/Desktop/test1.sh</string>
<key>LaunchEvents</key>
<dict>
<key>com.apple.iokit.matching</key>
<dict>
<key>com.apple.device-attach</key>
<dict>
<key>idProduct</key>
<integer>1476</integer>
<key>idVendor</key>
<integer>1356</integer>
<key>IOProviderClass</key>
<string>IOUSBDevice</string>
<key>IOMatchLaunchStream</key>
<true/>
</dict>
</dict>
</dict>
</dict>
</plist>
Here is the script:
#!/bin/bash
open -a "Spotify";
sleep 11;
I added sleep 11, as I read that the script needs to run at least 10 seconds to let launchd think its done its task. This however doesn't help any.
In terminal running launchctl list com.example.program gives:
"LimitLoadToSessionType" = "Aqua";
"Label" = "com.example.program";
"TimeOut" = 30;
"OnDemand" = true;
"LastExitStatus" = 0;
"Program" = "/Users/Peter/Desktop/test1.sh";
By default, launchd starts programs when their launch conditions are met, and then restarts them if they exit or crash. To keep it from relaunching your script, just add <key>KeepAlive</key><false/> to your .plist (and then unload and reload it). It might also be necessary to add <key>AbandonProcessGroup</key><true/> to keep launchd from killing the "leftover" Spotify process (though I think it'll work without this).

Run terminal command on startup with launchd.plist

I was looking for an answer to my question on stackoverflow and found a thread (https://superuser.com/questions/229773/run-command-on-startup-login-mac-os-x). That's how I found out about launchd.plist and I made one by myself:
<?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>js.leapmotion</string>
<key>OnDemand</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>open</string>
<string>/Applications/Utilities/Terminal.app</string>
</array>
<key>LaunchOnlyOnce</key>
<true/>
</dict>
</plist>
this indeed starts my terminal after booting my mac. But now I want it to navigate to a directory and run the command gulp in there.
This again will do the rest, opens up a localhost and so on...
So in the end I just need to run gulp within an specific directory. That's all. If launchd.plist is not the best way to go, then I'm open for alternatives.
Otherwise I would like to know how I can tell the terminal what commands it should run.
Thanks for hints.
cheers
J
You can use the open command to open Terminal and run a script by using the -a flag. For example, open -a Terminal /path/to/myscript will open a new Terminal window and run myscript. Note that when myscript finishes, the session will terminate (i.e. there's no shell). To change that, you can run bash or whatever your preferred shell is as part of the script.
In your case, I would suggest creating a basic script to do whatever you want Terminal to execute, such as :
#!/usr/bin/env bash
cd /path/to/your/directory
/usr/bin/gulp
Save that (making sure it's executable), and then change your launchd plist to match:
<key>ProgramArguments</key>
<array>
<string>open</string>
<string>-a</string>
<string>Terminal</string>
<string>/path/to/yourscript</string>
</array>

How to open the website at the certain moment using shell?

I am looking for the solution how to open the website at the certain time. Considering the shell programming, it is possible to open website by the command:
$ open http://stackoverflow.com
How to do it at the certain moment if it is possible at all?
You can use crontab to make it.
The crontab is a list of commands that you want to run on a regular
schedule, and also the name of the command used to manage that list.
crontab stands for "cron table," because it uses the job scheduler
cron to execute tasks; cron itself is named after "chronos," the Greek
word for time.
Say You have a script /bin/openURL.sh to open a website,
30 21* * * /bin/OpenURL.sh
means executing it 21 : 30 every day.
More usage about crontab, see http://www.computerhope.com/unix/ucrontab.htm
For one-time jobs (scheduled tasks), at commands are simple to schedule, as demonstrated by John1024's since-deleted answer, but at has drawbacks on OSX:
It must be enabled first; this is a one-time operation: sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist.
You must use sudo (have administrative privileges) to be able to schedule job with at.
If a job produces any output, it will be mailed to the user using mail, as stdout and stderr output (I don't know how to suppress this).
Example: schedule opening http://stackoverflow.com once, at 19:00 (7 PM):
sudo bash -c 'echo "open http://stackoverflow.com" | at 19:00'
Using crontab for periodic jobs is an option on OSX; e.g., to schedule a job that opens http://stackoverflow.com every day at 19:00 (7 PM):
Run crontab -e to open the current user's cronfile in your editor.
Add the following line, save, and close the file:
0 19 * * * open http://stackoverflow.com
If a job produces any output, it will be mailed to the user using mail, as combined stdout and stderr output (I don't know how to suppress this).
However, the official recommendation on OSX is to use launchd for both one-time and periodic jobs:
launchd is very flexible and centralizes all job scheduling; as with crontab, there are system-wide and per-user jobs.
the downside is that the .plist files required to define jobs are cumbersome and non-trivial to create.
Using our previous example:
One-time job: (opens http://stackoverflow.com once, at 19:00 (7 PM))
Create file ~/test.plist (for a one-off job, the location doesn't matter).
Paste the following:
<?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>TestJob</string>
<key>ProgramArguments</key>
<array>
<string>open</string>
<string>http://stackoverflow.com</string>
</array>
<key>LaunchOnlyOnce</key>
<true/>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>19</integer>
<key>Minute</key>
<integer>00</integer>
</dict>
</dict>
</plist>
TestJob uniquely identifies your job.
Setting LaunchOnlyOnce to true ensures that the job is only run once.
From Terminal, run launchctl load ~/test.plist to load the job.
Periodic job: (opens http://stackoverflow.com every day at 19:00 (7 PM))
Create file ~/Library/LaunchAgents/testPeriodic.plist
Note: The location matters: ~/Library/LaunchAgents is where per-user job-definition *.plist files must reside in order to be loaded automatically at every logon.
Paste the following:
<?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>TestJobPeriodic</string>
<key>ProgramArguments</key>
<array>
<string>open</string>
<string>http://stackoverflow.com</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>19</integer>
<key>Minute</key>
<integer>00</integer>
</dict>
</dict>
</plist>
Again, TestJobPeriodic uniquely identifies your job.
Jobs runs periodically by default (i.e., the absence of LaunchOnlyOnce makes the job periodic).
From Terminal, run launchctl load ~/Library/LaunchAgents/testPeriodic.plist to load the job.
For background information, see https://stackoverflow.com/a/23880156/45375.

Shell Script Variable Bug?

Hello generous computerists!
So I have a launchd plist item that is calling the below shell script every thirty seconds. It checks to see if a program is running and if it isn't, it restarts it. Or at least that is what it's supposed to do.
The problem is, even when the process has been killed, the shell script is stating that the process is still running. I think this is because somehow the boolean is not being reset (Or something along those lines). Any help?
n=`ps -ef | grep Intel | grep -v grep | wc -l`
if [ $n -gt 0 ]
then
echo `date` CURRENTLY RUNNING. >> /Library/A_Intel_WATCHDOG/A_Intel_WatchLog.txt
else
echo `date` not running. ATTEMPTING RESTART... >> /Library/A_Intel_WATCHDOG/A_Intel_WatchLog.txt
cd /Library/LaunchAgents/
launchctl load com.Intel.plist
fi
EDIT 1
It has been suggested that adding a 'Keep Alive' argument may be a good solution to my general problem. Any comments?
Here would be my updated plist file which should guarantee that my app keeps running perpetually:
<?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.Intel</string>
<key>OnDemand</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/Library/LaunchAgents/Contents/Intel</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
I would love to hear if people think this is correct or not. Thanks so much!
To troubleshoot the immediate problem, try logging the output of the ps command:
processes=`ps -ef | grep [I]ntel`
if [ -n "$processes" ]
then
echo `date` CURRENTLY RUNNING. "$processes" >> /Library/A_Intel_WATCHDOG/A_Intel_WatchLog.txt
...
I suspect there's something else running (maybe even the script itself) matching Intel; this'll tell you in the log.
However, I think this is irrelevant, because this script seems to be trying to solve a problem that's better solved elsewhere: launchd is entirely capable of monitoring and restarting the processes it manages (it's one of its significant features). Just add
<key>KeepAlive</key>
<true/>
to /Library/LaunchAgents/com.Intel.plist, and launchd will restart the program itself.
BTW, if you for some reason did need to manually restart a launchd-managed process, launchctl load is the wrong incantation -- you want launchd start.

Resources