Updated on 23 October 2020 - Better solution described in Persistent NFS mount points on macOS.
Intro
In a previous blog post “Automount NFS on macOS” I wrote about how to mount NFS shares. Unfortunately the solution was not reboot proof. On each reboot the OS resets the auto_master
to its default state.
As a workaround I created a script to add the missing lines to the auto_master
. The script needs to be run manually with sudo rights. The PAF-factor is below zero on that one (PAF = partner acceptance factor).
After manually fixing it too often I finally found a way to automate it. It’s still a workaround for the reset of the auto_master
file but solving that underlying problem is simply out of my reach.
I found a way to run the script with sudo rights at boot time. As a bonus it’s a native macOS feature. Enter the world of launchd.
launchd
The partial Wikipedia launchd definition:
“launchd is an init and operating system service management daemon …”
In other words it’s a kind of taskrunner that comes with the operating system (detailed info on the launchd.info) and Wikipedia).
Some tasks run as a local user (agents) and other task run as root user (daemons). The tasks are defined in plist files and the location of these plist files determines with what credentials they run.
An overview of the launchd
directories:
Type | Location | Run on behalf of |
---|---|---|
User Agents | ~/Library/LaunchAgents | Currently logged in user |
Global Agents | /Library/LaunchAgents | Currently logged in user |
Global Daemons | /Library/LaunchDaemons | root or the user specified with the key UserName |
System Agents | /System/Library/LaunchAgents | Currently logged in user |
System Daemons | /System/Library/LaunchDaemons | root or the user specified with the key UserName |
In order to run a script with sudo rights we have to call it from a plist-file in the directory ‘/Library/LaunchDaemons’.
plist-file
There are many plist-configuration keys, in our case we only need three:
- Label, defines a unique identifier for the launchd instance
- Program, defines what to start
- RunAtLoad, defines when the job should be run
To run our “workaround” script at boot-time:
- Label, who (the identifier): “org.tisgoud.restore_nfs_mount.plist”
- Program, what, (the script-path): “/Users/[your username]/Scripts/restore_nfs_mount.sh”
- RunAtLoad, when, (time to run): “RunAtLoad”
The plist-file is usually identified by its label. To run it as root it’s created in the directory ‘/Library/Launchdaemons’.
$ touch /Libray/Launchdaemons/org.tisgoud.restore_nfs_mount.plist
The plist-file uses the xml-format.
cat ./org.tisgoud.restore_nfs_mount.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>org.tisgoud.restore_nfs_mount.plist</string>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>/Users/[your username]/Scripts/restore_nfs_mount.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
Modify the path with “[your username]” to wherever your scripts are located. The location above is my personal preference.
As a final step set the file permissions:
$ chmod 644 /Libray/Launchdaemons/org.tisgoud.restore_nfs_mount.plist
Workaround script
In the Automount NFS blogpost I added the script as an update. Since then I renamed the script to “restore_nfs_mount.sh”
The workaround script checks the file ‘/etc/auto_master’ for the string “auto_nfs”, the ‘include’-file with the nfs-mountpoints.
In case the string “auto_nfs” is not found it will be added (») add the end of the file. Not finding “auto_nfs” indicates a reset of the file auto_master
probably caused by a reboot.
Automount is called to update the mountpoints defined in auto_master and now with the mountpoints define in auto_nfs
.
automount reads the /etc/auto_master file, and any local or network maps it includes, and mounts autofs on the appropriate mount points to cause mounts to be triggered. It will also attempt to unmount any top-level autofs mounts that correspond to maps no longer found.
#!/bin/bash
if ! grep '/etc/auto_master' -e 'auto_nfs'; then
echo "/-\t\t\tauto_nfs" >> /etc/auto_master
automount -cv
fi
File permissions:
$ chmod 744 /Users/tisgoud/Scripts/restore_nfs_mount.sh
auto_master
After running the script the “auto_nfs” line is added to the auto_master
file.
$ cat /etc/auto_master
#
# Automounter master map
#
+auto_master # Use directory service
#/net -hosts -nobrowse,hidefromfinder,nosuid
/home auto_home -nobrowse,hidefromfinder
/Network/Servers -fstab
/- -static
/- auto_nfs
auto_nfs
The NFS-shares on my Synology and mountpoints in auto_nfs
:
$ cat /etc/auto_nfs
# Shared family eBook library
/System/Volumes/Data/Synology/calibre -fstype=nfs,nolockd,resvport,hard,bg,intr,rw,tcp,nfc,rsize=65536,wsize=65536 nfs://192.168.200.200:/volume1/calibre
# Access to the Docker volumes
/System/Volumes/Data/Synology/docker -fstype=nfs,nolockd,resvport,hard,bg,intr,rw,tcp,nfc,rsize=65536,wsize=65536 nfs://192.168.200.200:/volume1/docker
# Webserver on my Synology
/System/Volumes/Data/Synology/web -fstype=nfs,nolockd,resvport,hard,bg,intr,rw,tcp,nfc,rsize=65536,wsize=65536 nfs://192.168.200.200:/volume1/web
auto_smb
After writing the “Automount NFS” I was asked if this also workes for SMB shares.
In the same way NFS mountpoints are included in the auto_master
also SMB shares can be mounted.
$ cat /etc/auto_master
#
# Automounter master map
#
+auto_master # Use directory service
#/net -hosts -nobrowse,hidefromfinder,nosuid
/home auto_home -nobrowse,hidefromfinder
/Network/Servers -fstab
/- -static
/- auto_nfs
/- auto_smb
The syntax for the SMB shares is different. A big difference is that you have to add your credentials. These credentials are stored in plain text. Depending on the situation, the risk could be acceptable but in most cases it is not.
I tested it with the following auto_smb
file.
$ cat /etc/auto_smb
/System/Volumes/Data/Synology/calibre -fstype=smbfs ://admin:NotMyRealP%40ssword%21@synology.local:/calibre
# Use the Hex ASCII value %40 for an `@`
# Use the Hex ASCII value %21 for an `!`
In the password all special characters need to be replaced by their Hex ASCII values.
“NotMyRealP@ssword!” => “NotMyRealP%40ssword%21”
In the current version of the workaround script the “SMB” part is not included but can easily be added.
Verify launchd
When all files are in place you can verify the whole chain by running the launchd task manually:
$ launchctl load /Library/LaunchDaemons/org.tisgoud.restore_nfs_mount.plist
No response means no errors, usually a good sign 😉.
With the following command you can check if the task is picked up by launchd:
$ launchctl list | grep 'org.tisgoud.restore_nfs_mount'
- 0 org.tisgoud.restore_nfs_mount.plist
And with that we know the launchd task is running.
The final test would be a reboot to verify the restored mountpoints.
Conclusion
At first I was a bit reluctant to go for the launchd solution but the PAF is 👍. The current solution uses native OS features and should be future proof.
Some food for thought and a possible improvement could be to go for a solution where launchd kicks of a script that would do the mounting directly instead of using automount and auto_master 🤔.