Wednesday, August 31, 2005

Mac OS X as an NFS Client

I'll discuss the changes necessary to mount NFS filesystems onto a Mac OS X machine. This was originally written in the 10.1 days, but is still applicable on 10.4.2 (non-server versions tested).

The example filesystem used here will be called /exported/path from the server nfsserver. It will be mounted to /private/mnt. You will obviously want to change these to something useful and sane for your situation.

Mounting NFS filesystems on OS X can be done simply by running:

sudo mount nfsserver:/exported/path /private/mnt

This is, however, temporary (it won't live through a reboot). In order to have the system deal with mounting it for you, you could add that mount command to an rc script or create a startup script in /Library/StartupItems. The best way, however, is to add the information to NetInfo, and let the automounter handle everything.

In a nutshell, a new directory is added to NetInfo, called /mounts, and subdirectories under that specify the remote filesystems to mount.

NetInfo Changes, Graphical-Style

  1. To accomplish this in Aqua, run NetInfo Manager (located in /Applications/Utilities) and authenticate as an administrator (the little lock at the bottom of the window).
    Authenticate lock
    Authenticate lock

  2. We need to create a new directory, so click on the left-most directory (called simply, /), and create a new directory (through the button, menu option, or shortcut Cmd-N).
    This will create a new directory called new_directory, which we need to rename.
    root in the directory browser
    root in the directory browser

    Ways to create a directory
    Ways to create a directory

  3. In the bottom part of the window, double-click on new_directory in the Value(s) column, which will highlight new_directory and place the insertion point there. Simply type mounts to rename it then save changes (Cmd-S or Domain menu, and select Save) to update the browser portion of the window.
    Renaming the newly-created directory
    Renaming the newly-created directory

    Now renamed, but not saved
    Now renamed, but not saved

    Now renamed and saved
    Now renamed and saved

    Any mounts the automounter handles will be listed under this new directory in NetInfo. Let's add one.

  4. Click on mounts in the browser, and create a new directory. The value of the name property for each subdirectory in mounts specifies the remote filesystem to be mounted (in our example, nfsserver:/exported/path). Double-click new_directory in Value(s), and enter nfsserver:/exported/path. This specifies what remote filesystem to mount, but nothing else; we need to add a few more properties in this directory.

  5. Under the Directory menu is a command, New Property, which is what we will use to add the properties. Select this command three times, as we'll be specifying the local mount point, mount options, and the mount type.
    Three new properties added
    Three new properties added

  6. Double-click the first new_property and rename it to type; set the value of this property to nfs since we're doing NFS. Change the second new_property to opts, and set the value to a blank (delete what is currently there, also see the note about opts at the end, especially if you experience problems). Change the third new_property to dir and set its value to /private/mnt.
    Properties are now set
    Properties are now set

  7. Save changes. At this point, all necessary information has been loaded into NetInfo for automount to take care of the NFS mount. The only thing left is to inform the automount process that things have changed.

This can, of course, be repeated for other NFS mounts. Run through the steps for each one, then do the final step (notifying automount) after all the mounts have been entered.

NetInfo Changes, Command Line
Adding an NFS mount point via the command line is actually quite simple, once you know the secret. It involves four simple steps, one to create the new NetInfo entry, and three to add the three new properties to that

  1. To create the new entry, run

    sudo nicl . -create /mounts/nfsserver:\\/exported\\/path

    Since NetInfo uses the / to separate path components, and we have / characters in the entry we want to create, they have to be escaped.
    This is done with the backslash, \, and since we are running in a shell, we need to double them up. After the shell is done examining the command, the string \\/ becomes \/ which is what we need to pass to nicl. If we don't use any backslashes, nicl will end up creating an entry /mounts/nfsserver: which has a subdirectory exported and that would have a subdirectory path. This is definitely not what we want.
    Basically, double-backslash the forward slashes in the NFS server's path (/exported/path), but not the NetInfo path (/mounts/).

  2. Now we need to add the three properties which tell automount about this entry. We need type which we set to nfs; opts, set to an empty string (but see the note about opts, below, if you have problems); and dir, set to the local mount point, /private/mnt. This is done:

    sudo nicl . -append /mounts/nfsserver:\\/exported\\/path type nfs
    sudo nicl . -append /mounts/nfsserver:\\/exported\\/path opts ""
    sudo nicl . -append /mounts/nfsserver:\\/exported\\/path dir /private/mnt

    The interesting thing to note is /private/mnt doesn't have any escaped forward slashes. This is due to the data being given to nicl in this case is a value, not a NetInfo path, so we needn't do any escaping this time. These commands simply append the given property to our newly-created NFS entry, and give those properties appropriate values.

  3. The last step is to notify automount that there are changes.

As with the graphical version, this can be repeated for all necessary NFS mounts you need to have on your OS X machine. Add them all, then notify automount.

Final Step: Tell automount
The automount process now needs to be told that new information is available for it to use. You can either simply reboot, or run the following in Terminal:

sudo kill -1 `cat /var/run/`

This will send a HUP signal to the automount process; note those are backticks, not the normal single quote marks. A HUP causes automount to unmount anything not busy, reread configuration, and start anew.

A Few Notes to Know

  • Local mount point, availability
    The first thing to note is the local mount point (once automount takes it) becomes a symlink. It should point to /automount/private/mnt, as that's where automount puts all of its mount points. Then, when the symlink is accessed, automount will live up to its name by automatically mounting the proper NFS server's filesystem. This is one reason why using automount is better than a static mount in some startup script: if the NFS server is down, it won't matter until you try to access the mount; with a static mount, booting up the client will take several minutes while it times out waiting for the down server.

  • opts
    The other thing to note is, if your NFS server requires a client to be coming from a privileged network port (less than 1024), you will need to add -P to the opts property, instead of the empty string. You can also modify the server to allow 'insecure' ports, but using -P doesn't require root access to the server.
    This will be the case with certain BSD-based servers and some Linux ones as well. If the local mount point becomes a symlink (as discussed above), but doesn't have any of the files expected from the server, try adding the -P option, then tell automount. If the mount still doesn't work, there are other issues to deal with (a full NFS troubleshooting discussion is beyond the scope of this document).

  • Viewing /mounts from the command line
    If you want to look at what's currently in /mounts from the command line, run

    nidump -r /mounts .

    This will dump out the information recursively (what's in /mounts, and all the information pertaining to it). It should look something like

    "name" = ( "mounts" );
    CHILDREN = (
    "dir" = ( "/private/mnt" );
    "name" = ( "nfsserver:/exported/path" );
    "type" = ( "nfs" );
    "opts" = ( "" );