I have an app service I want to start at system startup with a plist file:
<!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.my.app.ident</string>
<key>ProgramArguments</key>
<array>
<string>/Users/me/Desktop/MyApp/App</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/me/Desktop/MyApp/logfile.log</string>
<key>StandardErrorPath</key>
<string>/Users/me/Desktop/MyApp/logerr.log</string>
<key>UserName</key>
<string>me</string>
</dict>
</plist>
This has been created with
sudo chown root:wheel /Library/LaunchDaemons/com.my.app.ident.plist
and permissions
sudo chmod a+x /Library/LaunchDaemons/com.my.app.ident.plist
and then loaded:
sudo launchctl load -w /Library/LaunchDaemons/com.my.app.ident.plist
The application has permissions like:
-rwxr-xr-x 1 me staff 54755728 29 Nov 12:46 App
Which runs fine but is not starting up with the system - it just logs errors to logerr.log repeating:
Couldn't memory map the bundle file for reading.
A fatal error occured while processing application bundle
Failed to map file. open(/Users/me/Desktop/MyApp/App) failed with error 1
Failure processing application bundle.
These errors stop when the user "me" signs in and then the service starts working. I need it to work without "me" signing in.
any ideas?
From discussion in the comments, we have narrowed it down to a path issue. The exact mechanism preventing access isn't 100% clear to me here, but pre-login is a fairly locked down environment, so I'm not terribly surprised it doesn't work running from your user's desktop folder.
I suspect that in your particular case it's down to the consent system: the logged-in user needs to grant each process access to certain directories such as Desktop
, Documents
, Downloads
, etc., and as there is no user logged in, there will be no consent on record.
If your executable was inside an .app bundle, app translocation would be an additional concern.
The solution is to install launch daemon or global launch agent binaries system-wide. If they're part of an .app bundle, install the app in /Applications
(this will also avoid app translocation issues). Otherwise, a "good" location is /Library/Application Support/[Your-Application]/
.
Incidentally, if you're installing your daemon from a GUI app, on macOS 12 'Monterey' or older, SMJobBless
is an even better solution than manually picking a location and dropping a plist into /Library/LaunchDaemons
.
For macOS 13 'Ventura' and newer, take a look at the section about daemons and agents in the WWDC22 'What's new in Privacy' session and the new SMAppService
APIs available there.