macosposixosx-mavericksbsddiskarbitration

How to iterate all mounted file systems on OSX


I am interested in iterating all mounted file systems on OSX (currently running 10.9 Mavericks). I am looking for something similar to getmntent() or the output of the mount shell command (although I want to do it from objective C, so parsing the output of a shell command is obviously not optimal).

I have been looking a bit at the disk arbitration framework, and it appears that I could be notified about mount and unmount events using this framework. I may be missing something there, but it isn't clear to me if there is a way to iterate existing mounted file systems using Disk Arbitration.

I have explored using getfsent() which seemed like it would provide a solution, but after testing I discovered that I am not getting more than one entry from iterating getfsent(). See the following code:

struct fstab* fsentry;
setfsent();
fsentry = getfsent();
while(fsentry)
{
    //do something with fsentry
    fsentry = getfsent();
}
endfsent();

The only entry I am getting here is for the / file system. The second time I call getfsent() it returns NULL, as if there are no more entries. The mount command shows me several others including a mounted cifs/smb file system:

/dev/disk0s2 on / (hfs, local, journaled)
devfs on /dev (devfs, local, nobrowse)
map -hosts on /net (autofs, nosuid, automounted, nobrowse)
map auto_home on /home (autofs, automounted, nobrowse)
//user@<ip address>/public on /Volumes/public (smbfs, nodev, nosuid, mounted by user)

So it seems like getfsent() starts doing what I expect, but for some reason stops?

My question in summary is: What is the best way to iterate file systems on OSX?

If anyone has an answer to why I am only getting one result from getfsent() I would also be interested in that.


Solution

  • There are a couple of different ways to enumerate mounted volumes on OS X, each a using different set of APIs. At the highest (and easiest) level, you can use NSFileManager's mountedVolumeURLsIncludingResourceValuesForKeys:options:. Here's an abbreviated example:

    NSArray *urls = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:@[NSURLVolumeNameKey] options:0];
    for (NSURL *url in urls) {
      NSLog(@"Volume mounted at: %@", [url path]);
    }
    

    The next option takes us back to C territory - and you were so close with your original approach. On OS X (and BSD), there isn't getmntent(); instead, there is getmntinfo(), which is strikingly similar. To list mounted volumes via getmntinfo(), you can do the following:

    struct statfs* mounts;
    int num_mounts = getmntinfo(&mounts, MNT_WAIT);
    if (num_mounts < 0) {
      // do something with the error
    }
    
    for (int i = 0; i < num_mounts; i++) {
      NSLog(@"Disk type '%s' mounted at: %s", mounts[i].f_fstypename, mounts[i].f_mntonname);
    }
    

    I've used both of these APIs side-by-side since the release of 10.6. getmntinfo() is always more complete than [NSFileManager mountedVolumeURLsIncludingResourceValuesForKeys:options:]: the latter will filter the /dev and other filesystems that you may or may not want to know about. It is generally reliable, however, for the disks you plug into your system.

    The purpose behind the DiskArbitration framework is different, as you noticed. DiskArbitration is about monitoring and managing disk assets. With DA, you can get called whenever a new disk is mounted or unmounted. You can also manage those disks by renaming, mounting, unmounting, or ejecting them, as well as inserting yourself in the mount/unmount process - and potentially suspending requests to do the same. But, as you pointed out, it does not provide an interface for listing existing disks. Once you do get your list of mounted volumes, DA is an excellent next stop (depending, of course, on your reason for getting that list!).