8

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.

John Bowers
  • 1,695
  • 1
  • 16
  • 26

1 Answers1

9

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!).

tom metge
  • 106
  • 2
  • I ended up using getmntinfo(), which worked well. I still think getfsent() should have returned more than just the first mounted file system. Perhaps that is a mavericks bug. – John Bowers Nov 11 '13 at 22:29
  • 1
    It very well could be a bug in Mavericks - I'll have to check it out. For posterity, I've gone ahead and open-sourced a component of unDock that abstracts DiskArbitration, including listing mounted volumes. It's available on GitHub: http://tommetge.github.io/VolumeManager/ – tom metge Nov 13 '13 at 17:22
  • getmntinfo() is not reentrant/threadsafe. The implementation of getmntinfo() is a wrapper around getfsstat(). getfsstat() is documented and is reentrant/threadsafe, and so is a better choice for anything other than simple single-threaded utilities. – Joe Apr 07 '14 at 00:38