Creating a timed launchd plist - macos

I'm trying to create a plist for the LaunchAgents folder that will run perpetually and call a shell script every 30 seconds. It started with a template that I got here and that I tried to tailor to fit my needs, but it's still not working. Any help?
<?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_Watchdog</string>
<key>ProgramArguments</key>
<array>
<string>/Library/A_Intel_WATCHDOG/A_WatchDog.sh</string>
</array>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>StandardOutPath</key>
<string>/dev/null</string>
<key>StartInterval</key>
<integer>30</integer>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Thanks so much!

I dropped this in my LaunchDaemons directory, and it worked fine. So, here're some things to check:
Is the .plist getting loaded? Note that the contents of the LaunchAgents folders are loaded at login, so you either need to log out and back in, or manually load it with launchctl load ~/Library/LaunchAgents/com.Intel_Watchdog.plist (or whatever/wherever the file is). You can check its status with launchctl list.
Is /Library/A_Intel_WATCHDOG/A_WatchDog.sh executable? Check the system log (/var/log/system.log) to see if launchd is having trouble launching it.
Is the script running into trouble before it does its job? Try adding date >>/tmp/watchdog.log to it, right after the shebang, and see if anything appears in /tmp/watchdog.log. If it does, try changing the StandardErrorPath and StandardOutPath to an actual file so you can see what's going on as the script runs. Note that you'll have to unload and reload the .plist to get the change to take effect (logging out and back in would do it).
Finally, although it shouldn't cause trouble, your label doesn't follow the standard convention (unless you actually own the domain Intel_Watchdog.com). If this is for local-only use, name it something like local.Intel_Watchdog instead. If you're going to publish this item, you should base the label on a domain you own (in reverse order, with ".Intel_Watchdog" added to the end) -- see Wikipedia's entry on the reverse domain name system.

Related

Using launchd to activate daemon on file owner change

I'm trying to get a "daemon" (really just a script, more than a background process) to activate when a file (specifically, /dev/console) changes owner (i.e., when another user takes control of the console) on MacOS Mojave.
I'm trying to do this by running launchd and having it watch that file for changes. I tried doing this with WatchPaths, as in the script below, but apparently that only notices "creating, removing and writing to this file", not chown. Script is below, along with more background story. Any ideas on how to do this?
<?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>LoginScripts.blockyoutube.sh</string>
<key>ProgramArguments</key>
<array>
<string>/Users/Shared/blockyoutube.sh</string>
</array>
<key>WatchPaths</key>
<array>
<string>/dev/console</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/var/log/blockyoutube.log</string>
<key>StandardErrorPath</key>
<string>/var/log/blockyoutube.log</string>
</dict>
</plist>
Backstory
What I'm really trying to do is block my kids' accounts from YouTube ... but not my wife's account on the same computer. In theory System Preferences->Parental Controls should do this fine — which it does ... until someone launches Chrome and it backchannels the DNS lookup to 8.8.8.8.
The only way I've figured out to work around this is to not let the OS DNS query fail, so Chrome doesn't attempt to do that, so I'm updating /etc/hosts to point to localhost and flushing DNS whenever the console owner changes. Other solutions to this backstory are also welcome, but it does seem that there should be a way to make launchd watch for change in owner of a file.

MacOS: Use getxattr/setxattr from a Finder Sync Extension

I want to use setxattr/getxattr from a Finder Sync Extension on OSX 10.12.6, but the calls fail with errno==1, which is EPERM. Finder sync extensions run in a sandbox, so I guess I need to request permissions. No amount of googling and documentation browsing uncovered information so far.
The files I want to access are owned by myself, and setting attributes with the xattr command line utility succeeds and produces the expected result.
So the question is: Which permissions/entitlements do I need to give the sandbox, or is this possible at all?
I basically want to store the sync status in the extended attributes (clean, modified, syncing) and select the correct badge for requestBadgeIdentifierForURL based on that. A lower priority non-sandboxed process goes over files and updates the attributes.
The alternative would be to use a separate database to store sync status and I'm going to use that if the xattr doesn't work out.
Edit: Added entitlements file
<?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>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.temporary-exception.files.absolute-path.read-write</key>
<true/>
<key>com.apple.security.temporary-exception.files.home-relative-path.read-write</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>
The original entitlements file that comes with the sample is just
<key>com.apple.security.files.user-selected.read-only</key>
which didn't work either.
I added a test project to GitHub https://github.com/JensRestemeier/SyncExtensionTest
You are not specifying the path in the entitlement dic.
This is what it should look like:
<key>com.apple.security.temporary-exception.files.absolute-path.read-write</key>
<array>
<string>/</string>
</array>
This will give you access to all folders on the system.

Launchd runs with manual "launchctl start", but not on StartCalendarInterval

