Re: NFS_SUPER_MAGIC portability
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
Reply to: