Launch daemon in MacOs only once on boot - macos

I cant make daemon launches only one time on startup.
I created file /Library/LaunchDaemons/local.gz.startup.plist
Then I run loaded it with launchd command
<?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>local.gz.startup</string>
<key>ProgramArguments</key>
<array>
<string>/etc/rc.local</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
rc.local:
#!/bin/bash
sudo mkdir /Volumes/ESP
sudo mount -t msdos /dev/disk0s1 /Volumes/ESP/
....
sudo umount -f /Volumes/ESP/
exit
This works only when I load it manually with launchd command, not at startup.
I have tried another parameters, but it (rc.local) begins work continuously, it mounts and unmounts /dev/disk0s1.
How can I make it start only once on boot?

Related

Need help getting launch daemon working on macOS

I have a launch daemon that I just can't get to work. It's supposed to run a script every day at 3 AM. The script works and I can run it manually without sudo. See below for the launch daemon (com.rsync.plist) and the output of the commands I ran to start it. If anyone has any ideas why it won't run, I would really appreciate 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>com.rsync</string>
<key>Program</key>
<string>/Users/xserve10/Documents/rsync.sh</string>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
</dict>
</plist>
Xserve-10s-Mac-mini:Documents xserve10$ ls /Library/LaunchDaemons/com.rsync.plist
/Library/LaunchDaemons/com.rsync.plist
Xserve-10s-Mac-mini:Documents xserve10$ sudo launchctl load -w /Library/LaunchDaemons/com.rsync.plist
Password:
/Library/LaunchDaemons/com.rsync.plist: service already loaded
Load failed: 37: Operation already in progress
'''

Mono-service2 and MacOS daemon on startup

I'm trying to make a MacOS agent to launch mono service on startup. The issue is that loaded daemon exits without any errors (no output to console.log, err.log - see agent.plist below), but mono-service2 does not create my.lock file and start a service.
If I click on Start script manually, it runs flawlessly. Any suggestions?
Environment:
MacOS: Catalina 10.15.7
Mono framework: 6.12.0.90
agent load:
launchctl load /Library/LaunchDaemons/agent.plist
agent.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>agent</string>
<key>UserName</key>
<string>me</string>
<key>StandardErrorPath</key>
<string>/Users/me/Desktop/err.log</string>
<key>StandardOutPath</key>
<string>/Users/me/Desktop/console.log</string>
<key>KeepAlive</key>
<false/>
<key>LaunchOnlyOnce</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>Program</key>
<string>/bin/bash</string>
<key>ProgramArguments</key>
<array>
<string>bash</string>
<string>/Applications/my.app/Contents/MacOS/Start</string>
</array>
</dict>
</plist>
Start script:
#!/bin/bash
LOCK_FILE="my.lock"
MONO_DIR="/Library/Frameworks/Mono.framework"
cd `dirname "$0"`
rm -f $LOCK_FILE
$MONO_DIR/Commands/mono-service2 -l:$LOCK_FILE Service.exe
It appears that LaunchDaemon requires bash script to keep running to work properly. We can achieve this by supplying --no-daemon argument on Start script which prevents mono-service2 going background.
Complete Start script:
#!/bin/bash
LOCK_FILE="my.lock"
MONO_DIR="/Library/Frameworks/Mono.framework"
cd `dirname "$0"`
rm -f $LOCK_FILE
$MONO_DIR/Commands/mono-service2 -l:$LOCK_FILE Service.exe --no-daemon

How to set already running binary to run at startup

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.

Luanchd not starting mopidy & UDP listener

I'm trying to write a Launchd script to execute a simple sh script that will 1) launch mopidy 2) mkfifo /tmp/mopidy.fifo 3) pass data from port 5555 into this file using socat.
I've tried setting up a mopidy.plist LaunchAgent that executes a mopidy.sh script file at login. I've verified that the LaunchAgent gets started correctly and that the script has execution permissions. I've also tried the Program Arguments approach by passing the script as a one-liner to /bin/bash, but when I try that I get errors logged saying that its unable to find socat.
mopidy.sh
nohup mopidy;
mkfifo /tmp/mopidy.fifo;
while :; do
socat -d -d -T 1 -u UDP4-LISTEN:5555 OPEN:/tmp/mopidy.fifo;
done
mopidy.plist
<!-- Starts mopidy server -->
<?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.me.mopidy.plist</string>
<key>Program</key>
<string>/Users/me/.config/scripts/mopidy.sh</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/me/logfile.log</string>
<key>StandardErrorPath</key>
<string>/Users/me/error_logfile.log</string>
</dict>
</plist>
I am able to execute the bash script normally without error from the command line, however it doesn't seem like the service is able to because the /tmp/modipy.fifo file never gets created and the listener is never made. The logfile and error_logfile are never populated either.
I was able to get it working by including environment variables. I don't fully understand this, but everything works now with the following:
<!-- Starts mopidy server -->
<?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.me.mopidy.plist</string>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin</string>
</dict>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/me/.config/scripts/mopidy.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/me/logfile.log</string>
<key>StandardErrorPath</key>
<string>/Users/me/error_logfile.log</string>
</dict>
</plist>

Start docker-machine On Boot

I have a docker-machine called default. I am trying to get it to start upon boot. I can do it upon log in but I need it without having to log in.
I have put the following file in both /LaunchAgents/com.docker.machine.default.plist and /LaunchDaemons/com.docker.machine.default.plist, both of which aren't working.
/Library/LaunchDaemons/com.docker.machine.default.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>RunAtLoad</key>
<true/>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin</string>
</dict>
<key>Label</key>
<string>com.docker.machine.default</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/docker-machine</string>
<string>start</string>
<string>default</string>
</array>
</dict>
</plist>
I have also run sudo chmod 640 on both files in case there was a permission issue as described here.
When I run, sudo launchctl load -w com.docker.machine.default.plist as described in the tutorial I get "service already loaded".
The service is definitely not running as I have checked using docker-machine ls and docker-machine status default and the machine is stopped on start up.
Update
I have added logging into my LaunchDaemon and get the following output.
Host does not exist: "default"
I then run docker-machine ls and I get:
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
default - virtualbox Stopped Unknown
As you can see the machine is there. If I run docker-machine start default manually, it starts up fine...
Starting "default"...
(default) Check network to re-create if needed...
(default) Waiting for an IP...
Machine "default" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.
Services from /Library/LaunchDaemons by default run as root user. root have no any docker machines. You can specify user (jenkins in my case) as
<key>UserName</key>
<string>jenkins</string>
For more documentation you can use man launchd.plist.
Full org.vovkasm.docker-machine.plist that I'am use for jenkins user:
<?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>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin</string>
</dict>
<key>Label</key>
<string>org.vovkasm.docker-machine</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/opt/docker-machine/bin/docker-machine</string>
<string>start</string>
<string>default</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>/usr/local</string>
<key>UserName</key>
<string>jenkins</string>
</dict>
</plist>

Resources