I have a Go program that is supposed to run as a daemon with minimal front-end for the user (just an icon in the system tray.)
The fact that it's written in Go doesn't really matter much, the main issue I have is getting a binary (that is already running) to run at startup on a Mac.
I can set the binary to run at startup like so:
cp daemon.plist ~/Library/LaunchAgents/daemon.plist
(cp the plist into the LaunchAgents directory)
launchctl load -w ~/Library/LaunchAgents/daemon.plist
(then load the plist with launchctl.)
And that works fine. The only issue is that launchctl load it starts another instance of the binary that is already running. I want to be able to enable (and disable) running the binary at startup for the binary that is running, without starting another instance of it.
And here's the .plist file if you want to see it:
<?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>daemon</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/Daemon.app/Contents/MacOS/daemon</string>
</array>
<key>ProcessType</key>
<string>Interactive</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
I figured it out.
So first, the binary is running. It starts out as not enabled to run at startup. To initialize, you cp the plist to the ~/Library/LaunchAgents/ directory:
cp daemon.plist ~/Library/LaunchAgents/daemon.plist
And the plist looks 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>daemon</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/Daemon.app/Contents/MacOS/daemon</string>
</array>
<key>ProcessType</key>
<string>Interactive</string>
<key>RunAtLoad</key>
<false/>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
NOTE: The RunAtLoad key is set to false.
Then we load it into launchctl:
launchctl load -w ~/Library/LaunchAgents/daemon.plist
It shouldn't load since RunAtLoad is set to false.
Then, we can enable and disable running at startup like so:
To enable:
Set RunAtLoad to true
cp the plist over
To disable:
Set RunAtLoad to false
cp the plist over
Kind of hacky, but it works.
Related
I have a launch daemon plist that runs a python script. The problem is that it is unable to run the script because it does not have access to python.
I am trying to make a launch daemon to change mac address (https://github.com/feross/SpoofMAC)
Here is the plist file in /Library/LaunchDaemons:
<?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>MacSpoof</string>
<key>ProgramArguments</key>
<array>
<string>/Users/username/.asdf/shims/spoof-mac.py</string>
<string>randomize</string>
<string>en0</string>
</array>
<key>StandardOutPath</key>
<string>/Users/username/Projects/MAC/out.log</string>
<key>StandardErrorPath</key>
<string>/Users/username/Projects/MAC/err.log</string>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
The Error Log reads:
No version is set for command spoof-mac.py
Consider adding one of the following versions in your config file at
python 3.11.1
My tool_version does include Python, how can I make this work?
Okay, I kinda got it working. I moved the plist file from /Library/LaunchDaemons to /Library/LaunchAgents and it works because LaunchAgents run after the user is logged in. It's not exactly what I wanted, but it works.
Here is my file, I am not getting anything logged, although the loading is apparently successful, as I can see it running with the list command;
<?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.whtDaily.gexUW</string>
<key>ProgramArguments</key>
<array>
<string>/Users/x/Dropbox/ai/getData.sh</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>22</integer>
<key>Minute</key>
<integer>15</integer>
</dict>
<key>RunAtLoad</key><true/>
<key>StandardErrorPath</key>
<string>/Users/x/Dropbox/ai/logs/daily.err</string>
<key>StandardOutPath</key>
<string>/Users/x/Dropbox/ai/logs/daily.out</string>
</dict>
</plist>
I am also not clear if I need to running 'start' after load, or does that happen automatically since I have the 'RunAtLoad' key set to true? I have tried calling start after load, and not with no luck.
This plist file is in the /Library/LaunchAgents directory and I am calling with load and unload with sudo.
The sh file was not executable.
chmod +x getData.sh
did the trick.
I want to rsync my /var/repo backup to a remote machine when it changes.
I made a ssh key pairs to make my machine can ssh login to remote without password(ignore details).
I added a file com.ph.rsync2.plist in ~/Library/LaunchAgents.
The content is
<?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.ph.rsync2.plist</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/rsync</string>
<string>-avz</string>
<string>--rsh=ssh</string>
<string>/var/repo</string>
<string>flora#192.168.19.28:/var/ph_backups/</string>
</array>
<key>WatchPaths</key>
<array>
<string>/var/repo</string>
</array>
</dict>
Then I launchctl load com.ph.rysnc2.plist.
When /var/repo has any change, it will trigger rsync to work
but I always get the error log in Console.app
It reads like
11/3/15 2:15:26.399 PM com.apple.xpc.launchd[1]:
(com.ph.rsync2.plist) Service only ran for 1 seconds. Pushing respawn out by 9 seconds.
And I tried to move the rsync commands to a script, then let launchd exec my script. but it's still the same
I can't figure out which part of settings make all these fail.
Anyone can give me a clue?
Comments will mess up the formatting, so I'll post how to setup the StandardErrorPath key as an answer.
Modify your job definition 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>com.ph.rsync2.plist</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/rsync</string>
<string>-avz</string>
<string>--rsh=ssh</string>
<string>/var/repo</string>
<string>flora#192.168.19.28:/var/ph_backups/</string>
</array>
<key>StandardErrorPath</key>
<string>/tmp/com.ph.rsync2.plist.stderr</string>
<key>WatchPaths</key>
<array>
<string>/var/repo</string>
</array>
</dict>
</plist>
Check the file /tmp/com.ph.rsync2.plist.stderr after reloading and starting the job.
i did create an XPC service, that runs in background and creates periodical tasks
placed it into path
/Users/Peter/Library/Application Support/AGENT TEST APPS/CS Agent.xpc
i can run it, by directly executing the file
i placed a .plist it into the LaunchAgents, refereeing to the executable
<?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>Debug</key>
<true/>
<key>Label</key>
<string>com.company.CS-Agent</string>
<key>KeepAlive</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>Program</key>
<string>/Users/Peter/Library/Application Support/AGENT TEST APPS/CS Agent.xpc</string>
</dict>
</plist>
but it doesn't launch upon startup as it should
UPDATE
did try to load manually
Peters-MacBook-Air:LaunchAgents Peter$ launchctl load com.company.CS-Agent.plist
com.company.CS-Agent: Already loaded
But i don't see it in activity monitor, nor any output it should produce (create files)
when i do launchctl list i see
- 13 com.company.CS-Agent
Launch daemon worked as it should but now the problem is it keeps loading the same shell script and I can see multiple entries for the same rule. sudo ipfw list. How can this be prevented?
<?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.apple.ipfw</string>
<key>OnDemand</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>/usr/local/ipfw.apple.startup.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>ServiceDescription</key>
<string>Apple IPFW Filter Rules</string>
<key>StandardErrorPath</key>
<string>/var/log/ipfw.apple.stderr</string>
<key>StandardOutPath</key>
<string>/var/log/ipfw.apple.stdout</string>
<key>UserName</key>
<string>root</string>
</dict>
Use LaunchOnlyOnce key in plist file.
LaunchOnlyOnce :
This optional key specifies whether the job can only be run once and only once. In other words, if the
job cannot be safely respawned without a full machine reboot, then set this key to be true.