0

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>
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
agillgilla
  • 859
  • 1
  • 7
  • 22
  • 1
    Change `RunAtLoad` to `RunAtLoad` and start then call `launchctl load ....` and `launchctl start daemon` – georgeok May 31 '19 at 16:38
  • @George Oikonomou That doesn't work. The binary is already running. I don't want to start it manually with launchctl. All I want to do is dynamically enable/disable running a program at startup without restarting the program or creating another instance of it. – agillgilla May 31 '19 at 17:06
  • launchctl should start a new instance if the main process of your software is still around. Are you using any kind of subprocess or forks (daemonize)? – georgeok May 31 '19 at 17:35

1 Answers1

0

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.

agillgilla
  • 859
  • 1
  • 7
  • 22