On 09/25/2016 03:12 PM, Ole Streicher wrote: > I have the problem that in a package (casacore) there is basically the > following code: > > ---------------------------------8<------------------------------------ > #include <sys/vfs.h> > #include <linux/nfs_fs.h> > > Bool Directory::isNFSMounted() const > { > struct statfs buf; > if (statfs (itsFile.path().expandedName().chars(), &buf) < 0) { > throw (AipsError ("Directory::isNFSMounted error on " + > itsFile.path().expandedName() + > ": " + strerror(errno))); > } > return buf.f_type == NFS_SUPER_MAGIC; > } > ---------------------------------8<------------------------------------ > > The linux include subdir is obviously only available on Linux archs, not > on kfreebsd or hurd. From the "statfs" manpage, I had the impression > that the second include is just not needed; however then NFS_SUPER_MAGIC > is not available. > > So how do I do this portable (so that I could forward it to upstream as > well)?
There's no easy way to make that portable. NFS_SUPER_MAGIC is Linux- specific. statfs() is actually non-portable, and on e.g. FreeBSD kernels the structure is slightly different (and you need to include sys/param.h and sys/mount.h instead). Also, at least in a FreeBSD 10.3 VM of mine, the f_type field on an NFS mount is 0x3a - but I have no idea whether that's guaranteed to be stable or is just some number assigned dynamically. OTOH, struct statfs on FreeBSD has f_fstypename, which is "nfs" for NFS mounts. Also, f_flags on FreeBSD has MNT_LOCAL if it's a local mount, so you might want to check that instead. On Hurd I have no idea, I've never tried NFS there (but support exists). So the only thing you can actually do realistically is to use lots of #ifdefs, because file system detection is inherently unportable. Basically, you'd need to do something like (untested, written down in this email client): ---------------------------------------------------------- static int is_on_nfs (const char *file); #ifdef __linux__ #include <sys/vfs.h> #include <linux/nfs_fs.h> int is_on_nfs (const char *file) { struct statfs buf; if (statfs (file, &buf) < 0) return -1; return buf.f_type == NFS_SUPER_MAGIC; } #elif defined(__FreeBSD_kernel__) #include <sys/mount.h> #include <sys/param.h> #include <stdlib.h> int is_on_nfs (const char *file) { struct statfs buf; if (statfs (file, &buf) < 0) return -1; return strcmp (buf.f_fstypename, "nfs") == 0; } #elif defined(__hurd__) /* something else on Hurd */ #else /* no idea how to detect NFS on this OS */ int is_on_nfs (const char *file) { (void) file; return 0; } #endif Bool Directory::isNFSMounted() const { int result = is_on_nfs(itsFile.path().expandedName().chars()); if (result < 0) throw (AipsError ("Directory::isNFSMounted error on " + itsFile.path().expandedName() + ": " + strerror(errno))); } return result != 0; } ---------------------------------------------------------- The much more important question is: why do need this detection? Because typically you want to detect NFS for one of the following reasons: - network filesystem -> slow -> don't do too much I/O there - lacks specific guarantees / features In either case, NFS is not the only contender for this though. On Linux there are lots of other possibilities here: there are other network filesystems in the kernel, there are local filesystems that don't follow POSIX guarantees (think e.g. vfat), there are a ton of FUSE filesystems out there that support a varying number of features required by POSIX. Plus, FUSE filesystems exist for both network (e.g. sshfs) or local (think ntfs-3g). On Hurd, you can have arbitrary translators provide the backing of a specific directory, and different translators support a different degree of POSIX features. Therefore, it might be a good idea to know _why_ you want to check for NFS here? What's the use case? Perhaps there's a better and more portable way to check for that specific thing. Regards, Christian