I have a very simple Launch Daemon, com.daily.vocab.plist, which simply runs a basic script. It is supposed to run every day at a certain time (using StartCalendarInterval), but I can't get that to happen. Many posts online are saying it runs a minute or two off, but for me it just never runs.
I have been setting the run time to be 5 minutes in the future while I am testing, and now have it set to run at the 0th second of every minute, just so I can get it to work. Once it's working, I will set it to my desired daily run time.
As advised in this tutorial, it is saved in /Library/LaunchDaemons. I loaded it manually with launchctl load /Library/LaunchDaemons/com.daily.vocab.plist. I do in fact see it has loaded when I run launchctl list. When I manually tell it to run with launchctl start com.daily.vocab, it works immediately as expected. The only issue is that the StartCalendarInterval seems to be ignored. I am on Mavericks on my Macbook.
Here is the file: com.daily.vocab.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.daily.vocab</string>
<key>Program</key>
<string>/Users/MGS/developer/projects/vocab-sms/scripts/DEvocab.sh</string>
<key>StartCalendarInterval</key>
<dict>
<key>Second</key>
<integer>0</integer>
</dict>
</dict>
</plist>
Ideally, I believe I want it to run at 7:15am every day making the StartCalendarInterval section be instead:
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>7</integer>
<key>Minute</key>
<integer>15</integer>
</dict>
If you could even share an example of a LaunchDaemon you got to work using StartCalendarInterval and every step you made to make it work (e.g. running launchctl load x.x.x.plist), that would be really helpful!
Solution: This local daemon should actually be a user agent, so it needed to be saved in and loaded from the ~/Library/LaunchAgents directory. From there, I also needed to unload the agent and reload the agent.
NOTE: Daemons/Agents do not automatically update in launchd until you unload/load. You can't just save the updated .plist and expect it to work!
launchd plists saved in /Library/... are daemons / agents in the local domain and have to be loaded with sudo. Without sudo you're loading the daemon in the user domain which doesn't match the actual path.
Since you are calling a script in the user domain anyway, save the script in ~/Library/LaunchAgents (it's not a daemon). The plist syntax is supposed to be correct.
will have to change the permission for the bash file
chmod u+v /Users/MGS/developer/projects/vocab-sms/scripts/DEvocab.sh

Converting cron to launchd - MAILTO

Migrating from an old mac to a new one.
Trying to migrate the user crontab I had on the old mac.
Now I know I can probably get cron to run by creating /etc/crontab - but given that apple has deprecated it in favour of launchd - I thought I'd take a swing at migrating my crontab to launchd plist files. Always fun to learn something new :)
The crontab isn't that hard - I tend to set up shell scripts that do the work and then just call them at scheduled times.
I can call these fine from the plist at the same times - no issues.
But - at the top of my crontab I had MAILTO=my-gmail-email-address - so that instead of sending mail to the local user on the box's mail spool it sent them to gmail for me.
I can't see that you can configure this for a launchd plist file.
So - before I go modify all my scripts to redirect all output to tmp files then mail the tmp file (would have to do this in quite a few scripts) - is there a way to do this at the launchd level?
I'm afraid launchd(8) does not support mailing of stdout/stderr out of the box. Here's a workaround:
Redirect output via StandardOutPath and StandardErrorPath to files in a dedicated directory. Then setup a job which mails every file in this directory. Trigger this job with the QueueDirectories key. Make sure this script removes the files after mailing them.
one way to convert to launchd is the lazy way (how i do it)
You pay $0.99 for Lingon from the app store; then you can just fill out a few fields and it makes the launchd...
otherwise:
a launchd would look like this
<?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>name of launchd</string>
<key>ProgramArguments</key>
<array>
<string>[terminal command to execute]</string>
</array>
<key>RunAtLoad</key>
<[(true)/(false)]/>
<key>StartCalendarInterval</key>
<dict>
[any of these options are removable]
[for everyday remove the Day and Weekday tags]
<key>Day</key>
<integer>[day of the month]</integer>
<key>Weekday</key>
<integer>[day of the week 0-7 - (sunday=0);]</integer>
<key>Hour</key>
<integer>[hour of day (military time)]</integer>
<key>Minute</key>
<integer>[minute]</integer>
</dict>
</dict>
</plist>
any of the [] are either comments (must be removed) or a list of options
Use of the launchctl command would be used to mount the launchd

My mac osx launched plist won't run

it looks like it loads but has a status of 1 when using launchctl list
and using launchctl start ... it says No such Process...
i have it saved in /Users/IMG/Library/LaunchAgents.
The sh script runs fine.
the logging doesn't show anything - no file created..
I am very new to plist so please forgive ignorance.
<?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.IMG.shed</string>
<key>ProgramArguments</key>
<array>
<string>/Users/IMG/2012/Dropbox/Dev_2012/Java/sh_IMG.sh</string>
</array>
<key>StandardOutPath</key>
<string>myjob.log</string>
<key>StandardErrorPath</key>
<string>myjob.log</string>
<key>Debug</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>60</integer>
</dict>
</plist>
The first thing I thought was the process does not have permission to create the standard output log file (although I imagine the default value for working directory for a personal agent would be the user's home directory). There is an optional property key for WorkingDirectory - perhaps try setting that to see if anything changes.
Reference: Launchd.plist man page
In XCode 4.5.2, under the Product menu, you need to pick Edit Scheme. You will see the manage schemes box appear with several schemes. One of these is called Run <ProjectName>. Click the checkbox next to Working Directory Use custom working directory and point that to the path where your plist is at.
This elaborates on the answer given by unhillbilly. So thanks unhillbilly for steering me towards the Working Directory.

Resources